;;; sh-script.el --- shell-script editing commands for Emacs
-;; Copyright (C) 1993, 1994, 1995, 1996, 1997, 1999, 2001, 2002,
-;; 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+;; Copyright (C) 1993, 1994, 1995, 1996, 1997, 1999, 2001, 2002, 2003,
+;; 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
;; Author: Daniel Pfeiffer <occitan@esperanto.org>
;; Version: 2.0f
;; This file is part of GNU Emacs.
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
csh C Shell
jcsh C Shell with Job Control
- tcsh Turbo C Shell
- itcsh ? Turbo C Shell
+ tcsh TENEX C Shell
+ itcsh Ian's TENEX C Shell
rc Plan 9 Shell
es Extensible Shell
sh Bourne Shell
- ash ? Shell
+ ash Almquist Shell
jsh Bourne Shell with Job Control
bash GNU Bourne Again Shell
ksh88 Korn Shell '88
(defvar sh-mode-map
(let ((map (make-sparse-keymap))
- (menu-map (make-sparse-keymap "Insert")))
+ (menu-map (make-sparse-keymap)))
(define-key map "\C-c(" 'sh-function)
(define-key map "\C-c\C-w" 'sh-while)
(define-key map "\C-c\C-u" 'sh-until)
(define-key map "\"" 'skeleton-pair-insert-maybe)
(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)
(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))
- (define-key menu-map [sh-tmp-file] '("Temporary File" . sh-tmp-file))
- (define-key menu-map [sh-select] '("Select Statement" . sh-select))
- (define-key menu-map [sh-repeat] '("Repeat Loop" . sh-repeat))
- (define-key menu-map [sh-getopts] '("Options Loop" . sh-while-getopts))
- (define-key menu-map [sh-indexed-loop] '("Indexed Loop" . sh-indexed-loop))
- (define-key menu-map [sh-if] '("If Statement" . sh-if))
- (define-key menu-map [sh-for] '("For Loop" . sh-for))
- (define-key menu-map [sh-case] '("Case Statement" . sh-case))
+ (define-key map [menu-bar sh-script] (cons "Sh-Script" menu-map))
+ (define-key menu-map [sh-learn-buffer-indent]
+ '(menu-item "Learn buffer indentation" sh-learn-buffer-indent
+ :help "Learn how to indent the buffer the way it currently is."))
+ (define-key menu-map [sh-learn-line-indent]
+ '(menu-item "Learn line indentation" sh-learn-line-indent
+ :help "Learn how to indent a line as it currently is indented"))
+ (define-key menu-map [sh-show-indent]
+ '(menu-item "Show indentation" sh-show-indent
+ :help "Show the how the current line would be indented"))
+ (define-key menu-map [sh-set-indent]
+ '(menu-item "Set indentation" sh-set-indent
+ :help "Set the indentation for the current line"))
+
+ (define-key menu-map [sh-pair]
+ '(menu-item "Insert braces and quotes in pairs"
+ (lambda ()
+ (interactive)
+ (require 'skeleton)
+ (setq skeleton-pair (not skeleton-pair)))
+ :button (:toggle . (and (boundp 'skeleton-pair)
+ skeleton-pair))
+ :help "Inserting a brace or quote automatically inserts the matching pair"))
+
+ (define-key menu-map [sh-s0] '("--"))
+ ;; Insert
+ (define-key menu-map [sh-function]
+ '(menu-item "Function..." sh-function
+ :help "Insert a function definition"))
+ (define-key menu-map [sh-add]
+ '(menu-item "Addition..." sh-add
+ :help "Insert an addition of VAR and prefix DELTA for Bourne (type) shell"))
+ (define-key menu-map [sh-until]
+ '(menu-item "Until Loop" sh-until
+ :help "Insert an until loop"))
+ (define-key menu-map [sh-repeat]
+ '(menu-item "Repeat Loop" sh-repeat
+ :help "Insert a repeat loop definition"))
+ (define-key menu-map [sh-while]
+ '(menu-item "While Loop" sh-while
+ :help "Insert a while loop"))
+ (define-key menu-map [sh-getopts]
+ '(menu-item "Options Loop" sh-while-getopts
+ :help "Insert a while getopts loop."))
+ (define-key menu-map [sh-indexed-loop]
+ '(menu-item "Indexed Loop" sh-indexed-loop
+ :help "Insert an indexed loop from 1 to n."))
+ (define-key menu-map [sh-select]
+ '(menu-item "Select Statement" sh-select
+ :help "Insert a select statement "))
+ (define-key menu-map [sh-if]
+ '(menu-item "If Statement" sh-if
+ :help "Insert an if statement"))
+ (define-key menu-map [sh-for]
+ '(menu-item "For Loop" sh-for
+ :help "Insert a for loop"))
+ (define-key menu-map [sh-case]
+ '(menu-item "Case Statement" sh-case
+ :help "Insert a case/switch statement"))
+ (define-key menu-map [sh-s1] '("--"))
+ (define-key menu-map [sh-exec]
+ '(menu-item "Execute region" sh-execute-region
+ :help "Pass optional header and region to a subshell for noninteractive execution"))
+ (define-key menu-map [sh-exec-interpret]
+ '(menu-item "Execute script..." executable-interpret
+ :help "Run script with user-specified args, and collect output in a buffer"))
+ (define-key menu-map [sh-set-shell]
+ '(menu-item "Set shell type..." sh-set-shell
+ :help "Set this buffer's shell to SHELL (a string)"))
+ (define-key menu-map [sh-backslash-region]
+ '(menu-item "Backslash region" sh-backslash-region
+ :help "Insert, align, or delete end-of-line backslashes on the lines in the region."))
map)
"Keymap used in Shell-Script mode.")
"The width for further indentation in Shell-Script mode."
:type 'integer
:group 'sh-script)
-
+(put 'sh-indentation 'safe-local-variable 'integerp)
(defcustom sh-remember-variable-min 3
"Don't remember variables less than this length for completing reads."
(:foreground "yellow" :weight bold))
(((class color)
(background light))
- (:foreground "tan" ))
+ (:foreground "tan1" ))
(t
(:weight bold)))
"Face to show a here-document"
:group 'sh-indentation)
-;; These colours are probably icky. It's just a placeholder though.
+;; These colors are probably icky. It's just a placeholder though.
(defface sh-quoted-exec
'((((class color) (background dark))
(:foreground "salmon"))
(:weight bold)))
"Face to show quoted execs like ``"
:group 'sh-indentation)
-
-;; backward-compatibility alias
-(put 'sh-heredoc-face 'face-alias 'sh-heredoc)
+(define-obsolete-face-alias 'sh-heredoc-face 'sh-heredoc "22.1")
(defvar sh-heredoc-face 'sh-heredoc)
(defface sh-escaped-newline '((t :inherit font-lock-string-face))
(defun sh-font-lock-open-heredoc (start string)
"Determine the syntax of the \\n after a <<EOF.
START is the position of <<.
-STRING is the actual word used as delimiter (f.ex. \"EOF\").
+STRING is the actual word used as delimiter (e.g. \"EOF\").
INDENTED is non-nil if the here document's content (and the EOF mark) can
be indented (i.e. a <<- was used rather than just <<).
Point is at the beginning of the next line."
(state (if (eq (char-before) ?`) 'backquote 'code))
;; Stacked states in the context.
(states '(double-quote)))
- (while (and state (progn (skip-chars-forward "^'\\\"`$()" limit)
+ (while (and state (progn (skip-chars-forward "^'\\\\\"`$()" limit)
(< (point) limit)))
;; unescape " inside a $( ... ) construct.
(case (char-after)
- (?\' (skip-chars-forward "^'" limit))
+ (?\' (case state
+ (double-quote nil)
+ (t (forward-char 1) (skip-chars-forward "^'" limit))))
(?\\ (forward-char 1))
(?\" (case state
(double-quote (setq state (pop states)))
(when (memq (char-before) '(?\" ?\'))
(condition-case nil (progn (backward-sexp 1) t)
(error nil)))))
+ ;; Patterns can be preceded by an open-paren (Bug#1320).
+ (if (eq (char-before (point)) ?\()
+ (backward-char 1))
(while (progn
(forward-comment (- (point-max)))
;; Maybe we've bumped into an escaped newline.
;; change the syntax, so we have to tell syntax-ppss that the states it
;; has just computed will need to be recomputed.
(sh-font-lock-flush-syntax-ppss-cache)
- ;; Make sure $@ and @? are correctly recognized as sexps.
+ ;; Make sure $@ and $? are correctly recognized as sexps.
("\\$\\([?@]\\)" 1 ,sh-st-symbol)
;; Find HEREDOC starters and add a corresponding rule for the ender.
(sh-font-lock-here-doc
"Variables controlling indentation in shell scripts.
Note: customizing these variables will not affect existing buffers if
-`sh-make-vars-local' is no-nil. See the documentation for
+`sh-make-vars-local' is non-nil. See the documentation for
variable `sh-make-vars-local', command `sh-make-vars-local'
and command `sh-reset-indent-vars-to-global-values'."
:group 'sh-script)
This value is used for the `+' and `-' symbols in an indentation variable."
:type 'integer
:group 'sh-indentation)
+(put 'sh-basic-offset 'safe-local-variable 'integerp)
(defcustom sh-indent-comment nil
"How a comment line is to be indented.
\\[backward-delete-char-untabify] Delete backward one position, even if it was a tab.
-\\[sh-newline-and-indent] Delete unquoted space and indent new line same as this one.
+\\[newline-and-indent] Delete unquoted space and indent new line same as this one.
\\[sh-end-of-command] Go to end of successive commands.
\\[sh-beginning-of-command] Go to beginning of successive commands.
\\[sh-set-shell] Set this buffer's shell, and maybe its magic number.
(goto-char where))
(prog1
(buffer-substring (point)
- (progn (skip-chars-forward "^ \t\n;&|()")(point)))
+ (progn (skip-chars-forward "^ \t\n;&|")(point)))
(unless and-move
(goto-char start)))))
(if msg (message "%s" msg) (message nil))))
(defun sh-show-indent (arg)
- "Show the how the currently line would be indented.
+ "Show the how the current line would be indented.
This tells you which variable, if any, controls the indentation of
this line.
If optional arg ARG is non-null (called interactively with a prefix),
;;
;; (defun what-i-learned (list)
;; (let ((p list))
-;; (save-excursion
-;; (set-buffer "*scratch*")
+;; (with-current-buffer "*scratch*"
;; (goto-char (point-max))
;; (insert "(setq\n")
;; (while p
Output in buffer \"*indent*\" shows any lines which have conflicting
values of a variable, and the final value of all variables learned.
-This buffer is popped to automatically if there are any discrepancies.
+When called interactively, pop to this buffer automatically if
+there are any discrepancies.
If no prefix ARG is given, then variables are set to numbers.
If a prefix arg is given, then variables are set to symbols when
)))
;; Are abnormal hooks considered bad form?
(run-hook-with-args 'sh-learned-buffer-hook learned-var-list)
- (if (or sh-popup-occur-buffer (> num-diffs 0))
- (pop-to-buffer out-buffer))
- )))
+ (and (called-interactively-p 'any)
+ (or sh-popup-occur-buffer (> num-diffs 0))
+ (pop-to-buffer out-buffer)))))
(defun sh-guess-basic-offset (vec)
"See if we can determine a reasonable value for `sh-basic-offset'.
(interactive "*P")
(self-insert-command (prefix-numeric-value arg))
(or arg
- (not (eq (char-after (- (point) 2)) last-command-char))
+ (not (looking-back "[^<]<<"))
(save-excursion
(backward-char 2)
(sh-quoted-p))
-(defun sh-newline-and-indent ()
- "Strip unquoted whitespace, insert newline, and indent like current line."
- (interactive "*")
- (indent-to (prog1 (current-indentation)
- (delete-region (point)
- (progn
- (or (zerop (skip-chars-backward " \t"))
- (if (sh-quoted-p)
- (forward-char)))
- (point)))
- (newline))))
-
(defun sh-beginning-of-command ()
"Move point to successive beginnings of commands."
(interactive)