From 708374c7bc07fd778126e43daea2651ca66a893c Mon Sep 17 00:00:00 2001 From: Daniel Colascione Date: Tue, 20 May 2014 18:54:33 -0700 Subject: [PATCH] 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 --- lisp/ChangeLog | 15 ++++++++++ lisp/files.el | 1 + lisp/progmodes/sh-script.el | 57 +++++++++++++++++++++++++------------ 3 files changed, 55 insertions(+), 18 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 733d060f453..cfa46259690 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,18 @@ +2014-05-21 Daniel Colascione + + * 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 * emacs-lisp/cl-lib.el (cl-endp): Conform to CL's semantics. diff --git a/lisp/files.el b/lisp/files.el index 666316a2353..c153a11b243 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -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) diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el index 3ff4f57b887..6d7179c0447 100644 --- a/lisp/progmodes/sh-script.el +++ b/lisp/progmodes/sh-script.el @@ -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)) - -(defvar sh-shell (sh-canonicalize-shell (file-name-nondirectory sh-shell-file)) + "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 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) -- 2.39.2