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:
Phillip Lord 2015-11-19 15:57:55 +00:00
parent 02cd9cb8af
commit 7592cb9d2a
5 changed files with 109 additions and 33 deletions

View file

@ -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.

View file

@ -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

View file

@ -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;

View file

@ -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,

View file

@ -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