]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/sh-script.el
merge upstream
[gnu-emacs] / lisp / progmodes / sh-script.el
index 07e9bb85c4e98c20ccab69b09dc2ba136b18f5f2..3ea2afb6fc3aea0b929c0741736025f809649bd5 100644 (file)
@@ -1,7 +1,6 @@
 ;;; sh-script.el --- shell-script editing commands for Emacs
 
-;; Copyright (C) 1993-1997, 1999, 2001-2013 Free Software Foundation,
-;; Inc.
+;; Copyright (C) 1993-1997, 1999, 2001-2013 Free Software Foundation, Inc.
 
 ;; Author: Daniel Pfeiffer <occitan@esperanto.org>
 ;; Version: 2.0f
@@ -497,6 +496,9 @@ This is buffer-local in every such buffer.")
     (define-key map "\C-c+" 'sh-add)
     (define-key map "\C-\M-x" 'sh-execute-region)
     (define-key map "\C-c\C-x" 'executable-interpret)
+    (define-key map "\C-c\C-n" 'sh-send-line-or-region-and-step)
+    (define-key map "\C-c\C-d" 'sh-cd-here)
+    (define-key map "\C-c\C-z" 'sh-show-shell)
 
     (define-key map [remap delete-backward-char]
       'backward-delete-char-untabify)
@@ -670,7 +672,9 @@ removed when closing the here document."
          "." "alias" "bg" "bind" "builtin" "caller" "compgen" "complete"
           "declare" "dirs" "disown" "enable" "fc" "fg" "help" "history"
           "jobs" "kill" "let" "local" "popd" "printf" "pushd" "shopt"
-          "source" "suspend" "typeset" "unalias")
+          "source" "suspend" "typeset" "unalias"
+          ;; bash4
+          "mapfile" "readarray")
 
     ;; The next entry is only used for defining the others
     (bourne sh-append shell
@@ -734,6 +738,7 @@ implemented as aliases.  See `sh-feature'."
   :type '(repeat (cons (symbol :tag "Shell")
                       (choice (repeat string)
                               (sexp :format "Evaluate: %v"))))
+  :version "24.4"                       ; bash4 additions
   :group 'sh-script)
 
 
@@ -1461,6 +1466,61 @@ command `sh-make-vars-local'.
 The default is t because I assume that in one Emacs session one is
 frequently editing existing scripts with different styles.")
 
+\f
+;; inferior shell interaction
+;; TODO: support multiple interactive shells
+(defvar sh-shell-process nil
+  "The inferior shell process for interaction.")
+(make-variable-buffer-local 'sh-shell-process)
+(defun sh-shell-process (force)
+  "Get a shell process for interaction.
+If FORCE is non-nil and no process found, create one."
+  (if (and sh-shell-process (process-live-p sh-shell-process))
+      sh-shell-process
+    (setq sh-shell-process
+          (let ((found nil) proc
+                (procs (process-list)))
+            (while (and (not found) procs
+                        (process-live-p (setq proc (pop procs)))
+                        (process-command proc))
+              (when (string-equal sh-shell (file-name-nondirectory
+                                            (car (process-command proc))))
+                (setq found proc)))
+            (or found
+                (and force
+                     (get-buffer-process
+                      (let ((explicit-shell-file-name sh-shell-file))
+                        (shell)))))))))
+
+(defun sh-show-shell ()
+  "Pop the shell interaction buffer."
+  (interactive)
+  (pop-to-buffer (process-buffer (sh-shell-process t))))
+
+(defun sh-send-text (text)
+  "Send the text to the `sh-shell-process'."
+  (comint-send-string (sh-shell-process t) (concat text "\n")))
+
+(defun sh-cd-here ()
+  "Change directory in the current interaction shell to the current one."
+  (interactive)
+  (sh-send-text (concat "cd " default-directory)))
+
+(defun sh-send-line-or-region-and-step ()
+  "Send the current line to the inferior shell and step to the next line.
+When the region is active, send the region instead."
+  (interactive)
+  (let (from to end)
+    (if (use-region-p)
+        (setq from (region-beginning)
+              to (region-end)
+              end to)
+      (setq from (line-beginning-position)
+            to (line-end-position)
+            end (1+ to)))
+    (sh-send-text (buffer-substring-no-properties from to))
+    (goto-char end)))
+
 \f
 ;; mode-command and utility functions
 
@@ -2110,11 +2170,18 @@ the visited file executable, and NO-QUERY-FLAG (the second argument)
 controls whether to query about making the visited file executable.
 
 Calls the value of `sh-set-shell-hook' if set."
-  (interactive (list (completing-read (format "Shell \(default %s\): "
-                                             sh-shell-file)
-                                     interpreter-mode-alist
-                                     (lambda (x) (eq (cdr x) 'sh-mode))
-                                     nil nil nil sh-shell-file)
+  (interactive (list (completing-read
+                      (format "Shell \(default %s\): "
+                              sh-shell-file)
+                      ;; This used to use interpreter-mode-alist, but that is
+                      ;; no longer appropriate now that uses regexps.
+                      ;; Maybe there could be a separate variable that lists
+                      ;; the shells, used here and to construct i-mode-alist.
+                      ;; But the following is probably good enough:
+                      (append (mapcar (lambda (e) (symbol-name (car e)))
+                                      sh-ancestor-alist)
+                              '("csh" "rc" "sh"))
+                      nil nil nil nil sh-shell-file)
                     (eq executable-query 'function)
                     t))
   (if (string-match "\\.exe\\'" shell)
@@ -2169,6 +2236,7 @@ Calls the value of `sh-set-shell-hook' if set."
     (setq font-lock-set-defaults nil)
     (font-lock-set-defaults)
     (font-lock-fontify-buffer))
+  (setq sh-shell-process nil)
   (run-hooks 'sh-set-shell-hook))
 
 
@@ -2401,7 +2469,6 @@ which in this buffer is currently %s.
 
 (defun sh-read-variable (var)
   "Read a new value for indentation variable VAR."
-  (interactive "*variable? ") ;; to test
   (let ((minibuffer-help-form `(sh-help-string-for-variable
                                (quote ,var)))
        val)