From 3fe5fc3dc164fbc12c7716d6b5430f2b85833290 Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sat, 26 Nov 2022 15:31:48 -0800 Subject: [PATCH] Make bash-ts-mode fall back to sh-mode if the file isn't in Bash * lisp/progmodes/sh-script.el (sh--guess-shell): Take out into a new function. (sh-base-mode): Use the new function. (bash-ts-mode): Update docstring. (sh--redirect-recursing): New variable. (sh--redirect-bash-ts-mode): New function. --- lisp/progmodes/sh-script.el | 58 +++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el index e11fb42fc88..fee86dde7bf 100644 --- a/lisp/progmodes/sh-script.el +++ b/lisp/progmodes/sh-script.el @@ -1468,6 +1468,25 @@ When the region is active, send the region instead." (defvar sh-mode--treesit-settings) +(defun sh--guess-shell () + "Guess the shell used in the current buffer. +Return the name of the shell suitable for `sh-set-shell'." + (cond ((save-excursion + (goto-char (point-min)) + (looking-at auto-mode-interpreter-regexp)) + (match-string 2)) + ((not buffer-file-name) sh-shell-file) + ;; Checks that use `buffer-file-name' follow. + ((string-match "\\.m?spec\\'" buffer-file-name) "rpm") + ((string-match "[.]sh\\>" buffer-file-name) "sh") + ((string-match "[.]bash\\(rc\\)?\\>" buffer-file-name) "bash") + ((string-match "[.]ksh\\>" buffer-file-name) "ksh") + ((string-match "[.]mkshrc\\>" buffer-file-name) "mksh") + ((string-match "[.]t?csh\\(rc\\)?\\>" buffer-file-name) "csh") + ((string-match "[.]zsh\\(rc\\|env\\)?\\>" buffer-file-name) "zsh") + ((equal (file-name-nondirectory buffer-file-name) ".profile") "sh") + (t sh-shell-file))) + ;;;###autoload (define-derived-mode sh-base-mode prog-mode "Shell-script" "Generic major mode for editing shell scripts. @@ -1519,23 +1538,7 @@ implementations. Currently there are two: `sh-mode' and "\\"))) ;; Parse or insert magic number for exec, and set all variables depending ;; on the shell thus determined. - (sh-set-shell - (cond ((save-excursion - (goto-char (point-min)) - (looking-at auto-mode-interpreter-regexp)) - (match-string 2)) - ((not buffer-file-name) sh-shell-file) - ;; Checks that use `buffer-file-name' follow. - ((string-match "\\.m?spec\\'" buffer-file-name) "rpm") - ((string-match "[.]sh\\>" buffer-file-name) "sh") - ((string-match "[.]bash\\(rc\\)?\\>" buffer-file-name) "bash") - ((string-match "[.]ksh\\>" buffer-file-name) "ksh") - ((string-match "[.]mkshrc\\>" buffer-file-name) "mksh") - ((string-match "[.]t?csh\\(rc\\)?\\>" buffer-file-name) "csh") - ((string-match "[.]zsh\\(rc\\|env\\)?\\>" buffer-file-name) "zsh") - ((equal (file-name-nondirectory buffer-file-name) ".profile") "sh") - (t sh-shell-file)) - nil nil) + (sh-set-shell (sh--guess-shell) nil nil) (add-hook 'flymake-diagnostic-functions #'sh-shellcheck-flymake nil t) (add-hook 'hack-local-variables-hook #'sh-after-hack-local-variables nil t)) @@ -1605,7 +1608,9 @@ with your script for an edit-interpret-debug cycle." ;;;###autoload (define-derived-mode bash-ts-mode sh-base-mode "Bash" - "Major mode for editing Bash shell scripts." + "Major mode for editing Bash shell scripts. +This mode automatically falls back to `sh-mode' if the buffer is +not written in Bash or sh." (when (treesit-ready-p 'bash) (setq-local treesit-font-lock-feature-list '(( comment function) @@ -1616,6 +1621,23 @@ with your script for an edit-interpret-debug cycle." sh-mode--treesit-settings) (treesit-major-mode-setup))) +(advice-add 'bash-ts-mode :around #'sh--redirect-bash-ts-mode + ;; Give it lower precedence than normal advice, so other + ;; advices take precedence over it. + '((depth . 50))) + +(defvar sh--redirect-recursing nil) +(defun sh--redirect-bash-ts-mode (oldfn) + "Redirect to `sh-mode' if the current file is not written in Bash. +OLDFN should be `bash-ts-mode'." + (let ((sh--redirect-recursing sh--redirect-recursing)) + (funcall (if (or delay-mode-hooks sh--redirect-recursing) + oldfn + (setq sh--redirect-recursing t) + (if (member (file-name-base (sh--guess-shell)) '("bash" "sh")) + oldfn + #'sh-mode))))) + (defun sh-font-lock-keywords (&optional keywords) "Function to get simple fontification based on `sh-font-lock-keywords'. This adds rules for comments and assignments." -- 2.39.5