;;; 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.
;;
(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
-(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))
(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))
(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)
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)
: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)
(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
(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.
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)
((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)
(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)
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)
;; (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))
(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)
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
(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))
(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))
))
)))