Add rudimentary inferior shell interaction
authorSam Steingold <sds@gnu.org>
Wed, 21 Aug 2013 01:16:27 +0000 (21:16 -0400)
committerSam Steingold <sds@gnu.org>
Wed, 21 Aug 2013 01:16:27 +0000 (21:16 -0400)
* lisp/progmodes/sh-script.el (sh-shell-process): New buffer-local variable.
(sh-set-shell): Reset it.
(sh-show-shell, sh-cd-here, sh-send-line-or-region-and-step): New
commands (bound to C-c C-z, C-c C-d, and C-c C-n).

lisp/ChangeLog
lisp/progmodes/sh-script.el

index 8e33b30..9050178 100644 (file)
@@ -1,3 +1,11 @@
+2013-08-21  Sam Steingold  <sds@gnu.org>
+
+       Add rudimentary inferior shell interaction
+       * progmodes/sh-script.el (sh-shell-process): New buffer-local variable.
+       (sh-set-shell): Reset it.
+       (sh-show-shell, sh-cd-here, sh-send-line-or-region-and-step): New
+       commands (bound to C-c C-z, C-c C-d, and C-c C-n).
+
 2013-08-20  Stefan Monnier  <monnier@iro.umontreal.ca>
 
        * align.el: Use lexical-binding.
index 29020d9..c8b65e0 100644 (file)
@@ -497,6 +497,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)
@@ -1462,6 +1465,61 @@ 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
 
 ;;;###autoload
@@ -2169,6 +2227,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))