123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- (eval-when-compile (require 'eshell))
- (eshell-defgroup eshell-smart nil
- "This module combines the facility of normal, modern shells with
- some of the edit/review concepts inherent in the design of Plan 9's
- 9term. See the docs for more details.
- Most likely you will have to turn this option on and play around with
- it to get a real sense of how it works."
- :tag "Smart display of output"
-
- :group 'eshell-module)
- (defcustom eshell-smart-load-hook nil
- "A list of functions to call when loading `eshell-smart'."
- :version "24.1"
- :type 'hook
- :group 'eshell-smart)
- (defcustom eshell-smart-unload-hook
- (list
- (function
- (lambda ()
- (remove-hook 'window-configuration-change-hook
- 'eshell-refresh-windows))))
- "A hook that gets run when `eshell-smart' is unloaded."
- :type 'hook
- :group 'eshell-smart)
- (defcustom eshell-review-quick-commands nil
- "If t, always review commands.
- Reviewing means keeping point on the text of the command that was just
- invoked, to allow corrections to be made easily.
- If set to nil, quick commands won't be reviewed. A quick command is a
- command that produces no output, and exits successfully.
- If set to `not-even-short-output', then the definition of \"quick
- command\" is extended to include commands that produce output, if and
- only if that output can be presented in its entirely in the Eshell window."
- :type '(choice (const :tag "No" nil)
- (const :tag "Yes" t)
- (const :tag "Not even short output"
- not-even-short-output))
- :group 'eshell-smart)
- (defcustom eshell-smart-display-navigate-list
- '(insert-parentheses
- mouse-yank-at-click
- mouse-yank-primary
- mouse-yank-secondary
- yank-pop
- yank-rectangle
- yank)
- "A list of commands which cause Eshell to jump to the end of buffer."
- :type '(repeat function)
- :group 'eshell-smart)
- (defcustom eshell-smart-space-goes-to-end t
- "If non-nil, space will go to end of buffer when point-max is visible.
- That is, if a command is running and the user presses SPACE at a time
- when the end of the buffer is visible, point will go to the end of the
- buffer and smart-display will be turned off (that is, subsequently
- pressing backspace will not cause the buffer to scroll down).
- This feature is provided to make it very easy to watch the output of a
- long-running command, such as make, where it's more desirable to see
- the output go by than to review it afterward.
- Setting this variable to nil means that space and backspace will
- always have a consistent behavior, which is to move back and forth
- through displayed output. But it also means that enabling output
- tracking requires the user to manually move point to the end of the
- buffer using \\[end-of-buffer]."
- :type 'boolean
- :group 'eshell-smart)
- (defcustom eshell-where-to-jump 'begin
- "This variable indicates where point should jump to after a command.
- The options are `begin', `after' or `end'."
- :type '(radio (const :tag "Beginning of command" begin)
- (const :tag "After command word" after)
- (const :tag "End of command" end))
- :group 'eshell-smart)
- (defvar eshell-smart-displayed nil)
- (defvar eshell-smart-command-done nil)
- (defvar eshell-currently-handling-window nil)
- (defun eshell-smart-initialize ()
- "Setup Eshell smart display."
- (unless eshell-non-interactive-p
-
-
- (set (make-local-variable 'eshell-scroll-to-bottom-on-output) nil)
- (set (make-local-variable 'eshell-scroll-to-bottom-on-input) nil)
- (set (make-local-variable 'eshell-scroll-show-maximum-output) t)
- (add-hook 'window-scroll-functions 'eshell-smart-scroll-window nil t)
- (add-hook 'window-configuration-change-hook 'eshell-refresh-windows)
- (add-hook 'eshell-output-filter-functions 'eshell-refresh-windows t t)
- (add-hook 'after-change-functions 'eshell-disable-after-change nil t)
- (add-hook 'eshell-input-filter-functions 'eshell-smart-display-setup nil t)
- (make-local-variable 'eshell-smart-command-done)
- (add-hook 'eshell-post-command-hook
- (function
- (lambda ()
- (setq eshell-smart-command-done t))) t t)
- (unless (eq eshell-review-quick-commands t)
- (add-hook 'eshell-post-command-hook
- 'eshell-smart-maybe-jump-to-end nil t))))
- (defun eshell-smart-scroll-window (wind start)
- "Scroll the given Eshell window accordingly."
- (unless eshell-currently-handling-window
- (let ((inhibit-point-motion-hooks t)
- (eshell-currently-handling-window t))
- (save-selected-window
- (select-window wind)
- (eshell-smart-redisplay)))))
- (defun eshell-refresh-windows (&optional frame)
- "Refresh all visible Eshell buffers."
- (let (affected)
- (walk-windows
- (function
- (lambda (wind)
- (with-current-buffer (window-buffer wind)
- (if eshell-mode
- (let (window-scroll-functions)
- (eshell-smart-scroll-window wind (window-start))
- (setq affected t))))))
- 0 frame)
- (if affected
- (let (window-scroll-functions)
- (eshell-redisplay)))))
- (defun eshell-smart-display-setup ()
- "Set the point to somewhere in the beginning of the last command."
- (cond
- ((eq eshell-where-to-jump 'begin)
- (goto-char eshell-last-input-start))
- ((eq eshell-where-to-jump 'after)
- (goto-char (next-single-property-change
- eshell-last-input-start 'arg-end))
- (if (= (point) (- eshell-last-input-end 2))
- (forward-char)))
- ((eq eshell-where-to-jump 'end)
- (goto-char (1- eshell-last-input-end)))
- (t
- (error "Invalid value for `eshell-where-to-jump'")))
- (setq eshell-smart-command-done nil)
- (add-hook 'pre-command-hook 'eshell-smart-display-move nil t)
- (eshell-refresh-windows))
- (defun eshell-disable-after-change (b e l)
- "Disable smart display mode if the buffer changes in any way."
- (when eshell-smart-command-done
- (remove-hook 'pre-command-hook 'eshell-smart-display-move t)
- (setq eshell-smart-command-done nil)))
- (defun eshell-smart-maybe-jump-to-end ()
- "Jump to the end of the input buffer.
- This is done whenever a command exits successfully and both the command
- and the end of the buffer are still visible."
- (when (and (= eshell-last-command-status 0)
- (if (eq eshell-review-quick-commands 'not-even-short-output)
- (and (pos-visible-in-window-p (point-max))
- (pos-visible-in-window-p eshell-last-input-start))
- (= (count-lines eshell-last-input-end
- eshell-last-output-end) 0)))
- (goto-char (point-max))
- (remove-hook 'pre-command-hook 'eshell-smart-display-move t)))
- (defun eshell-smart-redisplay ()
- "Display as much output as possible, smartly."
- (if (eobp)
- (save-excursion
- (recenter -1)
-
-
- (eshell-redisplay))
- (let ((top-point (point)))
- (and (memq 'eshell-smart-display-move pre-command-hook)
- (>= (point) eshell-last-input-start)
- (< (point) eshell-last-input-end)
- (set-window-start (selected-window)
- (line-beginning-position) t))
- (if (pos-visible-in-window-p (point-max))
- (save-excursion
- (goto-char (point-max))
- (recenter -1)
- (unless (pos-visible-in-window-p top-point)
- (goto-char top-point)
- (set-window-start (selected-window)
- (line-beginning-position) t)))))))
- (defun eshell-smart-goto-end ()
- "Like `end-of-buffer', but do not push a mark."
- (interactive)
- (goto-char (point-max)))
- (defun eshell-smart-display-move ()
- "Handle self-inserting or movement commands intelligently."
- (let (clear)
- (if (or current-prefix-arg
- (and (> (point) eshell-last-input-start)
- (< (point) eshell-last-input-end))
- (>= (point) eshell-last-output-end))
- (setq clear t)
- (cond
- ((eq this-command 'self-insert-command)
- (if (eq last-command-event ? )
- (if (and eshell-smart-space-goes-to-end
- eshell-current-command)
- (if (not (pos-visible-in-window-p (point-max)))
- (setq this-command 'scroll-up)
- (setq this-command 'eshell-smart-goto-end))
- (setq this-command 'scroll-up))
- (setq clear t)
- (goto-char (point-max))))
- ((eq this-command 'delete-backward-char)
- (setq this-command 'ignore)
- (if (< (point) eshell-last-input-start)
- (eshell-show-output)
- (if (pos-visible-in-window-p eshell-last-input-start)
- (progn
- (ignore-errors
- (scroll-down))
- (eshell-show-output))
- (scroll-down)
- (if (pos-visible-in-window-p eshell-last-input-end)
- (eshell-show-output)))))
- ((or (memq this-command eshell-smart-display-navigate-list)
- (and (eq this-command 'eshell-send-input)
- (not (and (>= (point) eshell-last-input-start)
- (< (point) eshell-last-input-end)))))
- (setq clear t)
- (goto-char (point-max)))))
- (if clear
- (remove-hook 'pre-command-hook 'eshell-smart-display-move t))))
- (provide 'em-smart)
|