aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhillip Lord2015-11-12 22:01:22 +0000
committerPhillip Lord2015-11-12 22:01:22 +0000
commit20aa42e8204f8f0139ba3880cb32ddf88acc9bf4 (patch)
treef77644c920b0f6a5a2f5849a064c6828c17530b1
parentd2f73db50bec29724cb1324910350ad24420b174 (diff)
parent44dfa86b7d382b84564d68472da1448d08f48129 (diff)
downloademacs-20aa42e8204f8f0139ba3880cb32ddf88acc9bf4.tar.gz
emacs-20aa42e8204f8f0139ba3880cb32ddf88acc9bf4.zip
; Merge branch 'fix/no-undo-boundary-on-secondary-buffer-change'
Conflicts: src/cmds.c src/keyboard.c
-rw-r--r--lisp/simple.el137
-rw-r--r--src/cmds.c56
-rw-r--r--src/keyboard.c16
-rw-r--r--src/lisp.h1
-rw-r--r--src/undo.c51
5 files changed, 174 insertions, 87 deletions
diff --git a/lisp/simple.el b/lisp/simple.el
index 1f2f4fe0444..2781ad02b97 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -2768,6 +2768,143 @@ with < or <= based on USE-<."
2768 '(0 . 0))) 2768 '(0 . 0)))
2769 '(0 . 0))) 2769 '(0 . 0)))
2770 2770
2771;;; Default undo-boundary addition
2772;;
2773;; This section adds a new undo-boundary at either after a command is
2774;; called or in some cases on a timer called after a change is made in
2775;; any buffer.
2776(defvar-local undo-auto--last-boundary-cause nil
2777 "Describe the cause of the last undo-boundary.
2778
2779If `explicit', the last boundary was caused by an explicit call to
2780`undo-boundary', that is one not called by the code in this
2781section.
2782
2783If it is equal to `timer', then the last boundary was inserted
2784by `undo-auto--boundary-timer'.
2785
2786If it is equal to `command', then the last boundary was inserted
2787automatically after a command, that is by the code defined in
2788this section.
2789
2790If it is equal to a list, then the last boundary was inserted by
2791an amalgamating command. The car of the list is the number of
2792times an amalgamating command has been called, and the cdr are the
2793buffers that were changed during the last command.")
2794
2795(defvar undo-auto--current-boundary-timer nil
2796 "Current timer which will run `undo-auto--boundary-timer' or nil.
2797
2798If set to non-nil, this will effectively disable the timer.")
2799
2800(defvar undo-auto--this-command-amalgamating nil
2801 "Non-nil if `this-command' should be amalgamated.
2802This variable is set to nil by `undo-auto--boundaries' and is set
2803by `undo-auto--amalgamate'." )
2804
2805(defun undo-auto--needs-boundary-p ()
2806 "Return non-nil if `buffer-undo-list' needs a boundary at the start."
2807 (car-safe buffer-undo-list))
2808
2809(defun undo-auto--last-boundary-amalgamating-number ()
2810 "Return the number of amalgamating last commands or nil.
2811Amalgamating commands are, by default, either
2812`self-insert-command' and `delete-char', but can be any command
2813that calls `undo-auto--amalgamate'."
2814 (car-safe undo-auto--last-boundary-cause))
2815
2816(defun undo-auto--ensure-boundary (cause)
2817 "Add an `undo-boundary' to the current buffer if needed.
2818REASON describes the reason that the boundary is being added; see
2819`undo-auto--last-boundary' for more information."
2820 (when (and
2821 (undo-auto--needs-boundary-p))
2822 (let ((last-amalgamating
2823 (undo-auto--last-boundary-amalgamating-number)))
2824 (undo-boundary)
2825 (setq undo-auto--last-boundary-cause
2826 (if (eq 'amalgamate cause)
2827 (cons
2828 (if last-amalgamating (1+ last-amalgamating) 0)
2829 undo-auto--undoably-changed-buffers)
2830 cause)))))
2831
2832(defun undo-auto--boundaries (cause)
2833 "Check recently changed buffers and add a boundary if necessary.
2834REASON describes the reason that the boundary is being added; see
2835`undo-last-boundary' for more information."
2836 (dolist (b undo-auto--undoably-changed-buffers)
2837 (when (buffer-live-p b)
2838 (with-current-buffer b
2839 (undo-auto--ensure-boundary cause))))
2840 (setq undo-auto--undoably-changed-buffers nil))
2841
2842(defun undo-auto--boundary-timer ()
2843 "Timer which will run `undo--auto-boundary-timer'."
2844 (setq undo-auto--current-boundary-timer nil)
2845 (undo-auto--boundaries 'timer))
2846
2847(defun undo-auto--boundary-ensure-timer ()
2848 "Ensure that the `undo-auto-boundary-timer' is set."
2849 (unless undo-auto--current-boundary-timer
2850 (setq undo-auto--current-boundary-timer
2851 (run-at-time 10 nil #'undo-auto--boundary-timer))))
2852
2853(defvar undo-auto--undoably-changed-buffers nil
2854 "List of buffers that have changed recently.
2855
2856This list is maintained by `undo-auto--undoable-change' and
2857`undo-auto--boundaries' and can be affected by changes to their
2858default values.
2859
2860See also `undo-auto--buffer-undoably-changed'.")
2861
2862(defun undo-auto--add-boundary ()
2863 "Add an `undo-boundary' in appropriate buffers."
2864 (undo-auto--boundaries
2865 (if undo-auto--this-command-amalgamating
2866 'amalgamate
2867 'command))
2868 (setq undo-auto--this-command-amalgamating nil))
2869
2870(defun undo-auto--amalgamate ()
2871 "Amalgamate undo if necessary.
2872This function can be called after an amalgamating command. It
2873removes the previous `undo-boundary' if a series of such calls
2874have been made. By default `self-insert-command' and
2875`delete-char' are the only amalgamating commands, although this
2876function could be called by any command wishing to have this
2877behaviour."
2878 (let ((last-amalgamating-count
2879 (undo-auto--last-boundary-amalgamating-number)))
2880 (setq undo-auto--this-command-amalgamating t)
2881 (when
2882 last-amalgamating-count
2883 (if
2884 (and
2885 (< last-amalgamating-count 20)
2886 (eq this-command last-command))
2887 ;; Amalgamate all buffers that have changed.
2888 (dolist (b (cdr undo-auto--last-boundary-cause))
2889 (when (buffer-live-p b)
2890 (with-current-buffer
2891 b
2892 (when
2893 ;; The head of `buffer-undo-list' is nil.
2894 ;; `car-safe' doesn't work because
2895 ;; `buffer-undo-list' need not be a list!
2896 (and (listp buffer-undo-list)
2897 (not (car buffer-undo-list)))
2898 (setq buffer-undo-list
2899 (cdr buffer-undo-list))))))
2900 (setq undo-auto--last-boundary-cause 0)))))
2901
2902(defun undo-auto--undoable-change ()
2903 "Called after every undoable buffer change."
2904 (add-to-list 'undo-auto--undoably-changed-buffers (current-buffer))
2905 (undo-auto--boundary-ensure-timer))
2906;; End auto-boundary section
2907
2771(defcustom undo-ask-before-discard nil 2908(defcustom undo-ask-before-discard nil
2772 "If non-nil ask about discarding undo info for the current command. 2909 "If non-nil ask about discarding undo info for the current command.
2773Normally, Emacs discards the undo info for the current command if 2910Normally, Emacs discards the undo info for the current command if
diff --git a/src/cmds.c b/src/cmds.c
index 0afc023e681..167ebb74302 100644
--- a/src/cmds.c
+++ b/src/cmds.c
@@ -218,36 +218,6 @@ to t. */)
218 return Qnil; 218 return Qnil;
219} 219}
220 220
221static int nonundocount;
222
223static void
224remove_excessive_undo_boundaries (void)
225{
226 bool remove_boundary = true;
227
228 if (!EQ (Vthis_command, KVAR (current_kboard, Vlast_command)))
229 nonundocount = 0;
230
231 if (NILP (Vexecuting_kbd_macro))
232 {
233 if (nonundocount <= 0 || nonundocount >= 20)
234 {
235 remove_boundary = false;
236 nonundocount = 0;
237 }
238 nonundocount++;
239 }
240
241 if (remove_boundary
242 && CONSP (BVAR (current_buffer, undo_list))
243 && NILP (XCAR (BVAR (current_buffer, undo_list)))
244 /* Only remove auto-added boundaries, not boundaries
245 added by explicit calls to undo-boundary. */
246 && EQ (BVAR (current_buffer, undo_list), last_undo_boundary))
247 /* Remove the undo_boundary that was just pushed. */
248 bset_undo_list (current_buffer, XCDR (BVAR (current_buffer, undo_list)));
249}
250
251DEFUN ("delete-char", Fdelete_char, Sdelete_char, 1, 2, "p\nP", 221DEFUN ("delete-char", Fdelete_char, Sdelete_char, 1, 2, "p\nP",
252 doc: /* Delete the following N characters (previous if N is negative). 222 doc: /* Delete the following N characters (previous if N is negative).
253Optional second arg KILLFLAG non-nil means kill instead (save in kill ring). 223Optional second arg KILLFLAG non-nil means kill instead (save in kill ring).
@@ -263,7 +233,7 @@ because it respects values of `delete-active-region' and `overwrite-mode'. */)
263 CHECK_NUMBER (n); 233 CHECK_NUMBER (n);
264 234
265 if (eabs (XINT (n)) < 2) 235 if (eabs (XINT (n)) < 2)
266 remove_excessive_undo_boundaries (); 236 call0 (Qundo_auto__amalgamate);
267 237
268 pos = PT + XINT (n); 238 pos = PT + XINT (n);
269 if (NILP (killflag)) 239 if (NILP (killflag))
@@ -309,20 +279,19 @@ At the end, it runs `post-self-insert-hook'. */)
309 error ("Negative repetition argument %"pI"d", XINT (n)); 279 error ("Negative repetition argument %"pI"d", XINT (n));
310 280
311 if (XFASTINT (n) < 2) 281 if (XFASTINT (n) < 2)
312 remove_excessive_undo_boundaries (); 282 call0 (Qundo_auto__amalgamate);
313 283
314 /* Barf if the key that invoked this was not a character. */ 284 /* Barf if the key that invoked this was not a character. */
315 if (!CHARACTERP (last_command_event)) 285 if (!CHARACTERP (last_command_event))
316 bitch_at_user (); 286 bitch_at_user ();
317 else 287 else {
318 { 288 int character = translate_char (Vtranslation_table_for_input,
319 int character = translate_char (Vtranslation_table_for_input, 289 XINT (last_command_event));
320 XINT (last_command_event)); 290 int val = internal_self_insert (character, XFASTINT (n));
321 int val = internal_self_insert (character, XFASTINT (n)); 291 if (val == 2)
322 if (val == 2) 292 Fset (Qundo_auto__this_command_amalgamating, Qnil);
323 nonundocount = 0; 293 frame_make_pointer_invisible (SELECTED_FRAME ());
324 frame_make_pointer_invisible (SELECTED_FRAME ()); 294 }
325 }
326 295
327 return Qnil; 296 return Qnil;
328} 297}
@@ -525,6 +494,10 @@ internal_self_insert (int c, EMACS_INT n)
525void 494void
526syms_of_cmds (void) 495syms_of_cmds (void)
527{ 496{
497 DEFSYM (Qundo_auto__amalgamate, "undo-auto--amalgamate");
498 DEFSYM (Qundo_auto__this_command_amalgamating,
499 "undo-auto--this-command-amalgamating");
500
528 DEFSYM (Qkill_forward_chars, "kill-forward-chars"); 501 DEFSYM (Qkill_forward_chars, "kill-forward-chars");
529 502
530 /* A possible value for a buffer's overwrite-mode variable. */ 503 /* A possible value for a buffer's overwrite-mode variable. */
@@ -554,7 +527,6 @@ keys_of_cmds (void)
554{ 527{
555 int n; 528 int n;
556 529
557 nonundocount = 0;
558 initial_define_key (global_map, Ctl ('I'), "self-insert-command"); 530 initial_define_key (global_map, Ctl ('I'), "self-insert-command");
559 for (n = 040; n < 0177; n++) 531 for (n = 040; n < 0177; n++)
560 initial_define_key (global_map, n, "self-insert-command"); 532 initial_define_key (global_map, n, "self-insert-command");
diff --git a/src/keyboard.c b/src/keyboard.c
index 851207874db..2449abb7dfc 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -1230,9 +1230,6 @@ static int read_key_sequence (Lisp_Object *, int, Lisp_Object,
1230 bool, bool, bool, bool); 1230 bool, bool, bool, bool);
1231static void adjust_point_for_property (ptrdiff_t, bool); 1231static void adjust_point_for_property (ptrdiff_t, bool);
1232 1232
1233/* The last boundary auto-added to buffer-undo-list. */
1234Lisp_Object last_undo_boundary;
1235
1236Lisp_Object 1233Lisp_Object
1237command_loop_1 (void) 1234command_loop_1 (void)
1238{ 1235{
@@ -1448,13 +1445,10 @@ command_loop_1 (void)
1448 } 1445 }
1449#endif 1446#endif
1450 1447
1451 { 1448 /* Ensure that we have added appropriate undo-boundaries as a
1452 Lisp_Object undo = BVAR (current_buffer, undo_list); 1449 result of changes from the last command. */
1453 Fundo_boundary (); 1450 call0 (Qundo_auto__add_boundary);
1454 last_undo_boundary 1451
1455 = (EQ (undo, BVAR (current_buffer, undo_list))
1456 ? Qnil : BVAR (current_buffer, undo_list));
1457 }
1458 call1 (Qcommand_execute, Vthis_command); 1452 call1 (Qcommand_execute, Vthis_command);
1459 1453
1460#ifdef HAVE_WINDOW_SYSTEM 1454#ifdef HAVE_WINDOW_SYSTEM
@@ -10909,6 +10903,8 @@ syms_of_keyboard (void)
10909 DEFSYM (Qpre_command_hook, "pre-command-hook"); 10903 DEFSYM (Qpre_command_hook, "pre-command-hook");
10910 DEFSYM (Qpost_command_hook, "post-command-hook"); 10904 DEFSYM (Qpost_command_hook, "post-command-hook");
10911 10905
10906 DEFSYM (Qundo_auto__add_boundary, "undo-auto--add-boundary");
10907
10912 DEFSYM (Qdeferred_action_function, "deferred-action-function"); 10908 DEFSYM (Qdeferred_action_function, "deferred-action-function");
10913 DEFSYM (Qdelayed_warnings_hook, "delayed-warnings-hook"); 10909 DEFSYM (Qdelayed_warnings_hook, "delayed-warnings-hook");
10914 DEFSYM (Qfunction_key, "function-key"); 10910 DEFSYM (Qfunction_key, "function-key");
diff --git a/src/lisp.h b/src/lisp.h
index c782f0dd003..3efa492e0e8 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4008,7 +4008,6 @@ extern void syms_of_casetab (void);
4008extern Lisp_Object echo_message_buffer; 4008extern Lisp_Object echo_message_buffer;
4009extern struct kboard *echo_kboard; 4009extern struct kboard *echo_kboard;
4010extern void cancel_echoing (void); 4010extern void cancel_echoing (void);
4011extern Lisp_Object last_undo_boundary;
4012extern bool input_pending; 4011extern bool input_pending;
4013#ifdef HAVE_STACK_OVERFLOW_HANDLING 4012#ifdef HAVE_STACK_OVERFLOW_HANDLING
4014extern sigjmp_buf return_to_command_loop; 4013extern sigjmp_buf return_to_command_loop;
diff --git a/src/undo.c b/src/undo.c
index e0924b2b989..009ebc0f959 100644
--- a/src/undo.c
+++ b/src/undo.c
@@ -23,10 +23,6 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
23#include "lisp.h" 23#include "lisp.h"
24#include "buffer.h" 24#include "buffer.h"
25 25
26/* Last buffer for which undo information was recorded. */
27/* BEWARE: This is not traced by the GC, so never dereference it! */
28static struct buffer *last_undo_buffer;
29
30/* Position of point last time we inserted a boundary. */ 26/* Position of point last time we inserted a boundary. */
31static struct buffer *last_boundary_buffer; 27static struct buffer *last_boundary_buffer;
32static ptrdiff_t last_boundary_position; 28static ptrdiff_t last_boundary_position;
@@ -38,6 +34,12 @@ static ptrdiff_t last_boundary_position;
38 an undo-boundary. */ 34 an undo-boundary. */
39static Lisp_Object pending_boundary; 35static Lisp_Object pending_boundary;
40 36
37void
38run_undoable_change ()
39{
40 call0 (Qundo_auto__undoable_change);
41}
42
41/* Record point as it was at beginning of this command (if necessary) 43/* Record point as it was at beginning of this command (if necessary)
42 and prepare the undo info for recording a change. 44 and prepare the undo info for recording a change.
43 PT is the position of point that will naturally occur as a result of the 45 PT is the position of point that will naturally occur as a result of the
@@ -56,15 +58,7 @@ record_point (ptrdiff_t pt)
56 if (NILP (pending_boundary)) 58 if (NILP (pending_boundary))
57 pending_boundary = Fcons (Qnil, Qnil); 59 pending_boundary = Fcons (Qnil, Qnil);
58 60
59 if ((current_buffer != last_undo_buffer) 61 run_undoable_change ();
60 /* Don't call Fundo_boundary for the first change. Otherwise we
61 risk overwriting last_boundary_position in Fundo_boundary with
62 PT of the current buffer and as a consequence not insert an
63 undo boundary because last_boundary_position will equal pt in
64 the test at the end of the present function (Bug#731). */
65 && (MODIFF > SAVE_MODIFF))
66 Fundo_boundary ();
67 last_undo_buffer = current_buffer;
68 62
69 at_boundary = ! CONSP (BVAR (current_buffer, undo_list)) 63 at_boundary = ! CONSP (BVAR (current_buffer, undo_list))
70 || NILP (XCAR (BVAR (current_buffer, undo_list))); 64 || NILP (XCAR (BVAR (current_buffer, undo_list)));
@@ -136,9 +130,7 @@ record_marker_adjustments (ptrdiff_t from, ptrdiff_t to)
136 if (NILP (pending_boundary)) 130 if (NILP (pending_boundary))
137 pending_boundary = Fcons (Qnil, Qnil); 131 pending_boundary = Fcons (Qnil, Qnil);
138 132
139 if (current_buffer != last_undo_buffer) 133 run_undoable_change ();
140 Fundo_boundary ();
141 last_undo_buffer = current_buffer;
142 134
143 for (m = BUF_MARKERS (current_buffer); m; m = m->next) 135 for (m = BUF_MARKERS (current_buffer); m; m = m->next)
144 { 136 {
@@ -225,10 +217,6 @@ record_first_change (void)
225 if (EQ (BVAR (current_buffer, undo_list), Qt)) 217 if (EQ (BVAR (current_buffer, undo_list), Qt))
226 return; 218 return;
227 219
228 if (current_buffer != last_undo_buffer)
229 Fundo_boundary ();
230 last_undo_buffer = current_buffer;
231
232 if (base_buffer->base_buffer) 220 if (base_buffer->base_buffer)
233 base_buffer = base_buffer->base_buffer; 221 base_buffer = base_buffer->base_buffer;
234 222
@@ -256,15 +244,10 @@ record_property_change (ptrdiff_t beg, ptrdiff_t length,
256 if (NILP (pending_boundary)) 244 if (NILP (pending_boundary))
257 pending_boundary = Fcons (Qnil, Qnil); 245 pending_boundary = Fcons (Qnil, Qnil);
258 246
259 if (buf != last_undo_buffer)
260 boundary = true;
261 last_undo_buffer = buf;
262
263 /* Switch temporarily to the buffer that was changed. */ 247 /* Switch temporarily to the buffer that was changed. */
264 current_buffer = buf; 248 set_buffer_internal (buf);
265 249
266 if (boundary) 250 run_undoable_change ();
267 Fundo_boundary ();
268 251
269 if (MODIFF <= SAVE_MODIFF) 252 if (MODIFF <= SAVE_MODIFF)
270 record_first_change (); 253 record_first_change ();
@@ -275,7 +258,8 @@ record_property_change (ptrdiff_t beg, ptrdiff_t length,
275 bset_undo_list (current_buffer, 258 bset_undo_list (current_buffer,
276 Fcons (entry, BVAR (current_buffer, undo_list))); 259 Fcons (entry, BVAR (current_buffer, undo_list)));
277 260
278 current_buffer = obuf; 261 /* Reset the buffer */
262 set_buffer_internal (obuf);
279} 263}
280 264
281DEFUN ("undo-boundary", Fundo_boundary, Sundo_boundary, 0, 0, 0, 265DEFUN ("undo-boundary", Fundo_boundary, Sundo_boundary, 0, 0, 0,
@@ -305,6 +289,8 @@ but another undo command will undo to the previous boundary. */)
305 } 289 }
306 last_boundary_position = PT; 290 last_boundary_position = PT;
307 last_boundary_buffer = current_buffer; 291 last_boundary_buffer = current_buffer;
292
293 Fset (Qundo_auto__last_boundary_cause, Qexplicit);
308 return Qnil; 294 return Qnil;
309} 295}
310 296
@@ -380,7 +366,6 @@ truncate_undo_list (struct buffer *b)
380 && !NILP (Vundo_outer_limit_function)) 366 && !NILP (Vundo_outer_limit_function))
381 { 367 {
382 Lisp_Object tem; 368 Lisp_Object tem;
383 struct buffer *temp = last_undo_buffer;
384 369
385 /* Normally the function this calls is undo-outer-limit-truncate. */ 370 /* Normally the function this calls is undo-outer-limit-truncate. */
386 tem = call1 (Vundo_outer_limit_function, make_number (size_so_far)); 371 tem = call1 (Vundo_outer_limit_function, make_number (size_so_far));
@@ -391,10 +376,6 @@ truncate_undo_list (struct buffer *b)
391 unbind_to (count, Qnil); 376 unbind_to (count, Qnil);
392 return; 377 return;
393 } 378 }
394 /* That function probably used the minibuffer, and if so, that
395 changed last_undo_buffer. Change it back so that we don't
396 force next change to make an undo boundary here. */
397 last_undo_buffer = temp;
398 } 379 }
399 380
400 if (CONSP (next)) 381 if (CONSP (next))
@@ -452,6 +433,9 @@ void
452syms_of_undo (void) 433syms_of_undo (void)
453{ 434{
454 DEFSYM (Qinhibit_read_only, "inhibit-read-only"); 435 DEFSYM (Qinhibit_read_only, "inhibit-read-only");
436 DEFSYM (Qundo_auto__undoable_change, "undo-auto--undoable-change");
437 DEFSYM (Qundo_auto__last_boundary_cause, "undo-auto--last-boundary-cause");
438 DEFSYM (Qexplicit, "explicit");
455 439
456 /* Marker for function call undo list elements. */ 440 /* Marker for function call undo list elements. */
457 DEFSYM (Qapply, "apply"); 441 DEFSYM (Qapply, "apply");
@@ -459,7 +443,6 @@ syms_of_undo (void)
459 pending_boundary = Qnil; 443 pending_boundary = Qnil;
460 staticpro (&pending_boundary); 444 staticpro (&pending_boundary);
461 445
462 last_undo_buffer = NULL;
463 last_boundary_buffer = NULL; 446 last_boundary_buffer = NULL;
464 447
465 defsubr (&Sundo_boundary); 448 defsubr (&Sundo_boundary);