xref: /freebsd-src/contrib/tcsh/csh-mode.el (revision b2d5d167edc56df47468e5836b8129dfd3d0369a)
1c80476e4SDavid E. O'Brien;; csh-mode.el --- csh (and tcsh) script editing mode for Emacs.
2c80476e4SDavid E. O'Brien;;
3c80476e4SDavid E. O'Brien;; Version:    1.2
4c80476e4SDavid E. O'Brien;; Date:       April 2, 1999
5*b2d5d167SMark Peek;; Maintainer: Dan Harkless <software@harkless.org>
6c80476e4SDavid E. O'Brien;;
7c80476e4SDavid E. O'Brien;; Description:
8c80476e4SDavid E. O'Brien;;   csh and tcsh script editing mode for Emacs.
9c80476e4SDavid E. O'Brien;;
10c80476e4SDavid E. O'Brien;; Installation:
11c80476e4SDavid E. O'Brien;;   Put csh-mode.el in some directory in your load-path and load it.
12c80476e4SDavid E. O'Brien;;
13c80476e4SDavid E. O'Brien;; Usage:
14c80476e4SDavid E. O'Brien;;   This major mode assists shell script writers with indentation
15c80476e4SDavid E. O'Brien;;   control and control structure construct matching in much the same
16c80476e4SDavid E. O'Brien;;   fashion as other programming language modes. Invoke describe-mode
17c80476e4SDavid E. O'Brien;;   for more information.
18c80476e4SDavid E. O'Brien;;
19c80476e4SDavid E. O'Brien;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
20c80476e4SDavid E. O'Brien;;
21c80476e4SDavid E. O'Brien;; Author key:
22*b2d5d167SMark Peek;;   DH - Dan Harkless     <software@harkless.org>
23c80476e4SDavid E. O'Brien;;   CM - Carlo Migliorini <migliorini@sodalia.it>
24c80476e4SDavid E. O'Brien;;   JR - Jack Repenning   <jackr@sgi.com>
25c80476e4SDavid E. O'Brien;;   GE - Gary Ellison     <Gary.F.Ellison@att.com>
26c80476e4SDavid E. O'Brien;;
27c80476e4SDavid E. O'Brien;; *** REVISION HISTORY ***
28c80476e4SDavid E. O'Brien;;
29c80476e4SDavid E. O'Brien;; DATE MOD.  BY  REASON FOR MODIFICATION
30c80476e4SDavid E. O'Brien;; ---------  --  --------------------------------------------------------------
31c80476e4SDavid E. O'Brien;;  2 Apr 99  DH  1.2: Noticed an out-of-date comment referencing .bashrc etc.
32c80476e4SDavid E. O'Brien;; 11 Dec 96  DH  1.1: ksh-mode just indented continuation lines by 1 space.
33c80476e4SDavid E. O'Brien;;                csh-mode looks at the first line and indents properly to line
34c80476e4SDavid E. O'Brien;;                up under the open-paren, quote, or command.
35c80476e4SDavid E. O'Brien;; 11 Dec 96  DH  Added fontification for history substitutions.
36c80476e4SDavid E. O'Brien;; 10 Dec 96  DH  Added indentation and fontification for labels.  Added
37c80476e4SDavid E. O'Brien;;                fontification for variables and backquoted strings.
38c80476e4SDavid E. O'Brien;;  9 Dec 96  DH  1.0: Brought csh-mode up to the level of functionality of
39c80476e4SDavid E. O'Brien;;                the original ksh-mode.
40c80476e4SDavid E. O'Brien;;  7 Oct 96  CM  0.1: Hacked ksh-mode.el into minimally functional csh-mode.el
41c80476e4SDavid E. O'Brien;;                by doing search-and-replace and some keyword changes.
42c80476e4SDavid E. O'Brien;;  8 Aug 96  JR  (Last modification to ksh-mode 2.6.)
43c80476e4SDavid E. O'Brien;;                [...]
44c80476e4SDavid E. O'Brien;; 19 Jun 92  GE  (Conception of ksh-mode.)
45c80476e4SDavid E. O'Brien;;
46c80476e4SDavid E. O'Brien;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
47c80476e4SDavid E. O'Brien
48c80476e4SDavid E. O'Brien
49c80476e4SDavid E. O'Brien(defconst csh-mode-version "1.2"
50c80476e4SDavid E. O'Brien  "*Version number of this version of csh-mode")
51c80476e4SDavid E. O'Brien
52c80476e4SDavid E. O'Brien(defvar csh-mode-hook
53c80476e4SDavid E. O'Brien  '(lambda ()
54c80476e4SDavid E. O'Brien     (auto-fill-mode 1))
55c80476e4SDavid E. O'Brien  "Hook to run each time csh-mode is entered.")
56c80476e4SDavid E. O'Brien
57c80476e4SDavid E. O'Brien
58c80476e4SDavid E. O'Brien;;
59c80476e4SDavid E. O'Brien;; -------------------------------------------> Variables controlling completion
60c80476e4SDavid E. O'Brien;;
61c80476e4SDavid E. O'Brien(defvar csh-completion-list '())
62c80476e4SDavid E. O'Brien(make-variable-buffer-local 'csh-completion-list)
63c80476e4SDavid E. O'Brien(set-default 'csh-completion-list  '())
64c80476e4SDavid E. O'Brien;;
65c80476e4SDavid E. O'Brien;; -type-  : type number, 0:misc, 1:variable, 2:function
66c80476e4SDavid E. O'Brien;; -regexp-: regexp used to parse the script
67c80476e4SDavid E. O'Brien;; -match- : used by match-beginning/end to pickup target
68c80476e4SDavid E. O'Brien;;
69c80476e4SDavid E. O'Brien(defvar csh-completion-type-misc 0)
70c80476e4SDavid E. O'Brien(defvar csh-completion-regexp-var "\\([A-Za-z_0-9]+\\)=")
71c80476e4SDavid E. O'Brien(defvar csh-completion-type-var 1)
72c80476e4SDavid E. O'Brien(defvar csh-completion-match-var 1)
73c80476e4SDavid E. O'Brien(defvar csh-completion-regexp-var2 "\\$\\({\\|{#\\)?\\([A-Za-z_0-9]+\\)[#%:}]?")
74c80476e4SDavid E. O'Brien(defvar csh-completion-match-var2 2)
75c80476e4SDavid E. O'Brien(defvar csh-completion-regexp-function
76c80476e4SDavid E. O'Brien  "\\(function\\)?[ \t]*\\([A-Za-z_0-9]+\\)[ \t]*([ \t]*)")
77c80476e4SDavid E. O'Brien(defvar csh-completion-type-function 2)
78c80476e4SDavid E. O'Brien(defvar csh-completion-match-function 2)
79c80476e4SDavid E. O'Brien
80c80476e4SDavid E. O'Brien
81c80476e4SDavid E. O'Brien;;
82c80476e4SDavid E. O'Brien;; ------------------------------------> Variables controlling indentation style
83c80476e4SDavid E. O'Brien;;
84c80476e4SDavid E. O'Brien(defvar csh-indent 4
85c80476e4SDavid E. O'Brien  "*Indentation of csh statements with respect to containing block. A value
86c80476e4SDavid E. O'Brienof nil indicates compound list keyword \(\"do\" and \"then\"\) alignment.")
87c80476e4SDavid E. O'Brien
88c80476e4SDavid E. O'Brien(defvar csh-case-item-offset csh-indent
89c80476e4SDavid E. O'Brien  "*Additional indentation for case items within a case statement.")
90c80476e4SDavid E. O'Brien(defvar csh-case-indent nil
91c80476e4SDavid E. O'Brien  "*Additional indentation for statements under case items.")
92c80476e4SDavid E. O'Brien(defvar csh-comment-regexp "^\\s *#"
93c80476e4SDavid E. O'Brien  "*Regular expression used to recognize comments. Customize to support
94c80476e4SDavid E. O'Briencsh-like languages.")
95c80476e4SDavid E. O'Brien(defvar csh-match-and-tell t
96c80476e4SDavid E. O'Brien  "*If non-nil echo in the minibuffer the matching compound command
97c80476e4SDavid E. O'Brienfor the \"breaksw\", \"end\", or \"endif\".")
98c80476e4SDavid E. O'Brien(defvar csh-tab-always-indent t
99c80476e4SDavid E. O'Brien  "*Controls the operation of the TAB key. If t (the default), always
100c80476e4SDavid E. O'Brienreindent the current line.  If nil, indent the current line only if
101c80476e4SDavid E. O'Brienpoint is at the left margin or in the line's indentation; otherwise
102c80476e4SDavid E. O'Brieninsert a tab.")
103c80476e4SDavid E. O'Brien
104c80476e4SDavid E. O'Brien
105c80476e4SDavid E. O'Brien;;
106c80476e4SDavid E. O'Brien;; ----------------------------------------> Constants containing syntax regexps
107c80476e4SDavid E. O'Brien;;
108c80476e4SDavid E. O'Brien(defconst csh-case-default-re
109c80476e4SDavid E. O'Brien  "^\\s *\\(case\\|default\\)\\b"
110c80476e4SDavid E. O'Brien  "Regexp used to locate grouping keywords case and default" )
111c80476e4SDavid E. O'Brien
112c80476e4SDavid E. O'Brien(defconst csh-case-item-re "^\\s *\\(case .*\\|default\\):"
113c80476e4SDavid E. O'Brien  "Regexp used to match case-items")
114c80476e4SDavid E. O'Brien
115c80476e4SDavid E. O'Brien(defconst csh-end-re "^\\s *end\\b"
116c80476e4SDavid E. O'Brien  "Regexp used to match keyword: end")
117c80476e4SDavid E. O'Brien
118c80476e4SDavid E. O'Brien(defconst csh-endif-re "^\\s *endif\\b"
119c80476e4SDavid E. O'Brien  "Regexp used to match keyword: endif")
120c80476e4SDavid E. O'Brien
121c80476e4SDavid E. O'Brien(defconst csh-endsw-re "^\\s *endsw\\b"
122c80476e4SDavid E. O'Brien  "Regexp used to match keyword: endsw")
123c80476e4SDavid E. O'Brien
124c80476e4SDavid E. O'Brien(defconst csh-else-re "^\\s *\\belse\\(\\b\\|$\\)"
125c80476e4SDavid E. O'Brien  "Regexp used to match keyword: else")
126c80476e4SDavid E. O'Brien
127c80476e4SDavid E. O'Brien(defconst csh-else-if-re "^\\s *\\belse if\\(\\b\\|$\\)"
128c80476e4SDavid E. O'Brien  "Regexp used to match keyword pair: else if")
129c80476e4SDavid E. O'Brien
130c80476e4SDavid E. O'Brien(defconst csh-if-re "^\\s *if\\b.+\\(\\\\\\|\\bthen\\b\\)"
131c80476e4SDavid E. O'Brien  "Regexp used to match non-one-line if statements")
132c80476e4SDavid E. O'Brien
133c80476e4SDavid E. O'Brien(defconst csh-iteration-keywords-re "^[^#\n]*\\s\"*\\b\\(while\\|foreach\\)\\b"
134c80476e4SDavid E. O'Brien  "Match one of the keywords: while, foreach")
135c80476e4SDavid E. O'Brien
136c80476e4SDavid E. O'Brien(defconst csh-keywords-re
137c80476e4SDavid E. O'Brien  "^\\s *\\(else\\b\\|foreach\\b\\|if\\b.+\\(\\\\\\|\\bthen\\b\\)\\|switch\\b\\|while\\b\\)"
138c80476e4SDavid E. O'Brien  "Regexp used to detect compound command keywords: else, if, foreach, while")
139c80476e4SDavid E. O'Brien
140c80476e4SDavid E. O'Brien(defconst csh-label-re "^\\s *[^!#$\n ]+:"
141c80476e4SDavid E. O'Brien  "Regexp used to match flow-control labels")
142c80476e4SDavid E. O'Brien
143c80476e4SDavid E. O'Brien(defconst csh-multiline-re "^.*\\\\$"
144c80476e4SDavid E. O'Brien  "Regexp used to match a line with a statement using more lines.")
145c80476e4SDavid E. O'Brien
146c80476e4SDavid E. O'Brien(defconst csh-switch-re "^\\s *switch\\b"
147c80476e4SDavid E. O'Brien  "Regexp used to match keyword: switch")
148c80476e4SDavid E. O'Brien
149c80476e4SDavid E. O'Brien
150c80476e4SDavid E. O'Brien;;
151c80476e4SDavid E. O'Brien;; ----------------------------------------> Variables controlling fontification
152c80476e4SDavid E. O'Brien;;
153c80476e4SDavid E. O'Brien(defvar csh-keywords '("@" "alias" "bg" "break" "breaksw" "case" "cd" "chdir"
154c80476e4SDavid E. O'Brien		       "continue" "default" "dirs" "echo" "else" "end" "endif"
155c80476e4SDavid E. O'Brien		       "endsw" "eval" "exec" "exit" "fg" "foreach" "glob" "goto"
156c80476e4SDavid E. O'Brien		       "hashstat" "history" "if" "jobs" "kill" "limit" "login"
157c80476e4SDavid E. O'Brien		       "logout" "limit" "notify" "onintr" "popd" "printenv"
158c80476e4SDavid E. O'Brien		       "pushd" "rehash" "repeat" "set" "setenv" "shift" "source"
159c80476e4SDavid E. O'Brien		       "stop" "suspend" "switch" "then" "time" "umask" "unalias"
160c80476e4SDavid E. O'Brien		       "unhash" "unlimit" "unset" "unsetenv" "wait" "while"
161c80476e4SDavid E. O'Brien		       ;; tcsh-keywords
162c80476e4SDavid E. O'Brien		       "alloc" "bindkey" "builtins" "complete" "echotc"
163c80476e4SDavid E. O'Brien		       "filetest" "hup" "log" "ls-F" "nice" "nohup" "sched"
164c80476e4SDavid E. O'Brien		       "settc" "setty" "telltc" "uncomplete" "where" "which"))
165c80476e4SDavid E. O'Brien
166c80476e4SDavid E. O'Brien(require 'font-lock)  ; need to do this before referring to font-lock-* below
167c80476e4SDavid E. O'Brien
168c80476e4SDavid E. O'Brien(defconst csh-font-lock-keywords
169c80476e4SDavid E. O'Brien  ;; NOTE:  The order of some of the items in this list is significant.  Do not
170c80476e4SDavid E. O'Brien  ;;        alphabetize or otherwise blindly rearrange.
171c80476e4SDavid E. O'Brien  (list
172c80476e4SDavid E. O'Brien   ;; Comments on line 1, which are missed by syntactic fontification.
173c80476e4SDavid E. O'Brien   '("^#.*" 0 font-lock-comment-face)
174c80476e4SDavid E. O'Brien
175c80476e4SDavid E. O'Brien   ;; Label definitions (1 means first parenthesized exp in regexp).
176c80476e4SDavid E. O'Brien   '("^\\s *\\([^!#$\n ]+\\):" 1 font-lock-function-name-face)
177c80476e4SDavid E. O'Brien
178c80476e4SDavid E. O'Brien   ;; Label references.
179c80476e4SDavid E. O'Brien   '("\\b\\(goto\\|onintr\\)\\b\\s +\\([^!#$ \n\t]+\\)"
180c80476e4SDavid E. O'Brien     2 font-lock-function-name-face)
181c80476e4SDavid E. O'Brien
182c80476e4SDavid E. O'Brien   ;; Variable settings.
183c80476e4SDavid E. O'Brien   '("\\(@\\|set\\|setenv\\)\\s +\\([0-9A-Za-z_]+\\b\\)"
184c80476e4SDavid E. O'Brien     2 font-lock-variable-name-face)
185c80476e4SDavid E. O'Brien
186c80476e4SDavid E. O'Brien   ;; Variable references not inside of strings.
187c80476e4SDavid E. O'Brien   '("\\$[][0-9A-Za-z_#:?]+" 0 font-lock-variable-name-face)
188c80476e4SDavid E. O'Brien
189c80476e4SDavid E. O'Brien   ;; Backquoted strings.  'keep' means to just fontify non-fontified text.
190c80476e4SDavid E. O'Brien   '("`\\(.*\\)`" 1 font-lock-reference-face keep)
191c80476e4SDavid E. O'Brien
192c80476e4SDavid E. O'Brien   ;; NOTE:  The following variables need to be anchored to the beginning of
193c80476e4SDavid E. O'Brien   ;;        line to prevent re-fontifying text in comments.  Due to this, we
194c80476e4SDavid E. O'Brien   ;;        can only catch a finite number of occurrences.  More can be added.
195c80476e4SDavid E. O'Brien   ;;        The 't' means to override previous fontification.
196c80476e4SDavid E. O'Brien   ;;
197c80476e4SDavid E. O'Brien   ;;        Variable references inside of " strings.
198c80476e4SDavid E. O'Brien   '("^[^#\n]*\".*\\(\\$[][0-9A-Za-z_#:?]+\\).*\""
199c80476e4SDavid E. O'Brien     1 font-lock-variable-name-face t)                                    ; 1
200c80476e4SDavid E. O'Brien   '("^[^#\n]*\".*\\(\\$[][0-9A-Za-z_#:?]+\\).*\\$[][0-9A-Za-z_#:?]+.*\""
201c80476e4SDavid E. O'Brien     1 font-lock-variable-name-face t)                                    ; 2
202c80476e4SDavid E. O'Brien   (cons (concat "^[^#\n]*\".*\\(\\$[][0-9A-Za-z_#:?]+\\).*"
203c80476e4SDavid E. O'Brien		 "\\$[][0-9A-Za-z_#:?]+.*\\$[][0-9A-Za-z_#:?]+.*\"")
204c80476e4SDavid E. O'Brien	 (list 1 font-lock-variable-name-face t))                         ; 3
205c80476e4SDavid E. O'Brien   ;;
206c80476e4SDavid E. O'Brien   ;;        History substitutions.
207c80476e4SDavid E. O'Brien   '("^![^~= \n\t]+" 0 font-lock-reference-face t)                      ; BOL
208c80476e4SDavid E. O'Brien   '("^[^#\n]*[^#\\\n]\\(![^~= \n\t]+\\)" 1 font-lock-reference-face t) ; 1
209c80476e4SDavid E. O'Brien   '("^[^#\n]*[^#\\\n]\\(![^~= \n\t]+\\).*![^~= \n\t]+"
210c80476e4SDavid E. O'Brien     1 font-lock-reference-face t)                                      ; 2
211c80476e4SDavid E. O'Brien
212c80476e4SDavid E. O'Brien   ;; Keywords.
213c80476e4SDavid E. O'Brien   (cons (concat
214c80476e4SDavid E. O'Brien	  "\\(\\<"
215c80476e4SDavid E. O'Brien	  (mapconcat 'identity csh-keywords "\\>\\|\\<")
216c80476e4SDavid E. O'Brien	  "\\>\\)")
217c80476e4SDavid E. O'Brien	 1)
218c80476e4SDavid E. O'Brien   ))
219c80476e4SDavid E. O'Brien
220c80476e4SDavid E. O'Brien(put 'csh-mode 'font-lock-keywords 'csh-font-lock-keywords)
221c80476e4SDavid E. O'Brien
222c80476e4SDavid E. O'Brien
223c80476e4SDavid E. O'Brien;;
224c80476e4SDavid E. O'Brien;; -------------------------------------------------------> Mode-specific tables
225c80476e4SDavid E. O'Brien;;
226c80476e4SDavid E. O'Brien(defvar csh-mode-abbrev-table nil
227c80476e4SDavid E. O'Brien  "Abbrev table used while in csh mode.")
228c80476e4SDavid E. O'Brien(define-abbrev-table 'csh-mode-abbrev-table ())
229c80476e4SDavid E. O'Brien
230c80476e4SDavid E. O'Brien(defvar csh-mode-map nil
231c80476e4SDavid E. O'Brien  "Keymap used in csh mode")
232c80476e4SDavid E. O'Brien(if csh-mode-map
233c80476e4SDavid E. O'Brien    ()
234c80476e4SDavid E. O'Brien  (setq csh-mode-map (make-sparse-keymap))
235c80476e4SDavid E. O'Brien;;(define-key csh-mode-map "\177"    'backward-delete-char-untabify)
236c80476e4SDavid E. O'Brien  (define-key csh-mode-map "\C-c\t"  'csh-completion-init-and-pickup)
237c80476e4SDavid E. O'Brien  (define-key csh-mode-map "\C-j"    'reindent-then-newline-and-indent)
238c80476e4SDavid E. O'Brien  (define-key csh-mode-map "\e\t"    'csh-complete-symbol)
239c80476e4SDavid E. O'Brien  (define-key csh-mode-map "\n"      'reindent-then-newline-and-indent)
240c80476e4SDavid E. O'Brien  (define-key csh-mode-map '[return] 'reindent-then-newline-and-indent)
241c80476e4SDavid E. O'Brien  (define-key csh-mode-map "\t"      'csh-indent-command)
242c80476e4SDavid E. O'Brien;;(define-key csh-mode-map "\t"      'csh-indent-line)
243c80476e4SDavid E. O'Brien  )
244c80476e4SDavid E. O'Brien
245c80476e4SDavid E. O'Brien(defvar csh-mode-syntax-table nil
246c80476e4SDavid E. O'Brien  "Syntax table used while in csh mode.")
247c80476e4SDavid E. O'Brien(if csh-mode-syntax-table
248c80476e4SDavid E. O'Brien    ;; If it's already set up, don't change it.
249c80476e4SDavid E. O'Brien    ()
250c80476e4SDavid E. O'Brien  ;; Else, create it from the standard table and modify entries that need to be.
251c80476e4SDavid E. O'Brien  (setq csh-mode-syntax-table (make-syntax-table))
252c80476e4SDavid E. O'Brien  (modify-syntax-entry ?&  "."  csh-mode-syntax-table) ; & -punctuation
253c80476e4SDavid E. O'Brien  (modify-syntax-entry ?*  "."  csh-mode-syntax-table) ; * -punctuation
254c80476e4SDavid E. O'Brien  (modify-syntax-entry ?-  "."  csh-mode-syntax-table) ; - -punctuation
255c80476e4SDavid E. O'Brien  (modify-syntax-entry ?=  "."  csh-mode-syntax-table) ; = -punctuation
256c80476e4SDavid E. O'Brien  (modify-syntax-entry ?+  "."  csh-mode-syntax-table) ; + -punctuation
257c80476e4SDavid E. O'Brien  (modify-syntax-entry ?|  "."  csh-mode-syntax-table) ; | -punctuation
258c80476e4SDavid E. O'Brien  (modify-syntax-entry ?<  "."  csh-mode-syntax-table) ; < -punctuation
259c80476e4SDavid E. O'Brien  (modify-syntax-entry ?>  "."  csh-mode-syntax-table) ; > -punctuation
260c80476e4SDavid E. O'Brien  (modify-syntax-entry ?/  "."  csh-mode-syntax-table) ; / -punctuation
261c80476e4SDavid E. O'Brien  (modify-syntax-entry ?\' "\"" csh-mode-syntax-table) ; ' -string quote
262c80476e4SDavid E. O'Brien  (modify-syntax-entry ?.  "w"  csh-mode-syntax-table) ; . -word constituent
263c80476e4SDavid E. O'Brien  (modify-syntax-entry ??  "w"  csh-mode-syntax-table) ; ? -word constituent
264c80476e4SDavid E. O'Brien
265c80476e4SDavid E. O'Brien  ;; \n - comment ender, first character of 2-char comment sequence
266c80476e4SDavid E. O'Brien  (modify-syntax-entry ?\n "> 1" csh-mode-syntax-table) ; # -word constituent
267c80476e4SDavid E. O'Brien
268c80476e4SDavid E. O'Brien  ;;   - whitespace, first character of 2-char comment sequence
269c80476e4SDavid E. O'Brien  (modify-syntax-entry ?   "  1" csh-mode-syntax-table) ;
270c80476e4SDavid E. O'Brien
271c80476e4SDavid E. O'Brien  ;; \t - whitespace, first character of 2-char comment sequence
272c80476e4SDavid E. O'Brien  (modify-syntax-entry ?\t "  1" csh-mode-syntax-table) ; # -word constituent
273c80476e4SDavid E. O'Brien
274c80476e4SDavid E. O'Brien  ;; # - word constituent, second character of 2-char comment sequence
275c80476e4SDavid E. O'Brien  (modify-syntax-entry ?#  "w 2" csh-mode-syntax-table) ; # -word constituent
276c80476e4SDavid E. O'Brien  )
277c80476e4SDavid E. O'Brien
278c80476e4SDavid E. O'Brien
279c80476e4SDavid E. O'Brien;;
280c80476e4SDavid E. O'Brien;; ------------------------------------------------------------------> Functions
281c80476e4SDavid E. O'Brien;;
282c80476e4SDavid E. O'Brien(defun csh-current-line ()
283c80476e4SDavid E. O'Brien  "Return the vertical position of point in the buffer.
284c80476e4SDavid E. O'BrienTop line is 1."
285c80476e4SDavid E. O'Brien  (+ (count-lines (point-min) (point))
286c80476e4SDavid E. O'Brien     (if (= (current-column) 0) 1 0))
287c80476e4SDavid E. O'Brien  )
288c80476e4SDavid E. O'Brien
289c80476e4SDavid E. O'Brien(defun csh-get-compound-level
290c80476e4SDavid E. O'Brien  (begin-re end-re anchor-point &optional balance-list)
291c80476e4SDavid E. O'Brien  "Determine how much to indent this structure. Return a list (level line)
292c80476e4SDavid E. O'Brienof the matching compound command or nil if no match found."
293c80476e4SDavid E. O'Brien  (let*
294c80476e4SDavid E. O'Brien      (;; Locate the next compound begin keyword bounded by point-min
295c80476e4SDavid E. O'Brien       (match-point (if (re-search-backward begin-re (point-min) t)
296c80476e4SDavid E. O'Brien			(match-beginning 0) 0))
297c80476e4SDavid E. O'Brien       (nest-column (if (zerop match-point)
298c80476e4SDavid E. O'Brien			1
299c80476e4SDavid E. O'Brien		      (progn
300c80476e4SDavid E. O'Brien			(goto-char match-point)
301c80476e4SDavid E. O'Brien			(current-indentation))))
302c80476e4SDavid E. O'Brien       (nest-list (cons 0 0))    ;; sentinel cons since cdr is >= 1
303c80476e4SDavid E. O'Brien       )
304c80476e4SDavid E. O'Brien    (if (zerop match-point)
305c80476e4SDavid E. O'Brien	nil ;; graceful exit from recursion
306c80476e4SDavid E. O'Brien      (progn
307c80476e4SDavid E. O'Brien	(if (nlistp balance-list)
308c80476e4SDavid E. O'Brien	    (setq balance-list (list)))
309c80476e4SDavid E. O'Brien	;; Now search forward from matching start keyword for end keyword
310c80476e4SDavid E. O'Brien	(while (and (consp nest-list) (zerop (cdr nest-list))
311c80476e4SDavid E. O'Brien		    (re-search-forward end-re anchor-point t))
312c80476e4SDavid E. O'Brien	  (if (not (memq (point) balance-list))
313c80476e4SDavid E. O'Brien	      (progn
314c80476e4SDavid E. O'Brien		(setq balance-list (cons (point) balance-list))
315c80476e4SDavid E. O'Brien		(goto-char match-point)  ;; beginning of compound cmd
316c80476e4SDavid E. O'Brien		(setq nest-list
317c80476e4SDavid E. O'Brien		      (csh-get-compound-level begin-re end-re
318c80476e4SDavid E. O'Brien					     anchor-point balance-list))
319c80476e4SDavid E. O'Brien		)))
320c80476e4SDavid E. O'Brien
321c80476e4SDavid E. O'Brien	(cond ((consp nest-list)
322c80476e4SDavid E. O'Brien	       (if (zerop (cdr nest-list))
323c80476e4SDavid E. O'Brien		 (progn
324c80476e4SDavid E. O'Brien		   (goto-char match-point)
325c80476e4SDavid E. O'Brien		   (cons nest-column (csh-current-line)))
326c80476e4SDavid E. O'Brien		 nest-list))
327c80476e4SDavid E. O'Brien	      (t nil)
328c80476e4SDavid E. O'Brien	      )
329c80476e4SDavid E. O'Brien	)
330c80476e4SDavid E. O'Brien      )
331c80476e4SDavid E. O'Brien    )
332c80476e4SDavid E. O'Brien  )
333c80476e4SDavid E. O'Brien
334c80476e4SDavid E. O'Brien(defun csh-get-nest-level ()
335c80476e4SDavid E. O'Brien  "Return a 2 element list (nest-level nest-line) describing where the
336c80476e4SDavid E. O'Briencurrent line should nest."
337c80476e4SDavid E. O'Brien  (let ((case-fold-search)
338c80476e4SDavid E. O'Brien    	(level))
339c80476e4SDavid E. O'Brien    (save-excursion
340c80476e4SDavid E. O'Brien      (forward-line -1)
341c80476e4SDavid E. O'Brien      (while (and (not (bobp))
342c80476e4SDavid E. O'Brien		  (null level))
343c80476e4SDavid E. O'Brien	(if (and (not (looking-at "^\\s *$"))
344c80476e4SDavid E. O'Brien 		 (not (save-excursion
345c80476e4SDavid E. O'Brien 			(forward-line -1)
346c80476e4SDavid E. O'Brien 			(beginning-of-line)
347c80476e4SDavid E. O'Brien			(looking-at csh-multiline-re)))
348c80476e4SDavid E. O'Brien		 (not (looking-at csh-comment-regexp)))
349c80476e4SDavid E. O'Brien	    (setq level (cons (current-indentation)
350c80476e4SDavid E. O'Brien			      (csh-current-line)))
351c80476e4SDavid E. O'Brien	  (forward-line -1)
352c80476e4SDavid E. O'Brien	  );; if
353c80476e4SDavid E. O'Brien	);; while
354c80476e4SDavid E. O'Brien      (if (null level)
355c80476e4SDavid E. O'Brien	  (cons (current-indentation) (csh-current-line))
356c80476e4SDavid E. O'Brien	level)
357c80476e4SDavid E. O'Brien      )
358c80476e4SDavid E. O'Brien    )
359c80476e4SDavid E. O'Brien  )
360c80476e4SDavid E. O'Brien
361c80476e4SDavid E. O'Brien(defun csh-get-nester-column (nest-line)
362c80476e4SDavid E. O'Brien  "Return the column to indent to with respect to nest-line taking
363c80476e4SDavid E. O'Brieninto consideration keywords and other nesting constructs."
364c80476e4SDavid E. O'Brien  (save-excursion
365c80476e4SDavid E. O'Brien    (let ((fence-post)
366c80476e4SDavid E. O'Brien	  (case-fold-search)
367c80476e4SDavid E. O'Brien	  (start-line (csh-current-line)))
368c80476e4SDavid E. O'Brien      ;;
369c80476e4SDavid E. O'Brien      ;; Handle case item indentation constructs for this line
370c80476e4SDavid E. O'Brien      (cond ((looking-at csh-case-item-re)
371c80476e4SDavid E. O'Brien	     ;; This line is a case item...
372c80476e4SDavid E. O'Brien	     (save-excursion
373c80476e4SDavid E. O'Brien	       (goto-line nest-line)
374c80476e4SDavid E. O'Brien	       (let ((fence-post (save-excursion (end-of-line) (point))))
375c80476e4SDavid E. O'Brien		 (cond ((re-search-forward csh-switch-re fence-post t)
376c80476e4SDavid E. O'Brien			;; If this is the first case under the switch, indent.
377c80476e4SDavid E. O'Brien			(goto-char (match-beginning 0))
378c80476e4SDavid E. O'Brien			(+ (current-indentation) csh-case-item-offset))
379c80476e4SDavid E. O'Brien
380c80476e4SDavid E. O'Brien		       ((re-search-forward csh-case-item-re fence-post t)
381c80476e4SDavid E. O'Brien			;; If this is another case right under a previous case
382c80476e4SDavid E. O'Brien			;; without intervening code, stay at the same
383c80476e4SDavid E. O'Brien			;; indentation.
384c80476e4SDavid E. O'Brien			(goto-char (match-beginning 0))
385c80476e4SDavid E. O'Brien			(current-indentation))
386c80476e4SDavid E. O'Brien
387c80476e4SDavid E. O'Brien		       (t
388c80476e4SDavid E. O'Brien			;; Else, this is a new case.  Outdent.
389c80476e4SDavid E. O'Brien			(- (current-indentation) csh-case-item-offset))
390c80476e4SDavid E. O'Brien		       )
391c80476e4SDavid E. O'Brien		 )))
392c80476e4SDavid E. O'Brien	    (t;; Not a case-item.  What to do relative to the nest-line?
393c80476e4SDavid E. O'Brien	     (save-excursion
394c80476e4SDavid E. O'Brien	       (goto-line nest-line)
395c80476e4SDavid E. O'Brien	       (setq fence-post (save-excursion (end-of-line) (point)))
396c80476e4SDavid E. O'Brien	       (save-excursion
397c80476e4SDavid E. O'Brien		 (cond
398c80476e4SDavid E. O'Brien		  ;;
399c80476e4SDavid E. O'Brien		  ;; Check if we are in a continued statement
400c80476e4SDavid E. O'Brien		  ((and (looking-at csh-multiline-re)
401c80476e4SDavid E. O'Brien			(save-excursion
402c80476e4SDavid E. O'Brien			  (goto-line (1- start-line))
403c80476e4SDavid E. O'Brien			  (looking-at csh-multiline-re)))
404c80476e4SDavid E. O'Brien		   (if (looking-at ".*[\'\"]\\\\")
405c80476e4SDavid E. O'Brien		       ;; If this is a continued string, indent under
406c80476e4SDavid E. O'Brien		       ;; opening quote.
407c80476e4SDavid E. O'Brien		       (progn
408c80476e4SDavid E. O'Brien			 (re-search-forward "[\'\"]")
409c80476e4SDavid E. O'Brien			 (forward-char -1))
410c80476e4SDavid E. O'Brien		     (if (looking-at ".*([^\)\n]*\\\\")
411c80476e4SDavid E. O'Brien			 ;; Else if this is a continued parenthesized
412c80476e4SDavid E. O'Brien			 ;; list, indent after paren.
413c80476e4SDavid E. O'Brien			 (re-search-forward "(" fence-post t)
414c80476e4SDavid E. O'Brien		       ;; Else, indent after whitespace after first word.
415c80476e4SDavid E. O'Brien		       (re-search-forward "[^ \t]+[ \t]+" fence-post t)))
416c80476e4SDavid E. O'Brien		   (current-column))
417c80476e4SDavid E. O'Brien
418c80476e4SDavid E. O'Brien		  ;; In order to locate the column of the keyword,
419c80476e4SDavid E. O'Brien		  ;; which might be embedded within a case-item,
420c80476e4SDavid E. O'Brien		  ;; it is necessary to use re-search-forward.
421c80476e4SDavid E. O'Brien		  ;; Search by literal case, since shell is
422c80476e4SDavid E. O'Brien		  ;; case-sensitive.
423c80476e4SDavid E. O'Brien		  ((re-search-forward csh-keywords-re fence-post t)
424c80476e4SDavid E. O'Brien		   (goto-char (match-beginning 1))
425c80476e4SDavid E. O'Brien		   (if (looking-at csh-switch-re)
426c80476e4SDavid E. O'Brien		       (+ (current-indentation) csh-case-item-offset)
427c80476e4SDavid E. O'Brien		     (+ (current-indentation)
428c80476e4SDavid E. O'Brien			(if (null csh-indent)
429c80476e4SDavid E. O'Brien			    2 csh-indent)
430c80476e4SDavid E. O'Brien			)))
431c80476e4SDavid E. O'Brien
432c80476e4SDavid E. O'Brien		  ((re-search-forward csh-case-default-re fence-post t)
433c80476e4SDavid E. O'Brien		   (if (null csh-indent)
434c80476e4SDavid E. O'Brien		       (progn
435c80476e4SDavid E. O'Brien			 (goto-char (match-end 1))
436c80476e4SDavid E. O'Brien			 (+ (current-indentation) 1))
437c80476e4SDavid E. O'Brien		     (progn
438c80476e4SDavid E. O'Brien		       (goto-char (match-beginning 1))
439c80476e4SDavid E. O'Brien		       (+ (current-indentation) csh-indent))
440c80476e4SDavid E. O'Brien		     ))
441c80476e4SDavid E. O'Brien
442c80476e4SDavid E. O'Brien		  ;;
443c80476e4SDavid E. O'Brien		  ;; Now detect first statement under a case item
444c80476e4SDavid E. O'Brien		  ((looking-at csh-case-item-re)
445c80476e4SDavid E. O'Brien		   (if (null csh-case-indent)
446c80476e4SDavid E. O'Brien		       (progn
447c80476e4SDavid E. O'Brien			 (re-search-forward csh-case-item-re fence-post t)
448c80476e4SDavid E. O'Brien			 (goto-char (match-end 1))
449c80476e4SDavid E. O'Brien			 (+ (current-column) 1))
450c80476e4SDavid E. O'Brien		     (+ (current-indentation) csh-case-indent)))
451c80476e4SDavid E. O'Brien
452c80476e4SDavid E. O'Brien		  ;;
453c80476e4SDavid E. O'Brien		  ;; If this is the first statement under a control-flow
454c80476e4SDavid E. O'Brien		  ;; label, indent one level.
455c80476e4SDavid E. O'Brien		  ((csh-looking-at-label)
456c80476e4SDavid E. O'Brien		   (+ (current-indentation) csh-indent))
457c80476e4SDavid E. O'Brien
458c80476e4SDavid E. O'Brien		  ;; This is hosed when using current-column
459c80476e4SDavid E. O'Brien		  ;; and there is a multi-command expression as the
460c80476e4SDavid E. O'Brien		  ;; nester.
461c80476e4SDavid E. O'Brien		  (t (current-indentation)))
462c80476e4SDavid E. O'Brien		 )
463c80476e4SDavid E. O'Brien	       ));; excursion over
464c80476e4SDavid E. O'Brien	    );; Not a case-item
465c80476e4SDavid E. O'Brien      );;let
466c80476e4SDavid E. O'Brien    );; excursion
467c80476e4SDavid E. O'Brien  );; defun
468c80476e4SDavid E. O'Brien
469c80476e4SDavid E. O'Brien(defun csh-indent-command ()
470c80476e4SDavid E. O'Brien  "Indent current line relative to containing block and allow for
471c80476e4SDavid E. O'Briencsh-tab-always-indent customization"
472c80476e4SDavid E. O'Brien  (interactive)
473c80476e4SDavid E. O'Brien  (let (case-fold-search)
474c80476e4SDavid E. O'Brien    (cond ((save-excursion
475c80476e4SDavid E. O'Brien	     (skip-chars-backward " \t")
476c80476e4SDavid E. O'Brien	     (bolp))
477c80476e4SDavid E. O'Brien	   (csh-indent-line))
478c80476e4SDavid E. O'Brien	  (csh-tab-always-indent
479c80476e4SDavid E. O'Brien	   (save-excursion
480c80476e4SDavid E. O'Brien	     (csh-indent-line)))
481c80476e4SDavid E. O'Brien	  (t (insert-tab))
482c80476e4SDavid E. O'Brien	  ))
483c80476e4SDavid E. O'Brien  )
484c80476e4SDavid E. O'Brien
485c80476e4SDavid E. O'Brien(defun csh-indent-line ()
486c80476e4SDavid E. O'Brien  "Indent current line as far as it should go according
487c80476e4SDavid E. O'Briento the syntax/context"
488c80476e4SDavid E. O'Brien  (interactive)
489c80476e4SDavid E. O'Brien  (let (case-fold-search)
490c80476e4SDavid E. O'Brien    (save-excursion
491c80476e4SDavid E. O'Brien      (beginning-of-line)
492c80476e4SDavid E. O'Brien      (if (bobp)
493c80476e4SDavid E. O'Brien	  nil
494c80476e4SDavid E. O'Brien	;;
495c80476e4SDavid E. O'Brien	;; Align this line to current nesting level
496c80476e4SDavid E. O'Brien	(let*
497c80476e4SDavid E. O'Brien	    (
498c80476e4SDavid E. O'Brien	     (level-list (csh-get-nest-level)) ; Where to nest against
499c80476e4SDavid E. O'Brien	     ;;           (last-line-level (car level-list))
500c80476e4SDavid E. O'Brien	     (this-line-level (current-indentation))
501c80476e4SDavid E. O'Brien	     (nester-column (csh-get-nester-column (cdr level-list)))
502c80476e4SDavid E. O'Brien	     (struct-match (csh-match-structure-and-reindent))
503c80476e4SDavid E. O'Brien	     )
504c80476e4SDavid E. O'Brien	  (if struct-match
505c80476e4SDavid E. O'Brien	      (setq nester-column struct-match))
506c80476e4SDavid E. O'Brien	  (if (eq nester-column this-line-level)
507c80476e4SDavid E. O'Brien	      nil
508c80476e4SDavid E. O'Brien	    (beginning-of-line)
509c80476e4SDavid E. O'Brien	    (let ((beg (point)))
510c80476e4SDavid E. O'Brien	      (back-to-indentation)
511c80476e4SDavid E. O'Brien	      (delete-region beg (point)))
512c80476e4SDavid E. O'Brien	    (indent-to nester-column))
513c80476e4SDavid E. O'Brien	  );; let*
514c80476e4SDavid E. O'Brien	);; if
515c80476e4SDavid E. O'Brien      );; excursion
516c80476e4SDavid E. O'Brien    ;;
517c80476e4SDavid E. O'Brien    ;; Position point on this line
518c80476e4SDavid E. O'Brien    (let*
519c80476e4SDavid E. O'Brien	(
520c80476e4SDavid E. O'Brien	 (this-line-level (current-indentation))
521c80476e4SDavid E. O'Brien	 (this-bol (save-excursion
522c80476e4SDavid E. O'Brien		     (beginning-of-line)
523c80476e4SDavid E. O'Brien		     (point)))
524c80476e4SDavid E. O'Brien	 (this-point (- (point) this-bol))
525c80476e4SDavid E. O'Brien	 )
526c80476e4SDavid E. O'Brien      (cond ((> this-line-level this-point);; point in initial white space
527c80476e4SDavid E. O'Brien	     (back-to-indentation))
528c80476e4SDavid E. O'Brien	    (t nil)
529c80476e4SDavid E. O'Brien	    );; cond
530c80476e4SDavid E. O'Brien      );; let*
531c80476e4SDavid E. O'Brien    );; let
532c80476e4SDavid E. O'Brien  );; defun
533c80476e4SDavid E. O'Brien
534c80476e4SDavid E. O'Brien(defun csh-indent-region (start end)
535c80476e4SDavid E. O'Brien  "From start to end, indent each line."
536c80476e4SDavid E. O'Brien  ;; The algorithm is just moving through the region line by line with
537c80476e4SDavid E. O'Brien  ;; the match noise turned off.  Only modifies nonempty lines.
538c80476e4SDavid E. O'Brien  (save-excursion
539c80476e4SDavid E. O'Brien    (let (csh-match-and-tell
540c80476e4SDavid E. O'Brien	  (endmark (copy-marker end)))
541c80476e4SDavid E. O'Brien
542c80476e4SDavid E. O'Brien      (goto-char start)
543c80476e4SDavid E. O'Brien      (beginning-of-line)
544c80476e4SDavid E. O'Brien      (setq start (point))
545c80476e4SDavid E. O'Brien      (while (> (marker-position endmark) start)
546c80476e4SDavid E. O'Brien	(if (not (and (bolp) (eolp)))
547c80476e4SDavid E. O'Brien	    (csh-indent-line))
548c80476e4SDavid E. O'Brien	(forward-line 1)
549c80476e4SDavid E. O'Brien	(setq start (point)))
550c80476e4SDavid E. O'Brien
551c80476e4SDavid E. O'Brien      (set-marker endmark nil)
552c80476e4SDavid E. O'Brien      )
553c80476e4SDavid E. O'Brien    )
554c80476e4SDavid E. O'Brien  )
555c80476e4SDavid E. O'Brien
556c80476e4SDavid E. O'Brien(defun csh-line-to-string ()
557c80476e4SDavid E. O'Brien  "From point, construct a string from all characters on
558c80476e4SDavid E. O'Briencurrent line"
559c80476e4SDavid E. O'Brien  (skip-chars-forward " \t") ;; skip tabs as well as spaces
560c80476e4SDavid E. O'Brien  (buffer-substring (point)
561c80476e4SDavid E. O'Brien                    (progn
562c80476e4SDavid E. O'Brien                      (end-of-line 1)
563c80476e4SDavid E. O'Brien                      (point))))
564c80476e4SDavid E. O'Brien
565c80476e4SDavid E. O'Brien(defun csh-looking-at-label ()
566c80476e4SDavid E. O'Brien  "Return true if current line is a label (not the default: case label)."
567c80476e4SDavid E. O'Brien  (and
568c80476e4SDavid E. O'Brien   (looking-at csh-label-re)
569c80476e4SDavid E. O'Brien   (not (looking-at "^\\s *default:"))))
570c80476e4SDavid E. O'Brien
571c80476e4SDavid E. O'Brien(defun csh-match-indent-level (begin-re end-re)
572c80476e4SDavid E. O'Brien  "Match the compound command and indent. Return nil on no match,
573c80476e4SDavid E. O'Brienindentation to use for this line otherwise."
574c80476e4SDavid E. O'Brien  (interactive)
575c80476e4SDavid E. O'Brien  (let* ((case-fold-search)
576c80476e4SDavid E. O'Brien	 (nest-list
577c80476e4SDavid E. O'Brien	  (save-excursion
578c80476e4SDavid E. O'Brien	    (csh-get-compound-level begin-re end-re (point))
579c80476e4SDavid E. O'Brien	    ))
580c80476e4SDavid E. O'Brien	 ) ;; bindings
581c80476e4SDavid E. O'Brien    (if (null nest-list)
582c80476e4SDavid E. O'Brien	(progn
583c80476e4SDavid E. O'Brien	  (if csh-match-and-tell
584c80476e4SDavid E. O'Brien	      (message "No matching compound command"))
585c80476e4SDavid E. O'Brien	  nil) ;; Propagate a miss.
586c80476e4SDavid E. O'Brien      (let* (
587c80476e4SDavid E. O'Brien	     (nest-level (car nest-list))
588c80476e4SDavid E. O'Brien	     (match-line (cdr nest-list))
589c80476e4SDavid E. O'Brien	     ) ;; bindings
590c80476e4SDavid E. O'Brien	(if csh-match-and-tell
591c80476e4SDavid E. O'Brien	    (save-excursion
592c80476e4SDavid E. O'Brien	      (goto-line match-line)
593c80476e4SDavid E. O'Brien	      (message "Matched ... %s" (csh-line-to-string))
594c80476e4SDavid E. O'Brien	      ) ;; excursion
595c80476e4SDavid E. O'Brien	  ) ;; if csh-match-and-tell
596c80476e4SDavid E. O'Brien	nest-level ;;Propagate a hit.
597c80476e4SDavid E. O'Brien	) ;; let*
598c80476e4SDavid E. O'Brien      ) ;; if
599c80476e4SDavid E. O'Brien    ) ;; let*
600c80476e4SDavid E. O'Brien  ) ;; defun csh-match-indent-level
601c80476e4SDavid E. O'Brien
602c80476e4SDavid E. O'Brien(defun csh-match-structure-and-reindent ()
603c80476e4SDavid E. O'Brien  "If the current line matches one of the indenting keywords
604c80476e4SDavid E. O'Brienor one of the control structure ending keywords then reindent. Also
605c80476e4SDavid E. O'Brienif csh-match-and-tell is non-nil the matching structure will echo in
606c80476e4SDavid E. O'Brienthe minibuffer"
607c80476e4SDavid E. O'Brien  (interactive)
608c80476e4SDavid E. O'Brien  (let (case-fold-search)
609c80476e4SDavid E. O'Brien    (save-excursion
610c80476e4SDavid E. O'Brien      (beginning-of-line)
611c80476e4SDavid E. O'Brien      (cond ((looking-at csh-else-re)
612c80476e4SDavid E. O'Brien	     (csh-match-indent-level csh-if-re csh-endif-re))
613c80476e4SDavid E. O'Brien	    ((looking-at csh-else-if-re)
614c80476e4SDavid E. O'Brien	     (csh-match-indent-level csh-if-re csh-endif-re))
615c80476e4SDavid E. O'Brien	    ((looking-at csh-endif-re)
616c80476e4SDavid E. O'Brien	     (csh-match-indent-level csh-if-re csh-endif-re))
617c80476e4SDavid E. O'Brien	    ((looking-at csh-end-re)
618c80476e4SDavid E. O'Brien	     (csh-match-indent-level csh-iteration-keywords-re csh-end-re))
619c80476e4SDavid E. O'Brien	    ((looking-at csh-endsw-re)
620c80476e4SDavid E. O'Brien	     (csh-match-indent-level csh-switch-re csh-endsw-re))
621c80476e4SDavid E. O'Brien	    ((csh-looking-at-label)
622c80476e4SDavid E. O'Brien	     ;; Flush control-flow labels left since they don't nest.
623c80476e4SDavid E. O'Brien	     0)
624c80476e4SDavid E. O'Brien	    ;;
625c80476e4SDavid E. O'Brien	    (t nil)
626c80476e4SDavid E. O'Brien	    );; cond
627c80476e4SDavid E. O'Brien      )
628c80476e4SDavid E. O'Brien    ))
629c80476e4SDavid E. O'Brien
630c80476e4SDavid E. O'Brien;;;###autoload
631c80476e4SDavid E. O'Brien(defun csh-mode ()
632c80476e4SDavid E. O'Brien  "csh-mode 2.0 - Major mode for editing csh and tcsh scripts.
633c80476e4SDavid E. O'BrienSpecial key bindings and commands:
634c80476e4SDavid E. O'Brien\\{csh-mode-map}
635c80476e4SDavid E. O'BrienVariables controlling indentation style:
636c80476e4SDavid E. O'Briencsh-indent
637c80476e4SDavid E. O'Brien    Indentation of csh statements with respect to containing block.
638c80476e4SDavid E. O'Brien    Default value is 4.
639c80476e4SDavid E. O'Briencsh-case-indent
640c80476e4SDavid E. O'Brien    Additional indentation for statements under case items.
641c80476e4SDavid E. O'Brien    Default value is nil which will align the statements one position
642c80476e4SDavid E. O'Brien    past the \")\" of the pattern.
643c80476e4SDavid E. O'Briencsh-case-item-offset
644c80476e4SDavid E. O'Brien    Additional indentation for case items within a case statement.
645c80476e4SDavid E. O'Brien    Default value is 2.
646c80476e4SDavid E. O'Briencsh-tab-always-indent
647c80476e4SDavid E. O'Brien    Controls the operation of the TAB key. If t (the default), always
648c80476e4SDavid E. O'Brien    reindent the current line.  If nil, indent the current line only if
649c80476e4SDavid E. O'Brien    point is at the left margin or in the line's indentation; otherwise
650c80476e4SDavid E. O'Brien    insert a tab.
651c80476e4SDavid E. O'Briencsh-match-and-tell
652c80476e4SDavid E. O'Brien    If non-nil echo in the minibuffer the matching compound command
653c80476e4SDavid E. O'Brien    for the \"done\", \"}\", \"fi\", or \"endsw\". Default value is t.
654c80476e4SDavid E. O'Brien
655c80476e4SDavid E. O'Briencsh-comment-regexp
656c80476e4SDavid E. O'Brien  Regular expression used to recognize comments. Customize to support
657c80476e4SDavid E. O'Brien  csh-like languages. Default value is \"\^\\\\s *#\".
658c80476e4SDavid E. O'Brien
659c80476e4SDavid E. O'BrienStyle Guide.
660c80476e4SDavid E. O'Brien By setting
661c80476e4SDavid E. O'Brien    (setq csh-indent default-tab-width)
662c80476e4SDavid E. O'Brien
663c80476e4SDavid E. O'Brien    The following style is obtained:
664c80476e4SDavid E. O'Brien
665c80476e4SDavid E. O'Brien    if [ -z $foo ]
666c80476e4SDavid E. O'Brien	    then
667c80476e4SDavid E. O'Brien		    bar    # <-- csh-group-offset is additive to csh-indent
668c80476e4SDavid E. O'Brien		    foo
669c80476e4SDavid E. O'Brien    fi
670c80476e4SDavid E. O'Brien
671c80476e4SDavid E. O'Brien By setting
672c80476e4SDavid E. O'Brien    (setq csh-indent default-tab-width)
673c80476e4SDavid E. O'Brien    (setq csh-group-offset (- 0 csh-indent))
674c80476e4SDavid E. O'Brien
675c80476e4SDavid E. O'Brien    The following style is obtained:
676c80476e4SDavid E. O'Brien
677c80476e4SDavid E. O'Brien    if [ -z $foo ]
678c80476e4SDavid E. O'Brien    then
679c80476e4SDavid E. O'Brien	    bar
680c80476e4SDavid E. O'Brien	    foo
681c80476e4SDavid E. O'Brien    fi
682c80476e4SDavid E. O'Brien
683c80476e4SDavid E. O'Brien By setting
684c80476e4SDavid E. O'Brien    (setq csh-case-item-offset 1)
685c80476e4SDavid E. O'Brien    (setq csh-case-indent nil)
686c80476e4SDavid E. O'Brien
687c80476e4SDavid E. O'Brien    The following style is obtained:
688c80476e4SDavid E. O'Brien
689c80476e4SDavid E. O'Brien    case x in *
690c80476e4SDavid E. O'Brien     foo) bar           # <-- csh-case-item-offset
691c80476e4SDavid E. O'Brien          baz;;         # <-- csh-case-indent aligns with \")\"
692c80476e4SDavid E. O'Brien     foobar) foo
693c80476e4SDavid E. O'Brien             bar;;
694c80476e4SDavid E. O'Brien    endsw
695c80476e4SDavid E. O'Brien
696c80476e4SDavid E. O'Brien By setting
697c80476e4SDavid E. O'Brien    (setq csh-case-item-offset 1)
698c80476e4SDavid E. O'Brien    (setq csh-case-indent 6)
699c80476e4SDavid E. O'Brien
700c80476e4SDavid E. O'Brien    The following style is obtained:
701c80476e4SDavid E. O'Brien
702c80476e4SDavid E. O'Brien    case x in *
703c80476e4SDavid E. O'Brien     foo) bar           # <-- csh-case-item-offset
704c80476e4SDavid E. O'Brien           baz;;        # <-- csh-case-indent
705c80476e4SDavid E. O'Brien     foobar) foo
706c80476e4SDavid E. O'Brien           bar;;
707c80476e4SDavid E. O'Brien    endsw
708c80476e4SDavid E. O'Brien
709c80476e4SDavid E. O'Brien
710c80476e4SDavid E. O'BrienInstallation:
711c80476e4SDavid E. O'Brien  Put csh-mode.el in some directory in your load-path.
712c80476e4SDavid E. O'Brien  Put the following forms in your .emacs file.
713c80476e4SDavid E. O'Brien
714c80476e4SDavid E. O'Brien (setq auto-mode-alist
715c80476e4SDavid E. O'Brien      (append auto-mode-alist
716c80476e4SDavid E. O'Brien              (list
717c80476e4SDavid E. O'Brien               '(\"\\\\.csh$\" . csh-mode)
718c80476e4SDavid E. O'Brien               '(\"\\\\.login\" . csh-mode))))
719c80476e4SDavid E. O'Brien
720c80476e4SDavid E. O'Brien (setq csh-mode-hook
721c80476e4SDavid E. O'Brien      (function (lambda ()
722c80476e4SDavid E. O'Brien         (font-lock-mode 1)             ;; font-lock the buffer
723c80476e4SDavid E. O'Brien         (setq csh-indent 8)
724c80476e4SDavid E. O'Brien         (setq csh-tab-always-indent t)
725c80476e4SDavid E. O'Brien         (setq csh-match-and-tell t)
726c80476e4SDavid E. O'Brien         (setq csh-align-to-keyword t)	;; Turn on keyword alignment
727c80476e4SDavid E. O'Brien	 )))"
728c80476e4SDavid E. O'Brien  (interactive)
729c80476e4SDavid E. O'Brien  (kill-all-local-variables)
730c80476e4SDavid E. O'Brien  (use-local-map csh-mode-map)
731c80476e4SDavid E. O'Brien  (setq major-mode 'csh-mode)
732c80476e4SDavid E. O'Brien  (setq mode-name "Csh")
733c80476e4SDavid E. O'Brien  (setq local-abbrev-table csh-mode-abbrev-table)
734c80476e4SDavid E. O'Brien  (set-syntax-table csh-mode-syntax-table)
735c80476e4SDavid E. O'Brien  (make-local-variable 'indent-line-function)
736c80476e4SDavid E. O'Brien  (setq indent-line-function 'csh-indent-line)
737c80476e4SDavid E. O'Brien  (make-local-variable 'indent-region-function)
738c80476e4SDavid E. O'Brien  (setq indent-region-function 'csh-indent-region)
739c80476e4SDavid E. O'Brien  (make-local-variable 'comment-start)
740c80476e4SDavid E. O'Brien  (setq comment-start "# ")
741c80476e4SDavid E. O'Brien  (make-local-variable 'comment-end)
742c80476e4SDavid E. O'Brien  (setq comment-end "")
743c80476e4SDavid E. O'Brien  (make-local-variable 'comment-column)
744c80476e4SDavid E. O'Brien  (setq comment-column 32)
745c80476e4SDavid E. O'Brien  (make-local-variable 'comment-start-skip)
746c80476e4SDavid E. O'Brien  (setq comment-start-skip "#+ *")
747c80476e4SDavid E. O'Brien  ;;
748c80476e4SDavid E. O'Brien  ;; config font-lock mode
749c80476e4SDavid E. O'Brien  (make-local-variable 'font-lock-keywords)
750c80476e4SDavid E. O'Brien  (setq font-lock-keywords csh-font-lock-keywords)
751c80476e4SDavid E. O'Brien  ;;
752c80476e4SDavid E. O'Brien  ;; Let the user customize
753c80476e4SDavid E. O'Brien  (run-hooks 'csh-mode-hook)
754c80476e4SDavid E. O'Brien  ) ;; defun
755c80476e4SDavid E. O'Brien
756c80476e4SDavid E. O'Brien;;
757c80476e4SDavid E. O'Brien;; Completion code supplied by Haavard Rue <hrue@imf.unit.no>.
758c80476e4SDavid E. O'Brien;;
759c80476e4SDavid E. O'Brien;;
760c80476e4SDavid E. O'Brien;; add a completion with a given type to the list
761c80476e4SDavid E. O'Brien;;
762c80476e4SDavid E. O'Brien(defun csh-addto-alist (completion type)
763c80476e4SDavid E. O'Brien  (setq csh-completion-list
764c80476e4SDavid E. O'Brien	(append csh-completion-list
765c80476e4SDavid E. O'Brien		(list (cons completion type)))))
766c80476e4SDavid E. O'Brien
767c80476e4SDavid E. O'Brien(defun csh-bol-point ()
768c80476e4SDavid E. O'Brien  (save-excursion
769c80476e4SDavid E. O'Brien    (beginning-of-line)
770c80476e4SDavid E. O'Brien    (point)))
771c80476e4SDavid E. O'Brien
772c80476e4SDavid E. O'Brien(defun csh-complete-symbol ()
773c80476e4SDavid E. O'Brien  "Perform completion."
774c80476e4SDavid E. O'Brien  (interactive)
775c80476e4SDavid E. O'Brien  (let* ((case-fold-search)
776c80476e4SDavid E. O'Brien	 (end (point))
777c80476e4SDavid E. O'Brien         (beg (unwind-protect
778c80476e4SDavid E. O'Brien                  (save-excursion
779c80476e4SDavid E. O'Brien                    (backward-sexp 1)
780c80476e4SDavid E. O'Brien                    (while (= (char-syntax (following-char)) ?\')
781c80476e4SDavid E. O'Brien                      (forward-char 1))
782c80476e4SDavid E. O'Brien                    (point))))
783c80476e4SDavid E. O'Brien         (pattern (buffer-substring beg end))
784c80476e4SDavid E. O'Brien	 (predicate
785c80476e4SDavid E. O'Brien	  ;;
786c80476e4SDavid E. O'Brien	  ;; ` or $( mark a function
787c80476e4SDavid E. O'Brien	  ;;
788c80476e4SDavid E. O'Brien	  (save-excursion
789c80476e4SDavid E. O'Brien	    (goto-char beg)
790c80476e4SDavid E. O'Brien	    (if (or
791c80476e4SDavid E. O'Brien		 (save-excursion
792c80476e4SDavid E. O'Brien		   (backward-char 1)
793c80476e4SDavid E. O'Brien		   (looking-at "`"))
794c80476e4SDavid E. O'Brien		 (save-excursion
795c80476e4SDavid E. O'Brien		   (backward-char 2)
796c80476e4SDavid E. O'Brien		   (looking-at "\\$(")))
797c80476e4SDavid E. O'Brien		(function (lambda (sym)
798c80476e4SDavid E. O'Brien			    (equal (cdr sym) csh-completion-type-function)))
799c80476e4SDavid E. O'Brien	      ;;
800c80476e4SDavid E. O'Brien	      ;; a $, ${ or ${# mark a variable
801c80476e4SDavid E. O'Brien	      ;;
802c80476e4SDavid E. O'Brien	      (if (or
803c80476e4SDavid E. O'Brien		   (save-excursion
804c80476e4SDavid E. O'Brien		     (backward-char 1)
805c80476e4SDavid E. O'Brien		     (looking-at "\\$"))
806c80476e4SDavid E. O'Brien		   (save-excursion
807c80476e4SDavid E. O'Brien		     (backward-char 2)
808c80476e4SDavid E. O'Brien		     (looking-at "\\${"))
809c80476e4SDavid E. O'Brien		   (save-excursion
810c80476e4SDavid E. O'Brien		     (backward-char 3)
811c80476e4SDavid E. O'Brien		     (looking-at "\\${#")))
812c80476e4SDavid E. O'Brien		  (function (lambda (sym)
813c80476e4SDavid E. O'Brien			      (equal (cdr sym)
814c80476e4SDavid E. O'Brien				     csh-completion-type-var)))
815c80476e4SDavid E. O'Brien		;;
816c80476e4SDavid E. O'Brien		;; don't know. use 'em all
817c80476e4SDavid E. O'Brien		;;
818c80476e4SDavid E. O'Brien		(function (lambda (sym) t))))))
819c80476e4SDavid E. O'Brien	 ;;
820c80476e4SDavid E. O'Brien	 (completion (try-completion pattern csh-completion-list predicate)))
821c80476e4SDavid E. O'Brien    ;;
822c80476e4SDavid E. O'Brien    (cond ((eq completion t))
823c80476e4SDavid E. O'Brien	  ;;
824c80476e4SDavid E. O'Brien	  ;; oops, what is this ?
825c80476e4SDavid E. O'Brien	  ;;
826c80476e4SDavid E. O'Brien          ((null completion)
827c80476e4SDavid E. O'Brien           (message "Can't find completion for \"%s\"" pattern))
828c80476e4SDavid E. O'Brien	  ;;
829c80476e4SDavid E. O'Brien	  ;; insert
830c80476e4SDavid E. O'Brien	  ;;
831c80476e4SDavid E. O'Brien          ((not (string= pattern completion))
832c80476e4SDavid E. O'Brien           (delete-region beg end)
833c80476e4SDavid E. O'Brien           (insert completion))
834c80476e4SDavid E. O'Brien	  ;;
835c80476e4SDavid E. O'Brien	  ;; write possible completion in the minibuffer,
836c80476e4SDavid E. O'Brien	  ;; use this instead of a seperate buffer (usual)
837c80476e4SDavid E. O'Brien	  ;;
838c80476e4SDavid E. O'Brien          (t
839c80476e4SDavid E. O'Brien           (let ((list (all-completions pattern csh-completion-list predicate))
840c80476e4SDavid E. O'Brien		 (string ""))
841c80476e4SDavid E. O'Brien	     (while list
842c80476e4SDavid E. O'Brien	       (progn
843c80476e4SDavid E. O'Brien		 (setq string (concat string (format "%s " (car list))))
844c80476e4SDavid E. O'Brien		 (setq list (cdr list))))
845c80476e4SDavid E. O'Brien	     (message string))))))
846c80476e4SDavid E. O'Brien
847c80476e4SDavid E. O'Brien;;
848c80476e4SDavid E. O'Brien;; init the list and pickup all
849c80476e4SDavid E. O'Brien;;
850c80476e4SDavid E. O'Brien(defun csh-completion-init-and-pickup ()
851c80476e4SDavid E. O'Brien  (interactive)
852c80476e4SDavid E. O'Brien  (let (case-fold-search)
853c80476e4SDavid E. O'Brien    (csh-completion-list-init)
854c80476e4SDavid E. O'Brien    (csh-pickup-all)))
855c80476e4SDavid E. O'Brien
856c80476e4SDavid E. O'Brien;;
857c80476e4SDavid E. O'Brien;; init the list
858c80476e4SDavid E. O'Brien;;
859c80476e4SDavid E. O'Brien(defun csh-completion-list-init ()
860c80476e4SDavid E. O'Brien  (interactive)
861c80476e4SDavid E. O'Brien  (setq csh-completion-list
862c80476e4SDavid E. O'Brien	(list
863c80476e4SDavid E. O'Brien	 (cons "break"  csh-completion-type-misc)
864c80476e4SDavid E. O'Brien	 (cons "breaksw"  csh-completion-type-misc)
865c80476e4SDavid E. O'Brien	 (cons "case"  csh-completion-type-misc)
866c80476e4SDavid E. O'Brien	 (cons "continue"  csh-completion-type-misc)
867c80476e4SDavid E. O'Brien	 (cons "endif"  csh-completion-type-misc)
868c80476e4SDavid E. O'Brien	 (cons "exit"  csh-completion-type-misc)
869c80476e4SDavid E. O'Brien	 (cons "foreach"  csh-completion-type-misc)
870c80476e4SDavid E. O'Brien	 (cons "if"  csh-completion-type-misc)
871c80476e4SDavid E. O'Brien	 (cons "while"  csh-completion-type-misc))))
872c80476e4SDavid E. O'Brien
873c80476e4SDavid E. O'Brien(defun csh-eol-point ()
874c80476e4SDavid E. O'Brien  (save-excursion
875c80476e4SDavid E. O'Brien    (end-of-line)
876c80476e4SDavid E. O'Brien    (point)))
877c80476e4SDavid E. O'Brien
878c80476e4SDavid E. O'Brien(defun csh-pickup-all ()
879c80476e4SDavid E. O'Brien  "Pickup all completions in buffer."
880c80476e4SDavid E. O'Brien  (interactive)
881c80476e4SDavid E. O'Brien  (csh-pickup-completion-driver (point-min) (point-max) t))
882c80476e4SDavid E. O'Brien
883c80476e4SDavid E. O'Brien(defun csh-pickup-completion (regexp type match pmin pmax)
884c80476e4SDavid E. O'Brien  "Pickup completion in region and addit to the list, if not already
885c80476e4SDavid E. O'Brienthere."
886c80476e4SDavid E. O'Brien  (let ((i 0) kw obj)
887c80476e4SDavid E. O'Brien    (save-excursion
888c80476e4SDavid E. O'Brien      (goto-char pmin)
889c80476e4SDavid E. O'Brien      (while (and
890c80476e4SDavid E. O'Brien	      (re-search-forward regexp pmax t)
891c80476e4SDavid E. O'Brien	      (match-beginning match)
892c80476e4SDavid E. O'Brien	      (setq kw  (buffer-substring
893c80476e4SDavid E. O'Brien			 (match-beginning match)
894c80476e4SDavid E. O'Brien			 (match-end match))))
895c80476e4SDavid E. O'Brien	(progn
896c80476e4SDavid E. O'Brien	  (setq obj (assoc kw csh-completion-list))
897c80476e4SDavid E. O'Brien	  (if (or (equal nil obj)
898c80476e4SDavid E. O'Brien		  (and (not (equal nil obj))
899c80476e4SDavid E. O'Brien		       (not (= type (cdr obj)))))
900c80476e4SDavid E. O'Brien	      (progn
901c80476e4SDavid E. O'Brien		(setq i (1+ i))
902c80476e4SDavid E. O'Brien		(csh-addto-alist kw type))))))
903c80476e4SDavid E. O'Brien    i))
904c80476e4SDavid E. O'Brien
905c80476e4SDavid E. O'Brien(defun csh-pickup-completion-driver (pmin pmax message)
906c80476e4SDavid E. O'Brien  "Driver routine for csh-pickup-completion."
907c80476e4SDavid E. O'Brien  (if message
908c80476e4SDavid E. O'Brien      (message "pickup completion..."))
909c80476e4SDavid E. O'Brien  (let* (
910c80476e4SDavid E. O'Brien	 (i1
911c80476e4SDavid E. O'Brien	  (csh-pickup-completion  csh-completion-regexp-var
912c80476e4SDavid E. O'Brien				 csh-completion-type-var
913c80476e4SDavid E. O'Brien				 csh-completion-match-var
914c80476e4SDavid E. O'Brien				 pmin pmax))
915c80476e4SDavid E. O'Brien	 (i2
916c80476e4SDavid E. O'Brien	  (csh-pickup-completion  csh-completion-regexp-var2
917c80476e4SDavid E. O'Brien				 csh-completion-type-var
918c80476e4SDavid E. O'Brien				 csh-completion-match-var2
919c80476e4SDavid E. O'Brien				 pmin pmax))
920c80476e4SDavid E. O'Brien	 (i3
921c80476e4SDavid E. O'Brien	  (csh-pickup-completion  csh-completion-regexp-function
922c80476e4SDavid E. O'Brien				 csh-completion-type-function
923c80476e4SDavid E. O'Brien				 csh-completion-match-function
924c80476e4SDavid E. O'Brien				 pmin pmax)))
925c80476e4SDavid E. O'Brien    (if message
926c80476e4SDavid E. O'Brien	(message "pickup %d variables and %d functions." (+ i1 i2) i3))))
927c80476e4SDavid E. O'Brien
928c80476e4SDavid E. O'Brien(defun csh-pickup-this-line ()
929c80476e4SDavid E. O'Brien  "Pickup all completions in current line."
930c80476e4SDavid E. O'Brien  (interactive)
931c80476e4SDavid E. O'Brien  (csh-pickup-completion-driver (csh-bol-point) (csh-eol-point) nil))
932c80476e4SDavid E. O'Brien
933c80476e4SDavid E. O'Brien
934c80476e4SDavid E. O'Brien(provide 'csh-mode)
935c80476e4SDavid E. O'Brien;;; csh-mode.el ends here
936