From: Po Lu Date: Fri, 3 Nov 2023 03:32:17 +0000 (+0800) Subject: Avoid moving point while analyzing text conversion X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=e06e61f45615f66d5e32fa23ea7ede7c4da77fda;p=emacs.git Avoid moving point while analyzing text conversion * lisp/simple.el (analyze-text-conversion): If neither calling p-s-i-h nor calling p-t-c-h yields a change to point, return it to its location before analyze-text-conversion was called. * src/keyboard.c (kbd_buffer_get_event): See that text conversion events are uniformly delivered prior to keyboard events arriving in unison. --- diff --git a/lisp/simple.el b/lisp/simple.el index 30208debc2a..96cdedb4f38 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -11169,7 +11169,12 @@ place. If undo information is being recorded, make sure `undo-auto-current-boundary-timer' will run within the next 5 seconds." (interactive) - (let ((any-nonephemeral nil)) + ;; One important consideration to bear in mind when adjusting this + ;; code is to _never_ move point in reaction to an edit so long as + ;; the additional processing undertaken by this function does not + ;; also edit the buffer text. + (let ((any-nonephemeral nil) + point-moved) ;; The list must be processed in reverse. (dolist (edit (reverse text-conversion-edits)) ;; Filter out ephemeral edits and deletions after point. Here, we @@ -11177,6 +11182,9 @@ seconds." ;; can be identified. (when (stringp (nth 3 edit)) (with-current-buffer (car edit) + ;; Record that the point hasn't been moved by the execution + ;; of a post command or text conversion hook. + (setq point-moved nil) (if (not (eq (nth 1 edit) (nth 2 edit))) ;; Process this insertion. (nth 3 edit) is the text which ;; was inserted. @@ -11192,7 +11200,8 @@ seconds." ;; Save the current undo list to figure out ;; whether or not auto-fill has actually taken ;; place. - (old-undo-list buffer-undo-list)) + (old-undo-list buffer-undo-list) + (old-point (point))) (save-excursion (if (and auto-fill-function newline-p) (progn (goto-char (nth 2 edit)) @@ -11211,10 +11220,22 @@ seconds." (not (eq old-undo-list buffer-undo-list))))) (goto-char (nth 2 edit)) - (let ((last-command-event end)) + (let ((last-command-event end) + (point (point))) (unless (run-hook-with-args-until-success 'post-text-conversion-hook) - (run-hooks 'post-self-insert-hook)))) + (run-hooks 'post-self-insert-hook)) + (when (not (eq (point) point)) + (setq point-moved t))) + ;; If post-self-insert-hook doesn't move the point, + ;; restore it to its previous location. Generally, + ;; the call to goto-char upon processing the last edit + ;; recorded text-conversion-edit will see to this, but + ;; if the input method sets point expressly, no edit + ;; will be recorded, and point will wind up away from + ;; where the input method believes it is. + (unless point-moved + (goto-char old-point))) ;; Process this deletion before point. (nth 2 edit) is the ;; text which was deleted. Input methods typically prefer ;; to edit words instead of deleting characters off their diff --git a/src/keyboard.c b/src/keyboard.c index 003340c3e58..13cb7835dff 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -3993,6 +3993,19 @@ kbd_buffer_get_event (KBOARD **kbp, if (CONSP (Vunread_command_events)) break; +#ifdef HAVE_TEXT_CONVERSION + /* That text conversion events take priority over keyboard + events, since input methods frequently send them immediately + after edits, with the assumption that this order of events + will be observed. */ + + if (detect_conversion_events ()) + { + had_pending_conversion_events = true; + break; + } +#endif /* HAVE_TEXT_CONVERSION */ + if (kbd_fetch_ptr != kbd_store_ptr) break; if (some_mouse_moved ()) @@ -4020,13 +4033,6 @@ kbd_buffer_get_event (KBOARD **kbp, had_pending_selection_requests = true; break; } -#endif -#ifdef HAVE_TEXT_CONVERSION - if (detect_conversion_events ()) - { - had_pending_conversion_events = true; - break; - } #endif if (end_time) {