aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhil Sainty2017-10-21 11:17:56 +0300
committerEli Zaretskii2017-10-21 11:17:56 +0300
commit0d8e4f45d612ecd77f4997fae30e4d1591f9b8a6 (patch)
tree72c3d41f678300c07d799d7942ca6b2d8cce6d9d
parent79d57f4b7a8dc0d0cd213ce5989886cc9fc9b7f3 (diff)
downloademacs-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/NEWS17
-rw-r--r--lisp/term.el98
2 files changed, 115 insertions, 0 deletions
diff --git a/etc/NEWS b/etc/NEWS
index c5c76477b4f..82778932ab1 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1168,6 +1168,23 @@ provided.
1168The old Flymake behavior is preserved in the so-called "legacy 1168The old Flymake behavior is preserved in the so-called "legacy
1169backend", which has been updated to benefit from the new UI features. 1169backend", 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
1176The buffer is made read-only to prevent changes from being made by
1177anything other than the process filter; and movements of point away
1178from the process mark are counter-acted so that the cursor is in the
1179correct position after each command. This is needed to avoid states
1180which are inconsistent with the state of the terminal understood by
1181the inferior process.
1182
1183New user options `term-char-mode-buffer-read-only' and
1184`term-char-mode-point-at-process-mark' control these behaviors, and
1185are non-nil by default. Customize these options to nil if you want
1186the 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
495A non-nil value makes the buffer read-only in `term-char-mode',
496which prevents editing commands from making the buffer state
497inconsistent with the state of the terminal understood by the
498inferior process. Only the process filter is allowed to make
499changes to the buffer.
500
501Customize 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
509A non-nil value causes point to be moved to the current process
510mark after each command in `term-char-mode' (provided that the
511pre-command point position was also at the process mark). This
512prevents commands that move point from making the buffer state
513inconsistent with the state of the terminal understood by the
514inferior process.
515
516Mouse events are not affected, so moving point and selecting text
517is still possible in char mode via the mouse, after which other
518commands can be invoked on the mouse-selected point or region,
519until the process filter (or user) moves point to the process
520mark once again.
521
522Customize 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.
492If nil, then do not scroll. If t or `all', scroll all windows showing buffer. 529If 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
1265you type \\[term-send-input] which sends the current line to the inferior." 1311you 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
1324Called 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
3173Set 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
3178Always set to nil if `term-char-mode-point-at-process-mark' is nil.
3179
3180Called as a buffer-local `pre-command-hook' function in
3181`term-char-mode' so that when point is equal to the process mark
3182at the pre-command stage, we know to restore point to the process
3183mark at the post-command stage.
3184
3185See 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
3193Called as a buffer-local `post-command-hook' function in
3194`term-char-mode' to prevent commands from putting the buffer into
3195an inconsistent state by unexpectedly moving point.
3196
3197Mouse events are ignored so that mouse selection is unimpeded.
3198
3199Only acts when the pre-command position of point was equal to the
3200process mark, and the `term-char-mode-point-at-process-mark'
3201option 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)