159243Sobrien;; csh-mode.el --- csh (and tcsh) script editing mode for Emacs.
259243Sobrien;;
359243Sobrien;; Version:    1.2
459243Sobrien;; Date:       April 2, 1999
5131962Smp;; Maintainer: Dan Harkless <software@harkless.org>
659243Sobrien;;
759243Sobrien;; Description:
859243Sobrien;;   csh and tcsh script editing mode for Emacs.
959243Sobrien;;
1059243Sobrien;; Installation:
1159243Sobrien;;   Put csh-mode.el in some directory in your load-path and load it.
1259243Sobrien;;
1359243Sobrien;; Usage:
1459243Sobrien;;   This major mode assists shell script writers with indentation
1559243Sobrien;;   control and control structure construct matching in much the same
1659243Sobrien;;   fashion as other programming language modes. Invoke describe-mode
1759243Sobrien;;   for more information.
1859243Sobrien;;
1959243Sobrien;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2059243Sobrien;;
2159243Sobrien;; Author key:
22131962Smp;;   DH - Dan Harkless     <software@harkless.org>
2359243Sobrien;;   CM - Carlo Migliorini <migliorini@sodalia.it>
2459243Sobrien;;   JR - Jack Repenning   <jackr@sgi.com>
2559243Sobrien;;   GE - Gary Ellison     <Gary.F.Ellison@att.com>
2659243Sobrien;;
2759243Sobrien;; *** REVISION HISTORY ***
2859243Sobrien;;
2959243Sobrien;; DATE MOD.  BY  REASON FOR MODIFICATION
3059243Sobrien;; ---------  --  --------------------------------------------------------------
3159243Sobrien;;  2 Apr 99  DH  1.2: Noticed an out-of-date comment referencing .bashrc etc.
3259243Sobrien;; 11 Dec 96  DH  1.1: ksh-mode just indented continuation lines by 1 space.
3359243Sobrien;;                csh-mode looks at the first line and indents properly to line
3459243Sobrien;;                up under the open-paren, quote, or command.
3559243Sobrien;; 11 Dec 96  DH  Added fontification for history substitutions.
3659243Sobrien;; 10 Dec 96  DH  Added indentation and fontification for labels.  Added
3759243Sobrien;;                fontification for variables and backquoted strings.
3859243Sobrien;;  9 Dec 96  DH  1.0: Brought csh-mode up to the level of functionality of
3959243Sobrien;;                the original ksh-mode.
4059243Sobrien;;  7 Oct 96  CM  0.1: Hacked ksh-mode.el into minimally functional csh-mode.el
4159243Sobrien;;                by doing search-and-replace and some keyword changes.
4259243Sobrien;;  8 Aug 96  JR  (Last modification to ksh-mode 2.6.)
4359243Sobrien;;                [...]
4459243Sobrien;; 19 Jun 92  GE  (Conception of ksh-mode.)
4559243Sobrien;;
4659243Sobrien;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4759243Sobrien
4859243Sobrien
4959243Sobrien(defconst csh-mode-version "1.2"
5059243Sobrien  "*Version number of this version of csh-mode")
5159243Sobrien
5259243Sobrien(defvar csh-mode-hook
5359243Sobrien  '(lambda ()
5459243Sobrien     (auto-fill-mode 1))
5559243Sobrien  "Hook to run each time csh-mode is entered.")
5659243Sobrien
5759243Sobrien
5859243Sobrien;;
5959243Sobrien;; -------------------------------------------> Variables controlling completion
6059243Sobrien;;
6159243Sobrien(defvar csh-completion-list '())
6259243Sobrien(make-variable-buffer-local 'csh-completion-list)
6359243Sobrien(set-default 'csh-completion-list  '())
6459243Sobrien;;
6559243Sobrien;; -type-  : type number, 0:misc, 1:variable, 2:function
6659243Sobrien;; -regexp-: regexp used to parse the script
6759243Sobrien;; -match- : used by match-beginning/end to pickup target
6859243Sobrien;;
6959243Sobrien(defvar csh-completion-type-misc 0)
7059243Sobrien(defvar csh-completion-regexp-var "\\([A-Za-z_0-9]+\\)=")
7159243Sobrien(defvar csh-completion-type-var 1)
7259243Sobrien(defvar csh-completion-match-var 1)
7359243Sobrien(defvar csh-completion-regexp-var2 "\\$\\({\\|{#\\)?\\([A-Za-z_0-9]+\\)[#%:}]?")
7459243Sobrien(defvar csh-completion-match-var2 2)
7559243Sobrien(defvar csh-completion-regexp-function
7659243Sobrien  "\\(function\\)?[ \t]*\\([A-Za-z_0-9]+\\)[ \t]*([ \t]*)")
7759243Sobrien(defvar csh-completion-type-function 2)
7859243Sobrien(defvar csh-completion-match-function 2)
7959243Sobrien
8059243Sobrien
8159243Sobrien;;
8259243Sobrien;; ------------------------------------> Variables controlling indentation style
8359243Sobrien;;
8459243Sobrien(defvar csh-indent 4
8559243Sobrien  "*Indentation of csh statements with respect to containing block. A value
8659243Sobrienof nil indicates compound list keyword \(\"do\" and \"then\"\) alignment.")
8759243Sobrien
8859243Sobrien(defvar csh-case-item-offset csh-indent
8959243Sobrien  "*Additional indentation for case items within a case statement.")
9059243Sobrien(defvar csh-case-indent nil
9159243Sobrien  "*Additional indentation for statements under case items.")
9259243Sobrien(defvar csh-comment-regexp "^\\s *#"
9359243Sobrien  "*Regular expression used to recognize comments. Customize to support
9459243Sobriencsh-like languages.")
9559243Sobrien(defvar csh-match-and-tell t
9659243Sobrien  "*If non-nil echo in the minibuffer the matching compound command
9759243Sobrienfor the \"breaksw\", \"end\", or \"endif\".")
9859243Sobrien(defvar csh-tab-always-indent t
9959243Sobrien  "*Controls the operation of the TAB key. If t (the default), always
10059243Sobrienreindent the current line.  If nil, indent the current line only if
10159243Sobrienpoint is at the left margin or in the line's indentation; otherwise
10259243Sobrieninsert a tab.")
10359243Sobrien
10459243Sobrien
10559243Sobrien;;
10659243Sobrien;; ----------------------------------------> Constants containing syntax regexps
10759243Sobrien;;
10859243Sobrien(defconst csh-case-default-re
10959243Sobrien  "^\\s *\\(case\\|default\\)\\b"
11059243Sobrien  "Regexp used to locate grouping keywords case and default" )
11159243Sobrien
11259243Sobrien(defconst csh-case-item-re "^\\s *\\(case .*\\|default\\):"
11359243Sobrien  "Regexp used to match case-items")
11459243Sobrien
11559243Sobrien(defconst csh-end-re "^\\s *end\\b"
11659243Sobrien  "Regexp used to match keyword: end")
11759243Sobrien
11859243Sobrien(defconst csh-endif-re "^\\s *endif\\b"
11959243Sobrien  "Regexp used to match keyword: endif")
12059243Sobrien
12159243Sobrien(defconst csh-endsw-re "^\\s *endsw\\b"
12259243Sobrien  "Regexp used to match keyword: endsw")
12359243Sobrien
12459243Sobrien(defconst csh-else-re "^\\s *\\belse\\(\\b\\|$\\)"
12559243Sobrien  "Regexp used to match keyword: else")
12659243Sobrien
12759243Sobrien(defconst csh-else-if-re "^\\s *\\belse if\\(\\b\\|$\\)"
12859243Sobrien  "Regexp used to match keyword pair: else if")
12959243Sobrien
13059243Sobrien(defconst csh-if-re "^\\s *if\\b.+\\(\\\\\\|\\bthen\\b\\)"
13159243Sobrien  "Regexp used to match non-one-line if statements")
13259243Sobrien
13359243Sobrien(defconst csh-iteration-keywords-re "^[^#\n]*\\s\"*\\b\\(while\\|foreach\\)\\b"
13459243Sobrien  "Match one of the keywords: while, foreach")
13559243Sobrien
13659243Sobrien(defconst csh-keywords-re
13759243Sobrien  "^\\s *\\(else\\b\\|foreach\\b\\|if\\b.+\\(\\\\\\|\\bthen\\b\\)\\|switch\\b\\|while\\b\\)"
13859243Sobrien  "Regexp used to detect compound command keywords: else, if, foreach, while")
13959243Sobrien
14059243Sobrien(defconst csh-label-re "^\\s *[^!#$\n ]+:"
14159243Sobrien  "Regexp used to match flow-control labels")
14259243Sobrien
14359243Sobrien(defconst csh-multiline-re "^.*\\\\$"
14459243Sobrien  "Regexp used to match a line with a statement using more lines.")
14559243Sobrien
14659243Sobrien(defconst csh-switch-re "^\\s *switch\\b"
14759243Sobrien  "Regexp used to match keyword: switch")
14859243Sobrien
14959243Sobrien
15059243Sobrien;;
15159243Sobrien;; ----------------------------------------> Variables controlling fontification
15259243Sobrien;;
15359243Sobrien(defvar csh-keywords '("@" "alias" "bg" "break" "breaksw" "case" "cd" "chdir"
15459243Sobrien		       "continue" "default" "dirs" "echo" "else" "end" "endif"
15559243Sobrien		       "endsw" "eval" "exec" "exit" "fg" "foreach" "glob" "goto"
15659243Sobrien		       "hashstat" "history" "if" "jobs" "kill" "limit" "login"
15759243Sobrien		       "logout" "limit" "notify" "onintr" "popd" "printenv"
15859243Sobrien		       "pushd" "rehash" "repeat" "set" "setenv" "shift" "source"
15959243Sobrien		       "stop" "suspend" "switch" "then" "time" "umask" "unalias"
16059243Sobrien		       "unhash" "unlimit" "unset" "unsetenv" "wait" "while"
16159243Sobrien		       ;; tcsh-keywords
16259243Sobrien		       "alloc" "bindkey" "builtins" "complete" "echotc"
16359243Sobrien		       "filetest" "hup" "log" "ls-F" "nice" "nohup" "sched"
16459243Sobrien		       "settc" "setty" "telltc" "uncomplete" "where" "which"))
16559243Sobrien
16659243Sobrien(require 'font-lock)  ; need to do this before referring to font-lock-* below
16759243Sobrien
16859243Sobrien(defconst csh-font-lock-keywords
16959243Sobrien  ;; NOTE:  The order of some of the items in this list is significant.  Do not
17059243Sobrien  ;;        alphabetize or otherwise blindly rearrange.
17159243Sobrien  (list
17259243Sobrien   ;; Comments on line 1, which are missed by syntactic fontification.
17359243Sobrien   '("^#.*" 0 font-lock-comment-face)
17459243Sobrien
17559243Sobrien   ;; Label definitions (1 means first parenthesized exp in regexp).
17659243Sobrien   '("^\\s *\\([^!#$\n ]+\\):" 1 font-lock-function-name-face)
17759243Sobrien
17859243Sobrien   ;; Label references.
17959243Sobrien   '("\\b\\(goto\\|onintr\\)\\b\\s +\\([^!#$ \n\t]+\\)"
18059243Sobrien     2 font-lock-function-name-face)
18159243Sobrien
18259243Sobrien   ;; Variable settings.
18359243Sobrien   '("\\(@\\|set\\|setenv\\)\\s +\\([0-9A-Za-z_]+\\b\\)"
18459243Sobrien     2 font-lock-variable-name-face)
18559243Sobrien
18659243Sobrien   ;; Variable references not inside of strings.
18759243Sobrien   '("\\$[][0-9A-Za-z_#:?]+" 0 font-lock-variable-name-face)
18859243Sobrien
18959243Sobrien   ;; Backquoted strings.  'keep' means to just fontify non-fontified text.
19059243Sobrien   '("`\\(.*\\)`" 1 font-lock-reference-face keep)
19159243Sobrien
19259243Sobrien   ;; NOTE:  The following variables need to be anchored to the beginning of
19359243Sobrien   ;;        line to prevent re-fontifying text in comments.  Due to this, we
19459243Sobrien   ;;        can only catch a finite number of occurrences.  More can be added.
19559243Sobrien   ;;        The 't' means to override previous fontification.
19659243Sobrien   ;;
19759243Sobrien   ;;        Variable references inside of " strings.
19859243Sobrien   '("^[^#\n]*\".*\\(\\$[][0-9A-Za-z_#:?]+\\).*\""
19959243Sobrien     1 font-lock-variable-name-face t)                                    ; 1
20059243Sobrien   '("^[^#\n]*\".*\\(\\$[][0-9A-Za-z_#:?]+\\).*\\$[][0-9A-Za-z_#:?]+.*\""
20159243Sobrien     1 font-lock-variable-name-face t)                                    ; 2
20259243Sobrien   (cons (concat "^[^#\n]*\".*\\(\\$[][0-9A-Za-z_#:?]+\\).*"
20359243Sobrien		 "\\$[][0-9A-Za-z_#:?]+.*\\$[][0-9A-Za-z_#:?]+.*\"")
20459243Sobrien	 (list 1 font-lock-variable-name-face t))                         ; 3
20559243Sobrien   ;;
20659243Sobrien   ;;        History substitutions.
20759243Sobrien   '("^![^~= \n\t]+" 0 font-lock-reference-face t)                      ; BOL
20859243Sobrien   '("^[^#\n]*[^#\\\n]\\(![^~= \n\t]+\\)" 1 font-lock-reference-face t) ; 1
20959243Sobrien   '("^[^#\n]*[^#\\\n]\\(![^~= \n\t]+\\).*![^~= \n\t]+"
21059243Sobrien     1 font-lock-reference-face t)                                      ; 2
21159243Sobrien
21259243Sobrien   ;; Keywords.
21359243Sobrien   (cons (concat
21459243Sobrien	  "\\(\\<"
21559243Sobrien	  (mapconcat 'identity csh-keywords "\\>\\|\\<")
21659243Sobrien	  "\\>\\)")
21759243Sobrien	 1)
21859243Sobrien   ))
21959243Sobrien
22059243Sobrien(put 'csh-mode 'font-lock-keywords 'csh-font-lock-keywords)
22159243Sobrien
22259243Sobrien
22359243Sobrien;;
22459243Sobrien;; -------------------------------------------------------> Mode-specific tables
22559243Sobrien;;
22659243Sobrien(defvar csh-mode-abbrev-table nil
22759243Sobrien  "Abbrev table used while in csh mode.")
22859243Sobrien(define-abbrev-table 'csh-mode-abbrev-table ())
22959243Sobrien
23059243Sobrien(defvar csh-mode-map nil
23159243Sobrien  "Keymap used in csh mode")
23259243Sobrien(if csh-mode-map
23359243Sobrien    ()
23459243Sobrien  (setq csh-mode-map (make-sparse-keymap))
23559243Sobrien;;(define-key csh-mode-map "\177"    'backward-delete-char-untabify)
23659243Sobrien  (define-key csh-mode-map "\C-c\t"  'csh-completion-init-and-pickup)
23759243Sobrien  (define-key csh-mode-map "\C-j"    'reindent-then-newline-and-indent)
23859243Sobrien  (define-key csh-mode-map "\e\t"    'csh-complete-symbol)
23959243Sobrien  (define-key csh-mode-map "\n"      'reindent-then-newline-and-indent)
24059243Sobrien  (define-key csh-mode-map '[return] 'reindent-then-newline-and-indent)
24159243Sobrien  (define-key csh-mode-map "\t"      'csh-indent-command)
24259243Sobrien;;(define-key csh-mode-map "\t"      'csh-indent-line)
24359243Sobrien  )
24459243Sobrien
24559243Sobrien(defvar csh-mode-syntax-table nil
24659243Sobrien  "Syntax table used while in csh mode.")
24759243Sobrien(if csh-mode-syntax-table
24859243Sobrien    ;; If it's already set up, don't change it.
24959243Sobrien    ()
25059243Sobrien  ;; Else, create it from the standard table and modify entries that need to be.
25159243Sobrien  (setq csh-mode-syntax-table (make-syntax-table))
25259243Sobrien  (modify-syntax-entry ?&  "."  csh-mode-syntax-table) ; & -punctuation
25359243Sobrien  (modify-syntax-entry ?*  "."  csh-mode-syntax-table) ; * -punctuation
25459243Sobrien  (modify-syntax-entry ?-  "."  csh-mode-syntax-table) ; - -punctuation
25559243Sobrien  (modify-syntax-entry ?=  "."  csh-mode-syntax-table) ; = -punctuation
25659243Sobrien  (modify-syntax-entry ?+  "."  csh-mode-syntax-table) ; + -punctuation
25759243Sobrien  (modify-syntax-entry ?|  "."  csh-mode-syntax-table) ; | -punctuation
25859243Sobrien  (modify-syntax-entry ?<  "."  csh-mode-syntax-table) ; < -punctuation
25959243Sobrien  (modify-syntax-entry ?>  "."  csh-mode-syntax-table) ; > -punctuation
26059243Sobrien  (modify-syntax-entry ?/  "."  csh-mode-syntax-table) ; / -punctuation
26159243Sobrien  (modify-syntax-entry ?\' "\"" csh-mode-syntax-table) ; ' -string quote
26259243Sobrien  (modify-syntax-entry ?.  "w"  csh-mode-syntax-table) ; . -word constituent
26359243Sobrien  (modify-syntax-entry ??  "w"  csh-mode-syntax-table) ; ? -word constituent
26459243Sobrien
26559243Sobrien  ;; \n - comment ender, first character of 2-char comment sequence
26659243Sobrien  (modify-syntax-entry ?\n "> 1" csh-mode-syntax-table) ; # -word constituent
26759243Sobrien
26859243Sobrien  ;;   - whitespace, first character of 2-char comment sequence
26959243Sobrien  (modify-syntax-entry ?   "  1" csh-mode-syntax-table) ;
27059243Sobrien
27159243Sobrien  ;; \t - whitespace, first character of 2-char comment sequence
27259243Sobrien  (modify-syntax-entry ?\t "  1" csh-mode-syntax-table) ; # -word constituent
27359243Sobrien
27459243Sobrien  ;; # - word constituent, second character of 2-char comment sequence
27559243Sobrien  (modify-syntax-entry ?#  "w 2" csh-mode-syntax-table) ; # -word constituent
27659243Sobrien  )
27759243Sobrien
27859243Sobrien
27959243Sobrien;;
28059243Sobrien;; ------------------------------------------------------------------> Functions
28159243Sobrien;;
28259243Sobrien(defun csh-current-line ()
28359243Sobrien  "Return the vertical position of point in the buffer.
28459243SobrienTop line is 1."
28559243Sobrien  (+ (count-lines (point-min) (point))
28659243Sobrien     (if (= (current-column) 0) 1 0))
28759243Sobrien  )
28859243Sobrien
28959243Sobrien(defun csh-get-compound-level
29059243Sobrien  (begin-re end-re anchor-point &optional balance-list)
29159243Sobrien  "Determine how much to indent this structure. Return a list (level line)
29259243Sobrienof the matching compound command or nil if no match found."
29359243Sobrien  (let*
29459243Sobrien      (;; Locate the next compound begin keyword bounded by point-min
29559243Sobrien       (match-point (if (re-search-backward begin-re (point-min) t)
29659243Sobrien			(match-beginning 0) 0))
29759243Sobrien       (nest-column (if (zerop match-point)
29859243Sobrien			1
29959243Sobrien		      (progn
30059243Sobrien			(goto-char match-point)
30159243Sobrien			(current-indentation))))
30259243Sobrien       (nest-list (cons 0 0))    ;; sentinel cons since cdr is >= 1
30359243Sobrien       )
30459243Sobrien    (if (zerop match-point)
30559243Sobrien	nil ;; graceful exit from recursion
30659243Sobrien      (progn
30759243Sobrien	(if (nlistp balance-list)
30859243Sobrien	    (setq balance-list (list)))
30959243Sobrien	;; Now search forward from matching start keyword for end keyword
31059243Sobrien	(while (and (consp nest-list) (zerop (cdr nest-list))
31159243Sobrien		    (re-search-forward end-re anchor-point t))
31259243Sobrien	  (if (not (memq (point) balance-list))
31359243Sobrien	      (progn
31459243Sobrien		(setq balance-list (cons (point) balance-list))
31559243Sobrien		(goto-char match-point)  ;; beginning of compound cmd
31659243Sobrien		(setq nest-list
31759243Sobrien		      (csh-get-compound-level begin-re end-re
31859243Sobrien					     anchor-point balance-list))
31959243Sobrien		)))
32059243Sobrien
32159243Sobrien	(cond ((consp nest-list)
32259243Sobrien	       (if (zerop (cdr nest-list))
32359243Sobrien		 (progn
32459243Sobrien		   (goto-char match-point)
32559243Sobrien		   (cons nest-column (csh-current-line)))
32659243Sobrien		 nest-list))
32759243Sobrien	      (t nil)
32859243Sobrien	      )
32959243Sobrien	)
33059243Sobrien      )
33159243Sobrien    )
33259243Sobrien  )
33359243Sobrien
33459243Sobrien(defun csh-get-nest-level ()
33559243Sobrien  "Return a 2 element list (nest-level nest-line) describing where the
33659243Sobriencurrent line should nest."
33759243Sobrien  (let ((case-fold-search)
33859243Sobrien    	(level))
33959243Sobrien    (save-excursion
34059243Sobrien      (forward-line -1)
34159243Sobrien      (while (and (not (bobp))
34259243Sobrien		  (null level))
34359243Sobrien	(if (and (not (looking-at "^\\s *$"))
34459243Sobrien 		 (not (save-excursion
34559243Sobrien 			(forward-line -1)
34659243Sobrien 			(beginning-of-line)
34759243Sobrien			(looking-at csh-multiline-re)))
34859243Sobrien		 (not (looking-at csh-comment-regexp)))
34959243Sobrien	    (setq level (cons (current-indentation)
35059243Sobrien			      (csh-current-line)))
35159243Sobrien	  (forward-line -1)
35259243Sobrien	  );; if
35359243Sobrien	);; while
35459243Sobrien      (if (null level)
35559243Sobrien	  (cons (current-indentation) (csh-current-line))
35659243Sobrien	level)
35759243Sobrien      )
35859243Sobrien    )
35959243Sobrien  )
36059243Sobrien
36159243Sobrien(defun csh-get-nester-column (nest-line)
36259243Sobrien  "Return the column to indent to with respect to nest-line taking
36359243Sobrieninto consideration keywords and other nesting constructs."
36459243Sobrien  (save-excursion
36559243Sobrien    (let ((fence-post)
36659243Sobrien	  (case-fold-search)
36759243Sobrien	  (start-line (csh-current-line)))
36859243Sobrien      ;;
36959243Sobrien      ;; Handle case item indentation constructs for this line
37059243Sobrien      (cond ((looking-at csh-case-item-re)
37159243Sobrien	     ;; This line is a case item...
37259243Sobrien	     (save-excursion
37359243Sobrien	       (goto-line nest-line)
37459243Sobrien	       (let ((fence-post (save-excursion (end-of-line) (point))))
37559243Sobrien		 (cond ((re-search-forward csh-switch-re fence-post t)
37659243Sobrien			;; If this is the first case under the switch, indent.
37759243Sobrien			(goto-char (match-beginning 0))
37859243Sobrien			(+ (current-indentation) csh-case-item-offset))
37959243Sobrien
38059243Sobrien		       ((re-search-forward csh-case-item-re fence-post t)
38159243Sobrien			;; If this is another case right under a previous case
38259243Sobrien			;; without intervening code, stay at the same
38359243Sobrien			;; indentation.
38459243Sobrien			(goto-char (match-beginning 0))
38559243Sobrien			(current-indentation))
38659243Sobrien
38759243Sobrien		       (t
38859243Sobrien			;; Else, this is a new case.  Outdent.
38959243Sobrien			(- (current-indentation) csh-case-item-offset))
39059243Sobrien		       )
39159243Sobrien		 )))
39259243Sobrien	    (t;; Not a case-item.  What to do relative to the nest-line?
39359243Sobrien	     (save-excursion
39459243Sobrien	       (goto-line nest-line)
39559243Sobrien	       (setq fence-post (save-excursion (end-of-line) (point)))
39659243Sobrien	       (save-excursion
39759243Sobrien		 (cond
39859243Sobrien		  ;;
39959243Sobrien		  ;; Check if we are in a continued statement
40059243Sobrien		  ((and (looking-at csh-multiline-re)
40159243Sobrien			(save-excursion
40259243Sobrien			  (goto-line (1- start-line))
40359243Sobrien			  (looking-at csh-multiline-re)))
40459243Sobrien		   (if (looking-at ".*[\'\"]\\\\")
40559243Sobrien		       ;; If this is a continued string, indent under
40659243Sobrien		       ;; opening quote.
40759243Sobrien		       (progn
40859243Sobrien			 (re-search-forward "[\'\"]")
40959243Sobrien			 (forward-char -1))
41059243Sobrien		     (if (looking-at ".*([^\)\n]*\\\\")
41159243Sobrien			 ;; Else if this is a continued parenthesized
41259243Sobrien			 ;; list, indent after paren.
41359243Sobrien			 (re-search-forward "(" fence-post t)
41459243Sobrien		       ;; Else, indent after whitespace after first word.
41559243Sobrien		       (re-search-forward "[^ \t]+[ \t]+" fence-post t)))
41659243Sobrien		   (current-column))
41759243Sobrien
41859243Sobrien		  ;; In order to locate the column of the keyword,
41959243Sobrien		  ;; which might be embedded within a case-item,
42059243Sobrien		  ;; it is necessary to use re-search-forward.
42159243Sobrien		  ;; Search by literal case, since shell is
42259243Sobrien		  ;; case-sensitive.
42359243Sobrien		  ((re-search-forward csh-keywords-re fence-post t)
42459243Sobrien		   (goto-char (match-beginning 1))
42559243Sobrien		   (if (looking-at csh-switch-re)
42659243Sobrien		       (+ (current-indentation) csh-case-item-offset)
42759243Sobrien		     (+ (current-indentation)
42859243Sobrien			(if (null csh-indent)
42959243Sobrien			    2 csh-indent)
43059243Sobrien			)))
43159243Sobrien
43259243Sobrien		  ((re-search-forward csh-case-default-re fence-post t)
43359243Sobrien		   (if (null csh-indent)
43459243Sobrien		       (progn
43559243Sobrien			 (goto-char (match-end 1))
43659243Sobrien			 (+ (current-indentation) 1))
43759243Sobrien		     (progn
43859243Sobrien		       (goto-char (match-beginning 1))
43959243Sobrien		       (+ (current-indentation) csh-indent))
44059243Sobrien		     ))
44159243Sobrien
44259243Sobrien		  ;;
44359243Sobrien		  ;; Now detect first statement under a case item
44459243Sobrien		  ((looking-at csh-case-item-re)
44559243Sobrien		   (if (null csh-case-indent)
44659243Sobrien		       (progn
44759243Sobrien			 (re-search-forward csh-case-item-re fence-post t)
44859243Sobrien			 (goto-char (match-end 1))
44959243Sobrien			 (+ (current-column) 1))
45059243Sobrien		     (+ (current-indentation) csh-case-indent)))
45159243Sobrien
45259243Sobrien		  ;;
45359243Sobrien		  ;; If this is the first statement under a control-flow
45459243Sobrien		  ;; label, indent one level.
45559243Sobrien		  ((csh-looking-at-label)
45659243Sobrien		   (+ (current-indentation) csh-indent))
45759243Sobrien
45859243Sobrien		  ;; This is hosed when using current-column
45959243Sobrien		  ;; and there is a multi-command expression as the
46059243Sobrien		  ;; nester.
46159243Sobrien		  (t (current-indentation)))
46259243Sobrien		 )
46359243Sobrien	       ));; excursion over
46459243Sobrien	    );; Not a case-item
46559243Sobrien      );;let
46659243Sobrien    );; excursion
46759243Sobrien  );; defun
46859243Sobrien
46959243Sobrien(defun csh-indent-command ()
47059243Sobrien  "Indent current line relative to containing block and allow for
47159243Sobriencsh-tab-always-indent customization"
47259243Sobrien  (interactive)
47359243Sobrien  (let (case-fold-search)
47459243Sobrien    (cond ((save-excursion
47559243Sobrien	     (skip-chars-backward " \t")
47659243Sobrien	     (bolp))
47759243Sobrien	   (csh-indent-line))
47859243Sobrien	  (csh-tab-always-indent
47959243Sobrien	   (save-excursion
48059243Sobrien	     (csh-indent-line)))
48159243Sobrien	  (t (insert-tab))
48259243Sobrien	  ))
48359243Sobrien  )
48459243Sobrien
48559243Sobrien(defun csh-indent-line ()
48659243Sobrien  "Indent current line as far as it should go according
48759243Sobriento the syntax/context"
48859243Sobrien  (interactive)
48959243Sobrien  (let (case-fold-search)
49059243Sobrien    (save-excursion
49159243Sobrien      (beginning-of-line)
49259243Sobrien      (if (bobp)
49359243Sobrien	  nil
49459243Sobrien	;;
49559243Sobrien	;; Align this line to current nesting level
49659243Sobrien	(let*
49759243Sobrien	    (
49859243Sobrien	     (level-list (csh-get-nest-level)) ; Where to nest against
49959243Sobrien	     ;;           (last-line-level (car level-list))
50059243Sobrien	     (this-line-level (current-indentation))
50159243Sobrien	     (nester-column (csh-get-nester-column (cdr level-list)))
50259243Sobrien	     (struct-match (csh-match-structure-and-reindent))
50359243Sobrien	     )
50459243Sobrien	  (if struct-match
50559243Sobrien	      (setq nester-column struct-match))
50659243Sobrien	  (if (eq nester-column this-line-level)
50759243Sobrien	      nil
50859243Sobrien	    (beginning-of-line)
50959243Sobrien	    (let ((beg (point)))
51059243Sobrien	      (back-to-indentation)
51159243Sobrien	      (delete-region beg (point)))
51259243Sobrien	    (indent-to nester-column))
51359243Sobrien	  );; let*
51459243Sobrien	);; if
51559243Sobrien      );; excursion
51659243Sobrien    ;;
51759243Sobrien    ;; Position point on this line
51859243Sobrien    (let*
51959243Sobrien	(
52059243Sobrien	 (this-line-level (current-indentation))
52159243Sobrien	 (this-bol (save-excursion
52259243Sobrien		     (beginning-of-line)
52359243Sobrien		     (point)))
52459243Sobrien	 (this-point (- (point) this-bol))
52559243Sobrien	 )
52659243Sobrien      (cond ((> this-line-level this-point);; point in initial white space
52759243Sobrien	     (back-to-indentation))
52859243Sobrien	    (t nil)
52959243Sobrien	    );; cond
53059243Sobrien      );; let*
53159243Sobrien    );; let
53259243Sobrien  );; defun
53359243Sobrien
53459243Sobrien(defun csh-indent-region (start end)
53559243Sobrien  "From start to end, indent each line."
53659243Sobrien  ;; The algorithm is just moving through the region line by line with
53759243Sobrien  ;; the match noise turned off.  Only modifies nonempty lines.
53859243Sobrien  (save-excursion
53959243Sobrien    (let (csh-match-and-tell
54059243Sobrien	  (endmark (copy-marker end)))
54159243Sobrien
54259243Sobrien      (goto-char start)
54359243Sobrien      (beginning-of-line)
54459243Sobrien      (setq start (point))
54559243Sobrien      (while (> (marker-position endmark) start)
54659243Sobrien	(if (not (and (bolp) (eolp)))
54759243Sobrien	    (csh-indent-line))
54859243Sobrien	(forward-line 1)
54959243Sobrien	(setq start (point)))
55059243Sobrien
55159243Sobrien      (set-marker endmark nil)
55259243Sobrien      )
55359243Sobrien    )
55459243Sobrien  )
55559243Sobrien
55659243Sobrien(defun csh-line-to-string ()
55759243Sobrien  "From point, construct a string from all characters on
55859243Sobriencurrent line"
55959243Sobrien  (skip-chars-forward " \t") ;; skip tabs as well as spaces
56059243Sobrien  (buffer-substring (point)
56159243Sobrien                    (progn
56259243Sobrien                      (end-of-line 1)
56359243Sobrien                      (point))))
56459243Sobrien
56559243Sobrien(defun csh-looking-at-label ()
56659243Sobrien  "Return true if current line is a label (not the default: case label)."
56759243Sobrien  (and
56859243Sobrien   (looking-at csh-label-re)
56959243Sobrien   (not (looking-at "^\\s *default:"))))
57059243Sobrien
57159243Sobrien(defun csh-match-indent-level (begin-re end-re)
57259243Sobrien  "Match the compound command and indent. Return nil on no match,
57359243Sobrienindentation to use for this line otherwise."
57459243Sobrien  (interactive)
57559243Sobrien  (let* ((case-fold-search)
57659243Sobrien	 (nest-list
57759243Sobrien	  (save-excursion
57859243Sobrien	    (csh-get-compound-level begin-re end-re (point))
57959243Sobrien	    ))
58059243Sobrien	 ) ;; bindings
58159243Sobrien    (if (null nest-list)
58259243Sobrien	(progn
58359243Sobrien	  (if csh-match-and-tell
58459243Sobrien	      (message "No matching compound command"))
58559243Sobrien	  nil) ;; Propagate a miss.
58659243Sobrien      (let* (
58759243Sobrien	     (nest-level (car nest-list))
58859243Sobrien	     (match-line (cdr nest-list))
58959243Sobrien	     ) ;; bindings
59059243Sobrien	(if csh-match-and-tell
59159243Sobrien	    (save-excursion
59259243Sobrien	      (goto-line match-line)
59359243Sobrien	      (message "Matched ... %s" (csh-line-to-string))
59459243Sobrien	      ) ;; excursion
59559243Sobrien	  ) ;; if csh-match-and-tell
59659243Sobrien	nest-level ;;Propagate a hit.
59759243Sobrien	) ;; let*
59859243Sobrien      ) ;; if
59959243Sobrien    ) ;; let*
60059243Sobrien  ) ;; defun csh-match-indent-level
60159243Sobrien
60259243Sobrien(defun csh-match-structure-and-reindent ()
60359243Sobrien  "If the current line matches one of the indenting keywords
60459243Sobrienor one of the control structure ending keywords then reindent. Also
60559243Sobrienif csh-match-and-tell is non-nil the matching structure will echo in
60659243Sobrienthe minibuffer"
60759243Sobrien  (interactive)
60859243Sobrien  (let (case-fold-search)
60959243Sobrien    (save-excursion
61059243Sobrien      (beginning-of-line)
61159243Sobrien      (cond ((looking-at csh-else-re)
61259243Sobrien	     (csh-match-indent-level csh-if-re csh-endif-re))
61359243Sobrien	    ((looking-at csh-else-if-re)
61459243Sobrien	     (csh-match-indent-level csh-if-re csh-endif-re))
61559243Sobrien	    ((looking-at csh-endif-re)
61659243Sobrien	     (csh-match-indent-level csh-if-re csh-endif-re))
61759243Sobrien	    ((looking-at csh-end-re)
61859243Sobrien	     (csh-match-indent-level csh-iteration-keywords-re csh-end-re))
61959243Sobrien	    ((looking-at csh-endsw-re)
62059243Sobrien	     (csh-match-indent-level csh-switch-re csh-endsw-re))
62159243Sobrien	    ((csh-looking-at-label)
62259243Sobrien	     ;; Flush control-flow labels left since they don't nest.
62359243Sobrien	     0)
62459243Sobrien	    ;;
62559243Sobrien	    (t nil)
62659243Sobrien	    );; cond
62759243Sobrien      )
62859243Sobrien    ))
62959243Sobrien
63059243Sobrien;;;###autoload
63159243Sobrien(defun csh-mode ()
63259243Sobrien  "csh-mode 2.0 - Major mode for editing csh and tcsh scripts.
63359243SobrienSpecial key bindings and commands:
63459243Sobrien\\{csh-mode-map}
63559243SobrienVariables controlling indentation style:
63659243Sobriencsh-indent
63759243Sobrien    Indentation of csh statements with respect to containing block.
63859243Sobrien    Default value is 4.
63959243Sobriencsh-case-indent
64059243Sobrien    Additional indentation for statements under case items.
64159243Sobrien    Default value is nil which will align the statements one position
64259243Sobrien    past the \")\" of the pattern.
64359243Sobriencsh-case-item-offset
64459243Sobrien    Additional indentation for case items within a case statement.
64559243Sobrien    Default value is 2.
64659243Sobriencsh-tab-always-indent
64759243Sobrien    Controls the operation of the TAB key. If t (the default), always
64859243Sobrien    reindent the current line.  If nil, indent the current line only if
64959243Sobrien    point is at the left margin or in the line's indentation; otherwise
65059243Sobrien    insert a tab.
65159243Sobriencsh-match-and-tell
65259243Sobrien    If non-nil echo in the minibuffer the matching compound command
65359243Sobrien    for the \"done\", \"}\", \"fi\", or \"endsw\". Default value is t.
65459243Sobrien
65559243Sobriencsh-comment-regexp
65659243Sobrien  Regular expression used to recognize comments. Customize to support
65759243Sobrien  csh-like languages. Default value is \"\^\\\\s *#\".
65859243Sobrien
65959243SobrienStyle Guide.
66059243Sobrien By setting
66159243Sobrien    (setq csh-indent default-tab-width)
66259243Sobrien
66359243Sobrien    The following style is obtained:
66459243Sobrien
66559243Sobrien    if [ -z $foo ]
66659243Sobrien	    then
66759243Sobrien		    bar    # <-- csh-group-offset is additive to csh-indent
66859243Sobrien		    foo
66959243Sobrien    fi
67059243Sobrien
67159243Sobrien By setting
67259243Sobrien    (setq csh-indent default-tab-width)
67359243Sobrien    (setq csh-group-offset (- 0 csh-indent))
67459243Sobrien
67559243Sobrien    The following style is obtained:
67659243Sobrien
67759243Sobrien    if [ -z $foo ]
67859243Sobrien    then
67959243Sobrien	    bar
68059243Sobrien	    foo
68159243Sobrien    fi
68259243Sobrien
68359243Sobrien By setting
68459243Sobrien    (setq csh-case-item-offset 1)
68559243Sobrien    (setq csh-case-indent nil)
68659243Sobrien
68759243Sobrien    The following style is obtained:
68859243Sobrien
68959243Sobrien    case x in *
69059243Sobrien     foo) bar           # <-- csh-case-item-offset
69159243Sobrien          baz;;         # <-- csh-case-indent aligns with \")\"
69259243Sobrien     foobar) foo
69359243Sobrien             bar;;
69459243Sobrien    endsw
69559243Sobrien
69659243Sobrien By setting
69759243Sobrien    (setq csh-case-item-offset 1)
69859243Sobrien    (setq csh-case-indent 6)
69959243Sobrien
70059243Sobrien    The following style is obtained:
70159243Sobrien
70259243Sobrien    case x in *
70359243Sobrien     foo) bar           # <-- csh-case-item-offset
70459243Sobrien           baz;;        # <-- csh-case-indent
70559243Sobrien     foobar) foo
70659243Sobrien           bar;;
70759243Sobrien    endsw
70859243Sobrien
70959243Sobrien
71059243SobrienInstallation:
71159243Sobrien  Put csh-mode.el in some directory in your load-path.
71259243Sobrien  Put the following forms in your .emacs file.
71359243Sobrien
71459243Sobrien (setq auto-mode-alist
71559243Sobrien      (append auto-mode-alist
71659243Sobrien              (list
71759243Sobrien               '(\"\\\\.csh$\" . csh-mode)
71859243Sobrien               '(\"\\\\.login\" . csh-mode))))
71959243Sobrien
72059243Sobrien (setq csh-mode-hook
72159243Sobrien      (function (lambda ()
72259243Sobrien         (font-lock-mode 1)             ;; font-lock the buffer
72359243Sobrien         (setq csh-indent 8)
72459243Sobrien         (setq csh-tab-always-indent t)
72559243Sobrien         (setq csh-match-and-tell t)
72659243Sobrien         (setq csh-align-to-keyword t)	;; Turn on keyword alignment
72759243Sobrien	 )))"
72859243Sobrien  (interactive)
72959243Sobrien  (kill-all-local-variables)
73059243Sobrien  (use-local-map csh-mode-map)
73159243Sobrien  (setq major-mode 'csh-mode)
73259243Sobrien  (setq mode-name "Csh")
73359243Sobrien  (setq local-abbrev-table csh-mode-abbrev-table)
73459243Sobrien  (set-syntax-table csh-mode-syntax-table)
73559243Sobrien  (make-local-variable 'indent-line-function)
73659243Sobrien  (setq indent-line-function 'csh-indent-line)
73759243Sobrien  (make-local-variable 'indent-region-function)
73859243Sobrien  (setq indent-region-function 'csh-indent-region)
73959243Sobrien  (make-local-variable 'comment-start)
74059243Sobrien  (setq comment-start "# ")
74159243Sobrien  (make-local-variable 'comment-end)
74259243Sobrien  (setq comment-end "")
74359243Sobrien  (make-local-variable 'comment-column)
74459243Sobrien  (setq comment-column 32)
74559243Sobrien  (make-local-variable 'comment-start-skip)
74659243Sobrien  (setq comment-start-skip "#+ *")
74759243Sobrien  ;;
74859243Sobrien  ;; config font-lock mode
74959243Sobrien  (make-local-variable 'font-lock-keywords)
75059243Sobrien  (setq font-lock-keywords csh-font-lock-keywords)
75159243Sobrien  ;;
75259243Sobrien  ;; Let the user customize
75359243Sobrien  (run-hooks 'csh-mode-hook)
75459243Sobrien  ) ;; defun
75559243Sobrien
75659243Sobrien;;
75759243Sobrien;; Completion code supplied by Haavard Rue <hrue@imf.unit.no>.
75859243Sobrien;;
75959243Sobrien;;
76059243Sobrien;; add a completion with a given type to the list
76159243Sobrien;;
76259243Sobrien(defun csh-addto-alist (completion type)
76359243Sobrien  (setq csh-completion-list
76459243Sobrien	(append csh-completion-list
76559243Sobrien		(list (cons completion type)))))
76659243Sobrien
76759243Sobrien(defun csh-bol-point ()
76859243Sobrien  (save-excursion
76959243Sobrien    (beginning-of-line)
77059243Sobrien    (point)))
77159243Sobrien
77259243Sobrien(defun csh-complete-symbol ()
77359243Sobrien  "Perform completion."
77459243Sobrien  (interactive)
77559243Sobrien  (let* ((case-fold-search)
77659243Sobrien	 (end (point))
77759243Sobrien         (beg (unwind-protect
77859243Sobrien                  (save-excursion
77959243Sobrien                    (backward-sexp 1)
78059243Sobrien                    (while (= (char-syntax (following-char)) ?\')
78159243Sobrien                      (forward-char 1))
78259243Sobrien                    (point))))
78359243Sobrien         (pattern (buffer-substring beg end))
78459243Sobrien	 (predicate
78559243Sobrien	  ;;
78659243Sobrien	  ;; ` or $( mark a function
78759243Sobrien	  ;;
78859243Sobrien	  (save-excursion
78959243Sobrien	    (goto-char beg)
79059243Sobrien	    (if (or
79159243Sobrien		 (save-excursion
79259243Sobrien		   (backward-char 1)
79359243Sobrien		   (looking-at "`"))
79459243Sobrien		 (save-excursion
79559243Sobrien		   (backward-char 2)
79659243Sobrien		   (looking-at "\\$(")))
79759243Sobrien		(function (lambda (sym)
79859243Sobrien			    (equal (cdr sym) csh-completion-type-function)))
79959243Sobrien	      ;;
80059243Sobrien	      ;; a $, ${ or ${# mark a variable
80159243Sobrien	      ;;
80259243Sobrien	      (if (or
80359243Sobrien		   (save-excursion
80459243Sobrien		     (backward-char 1)
80559243Sobrien		     (looking-at "\\$"))
80659243Sobrien		   (save-excursion
80759243Sobrien		     (backward-char 2)
80859243Sobrien		     (looking-at "\\${"))
80959243Sobrien		   (save-excursion
81059243Sobrien		     (backward-char 3)
81159243Sobrien		     (looking-at "\\${#")))
81259243Sobrien		  (function (lambda (sym)
81359243Sobrien			      (equal (cdr sym)
81459243Sobrien				     csh-completion-type-var)))
81559243Sobrien		;;
81659243Sobrien		;; don't know. use 'em all
81759243Sobrien		;;
81859243Sobrien		(function (lambda (sym) t))))))
81959243Sobrien	 ;;
82059243Sobrien	 (completion (try-completion pattern csh-completion-list predicate)))
82159243Sobrien    ;;
82259243Sobrien    (cond ((eq completion t))
82359243Sobrien	  ;;
82459243Sobrien	  ;; oops, what is this ?
82559243Sobrien	  ;;
82659243Sobrien          ((null completion)
82759243Sobrien           (message "Can't find completion for \"%s\"" pattern))
82859243Sobrien	  ;;
82959243Sobrien	  ;; insert
83059243Sobrien	  ;;
83159243Sobrien          ((not (string= pattern completion))
83259243Sobrien           (delete-region beg end)
83359243Sobrien           (insert completion))
83459243Sobrien	  ;;
83559243Sobrien	  ;; write possible completion in the minibuffer,
83659243Sobrien	  ;; use this instead of a seperate buffer (usual)
83759243Sobrien	  ;;
83859243Sobrien          (t
83959243Sobrien           (let ((list (all-completions pattern csh-completion-list predicate))
84059243Sobrien		 (string ""))
84159243Sobrien	     (while list
84259243Sobrien	       (progn
84359243Sobrien		 (setq string (concat string (format "%s " (car list))))
84459243Sobrien		 (setq list (cdr list))))
84559243Sobrien	     (message string))))))
84659243Sobrien
84759243Sobrien;;
84859243Sobrien;; init the list and pickup all
84959243Sobrien;;
85059243Sobrien(defun csh-completion-init-and-pickup ()
85159243Sobrien  (interactive)
85259243Sobrien  (let (case-fold-search)
85359243Sobrien    (csh-completion-list-init)
85459243Sobrien    (csh-pickup-all)))
85559243Sobrien
85659243Sobrien;;
85759243Sobrien;; init the list
85859243Sobrien;;
85959243Sobrien(defun csh-completion-list-init ()
86059243Sobrien  (interactive)
86159243Sobrien  (setq csh-completion-list
86259243Sobrien	(list
86359243Sobrien	 (cons "break"  csh-completion-type-misc)
86459243Sobrien	 (cons "breaksw"  csh-completion-type-misc)
86559243Sobrien	 (cons "case"  csh-completion-type-misc)
86659243Sobrien	 (cons "continue"  csh-completion-type-misc)
86759243Sobrien	 (cons "endif"  csh-completion-type-misc)
86859243Sobrien	 (cons "exit"  csh-completion-type-misc)
86959243Sobrien	 (cons "foreach"  csh-completion-type-misc)
87059243Sobrien	 (cons "if"  csh-completion-type-misc)
87159243Sobrien	 (cons "while"  csh-completion-type-misc))))
87259243Sobrien
87359243Sobrien(defun csh-eol-point ()
87459243Sobrien  (save-excursion
87559243Sobrien    (end-of-line)
87659243Sobrien    (point)))
87759243Sobrien
87859243Sobrien(defun csh-pickup-all ()
87959243Sobrien  "Pickup all completions in buffer."
88059243Sobrien  (interactive)
88159243Sobrien  (csh-pickup-completion-driver (point-min) (point-max) t))
88259243Sobrien
88359243Sobrien(defun csh-pickup-completion (regexp type match pmin pmax)
88459243Sobrien  "Pickup completion in region and addit to the list, if not already
88559243Sobrienthere."
88659243Sobrien  (let ((i 0) kw obj)
88759243Sobrien    (save-excursion
88859243Sobrien      (goto-char pmin)
88959243Sobrien      (while (and
89059243Sobrien	      (re-search-forward regexp pmax t)
89159243Sobrien	      (match-beginning match)
89259243Sobrien	      (setq kw  (buffer-substring
89359243Sobrien			 (match-beginning match)
89459243Sobrien			 (match-end match))))
89559243Sobrien	(progn
89659243Sobrien	  (setq obj (assoc kw csh-completion-list))
89759243Sobrien	  (if (or (equal nil obj)
89859243Sobrien		  (and (not (equal nil obj))
89959243Sobrien		       (not (= type (cdr obj)))))
90059243Sobrien	      (progn
90159243Sobrien		(setq i (1+ i))
90259243Sobrien		(csh-addto-alist kw type))))))
90359243Sobrien    i))
90459243Sobrien
90559243Sobrien(defun csh-pickup-completion-driver (pmin pmax message)
90659243Sobrien  "Driver routine for csh-pickup-completion."
90759243Sobrien  (if message
90859243Sobrien      (message "pickup completion..."))
90959243Sobrien  (let* (
91059243Sobrien	 (i1
91159243Sobrien	  (csh-pickup-completion  csh-completion-regexp-var
91259243Sobrien				 csh-completion-type-var
91359243Sobrien				 csh-completion-match-var
91459243Sobrien				 pmin pmax))
91559243Sobrien	 (i2
91659243Sobrien	  (csh-pickup-completion  csh-completion-regexp-var2
91759243Sobrien				 csh-completion-type-var
91859243Sobrien				 csh-completion-match-var2
91959243Sobrien				 pmin pmax))
92059243Sobrien	 (i3
92159243Sobrien	  (csh-pickup-completion  csh-completion-regexp-function
92259243Sobrien				 csh-completion-type-function
92359243Sobrien				 csh-completion-match-function
92459243Sobrien				 pmin pmax)))
92559243Sobrien    (if message
92659243Sobrien	(message "pickup %d variables and %d functions." (+ i1 i2) i3))))
92759243Sobrien
92859243Sobrien(defun csh-pickup-this-line ()
92959243Sobrien  "Pickup all completions in current line."
93059243Sobrien  (interactive)
93159243Sobrien  (csh-pickup-completion-driver (csh-bol-point) (csh-eol-point) nil))
93259243Sobrien
93359243Sobrien
93459243Sobrien(provide 'csh-mode)
93559243Sobrien;;; csh-mode.el ends here
936