mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2025-01-28 19:42:02 +00:00
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.
This commit is contained in:
parent
79d57f4b7a
commit
0d8e4f45d6
17
etc/NEWS
17
etc/NEWS
@ -1168,6 +1168,23 @@ provided.
|
||||
The old Flymake behavior is preserved in the so-called "legacy
|
||||
backend", which has been updated to benefit from the new UI features.
|
||||
|
||||
** Term
|
||||
|
||||
---
|
||||
*** `term-char-mode' now makes its buffer read-only.
|
||||
|
||||
The buffer is made read-only to prevent changes from being made by
|
||||
anything other than the process filter; and movements of point away
|
||||
from the process mark are counter-acted so that the cursor is in the
|
||||
correct position after each command. This is needed to avoid states
|
||||
which are inconsistent with the state of the terminal understood by
|
||||
the inferior process.
|
||||
|
||||
New user options `term-char-mode-buffer-read-only' and
|
||||
`term-char-mode-point-at-process-mark' control these behaviors, and
|
||||
are non-nil by default. Customize these options to nil if you want
|
||||
the previous behavior.
|
||||
|
||||
|
||||
* New Modes and Packages in Emacs 26.1
|
||||
|
||||
|
98
lisp/term.el
98
lisp/term.el
@ -427,6 +427,8 @@ by moving term-home-marker. It is set to t if there is a
|
||||
(defvar term-old-mode-line-format) ; Saves old mode-line-format while paging.
|
||||
(defvar term-pager-old-local-map nil "Saves old keymap while paging.")
|
||||
(defvar term-pager-old-filter) ; Saved process-filter while paging.
|
||||
(defvar-local term-line-mode-buffer-read-only nil
|
||||
"The `buffer-read-only' state to set in `term-line-mode'.")
|
||||
|
||||
(defcustom explicit-shell-file-name nil
|
||||
"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."
|
||||
:type 'boolean
|
||||
:group 'term)
|
||||
|
||||
(defcustom term-char-mode-buffer-read-only t
|
||||
"If non-nil, only the process filter may modify the buffer in char mode.
|
||||
|
||||
A non-nil value makes the buffer read-only in `term-char-mode',
|
||||
which prevents editing commands from making the buffer state
|
||||
inconsistent with the state of the terminal understood by the
|
||||
inferior process. Only the process filter is allowed to make
|
||||
changes to the buffer.
|
||||
|
||||
Customize this option to nil if you want the previous behaviour."
|
||||
:version "26.1"
|
||||
:type 'boolean
|
||||
:group 'term)
|
||||
|
||||
(defcustom term-char-mode-point-at-process-mark t
|
||||
"If non-nil, keep point at the process mark in char mode.
|
||||
|
||||
A non-nil value causes point to be moved to the current process
|
||||
mark after each command in `term-char-mode' (provided that the
|
||||
pre-command point position was also at the process mark). This
|
||||
prevents commands that move point from making the buffer state
|
||||
inconsistent with the state of the terminal understood by the
|
||||
inferior process.
|
||||
|
||||
Mouse events are not affected, so moving point and selecting text
|
||||
is still possible in char mode via the mouse, after which other
|
||||
commands can be invoked on the mouse-selected point or region,
|
||||
until the process filter (or user) moves point to the process
|
||||
mark once again.
|
||||
|
||||
Customize this option to nil if you want the previous behaviour."
|
||||
:version "26.1"
|
||||
:type 'boolean
|
||||
:group 'term)
|
||||
|
||||
(defcustom term-scroll-to-bottom-on-output nil
|
||||
"Controls whether interpreter output causes window to scroll.
|
||||
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'."
|
||||
(term-reset-size (cdr size) (car size)))
|
||||
size))
|
||||
|
||||
(add-hook 'read-only-mode-hook #'term-line-mode-buffer-read-only-update nil t)
|
||||
|
||||
(easy-menu-add term-terminal-menu)
|
||||
(easy-menu-add term-signals-menu)
|
||||
(or term-input-ring
|
||||
@ -1246,6 +1285,13 @@ intervention from Emacs, except for the escape character (usually C-c)."
|
||||
(easy-menu-add term-terminal-menu)
|
||||
(easy-menu-add term-signals-menu)
|
||||
|
||||
;; Don't allow changes to the buffer or to point which are not
|
||||
;; caused by the process filter.
|
||||
(when term-char-mode-buffer-read-only
|
||||
(setq buffer-read-only t))
|
||||
(add-hook 'pre-command-hook #'term-set-goto-process-mark nil t)
|
||||
(add-hook 'post-command-hook #'term-goto-process-mark-maybe nil t)
|
||||
|
||||
;; Send existing partial line to inferior (without newline).
|
||||
(let ((pmark (process-mark (get-buffer-process (current-buffer))))
|
||||
(save-input-sender term-input-sender))
|
||||
@ -1265,9 +1311,20 @@ This means that Emacs editing commands work as normally, until
|
||||
you type \\[term-send-input] which sends the current line to the inferior."
|
||||
(interactive)
|
||||
(when (term-in-char-mode)
|
||||
(when term-char-mode-buffer-read-only
|
||||
(setq buffer-read-only term-line-mode-buffer-read-only))
|
||||
(remove-hook 'pre-command-hook #'term-set-goto-process-mark t)
|
||||
(remove-hook 'post-command-hook #'term-goto-process-mark-maybe t)
|
||||
(use-local-map term-old-mode-map)
|
||||
(term-update-mode-line)))
|
||||
|
||||
(defun term-line-mode-buffer-read-only-update ()
|
||||
"Update the user-set state of `buffer-read-only' in `term-line-mode'.
|
||||
|
||||
Called as a buffer-local `read-only-mode-hook' function."
|
||||
(when (term-in-line-mode)
|
||||
(setq term-line-mode-buffer-read-only buffer-read-only)))
|
||||
|
||||
(defun term-update-mode-line ()
|
||||
(let ((term-mode
|
||||
(if (term-in-char-mode)
|
||||
@ -2711,6 +2768,7 @@ See `term-prompt-regexp'."
|
||||
count-bytes ; number of bytes
|
||||
decoded-substring
|
||||
save-point save-marker old-point temp win
|
||||
(inhibit-read-only t)
|
||||
(buffer-undo-list t)
|
||||
(selected (selected-window))
|
||||
last-win
|
||||
@ -3109,6 +3167,46 @@ See `term-prompt-regexp'."
|
||||
(when (get-buffer-window (current-buffer))
|
||||
(redisplay))))
|
||||
|
||||
(defvar-local term-goto-process-mark t
|
||||
"Whether to reset point to the current process mark after this command.
|
||||
|
||||
Set in `pre-command-hook' in char mode by `term-set-goto-process-mark'.")
|
||||
|
||||
(defun term-set-goto-process-mark ()
|
||||
"Sets `term-goto-process-mark'.
|
||||
|
||||
Always set to nil if `term-char-mode-point-at-process-mark' is nil.
|
||||
|
||||
Called as a buffer-local `pre-command-hook' function in
|
||||
`term-char-mode' so that when point is equal to the process mark
|
||||
at the pre-command stage, we know to restore point to the process
|
||||
mark at the post-command stage.
|
||||
|
||||
See also `term-goto-process-mark-maybe'."
|
||||
(setq term-goto-process-mark
|
||||
(and term-char-mode-point-at-process-mark
|
||||
(eq (point) (marker-position (term-process-mark))))))
|
||||
|
||||
(defun term-goto-process-mark-maybe ()
|
||||
"Move point to the term buffer's process mark upon keyboard input.
|
||||
|
||||
Called as a buffer-local `post-command-hook' function in
|
||||
`term-char-mode' to prevent commands from putting the buffer into
|
||||
an inconsistent state by unexpectedly moving point.
|
||||
|
||||
Mouse events are ignored so that mouse selection is unimpeded.
|
||||
|
||||
Only acts when the pre-command position of point was equal to the
|
||||
process mark, and the `term-char-mode-point-at-process-mark'
|
||||
option is enabled. See `term-set-goto-process-mark'."
|
||||
(when term-goto-process-mark
|
||||
(unless (mouse-event-p last-command-event)
|
||||
(goto-char (term-process-mark)))))
|
||||
|
||||
(defun term-process-mark ()
|
||||
"The current `process-mark' for the term buffer process."
|
||||
(process-mark (get-buffer-process (current-buffer))))
|
||||
|
||||
(defun term-handle-deferred-scroll ()
|
||||
(let ((count (- (term-current-row) term-height)))
|
||||
(when (>= count 0)
|
||||
|
Loading…
Reference in New Issue
Block a user