Sync to HEAD
[bpt/emacs.git] / lisp / eshell / esh-mode.el
index 0bb0773..fefa340 100644 (file)
@@ -1,6 +1,8 @@
-;;; esh-mode --- user interface
+;;; esh-mode.el --- user interface
 
-;; Copyright (C) 1999, 2000 Free Software Foundation
+;; Copyright (C) 1999, 2000, 2001, 2004 Free Software Foundation
+
+;; Author: John Wiegley <johnw@gnu.org>
 
 ;; This file is part of GNU Emacs.
 
@@ -107,6 +109,11 @@ The input is contained in the region from `eshell-last-input-start' to
   :type 'hook
   :group 'eshell-mode)
 
+(defcustom eshell-send-direct-to-subprocesses nil
+  "*If t, send any input immediately to a subprocess."
+  :type 'boolean
+  :group 'eshell-mode)
+
 (defcustom eshell-expand-input-functions nil
   "*Functions to call before input is parsed.
 Each function is passed two arguments, which bounds the region of the
@@ -173,9 +180,7 @@ inserted.  They return the string as it should be inserted."
   :group 'eshell-mode)
 
 (defcustom eshell-password-prompt-regexp
-  "\\(\\([Oo]ld \\|[Nn]ew \\|Kerberos \\|CVS \\|'s \\|login \\|^\\)\
-[Pp]assword\\|pass phrase\\|\\(Enter\\|Repeat\\) passphrase\\)\
-\\( for [^@ \t\n]+@[^@ \t\n]+\\)?:\\s *\\'"
+  "[Pp]ass\\(word\\|phrase\\).*:\\s *\\'"
   "*Regexp matching prompts for passwords in the inferior process.
 This is used by `eshell-watch-for-password-prompt'."
   :type 'regexp
@@ -183,7 +188,7 @@ This is used by `eshell-watch-for-password-prompt'."
 
 (defcustom eshell-skip-prompt-function nil
   "*A function called from beginning of line to skip the prompt."
-  :type 'function
+  :type '(choice (const nil) function)
   :group 'eshell-mode)
 
 (defcustom eshell-status-in-modeline t
@@ -191,11 +196,6 @@ This is used by `eshell-watch-for-password-prompt'."
   :type 'boolean
   :group 'eshell-mode)
 
-(defvar eshell-non-interactive-p nil
-  "A variable which is non-nil when Eshell is not running interactively.
-Modules should use this variable so that they don't clutter non-interactive
-sessions, such as when using `eshell-command'.")
-
 (defvar eshell-first-time-p t
   "A variable which is non-nil the first time Eshell is loaded.")
 
@@ -280,8 +280,11 @@ sessions, such as when using `eshell-command'.")
        (map-char-table
         (function
          (lambda (key val)
-           (and (>= key 256)
-                (/= (char-syntax key) ?w)
+           (and (if (consp key)
+                    (and (>= (car key) 128)
+                         (/= (char-syntax (car key)) ?w))
+                  (and (>= key 256)
+                       (/= (char-syntax key) ?w)))
                 (modify-syntax-entry key "_   "
                                      eshell-mode-syntax-table))))
         (standard-syntax-table)))))
@@ -305,7 +308,7 @@ sessions, such as when using `eshell-command'.")
 
   (when eshell-status-in-modeline
     (make-local-variable 'eshell-command-running-string)
-    (let ((fmt (eshell-copy-list mode-line-format)))
+    (let ((fmt (copy-sequence mode-line-format)))
       (make-local-variable 'mode-line-format)
       (setq mode-line-format fmt))
     (let ((modeline (memq 'mode-line-modified mode-line-format)))
@@ -331,6 +334,7 @@ sessions, such as when using `eshell-command'.")
   (if (eq (key-binding [(meta ?.)]) 'find-tag)
       (define-key eshell-mode-map [(meta ?.)] 'eshell-find-tag))
   (define-key eshell-command-map [(meta ?o)] 'eshell-mark-output)
+  (define-key eshell-command-map [(meta ?d)] 'eshell-toggle-direct-send)
 
   (define-key eshell-command-map [(control ?a)] 'eshell-bol)
   (define-key eshell-command-map [(control ?b)] 'eshell-backward-argument)
@@ -381,7 +385,7 @@ sessions, such as when using `eshell-command'.")
   (set (make-local-variable 'eshell-last-output-end) (point-marker))
   (set (make-local-variable 'eshell-last-output-block-begin) (point))
 
-  (let ((modules-list (eshell-copy-list eshell-modules-list)))
+  (let ((modules-list (copy-sequence eshell-modules-list)))
     (make-local-variable 'eshell-modules-list)
     (setq eshell-modules-list modules-list))
 
@@ -414,20 +418,19 @@ sessions, such as when using `eshell-command'.")
       (if (and load-hook (boundp load-hook))
          (run-hooks load-hook))))
 
-  (when eshell-scroll-to-bottom-on-input
-    (make-local-hook 'pre-command-hook)
-    (add-hook 'pre-command-hook 'eshell-preinput-scroll-to-bottom t t))
+  (if eshell-send-direct-to-subprocesses
+      (add-hook 'pre-command-hook 'eshell-intercept-commands t t))
+
+  (if eshell-scroll-to-bottom-on-input
+      (add-hook 'pre-command-hook 'eshell-preinput-scroll-to-bottom t t))
 
   (when eshell-scroll-show-maximum-output
     (set (make-local-variable 'scroll-conservatively) 1000))
 
   (when eshell-status-in-modeline
-    (make-local-hook 'eshell-pre-command-hook)
     (add-hook 'eshell-pre-command-hook 'eshell-command-started nil t)
-    (make-local-hook 'eshell-post-command-hook)
     (add-hook 'eshell-post-command-hook 'eshell-command-finished nil t))
 
-  (make-local-hook 'kill-buffer-hook)
   (add-hook 'kill-buffer-hook
            (function
             (lambda ()
@@ -450,7 +453,8 @@ sessions, such as when using `eshell-command'.")
 
 (eshell-deftest var window-height
   "LINES equals window height"
-  (eshell-command-result-p "= $LINES (window-height)" "t\n"))
+  (let ((eshell-stringify-t t))
+    (eshell-command-result-p "= $LINES (window-height)" "t\n")))
 
 (defun eshell-command-started ()
   "Indicate in the modeline that a command has started."
@@ -471,12 +475,52 @@ sessions, such as when using `eshell-command'.")
 
 ;;; Internal Functions:
 
+(defun eshell-toggle-direct-send ()
+  (interactive)
+  (if eshell-send-direct-to-subprocesses
+      (progn
+       (setq eshell-send-direct-to-subprocesses nil)
+       (remove-hook 'pre-command-hook 'eshell-intercept-commands t)
+       (message "Sending subprocess input on RET"))
+    (setq eshell-send-direct-to-subprocesses t)
+    (add-hook 'pre-command-hook 'eshell-intercept-commands t t)
+    (message "Sending subprocess input directly")))
+
+(defun eshell-self-insert-command (N)
+  (interactive "i")
+  (process-send-string
+   (eshell-interactive-process)
+   (char-to-string (if (symbolp last-command-char)
+                      (get last-command-char 'ascii-character)
+                    last-command-char))))
+
+(defun eshell-intercept-commands ()
+  (when (and (eshell-interactive-process)
+            (not (and (integerp last-input-event)
+                      (memq last-input-event '(?\C-x ?\C-c)))))
+    (let ((possible-events (where-is-internal this-command))
+         (name (symbol-name this-command))
+         (intercept t))
+      ;; Assume that any multikey combination which does NOT target an
+      ;; Eshell command, is a combo the user wants invoked rather than
+      ;; sent to the underlying subprocess.
+      (unless (and (> (length name) 7)
+                  (equal (substring name 0 7) "eshell-"))
+       (while possible-events
+         (if (> (length (car possible-events)) 1)
+             (setq intercept nil possible-events nil)
+           (setq possible-events (cdr possible-events)))))
+      (if intercept
+         (setq this-command 'eshell-self-insert-command)))))
+
 (defun eshell-find-tag (&optional tagname next-p regexp-p)
   "A special version of `find-tag' that ignores read-onlyness."
   (interactive)
+  (require 'etags)
   (let ((inhibit-read-only t)
-       (no-default (eobp)))
-    (setq tagname (find-tag-interactive "Find tag: " no-default))
+       (no-default (eobp))
+       (find-tag-default-function 'ignore))
+    (setq tagname (car (find-tag-interactive "Find tag: ")))
     (find-tag tagname next-p regexp-p)))
 
 (defun eshell-move-argument (limit func property arg)
@@ -651,12 +695,15 @@ newline."
        (let ((copy (eshell-get-old-input use-region)))
          (goto-char eshell-last-output-end)
          (insert-and-inherit copy)))
-      (unless no-newline
+      (unless (or no-newline
+                 (and eshell-send-direct-to-subprocesses
+                      proc-running-p))
        (insert-before-markers-and-inherit ?\n))
       (if proc-running-p
          (progn
            (eshell-update-markers eshell-last-output-end)
-           (if (= eshell-last-input-start eshell-last-input-end)
+           (if (or eshell-send-direct-to-subprocesses
+                   (= eshell-last-input-start eshell-last-input-end))
                (unless no-newline
                  (process-send-string (eshell-interactive-process) "\n"))
              (process-send-region (eshell-interactive-process)
@@ -681,7 +728,9 @@ newline."
                      (run-hooks 'eshell-input-filter-functions)
                      (and (catch 'eshell-terminal
                             (ignore
-                             (eshell-eval-command cmd input)))
+                             (if (eshell-invoke-directly cmd input)
+                                 (eval cmd)
+                               (eshell-eval-command cmd input))))
                           (eshell-life-is-too-much)))))
              (quit
               (eshell-reset t)
@@ -694,19 +743,19 @@ newline."
               (run-hooks 'eshell-post-command-hook)
               (insert-and-inherit input)))))))))
 
-(eshell-deftest proc send-to-subprocess
-  "Send input to a subprocess"
-  ;; jww (1999-12-06): what about when bc is unavailable?
-  (if (not (eshell-search-path "bc"))
-      t
-    (eshell-insert-command "bc")
-    (eshell-insert-command "1 + 2")
-    (sit-for 1 0)
-    (forward-line -1)
-    (prog1
-       (looking-at "3\n")
-      (eshell-insert-command "quit")
-      (sit-for 1 0))))
+(eshell-deftest proc send-to-subprocess
+  "Send input to a subprocess"
+  ;; jww (1999-12-06): what about when bc is unavailable?
+  (if (not (eshell-search-path "bc"))
+      t
+    (eshell-insert-command "bc")
+    (eshell-insert-command "1 + 2")
+    (sit-for 1 0)
+    (forward-line -1)
+    (prog1
+;      (looking-at "3\n")
+      (eshell-insert-command "quit")
+      (sit-for 1 0))))
 
 (defsubst eshell-kill-new ()
   "Add the last input text to the kill ring."
@@ -966,12 +1015,12 @@ a key."
 (custom-add-option 'eshell-output-filter-functions
                   'eshell-truncate-buffer)
 
-(defun send-invisible (str)
+(defun eshell-send-invisible (str)
   "Read a string without echoing.
 Then send it to the process running in the current buffer."
   (interactive "P")                     ; Defeat snooping via C-x ESC ESC
   (let ((str (read-passwd
-             (format "Password: "
+             (format "%s Password: "
                      (process-name (eshell-interactive-process))))))
     (if (stringp str)
        (process-send-string (eshell-interactive-process)
@@ -980,7 +1029,7 @@ Then send it to the process running in the current buffer."
 
 (defun eshell-watch-for-password-prompt ()
   "Prompt in the minibuffer for password and send without echoing.
-This function uses `send-invisible' to read and send a password to the
+This function uses `eshell-send-invisible' to read and send a password to the
 buffer's process if STRING contains a password prompt defined by
 `eshell-password-prompt-regexp'.
 
@@ -991,7 +1040,7 @@ This function could be in the list `eshell-output-filter-functions'."
       (beginning-of-line)
       (if (re-search-forward eshell-password-prompt-regexp
                             eshell-last-output-end t)
-         (send-invisible nil)))))
+         (eshell-send-invisible nil)))))
 
 (custom-add-option 'eshell-output-filter-functions
                   'eshell-watch-for-password-prompt)
@@ -1031,4 +1080,5 @@ This function could be in the list `eshell-output-filter-functions'."
 
 ;;; Code:
 
+;;; arch-tag: ec65bc2b-da14-4547-81d3-a32af3a4dc57
 ;;; esh-mode.el ends here