]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/sh-script.el
Add new maintainer (deego).
[gnu-emacs] / lisp / progmodes / sh-script.el
index a3b95231774f16167153fe61a8ad9186108ce707..283fe09cea26daf0117739c18f1a2017cfcf2382 100644 (file)
@@ -1,6 +1,6 @@
 ;;; sh-script.el --- shell-script editing commands for Emacs
 
-;; Copyright (C) 1993, 94, 95, 96, 97, 1999, 2001
+;; Copyright (C) 1993, 94, 95, 96, 97, 1999, 2001, 2003
 ;;  Free Software Foundation, Inc.
 
 ;; Author: Daniel Pfeiffer <occitan@esperanto.org>
 ;; You can do this automatically like this:
 ;;   (add-hook 'sh-set-shell-hook 'sh-learn-buffer-indent)
 ;;
-;; However...   `sh-learn-buffer-indent' is extremely slow,
+;; However...  `sh-learn-buffer-indent' is extremely slow,
 ;; especially on large-ish buffer.  Also, if there are conflicts the
 ;; "last one wins" which may not produce the desired setting.
 ;;
@@ -258,7 +258,7 @@ sh          Bourne Shell
 
 
 (defcustom sh-alias-alist
-  (nconc (if (eq system-type 'gnu/linux)
+  (append (if (eq system-type 'gnu/linux)
             '((csh . tcsh)
               (ksh . pdksh)))
         ;; for the time being
@@ -392,23 +392,25 @@ the car and cdr are the same symbol.")
 
 
 
-(easy-mmode-defsyntax sh-mode-syntax-table
-  '((?\# . "<")
-   (?\^l . ">#")
-   (?\n . ">#")
-   (?\" . "\"\"")
-   (?\' . "\"'")
-   (?\` . "\"`")
-   (?! . "_")
-   (?% . "_")
-   (?: . "_")
-   (?. . "_")
-   (?^ . "_")
-   (?~ . "_")
-   (?< . ".")
-   (?> . "."))
-  "Syntax-table used in Shell-Script mode.")
+(defvar sh-mode-syntax-table
+  '((sh eval sh-mode-syntax-table ()
+       ?\# "<"
+       ?\n ">#"
+       ?\" "\"\""
+       ?\' "\"'"
+       ?\` "\"`"
+       ?! "_"
+       ?% "_"
+       ?: "_"
+       ?. "_"
+       ?^ "_"
+       ?~ "_"
+       ?< "."
+       ?> ".")
+    (csh eval identity sh)
+    (rc eval identity sh))
 
+  "Syntax-table used in Shell-Script mode.  See `sh-feature'.")
 
 (defvar sh-mode-map
   (let ((map (make-sparse-keymap))
@@ -441,21 +443,15 @@ the car and cdr are the same symbol.")
     (define-key map "`" 'skeleton-pair-insert-maybe)
     (define-key map "\"" 'skeleton-pair-insert-maybe)
 
-    (substitute-key-definition 'complete-tag 'comint-dynamic-complete
-                              map (current-global-map))
-    (substitute-key-definition 'newline-and-indent 'sh-newline-and-indent
-                              map (current-global-map))
-    (substitute-key-definition 'delete-backward-char
-                              'backward-delete-char-untabify
-                              map (current-global-map))
+    (define-key map [remap complete-tag] 'comint-dynamic-complete)
+    (define-key map [remap newline-and-indent] 'sh-newline-and-indent)
+    (define-key map [remap delete-backward-char]
+      'backward-delete-char-untabify)
     (define-key map "\C-c:" 'sh-set-shell)
-    (substitute-key-definition 'beginning-of-defun
-                              'sh-beginning-of-compound-command
-                              map (current-global-map))
-    (substitute-key-definition 'backward-sentence 'sh-beginning-of-command
-                              map (current-global-map))
-    (substitute-key-definition 'forward-sentence 'sh-end-of-command
-                              map (current-global-map))
+    (define-key map [remap beginning-of-defun]
+      'sh-beginning-of-compound-command)
+    (define-key map [remap backward-sentence] 'sh-beginning-of-command)
+    (define-key map [remap forward-sentence] 'sh-end-of-command)
     (define-key map [menu-bar insert] (cons "Insert" menu-map))
     (define-key menu-map [sh-while]    '("While Loop" . sh-while))
     (define-key menu-map [sh-until]    '("Until Loop" . sh-until))
@@ -763,12 +759,12 @@ See `sh-feature'.")
 (defface sh-heredoc-face
   '((((class color)
       (background dark))
-     (:foreground "yellow" :bold t))
+     (:foreground "yellow" :weight bold))
     (((class color)
       (background light))
      (:foreground "tan" ))
     (t
-     (:bold t)))
+     (:weight bold)))
   "Face to show a here-document"
   :group 'sh-indentation)
 (defvar sh-heredoc-face 'sh-heredoc-face)
@@ -1055,12 +1051,12 @@ a number means align to that column, e.g. 0 means fist column."
          sh-symbol-list))
 
 (defcustom sh-indent-for-fi 0
-  "*How much to indent a fi relative to an if.   Usually 0."
+  "*How much to indent a fi relative to an if.  Usually 0."
   :type `(choice ,@ sh-number-or-symbol-list )
   :group 'sh-indentation)
 
 (defcustom sh-indent-for-done '0
-  "*How much to indent a done relative to its matching stmt.   Usually 0."
+  "*How much to indent a done relative to its matching stmt.  Usually 0."
   :type `(choice ,@ sh-number-or-symbol-list )
   :group 'sh-indentation)
 
@@ -1077,7 +1073,7 @@ does not affect then else elif or fi statements themselves."
   :group 'sh-indentation)
 
 (defcustom sh-indent-for-then '+
-  "*How much to indent an then relative to an if."
+  "*How much to indent a then relative to an if."
   :type `(choice ,@ sh-number-or-symbol-list )
   :group 'sh-indentation)
 
@@ -1186,10 +1182,6 @@ punctuation characters like '-'."
 (defvar sh-indent-supported-here nil
   "Non-nil if we support indentation for the current buffer's shell type.")
 
-(defconst sh-electric-rparen-needed
-  '((sh . t))
-  "Non-nil if the shell type needs an electric handling of case alternatives.")
-
 (defconst sh-var-list
   '(
     sh-basic-offset sh-first-lines-indent sh-indent-after-case
@@ -1227,7 +1219,7 @@ frequently editing existing scripts with different styles.")
 (put 'sh-mode 'mode-class 'special)
 
 ;;;###autoload
-(define-derived-mode sh-mode nil "Shell-script"
+(defun sh-mode ()
   "Major mode for editing shell scripts.
 This mode works for many shells, since they all have roughly the same syntax,
 as far as commands, arguments, variables, pipes, comments etc. are concerned.
@@ -1271,7 +1263,7 @@ buffer indents as it currently is indented.
 \\[sh-execute-region]   Have optional header and region be executed in a subshell.
 
 \\[sh-maybe-here-document]      Without prefix, following an unquoted < inserts here document.
-{, (, [, ', \", `
+\{, (, [, ', \", `
        Unless quoted with \\, insert the pairs {}, (), [], or '', \"\", ``.
 
 If you generally program a shell different from your login shell you can
@@ -1280,6 +1272,11 @@ indicate what shell it is use `sh-alias-alist' to translate.
 
 If your shell gives error messages with line numbers, you can use \\[executable-interpret]
 with your script for an edit-interpret-debug cycle."
+  (interactive)
+  (kill-all-local-variables)
+  (setq major-mode 'sh-mode
+       mode-name "Shell-script")
+  (use-local-map sh-mode-map)
   (make-local-variable 'skeleton-end-hook)
   (make-local-variable 'paragraph-start)
   (make-local-variable 'paragraph-separate)
@@ -1334,7 +1331,8 @@ with your script for an edit-interpret-debug cycle."
                 ((and buffer-file-name
                       (string-match "\\.m?spec$" buffer-file-name))
                  "rpm")))))
-    (sh-set-shell (or interpreter sh-shell-file) nil nil)))
+    (sh-set-shell (or interpreter sh-shell-file) nil nil))
+  (run-hooks 'sh-mode-hook))
 
 ;;;###autoload
 (defalias 'shell-script-mode 'sh-mode)
@@ -1433,12 +1431,21 @@ This adds rules for comments and assignments."
 
 (defun sh-set-shell (shell &optional no-query-flag insert-flag)
   "Set this buffer's shell to SHELL (a string).
-Makes this script executable via `executable-set-magic', and sets up the
-proper starting #!-line, if INSERT-FLAG is non-nil.
+When used interactively, insert the proper starting #!-line,
+and make the visited file executable via `executable-set-magic',
+perhaps querying depending on the value of `executable-query'.
+
+When this function is called noninteractively, INSERT-FLAG (the third
+argument) controls whether to insert a #!-line and think about making
+the visited file executable, and NO-QUERY-FLAG (the second argument)
+controls whether to query about making the visited file executable.
+
 Calls the value of `sh-set-shell-hook' if set."
-  (interactive (list (completing-read "Name or path of shell: "
-                                     interpreter-mode-alist
-                                     (lambda (x) (eq (cdr x) 'sh-mode)))
+  (interactive (list (completing-read (format "Shell \(default %s\): "
+                                             sh-shell-file)
+                                     interpreter-mode-alist
+                                     (lambda (x) (eq (cdr x) 'sh-mode))
+                                     nil nil nil sh-shell-file)
                     (eq executable-query 'function)
                     t))
   (if (string-match "\\.exe\\'" shell)
@@ -1458,6 +1465,8 @@ Calls the value of `sh-set-shell-hook' if set."
        sh-shell-variables-initialized nil
        imenu-generic-expression (sh-feature sh-imenu-generic-expression)
        imenu-case-fold-search nil)
+  (set-syntax-table (or (sh-feature sh-mode-syntax-table)
+                       (standard-syntax-table)))
   (dolist (var (sh-feature sh-variables))
     (sh-remember-variable var))
   (make-local-variable 'indent-line-function)
@@ -1572,6 +1581,13 @@ in ALIST."
 ;;      (symbol-value sh-shell)))
 
 
+(defun sh-mode-syntax-table (table &rest list)
+  "Copy TABLE and set syntax for successive CHARs according to strings S."
+  (setq table (copy-syntax-table table))
+  (while list
+    (modify-syntax-entry (pop list) (pop list) table))
+  table)
+
 (defun sh-append (ancestor &rest list)
   "Return list composed of first argument (a list) physically appended to rest."
   (nconc list ancestor))
@@ -1660,17 +1676,11 @@ region, clear header."
   (eq -1 (% (save-excursion (skip-chars-backward "\\\\")) 2)))
 \f
 ;; Indentation stuff.
-(defun sh-must-be-shell-mode ()
-  "Signal an error if not in Shell-script mode."
-  (unless (eq major-mode 'sh-mode)
-    (error "This buffer is not in Shell-script mode")))
-
 (defun sh-must-support-indent ()
   "*Signal an error if the shell type for this buffer is not supported.
 Also, the buffer must be in Shell-script mode."
-  (sh-must-be-shell-mode)
   (unless sh-indent-supported-here
-    (error "This buffer's shell type is not supported for this command")))
+    (error "This buffer's shell does not support indentation through Emacs")))
 
 (defun sh-make-vars-local ()
   "Make the indentation variables local to this buffer.
@@ -1680,7 +1690,6 @@ variable `sh-make-vars-local' has been set to nil.
 To revert all these variables to the global values, use
 command `sh-reset-indent-vars-to-global-values'."
   (interactive)
-  (sh-must-be-shell-mode)
   (mapcar 'make-local-variable sh-var-list)
   (message "Indentation variable are now local."))
 
@@ -1688,7 +1697,6 @@ command `sh-reset-indent-vars-to-global-values'."
   "Reset local indentation variables to the global values.
 Then, if variable `sh-make-vars-local' is non-nil, make them local."
   (interactive)
-  (sh-must-be-shell-mode)
   (mapcar 'kill-local-variable sh-var-list)
   (if sh-make-vars-local
       (mapcar 'make-local-variable sh-var-list)))
@@ -2147,7 +2155,6 @@ If INFO is supplied it is used, else it is calculated."
   "Back to end of previous non-comment non-empty line.
 Go to beginning of logical line unless END is non-nil, in which case
 we go to the end of the previous line and do not check for continuations."
-  (sh-must-be-shell-mode)
   (save-excursion
     (beginning-of-line)
     (forward-comment (- (point-max)))
@@ -2478,7 +2485,6 @@ If INFO is supplied it is used, else it is calculated from current line."
 (defun sh-indent-line ()
   "Indent the current line."
   (interactive)
-  (sh-must-be-shell-mode)
   (let ((indent (sh-calculate-indent)) shift-amt beg end
        (pos (- (point-max) (point))))
     (when indent
@@ -2644,13 +2650,11 @@ unless optional argument ARG (the prefix when interactive) is non-nil."
 
 (defun sh-mark-init (buffer)
   "Initialize a BUFFER to be used by `sh-mark-line'."
-  (let ((main-buffer (current-buffer)))
-    (save-excursion
-      (set-buffer (get-buffer-create buffer))
-      (erase-buffer)
-      (occur-mode)
-      (setq occur-buffer main-buffer)
-      )))
+  (save-excursion
+    (set-buffer (get-buffer-create buffer))
+    (erase-buffer)
+    (occur-mode)
+    ))
 
 
 (defun sh-mark-line (message point buffer &optional add-linenum occur-point)
@@ -2660,7 +2664,6 @@ If ADD-LINENUM is non-nil the message is preceded by the line number.
 If OCCUR-POINT is non-nil then the line is marked as a new occurrence
 so that `occur-next' and `occur-prev' will work."
   (let ((m1 (make-marker))
-       (main-buffer (current-buffer))
        start
        (line ""))
     (when point
@@ -2672,7 +2675,6 @@ so that `occur-next' and `occur-prev' will work."
          (set-buffer (get-buffer buffer))
        (set-buffer (get-buffer-create buffer))
        (occur-mode)
-       (setq occur-buffer main-buffer)
        )
       (goto-char (point-max))
       (setq start (point))
@@ -2688,10 +2690,10 @@ so that `occur-next' and `occur-prev' will work."
       (insert "\n")
       (if point
          (progn
-           (put-text-property start (point) 'occur m1)
+           (put-text-property start (point) 'occur-target m1)
            (if occur-point
-               (put-text-property occur-point (1+ occur-point)
-                                  'occur-point t))
+               (put-text-property start occur-point
+                                  'occur-match t))
            ))
       )))