aboutsummaryrefslogtreecommitdiff
path: root/contrib/tcsh/csh-mode.el
diff options
context:
space:
mode:
authorDavid E. O'Brien <obrien@FreeBSD.org>2000-04-15 04:41:27 +0000
committerDavid E. O'Brien <obrien@FreeBSD.org>2000-04-15 04:41:27 +0000
commitc80476e4c3e6730697b9424f88dfa74d1907cabd (patch)
tree7679c440a91912ee9586cee3ebab24596c0fe1c4 /contrib/tcsh/csh-mode.el
downloadsrc-c80476e4c3e6730697b9424f88dfa74d1907cabd.tar.gz
src-c80476e4c3e6730697b9424f88dfa74d1907cabd.zip
Import the latest version of the 44BSD C-shell -- tcsh-6.09.vendor/tcsh/6.09
Notes
Notes: svn path=/vendor/tcsh/dist/; revision=59243 svn path=/vendor/tcsh/6.09/; revision=59245; tag=vendor/tcsh/6.09
Diffstat (limited to 'contrib/tcsh/csh-mode.el')
-rw-r--r--contrib/tcsh/csh-mode.el935
1 files changed, 935 insertions, 0 deletions
diff --git a/contrib/tcsh/csh-mode.el b/contrib/tcsh/csh-mode.el
new file mode 100644
index 000000000000..20fee71287fc
--- /dev/null
+++ b/contrib/tcsh/csh-mode.el
@@ -0,0 +1,935 @@
+;; csh-mode.el --- csh (and tcsh) script editing mode for Emacs.
+;;
+;; Version: 1.2
+;; Date: April 2, 1999
+;; Maintainer: Dan Harkless <dan@wave.eng.uci.edu>
+;;
+;; Description:
+;; csh and tcsh script editing mode for Emacs.
+;;
+;; Installation:
+;; Put csh-mode.el in some directory in your load-path and load it.
+;;
+;; Usage:
+;; This major mode assists shell script writers with indentation
+;; control and control structure construct matching in much the same
+;; fashion as other programming language modes. Invoke describe-mode
+;; for more information.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Author key:
+;; DH - Dan Harkless <dan@wave.eng.uci.edu>
+;; CM - Carlo Migliorini <migliorini@sodalia.it>
+;; JR - Jack Repenning <jackr@sgi.com>
+;; GE - Gary Ellison <Gary.F.Ellison@att.com>
+;;
+;; *** REVISION HISTORY ***
+;;
+;; DATE MOD. BY REASON FOR MODIFICATION
+;; --------- -- --------------------------------------------------------------
+;; 2 Apr 99 DH 1.2: Noticed an out-of-date comment referencing .bashrc etc.
+;; 11 Dec 96 DH 1.1: ksh-mode just indented continuation lines by 1 space.
+;; csh-mode looks at the first line and indents properly to line
+;; up under the open-paren, quote, or command.
+;; 11 Dec 96 DH Added fontification for history substitutions.
+;; 10 Dec 96 DH Added indentation and fontification for labels. Added
+;; fontification for variables and backquoted strings.
+;; 9 Dec 96 DH 1.0: Brought csh-mode up to the level of functionality of
+;; the original ksh-mode.
+;; 7 Oct 96 CM 0.1: Hacked ksh-mode.el into minimally functional csh-mode.el
+;; by doing search-and-replace and some keyword changes.
+;; 8 Aug 96 JR (Last modification to ksh-mode 2.6.)
+;; [...]
+;; 19 Jun 92 GE (Conception of ksh-mode.)
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+(defconst csh-mode-version "1.2"
+ "*Version number of this version of csh-mode")
+
+(defvar csh-mode-hook
+ '(lambda ()
+ (auto-fill-mode 1))
+ "Hook to run each time csh-mode is entered.")
+
+
+;;
+;; -------------------------------------------> Variables controlling completion
+;;
+(defvar csh-completion-list '())
+(make-variable-buffer-local 'csh-completion-list)
+(set-default 'csh-completion-list '())
+;;
+;; -type- : type number, 0:misc, 1:variable, 2:function
+;; -regexp-: regexp used to parse the script
+;; -match- : used by match-beginning/end to pickup target
+;;
+(defvar csh-completion-type-misc 0)
+(defvar csh-completion-regexp-var "\\([A-Za-z_0-9]+\\)=")
+(defvar csh-completion-type-var 1)
+(defvar csh-completion-match-var 1)
+(defvar csh-completion-regexp-var2 "\\$\\({\\|{#\\)?\\([A-Za-z_0-9]+\\)[#%:}]?")
+(defvar csh-completion-match-var2 2)
+(defvar csh-completion-regexp-function
+ "\\(function\\)?[ \t]*\\([A-Za-z_0-9]+\\)[ \t]*([ \t]*)")
+(defvar csh-completion-type-function 2)
+(defvar csh-completion-match-function 2)
+
+
+;;
+;; ------------------------------------> Variables controlling indentation style
+;;
+(defvar csh-indent 4
+ "*Indentation of csh statements with respect to containing block. A value
+of nil indicates compound list keyword \(\"do\" and \"then\"\) alignment.")
+
+(defvar csh-case-item-offset csh-indent
+ "*Additional indentation for case items within a case statement.")
+(defvar csh-case-indent nil
+ "*Additional indentation for statements under case items.")
+(defvar csh-comment-regexp "^\\s *#"
+ "*Regular expression used to recognize comments. Customize to support
+csh-like languages.")
+(defvar csh-match-and-tell t
+ "*If non-nil echo in the minibuffer the matching compound command
+for the \"breaksw\", \"end\", or \"endif\".")
+(defvar csh-tab-always-indent t
+ "*Controls the operation of the TAB key. If t (the default), always
+reindent the current line. If nil, indent the current line only if
+point is at the left margin or in the line's indentation; otherwise
+insert a tab.")
+
+
+;;
+;; ----------------------------------------> Constants containing syntax regexps
+;;
+(defconst csh-case-default-re
+ "^\\s *\\(case\\|default\\)\\b"
+ "Regexp used to locate grouping keywords case and default" )
+
+(defconst csh-case-item-re "^\\s *\\(case .*\\|default\\):"
+ "Regexp used to match case-items")
+
+(defconst csh-end-re "^\\s *end\\b"
+ "Regexp used to match keyword: end")
+
+(defconst csh-endif-re "^\\s *endif\\b"
+ "Regexp used to match keyword: endif")
+
+(defconst csh-endsw-re "^\\s *endsw\\b"
+ "Regexp used to match keyword: endsw")
+
+(defconst csh-else-re "^\\s *\\belse\\(\\b\\|$\\)"
+ "Regexp used to match keyword: else")
+
+(defconst csh-else-if-re "^\\s *\\belse if\\(\\b\\|$\\)"
+ "Regexp used to match keyword pair: else if")
+
+(defconst csh-if-re "^\\s *if\\b.+\\(\\\\\\|\\bthen\\b\\)"
+ "Regexp used to match non-one-line if statements")
+
+(defconst csh-iteration-keywords-re "^[^#\n]*\\s\"*\\b\\(while\\|foreach\\)\\b"
+ "Match one of the keywords: while, foreach")
+
+(defconst csh-keywords-re
+ "^\\s *\\(else\\b\\|foreach\\b\\|if\\b.+\\(\\\\\\|\\bthen\\b\\)\\|switch\\b\\|while\\b\\)"
+ "Regexp used to detect compound command keywords: else, if, foreach, while")
+
+(defconst csh-label-re "^\\s *[^!#$\n ]+:"
+ "Regexp used to match flow-control labels")
+
+(defconst csh-multiline-re "^.*\\\\$"
+ "Regexp used to match a line with a statement using more lines.")
+
+(defconst csh-switch-re "^\\s *switch\\b"
+ "Regexp used to match keyword: switch")
+
+
+;;
+;; ----------------------------------------> Variables controlling fontification
+;;
+(defvar csh-keywords '("@" "alias" "bg" "break" "breaksw" "case" "cd" "chdir"
+ "continue" "default" "dirs" "echo" "else" "end" "endif"
+ "endsw" "eval" "exec" "exit" "fg" "foreach" "glob" "goto"
+ "hashstat" "history" "if" "jobs" "kill" "limit" "login"
+ "logout" "limit" "notify" "onintr" "popd" "printenv"
+ "pushd" "rehash" "repeat" "set" "setenv" "shift" "source"
+ "stop" "suspend" "switch" "then" "time" "umask" "unalias"
+ "unhash" "unlimit" "unset" "unsetenv" "wait" "while"
+ ;; tcsh-keywords
+ "alloc" "bindkey" "builtins" "complete" "echotc"
+ "filetest" "hup" "log" "ls-F" "nice" "nohup" "sched"
+ "settc" "setty" "telltc" "uncomplete" "where" "which"))
+
+(require 'font-lock) ; need to do this before referring to font-lock-* below
+
+(defconst csh-font-lock-keywords
+ ;; NOTE: The order of some of the items in this list is significant. Do not
+ ;; alphabetize or otherwise blindly rearrange.
+ (list
+ ;; Comments on line 1, which are missed by syntactic fontification.
+ '("^#.*" 0 font-lock-comment-face)
+
+ ;; Label definitions (1 means first parenthesized exp in regexp).
+ '("^\\s *\\([^!#$\n ]+\\):" 1 font-lock-function-name-face)
+
+ ;; Label references.
+ '("\\b\\(goto\\|onintr\\)\\b\\s +\\([^!#$ \n\t]+\\)"
+ 2 font-lock-function-name-face)
+
+ ;; Variable settings.
+ '("\\(@\\|set\\|setenv\\)\\s +\\([0-9A-Za-z_]+\\b\\)"
+ 2 font-lock-variable-name-face)
+
+ ;; Variable references not inside of strings.
+ '("\\$[][0-9A-Za-z_#:?]+" 0 font-lock-variable-name-face)
+
+ ;; Backquoted strings. 'keep' means to just fontify non-fontified text.
+ '("`\\(.*\\)`" 1 font-lock-reference-face keep)
+
+ ;; NOTE: The following variables need to be anchored to the beginning of
+ ;; line to prevent re-fontifying text in comments. Due to this, we
+ ;; can only catch a finite number of occurrences. More can be added.
+ ;; The 't' means to override previous fontification.
+ ;;
+ ;; Variable references inside of " strings.
+ '("^[^#\n]*\".*\\(\\$[][0-9A-Za-z_#:?]+\\).*\""
+ 1 font-lock-variable-name-face t) ; 1
+ '("^[^#\n]*\".*\\(\\$[][0-9A-Za-z_#:?]+\\).*\\$[][0-9A-Za-z_#:?]+.*\""
+ 1 font-lock-variable-name-face t) ; 2
+ (cons (concat "^[^#\n]*\".*\\(\\$[][0-9A-Za-z_#:?]+\\).*"
+ "\\$[][0-9A-Za-z_#:?]+.*\\$[][0-9A-Za-z_#:?]+.*\"")
+ (list 1 font-lock-variable-name-face t)) ; 3
+ ;;
+ ;; History substitutions.
+ '("^![^~= \n\t]+" 0 font-lock-reference-face t) ; BOL
+ '("^[^#\n]*[^#\\\n]\\(![^~= \n\t]+\\)" 1 font-lock-reference-face t) ; 1
+ '("^[^#\n]*[^#\\\n]\\(![^~= \n\t]+\\).*![^~= \n\t]+"
+ 1 font-lock-reference-face t) ; 2
+
+ ;; Keywords.
+ (cons (concat
+ "\\(\\<"
+ (mapconcat 'identity csh-keywords "\\>\\|\\<")
+ "\\>\\)")
+ 1)
+ ))
+
+(put 'csh-mode 'font-lock-keywords 'csh-font-lock-keywords)
+
+
+;;
+;; -------------------------------------------------------> Mode-specific tables
+;;
+(defvar csh-mode-abbrev-table nil
+ "Abbrev table used while in csh mode.")
+(define-abbrev-table 'csh-mode-abbrev-table ())
+
+(defvar csh-mode-map nil
+ "Keymap used in csh mode")
+(if csh-mode-map
+ ()
+ (setq csh-mode-map (make-sparse-keymap))
+;;(define-key csh-mode-map "\177" 'backward-delete-char-untabify)
+ (define-key csh-mode-map "\C-c\t" 'csh-completion-init-and-pickup)
+ (define-key csh-mode-map "\C-j" 'reindent-then-newline-and-indent)
+ (define-key csh-mode-map "\e\t" 'csh-complete-symbol)
+ (define-key csh-mode-map "\n" 'reindent-then-newline-and-indent)
+ (define-key csh-mode-map '[return] 'reindent-then-newline-and-indent)
+ (define-key csh-mode-map "\t" 'csh-indent-command)
+;;(define-key csh-mode-map "\t" 'csh-indent-line)
+ )
+
+(defvar csh-mode-syntax-table nil
+ "Syntax table used while in csh mode.")
+(if csh-mode-syntax-table
+ ;; If it's already set up, don't change it.
+ ()
+ ;; Else, create it from the standard table and modify entries that need to be.
+ (setq csh-mode-syntax-table (make-syntax-table))
+ (modify-syntax-entry ?& "." csh-mode-syntax-table) ; & -punctuation
+ (modify-syntax-entry ?* "." csh-mode-syntax-table) ; * -punctuation
+ (modify-syntax-entry ?- "." csh-mode-syntax-table) ; - -punctuation
+ (modify-syntax-entry ?= "." csh-mode-syntax-table) ; = -punctuation
+ (modify-syntax-entry ?+ "." csh-mode-syntax-table) ; + -punctuation
+ (modify-syntax-entry ?| "." csh-mode-syntax-table) ; | -punctuation
+ (modify-syntax-entry ?< "." csh-mode-syntax-table) ; < -punctuation
+ (modify-syntax-entry ?> "." csh-mode-syntax-table) ; > -punctuation
+ (modify-syntax-entry ?/ "." csh-mode-syntax-table) ; / -punctuation
+ (modify-syntax-entry ?\' "\"" csh-mode-syntax-table) ; ' -string quote
+ (modify-syntax-entry ?. "w" csh-mode-syntax-table) ; . -word constituent
+ (modify-syntax-entry ?? "w" csh-mode-syntax-table) ; ? -word constituent
+
+ ;; \n - comment ender, first character of 2-char comment sequence
+ (modify-syntax-entry ?\n "> 1" csh-mode-syntax-table) ; # -word constituent
+
+ ;; - whitespace, first character of 2-char comment sequence
+ (modify-syntax-entry ? " 1" csh-mode-syntax-table) ;
+
+ ;; \t - whitespace, first character of 2-char comment sequence
+ (modify-syntax-entry ?\t " 1" csh-mode-syntax-table) ; # -word constituent
+
+ ;; # - word constituent, second character of 2-char comment sequence
+ (modify-syntax-entry ?# "w 2" csh-mode-syntax-table) ; # -word constituent
+ )
+
+
+;;
+;; ------------------------------------------------------------------> Functions
+;;
+(defun csh-current-line ()
+ "Return the vertical position of point in the buffer.
+Top line is 1."
+ (+ (count-lines (point-min) (point))
+ (if (= (current-column) 0) 1 0))
+ )
+
+(defun csh-get-compound-level
+ (begin-re end-re anchor-point &optional balance-list)
+ "Determine how much to indent this structure. Return a list (level line)
+of the matching compound command or nil if no match found."
+ (let*
+ (;; Locate the next compound begin keyword bounded by point-min
+ (match-point (if (re-search-backward begin-re (point-min) t)
+ (match-beginning 0) 0))
+ (nest-column (if (zerop match-point)
+ 1
+ (progn
+ (goto-char match-point)
+ (current-indentation))))
+ (nest-list (cons 0 0)) ;; sentinel cons since cdr is >= 1
+ )
+ (if (zerop match-point)
+ nil ;; graceful exit from recursion
+ (progn
+ (if (nlistp balance-list)
+ (setq balance-list (list)))
+ ;; Now search forward from matching start keyword for end keyword
+ (while (and (consp nest-list) (zerop (cdr nest-list))
+ (re-search-forward end-re anchor-point t))
+ (if (not (memq (point) balance-list))
+ (progn
+ (setq balance-list (cons (point) balance-list))
+ (goto-char match-point) ;; beginning of compound cmd
+ (setq nest-list
+ (csh-get-compound-level begin-re end-re
+ anchor-point balance-list))
+ )))
+
+ (cond ((consp nest-list)
+ (if (zerop (cdr nest-list))
+ (progn
+ (goto-char match-point)
+ (cons nest-column (csh-current-line)))
+ nest-list))
+ (t nil)
+ )
+ )
+ )
+ )
+ )
+
+(defun csh-get-nest-level ()
+ "Return a 2 element list (nest-level nest-line) describing where the
+current line should nest."
+ (let ((case-fold-search)
+ (level))
+ (save-excursion
+ (forward-line -1)
+ (while (and (not (bobp))
+ (null level))
+ (if (and (not (looking-at "^\\s *$"))
+ (not (save-excursion
+ (forward-line -1)
+ (beginning-of-line)
+ (looking-at csh-multiline-re)))
+ (not (looking-at csh-comment-regexp)))
+ (setq level (cons (current-indentation)
+ (csh-current-line)))
+ (forward-line -1)
+ );; if
+ );; while
+ (if (null level)
+ (cons (current-indentation) (csh-current-line))
+ level)
+ )
+ )
+ )
+
+(defun csh-get-nester-column (nest-line)
+ "Return the column to indent to with respect to nest-line taking
+into consideration keywords and other nesting constructs."
+ (save-excursion
+ (let ((fence-post)
+ (case-fold-search)
+ (start-line (csh-current-line)))
+ ;;
+ ;; Handle case item indentation constructs for this line
+ (cond ((looking-at csh-case-item-re)
+ ;; This line is a case item...
+ (save-excursion
+ (goto-line nest-line)
+ (let ((fence-post (save-excursion (end-of-line) (point))))
+ (cond ((re-search-forward csh-switch-re fence-post t)
+ ;; If this is the first case under the switch, indent.
+ (goto-char (match-beginning 0))
+ (+ (current-indentation) csh-case-item-offset))
+
+ ((re-search-forward csh-case-item-re fence-post t)
+ ;; If this is another case right under a previous case
+ ;; without intervening code, stay at the same
+ ;; indentation.
+ (goto-char (match-beginning 0))
+ (current-indentation))
+
+ (t
+ ;; Else, this is a new case. Outdent.
+ (- (current-indentation) csh-case-item-offset))
+ )
+ )))
+ (t;; Not a case-item. What to do relative to the nest-line?
+ (save-excursion
+ (goto-line nest-line)
+ (setq fence-post (save-excursion (end-of-line) (point)))
+ (save-excursion
+ (cond
+ ;;
+ ;; Check if we are in a continued statement
+ ((and (looking-at csh-multiline-re)
+ (save-excursion
+ (goto-line (1- start-line))
+ (looking-at csh-multiline-re)))
+ (if (looking-at ".*[\'\"]\\\\")
+ ;; If this is a continued string, indent under
+ ;; opening quote.
+ (progn
+ (re-search-forward "[\'\"]")
+ (forward-char -1))
+ (if (looking-at ".*([^\)\n]*\\\\")
+ ;; Else if this is a continued parenthesized
+ ;; list, indent after paren.
+ (re-search-forward "(" fence-post t)
+ ;; Else, indent after whitespace after first word.
+ (re-search-forward "[^ \t]+[ \t]+" fence-post t)))
+ (current-column))
+
+ ;; In order to locate the column of the keyword,
+ ;; which might be embedded within a case-item,
+ ;; it is necessary to use re-search-forward.
+ ;; Search by literal case, since shell is
+ ;; case-sensitive.
+ ((re-search-forward csh-keywords-re fence-post t)
+ (goto-char (match-beginning 1))
+ (if (looking-at csh-switch-re)
+ (+ (current-indentation) csh-case-item-offset)
+ (+ (current-indentation)
+ (if (null csh-indent)
+ 2 csh-indent)
+ )))
+
+ ((re-search-forward csh-case-default-re fence-post t)
+ (if (null csh-indent)
+ (progn
+ (goto-char (match-end 1))
+ (+ (current-indentation) 1))
+ (progn
+ (goto-char (match-beginning 1))
+ (+ (current-indentation) csh-indent))
+ ))
+
+ ;;
+ ;; Now detect first statement under a case item
+ ((looking-at csh-case-item-re)
+ (if (null csh-case-indent)
+ (progn
+ (re-search-forward csh-case-item-re fence-post t)
+ (goto-char (match-end 1))
+ (+ (current-column) 1))
+ (+ (current-indentation) csh-case-indent)))
+
+ ;;
+ ;; If this is the first statement under a control-flow
+ ;; label, indent one level.
+ ((csh-looking-at-label)
+ (+ (current-indentation) csh-indent))
+
+ ;; This is hosed when using current-column
+ ;; and there is a multi-command expression as the
+ ;; nester.
+ (t (current-indentation)))
+ )
+ ));; excursion over
+ );; Not a case-item
+ );;let
+ );; excursion
+ );; defun
+
+(defun csh-indent-command ()
+ "Indent current line relative to containing block and allow for
+csh-tab-always-indent customization"
+ (interactive)
+ (let (case-fold-search)
+ (cond ((save-excursion
+ (skip-chars-backward " \t")
+ (bolp))
+ (csh-indent-line))
+ (csh-tab-always-indent
+ (save-excursion
+ (csh-indent-line)))
+ (t (insert-tab))
+ ))
+ )
+
+(defun csh-indent-line ()
+ "Indent current line as far as it should go according
+to the syntax/context"
+ (interactive)
+ (let (case-fold-search)
+ (save-excursion
+ (beginning-of-line)
+ (if (bobp)
+ nil
+ ;;
+ ;; Align this line to current nesting level
+ (let*
+ (
+ (level-list (csh-get-nest-level)) ; Where to nest against
+ ;; (last-line-level (car level-list))
+ (this-line-level (current-indentation))
+ (nester-column (csh-get-nester-column (cdr level-list)))
+ (struct-match (csh-match-structure-and-reindent))
+ )
+ (if struct-match
+ (setq nester-column struct-match))
+ (if (eq nester-column this-line-level)
+ nil
+ (beginning-of-line)
+ (let ((beg (point)))
+ (back-to-indentation)
+ (delete-region beg (point)))
+ (indent-to nester-column))
+ );; let*
+ );; if
+ );; excursion
+ ;;
+ ;; Position point on this line
+ (let*
+ (
+ (this-line-level (current-indentation))
+ (this-bol (save-excursion
+ (beginning-of-line)
+ (point)))
+ (this-point (- (point) this-bol))
+ )
+ (cond ((> this-line-level this-point);; point in initial white space
+ (back-to-indentation))
+ (t nil)
+ );; cond
+ );; let*
+ );; let
+ );; defun
+
+(defun csh-indent-region (start end)
+ "From start to end, indent each line."
+ ;; The algorithm is just moving through the region line by line with
+ ;; the match noise turned off. Only modifies nonempty lines.
+ (save-excursion
+ (let (csh-match-and-tell
+ (endmark (copy-marker end)))
+
+ (goto-char start)
+ (beginning-of-line)
+ (setq start (point))
+ (while (> (marker-position endmark) start)
+ (if (not (and (bolp) (eolp)))
+ (csh-indent-line))
+ (forward-line 1)
+ (setq start (point)))
+
+ (set-marker endmark nil)
+ )
+ )
+ )
+
+(defun csh-line-to-string ()
+ "From point, construct a string from all characters on
+current line"
+ (skip-chars-forward " \t") ;; skip tabs as well as spaces
+ (buffer-substring (point)
+ (progn
+ (end-of-line 1)
+ (point))))
+
+(defun csh-looking-at-label ()
+ "Return true if current line is a label (not the default: case label)."
+ (and
+ (looking-at csh-label-re)
+ (not (looking-at "^\\s *default:"))))
+
+(defun csh-match-indent-level (begin-re end-re)
+ "Match the compound command and indent. Return nil on no match,
+indentation to use for this line otherwise."
+ (interactive)
+ (let* ((case-fold-search)
+ (nest-list
+ (save-excursion
+ (csh-get-compound-level begin-re end-re (point))
+ ))
+ ) ;; bindings
+ (if (null nest-list)
+ (progn
+ (if csh-match-and-tell
+ (message "No matching compound command"))
+ nil) ;; Propagate a miss.
+ (let* (
+ (nest-level (car nest-list))
+ (match-line (cdr nest-list))
+ ) ;; bindings
+ (if csh-match-and-tell
+ (save-excursion
+ (goto-line match-line)
+ (message "Matched ... %s" (csh-line-to-string))
+ ) ;; excursion
+ ) ;; if csh-match-and-tell
+ nest-level ;;Propagate a hit.
+ ) ;; let*
+ ) ;; if
+ ) ;; let*
+ ) ;; defun csh-match-indent-level
+
+(defun csh-match-structure-and-reindent ()
+ "If the current line matches one of the indenting keywords
+or one of the control structure ending keywords then reindent. Also
+if csh-match-and-tell is non-nil the matching structure will echo in
+the minibuffer"
+ (interactive)
+ (let (case-fold-search)
+ (save-excursion
+ (beginning-of-line)
+ (cond ((looking-at csh-else-re)
+ (csh-match-indent-level csh-if-re csh-endif-re))
+ ((looking-at csh-else-if-re)
+ (csh-match-indent-level csh-if-re csh-endif-re))
+ ((looking-at csh-endif-re)
+ (csh-match-indent-level csh-if-re csh-endif-re))
+ ((looking-at csh-end-re)
+ (csh-match-indent-level csh-iteration-keywords-re csh-end-re))
+ ((looking-at csh-endsw-re)
+ (csh-match-indent-level csh-switch-re csh-endsw-re))
+ ((csh-looking-at-label)
+ ;; Flush control-flow labels left since they don't nest.
+ 0)
+ ;;
+ (t nil)
+ );; cond
+ )
+ ))
+
+;;;###autoload
+(defun csh-mode ()
+ "csh-mode 2.0 - Major mode for editing csh and tcsh scripts.
+Special key bindings and commands:
+\\{csh-mode-map}
+Variables controlling indentation style:
+csh-indent
+ Indentation of csh statements with respect to containing block.
+ Default value is 4.
+csh-case-indent
+ Additional indentation for statements under case items.
+ Default value is nil which will align the statements one position
+ past the \")\" of the pattern.
+csh-case-item-offset
+ Additional indentation for case items within a case statement.
+ Default value is 2.
+csh-tab-always-indent
+ Controls the operation of the TAB key. If t (the default), always
+ reindent the current line. If nil, indent the current line only if
+ point is at the left margin or in the line's indentation; otherwise
+ insert a tab.
+csh-match-and-tell
+ If non-nil echo in the minibuffer the matching compound command
+ for the \"done\", \"}\", \"fi\", or \"endsw\". Default value is t.
+
+csh-comment-regexp
+ Regular expression used to recognize comments. Customize to support
+ csh-like languages. Default value is \"\^\\\\s *#\".
+
+Style Guide.
+ By setting
+ (setq csh-indent default-tab-width)
+
+ The following style is obtained:
+
+ if [ -z $foo ]
+ then
+ bar # <-- csh-group-offset is additive to csh-indent
+ foo
+ fi
+
+ By setting
+ (setq csh-indent default-tab-width)
+ (setq csh-group-offset (- 0 csh-indent))
+
+ The following style is obtained:
+
+ if [ -z $foo ]
+ then
+ bar
+ foo
+ fi
+
+ By setting
+ (setq csh-case-item-offset 1)
+ (setq csh-case-indent nil)
+
+ The following style is obtained:
+
+ case x in *
+ foo) bar # <-- csh-case-item-offset
+ baz;; # <-- csh-case-indent aligns with \")\"
+ foobar) foo
+ bar;;
+ endsw
+
+ By setting
+ (setq csh-case-item-offset 1)
+ (setq csh-case-indent 6)
+
+ The following style is obtained:
+
+ case x in *
+ foo) bar # <-- csh-case-item-offset
+ baz;; # <-- csh-case-indent
+ foobar) foo
+ bar;;
+ endsw
+
+
+Installation:
+ Put csh-mode.el in some directory in your load-path.
+ Put the following forms in your .emacs file.
+
+ (setq auto-mode-alist
+ (append auto-mode-alist
+ (list
+ '(\"\\\\.csh$\" . csh-mode)
+ '(\"\\\\.login\" . csh-mode))))
+
+ (setq csh-mode-hook
+ (function (lambda ()
+ (font-lock-mode 1) ;; font-lock the buffer
+ (setq csh-indent 8)
+ (setq csh-tab-always-indent t)
+ (setq csh-match-and-tell t)
+ (setq csh-align-to-keyword t) ;; Turn on keyword alignment
+ )))"
+ (interactive)
+ (kill-all-local-variables)
+ (use-local-map csh-mode-map)
+ (setq major-mode 'csh-mode)
+ (setq mode-name "Csh")
+ (setq local-abbrev-table csh-mode-abbrev-table)
+ (set-syntax-table csh-mode-syntax-table)
+ (make-local-variable 'indent-line-function)
+ (setq indent-line-function 'csh-indent-line)
+ (make-local-variable 'indent-region-function)
+ (setq indent-region-function 'csh-indent-region)
+ (make-local-variable 'comment-start)
+ (setq comment-start "# ")
+ (make-local-variable 'comment-end)
+ (setq comment-end "")
+ (make-local-variable 'comment-column)
+ (setq comment-column 32)
+ (make-local-variable 'comment-start-skip)
+ (setq comment-start-skip "#+ *")
+ ;;
+ ;; config font-lock mode
+ (make-local-variable 'font-lock-keywords)
+ (setq font-lock-keywords csh-font-lock-keywords)
+ ;;
+ ;; Let the user customize
+ (run-hooks 'csh-mode-hook)
+ ) ;; defun
+
+;;
+;; Completion code supplied by Haavard Rue <hrue@imf.unit.no>.
+;;
+;;
+;; add a completion with a given type to the list
+;;
+(defun csh-addto-alist (completion type)
+ (setq csh-completion-list
+ (append csh-completion-list
+ (list (cons completion type)))))
+
+(defun csh-bol-point ()
+ (save-excursion
+ (beginning-of-line)
+ (point)))
+
+(defun csh-complete-symbol ()
+ "Perform completion."
+ (interactive)
+ (let* ((case-fold-search)
+ (end (point))
+ (beg (unwind-protect
+ (save-excursion
+ (backward-sexp 1)
+ (while (= (char-syntax (following-char)) ?\')
+ (forward-char 1))
+ (point))))
+ (pattern (buffer-substring beg end))
+ (predicate
+ ;;
+ ;; ` or $( mark a function
+ ;;
+ (save-excursion
+ (goto-char beg)
+ (if (or
+ (save-excursion
+ (backward-char 1)
+ (looking-at "`"))
+ (save-excursion
+ (backward-char 2)
+ (looking-at "\\$(")))
+ (function (lambda (sym)
+ (equal (cdr sym) csh-completion-type-function)))
+ ;;
+ ;; a $, ${ or ${# mark a variable
+ ;;
+ (if (or
+ (save-excursion
+ (backward-char 1)
+ (looking-at "\\$"))
+ (save-excursion
+ (backward-char 2)
+ (looking-at "\\${"))
+ (save-excursion
+ (backward-char 3)
+ (looking-at "\\${#")))
+ (function (lambda (sym)
+ (equal (cdr sym)
+ csh-completion-type-var)))
+ ;;
+ ;; don't know. use 'em all
+ ;;
+ (function (lambda (sym) t))))))
+ ;;
+ (completion (try-completion pattern csh-completion-list predicate)))
+ ;;
+ (cond ((eq completion t))
+ ;;
+ ;; oops, what is this ?
+ ;;
+ ((null completion)
+ (message "Can't find completion for \"%s\"" pattern))
+ ;;
+ ;; insert
+ ;;
+ ((not (string= pattern completion))
+ (delete-region beg end)
+ (insert completion))
+ ;;
+ ;; write possible completion in the minibuffer,
+ ;; use this instead of a seperate buffer (usual)
+ ;;
+ (t
+ (let ((list (all-completions pattern csh-completion-list predicate))
+ (string ""))
+ (while list
+ (progn
+ (setq string (concat string (format "%s " (car list))))
+ (setq list (cdr list))))
+ (message string))))))
+
+;;
+;; init the list and pickup all
+;;
+(defun csh-completion-init-and-pickup ()
+ (interactive)
+ (let (case-fold-search)
+ (csh-completion-list-init)
+ (csh-pickup-all)))
+
+;;
+;; init the list
+;;
+(defun csh-completion-list-init ()
+ (interactive)
+ (setq csh-completion-list
+ (list
+ (cons "break" csh-completion-type-misc)
+ (cons "breaksw" csh-completion-type-misc)
+ (cons "case" csh-completion-type-misc)
+ (cons "continue" csh-completion-type-misc)
+ (cons "endif" csh-completion-type-misc)
+ (cons "exit" csh-completion-type-misc)
+ (cons "foreach" csh-completion-type-misc)
+ (cons "if" csh-completion-type-misc)
+ (cons "while" csh-completion-type-misc))))
+
+(defun csh-eol-point ()
+ (save-excursion
+ (end-of-line)
+ (point)))
+
+(defun csh-pickup-all ()
+ "Pickup all completions in buffer."
+ (interactive)
+ (csh-pickup-completion-driver (point-min) (point-max) t))
+
+(defun csh-pickup-completion (regexp type match pmin pmax)
+ "Pickup completion in region and addit to the list, if not already
+there."
+ (let ((i 0) kw obj)
+ (save-excursion
+ (goto-char pmin)
+ (while (and
+ (re-search-forward regexp pmax t)
+ (match-beginning match)
+ (setq kw (buffer-substring
+ (match-beginning match)
+ (match-end match))))
+ (progn
+ (setq obj (assoc kw csh-completion-list))
+ (if (or (equal nil obj)
+ (and (not (equal nil obj))
+ (not (= type (cdr obj)))))
+ (progn
+ (setq i (1+ i))
+ (csh-addto-alist kw type))))))
+ i))
+
+(defun csh-pickup-completion-driver (pmin pmax message)
+ "Driver routine for csh-pickup-completion."
+ (if message
+ (message "pickup completion..."))
+ (let* (
+ (i1
+ (csh-pickup-completion csh-completion-regexp-var
+ csh-completion-type-var
+ csh-completion-match-var
+ pmin pmax))
+ (i2
+ (csh-pickup-completion csh-completion-regexp-var2
+ csh-completion-type-var
+ csh-completion-match-var2
+ pmin pmax))
+ (i3
+ (csh-pickup-completion csh-completion-regexp-function
+ csh-completion-type-function
+ csh-completion-match-function
+ pmin pmax)))
+ (if message
+ (message "pickup %d variables and %d functions." (+ i1 i2) i3))))
+
+(defun csh-pickup-this-line ()
+ "Pickup all completions in current line."
+ (interactive)
+ (csh-pickup-completion-driver (csh-bol-point) (csh-eol-point) nil))
+
+
+(provide 'csh-mode)
+;;; csh-mode.el ends here