1 |
;;; sh-script.el --- shell-script editing commands for Emacs |
;;; sh-script.el --- shell-script editing commands for Emacs |
2 |
|
|
3 |
;; Copyright (C) 1993, 94, 95, 96, 97, 1999, 2001 |
;; Copyright (C) 1993, 94, 95, 96, 97, 1999, 2001, 2003 |
4 |
;; Free Software Foundation, Inc. |
;; Free Software Foundation, Inc. |
5 |
|
|
6 |
;; Author: Daniel Pfeiffer <occitan@esperanto.org> |
;; Author: Daniel Pfeiffer <occitan@esperanto.org> |
116 |
;; You can do this automatically like this: |
;; You can do this automatically like this: |
117 |
;; (add-hook 'sh-set-shell-hook 'sh-learn-buffer-indent) |
;; (add-hook 'sh-set-shell-hook 'sh-learn-buffer-indent) |
118 |
;; |
;; |
119 |
;; However... `sh-learn-buffer-indent' is extremely slow, |
;; However... `sh-learn-buffer-indent' is extremely slow, |
120 |
;; especially on large-ish buffer. Also, if there are conflicts the |
;; especially on large-ish buffer. Also, if there are conflicts the |
121 |
;; "last one wins" which may not produce the desired setting. |
;; "last one wins" which may not produce the desired setting. |
122 |
;; |
;; |
195 |
|
|
196 |
(eval-when-compile |
(eval-when-compile |
197 |
(require 'skeleton) |
(require 'skeleton) |
198 |
|
(require 'cl) |
199 |
(require 'comint)) |
(require 'comint)) |
200 |
(require 'executable) |
(require 'executable) |
201 |
|
|
259 |
|
|
260 |
|
|
261 |
(defcustom sh-alias-alist |
(defcustom sh-alias-alist |
262 |
(nconc (if (eq system-type 'gnu/linux) |
(append (if (eq system-type 'gnu/linux) |
263 |
'((csh . tcsh) |
'((csh . tcsh) |
264 |
(ksh . pdksh))) |
(ksh . pdksh))) |
265 |
;; for the time being |
;; for the time being |
396 |
(defvar sh-mode-syntax-table |
(defvar sh-mode-syntax-table |
397 |
'((sh eval sh-mode-syntax-table () |
'((sh eval sh-mode-syntax-table () |
398 |
?\# "<" |
?\# "<" |
|
?\^l ">#" |
|
399 |
?\n ">#" |
?\n ">#" |
400 |
?\" "\"\"" |
?\" "\"\"" |
401 |
?\' "\"'" |
?\' "\"'" |
444 |
(define-key map "`" 'skeleton-pair-insert-maybe) |
(define-key map "`" 'skeleton-pair-insert-maybe) |
445 |
(define-key map "\"" 'skeleton-pair-insert-maybe) |
(define-key map "\"" 'skeleton-pair-insert-maybe) |
446 |
|
|
447 |
(substitute-key-definition 'complete-tag 'comint-dynamic-complete |
(define-key map [remap complete-tag] 'comint-dynamic-complete) |
448 |
map (current-global-map)) |
(define-key map [remap newline-and-indent] 'sh-newline-and-indent) |
449 |
(substitute-key-definition 'newline-and-indent 'sh-newline-and-indent |
(define-key map [remap delete-backward-char] |
450 |
map (current-global-map)) |
'backward-delete-char-untabify) |
|
(substitute-key-definition 'delete-backward-char |
|
|
'backward-delete-char-untabify |
|
|
map (current-global-map)) |
|
451 |
(define-key map "\C-c:" 'sh-set-shell) |
(define-key map "\C-c:" 'sh-set-shell) |
452 |
(substitute-key-definition 'beginning-of-defun |
(define-key map [remap backward-sentence] 'sh-beginning-of-command) |
453 |
'sh-beginning-of-compound-command |
(define-key map [remap forward-sentence] 'sh-end-of-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)) |
|
454 |
(define-key map [menu-bar insert] (cons "Insert" menu-map)) |
(define-key map [menu-bar insert] (cons "Insert" menu-map)) |
455 |
(define-key menu-map [sh-while] '("While Loop" . sh-while)) |
(define-key menu-map [sh-while] '("While Loop" . sh-while)) |
456 |
(define-key menu-map [sh-until] '("Until Loop" . sh-until)) |
(define-key menu-map [sh-until] '("Until Loop" . sh-until)) |
1050 |
sh-symbol-list)) |
sh-symbol-list)) |
1051 |
|
|
1052 |
(defcustom sh-indent-for-fi 0 |
(defcustom sh-indent-for-fi 0 |
1053 |
"*How much to indent a fi relative to an if. Usually 0." |
"*How much to indent a fi relative to an if. Usually 0." |
1054 |
:type `(choice ,@ sh-number-or-symbol-list ) |
:type `(choice ,@ sh-number-or-symbol-list ) |
1055 |
:group 'sh-indentation) |
:group 'sh-indentation) |
1056 |
|
|
1057 |
(defcustom sh-indent-for-done '0 |
(defcustom sh-indent-for-done '0 |
1058 |
"*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." |
1059 |
:type `(choice ,@ sh-number-or-symbol-list ) |
:type `(choice ,@ sh-number-or-symbol-list ) |
1060 |
:group 'sh-indentation) |
:group 'sh-indentation) |
1061 |
|
|
1072 |
:group 'sh-indentation) |
:group 'sh-indentation) |
1073 |
|
|
1074 |
(defcustom sh-indent-for-then '+ |
(defcustom sh-indent-for-then '+ |
1075 |
"*How much to indent an then relative to an if." |
"*How much to indent a then relative to an if." |
1076 |
:type `(choice ,@ sh-number-or-symbol-list ) |
:type `(choice ,@ sh-number-or-symbol-list ) |
1077 |
:group 'sh-indentation) |
:group 'sh-indentation) |
1078 |
|
|
1181 |
(defvar sh-indent-supported-here nil |
(defvar sh-indent-supported-here nil |
1182 |
"Non-nil if we support indentation for the current buffer's shell type.") |
"Non-nil if we support indentation for the current buffer's shell type.") |
1183 |
|
|
|
(defconst sh-electric-rparen-needed |
|
|
'((sh . t)) |
|
|
"Non-nil if the shell type needs an electric handling of case alternatives.") |
|
|
|
|
1184 |
(defconst sh-var-list |
(defconst sh-var-list |
1185 |
'( |
'( |
1186 |
sh-basic-offset sh-first-lines-indent sh-indent-after-case |
sh-basic-offset sh-first-lines-indent sh-indent-after-case |
1440 |
controls whether to query about making the visited file executable. |
controls whether to query about making the visited file executable. |
1441 |
|
|
1442 |
Calls the value of `sh-set-shell-hook' if set." |
Calls the value of `sh-set-shell-hook' if set." |
1443 |
(interactive (list (completing-read "Name or path of shell: " |
(interactive (list (completing-read (format "Shell \(default %s\): " |
1444 |
interpreter-mode-alist |
sh-shell-file) |
1445 |
(lambda (x) (eq (cdr x) 'sh-mode))) |
interpreter-mode-alist |
1446 |
|
(lambda (x) (eq (cdr x) 'sh-mode)) |
1447 |
|
nil nil nil sh-shell-file) |
1448 |
(eq executable-query 'function) |
(eq executable-query 'function) |
1449 |
t)) |
t)) |
1450 |
(if (string-match "\\.exe\\'" shell) |
(if (string-match "\\.exe\\'" shell) |
2484 |
(defun sh-indent-line () |
(defun sh-indent-line () |
2485 |
"Indent the current line." |
"Indent the current line." |
2486 |
(interactive) |
(interactive) |
2487 |
(let ((indent (sh-calculate-indent)) shift-amt beg end |
(let ((indent (sh-calculate-indent)) |
2488 |
(pos (- (point-max) (point)))) |
(pos (- (point-max) (point)))) |
2489 |
(when indent |
(when indent |
2490 |
(beginning-of-line) |
(beginning-of-line) |
|
(setq beg (point)) |
|
2491 |
(skip-chars-forward " \t") |
(skip-chars-forward " \t") |
2492 |
(setq shift-amt (- indent (current-column))) |
(indent-line-to indent) |
|
(unless (zerop shift-amt) |
|
|
(delete-region beg (point)) |
|
|
(indent-to indent)) |
|
2493 |
;; If initial point was within line's indentation, |
;; If initial point was within line's indentation, |
2494 |
;; position after the indentation. Else stay at same point in text. |
;; position after the indentation. Else stay at same point in text. |
2495 |
(if (> (- (point-max) pos) (point)) |
(if (> (- (point-max) pos) (point)) |
2645 |
|
|
2646 |
(defun sh-mark-init (buffer) |
(defun sh-mark-init (buffer) |
2647 |
"Initialize a BUFFER to be used by `sh-mark-line'." |
"Initialize a BUFFER to be used by `sh-mark-line'." |
2648 |
(let ((main-buffer (current-buffer))) |
(save-excursion |
2649 |
(save-excursion |
(set-buffer (get-buffer-create buffer)) |
2650 |
(set-buffer (get-buffer-create buffer)) |
(erase-buffer) |
2651 |
(erase-buffer) |
(occur-mode) |
2652 |
(occur-mode) |
)) |
|
(setq occur-buffer main-buffer) |
|
|
))) |
|
2653 |
|
|
2654 |
|
|
2655 |
(defun sh-mark-line (message point buffer &optional add-linenum occur-point) |
(defun sh-mark-line (message point buffer &optional add-linenum occur-point) |
2659 |
If OCCUR-POINT is non-nil then the line is marked as a new occurrence |
If OCCUR-POINT is non-nil then the line is marked as a new occurrence |
2660 |
so that `occur-next' and `occur-prev' will work." |
so that `occur-next' and `occur-prev' will work." |
2661 |
(let ((m1 (make-marker)) |
(let ((m1 (make-marker)) |
|
(main-buffer (current-buffer)) |
|
2662 |
start |
start |
2663 |
(line "")) |
(line "")) |
2664 |
(when point |
(when point |
2670 |
(set-buffer (get-buffer buffer)) |
(set-buffer (get-buffer buffer)) |
2671 |
(set-buffer (get-buffer-create buffer)) |
(set-buffer (get-buffer-create buffer)) |
2672 |
(occur-mode) |
(occur-mode) |
|
(setq occur-buffer main-buffer) |
|
2673 |
) |
) |
2674 |
(goto-char (point-max)) |
(goto-char (point-max)) |
2675 |
(setq start (point)) |
(setq start (point)) |
2685 |
(insert "\n") |
(insert "\n") |
2686 |
(if point |
(if point |
2687 |
(progn |
(progn |
2688 |
(put-text-property start (point) 'occur m1) |
(put-text-property start (point) 'occur-target m1) |
2689 |
(if occur-point |
(if occur-point |
2690 |
(put-text-property occur-point (1+ occur-point) |
(put-text-property start occur-point |
2691 |
'occur-point t)) |
'occur-match t)) |
2692 |
)) |
)) |
2693 |
))) |
))) |
2694 |
|
|
3074 |
;; You are welcome to add the syntax or even completely new statements as |
;; You are welcome to add the syntax or even completely new statements as |
3075 |
;; appropriate for your favorite shell. |
;; appropriate for your favorite shell. |
3076 |
|
|
3077 |
|
(defconst sh-non-closing-paren |
3078 |
|
;; If we leave it rear-sticky, calling `newline' ends up inserting a \n |
3079 |
|
;; that inherits this property, which then confuses the indentation. |
3080 |
|
(propertize ")" 'syntax-table sh-st-punc 'rear-nonsticky t)) |
3081 |
|
|
3082 |
(define-skeleton sh-case |
(define-skeleton sh-case |
3083 |
"Insert a case/switch statement. See `sh-feature'." |
"Insert a case/switch statement. See `sh-feature'." |
3084 |
(csh "expression: " |
(csh "expression: " |
3108 |
?\} > \n) |
?\} > \n) |
3109 |
(sh "expression: " |
(sh "expression: " |
3110 |
> "case " str " in" \n |
> "case " str " in" \n |
3111 |
> (read-string "pattern: ") |
( "pattern, %s: " |
3112 |
(propertize ")" 'syntax-table sh-st-punc) |
> str sh-non-closing-paren \n |
|
\n |
|
|
> _ \n |
|
|
";;" \n |
|
|
( "other pattern, %s: " |
|
|
> str (propertize ")" 'syntax-table sh-st-punc) \n |
|
3113 |
> _ \n |
> _ \n |
3114 |
";;" \n) |
";;" \n) |
3115 |
> "*" (propertize ")" 'syntax-table sh-st-punc) \n |
> "*" sh-non-closing-paren \n |
3116 |
> _ \n |
> _ \n |
3117 |
resume: |
resume: |
3118 |
"esac" > \n)) |
"esac" > \n)) |
3215 |
(cons name name))) |
(cons name name))) |
3216 |
process-environment) |
process-environment) |
3217 |
sh-shell-variables)))) |
sh-shell-variables)))) |
3218 |
(cond ((null code) |
(case code |
3219 |
(try-completion string sh-shell-variables predicate)) |
(nil (try-completion string sh-shell-variables predicate)) |
3220 |
((eq code t) |
(lambda (test-completion string sh-shell-variables predicate)) |
3221 |
(all-completions string sh-shell-variables predicate)) |
(t (all-completions string sh-shell-variables predicate))))) |
|
((eq code 'lambda) |
|
|
(assoc string sh-shell-variables))))) |
|
3222 |
|
|
3223 |
(defun sh-add (var delta) |
(defun sh-add (var delta) |
3224 |
"Insert an addition of VAR and prefix DELTA for Bourne (type) shell." |
"Insert an addition of VAR and prefix DELTA for Bourne (type) shell." |
3445 |
v2 "\"$OPTARG\"") |
v2 "\"$OPTARG\"") |
3446 |
(setq v1 (cdr v1) |
(setq v1 (cdr v1) |
3447 |
v2 nil))) |
v2 nil))) |
3448 |
> str "|+" str (propertize ")" 'syntax-table sh-st-punc) \n |
> str "|+" str sh-non-closing-paren \n |
3449 |
> _ v2 \n |
> _ v2 \n |
3450 |
> ";;" \n) |
> ";;" \n) |
3451 |
> "*" (propertize ")" 'syntax-table sh-st-punc) \n |
> "*" sh-non-closing-paren \n |
3452 |
> "echo" " \"usage: " "`basename $0`" |
> "echo" " \"usage: " "`basename $0`" |
3453 |
" [+-" '(setq v1 (point)) str |
" [+-" '(setq v1 (point)) str |
3454 |
'(save-excursion |
'(save-excursion |