1 ;; csh-mode.el --- csh (and tcsh) script editing mode for Emacs.
5 ;; Maintainer: Dan Harkless <dan@wave.eng.uci.edu>
8 ;; csh and tcsh script editing mode for Emacs.
11 ;; Put csh-mode.el in some directory in your load-path and load it.
14 ;; This major mode assists shell script writers with indentation
15 ;; control and control structure construct matching in much the same
16 ;; fashion as other programming language modes. Invoke describe-mode
17 ;; for more information.
19 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
22 ;; DH - Dan Harkless <dan@wave.eng.uci.edu>
23 ;; CM - Carlo Migliorini <migliorini@sodalia.it>
24 ;; JR - Jack Repenning <jackr@sgi.com>
25 ;; GE - Gary Ellison <Gary.F.Ellison@att.com>
27 ;; *** REVISION HISTORY ***
29 ;; DATE MOD. BY REASON FOR MODIFICATION
30 ;; --------- -- --------------------------------------------------------------
31 ;; 2 Apr 99 DH 1.2: Noticed an out-of-date comment referencing .bashrc etc.
32 ;; 11 Dec 96 DH 1.1: ksh-mode just indented continuation lines by 1 space.
33 ;; csh-mode looks at the first line and indents properly to line
34 ;; up under the open-paren, quote, or command.
35 ;; 11 Dec 96 DH Added fontification for history substitutions.
36 ;; 10 Dec 96 DH Added indentation and fontification for labels. Added
37 ;; fontification for variables and backquoted strings.
38 ;; 9 Dec 96 DH 1.0: Brought csh-mode up to the level of functionality of
39 ;; the original ksh-mode.
40 ;; 7 Oct 96 CM 0.1: Hacked ksh-mode.el into minimally functional csh-mode.el
41 ;; by doing search-and-replace and some keyword changes.
42 ;; 8 Aug 96 JR (Last modification to ksh-mode 2.6.)
44 ;; 19 Jun 92 GE (Conception of ksh-mode.)
46 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
49 (defconst csh-mode-version "1.2"
50 "*Version number of this version of csh-mode")
55 "Hook to run each time csh-mode is entered.")
59 ;; -------------------------------------------> Variables controlling completion
61 (defvar csh-completion-list '())
62 (make-variable-buffer-local 'csh-completion-list)
63 (set-default 'csh-completion-list '())
65 ;; -type- : type number, 0:misc, 1:variable, 2:function
66 ;; -regexp-: regexp used to parse the script
67 ;; -match- : used by match-beginning/end to pickup target
69 (defvar csh-completion-type-misc 0)
70 (defvar csh-completion-regexp-var "\\([A-Za-z_0-9]+\\)=")
71 (defvar csh-completion-type-var 1)
72 (defvar csh-completion-match-var 1)
73 (defvar csh-completion-regexp-var2 "\\$\\({\\|{#\\)?\\([A-Za-z_0-9]+\\)[#%:}]?")
74 (defvar csh-completion-match-var2 2)
75 (defvar csh-completion-regexp-function
76 "\\(function\\)?[ \t]*\\([A-Za-z_0-9]+\\)[ \t]*([ \t]*)")
77 (defvar csh-completion-type-function 2)
78 (defvar csh-completion-match-function 2)
82 ;; ------------------------------------> Variables controlling indentation style
85 "*Indentation of csh statements with respect to containing block. A value
86 of nil indicates compound list keyword \(\"do\" and \"then\"\) alignment.")
88 (defvar csh-case-item-offset csh-indent
89 "*Additional indentation for case items within a case statement.")
90 (defvar csh-case-indent nil
91 "*Additional indentation for statements under case items.")
92 (defvar csh-comment-regexp "^\\s *#"
93 "*Regular expression used to recognize comments. Customize to support
95 (defvar csh-match-and-tell t
96 "*If non-nil echo in the minibuffer the matching compound command
97 for the \"breaksw\", \"end\", or \"endif\".")
98 (defvar csh-tab-always-indent t
99 "*Controls the operation of the TAB key. If t (the default), always
100 reindent the current line. If nil, indent the current line only if
101 point is at the left margin or in the line's indentation; otherwise
106 ;; ----------------------------------------> Constants containing syntax regexps
108 (defconst csh-case-default-re
109 "^\\s *\\(case\\|default\\)\\b"
110 "Regexp used to locate grouping keywords case and default" )
112 (defconst csh-case-item-re "^\\s *\\(case .*\\|default\\):"
113 "Regexp used to match case-items")
115 (defconst csh-end-re "^\\s *end\\b"
116 "Regexp used to match keyword: end")
118 (defconst csh-endif-re "^\\s *endif\\b"
119 "Regexp used to match keyword: endif")
121 (defconst csh-endsw-re "^\\s *endsw\\b"
122 "Regexp used to match keyword: endsw")
124 (defconst csh-else-re "^\\s *\\belse\\(\\b\\|$\\)"
125 "Regexp used to match keyword: else")
127 (defconst csh-else-if-re "^\\s *\\belse if\\(\\b\\|$\\)"
128 "Regexp used to match keyword pair: else if")
130 (defconst csh-if-re "^\\s *if\\b.+\\(\\\\\\|\\bthen\\b\\)"
131 "Regexp used to match non-one-line if statements")
133 (defconst csh-iteration-keywords-re "^[^#\n]*\\s\"*\\b\\(while\\|foreach\\)\\b"
134 "Match one of the keywords: while, foreach")
136 (defconst csh-keywords-re
137 "^\\s *\\(else\\b\\|foreach\\b\\|if\\b.+\\(\\\\\\|\\bthen\\b\\)\\|switch\\b\\|while\\b\\)"
138 "Regexp used to detect compound command keywords: else, if, foreach, while")
140 (defconst csh-label-re "^\\s *[^!#$\n ]+:"
141 "Regexp used to match flow-control labels")
143 (defconst csh-multiline-re "^.*\\\\$"
144 "Regexp used to match a line with a statement using more lines.")
146 (defconst csh-switch-re "^\\s *switch\\b"
147 "Regexp used to match keyword: switch")
151 ;; ----------------------------------------> Variables controlling fontification
153 (defvar csh-keywords '("@" "alias" "bg" "break" "breaksw" "case" "cd" "chdir"
154 "continue" "default" "dirs" "echo" "else" "end" "endif"
155 "endsw" "eval" "exec" "exit" "fg" "foreach" "glob" "goto"
156 "hashstat" "history" "if" "jobs" "kill" "limit" "login"
157 "logout" "limit" "notify" "onintr" "popd" "printenv"
158 "pushd" "rehash" "repeat" "set" "setenv" "shift" "source"
159 "stop" "suspend" "switch" "then" "time" "umask" "unalias"
160 "unhash" "unlimit" "unset" "unsetenv" "wait" "while"
162 "alloc" "bindkey" "builtins" "complete" "echotc"
163 "filetest" "hup" "log" "ls-F" "nice" "nohup" "sched"
164 "settc" "setty" "telltc" "uncomplete" "where" "which"))
166 (require 'font-lock) ; need to do this before referring to font-lock-* below
168 (defconst csh-font-lock-keywords
169 ;; NOTE: The order of some of the items in this list is significant. Do not
170 ;; alphabetize or otherwise blindly rearrange.
172 ;; Comments on line 1, which are missed by syntactic fontification.
173 '("^#.*" 0 font-lock-comment-face)
175 ;; Label definitions (1 means first parenthesized exp in regexp).
176 '("^\\s *\\([^!#$\n ]+\\):" 1 font-lock-function-name-face)
179 '("\\b\\(goto\\|onintr\\)\\b\\s +\\([^!#$ \n\t]+\\)"
180 2 font-lock-function-name-face)
182 ;; Variable settings.
183 '("\\(@\\|set\\|setenv\\)\\s +\\([0-9A-Za-z_]+\\b\\)"
184 2 font-lock-variable-name-face)
186 ;; Variable references not inside of strings.
187 '("\\$[][0-9A-Za-z_#:?]+" 0 font-lock-variable-name-face)
189 ;; Backquoted strings. 'keep' means to just fontify non-fontified text.
190 '("`\\(.*\\)`" 1 font-lock-reference-face keep)
192 ;; NOTE: The following variables need to be anchored to the beginning of
193 ;; line to prevent re-fontifying text in comments. Due to this, we
194 ;; can only catch a finite number of occurrences. More can be added.
195 ;; The 't' means to override previous fontification.
197 ;; Variable references inside of " strings.
198 '("^[^#\n]*\".*\\(\\$[][0-9A-Za-z_#:?]+\\).*\""
199 1 font-lock-variable-name-face t) ; 1
200 '("^[^#\n]*\".*\\(\\$[][0-9A-Za-z_#:?]+\\).*\\$[][0-9A-Za-z_#:?]+.*\""
201 1 font-lock-variable-name-face t) ; 2
202 (cons (concat "^[^#\n]*\".*\\(\\$[][0-9A-Za-z_#:?]+\\).*"
203 "\\$[][0-9A-Za-z_#:?]+.*\\$[][0-9A-Za-z_#:?]+.*\"")
204 (list 1 font-lock-variable-name-face t)) ; 3
206 ;; History substitutions.
207 '("^![^~= \n\t]+" 0 font-lock-reference-face t) ; BOL
208 '("^[^#\n]*[^#\\\n]\\(![^~= \n\t]+\\)" 1 font-lock-reference-face t) ; 1
209 '("^[^#\n]*[^#\\\n]\\(![^~= \n\t]+\\).*![^~= \n\t]+"
210 1 font-lock-reference-face t) ; 2
215 (mapconcat 'identity csh-keywords "\\>\\|\\<")
220 (put 'csh-mode 'font-lock-keywords 'csh-font-lock-keywords)
224 ;; -------------------------------------------------------> Mode-specific tables
226 (defvar csh-mode-abbrev-table nil
227 "Abbrev table used while in csh mode.")
228 (define-abbrev-table 'csh-mode-abbrev-table ())
230 (defvar csh-mode-map nil
231 "Keymap used in csh mode")
234 (setq csh-mode-map (make-sparse-keymap))
235 ;;(define-key csh-mode-map "\177" 'backward-delete-char-untabify)
236 (define-key csh-mode-map "\C-c\t" 'csh-completion-init-and-pickup)
237 (define-key csh-mode-map "\C-j" 'reindent-then-newline-and-indent)
238 (define-key csh-mode-map "\e\t" 'csh-complete-symbol)
239 (define-key csh-mode-map "\n" 'reindent-then-newline-and-indent)
240 (define-key csh-mode-map '[return] 'reindent-then-newline-and-indent)
241 (define-key csh-mode-map "\t" 'csh-indent-command)
242 ;;(define-key csh-mode-map "\t" 'csh-indent-line)
245 (defvar csh-mode-syntax-table nil
246 "Syntax table used while in csh mode.")
247 (if csh-mode-syntax-table
248 ;; If it's already set up, don't change it.
250 ;; Else, create it from the standard table and modify entries that need to be.
251 (setq csh-mode-syntax-table (make-syntax-table))
252 (modify-syntax-entry ?& "." csh-mode-syntax-table) ; & -punctuation
253 (modify-syntax-entry ?* "." csh-mode-syntax-table) ; * -punctuation
254 (modify-syntax-entry ?- "." csh-mode-syntax-table) ; - -punctuation
255 (modify-syntax-entry ?= "." csh-mode-syntax-table) ; = -punctuation
256 (modify-syntax-entry ?+ "." csh-mode-syntax-table) ; + -punctuation
257 (modify-syntax-entry ?| "." csh-mode-syntax-table) ; | -punctuation
258 (modify-syntax-entry ?< "." csh-mode-syntax-table) ; < -punctuation
259 (modify-syntax-entry ?> "." csh-mode-syntax-table) ; > -punctuation
260 (modify-syntax-entry ?/ "." csh-mode-syntax-table) ; / -punctuation
261 (modify-syntax-entry ?\' "\"" csh-mode-syntax-table) ; ' -string quote
262 (modify-syntax-entry ?. "w" csh-mode-syntax-table) ; . -word constituent
263 (modify-syntax-entry ?? "w" csh-mode-syntax-table) ; ? -word constituent
265 ;; \n - comment ender, first character of 2-char comment sequence
266 (modify-syntax-entry ?\n "> 1" csh-mode-syntax-table) ; # -word constituent
268 ;; - whitespace, first character of 2-char comment sequence
269 (modify-syntax-entry ? " 1" csh-mode-syntax-table) ;
271 ;; \t - whitespace, first character of 2-char comment sequence
272 (modify-syntax-entry ?\t " 1" csh-mode-syntax-table) ; # -word constituent
274 ;; # - word constituent, second character of 2-char comment sequence
275 (modify-syntax-entry ?# "w 2" csh-mode-syntax-table) ; # -word constituent
280 ;; ------------------------------------------------------------------> Functions
282 (defun csh-current-line ()
283 "Return the vertical position of point in the buffer.
285 (+ (count-lines (point-min) (point))
286 (if (= (current-column) 0) 1 0))
289 (defun csh-get-compound-level
290 (begin-re end-re anchor-point &optional balance-list)
291 "Determine how much to indent this structure. Return a list (level line)
292 of the matching compound command or nil if no match found."
294 (;; Locate the next compound begin keyword bounded by point-min
295 (match-point (if (re-search-backward begin-re (point-min) t)
296 (match-beginning 0) 0))
297 (nest-column (if (zerop match-point)
300 (goto-char match-point)
301 (current-indentation))))
302 (nest-list (cons 0 0)) ;; sentinel cons since cdr is >= 1
304 (if (zerop match-point)
305 nil ;; graceful exit from recursion
307 (if (nlistp balance-list)
308 (setq balance-list (list)))
309 ;; Now search forward from matching start keyword for end keyword
310 (while (and (consp nest-list) (zerop (cdr nest-list))
311 (re-search-forward end-re anchor-point t))
312 (if (not (memq (point) balance-list))
314 (setq balance-list (cons (point) balance-list))
315 (goto-char match-point) ;; beginning of compound cmd
317 (csh-get-compound-level begin-re end-re
318 anchor-point balance-list))
321 (cond ((consp nest-list)
322 (if (zerop (cdr nest-list))
324 (goto-char match-point)
325 (cons nest-column (csh-current-line)))
334 (defun csh-get-nest-level ()
335 "Return a 2 element list (nest-level nest-line) describing where the
336 current line should nest."
337 (let ((case-fold-search)
341 (while (and (not (bobp))
343 (if (and (not (looking-at "^\\s *$"))
347 (looking-at csh-multiline-re)))
348 (not (looking-at csh-comment-regexp)))
349 (setq level (cons (current-indentation)
355 (cons (current-indentation) (csh-current-line))
361 (defun csh-get-nester-column (nest-line)
362 "Return the column to indent to with respect to nest-line taking
363 into consideration keywords and other nesting constructs."
367 (start-line (csh-current-line)))
369 ;; Handle case item indentation constructs for this line
370 (cond ((looking-at csh-case-item-re)
371 ;; This line is a case item...
373 (goto-line nest-line)
374 (let ((fence-post (save-excursion (end-of-line) (point))))
375 (cond ((re-search-forward csh-switch-re fence-post t)
376 ;; If this is the first case under the switch, indent.
377 (goto-char (match-beginning 0))
378 (+ (current-indentation) csh-case-item-offset))
380 ((re-search-forward csh-case-item-re fence-post t)
381 ;; If this is another case right under a previous case
382 ;; without intervening code, stay at the same
384 (goto-char (match-beginning 0))
385 (current-indentation))
388 ;; Else, this is a new case. Outdent.
389 (- (current-indentation) csh-case-item-offset))
392 (t;; Not a case-item. What to do relative to the nest-line?
394 (goto-line nest-line)
395 (setq fence-post (save-excursion (end-of-line) (point)))
399 ;; Check if we are in a continued statement
400 ((and (looking-at csh-multiline-re)
402 (goto-line (1- start-line))
403 (looking-at csh-multiline-re)))
404 (if (looking-at ".*[\'\"]\\\\")
405 ;; If this is a continued string, indent under
408 (re-search-forward "[\'\"]")
410 (if (looking-at ".*([^\)\n]*\\\\")
411 ;; Else if this is a continued parenthesized
412 ;; list, indent after paren.
413 (re-search-forward "(" fence-post t)
414 ;; Else, indent after whitespace after first word.
415 (re-search-forward "[^ \t]+[ \t]+" fence-post t)))
418 ;; In order to locate the column of the keyword,
419 ;; which might be embedded within a case-item,
420 ;; it is necessary to use re-search-forward.
421 ;; Search by literal case, since shell is
423 ((re-search-forward csh-keywords-re fence-post t)
424 (goto-char (match-beginning 1))
425 (if (looking-at csh-switch-re)
426 (+ (current-indentation) csh-case-item-offset)
427 (+ (current-indentation)
428 (if (null csh-indent)
432 ((re-search-forward csh-case-default-re fence-post t)
433 (if (null csh-indent)
435 (goto-char (match-end 1))
436 (+ (current-indentation) 1))
438 (goto-char (match-beginning 1))
439 (+ (current-indentation) csh-indent))
443 ;; Now detect first statement under a case item
444 ((looking-at csh-case-item-re)
445 (if (null csh-case-indent)
447 (re-search-forward csh-case-item-re fence-post t)
448 (goto-char (match-end 1))
449 (+ (current-column) 1))
450 (+ (current-indentation) csh-case-indent)))
453 ;; If this is the first statement under a control-flow
454 ;; label, indent one level.
455 ((csh-looking-at-label)
456 (+ (current-indentation) csh-indent))
458 ;; This is hosed when using current-column
459 ;; and there is a multi-command expression as the
461 (t (current-indentation)))
469 (defun csh-indent-command ()
470 "Indent current line relative to containing block and allow for
471 csh-tab-always-indent customization"
473 (let (case-fold-search)
474 (cond ((save-excursion
475 (skip-chars-backward " \t")
478 (csh-tab-always-indent
485 (defun csh-indent-line ()
486 "Indent current line as far as it should go according
487 to the syntax/context"
489 (let (case-fold-search)
495 ;; Align this line to current nesting level
498 (level-list (csh-get-nest-level)) ; Where to nest against
499 ;; (last-line-level (car level-list))
500 (this-line-level (current-indentation))
501 (nester-column (csh-get-nester-column (cdr level-list)))
502 (struct-match (csh-match-structure-and-reindent))
505 (setq nester-column struct-match))
506 (if (eq nester-column this-line-level)
510 (back-to-indentation)
511 (delete-region beg (point)))
512 (indent-to nester-column))
517 ;; Position point on this line
520 (this-line-level (current-indentation))
521 (this-bol (save-excursion
524 (this-point (- (point) this-bol))
526 (cond ((> this-line-level this-point);; point in initial white space
527 (back-to-indentation))
534 (defun csh-indent-region (start end)
535 "From start to end, indent each line."
536 ;; The algorithm is just moving through the region line by line with
537 ;; the match noise turned off. Only modifies nonempty lines.
539 (let (csh-match-and-tell
540 (endmark (copy-marker end)))
545 (while (> (marker-position endmark) start)
546 (if (not (and (bolp) (eolp)))
549 (setq start (point)))
551 (set-marker endmark nil)
556 (defun csh-line-to-string ()
557 "From point, construct a string from all characters on
559 (skip-chars-forward " \t") ;; skip tabs as well as spaces
560 (buffer-substring (point)
565 (defun csh-looking-at-label ()
566 "Return true if current line is a label (not the default: case label)."
568 (looking-at csh-label-re)
569 (not (looking-at "^\\s *default:"))))
571 (defun csh-match-indent-level (begin-re end-re)
572 "Match the compound command and indent. Return nil on no match,
573 indentation to use for this line otherwise."
575 (let* ((case-fold-search)
578 (csh-get-compound-level begin-re end-re (point))
583 (if csh-match-and-tell
584 (message "No matching compound command"))
585 nil) ;; Propagate a miss.
587 (nest-level (car nest-list))
588 (match-line (cdr nest-list))
590 (if csh-match-and-tell
592 (goto-line match-line)
593 (message "Matched ... %s" (csh-line-to-string))
595 ) ;; if csh-match-and-tell
596 nest-level ;;Propagate a hit.
600 ) ;; defun csh-match-indent-level
602 (defun csh-match-structure-and-reindent ()
603 "If the current line matches one of the indenting keywords
604 or one of the control structure ending keywords then reindent. Also
605 if csh-match-and-tell is non-nil the matching structure will echo in
608 (let (case-fold-search)
611 (cond ((looking-at csh-else-re)
612 (csh-match-indent-level csh-if-re csh-endif-re))
613 ((looking-at csh-else-if-re)
614 (csh-match-indent-level csh-if-re csh-endif-re))
615 ((looking-at csh-endif-re)
616 (csh-match-indent-level csh-if-re csh-endif-re))
617 ((looking-at csh-end-re)
618 (csh-match-indent-level csh-iteration-keywords-re csh-end-re))
619 ((looking-at csh-endsw-re)
620 (csh-match-indent-level csh-switch-re csh-endsw-re))
621 ((csh-looking-at-label)
622 ;; Flush control-flow labels left since they don't nest.
632 "csh-mode 2.0 - Major mode for editing csh and tcsh scripts.
633 Special key bindings and commands:
635 Variables controlling indentation style:
637 Indentation of csh statements with respect to containing block.
640 Additional indentation for statements under case items.
641 Default value is nil which will align the statements one position
642 past the \")\" of the pattern.
644 Additional indentation for case items within a case statement.
646 csh-tab-always-indent
647 Controls the operation of the TAB key. If t (the default), always
648 reindent the current line. If nil, indent the current line only if
649 point is at the left margin or in the line's indentation; otherwise
652 If non-nil echo in the minibuffer the matching compound command
653 for the \"done\", \"}\", \"fi\", or \"endsw\". Default value is t.
656 Regular expression used to recognize comments. Customize to support
657 csh-like languages. Default value is \"\^\\\\s *#\".
661 (setq csh-indent default-tab-width)
663 The following style is obtained:
667 bar # <-- csh-group-offset is additive to csh-indent
672 (setq csh-indent default-tab-width)
673 (setq csh-group-offset (- 0 csh-indent))
675 The following style is obtained:
684 (setq csh-case-item-offset 1)
685 (setq csh-case-indent nil)
687 The following style is obtained:
690 foo) bar # <-- csh-case-item-offset
691 baz;; # <-- csh-case-indent aligns with \")\"
697 (setq csh-case-item-offset 1)
698 (setq csh-case-indent 6)
700 The following style is obtained:
703 foo) bar # <-- csh-case-item-offset
704 baz;; # <-- csh-case-indent
711 Put csh-mode.el in some directory in your load-path.
712 Put the following forms in your .emacs file.
714 (setq auto-mode-alist
715 (append auto-mode-alist
717 '(\"\\\\.csh$\" . csh-mode)
718 '(\"\\\\.login\" . csh-mode))))
722 (font-lock-mode 1) ;; font-lock the buffer
724 (setq csh-tab-always-indent t)
725 (setq csh-match-and-tell t)
726 (setq csh-align-to-keyword t) ;; Turn on keyword alignment
729 (kill-all-local-variables)
730 (use-local-map csh-mode-map)
731 (setq major-mode 'csh-mode)
732 (setq mode-name "Csh")
733 (setq local-abbrev-table csh-mode-abbrev-table)
734 (set-syntax-table csh-mode-syntax-table)
735 (make-local-variable 'indent-line-function)
736 (setq indent-line-function 'csh-indent-line)
737 (make-local-variable 'indent-region-function)
738 (setq indent-region-function 'csh-indent-region)
739 (make-local-variable 'comment-start)
740 (setq comment-start "# ")
741 (make-local-variable 'comment-end)
742 (setq comment-end "")
743 (make-local-variable 'comment-column)
744 (setq comment-column 32)
745 (make-local-variable 'comment-start-skip)
746 (setq comment-start-skip "#+ *")
748 ;; config font-lock mode
749 (make-local-variable 'font-lock-keywords)
750 (setq font-lock-keywords csh-font-lock-keywords)
752 ;; Let the user customize
753 (run-hooks 'csh-mode-hook)
757 ;; Completion code supplied by Haavard Rue <hrue@imf.unit.no>.
760 ;; add a completion with a given type to the list
762 (defun csh-addto-alist (completion type)
763 (setq csh-completion-list
764 (append csh-completion-list
765 (list (cons completion type)))))
767 (defun csh-bol-point ()
772 (defun csh-complete-symbol ()
773 "Perform completion."
775 (let* ((case-fold-search)
780 (while (= (char-syntax (following-char)) ?\')
783 (pattern (buffer-substring beg end))
786 ;; ` or $( mark a function
796 (looking-at "\\$(")))
797 (function (lambda (sym)
798 (equal (cdr sym) csh-completion-type-function)))
800 ;; a $, ${ or ${# mark a variable
811 (looking-at "\\${#")))
812 (function (lambda (sym)
814 csh-completion-type-var)))
816 ;; don't know. use 'em all
818 (function (lambda (sym) t))))))
820 (completion (try-completion pattern csh-completion-list predicate)))
822 (cond ((eq completion t))
824 ;; oops, what is this ?
827 (message "Can't find completion for \"%s\"" pattern))
831 ((not (string= pattern completion))
832 (delete-region beg end)
835 ;; write possible completion in the minibuffer,
836 ;; use this instead of a seperate buffer (usual)
839 (let ((list (all-completions pattern csh-completion-list predicate))
843 (setq string (concat string (format "%s " (car list))))
844 (setq list (cdr list))))
845 (message string))))))
848 ;; init the list and pickup all
850 (defun csh-completion-init-and-pickup ()
852 (let (case-fold-search)
853 (csh-completion-list-init)
859 (defun csh-completion-list-init ()
861 (setq csh-completion-list
863 (cons "break" csh-completion-type-misc)
864 (cons "breaksw" csh-completion-type-misc)
865 (cons "case" csh-completion-type-misc)
866 (cons "continue" csh-completion-type-misc)
867 (cons "endif" csh-completion-type-misc)
868 (cons "exit" csh-completion-type-misc)
869 (cons "foreach" csh-completion-type-misc)
870 (cons "if" csh-completion-type-misc)
871 (cons "while" csh-completion-type-misc))))
873 (defun csh-eol-point ()
878 (defun csh-pickup-all ()
879 "Pickup all completions in buffer."
881 (csh-pickup-completion-driver (point-min) (point-max) t))
883 (defun csh-pickup-completion (regexp type match pmin pmax)
884 "Pickup completion in region and addit to the list, if not already
890 (re-search-forward regexp pmax t)
891 (match-beginning match)
892 (setq kw (buffer-substring
893 (match-beginning match)
896 (setq obj (assoc kw csh-completion-list))
897 (if (or (equal nil obj)
898 (and (not (equal nil obj))
899 (not (= type (cdr obj)))))
902 (csh-addto-alist kw type))))))
905 (defun csh-pickup-completion-driver (pmin pmax message)
906 "Driver routine for csh-pickup-completion."
908 (message "pickup completion..."))
911 (csh-pickup-completion csh-completion-regexp-var
912 csh-completion-type-var
913 csh-completion-match-var
916 (csh-pickup-completion csh-completion-regexp-var2
917 csh-completion-type-var
918 csh-completion-match-var2
921 (csh-pickup-completion csh-completion-regexp-function
922 csh-completion-type-function
923 csh-completion-match-function
926 (message "pickup %d variables and %d functions." (+ i1 i2) i3))))
928 (defun csh-pickup-this-line ()
929 "Pickup all completions in current line."
931 (csh-pickup-completion-driver (csh-bol-point) (csh-eol-point) nil))
935 ;;; csh-mode.el ends here