diff options
| author | Phil Sainty | 2017-10-21 11:17:56 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2017-10-21 11:17:56 +0300 |
| commit | 0d8e4f45d612ecd77f4997fae30e4d1591f9b8a6 (patch) | |
| tree | 72c3d41f678300c07d799d7942ca6b2d8cce6d9d | |
| parent | 79d57f4b7a8dc0d0cd213ce5989886cc9fc9b7f3 (diff) | |
| download | emacs-0d8e4f45d612ecd77f4997fae30e4d1591f9b8a6.tar.gz emacs-0d8e4f45d612ecd77f4997fae30e4d1591f9b8a6.zip | |
Avoid creating inconsistent buffer states in term-char-mode
* lisp/term.el (term-mode, term-char-mode, term-line-mode)
(term-emulate-terminal): Make buffer read-only in 'term-char-mode',
except for the process filter's output. Use 'read-only-mode-hook' to
track and restore the user-set state of 'buffer-read-only' for
'term-line-mode'. (Bug#24837)
(term-char-mode-buffer-read-only): New user option.
(term-line-mode-buffer-read-only): New buffer-local variable.
(term-line-mode-buffer-read-only-update): New function.
(term-char-mode, term-line-mode): Use 'term-set-goto-process-mark'
in pre-command-hook, and 'term-goto-process-mark-maybe' in
post-command-hook to counter-act unexpected changes to point when
using 'term-char-mode'.
(term-char-mode-point-at-process-mark): New user option.
(term-goto-process-mark): New buffer-local variable.
(term-set-goto-process-mark): New function.
(term-goto-process-mark-maybe): New function.
(term-process-mark): New function.
* etc/NEWS: Mention the new behavior and user options.
| -rw-r--r-- | etc/NEWS | 17 | ||||
| -rw-r--r-- | lisp/term.el | 98 |
2 files changed, 115 insertions, 0 deletions
| @@ -1168,6 +1168,23 @@ provided. | |||
| 1168 | The old Flymake behavior is preserved in the so-called "legacy | 1168 | The old Flymake behavior is preserved in the so-called "legacy |
| 1169 | backend", which has been updated to benefit from the new UI features. | 1169 | backend", which has been updated to benefit from the new UI features. |
| 1170 | 1170 | ||
| 1171 | ** Term | ||
| 1172 | |||
| 1173 | --- | ||
| 1174 | *** `term-char-mode' now makes its buffer read-only. | ||
| 1175 | |||
| 1176 | The buffer is made read-only to prevent changes from being made by | ||
| 1177 | anything other than the process filter; and movements of point away | ||
| 1178 | from the process mark are counter-acted so that the cursor is in the | ||
| 1179 | correct position after each command. This is needed to avoid states | ||
| 1180 | which are inconsistent with the state of the terminal understood by | ||
| 1181 | the inferior process. | ||
| 1182 | |||
| 1183 | New user options `term-char-mode-buffer-read-only' and | ||
| 1184 | `term-char-mode-point-at-process-mark' control these behaviors, and | ||
| 1185 | are non-nil by default. Customize these options to nil if you want | ||
| 1186 | the previous behavior. | ||
| 1187 | |||
| 1171 | 1188 | ||
| 1172 | * New Modes and Packages in Emacs 26.1 | 1189 | * New Modes and Packages in Emacs 26.1 |
| 1173 | 1190 | ||
diff --git a/lisp/term.el b/lisp/term.el index c748c450206..2046578368c 100644 --- a/lisp/term.el +++ b/lisp/term.el | |||
| @@ -427,6 +427,8 @@ by moving term-home-marker. It is set to t if there is a | |||
| 427 | (defvar term-old-mode-line-format) ; Saves old mode-line-format while paging. | 427 | (defvar term-old-mode-line-format) ; Saves old mode-line-format while paging. |
| 428 | (defvar term-pager-old-local-map nil "Saves old keymap while paging.") | 428 | (defvar term-pager-old-local-map nil "Saves old keymap while paging.") |
| 429 | (defvar term-pager-old-filter) ; Saved process-filter while paging. | 429 | (defvar term-pager-old-filter) ; Saved process-filter while paging. |
| 430 | (defvar-local term-line-mode-buffer-read-only nil | ||
| 431 | "The `buffer-read-only' state to set in `term-line-mode'.") | ||
| 430 | 432 | ||
| 431 | (defcustom explicit-shell-file-name nil | 433 | (defcustom explicit-shell-file-name nil |
| 432 | "If non-nil, is file name to use for explicitly requested inferior shell." | 434 | "If non-nil, is file name to use for explicitly requested inferior shell." |
| @@ -487,6 +489,41 @@ This variable is buffer-local, and is a good thing to set in mode hooks." | |||
| 487 | :type 'boolean | 489 | :type 'boolean |
| 488 | :group 'term) | 490 | :group 'term) |
| 489 | 491 | ||
| 492 | (defcustom term-char-mode-buffer-read-only t | ||
| 493 | "If non-nil, only the process filter may modify the buffer in char mode. | ||
| 494 | |||
| 495 | A non-nil value makes the buffer read-only in `term-char-mode', | ||
| 496 | which prevents editing commands from making the buffer state | ||
| 497 | inconsistent with the state of the terminal understood by the | ||
| 498 | inferior process. Only the process filter is allowed to make | ||
| 499 | changes to the buffer. | ||
| 500 | |||
| 501 | Customize this option to nil if you want the previous behaviour." | ||
| 502 | :version "26.1" | ||
| 503 | :type 'boolean | ||
| 504 | :group 'term) | ||
| 505 | |||
| 506 | (defcustom term-char-mode-point-at-process-mark t | ||
| 507 | "If non-nil, keep point at the process mark in char mode. | ||
| 508 | |||
| 509 | A non-nil value causes point to be moved to the current process | ||
| 510 | mark after each command in `term-char-mode' (provided that the | ||
| 511 | pre-command point position was also at the process mark). This | ||
| 512 | prevents commands that move point from making the buffer state | ||
| 513 | inconsistent with the state of the terminal understood by the | ||
| 514 | inferior process. | ||
| 515 | |||
| 516 | Mouse events are not affected, so moving point and selecting text | ||
| 517 | is still possible in char mode via the mouse, after which other | ||
| 518 | commands can be invoked on the mouse-selected point or region, | ||
| 519 | until the process filter (or user) moves point to the process | ||
| 520 | mark once again. | ||
| 521 | |||
| 522 | Customize this option to nil if you want the previous behaviour." | ||
| 523 | :version "26.1" | ||
| 524 | :type 'boolean | ||
| 525 | :group 'term) | ||
| 526 | |||
| 490 | (defcustom term-scroll-to-bottom-on-output nil | 527 | (defcustom term-scroll-to-bottom-on-output nil |
| 491 | "Controls whether interpreter output causes window to scroll. | 528 | "Controls whether interpreter output causes window to scroll. |
| 492 | If nil, then do not scroll. If t or `all', scroll all windows showing buffer. | 529 | If nil, then do not scroll. If t or `all', scroll all windows showing buffer. |
| @@ -1105,6 +1142,8 @@ Entry to this mode runs the hooks on `term-mode-hook'." | |||
| 1105 | (term-reset-size (cdr size) (car size))) | 1142 | (term-reset-size (cdr size) (car size))) |
| 1106 | size)) | 1143 | size)) |
| 1107 | 1144 | ||
| 1145 | (add-hook 'read-only-mode-hook #'term-line-mode-buffer-read-only-update nil t) | ||
| 1146 | |||
| 1108 | (easy-menu-add term-terminal-menu) | 1147 | (easy-menu-add term-terminal-menu) |
| 1109 | (easy-menu-add term-signals-menu) | 1148 | (easy-menu-add term-signals-menu) |
| 1110 | (or term-input-ring | 1149 | (or term-input-ring |
| @@ -1246,6 +1285,13 @@ intervention from Emacs, except for the escape character (usually C-c)." | |||
| 1246 | (easy-menu-add term-terminal-menu) | 1285 | (easy-menu-add term-terminal-menu) |
| 1247 | (easy-menu-add term-signals-menu) | 1286 | (easy-menu-add term-signals-menu) |
| 1248 | 1287 | ||
| 1288 | ;; Don't allow changes to the buffer or to point which are not | ||
| 1289 | ;; caused by the process filter. | ||
| 1290 | (when term-char-mode-buffer-read-only | ||
| 1291 | (setq buffer-read-only t)) | ||
| 1292 | (add-hook 'pre-command-hook #'term-set-goto-process-mark nil t) | ||
| 1293 | (add-hook 'post-command-hook #'term-goto-process-mark-maybe nil t) | ||
| 1294 | |||
| 1249 | ;; Send existing partial line to inferior (without newline). | 1295 | ;; Send existing partial line to inferior (without newline). |
| 1250 | (let ((pmark (process-mark (get-buffer-process (current-buffer)))) | 1296 | (let ((pmark (process-mark (get-buffer-process (current-buffer)))) |
| 1251 | (save-input-sender term-input-sender)) | 1297 | (save-input-sender term-input-sender)) |
| @@ -1265,9 +1311,20 @@ This means that Emacs editing commands work as normally, until | |||
| 1265 | you type \\[term-send-input] which sends the current line to the inferior." | 1311 | you type \\[term-send-input] which sends the current line to the inferior." |
| 1266 | (interactive) | 1312 | (interactive) |
| 1267 | (when (term-in-char-mode) | 1313 | (when (term-in-char-mode) |
| 1314 | (when term-char-mode-buffer-read-only | ||
| 1315 | (setq buffer-read-only term-line-mode-buffer-read-only)) | ||
| 1316 | (remove-hook 'pre-command-hook #'term-set-goto-process-mark t) | ||
| 1317 | (remove-hook 'post-command-hook #'term-goto-process-mark-maybe t) | ||
| 1268 | (use-local-map term-old-mode-map) | 1318 | (use-local-map term-old-mode-map) |
| 1269 | (term-update-mode-line))) | 1319 | (term-update-mode-line))) |
| 1270 | 1320 | ||
| 1321 | (defun term-line-mode-buffer-read-only-update () | ||
| 1322 | "Update the user-set state of `buffer-read-only' in `term-line-mode'. | ||
| 1323 | |||
| 1324 | Called as a buffer-local `read-only-mode-hook' function." | ||
| 1325 | (when (term-in-line-mode) | ||
| 1326 | (setq term-line-mode-buffer-read-only buffer-read-only))) | ||
| 1327 | |||
| 1271 | (defun term-update-mode-line () | 1328 | (defun term-update-mode-line () |
| 1272 | (let ((term-mode | 1329 | (let ((term-mode |
| 1273 | (if (term-in-char-mode) | 1330 | (if (term-in-char-mode) |
| @@ -2711,6 +2768,7 @@ See `term-prompt-regexp'." | |||
| 2711 | count-bytes ; number of bytes | 2768 | count-bytes ; number of bytes |
| 2712 | decoded-substring | 2769 | decoded-substring |
| 2713 | save-point save-marker old-point temp win | 2770 | save-point save-marker old-point temp win |
| 2771 | (inhibit-read-only t) | ||
| 2714 | (buffer-undo-list t) | 2772 | (buffer-undo-list t) |
| 2715 | (selected (selected-window)) | 2773 | (selected (selected-window)) |
| 2716 | last-win | 2774 | last-win |
| @@ -3109,6 +3167,46 @@ See `term-prompt-regexp'." | |||
| 3109 | (when (get-buffer-window (current-buffer)) | 3167 | (when (get-buffer-window (current-buffer)) |
| 3110 | (redisplay)))) | 3168 | (redisplay)))) |
| 3111 | 3169 | ||
| 3170 | (defvar-local term-goto-process-mark t | ||
| 3171 | "Whether to reset point to the current process mark after this command. | ||
| 3172 | |||
| 3173 | Set in `pre-command-hook' in char mode by `term-set-goto-process-mark'.") | ||
| 3174 | |||
| 3175 | (defun term-set-goto-process-mark () | ||
| 3176 | "Sets `term-goto-process-mark'. | ||
| 3177 | |||
| 3178 | Always set to nil if `term-char-mode-point-at-process-mark' is nil. | ||
| 3179 | |||
| 3180 | Called as a buffer-local `pre-command-hook' function in | ||
| 3181 | `term-char-mode' so that when point is equal to the process mark | ||
| 3182 | at the pre-command stage, we know to restore point to the process | ||
| 3183 | mark at the post-command stage. | ||
| 3184 | |||
| 3185 | See also `term-goto-process-mark-maybe'." | ||
| 3186 | (setq term-goto-process-mark | ||
| 3187 | (and term-char-mode-point-at-process-mark | ||
| 3188 | (eq (point) (marker-position (term-process-mark)))))) | ||
| 3189 | |||
| 3190 | (defun term-goto-process-mark-maybe () | ||
| 3191 | "Move point to the term buffer's process mark upon keyboard input. | ||
| 3192 | |||
| 3193 | Called as a buffer-local `post-command-hook' function in | ||
| 3194 | `term-char-mode' to prevent commands from putting the buffer into | ||
| 3195 | an inconsistent state by unexpectedly moving point. | ||
| 3196 | |||
| 3197 | Mouse events are ignored so that mouse selection is unimpeded. | ||
| 3198 | |||
| 3199 | Only acts when the pre-command position of point was equal to the | ||
| 3200 | process mark, and the `term-char-mode-point-at-process-mark' | ||
| 3201 | option is enabled. See `term-set-goto-process-mark'." | ||
| 3202 | (when term-goto-process-mark | ||
| 3203 | (unless (mouse-event-p last-command-event) | ||
| 3204 | (goto-char (term-process-mark))))) | ||
| 3205 | |||
| 3206 | (defun term-process-mark () | ||
| 3207 | "The current `process-mark' for the term buffer process." | ||
| 3208 | (process-mark (get-buffer-process (current-buffer)))) | ||
| 3209 | |||
| 3112 | (defun term-handle-deferred-scroll () | 3210 | (defun term-handle-deferred-scroll () |
| 3113 | (let ((count (- (term-current-row) term-height))) | 3211 | (let ((count (- (term-current-row) term-height))) |
| 3114 | (when (>= count 0) | 3212 | (when (>= count 0) |