File-local-variable support for sh-script; add mksh support

* lisp/files.el (interpreter-mode-alist): Add mksh.

* lisp/progmodes/sh-script.el (sh-ancestor-alist): Add mksh, a pdksh
derivative.
(sh-alias-alist): Alias /system/bin/sh (Android's system shell) to
mksh. Improve custom spec; allow regular expressions.
(sh-shell): Delegate name splitting to `sh-canonicalize-shell'.
(sh-after-hack-local-variables): New function.
(sh-mode): Use it; respect file-local `sh-shell' variable.
(sh-set-shell): Use `sh-canonicalize-shell' instead of open-coding
the normalization.
(sh-canonicalize-shell): Rewrite to support regexes.

Fixes: debbugs:17333
This commit is contained in:
Daniel Colascione 2014-05-20 18:54:33 -07:00
parent a05affb238
commit 708374c7bc
3 changed files with 54 additions and 17 deletions

View file

@ -1,3 +1,18 @@
2014-05-21 Daniel Colascione <dancol@dancol.org>
* files.el (interpreter-mode-alist): Add mksh.
* progmodes/sh-script.el (sh-ancestor-alist): Add mksh, a pdksh
derivative.
(sh-alias-alist): Alias /system/bin/sh (Android's system shell) to
mksh. Improve custom spec; allow regular expressions.
(sh-shell): Delegate name splitting to `sh-canonicalize-shell'.
(sh-after-hack-local-variables): New function.
(sh-mode): Use it; respect file-local `sh-shell' variable. (bug#17333)
(sh-set-shell): Use `sh-canonicalize-shell' instead of open-coding
the normalization.
(sh-canonicalize-shell): Rewrite to support regexes.
2014-05-19 Leo Liu <sdl.web@gmail.com>
* emacs-lisp/cl-lib.el (cl-endp): Conform to CL's semantics.

View file

@ -2501,6 +2501,7 @@ and `magic-mode-alist', which determines modes based on file contents.")
("[acjkwz]sh" . sh-mode)
("r?bash2?" . sh-mode)
("dash" . sh-mode)
("mksh" . sh-mode)
("\\(dt\\|pd\\|w\\)ksh" . sh-mode)
("es" . sh-mode)
("i?tcsh" . sh-mode)

View file

@ -237,6 +237,7 @@
(ksh88 . jsh)
(oash . sh)
(pdksh . ksh88)
(mksh . pdksh)
(posix . sh)
(tcsh . csh)
(wksh . ksh88)
@ -262,6 +263,7 @@ sh Bourne Shell
ksh Korn Shell '93
dtksh CDE Desktop Korn Shell
pdksh Public Domain Korn Shell
mksh MirOS BSD Korn Shell
wksh Window Korn Shell
zsh Z Shell
oash SCO OA (curses) Shell
@ -271,7 +273,6 @@ sh Bourne Shell
:version "24.4" ; added dash
:group 'sh-script)
(defcustom sh-alias-alist
(append (if (eq system-type 'gnu/linux)
'((csh . tcsh)
@ -279,11 +280,20 @@ sh Bourne Shell
;; for the time being
'((ksh . ksh88)
(bash2 . bash)
(sh5 . sh)))
(sh5 . sh)
;; Android's system shell
("^/system/bin/sh$" . mksh)))
"Alist for transforming shell names to what they really are.
Use this where the name of the executable doesn't correspond to the type of
shell it really is."
:type '(repeat (cons symbol symbol))
Use this where the name of the executable doesn't correspond to
the type of shell it really is. Keys are regular expressions
matched against the full path of the interpreter. (For backward
compatibility, keys may also be symbols, which are matched
against the interpreter's basename. The values are symbols
naming the shell."
:type '(repeat (cons (radio
(regexp :tag "Regular expression")
(symbol :tag "Basename"))
(symbol :tag "Shell")))
:group 'sh-script)
@ -387,15 +397,20 @@ the car and cdr are the same symbol.")
"Non-nil if `sh-shell-variables' is initialized.")
(defun sh-canonicalize-shell (shell)
"Convert a shell name SHELL to the one we should handle it as."
(if (string-match "\\.exe\\'" shell)
(setq shell (substring shell 0 (match-beginning 0))))
(or (symbolp shell)
(setq shell (intern shell)))
(or (cdr (assq shell sh-alias-alist))
shell))
"Convert a shell name SHELL to the one we should handle it as.
SHELL is a full path to the shell interpreter; return a shell
name symbol."
(cl-loop
with shell = (cond ((string-match "\\.exe\\'" shell)
(substring shell 0 (match-beginning 0)))
(t shell))
with shell-base = (intern (file-name-nondirectory shell))
for (key . value) in sh-alias-alist
if (and (stringp key) (string-match key shell)) return value
if (eq key shell-base) return value
finally return shell-base))
(defvar sh-shell (sh-canonicalize-shell (file-name-nondirectory sh-shell-file))
(defvar sh-shell (sh-canonicalize-shell sh-shell-file)
"The shell being programmed. This is set by \\[sh-set-shell].")
;;;###autoload(put 'sh-shell 'safe-local-variable 'symbolp)
@ -1533,6 +1548,12 @@ When the region is active, send the region instead."
;; mode-command and utility functions
(defun sh-after-hack-local-variables ()
(when (assq 'sh-shell file-local-variables-alist)
(sh-set-shell (if (symbolp sh-shell)
(symbol-name sh-shell)
sh-shell))))
;;;###autoload
(define-derived-mode sh-mode prog-mode "Shell-script"
"Major mode for editing shell scripts.
@ -1643,7 +1664,9 @@ with your script for an edit-interpret-debug cycle."
((string-match "[.]csh\\>" buffer-file-name) "csh")
((equal (file-name-nondirectory buffer-file-name) ".profile") "sh")
(t sh-shell-file))
nil nil))
nil nil)
(add-hook 'hack-local-variables-hook
#'sh-after-hack-local-variables nil t))
;;;###autoload
(defalias 'shell-script-mode 'sh-mode)
@ -2253,9 +2276,7 @@ Calls the value of `sh-set-shell-hook' if set."
t))
(if (string-match "\\.exe\\'" shell)
(setq shell (substring shell 0 (match-beginning 0))))
(setq sh-shell (intern (file-name-nondirectory shell))
sh-shell (or (cdr (assq sh-shell sh-alias-alist))
sh-shell))
(setq sh-shell (sh-canonicalize-shell shell))
(if insert-flag
(setq sh-shell-file
(executable-set-magic shell (sh-feature sh-shell-arg)