unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Phil Sainty <psainty@orcon.net.nz>
To: Eli Zaretskii <eliz@gnu.org>
Cc: p.stephani2@gmail.com, 24837@debbugs.gnu.org,
	21609@debbugs.gnu.org,
	bug-gnu-emacs-bounces+psainty=orcon.net.nz@gnu.org
Subject: bug#21609: bug#24837: 26.0.50; term.el: In char mode, displayed and executed commands can differ
Date: Tue, 10 Oct 2017 03:04:24 +1300	[thread overview]
Message-ID: <33aed754-b4cf-a75d-837d-14ee596613b1@orcon.net.nz> (raw)
In-Reply-To: <fa207a80-eba1-280e-ad59-fb41d03e9e99@orcon.net.nz>

[-- Attachment #1: Type: text/plain, Size: 339 bytes --]

On 09/10/17 01:39, Phil Sainty wrote:
> I think the remaining task would be to add user options to disable
> the new behaviours, as some users might object to them?

This is now done, and rebased onto the emacs-26 branch.  The new user
options are enabled by default, and a NEWS entry added.  New patch is
attached; please review.


-Phil

[-- Attachment #2: 0001-Avoid-creating-inconsistent-buffer-states-in-term-ch.patch --]
[-- Type: text/x-patch, Size: 7949 bytes --]

From ecd56a565bd4260bcd88e63b0f99cd7eeec71714 Mon Sep 17 00:00:00 2001
From: Phil Sainty <psainty@orcon.net.nz>
Date: Sun, 3 Sep 2017 14:30:18 +1200
Subject: [PATCH] Avoid creating inconsistent buffer states in term-char-mode
 (bug#24837)

* 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'.

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 user options.
---
 etc/NEWS     | 12 ++++++++
 lisp/term.el | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+)

diff --git a/etc/NEWS b/etc/NEWS
index a9a4bc6..2149829 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1148,6 +1148,18 @@ languages.  (Version 2.1.0 or later of Enchant is required.)
 +++
 *** Emacs no longer prompts the user before killing Flymake processes on exit.
 
+** Term
+
++++
+*** New user options `term-char-mode-buffer-read-only' and
+`term-char-mode-point-at-process-mark' are enabled by default to avoid
+buffer states being created in `term-char-mode' which are inconsistent
+with the terminal state expected by the inferior process.
+
+Respectively, these options prevent buffer changes which are not
+caused by the process filter, and counter-act movements of point away
+from the process mark (with the exception of mouse events).
+
 \f
 * New Modes and Packages in Emacs 26.1
 
diff --git a/lisp/term.el b/lisp/term.el
index c748c45..ffd0e92 100644
--- a/lisp/term.el
+++ b/lisp/term.el
@@ -427,6 +427,8 @@ term-old-mode-map
 (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,36 @@ term-input-ring-file-name
   :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.
+
+This makes the buffer read-only in char mode (except for the
+process filter), to prevent editing commands from causing a
+buffer state which is inconsistent with the state understood by
+the inferior process."
+  :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.
+
+This prevents commands that move point from causing a buffer
+state which is inconsistent with the state understood by the
+inferior process.
+
+Takes effect during `post-command-hook', provided that the
+pre-command point position was also at the process mark.
+
+Mouse selection and other mouse events are ignored, so moving
+point is still possible in char mode via the mouse, and other
+commands can then be invoked at the mouse-selected point or
+region, until the process filter (or user) moves point to the
+process mark once again.
+
+This option has no effect in line mode."
+  :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 +1137,8 @@ term-mode
                     (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 +1280,13 @@ term-char-mode
     (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 +1306,20 @@ term-line-mode
 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 +2763,7 @@ term-emulate-terminal
 	   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 +3162,46 @@ term-emulate-terminal
     (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)
-- 
2.8.3


  reply	other threads:[~2017-10-09 14:04 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-10-31 14:10 bug#24837: 26.0.50; term.el: In char mode, displayed and executed commands can differ Philipp Stephani
2016-10-31 20:46 ` Phil Sainty
2016-11-23 19:44   ` Philipp Stephani
2016-11-23 20:08     ` bug#21609: " Phil Sainty
2016-11-23 20:21       ` Philipp Stephani
2017-09-02 14:14         ` Eli Zaretskii
2017-09-03  2:58           ` Phil Sainty
2017-09-03  3:09             ` bug#21609: " Phil Sainty
2017-09-04  9:55             ` Phil Sainty
2017-09-04 10:10               ` bug#24837: " Phil Sainty
2017-09-04 11:59                 ` bug#21609: " Phil Sainty
2017-09-24 10:59             ` Philipp Stephani
2017-09-25  0:48               ` bug#21609: " Phil Sainty
2017-09-25  3:09                 ` Phil Sainty
2017-09-29  8:37                   ` Eli Zaretskii
2017-10-08 12:39                     ` bug#21609: " Phil Sainty
2017-10-09 14:04                       ` Phil Sainty [this message]
2017-10-09 15:32                         ` Eli Zaretskii
2017-10-10 10:16                           ` bug#28777: Clarifying the temporary documentation update marks in etc/NEWS Phil Sainty
2017-10-10 12:25                             ` Eli Zaretskii
2017-10-10 11:11                           ` bug#24837: bug#21609: bug#24837: 26.0.50; term.el: In char mode, displayed and executed commands can differ Phil Sainty
2017-10-10 12:35                             ` Eli Zaretskii
2017-10-12 10:54                               ` Phil Sainty
2017-10-12 12:04                                 ` bug#21609: " Eli Zaretskii
2017-10-21  8:20                                 ` Eli Zaretskii

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=33aed754-b4cf-a75d-837d-14ee596613b1@orcon.net.nz \
    --to=psainty@orcon.net.nz \
    --cc=21609@debbugs.gnu.org \
    --cc=24837@debbugs.gnu.org \
    --cc=bug-gnu-emacs-bounces+psainty=orcon.net.nz@gnu.org \
    --cc=eliz@gnu.org \
    --cc=p.stephani2@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).