Kernel part of bluetooth stack ported by Dmitry Komissaroff. Very much work
[dragonfly.git] / contrib / tcsh / csh-mode.el
blob20fee71287fcbaf9d4521877a81f4535b511ff2f
1 ;; csh-mode.el --- csh (and tcsh) script editing mode for Emacs.
2 ;;
3 ;; Version: 1.2
4 ;; Date: April 2, 1999
5 ;; Maintainer: Dan Harkless <dan@wave.eng.uci.edu>
6 ;;
7 ;; Description:
8 ;; csh and tcsh script editing mode for Emacs.
9 ;;
10 ;; Installation:
11 ;; Put csh-mode.el in some directory in your load-path and load it.
13 ;; Usage:
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.
18 ;;
19 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
21 ;; Author key:
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.)
43 ;; [...]
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")
52 (defvar csh-mode-hook
53 '(lambda ()
54 (auto-fill-mode 1))
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
84 (defvar csh-indent 4
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
94 csh-like languages.")
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
102 insert a tab.")
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"
161 ;; tcsh-keywords
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.
171 (list
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)
178 ;; Label references.
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
212 ;; Keywords.
213 (cons (concat
214 "\\(\\<"
215 (mapconcat 'identity csh-keywords "\\>\\|\\<")
216 "\\>\\)")
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")
232 (if csh-mode-map
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.
284 Top line is 1."
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."
293 (let*
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)
299 (progn
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
306 (progn
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))
313 (progn
314 (setq balance-list (cons (point) balance-list))
315 (goto-char match-point) ;; beginning of compound cmd
316 (setq nest-list
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))
323 (progn
324 (goto-char match-point)
325 (cons nest-column (csh-current-line)))
326 nest-list))
327 (t nil)
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)
338 (level))
339 (save-excursion
340 (forward-line -1)
341 (while (and (not (bobp))
342 (null level))
343 (if (and (not (looking-at "^\\s *$"))
344 (not (save-excursion
345 (forward-line -1)
346 (beginning-of-line)
347 (looking-at csh-multiline-re)))
348 (not (looking-at csh-comment-regexp)))
349 (setq level (cons (current-indentation)
350 (csh-current-line)))
351 (forward-line -1)
352 );; if
353 );; while
354 (if (null level)
355 (cons (current-indentation) (csh-current-line))
356 level)
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."
364 (save-excursion
365 (let ((fence-post)
366 (case-fold-search)
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...
372 (save-excursion
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
383 ;; indentation.
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?
393 (save-excursion
394 (goto-line nest-line)
395 (setq fence-post (save-excursion (end-of-line) (point)))
396 (save-excursion
397 (cond
399 ;; Check if we are in a continued statement
400 ((and (looking-at csh-multiline-re)
401 (save-excursion
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
406 ;; opening quote.
407 (progn
408 (re-search-forward "[\'\"]")
409 (forward-char -1))
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)))
416 (current-column))
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
422 ;; case-sensitive.
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)
429 2 csh-indent)
432 ((re-search-forward csh-case-default-re fence-post t)
433 (if (null csh-indent)
434 (progn
435 (goto-char (match-end 1))
436 (+ (current-indentation) 1))
437 (progn
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)
446 (progn
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
460 ;; nester.
461 (t (current-indentation)))
463 ));; excursion over
464 );; Not a case-item
465 );;let
466 );; excursion
467 );; defun
469 (defun csh-indent-command ()
470 "Indent current line relative to containing block and allow for
471 csh-tab-always-indent customization"
472 (interactive)
473 (let (case-fold-search)
474 (cond ((save-excursion
475 (skip-chars-backward " \t")
476 (bolp))
477 (csh-indent-line))
478 (csh-tab-always-indent
479 (save-excursion
480 (csh-indent-line)))
481 (t (insert-tab))
485 (defun csh-indent-line ()
486 "Indent current line as far as it should go according
487 to the syntax/context"
488 (interactive)
489 (let (case-fold-search)
490 (save-excursion
491 (beginning-of-line)
492 (if (bobp)
495 ;; Align this line to current nesting level
496 (let*
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))
504 (if struct-match
505 (setq nester-column struct-match))
506 (if (eq nester-column this-line-level)
508 (beginning-of-line)
509 (let ((beg (point)))
510 (back-to-indentation)
511 (delete-region beg (point)))
512 (indent-to nester-column))
513 );; let*
514 );; if
515 );; excursion
517 ;; Position point on this line
518 (let*
520 (this-line-level (current-indentation))
521 (this-bol (save-excursion
522 (beginning-of-line)
523 (point)))
524 (this-point (- (point) this-bol))
526 (cond ((> this-line-level this-point);; point in initial white space
527 (back-to-indentation))
528 (t nil)
529 );; cond
530 );; let*
531 );; let
532 );; defun
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.
538 (save-excursion
539 (let (csh-match-and-tell
540 (endmark (copy-marker end)))
542 (goto-char start)
543 (beginning-of-line)
544 (setq start (point))
545 (while (> (marker-position endmark) start)
546 (if (not (and (bolp) (eolp)))
547 (csh-indent-line))
548 (forward-line 1)
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
558 current line"
559 (skip-chars-forward " \t") ;; skip tabs as well as spaces
560 (buffer-substring (point)
561 (progn
562 (end-of-line 1)
563 (point))))
565 (defun csh-looking-at-label ()
566 "Return true if current line is a label (not the default: case label)."
567 (and
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."
574 (interactive)
575 (let* ((case-fold-search)
576 (nest-list
577 (save-excursion
578 (csh-get-compound-level begin-re end-re (point))
580 ) ;; bindings
581 (if (null nest-list)
582 (progn
583 (if csh-match-and-tell
584 (message "No matching compound command"))
585 nil) ;; Propagate a miss.
586 (let* (
587 (nest-level (car nest-list))
588 (match-line (cdr nest-list))
589 ) ;; bindings
590 (if csh-match-and-tell
591 (save-excursion
592 (goto-line match-line)
593 (message "Matched ... %s" (csh-line-to-string))
594 ) ;; excursion
595 ) ;; if csh-match-and-tell
596 nest-level ;;Propagate a hit.
597 ) ;; let*
598 ) ;; if
599 ) ;; let*
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
606 the minibuffer"
607 (interactive)
608 (let (case-fold-search)
609 (save-excursion
610 (beginning-of-line)
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.
625 (t nil)
626 );; cond
630 ;;;###autoload
631 (defun csh-mode ()
632 "csh-mode 2.0 - Major mode for editing csh and tcsh scripts.
633 Special key bindings and commands:
634 \\{csh-mode-map}
635 Variables controlling indentation style:
636 csh-indent
637 Indentation of csh statements with respect to containing block.
638 Default value is 4.
639 csh-case-indent
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.
643 csh-case-item-offset
644 Additional indentation for case items within a case statement.
645 Default value is 2.
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
650 insert a tab.
651 csh-match-and-tell
652 If non-nil echo in the minibuffer the matching compound command
653 for the \"done\", \"}\", \"fi\", or \"endsw\". Default value is t.
655 csh-comment-regexp
656 Regular expression used to recognize comments. Customize to support
657 csh-like languages. Default value is \"\^\\\\s *#\".
659 Style Guide.
660 By setting
661 (setq csh-indent default-tab-width)
663 The following style is obtained:
665 if [ -z $foo ]
666 then
667 bar # <-- csh-group-offset is additive to csh-indent
671 By setting
672 (setq csh-indent default-tab-width)
673 (setq csh-group-offset (- 0 csh-indent))
675 The following style is obtained:
677 if [ -z $foo ]
678 then
683 By setting
684 (setq csh-case-item-offset 1)
685 (setq csh-case-indent nil)
687 The following style is obtained:
689 case x in *
690 foo) bar # <-- csh-case-item-offset
691 baz;; # <-- csh-case-indent aligns with \")\"
692 foobar) foo
693 bar;;
694 endsw
696 By setting
697 (setq csh-case-item-offset 1)
698 (setq csh-case-indent 6)
700 The following style is obtained:
702 case x in *
703 foo) bar # <-- csh-case-item-offset
704 baz;; # <-- csh-case-indent
705 foobar) foo
706 bar;;
707 endsw
710 Installation:
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
716 (list
717 '(\"\\\\.csh$\" . csh-mode)
718 '(\"\\\\.login\" . csh-mode))))
720 (setq csh-mode-hook
721 (function (lambda ()
722 (font-lock-mode 1) ;; font-lock the buffer
723 (setq csh-indent 8)
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
727 )))"
728 (interactive)
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)
754 ) ;; defun
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 ()
768 (save-excursion
769 (beginning-of-line)
770 (point)))
772 (defun csh-complete-symbol ()
773 "Perform completion."
774 (interactive)
775 (let* ((case-fold-search)
776 (end (point))
777 (beg (unwind-protect
778 (save-excursion
779 (backward-sexp 1)
780 (while (= (char-syntax (following-char)) ?\')
781 (forward-char 1))
782 (point))))
783 (pattern (buffer-substring beg end))
784 (predicate
786 ;; ` or $( mark a function
788 (save-excursion
789 (goto-char beg)
790 (if (or
791 (save-excursion
792 (backward-char 1)
793 (looking-at "`"))
794 (save-excursion
795 (backward-char 2)
796 (looking-at "\\$(")))
797 (function (lambda (sym)
798 (equal (cdr sym) csh-completion-type-function)))
800 ;; a $, ${ or ${# mark a variable
802 (if (or
803 (save-excursion
804 (backward-char 1)
805 (looking-at "\\$"))
806 (save-excursion
807 (backward-char 2)
808 (looking-at "\\${"))
809 (save-excursion
810 (backward-char 3)
811 (looking-at "\\${#")))
812 (function (lambda (sym)
813 (equal (cdr 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 ?
826 ((null completion)
827 (message "Can't find completion for \"%s\"" pattern))
829 ;; insert
831 ((not (string= pattern completion))
832 (delete-region beg end)
833 (insert completion))
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))
840 (string ""))
841 (while list
842 (progn
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 ()
851 (interactive)
852 (let (case-fold-search)
853 (csh-completion-list-init)
854 (csh-pickup-all)))
857 ;; init the list
859 (defun csh-completion-list-init ()
860 (interactive)
861 (setq csh-completion-list
862 (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 ()
874 (save-excursion
875 (end-of-line)
876 (point)))
878 (defun csh-pickup-all ()
879 "Pickup all completions in buffer."
880 (interactive)
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
885 there."
886 (let ((i 0) kw obj)
887 (save-excursion
888 (goto-char pmin)
889 (while (and
890 (re-search-forward regexp pmax t)
891 (match-beginning match)
892 (setq kw (buffer-substring
893 (match-beginning match)
894 (match-end match))))
895 (progn
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)))))
900 (progn
901 (setq i (1+ i))
902 (csh-addto-alist kw type))))))
905 (defun csh-pickup-completion-driver (pmin pmax message)
906 "Driver routine for csh-pickup-completion."
907 (if message
908 (message "pickup completion..."))
909 (let* (
911 (csh-pickup-completion csh-completion-regexp-var
912 csh-completion-type-var
913 csh-completion-match-var
914 pmin pmax))
916 (csh-pickup-completion csh-completion-regexp-var2
917 csh-completion-type-var
918 csh-completion-match-var2
919 pmin pmax))
921 (csh-pickup-completion csh-completion-regexp-function
922 csh-completion-type-function
923 csh-completion-match-function
924 pmin pmax)))
925 (if message
926 (message "pickup %d variables and %d functions." (+ i1 i2) i3))))
928 (defun csh-pickup-this-line ()
929 "Pickup all completions in current line."
930 (interactive)
931 (csh-pickup-completion-driver (csh-bol-point) (csh-eol-point) nil))
934 (provide 'csh-mode)
935 ;;; csh-mode.el ends here