Mercurial > emacs
annotate lisp/eshell/em-smart.el @ 85607:c19beeecd4fd
*** empty log message ***
| author | Carsten Dominik <dominik@science.uva.nl> |
|---|---|
| date | Wed, 24 Oct 2007 05:36:34 +0000 |
| parents | a1e8300d3c55 |
| children | 48c4bb2b7d11 dff2dab8707b f55f9811f5d7 |
| rev | line source |
|---|---|
|
38414
67b464da13ec
Some fixes to follow coding conventions.
Pavel Jan?k <Pavel@Janik.cz>
parents:
37439
diff
changeset
|
1 ;;; em-smart.el --- smart display of output |
| 29876 | 2 |
| 74509 | 3 ;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, |
| 75346 | 4 ;; 2005, 2006, 2007 Free Software Foundation, Inc. |
| 29876 | 5 |
| 32526 | 6 ;; Author: John Wiegley <johnw@gnu.org> |
| 7 | |
| 29876 | 8 ;; This file is part of GNU Emacs. |
| 9 | |
| 10 ;; GNU Emacs is free software; you can redistribute it and/or modify | |
| 11 ;; it under the terms of the GNU General Public License as published by | |
|
78220
a1e8300d3c55
Switch license to GPLv3 or later.
Glenn Morris <rgm@gnu.org>
parents:
75346
diff
changeset
|
12 ;; the Free Software Foundation; either version 3, or (at your option) |
| 29876 | 13 ;; any later version. |
| 14 | |
| 15 ;; GNU Emacs is distributed in the hope that it will be useful, | |
| 16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 18 ;; GNU General Public License for more details. | |
| 19 | |
| 20 ;; You should have received a copy of the GNU General Public License | |
| 21 ;; along with GNU Emacs; see the file COPYING. If not, write to the | |
| 64085 | 22 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| 23 ;; Boston, MA 02110-1301, USA. | |
| 29876 | 24 |
| 25 (provide 'em-smart) | |
| 26 | |
| 27 (eval-when-compile (require 'esh-maint)) | |
| 28 | |
| 29 (defgroup eshell-smart nil | |
| 30 "This module combines the facility of normal, modern shells with | |
| 31 some of the edit/review concepts inherent in the design of Plan 9's | |
| 32 9term. See the docs for more details. | |
| 33 | |
| 34 Most likely you will have to turn this option on and play around with | |
| 35 it to get a real sense of how it works." | |
| 36 :tag "Smart display of output" | |
|
54567
5aa470f4fc15
* eshell/em-smart.el (eshell-smart):
Juri Linkov <juri@jurta.org>
parents:
54204
diff
changeset
|
37 ;; :link '(info-link "(eshell)Smart display of output") |
| 29876 | 38 :group 'eshell-module) |
| 39 | |
| 40 ;;; Commentary: | |
| 41 | |
| 42 ;; The best way to get a sense of what this code is trying to do is by | |
| 43 ;; using it. Basically, the philosophy represents a blend between the | |
| 44 ;; ease of use of modern day shells, and the review-before-you-proceed | |
| 45 ;; mentality of Plan 9's 9term. | |
| 46 ;; | |
| 47 ;; @ When you invoke a command, it is assumed that you want to read | |
| 48 ;; the output of that command. | |
| 49 ;; | |
| 50 ;; @ If the output is not what you wanted, it is assumed that you will | |
| 51 ;; want to edit, and then resubmit a refined version of that | |
| 52 ;; command. | |
| 53 ;; | |
| 54 ;; @ If the output is valid, pressing any self-inserting character key | |
| 55 ;; will jump to end of the buffer and insert that character, in | |
| 56 ;; order to begin entry of a new command. | |
| 57 ;; | |
| 58 ;; @ If you show an intention to edit the previous command -- by | |
| 59 ;; moving around within it -- then the next self-inserting | |
| 60 ;; characters will insert *there*, instead of at the bottom of the | |
| 61 ;; buffer. | |
| 62 ;; | |
| 63 ;; @ If you show an intention to review old commands, such as M-p or | |
| 64 ;; M-r, point will jump to the bottom of the buffer before invoking | |
| 65 ;; that command. | |
| 66 ;; | |
| 67 ;; @ If none of the above has happened yet (i.e., your point is just | |
| 68 ;; sitting on the previous command), you can use SPACE and BACKSPACE | |
| 69 ;; (or DELETE) to page forward and backward *through the output of | |
| 70 ;; the last command only*. It will constrain the movement of the | |
| 71 ;; point and window so that the maximum amount of output is always | |
| 72 ;; displayed at all times. | |
| 73 ;; | |
| 74 ;; @ While output is being generated from a command, the window will | |
| 75 ;; be constantly reconfigured (until it would otherwise make no | |
| 76 ;; difference) in order to always show you the most output from the | |
| 77 ;; command possible. This happens if you change window sizes, | |
| 78 ;; scroll, etc. | |
| 79 ;; | |
| 80 ;; @ Like I said, it's not really comprehensible until you try it! ;) | |
| 33020 | 81 ;; |
| 82 ;; One disadvantage of this module is that it increases Eshell's | |
| 83 ;; memory consumption by a factor of two or more. With small commands | |
| 84 ;; (such as pwd), where the screen is mostly full, consumption can | |
| 85 ;; increase by orders of magnitude. | |
| 29876 | 86 |
| 87 ;;; User Variables: | |
| 88 | |
| 89 (defcustom eshell-smart-load-hook '(eshell-smart-initialize) | |
| 90 "*A list of functions to call when loading `eshell-smart'." | |
| 91 :type 'hook | |
| 92 :group 'eshell-smart) | |
| 93 | |
| 94 (defcustom eshell-smart-unload-hook | |
| 95 (list | |
| 96 (function | |
| 97 (lambda () | |
| 98 (remove-hook 'window-configuration-change-hook | |
| 99 'eshell-refresh-windows)))) | |
| 100 "*A hook that gets run when `eshell-smart' is unloaded." | |
| 101 :type 'hook | |
| 102 :group 'eshell-smart) | |
| 103 | |
| 104 (defcustom eshell-review-quick-commands nil | |
| 31240 | 105 "*If t, always review commands. |
| 106 Reviewing means keeping point on the text of the command that was just | |
| 107 invoked, to allow corrections to be made easily. | |
| 108 | |
| 109 If set to nil, quick commands won't be reviewed. A quick command is a | |
| 110 command that produces no output, and exits successfully. | |
| 111 | |
| 112 If set to `not-even-short-output', then the definition of \"quick | |
| 113 command\" is extended to include commands that produce output, iff | |
| 114 that output can be presented in its entirely in the Eshell window." | |
| 115 :type '(choice (const :tag "No" nil) | |
| 116 (const :tag "Yes" t) | |
| 117 (const :tag "Not even short output" | |
| 118 not-even-short-output)) | |
| 29876 | 119 :group 'eshell-smart) |
| 120 | |
| 121 (defcustom eshell-smart-display-navigate-list | |
| 122 '(insert-parentheses | |
| 123 mouse-yank-at-click | |
| 124 mouse-yank-secondary | |
| 125 yank-pop | |
| 126 yank-rectangle | |
| 127 yank) | |
| 128 "*A list of commands which cause Eshell to jump to the end of buffer." | |
| 129 :type '(repeat function) | |
| 130 :group 'eshell-smart) | |
| 131 | |
| 132 (defcustom eshell-smart-space-goes-to-end t | |
| 133 "*If non-nil, space will go to end of buffer when point-max is visible. | |
| 134 That is, if a command is running and the user presses SPACE at a time | |
| 135 when the end of the buffer is visible, point will go to the end of the | |
| 136 buffer and smart-display will be turned off (that is, subsequently | |
| 137 pressing backspace will not cause the buffer to scroll down). | |
| 138 | |
| 139 This feature is provided to make it very easy to watch the output of a | |
| 140 long-running command, such as make, where it's more desirable to see | |
| 141 the output go by than to review it afterward. | |
| 142 | |
| 143 Setting this variable to nil means that space and backspace will | |
| 144 always have a consistent behavior, which is to move back and forth | |
| 145 through displayed output. But it also means that enabling output | |
| 146 tracking requires the user to manually move point to the end of the | |
| 147 buffer using \\[end-of-buffer]." | |
| 148 :type 'boolean | |
| 149 :group 'eshell-smart) | |
| 150 | |
| 151 (defcustom eshell-where-to-jump 'begin | |
| 152 "*This variable indicates where point should jump to after a command. | |
| 153 The options are `begin', `after' or `end'." | |
| 154 :type '(radio (const :tag "Beginning of command" begin) | |
| 155 (const :tag "After command word" after) | |
| 156 (const :tag "End of command" end)) | |
| 157 :group 'eshell-smart) | |
| 158 | |
| 159 ;;; Internal Variables: | |
| 160 | |
| 161 (defvar eshell-smart-displayed nil) | |
| 162 (defvar eshell-smart-command-done nil) | |
| 33020 | 163 (defvar eshell-currently-handling-window nil) |
| 29876 | 164 |
| 165 ;;; Functions: | |
| 166 | |
| 167 (defun eshell-smart-initialize () | |
| 168 "Setup Eshell smart display." | |
| 169 (unless eshell-non-interactive-p | |
| 170 ;; override a few variables, since they would interfere with the | |
| 171 ;; smart display functionality. | |
| 172 (set (make-local-variable 'eshell-scroll-to-bottom-on-output) nil) | |
| 173 (set (make-local-variable 'eshell-scroll-to-bottom-on-input) nil) | |
| 174 (set (make-local-variable 'eshell-scroll-show-maximum-output) t) | |
| 175 | |
| 176 (add-hook 'window-scroll-functions 'eshell-smart-scroll-window nil t) | |
| 177 (add-hook 'window-configuration-change-hook 'eshell-refresh-windows) | |
| 178 | |
| 179 (add-hook 'eshell-output-filter-functions 'eshell-refresh-windows t t) | |
| 180 | |
| 33020 | 181 (add-hook 'after-change-functions 'eshell-disable-after-change nil t) |
| 29876 | 182 |
| 33020 | 183 (add-hook 'eshell-input-filter-functions 'eshell-smart-display-setup nil t) |
| 29876 | 184 |
| 185 (make-local-variable 'eshell-smart-command-done) | |
| 33020 | 186 (add-hook 'eshell-post-command-hook |
| 187 (function | |
| 188 (lambda () | |
| 189 (setq eshell-smart-command-done t))) t t) | |
| 29876 | 190 |
| 31240 | 191 (unless (eq eshell-review-quick-commands t) |
| 29876 | 192 (add-hook 'eshell-post-command-hook |
| 193 'eshell-smart-maybe-jump-to-end nil t)))) | |
| 194 | |
| 195 (defun eshell-smart-scroll-window (wind start) | |
| 196 "Scroll the given Eshell window accordingly." | |
| 197 (unless eshell-currently-handling-window | |
| 198 (let ((inhibit-point-motion-hooks t) | |
| 199 (eshell-currently-handling-window t)) | |
| 33020 | 200 (save-selected-window |
| 201 (select-window wind) | |
| 202 (eshell-smart-redisplay))))) | |
| 29876 | 203 |
| 204 (defun eshell-refresh-windows (&optional frame) | |
| 205 "Refresh all visible Eshell buffers." | |
| 206 (let (affected) | |
| 207 (walk-windows | |
| 208 (function | |
| 209 (lambda (wind) | |
| 210 (with-current-buffer (window-buffer wind) | |
| 33020 | 211 (if eshell-mode |
| 212 (let (window-scroll-functions) | |
| 213 (eshell-smart-scroll-window wind (window-start)) | |
| 214 (setq affected t)))))) | |
| 29876 | 215 0 frame) |
| 216 (if affected | |
| 217 (let (window-scroll-functions) | |
| 218 (eshell-redisplay))))) | |
| 219 | |
| 220 (defun eshell-smart-display-setup () | |
| 221 "Set the point to somewhere in the beginning of the last command." | |
| 222 (cond | |
| 223 ((eq eshell-where-to-jump 'begin) | |
| 224 (goto-char eshell-last-input-start)) | |
| 225 ((eq eshell-where-to-jump 'after) | |
| 226 (goto-char (next-single-property-change | |
| 227 eshell-last-input-start 'arg-end)) | |
| 228 (if (= (point) (- eshell-last-input-end 2)) | |
| 229 (forward-char))) | |
| 230 ((eq eshell-where-to-jump 'end) | |
| 231 (goto-char (1- eshell-last-input-end))) | |
| 232 (t | |
| 233 (error "Invalid value for `eshell-where-to-jump'"))) | |
| 234 (setq eshell-smart-command-done nil) | |
| 235 (add-hook 'pre-command-hook 'eshell-smart-display-move nil t) | |
| 236 (eshell-refresh-windows)) | |
| 237 | |
| 238 (defun eshell-disable-after-change (b e l) | |
| 239 "Disable smart display mode if the buffer changes in any way." | |
| 240 (when eshell-smart-command-done | |
| 241 (remove-hook 'pre-command-hook 'eshell-smart-display-move t) | |
| 242 (setq eshell-smart-command-done nil))) | |
| 243 | |
| 244 (defun eshell-smart-maybe-jump-to-end () | |
| 245 "Jump to the end of the input buffer. | |
|
54204
e0d19d483614
(eshell-smart-maybe-jump-to-end): Fix typo.
Juanma Barranquero <lekktu@gmail.com>
parents:
52401
diff
changeset
|
246 This is done whenever a command exits successfully and both the command |
| 31240 | 247 and the end of the buffer are still visible." |
| 29876 | 248 (when (and (= eshell-last-command-status 0) |
| 31240 | 249 (if (eq eshell-review-quick-commands 'not-even-short-output) |
| 250 (and (pos-visible-in-window-p (point-max)) | |
| 251 (pos-visible-in-window-p eshell-last-input-start)) | |
| 252 (= (count-lines eshell-last-input-end | |
| 253 eshell-last-output-end) 0))) | |
| 29876 | 254 (goto-char (point-max)) |
| 255 (remove-hook 'pre-command-hook 'eshell-smart-display-move t))) | |
| 256 | |
| 257 (defun eshell-smart-redisplay () | |
| 258 "Display as much output as possible, smartly." | |
| 259 (if (eobp) | |
|
37439
f8c03126b032
(eshell-smart-redisplay): Added some safety code to work around a
John Wiegley <johnw@newartisans.com>
parents:
33020
diff
changeset
|
260 (save-excursion |
|
f8c03126b032
(eshell-smart-redisplay): Added some safety code to work around a
John Wiegley <johnw@newartisans.com>
parents:
33020
diff
changeset
|
261 (recenter -1) |
|
f8c03126b032
(eshell-smart-redisplay): Added some safety code to work around a
John Wiegley <johnw@newartisans.com>
parents:
33020
diff
changeset
|
262 ;; trigger the redisplay now, so that we catch any attempted |
|
f8c03126b032
(eshell-smart-redisplay): Added some safety code to work around a
John Wiegley <johnw@newartisans.com>
parents:
33020
diff
changeset
|
263 ;; point motion; this is to cover for a redisplay bug |
|
f8c03126b032
(eshell-smart-redisplay): Added some safety code to work around a
John Wiegley <johnw@newartisans.com>
parents:
33020
diff
changeset
|
264 (eshell-redisplay)) |
| 31241 | 265 (let ((top-point (point))) |
| 266 (and (memq 'eshell-smart-display-move pre-command-hook) | |
| 267 (>= (point) eshell-last-input-start) | |
| 268 (< (point) eshell-last-input-end) | |
| 269 (set-window-start (selected-window) | |
| 270 (line-beginning-position) t)) | |
| 271 (if (pos-visible-in-window-p (point-max)) | |
| 272 (save-excursion | |
| 273 (goto-char (point-max)) | |
| 274 (recenter -1) | |
| 275 (unless (pos-visible-in-window-p top-point) | |
| 276 (goto-char top-point) | |
| 277 (set-window-start (selected-window) | |
| 278 (line-beginning-position) t))))))) | |
| 29876 | 279 |
| 280 (defun eshell-smart-goto-end () | |
| 281 "Like `end-of-buffer', but do not push a mark." | |
| 282 (interactive) | |
| 283 (goto-char (point-max))) | |
| 284 | |
| 285 (defun eshell-smart-display-move () | |
| 286 "Handle self-inserting or movement commands intelligently." | |
| 287 (let (clear) | |
| 288 (if (or current-prefix-arg | |
| 289 (and (> (point) eshell-last-input-start) | |
| 290 (< (point) eshell-last-input-end)) | |
| 291 (>= (point) eshell-last-output-end)) | |
| 292 (setq clear t) | |
| 293 (cond | |
| 294 ((eq this-command 'self-insert-command) | |
| 295 (if (eq last-command-char ? ) | |
| 296 (if (and eshell-smart-space-goes-to-end | |
| 297 eshell-current-command) | |
| 298 (if (not (pos-visible-in-window-p (point-max))) | |
| 299 (setq this-command 'scroll-up) | |
| 300 (setq this-command 'eshell-smart-goto-end)) | |
| 301 (setq this-command 'scroll-up)) | |
| 302 (setq clear t) | |
| 303 (goto-char (point-max)))) | |
| 304 ((eq this-command 'delete-backward-char) | |
| 305 (setq this-command 'ignore) | |
| 306 (if (< (point) eshell-last-input-start) | |
| 307 (eshell-show-output) | |
| 308 (if (pos-visible-in-window-p eshell-last-input-start) | |
| 309 (progn | |
| 310 (ignore-errors | |
| 311 (scroll-down)) | |
| 312 (eshell-show-output)) | |
| 313 (scroll-down) | |
| 314 (if (pos-visible-in-window-p eshell-last-input-end) | |
| 315 (eshell-show-output))))) | |
| 316 ((or (memq this-command eshell-smart-display-navigate-list) | |
| 317 (and (eq this-command 'eshell-send-input) | |
| 318 (not (and (>= (point) eshell-last-input-start) | |
| 319 (< (point) eshell-last-input-end))))) | |
| 320 (setq clear t) | |
| 321 (goto-char (point-max))))) | |
| 322 (if clear | |
| 323 (remove-hook 'pre-command-hook 'eshell-smart-display-move t)))) | |
| 324 | |
| 325 ;;; Code: | |
| 326 | |
| 52401 | 327 ;;; arch-tag: 8c0112c7-379c-4d54-9a1c-204d68786a4b |
| 29876 | 328 ;;; em-smart.el ends here |
