Replace version 24.2 with 24.3 where appropriate (hopefully)
[bpt/emacs.git] / lisp / eshell / esh-mode.el
CommitLineData
60370d40 1;;; esh-mode.el --- user interface
26b4dc84 2
acaf905b 3;; Copyright (C) 1999-2012 Free Software Foundation, Inc.
26b4dc84 4
7de5b421
GM
5;; Author: John Wiegley <johnw@gnu.org>
6
26b4dc84
GM
7;; This file is part of GNU Emacs.
8
4ee57b2a 9;; GNU Emacs is free software: you can redistribute it and/or modify
26b4dc84 10;; it under the terms of the GNU General Public License as published by
4ee57b2a
GM
11;; the Free Software Foundation, either version 3 of the License, or
12;; (at your option) any later version.
26b4dc84
GM
13
14;; GNU Emacs is distributed in the hope that it will be useful,
15;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17;; GNU General Public License for more details.
18
19;; You should have received a copy of the GNU General Public License
4ee57b2a 20;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
26b4dc84 21
26b4dc84
GM
22;;; Commentary:
23
24;; Basically, Eshell is used just like shell mode (<M-x shell>). The
25;; keystrokes for navigating the buffer, and accessing the command
26;; history, are identical. Unlike shell mode, however, Eshell mode's
27;; governing process is Emacs itself. With shell mode, an inferior
28;; shell process is executed that communicates with Emacs via comint
29;; -- a mode for handling sub-process interaction. Eshell mode, on
30;; the other hand, is a truly native Emacs shell. No subprocess are
31;; invoked except the ones requested by the user at the prompt.
32;;
33;; After entering a command, use <RET> to invoke it ([Command
34;; invocation]) . If there is a command on disk, it will be executed
35;; as in a normal shell. If there is no command by that name on disk,
36;; but a Lisp function with that name is defined, the Lisp function
37;; will be called, using the arguments passed on the command line.
38;;
39;; Some of the other features of the command interaction mode are:
40;;
41;; @ <M-RET> can be used to accumulate further commands while a
42;; command is currently running. Since all input is passed to the
43;; subprocess being executed, there is no automatic input queueing
44;; as there is with other shells.
45;;
46;; @ <C-c C-t> can be used to truncate the buffer if it grows too
47;; large.
48;;
49;; @ <C-c C-r> will move point to the beginning of the output of the
50;; last command. With a prefix argument, it will narrow to view
51;; only that output.
52;;
53;; @ <C-c C-o> will delete the output from the last command.
54;;
55;; @ <C-c C-f> will move forward a complete shell argument.
56;;
57;; @ <C-c C-b> will move backward a complete shell argument.
58
8c7309fe
GM
59;;; Code:
60
4e6cc05c
GM
61(provide 'esh-mode)
62
63(eval-when-compile (require 'esh-util))
26b4dc84
GM
64(require 'esh-module)
65(require 'esh-cmd)
66(require 'esh-io)
67(require 'esh-var)
68
4e6cc05c
GM
69(defgroup eshell-mode nil
70 "This module contains code for handling input from the user."
71 :tag "User interface"
72 :group 'eshell)
73
26b4dc84
GM
74;;; User Variables:
75
76(defcustom eshell-mode-unload-hook nil
ec60da52 77 "A hook that gets run when `eshell-mode' is unloaded."
26b4dc84
GM
78 :type 'hook
79 :group 'eshell-mode)
80
81(defcustom eshell-mode-hook nil
ec60da52 82 "A hook that gets run when `eshell-mode' is entered."
26b4dc84
GM
83 :type 'hook
84 :group 'eshell-mode)
85
86(defcustom eshell-first-time-mode-hook nil
ec60da52 87 "A hook that gets run the first time `eshell-mode' is entered.
26b4dc84
GM
88That is to say, the first time during an Emacs session."
89 :type 'hook
90 :group 'eshell-mode)
91
d783d303 92(defcustom eshell-exit-hook nil
ec60da52 93 "A hook that is run whenever `eshell' is exited.
26b4dc84 94This hook is only run if exiting actually kills the buffer."
d783d303 95 :version "24.1" ; removed eshell-query-kill-processes
26b4dc84
GM
96 :type 'hook
97 :group 'eshell-mode)
98
99(defcustom eshell-kill-on-exit t
ec60da52 100 "If non-nil, kill the Eshell buffer on the `exit' command.
26b4dc84
GM
101Otherwise, the buffer will simply be buried."
102 :type 'boolean
103 :group 'eshell-mode)
104
105(defcustom eshell-input-filter-functions nil
ec60da52 106 "Functions to call before input is processed.
26b4dc84
GM
107The input is contained in the region from `eshell-last-input-start' to
108`eshell-last-input-end'."
109 :type 'hook
110 :group 'eshell-mode)
111
79cf8e80 112(defcustom eshell-send-direct-to-subprocesses nil
ec60da52 113 "If t, send any input immediately to a subprocess."
79cf8e80
JW
114 :type 'boolean
115 :group 'eshell-mode)
116
26b4dc84 117(defcustom eshell-expand-input-functions nil
ec60da52 118 "Functions to call before input is parsed.
26b4dc84
GM
119Each function is passed two arguments, which bounds the region of the
120current input text."
121 :type 'hook
122 :group 'eshell-mode)
123
124(defcustom eshell-scroll-to-bottom-on-input nil
ec60da52 125 "Controls whether input to interpreter causes window to scroll.
26b4dc84
GM
126If nil, then do not scroll. If t or `all', scroll all windows showing
127buffer. If `this', scroll only the selected window.
128
129See `eshell-preinput-scroll-to-bottom'."
130 :type '(radio (const :tag "Do not scroll Eshell windows" nil)
131 (const :tag "Scroll all windows showing the buffer" all)
132 (const :tag "Scroll only the selected window" this))
133 :group 'eshell-mode)
134
135(defcustom eshell-scroll-to-bottom-on-output nil
ec60da52 136 "Controls whether interpreter output causes window to scroll.
26b4dc84
GM
137If nil, then do not scroll. If t or `all', scroll all windows showing
138buffer. If `this', scroll only the selected window. If `others',
139scroll only those that are not the selected window.
140
141See variable `eshell-scroll-show-maximum-output' and function
142`eshell-postoutput-scroll-to-bottom'."
143 :type '(radio (const :tag "Do not scroll Eshell windows" nil)
144 (const :tag "Scroll all windows showing the buffer" all)
145 (const :tag "Scroll only the selected window" this)
146 (const :tag "Scroll all windows other than selected" this))
147 :group 'eshell-mode)
148
149(defcustom eshell-scroll-show-maximum-output t
ec60da52 150 "Controls how interpreter output causes window to scroll.
26b4dc84
GM
151If non-nil, then show the maximum output when the window is scrolled.
152
153See variable `eshell-scroll-to-bottom-on-output' and function
154`eshell-postoutput-scroll-to-bottom'."
155 :type 'boolean
156 :group 'eshell-mode)
157
158(defcustom eshell-buffer-maximum-lines 1024
ec60da52 159 "The maximum size in lines for eshell buffers.
26b4dc84
GM
160Eshell buffers are truncated from the top to be no greater than this
161number, if the function `eshell-truncate-buffer' is on
162`eshell-output-filter-functions'."
163 :type 'integer
164 :group 'eshell-mode)
165
166(defcustom eshell-output-filter-functions
007306f9
GM
167 '(eshell-postoutput-scroll-to-bottom
168 eshell-handle-control-codes
fd94644f 169 eshell-handle-ansi-color
26b4dc84 170 eshell-watch-for-password-prompt)
ec60da52 171 "Functions to call before output is displayed.
26b4dc84
GM
172These functions are only called for output that is displayed
173interactively, and not for output which is redirected."
174 :type 'hook
175 :group 'eshell-mode)
176
177(defcustom eshell-preoutput-filter-functions nil
ec60da52 178 "Functions to call before output is inserted into the buffer.
26b4dc84
GM
179These functions get one argument, a string containing the text to be
180inserted. They return the string as it should be inserted."
181 :type 'hook
182 :group 'eshell-mode)
183
184(defcustom eshell-password-prompt-regexp
dace60cf 185 "[Pp]ass\\(word\\|phrase\\).*:\\s *\\'"
ec60da52 186 "Regexp matching prompts for passwords in the inferior process.
26b4dc84
GM
187This is used by `eshell-watch-for-password-prompt'."
188 :type 'regexp
189 :group 'eshell-mode)
190
191(defcustom eshell-skip-prompt-function nil
ec60da52 192 "A function called from beginning of line to skip the prompt."
6a44f20f 193 :type '(choice (const nil) function)
26b4dc84
GM
194 :group 'eshell-mode)
195
37269466
CY
196(defcustom eshell-status-in-mode-line t
197 "If non-nil, let the user know a command is running in the mode line."
26b4dc84
GM
198 :type 'boolean
199 :group 'eshell-mode)
200
37269466 201(define-obsolete-variable-alias 'eshell-status-in-modeline
2a1e2476 202 'eshell-status-in-mode-line "24.3")
37269466 203
26b4dc84
GM
204(defvar eshell-first-time-p t
205 "A variable which is non-nil the first time Eshell is loaded.")
206
207;; Internal Variables:
208
209;; these are only set to `nil' initially for the sake of the
210;; byte-compiler, when compiling other files which `require' this one
211(defvar eshell-mode nil)
212(defvar eshell-mode-map nil)
213(defvar eshell-command-running-string "--")
214(defvar eshell-command-map nil)
215(defvar eshell-command-prefix nil)
216(defvar eshell-last-input-start nil)
217(defvar eshell-last-input-end nil)
218(defvar eshell-last-output-start nil)
219(defvar eshell-last-output-block-begin nil)
220(defvar eshell-last-output-end nil)
221
222(defvar eshell-currently-handling-window nil)
223(defvar eshell-mode-syntax-table nil)
224(defvar eshell-mode-abbrev-table nil)
225
226(define-abbrev-table 'eshell-mode-abbrev-table ())
227
26b4dc84
GM
228(if (not eshell-mode-syntax-table)
229 (let ((i 0))
230 (setq eshell-mode-syntax-table (make-syntax-table))
231 (while (< i ?0)
232 (modify-syntax-entry i "_ " eshell-mode-syntax-table)
233 (setq i (1+ i)))
234 (setq i (1+ ?9))
235 (while (< i ?A)
236 (modify-syntax-entry i "_ " eshell-mode-syntax-table)
237 (setq i (1+ i)))
238 (setq i (1+ ?Z))
239 (while (< i ?a)
240 (modify-syntax-entry i "_ " eshell-mode-syntax-table)
241 (setq i (1+ i)))
242 (setq i (1+ ?z))
243 (while (< i 128)
244 (modify-syntax-entry i "_ " eshell-mode-syntax-table)
245 (setq i (1+ i)))
246 (modify-syntax-entry ? " " eshell-mode-syntax-table)
247 (modify-syntax-entry ?\t " " eshell-mode-syntax-table)
248 (modify-syntax-entry ?\f " " eshell-mode-syntax-table)
249 (modify-syntax-entry ?\n "> " eshell-mode-syntax-table)
250 ;; Give CR the same syntax as newline, for selective-display.
251 (modify-syntax-entry ?\^m "> " eshell-mode-syntax-table)
252;;; (modify-syntax-entry ?\; "< " eshell-mode-syntax-table)
253 (modify-syntax-entry ?` "' " eshell-mode-syntax-table)
254 (modify-syntax-entry ?' "' " eshell-mode-syntax-table)
255 (modify-syntax-entry ?, "' " eshell-mode-syntax-table)
256 ;; Used to be singlequote; changed for flonums.
257 (modify-syntax-entry ?. "_ " eshell-mode-syntax-table)
258 (modify-syntax-entry ?- "_ " eshell-mode-syntax-table)
259 (modify-syntax-entry ?| ". " eshell-mode-syntax-table)
260 (modify-syntax-entry ?# "' " eshell-mode-syntax-table)
261 (modify-syntax-entry ?\" "\" " eshell-mode-syntax-table)
262 (modify-syntax-entry ?\\ "/ " eshell-mode-syntax-table)
263 (modify-syntax-entry ?\( "() " eshell-mode-syntax-table)
264 (modify-syntax-entry ?\) ")( " eshell-mode-syntax-table)
265 (modify-syntax-entry ?\{ "(} " eshell-mode-syntax-table)
266 (modify-syntax-entry ?\} "){ " eshell-mode-syntax-table)
267 (modify-syntax-entry ?\[ "(] " eshell-mode-syntax-table)
268 (modify-syntax-entry ?\] ")[ " eshell-mode-syntax-table)
269 ;; All non-word multibyte characters should be `symbol'.
a3269bc4 270 (if (featurep 'xemacs)
26b4dc84
GM
271 (map-char-table
272 (function
273 (lambda (key val)
274 (and (characterp key)
275 (>= (char-int key) 256)
276 (/= (char-syntax key) ?w)
277 (modify-syntax-entry key "_ "
278 eshell-mode-syntax-table))))
279 (standard-syntax-table))
280 (map-char-table
281 (function
282 (lambda (key val)
2494c91b 283 (and (if (consp key)
8f924df7
KH
284 (and (>= (car key) 128)
285 (/= (char-syntax (car key)) ?w))
2494c91b
KH
286 (and (>= key 256)
287 (/= (char-syntax key) ?w)))
26b4dc84
GM
288 (modify-syntax-entry key "_ "
289 eshell-mode-syntax-table))))
290 (standard-syntax-table)))))
291
292;;; User Functions:
293
d783d303
GM
294(defun eshell-kill-buffer-function ()
295 "Function added to `kill-buffer-hook' in Eshell buffers.
296This runs the function `eshell-kill-processes-on-exit',
297and the hook `eshell-exit-hook'."
298 ;; It's fine to run this unconditionally since it can be customized
299 ;; via the `eshell-kill-processes-on-exit' variable.
300 (and (fboundp 'eshell-query-kill-processes)
301 (not (memq 'eshell-query-kill-processes eshell-exit-hook))
302 (eshell-query-kill-processes))
303 (run-hooks 'eshell-exit-hook))
304
26b4dc84
GM
305;;;###autoload
306(defun eshell-mode ()
307 "Emacs shell interactive mode.
308
309\\{eshell-mode-map}"
310 (kill-all-local-variables)
311
312 (setq major-mode 'eshell-mode)
313 (setq mode-name "EShell")
314 (set (make-local-variable 'eshell-mode) t)
315
316 (make-local-variable 'eshell-mode-map)
317 (setq eshell-mode-map (make-sparse-keymap))
318 (use-local-map eshell-mode-map)
319
37269466 320 (when eshell-status-in-mode-line
26b4dc84 321 (make-local-variable 'eshell-command-running-string)
48e889be 322 (let ((fmt (copy-sequence mode-line-format)))
26b4dc84
GM
323 (make-local-variable 'mode-line-format)
324 (setq mode-line-format fmt))
37269466
CY
325 (let ((mode-line-elt (memq 'mode-line-modified mode-line-format)))
326 (if mode-line-elt
327 (setcar mode-line-elt 'eshell-command-running-string))))
26b4dc84
GM
328
329 (define-key eshell-mode-map [return] 'eshell-send-input)
330 (define-key eshell-mode-map [(control ?m)] 'eshell-send-input)
331 (define-key eshell-mode-map [(control ?j)] 'eshell-send-input)
332 (define-key eshell-mode-map [(meta return)] 'eshell-queue-input)
333 (define-key eshell-mode-map [(meta control ?m)] 'eshell-queue-input)
334 (define-key eshell-mode-map [(meta control ?l)] 'eshell-show-output)
c2b2a6ca 335 (define-key eshell-mode-map [(control ?a)] 'eshell-bol)
26b4dc84
GM
336
337 (set (make-local-variable 'eshell-command-prefix)
338 (make-symbol "eshell-command-prefix"))
339 (fset eshell-command-prefix (make-sparse-keymap))
340 (set (make-local-variable 'eshell-command-map)
341 (symbol-function eshell-command-prefix))
342 (define-key eshell-mode-map [(control ?c)] eshell-command-prefix)
343
b4bd214e
JW
344 ;; without this, find-tag complains about read-only text being
345 ;; modified
346 (if (eq (key-binding [(meta ?.)]) 'find-tag)
347 (define-key eshell-mode-map [(meta ?.)] 'eshell-find-tag))
26b4dc84 348 (define-key eshell-command-map [(meta ?o)] 'eshell-mark-output)
79cf8e80 349 (define-key eshell-command-map [(meta ?d)] 'eshell-toggle-direct-send)
26b4dc84
GM
350
351 (define-key eshell-command-map [(control ?a)] 'eshell-bol)
352 (define-key eshell-command-map [(control ?b)] 'eshell-backward-argument)
353 (define-key eshell-command-map [(control ?e)] 'eshell-show-maximum-output)
354 (define-key eshell-command-map [(control ?f)] 'eshell-forward-argument)
355 (define-key eshell-command-map [return] 'eshell-copy-old-input)
356 (define-key eshell-command-map [(control ?m)] 'eshell-copy-old-input)
357 (define-key eshell-command-map [(control ?o)] 'eshell-kill-output)
358 (define-key eshell-command-map [(control ?r)] 'eshell-show-output)
359 (define-key eshell-command-map [(control ?t)] 'eshell-truncate-buffer)
360 (define-key eshell-command-map [(control ?u)] 'eshell-kill-input)
361 (define-key eshell-command-map [(control ?w)] 'backward-kill-word)
b4bd214e 362 (define-key eshell-command-map [(control ?y)] 'eshell-repeat-argument)
26b4dc84
GM
363
364 (setq local-abbrev-table eshell-mode-abbrev-table)
365 (set-syntax-table eshell-mode-syntax-table)
366
367 (set (make-local-variable 'dired-directory) default-directory)
368 (set (make-local-variable 'list-buffers-directory)
369 (expand-file-name default-directory))
370
371 ;; always set the tab width to 8 in Eshell buffers, since external
372 ;; commands which do their own formatting almost always expect this
373 (set (make-local-variable 'tab-width) 8)
374
b4bd214e
JW
375 ;; don't ever use auto-fill in Eshell buffers
376 (setq auto-fill-function nil)
377
26b4dc84
GM
378 ;; always display everything from a return value
379 (if (boundp 'print-length)
380 (set (make-local-variable 'print-length) nil))
381 (if (boundp 'print-level)
382 (set (make-local-variable 'print-level) nil))
383
384 ;; set require-final-newline to nil; otherwise, all redirected
385 ;; output will end with a newline, whether or not the source
386 ;; indicated it!
387 (set (make-local-variable 'require-final-newline) nil)
388
389 (set (make-local-variable 'max-lisp-eval-depth)
390 (max 3000 max-lisp-eval-depth))
391 (set (make-local-variable 'max-specpdl-size)
392 (max 6000 max-lisp-eval-depth))
393
394 (set (make-local-variable 'eshell-last-input-start) (point-marker))
395 (set (make-local-variable 'eshell-last-input-end) (point-marker))
396 (set (make-local-variable 'eshell-last-output-start) (point-marker))
397 (set (make-local-variable 'eshell-last-output-end) (point-marker))
398 (set (make-local-variable 'eshell-last-output-block-begin) (point))
399
48e889be 400 (let ((modules-list (copy-sequence eshell-modules-list)))
26b4dc84
GM
401 (make-local-variable 'eshell-modules-list)
402 (setq eshell-modules-list modules-list))
403
404 ;; load extension modules into memory. This will cause any global
405 ;; variables they define to be visible, since some of the core
406 ;; modules sometimes take advantage of their functionality if used.
a9eeff78 407 (dolist (module eshell-modules-list)
26b4dc84
GM
408 (let ((module-fullname (symbol-name module))
409 module-shortname)
410 (if (string-match "^eshell-\\(.*\\)" module-fullname)
411 (setq module-shortname
412 (concat "em-" (match-string 1 module-fullname))))
413 (unless module-shortname
414 (error "Invalid Eshell module name: %s" module-fullname))
415 (unless (featurep (intern module-shortname))
416 (load module-shortname))))
417
418 (unless (file-exists-p eshell-directory-name)
419 (eshell-make-private-directory eshell-directory-name t))
420
d783d303
GM
421 ;; Load core Eshell modules, then extension modules, for this session.
422 (dolist (module (append (eshell-subgroups 'eshell) eshell-modules-list))
423 (let ((load-hook (intern-soft (format "%s-load-hook" module)))
424 (initfunc (intern-soft (format "%s-initialize" module))))
425 (when (and load-hook (boundp load-hook))
426 (if (memq initfunc (symbol-value load-hook)) (setq initfunc nil))
427 (run-hooks load-hook))
428 ;; So we don't need the -initialize functions on the hooks (b#5375).
429 (and initfunc (fboundp initfunc) (funcall initfunc))))
26b4dc84 430
79cf8e80
JW
431 (if eshell-send-direct-to-subprocesses
432 (add-hook 'pre-command-hook 'eshell-intercept-commands t t))
433
434 (if eshell-scroll-to-bottom-on-input
435 (add-hook 'pre-command-hook 'eshell-preinput-scroll-to-bottom t t))
26b4dc84
GM
436
437 (when eshell-scroll-show-maximum-output
438 (set (make-local-variable 'scroll-conservatively) 1000))
439
37269466 440 (when eshell-status-in-mode-line
26b4dc84 441 (add-hook 'eshell-pre-command-hook 'eshell-command-started nil t)
26b4dc84
GM
442 (add-hook 'eshell-post-command-hook 'eshell-command-finished nil t))
443
d783d303 444 (add-hook 'kill-buffer-hook 'eshell-kill-buffer-function t t)
26b4dc84
GM
445
446 (if eshell-first-time-p
447 (run-hooks 'eshell-first-time-mode-hook))
5c3066b8 448 (run-mode-hooks 'eshell-mode-hook)
26b4dc84
GM
449 (run-hooks 'eshell-post-command-hook))
450
451(put 'eshell-mode 'mode-class 'special)
452
26b4dc84 453(defun eshell-command-started ()
37269466 454 "Indicate in the mode line that a command has started."
26b4dc84
GM
455 (setq eshell-command-running-string "**")
456 (force-mode-line-update))
457
458(defun eshell-command-finished ()
37269466 459 "Indicate in the mode line that a command has finished."
26b4dc84
GM
460 (setq eshell-command-running-string "--")
461 (force-mode-line-update))
462
26b4dc84
GM
463;;; Internal Functions:
464
79cf8e80
JW
465(defun eshell-toggle-direct-send ()
466 (interactive)
467 (if eshell-send-direct-to-subprocesses
468 (progn
469 (setq eshell-send-direct-to-subprocesses nil)
470 (remove-hook 'pre-command-hook 'eshell-intercept-commands t)
471 (message "Sending subprocess input on RET"))
472 (setq eshell-send-direct-to-subprocesses t)
473 (add-hook 'pre-command-hook 'eshell-intercept-commands t t)
474 (message "Sending subprocess input directly")))
475
476(defun eshell-self-insert-command (N)
477 (interactive "i")
478 (process-send-string
479 (eshell-interactive-process)
1ba983e8
GM
480 (char-to-string (if (symbolp last-command-event)
481 (get last-command-event 'ascii-character)
482 last-command-event))))
79cf8e80
JW
483
484(defun eshell-intercept-commands ()
485 (when (and (eshell-interactive-process)
486 (not (and (integerp last-input-event)
487 (memq last-input-event '(?\C-x ?\C-c)))))
488 (let ((possible-events (where-is-internal this-command))
489 (name (symbol-name this-command))
490 (intercept t))
491 ;; Assume that any multikey combination which does NOT target an
492 ;; Eshell command, is a combo the user wants invoked rather than
493 ;; sent to the underlying subprocess.
494 (unless (and (> (length name) 7)
495 (equal (substring name 0 7) "eshell-"))
496 (while possible-events
497 (if (> (length (car possible-events)) 1)
498 (setq intercept nil possible-events nil)
499 (setq possible-events (cdr possible-events)))))
500 (if intercept
501 (setq this-command 'eshell-self-insert-command)))))
502
c2fb1b60
JB
503(declare-function find-tag-interactive "etags" (prompt &optional no-default))
504
b4bd214e
JW
505(defun eshell-find-tag (&optional tagname next-p regexp-p)
506 "A special version of `find-tag' that ignores read-onlyness."
507 (interactive)
ca7aae91 508 (require 'etags)
b4bd214e 509 (let ((inhibit-read-only t)
8c6b1d83
JW
510 (no-default (eobp))
511 (find-tag-default-function 'ignore))
c2fb1b60 512 (setq tagname (car (find-tag-interactive "Find tag: " no-default)))
b4bd214e
JW
513 (find-tag tagname next-p regexp-p)))
514
26b4dc84
GM
515(defun eshell-move-argument (limit func property arg)
516 "Move forward ARG arguments."
517 (catch 'eshell-incomplete
518 (eshell-parse-arguments (save-excursion (eshell-bol) (point))
519 (line-end-position)))
b4bd214e
JW
520 (let ((pos (save-excursion
521 (funcall func 1)
522 (while (and (> arg 0) (/= (point) limit))
523 (if (get-text-property (point) property)
524 (setq arg (1- arg)))
525 (if (> arg 0)
526 (funcall func 1)))
527 (point))))
26b4dc84
GM
528 (goto-char pos)
529 (if (and (eq func 'forward-char)
530 (= (1+ pos) limit))
531 (forward-char 1))))
532
26b4dc84
GM
533(defun eshell-forward-argument (&optional arg)
534 "Move forward ARG arguments."
535 (interactive "p")
536 (eshell-move-argument (point-max) 'forward-char 'arg-end arg))
537
538(defun eshell-backward-argument (&optional arg)
539 "Move backward ARG arguments."
540 (interactive "p")
541 (eshell-move-argument (point-min) 'backward-char 'arg-begin arg))
542
b4bd214e
JW
543(defun eshell-repeat-argument (&optional arg)
544 (interactive "p")
545 (let ((begin (save-excursion
546 (eshell-backward-argument arg)
547 (point))))
548 (kill-ring-save begin (point))
549 (yank)))
550
26b4dc84
GM
551(defun eshell-bol ()
552 "Goes to the beginning of line, then skips past the prompt, if any."
553 (interactive)
554 (beginning-of-line)
555 (and eshell-skip-prompt-function
556 (funcall eshell-skip-prompt-function)))
557
558(defsubst eshell-push-command-mark ()
559 "Push a mark at the end of the last input text."
560 (push-mark (1- eshell-last-input-end) t))
561
562(custom-add-option 'eshell-pre-command-hook 'eshell-push-command-mark)
563
564(defsubst eshell-goto-input-start ()
565 "Goto the start of the last command input.
566Putting this function on `eshell-pre-command-hook' will mimic Plan 9's
5679term behavior."
568 (goto-char eshell-last-input-start))
569
570(custom-add-option 'eshell-pre-command-hook 'eshell-push-command-mark)
571
572(defsubst eshell-interactive-print (string)
573 "Print STRING to the eshell display buffer."
574 (eshell-output-filter nil string))
575
576(defsubst eshell-begin-on-new-line ()
577 "This function outputs a newline if not at beginning of line."
578 (save-excursion
579 (goto-char eshell-last-output-end)
580 (or (bolp)
581 (eshell-interactive-print "\n"))))
582
583(defsubst eshell-reset (&optional no-hooks)
584 "Output a prompt on a new line, aborting any current input.
585If NO-HOOKS is non-nil, then `eshell-post-command-hook' won't be run."
586 (goto-char (point-max))
587 (setq eshell-last-input-start (point-marker)
588 eshell-last-input-end (point-marker)
589 eshell-last-output-start (point-marker)
590 eshell-last-output-block-begin (point)
591 eshell-last-output-end (point-marker))
592 (eshell-begin-on-new-line)
593 (unless no-hooks
594 (run-hooks 'eshell-post-command-hook)
595 (goto-char (point-max))))
596
597(defun eshell-parse-command-input (beg end &optional args)
598 "Parse the command input from BEG to END.
599The difference is that `eshell-parse-command' expects a complete
600command string (and will error if it doesn't get one), whereas this
601function will inform the caller whether more input is required.
602
603If nil is returned, more input is necessary (probably because a
604multi-line input string wasn't terminated properly). Otherwise, it
605will return the parsed command."
b4bd214e
JW
606 (let (delim command)
607 (if (setq delim
608 (catch 'eshell-incomplete
609 (ignore
610 (setq command (eshell-parse-command (cons beg end)
611 args t)))))
612 (ignore
4c36be58 613 (message "Expecting completion of delimiter %c ..."
b4bd214e
JW
614 (if (listp delim)
615 (car delim)
616 delim)))
26b4dc84
GM
617 command)))
618
619(defun eshell-update-markers (pmark)
620 "Update the input and output markers relative to point and PMARK."
621 (set-marker eshell-last-input-start pmark)
622 (set-marker eshell-last-input-end (point))
623 (set-marker eshell-last-output-end (point)))
624
625(defun eshell-queue-input (&optional use-region)
626 "Queue the current input text for execution by Eshell.
627Particularly, don't send the text to the current process, even if it's
628waiting for input."
629 (interactive "P")
630 (eshell-send-input use-region t))
631
26b4dc84 632(defun eshell-send-input (&optional use-region queue-p no-newline)
e94dae7f 633 "Send the input received to Eshell for parsing and processing.
26b4dc84
GM
634After `eshell-last-output-end', sends all text from that marker to
635point as input. Before that marker, calls `eshell-get-old-input' to
636retrieve old input, copies it to the end of the buffer, and sends it.
637
638If USE-REGION is non-nil, the current region (between point and mark)
639will be used as input.
640
641If QUEUE-P is non-nil, input will be queued until the next prompt,
642rather than sent to the currently active process. If no process, the
643input is processed immediately.
644
645If NO-NEWLINE is non-nil, the input is sent without an implied final
646newline."
647 (interactive "P")
648 ;; Note that the input string does not include its terminal newline.
649 (let ((proc-running-p (and (eshell-interactive-process)
650 (not queue-p)))
651 (inhibit-point-motion-hooks t)
652 after-change-functions)
653 (unless (and proc-running-p
654 (not (eq (process-status
655 (eshell-interactive-process)) 'run)))
656 (if (or proc-running-p
657 (>= (point) eshell-last-output-end))
658 (goto-char (point-max))
659 (let ((copy (eshell-get-old-input use-region)))
660 (goto-char eshell-last-output-end)
661 (insert-and-inherit copy)))
79cf8e80
JW
662 (unless (or no-newline
663 (and eshell-send-direct-to-subprocesses
664 proc-running-p))
26b4dc84
GM
665 (insert-before-markers-and-inherit ?\n))
666 (if proc-running-p
667 (progn
668 (eshell-update-markers eshell-last-output-end)
79cf8e80
JW
669 (if (or eshell-send-direct-to-subprocesses
670 (= eshell-last-input-start eshell-last-input-end))
26b4dc84
GM
671 (unless no-newline
672 (process-send-string (eshell-interactive-process) "\n"))
673 (process-send-region (eshell-interactive-process)
674 eshell-last-input-start
675 eshell-last-input-end)))
676 (if (= eshell-last-output-end (point))
677 (run-hooks 'eshell-post-command-hook)
678 (let (input)
679 (eshell-condition-case err
680 (progn
681 (setq input (buffer-substring-no-properties
682 eshell-last-output-end (1- (point))))
683 (run-hook-with-args 'eshell-expand-input-functions
684 eshell-last-output-end (1- (point)))
685 (let ((cmd (eshell-parse-command-input
686 eshell-last-output-end (1- (point)))))
687 (when cmd
688 (eshell-update-markers eshell-last-output-end)
689 (setq input (buffer-substring-no-properties
690 eshell-last-input-start
691 (1- eshell-last-input-end)))
692 (run-hooks 'eshell-input-filter-functions)
693 (and (catch 'eshell-terminal
694 (ignore
dace60cf
JW
695 (if (eshell-invoke-directly cmd input)
696 (eval cmd)
697 (eshell-eval-command cmd input))))
26b4dc84
GM
698 (eshell-life-is-too-much)))))
699 (quit
700 (eshell-reset t)
701 (run-hooks 'eshell-post-command-hook)
702 (signal 'quit nil))
703 (error
704 (eshell-reset t)
705 (eshell-interactive-print
706 (concat (error-message-string err) "\n"))
707 (run-hooks 'eshell-post-command-hook)
708 (insert-and-inherit input)))))))))
709
26b4dc84
GM
710(defsubst eshell-kill-new ()
711 "Add the last input text to the kill ring."
712 (kill-ring-save eshell-last-input-start eshell-last-input-end))
713
714(custom-add-option 'eshell-input-filter-functions 'eshell-kill-new)
715
716(defun eshell-output-filter (process string)
717 "Send the output from PROCESS (STRING) to the interactive display.
718This is done after all necessary filtering has been done."
719 (let ((oprocbuf (if process (process-buffer process)
720 (current-buffer)))
721 (inhibit-point-motion-hooks t)
722 after-change-functions)
723 (let ((functions eshell-preoutput-filter-functions))
724 (while (and functions string)
725 (setq string (funcall (car functions) string))
726 (setq functions (cdr functions))))
727 (if (and string oprocbuf (buffer-name oprocbuf))
d3204296
GM
728 (let (opoint obeg oend)
729 (with-current-buffer oprocbuf
730 (setq opoint (point))
731 (setq obeg (point-min))
732 (setq oend (point-max))
733 (let ((buffer-read-only nil)
734 (nchars (length string))
735 (ostart nil))
736 (widen)
737 (goto-char eshell-last-output-end)
738 (setq ostart (point))
739 (if (<= (point) opoint)
740 (setq opoint (+ opoint nchars)))
741 (if (< (point) obeg)
742 (setq obeg (+ obeg nchars)))
743 (if (<= (point) oend)
744 (setq oend (+ oend nchars)))
745 (insert-before-markers string)
746 (if (= (window-start (selected-window)) (point))
747 (set-window-start (selected-window)
748 (- (point) nchars)))
749 (if (= (point) eshell-last-input-end)
750 (set-marker eshell-last-input-end
751 (- eshell-last-input-end nchars)))
752 (set-marker eshell-last-output-start ostart)
753 (set-marker eshell-last-output-end (point))
754 (force-mode-line-update))
755 (narrow-to-region obeg oend)
756 (goto-char opoint)
757 (eshell-run-output-filters))))))
26b4dc84
GM
758
759(defun eshell-run-output-filters ()
760 "Run the `eshell-output-filter-functions' on the current output."
761 (save-current-buffer
762 (run-hooks 'eshell-output-filter-functions))
763 (setq eshell-last-output-block-begin
764 (marker-position eshell-last-output-end)))
765
766;;; jww (1999-10-23): this needs testing
767(defun eshell-preinput-scroll-to-bottom ()
768 "Go to the end of buffer in all windows showing it.
769Movement occurs if point in the selected window is not after the
770process mark, and `this-command' is an insertion command. Insertion
b7599623 771commands recognized are `self-insert-command', `yank', and
26b4dc84
GM
772`hilit-yank'. Depends on the value of
773`eshell-scroll-to-bottom-on-input'.
774
775This function should be a pre-command hook."
776 (if (memq this-command '(self-insert-command yank hilit-yank))
777 (let* ((selected (selected-window))
778 (current (current-buffer))
779 (scroll eshell-scroll-to-bottom-on-input))
780 (if (< (point) eshell-last-output-end)
781 (if (eq scroll 'this)
782 (goto-char (point-max))
783 (walk-windows
784 (function
785 (lambda (window)
786 (when (and (eq (window-buffer window) current)
787 (or (eq scroll t) (eq scroll 'all)))
788 (select-window window)
789 (goto-char (point-max))
790 (select-window selected))))
791 nil t))))))
792
793;;; jww (1999-10-23): this needs testing
794(defun eshell-postoutput-scroll-to-bottom ()
795 "Go to the end of buffer in all windows showing it.
796Does not scroll if the current line is the last line in the buffer.
797Depends on the value of `eshell-scroll-to-bottom-on-output' and
798`eshell-scroll-show-maximum-output'.
799
800This function should be in the list `eshell-output-filter-functions'."
801 (let* ((selected (selected-window))
802 (current (current-buffer))
803 (scroll eshell-scroll-to-bottom-on-output))
804 (unwind-protect
805 (walk-windows
806 (function
807 (lambda (window)
808 (if (eq (window-buffer window) current)
809 (progn
810 (select-window window)
811 (if (and (< (point) eshell-last-output-end)
812 (or (eq scroll t) (eq scroll 'all)
813 ;; Maybe user wants point to jump to end.
814 (and (eq scroll 'this)
815 (eq selected window))
816 (and (eq scroll 'others)
817 (not (eq selected window)))
818 ;; If point was at the end, keep it at end.
819 (>= (point) eshell-last-output-start)))
820 (goto-char eshell-last-output-end))
821 ;; Optionally scroll so that the text
822 ;; ends at the bottom of the window.
823 (if (and eshell-scroll-show-maximum-output
824 (>= (point) eshell-last-output-end))
825 (save-excursion
826 (goto-char (point-max))
827 (recenter -1)))
828 (select-window selected)))))
829 nil t)
830 (set-buffer current))))
831
26b4dc84
GM
832(defun eshell-beginning-of-input ()
833 "Return the location of the start of the previous input."
834 eshell-last-input-start)
835
836(defun eshell-beginning-of-output ()
837 "Return the location of the end of the previous output block."
838 eshell-last-input-end)
839
840(defun eshell-end-of-output ()
841 "Return the location of the end of the previous output block."
842 (if (eshell-using-module 'eshell-prompt)
843 eshell-last-output-start
844 eshell-last-output-end))
845
846(defun eshell-kill-output ()
847 "Kill all output from interpreter since last input.
848Does not delete the prompt."
849 (interactive)
850 (save-excursion
851 (goto-char (eshell-beginning-of-output))
852 (insert "*** output flushed ***\n")
853 (delete-region (point) (eshell-end-of-output))))
854
26b4dc84
GM
855(defun eshell-show-output (&optional arg)
856 "Display start of this batch of interpreter output at top of window.
857Sets mark to the value of point when this command is run.
858With a prefix argument, narrows region to last command output."
859 (interactive "P")
860 (goto-char (eshell-beginning-of-output))
861 (set-window-start (selected-window)
862 (save-excursion
863 (goto-char (eshell-beginning-of-input))
864 (line-beginning-position)))
865 (if arg
866 (narrow-to-region (eshell-beginning-of-output)
867 (eshell-end-of-output)))
868 (eshell-end-of-output))
869
870(defun eshell-mark-output (&optional arg)
871 "Display start of this batch of interpreter output at top of window.
872Sets mark to the value of point when this command is run.
873With a prefix argument, narrows region to last command output."
874 (interactive "P")
875 (push-mark (eshell-show-output arg)))
876
877(defun eshell-kill-input ()
878 "Kill all text from last stuff output by interpreter to point."
879 (interactive)
880 (if (> (point) eshell-last-output-end)
881 (kill-region eshell-last-output-end (point))
882 (let ((here (point)))
883 (eshell-bol)
884 (kill-region (point) here))))
885
3e80ba3c
RS
886(defun eshell-show-maximum-output (&optional interactive)
887 "Put the end of the buffer at the bottom of the window.
888When run interactively, widen the buffer first."
889 (interactive "p")
890 (if interactive
26b4dc84
GM
891 (widen))
892 (goto-char (point-max))
893 (recenter -1))
894
895(defun eshell-get-old-input (&optional use-current-region)
896 "Return the command input on the current line."
897 (if use-current-region
898 (buffer-substring (min (point) (mark))
899 (max (point) (mark)))
900 (save-excursion
901 (beginning-of-line)
902 (and eshell-skip-prompt-function
903 (funcall eshell-skip-prompt-function))
904 (let ((beg (point)))
905 (end-of-line)
906 (buffer-substring beg (point))))))
907
908(defun eshell-copy-old-input ()
909 "Insert after prompt old input at point as new input to be edited."
910 (interactive)
911 (let ((input (eshell-get-old-input)))
912 (goto-char eshell-last-output-end)
913 (insert-and-inherit input)))
914
26b4dc84
GM
915(defun eshell/exit ()
916 "Leave or kill the Eshell buffer, depending on `eshell-kill-on-exit'."
917 (throw 'eshell-terminal t))
918
919(defun eshell-life-is-too-much ()
920 "Kill the current buffer (or bury it). Good-bye Eshell."
921 (interactive)
922 (if (not eshell-kill-on-exit)
923 (bury-buffer)
924 (kill-buffer (current-buffer))))
925
926(defun eshell-truncate-buffer ()
927 "Truncate the buffer to `eshell-buffer-maximum-lines'.
928This function could be on `eshell-output-filter-functions' or bound to
929a key."
930 (interactive)
931 (save-excursion
932 (goto-char eshell-last-output-end)
933 (let ((lines (count-lines 1 (point)))
934 (inhibit-read-only t))
935 (forward-line (- eshell-buffer-maximum-lines))
936 (beginning-of-line)
937 (let ((pos (point)))
938 (if (bobp)
32226619 939 (if (called-interactively-p 'interactive)
3e80ba3c 940 (message "Buffer too short to truncate"))
26b4dc84 941 (delete-region (point-min) (point))
32226619 942 (if (called-interactively-p 'interactive)
26b4dc84
GM
943 (message "Truncated buffer from %d to %d lines (%.1fk freed)"
944 lines eshell-buffer-maximum-lines
945 (/ pos 1024.0))))))))
946
947(custom-add-option 'eshell-output-filter-functions
948 'eshell-truncate-buffer)
949
a07c7ade 950(defun eshell-send-invisible (str)
26b4dc84
GM
951 "Read a string without echoing.
952Then send it to the process running in the current buffer."
953 (interactive "P") ; Defeat snooping via C-x ESC ESC
954 (let ((str (read-passwd
6b61353c 955 (format "%s Password: "
26b4dc84
GM
956 (process-name (eshell-interactive-process))))))
957 (if (stringp str)
958 (process-send-string (eshell-interactive-process)
959 (concat str "\n"))
960 (message "Warning: text will be echoed"))))
961
962(defun eshell-watch-for-password-prompt ()
963 "Prompt in the minibuffer for password and send without echoing.
a07c7ade 964This function uses `eshell-send-invisible' to read and send a password to the
26b4dc84
GM
965buffer's process if STRING contains a password prompt defined by
966`eshell-password-prompt-regexp'.
967
968This function could be in the list `eshell-output-filter-functions'."
969 (when (eshell-interactive-process)
970 (save-excursion
971 (goto-char eshell-last-output-block-begin)
972 (beginning-of-line)
973 (if (re-search-forward eshell-password-prompt-regexp
974 eshell-last-output-end t)
a07c7ade 975 (eshell-send-invisible nil)))))
26b4dc84
GM
976
977(custom-add-option 'eshell-output-filter-functions
978 'eshell-watch-for-password-prompt)
979
980(defun eshell-handle-control-codes ()
981 "Act properly when certain control codes are seen."
982 (save-excursion
983 (let ((orig (point)))
984 (goto-char eshell-last-output-block-begin)
985 (unless (eolp)
986 (beginning-of-line))
987 (while (< (point) eshell-last-output-end)
988 (let ((char (char-after)))
989 (cond
990 ((eq char ?\r)
991 (if (< (1+ (point)) eshell-last-output-end)
992 (if (memq (char-after (1+ (point)))
993 '(?\n ?\r))
994 (delete-char 1)
995 (let ((end (1+ (point))))
996 (beginning-of-line)
997 (delete-region (point) end)))
998 (add-text-properties (point) (1+ (point))
999 '(invisible t))
1000 (forward-char)))
1001 ((eq char ?\a)
1002 (delete-char 1)
1003 (beep))
1004 ((eq char ?\C-h)
1005 (delete-backward-char 1)
1006 (delete-char 1))
1007 (t
1008 (forward-char))))))))
1009
1010(custom-add-option 'eshell-output-filter-functions
1011 'eshell-handle-control-codes)
1012
db04f33f
GM
1013(autoload 'ansi-color-apply-on-region "ansi-color")
1014
1c979bff
MH
1015(defun eshell-handle-ansi-color ()
1016 "Handle ANSI color codes."
1c979bff
MH
1017 (ansi-color-apply-on-region eshell-last-output-start
1018 eshell-last-output-end))
1019
1020(custom-add-option 'eshell-output-filter-functions
1021 'eshell-handle-ansi-color)
1022
26b4dc84 1023;;; esh-mode.el ends here