After delete, record point location in undo.
Addresses Bug #21968. * lisp/simple.el (undo-auto--add-boundary): Clean up code to better support intercalating calls. * src/keyboard.c,src/keyboard.h (command_loop_1): Store value of point and current buffer before each command. * src/undo.c (record_point): Now only record the point. * src/undo.c (prepare_record): Functionality removed form record_point. * src/undo.c (record_delete): Check if point needs recording. * src/undo.c (undo-boundary): Record value of point before each boundary. * test/automated/simple-test.el: New tests. Conflicts: src/undo.c
This commit is contained in:
parent
02cd9cb8af
commit
7592cb9d2a
5 changed files with 109 additions and 33 deletions
|
@ -2872,10 +2872,11 @@ See also `undo-auto--buffer-undoably-changed'.")
|
|||
(defun undo-auto--add-boundary ()
|
||||
"Add an `undo-boundary' in appropriate buffers."
|
||||
(undo-auto--boundaries
|
||||
(if undo-auto--this-command-amalgamating
|
||||
'amalgamate
|
||||
'command))
|
||||
(setq undo-auto--this-command-amalgamating nil))
|
||||
(let ((amal undo-auto--this-command-amalgamating))
|
||||
(setq undo-auto--this-command-amalgamating nil)
|
||||
(if amal
|
||||
'amalgamate
|
||||
'command))))
|
||||
|
||||
(defun undo-auto--amalgamate ()
|
||||
"Amalgamate undo if necessary.
|
||||
|
|
|
@ -202,7 +202,7 @@ uintmax_t num_input_events;
|
|||
|
||||
static EMACS_INT last_auto_save;
|
||||
|
||||
/* The value of point when the last command was started. */
|
||||
/* The value of point when the last command was started. */
|
||||
static ptrdiff_t last_point_position;
|
||||
|
||||
/* The frame in which the last input event occurred, or Qmacro if the
|
||||
|
@ -1449,6 +1449,11 @@ command_loop_1 (void)
|
|||
result of changes from the last command. */
|
||||
call0 (Qundo_auto__add_boundary);
|
||||
|
||||
/* Record point and buffer, so we can put point into the undo
|
||||
information if necessary. */
|
||||
point_before_last_command_or_undo = PT;
|
||||
buffer_before_last_command_or_undo = current_buffer;
|
||||
|
||||
call1 (Qcommand_execute, Vthis_command);
|
||||
|
||||
#ifdef HAVE_WINDOW_SYSTEM
|
||||
|
|
|
@ -245,6 +245,19 @@ extern KBOARD *current_kboard;
|
|||
/* Total number of times read_char has returned, modulo UINTMAX_MAX + 1. */
|
||||
extern uintmax_t num_input_events;
|
||||
|
||||
|
||||
/* The location of point immediately before the last command was
|
||||
executed, or the last time the undo-boundary command added a
|
||||
boundary.*/
|
||||
ptrdiff_t point_before_last_command_or_undo;
|
||||
|
||||
/* The value of current_buffer immediately before the last command was
|
||||
executed, or the last time the undo-boundary command added a
|
||||
boundary.*/
|
||||
struct buffer *buffer_before_last_command_or_undo;
|
||||
|
||||
extern struct buffer *prev_buffer;
|
||||
|
||||
/* Nonzero means polling for input is temporarily suppressed. */
|
||||
extern int poll_suppress_count;
|
||||
|
||||
|
|
65
src/undo.c
65
src/undo.c
|
@ -22,10 +22,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
|
|||
|
||||
#include "lisp.h"
|
||||
#include "buffer.h"
|
||||
|
||||
/* Position of point last time we inserted a boundary. */
|
||||
static struct buffer *last_boundary_buffer;
|
||||
static ptrdiff_t last_boundary_position;
|
||||
#include "keyboard.h"
|
||||
|
||||
/* The first time a command records something for undo.
|
||||
it also allocates the undo-boundary object
|
||||
|
@ -36,36 +33,44 @@ static Lisp_Object pending_boundary;
|
|||
|
||||
/* Record point as it was at beginning of this command (if necessary)
|
||||
and prepare the undo info for recording a change.
|
||||
PT is the position of point that will naturally occur as a result of the
|
||||
undo record that will be added just after this command terminates. */
|
||||
|
||||
/* Prepare the undo info for recording a change. */
|
||||
static void
|
||||
record_point (ptrdiff_t pt)
|
||||
prepare_record ()
|
||||
{
|
||||
bool at_boundary;
|
||||
|
||||
/* Don't record position of pt when undo_inhibit_record_point holds. */
|
||||
if (undo_inhibit_record_point)
|
||||
return;
|
||||
|
||||
/* Allocate a cons cell to be the undo boundary after this command. */
|
||||
if (NILP (pending_boundary))
|
||||
pending_boundary = Fcons (Qnil, Qnil);
|
||||
|
||||
at_boundary = ! CONSP (BVAR (current_buffer, undo_list))
|
||||
|| NILP (XCAR (BVAR (current_buffer, undo_list)));
|
||||
run_undoable_change ();
|
||||
|
||||
if (MODIFF <= SAVE_MODIFF)
|
||||
record_first_change ();
|
||||
}
|
||||
|
||||
/* Record point as it was at beginning of this command.
|
||||
PT is the position of point that will naturally occur as a result of the
|
||||
undo record that will be added just after this command terminates. */
|
||||
static void
|
||||
record_point (ptrdiff_t pt)
|
||||
{
|
||||
/* Don't record position of pt when undo_inhibit_record_point holds. */
|
||||
if (undo_inhibit_record_point)
|
||||
return;
|
||||
|
||||
bool at_boundary;
|
||||
|
||||
at_boundary = ! CONSP (BVAR (current_buffer, undo_list))
|
||||
|| NILP (XCAR (BVAR (current_buffer, undo_list)));
|
||||
|
||||
prepare_record();
|
||||
|
||||
/* If we are just after an undo boundary, and
|
||||
point wasn't at start of deleted range, record where it was. */
|
||||
if (at_boundary
|
||||
&& current_buffer == last_boundary_buffer
|
||||
&& last_boundary_position != pt)
|
||||
if (at_boundary){
|
||||
bset_undo_list (current_buffer,
|
||||
Fcons (make_number (last_boundary_position),
|
||||
Fcons (make_number (pt),
|
||||
BVAR (current_buffer, undo_list)));
|
||||
}
|
||||
}
|
||||
|
||||
/* Record an insertion that just happened or is about to happen,
|
||||
|
@ -81,7 +86,7 @@ record_insert (ptrdiff_t beg, ptrdiff_t length)
|
|||
if (EQ (BVAR (current_buffer, undo_list), Qt))
|
||||
return;
|
||||
|
||||
record_point (beg);
|
||||
prepare_record ();
|
||||
|
||||
/* If this is following another insertion and consecutive with it
|
||||
in the buffer, combine the two. */
|
||||
|
@ -153,7 +158,6 @@ record_marker_adjustments (ptrdiff_t from, ptrdiff_t to)
|
|||
/* Record that a deletion is about to take place, of the characters in
|
||||
STRING, at location BEG. Optionally record adjustments for markers
|
||||
in the region STRING occupies in the current buffer. */
|
||||
|
||||
void
|
||||
record_delete (ptrdiff_t beg, Lisp_Object string, bool record_markers)
|
||||
{
|
||||
|
@ -162,15 +166,21 @@ record_delete (ptrdiff_t beg, Lisp_Object string, bool record_markers)
|
|||
if (EQ (BVAR (current_buffer, undo_list), Qt))
|
||||
return;
|
||||
|
||||
if (point_before_last_command_or_undo != beg &&
|
||||
buffer_before_last_command_or_undo == current_buffer)
|
||||
{
|
||||
record_point (point_before_last_command_or_undo);
|
||||
}
|
||||
|
||||
if (PT == beg + SCHARS (string))
|
||||
{
|
||||
XSETINT (sbeg, -beg);
|
||||
record_point (PT);
|
||||
prepare_record ();
|
||||
}
|
||||
else
|
||||
{
|
||||
XSETFASTINT (sbeg, beg);
|
||||
record_point (beg);
|
||||
prepare_record ();
|
||||
}
|
||||
|
||||
/* primitive-undo assumes marker adjustments are recorded
|
||||
|
@ -268,10 +278,11 @@ but another undo command will undo to the previous boundary. */)
|
|||
bset_undo_list (current_buffer,
|
||||
Fcons (Qnil, BVAR (current_buffer, undo_list)));
|
||||
}
|
||||
last_boundary_position = PT;
|
||||
last_boundary_buffer = current_buffer;
|
||||
|
||||
Fset (Qundo_auto__last_boundary_cause, Qexplicit);
|
||||
point_before_last_command_or_undo = PT;
|
||||
buffer_before_last_command_or_undo = current_buffer;
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
|
@ -423,8 +434,6 @@ syms_of_undo (void)
|
|||
pending_boundary = Qnil;
|
||||
staticpro (&pending_boundary);
|
||||
|
||||
last_boundary_buffer = NULL;
|
||||
|
||||
defsubr (&Sundo_boundary);
|
||||
|
||||
DEFVAR_INT ("undo-limit", undo_limit,
|
||||
|
|
|
@ -263,5 +263,53 @@
|
|||
'("(s1) (s4)" . " (s2) (s3) (s5)"))))
|
||||
|
||||
|
||||
;; Test for a regression introduced by undo-auto--boundaries changes.
|
||||
;; https://lists.gnu.org/archive/html/emacs-devel/2015-11/msg01652.html
|
||||
(defun undo-test-kill-c-a-then-undo ()
|
||||
(with-temp-buffer
|
||||
(switch-to-buffer (current-buffer))
|
||||
(setq buffer-undo-list nil)
|
||||
(insert "a\nb\n\c\n")
|
||||
(goto-char (point-max))
|
||||
;; We use a keyboard macro because it adds undo events in the same
|
||||
;; way as if a user were involved.
|
||||
(kmacro-call-macro nil nil nil
|
||||
[left
|
||||
;; Delete "c"
|
||||
backspace
|
||||
left left left
|
||||
;; Delete "a"
|
||||
backspace
|
||||
;; C-/ or undo
|
||||
67108911
|
||||
])
|
||||
(point)))
|
||||
|
||||
(defun undo-test-point-after-forward-kill ()
|
||||
(with-temp-buffer
|
||||
(switch-to-buffer (current-buffer))
|
||||
(setq buffer-undo-list nil)
|
||||
(insert "kill word forward")
|
||||
;; Move to word "word".
|
||||
(goto-char 6)
|
||||
(kmacro-call-macro nil nil nil
|
||||
[
|
||||
;; kill-word
|
||||
C-delete
|
||||
;; undo
|
||||
67108911
|
||||
])
|
||||
(point)))
|
||||
|
||||
(ert-deftest undo-point-in-wrong-place ()
|
||||
(should
|
||||
;; returns 5 with the bug
|
||||
(= 2
|
||||
(undo-test-kill-c-a-then-undo)))
|
||||
(should
|
||||
(= 6
|
||||
(undo-test-point-after-forward-kill))))
|
||||
|
||||
|
||||
(provide 'simple-test)
|
||||
;;; simple-test.el ends here
|
||||
|
|
Loading…
Add table
Reference in a new issue