223
|
1 /* undo handling for GNU Emacs.
|
7307
|
2 Copyright (C) 1990, 1993, 1994 Free Software Foundation, Inc.
|
223
|
3
|
|
4 This file is part of GNU Emacs.
|
|
5
|
|
6 GNU Emacs is distributed in the hope that it will be useful,
|
|
7 but WITHOUT ANY WARRANTY. No author or distributor
|
|
8 accepts responsibility to anyone for the consequences of using it
|
|
9 or for whether it serves any particular purpose or works at all,
|
|
10 unless he says so in writing. Refer to the GNU Emacs General Public
|
|
11 License for full details.
|
|
12
|
|
13 Everyone is granted permission to copy, modify and redistribute
|
|
14 GNU Emacs, but only under the conditions described in the
|
|
15 GNU Emacs General Public License. A copy of this license is
|
|
16 supposed to have been given to you along with GNU Emacs so you
|
|
17 can know your rights and responsibilities. It should be in a
|
|
18 file named COPYING. Among other things, the copyright notice
|
|
19 and this notice must be preserved on all copies. */
|
|
20
|
|
21
|
4696
|
22 #include <config.h>
|
223
|
23 #include "lisp.h"
|
|
24 #include "buffer.h"
|
6180
d369907be635
(record_delete): Save last_point_position in the undo record, rather than the
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
25 #include "commands.h"
|
223
|
26
|
|
27 /* Last buffer for which undo information was recorded. */
|
|
28 Lisp_Object last_undo_buffer;
|
|
29
|
3696
|
30 Lisp_Object Qinhibit_read_only;
|
|
31
|
6254
|
32 /* The first time a command records something for undo.
|
|
33 it also allocates the undo-boundary object
|
|
34 which will be added to the list at the end of the command.
|
|
35 This ensures we can't run out of space while trying to make
|
|
36 an undo-boundary. */
|
|
37 Lisp_Object pending_boundary;
|
|
38
|
223
|
39 /* Record an insertion that just happened or is about to happen,
|
|
40 for LENGTH characters at position BEG.
|
|
41 (It is possible to record an insertion before or after the fact
|
|
42 because we don't need to record the contents.) */
|
|
43
|
|
44 record_insert (beg, length)
|
12088
|
45 int beg, length;
|
223
|
46 {
|
|
47 Lisp_Object lbeg, lend;
|
|
48
|
2194
|
49 if (EQ (current_buffer->undo_list, Qt))
|
|
50 return;
|
|
51
|
6254
|
52 /* Allocate a cons cell to be the undo boundary after this command. */
|
|
53 if (NILP (pending_boundary))
|
|
54 pending_boundary = Fcons (Qnil, Qnil);
|
|
55
|
223
|
56 if (current_buffer != XBUFFER (last_undo_buffer))
|
|
57 Fundo_boundary ();
|
9281
05b2bd5d5559
(record_insert, record_delete, record_first_change, record_property_change):
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
58 XSETBUFFER (last_undo_buffer, current_buffer);
|
223
|
59
|
10300
|
60 if (MODIFF <= SAVE_MODIFF)
|
223
|
61 record_first_change ();
|
|
62
|
|
63 /* If this is following another insertion and consecutive with it
|
|
64 in the buffer, combine the two. */
|
9108
c0287cefc0f8
(record_insert, truncate_undo_list, Fprimitive_undo): Use type test macros.
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
65 if (CONSP (current_buffer->undo_list))
|
223
|
66 {
|
|
67 Lisp_Object elt;
|
|
68 elt = XCONS (current_buffer->undo_list)->car;
|
9108
c0287cefc0f8
(record_insert, truncate_undo_list, Fprimitive_undo): Use type test macros.
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
69 if (CONSP (elt)
|
c0287cefc0f8
(record_insert, truncate_undo_list, Fprimitive_undo): Use type test macros.
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
70 && INTEGERP (XCONS (elt)->car)
|
c0287cefc0f8
(record_insert, truncate_undo_list, Fprimitive_undo): Use type test macros.
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
71 && INTEGERP (XCONS (elt)->cdr)
|
12088
|
72 && XINT (XCONS (elt)->cdr) == beg)
|
223
|
73 {
|
12088
|
74 XSETINT (XCONS (elt)->cdr, beg + length);
|
223
|
75 return;
|
|
76 }
|
|
77 }
|
|
78
|
12088
|
79 XSETFASTINT (lbeg, beg);
|
|
80 XSETINT (lend, beg + length);
|
1524
|
81 current_buffer->undo_list = Fcons (Fcons (lbeg, lend),
|
|
82 current_buffer->undo_list);
|
223
|
83 }
|
|
84
|
|
85 /* Record that a deletion is about to take place,
|
|
86 for LENGTH characters at location BEG. */
|
|
87
|
|
88 record_delete (beg, length)
|
|
89 int beg, length;
|
|
90 {
|
|
91 Lisp_Object lbeg, lend, sbeg;
|
7395
99e9c133a752
(record_delete): Record the old point value only right after a boundary.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
92 int at_boundary;
|
223
|
93
|
2194
|
94 if (EQ (current_buffer->undo_list, Qt))
|
|
95 return;
|
|
96
|
6254
|
97 /* Allocate a cons cell to be the undo boundary after this command. */
|
|
98 if (NILP (pending_boundary))
|
|
99 pending_boundary = Fcons (Qnil, Qnil);
|
|
100
|
223
|
101 if (current_buffer != XBUFFER (last_undo_buffer))
|
|
102 Fundo_boundary ();
|
9281
05b2bd5d5559
(record_insert, record_delete, record_first_change, record_property_change):
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
103 XSETBUFFER (last_undo_buffer, current_buffer);
|
223
|
104
|
7395
99e9c133a752
(record_delete): Record the old point value only right after a boundary.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
105 at_boundary = (CONSP (current_buffer->undo_list)
|
99e9c133a752
(record_delete): Record the old point value only right after a boundary.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
106 && NILP (XCONS (current_buffer->undo_list)->car));
|
99e9c133a752
(record_delete): Record the old point value only right after a boundary.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
107
|
10300
|
108 if (MODIFF <= SAVE_MODIFF)
|
223
|
109 record_first_change ();
|
|
110
|
|
111 if (point == beg + length)
|
9281
05b2bd5d5559
(record_insert, record_delete, record_first_change, record_property_change):
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
112 XSETINT (sbeg, -beg);
|
223
|
113 else
|
9322
|
114 XSETFASTINT (sbeg, beg);
|
|
115 XSETFASTINT (lbeg, beg);
|
|
116 XSETFASTINT (lend, beg + length);
|
1248
|
117
|
7395
99e9c133a752
(record_delete): Record the old point value only right after a boundary.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
118 /* If we are just after an undo boundary, and
|
99e9c133a752
(record_delete): Record the old point value only right after a boundary.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
119 point wasn't at start of deleted range, record where it was. */
|
99e9c133a752
(record_delete): Record the old point value only right after a boundary.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
120 if (at_boundary
|
99e9c133a752
(record_delete): Record the old point value only right after a boundary.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
121 && last_point_position != XFASTINT (sbeg)
|
99e9c133a752
(record_delete): Record the old point value only right after a boundary.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
122 && current_buffer == XBUFFER (last_point_position_buffer))
|
1248
|
123 current_buffer->undo_list
|
6180
d369907be635
(record_delete): Save last_point_position in the undo record, rather than the
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
124 = Fcons (make_number (last_point_position), current_buffer->undo_list);
|
1248
|
125
|
223
|
126 current_buffer->undo_list
|
|
127 = Fcons (Fcons (Fbuffer_substring (lbeg, lend), sbeg),
|
|
128 current_buffer->undo_list);
|
|
129 }
|
|
130
|
|
131 /* Record that a replacement is about to take place,
|
|
132 for LENGTH characters at location BEG.
|
|
133 The replacement does not change the number of characters. */
|
|
134
|
|
135 record_change (beg, length)
|
|
136 int beg, length;
|
|
137 {
|
|
138 record_delete (beg, length);
|
|
139 record_insert (beg, length);
|
|
140 }
|
|
141
|
|
142 /* Record that an unmodified buffer is about to be changed.
|
|
143 Record the file modification date so that when undoing this entry
|
|
144 we can tell whether it is obsolete because the file was saved again. */
|
|
145
|
|
146 record_first_change ()
|
|
147 {
|
|
148 Lisp_Object high, low;
|
10300
|
149 struct buffer *base_buffer = current_buffer;
|
5762
|
150
|
|
151 if (EQ (current_buffer->undo_list, Qt))
|
|
152 return;
|
|
153
|
|
154 if (current_buffer != XBUFFER (last_undo_buffer))
|
|
155 Fundo_boundary ();
|
9281
05b2bd5d5559
(record_insert, record_delete, record_first_change, record_property_change):
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
156 XSETBUFFER (last_undo_buffer, current_buffer);
|
5762
|
157
|
10300
|
158 if (base_buffer->base_buffer)
|
|
159 base_buffer = base_buffer->base_buffer;
|
|
160
|
|
161 XSETFASTINT (high, (base_buffer->modtime >> 16) & 0xffff);
|
|
162 XSETFASTINT (low, base_buffer->modtime & 0xffff);
|
223
|
163 current_buffer->undo_list = Fcons (Fcons (Qt, Fcons (high, low)), current_buffer->undo_list);
|
|
164 }
|
|
165
|
1968
|
166 /* Record a change in property PROP (whose old value was VAL)
|
|
167 for LENGTH characters starting at position BEG in BUFFER. */
|
|
168
|
|
169 record_property_change (beg, length, prop, value, buffer)
|
|
170 int beg, length;
|
|
171 Lisp_Object prop, value, buffer;
|
|
172 {
|
|
173 Lisp_Object lbeg, lend, entry;
|
|
174 struct buffer *obuf = current_buffer;
|
|
175 int boundary = 0;
|
|
176
|
5762
|
177 if (EQ (XBUFFER (buffer)->undo_list, Qt))
|
2194
|
178 return;
|
|
179
|
6254
|
180 /* Allocate a cons cell to be the undo boundary after this command. */
|
|
181 if (NILP (pending_boundary))
|
|
182 pending_boundary = Fcons (Qnil, Qnil);
|
|
183
|
1968
|
184 if (!EQ (buffer, last_undo_buffer))
|
|
185 boundary = 1;
|
|
186 last_undo_buffer = buffer;
|
|
187
|
|
188 /* Switch temporarily to the buffer that was changed. */
|
|
189 current_buffer = XBUFFER (buffer);
|
|
190
|
|
191 if (boundary)
|
|
192 Fundo_boundary ();
|
|
193
|
10300
|
194 if (MODIFF <= SAVE_MODIFF)
|
1968
|
195 record_first_change ();
|
|
196
|
9281
05b2bd5d5559
(record_insert, record_delete, record_first_change, record_property_change):
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
197 XSETINT (lbeg, beg);
|
05b2bd5d5559
(record_insert, record_delete, record_first_change, record_property_change):
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
198 XSETINT (lend, beg + length);
|
1968
|
199 entry = Fcons (Qnil, Fcons (prop, Fcons (value, Fcons (lbeg, lend))));
|
|
200 current_buffer->undo_list = Fcons (entry, current_buffer->undo_list);
|
|
201
|
|
202 current_buffer = obuf;
|
|
203 }
|
|
204
|
223
|
205 DEFUN ("undo-boundary", Fundo_boundary, Sundo_boundary, 0, 0, 0,
|
|
206 "Mark a boundary between units of undo.\n\
|
|
207 An undo command will stop at this point,\n\
|
|
208 but another undo command will undo to the previous boundary.")
|
|
209 ()
|
|
210 {
|
|
211 Lisp_Object tem;
|
|
212 if (EQ (current_buffer->undo_list, Qt))
|
|
213 return Qnil;
|
|
214 tem = Fcar (current_buffer->undo_list);
|
485
|
215 if (!NILP (tem))
|
6254
|
216 {
|
|
217 /* One way or another, cons nil onto the front of the undo list. */
|
|
218 if (!NILP (pending_boundary))
|
|
219 {
|
|
220 /* If we have preallocated the cons cell to use here,
|
|
221 use that one. */
|
|
222 XCONS (pending_boundary)->cdr = current_buffer->undo_list;
|
|
223 current_buffer->undo_list = pending_boundary;
|
|
224 pending_boundary = Qnil;
|
|
225 }
|
|
226 else
|
|
227 current_buffer->undo_list = Fcons (Qnil, current_buffer->undo_list);
|
|
228 }
|
223
|
229 return Qnil;
|
|
230 }
|
|
231
|
|
232 /* At garbage collection time, make an undo list shorter at the end,
|
|
233 returning the truncated list.
|
|
234 MINSIZE and MAXSIZE are the limits on size allowed, as described below.
|
761
|
235 In practice, these are the values of undo-limit and
|
|
236 undo-strong-limit. */
|
223
|
237
|
|
238 Lisp_Object
|
|
239 truncate_undo_list (list, minsize, maxsize)
|
|
240 Lisp_Object list;
|
|
241 int minsize, maxsize;
|
|
242 {
|
|
243 Lisp_Object prev, next, last_boundary;
|
|
244 int size_so_far = 0;
|
|
245
|
|
246 prev = Qnil;
|
|
247 next = list;
|
|
248 last_boundary = Qnil;
|
|
249
|
|
250 /* Always preserve at least the most recent undo record.
|
241
|
251 If the first element is an undo boundary, skip past it.
|
|
252
|
|
253 Skip, skip, skip the undo, skip, skip, skip the undo,
|
970
|
254 Skip, skip, skip the undo, skip to the undo bound'ry.
|
|
255 (Get it? "Skip to my Loo?") */
|
9108
c0287cefc0f8
(record_insert, truncate_undo_list, Fprimitive_undo): Use type test macros.
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
256 if (CONSP (next) && NILP (XCONS (next)->car))
|
223
|
257 {
|
|
258 /* Add in the space occupied by this element and its chain link. */
|
|
259 size_so_far += sizeof (struct Lisp_Cons);
|
|
260
|
|
261 /* Advance to next element. */
|
|
262 prev = next;
|
|
263 next = XCONS (next)->cdr;
|
|
264 }
|
9108
c0287cefc0f8
(record_insert, truncate_undo_list, Fprimitive_undo): Use type test macros.
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
265 while (CONSP (next) && ! NILP (XCONS (next)->car))
|
223
|
266 {
|
|
267 Lisp_Object elt;
|
|
268 elt = XCONS (next)->car;
|
|
269
|
|
270 /* Add in the space occupied by this element and its chain link. */
|
|
271 size_so_far += sizeof (struct Lisp_Cons);
|
9108
c0287cefc0f8
(record_insert, truncate_undo_list, Fprimitive_undo): Use type test macros.
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
272 if (CONSP (elt))
|
223
|
273 {
|
|
274 size_so_far += sizeof (struct Lisp_Cons);
|
9108
c0287cefc0f8
(record_insert, truncate_undo_list, Fprimitive_undo): Use type test macros.
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
275 if (STRINGP (XCONS (elt)->car))
|
223
|
276 size_so_far += (sizeof (struct Lisp_String) - 1
|
|
277 + XSTRING (XCONS (elt)->car)->size);
|
|
278 }
|
|
279
|
|
280 /* Advance to next element. */
|
|
281 prev = next;
|
|
282 next = XCONS (next)->cdr;
|
|
283 }
|
9108
c0287cefc0f8
(record_insert, truncate_undo_list, Fprimitive_undo): Use type test macros.
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
284 if (CONSP (next))
|
223
|
285 last_boundary = prev;
|
|
286
|
9108
c0287cefc0f8
(record_insert, truncate_undo_list, Fprimitive_undo): Use type test macros.
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
287 while (CONSP (next))
|
223
|
288 {
|
|
289 Lisp_Object elt;
|
|
290 elt = XCONS (next)->car;
|
|
291
|
|
292 /* When we get to a boundary, decide whether to truncate
|
|
293 either before or after it. The lower threshold, MINSIZE,
|
|
294 tells us to truncate after it. If its size pushes past
|
|
295 the higher threshold MAXSIZE as well, we truncate before it. */
|
485
|
296 if (NILP (elt))
|
223
|
297 {
|
|
298 if (size_so_far > maxsize)
|
|
299 break;
|
|
300 last_boundary = prev;
|
|
301 if (size_so_far > minsize)
|
|
302 break;
|
|
303 }
|
|
304
|
|
305 /* Add in the space occupied by this element and its chain link. */
|
|
306 size_so_far += sizeof (struct Lisp_Cons);
|
9108
c0287cefc0f8
(record_insert, truncate_undo_list, Fprimitive_undo): Use type test macros.
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
307 if (CONSP (elt))
|
223
|
308 {
|
|
309 size_so_far += sizeof (struct Lisp_Cons);
|
9108
c0287cefc0f8
(record_insert, truncate_undo_list, Fprimitive_undo): Use type test macros.
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
310 if (STRINGP (XCONS (elt)->car))
|
223
|
311 size_so_far += (sizeof (struct Lisp_String) - 1
|
|
312 + XSTRING (XCONS (elt)->car)->size);
|
|
313 }
|
|
314
|
|
315 /* Advance to next element. */
|
|
316 prev = next;
|
|
317 next = XCONS (next)->cdr;
|
|
318 }
|
|
319
|
|
320 /* If we scanned the whole list, it is short enough; don't change it. */
|
485
|
321 if (NILP (next))
|
223
|
322 return list;
|
|
323
|
|
324 /* Truncate at the boundary where we decided to truncate. */
|
485
|
325 if (!NILP (last_boundary))
|
223
|
326 {
|
|
327 XCONS (last_boundary)->cdr = Qnil;
|
|
328 return list;
|
|
329 }
|
|
330 else
|
|
331 return Qnil;
|
|
332 }
|
|
333
|
|
334 DEFUN ("primitive-undo", Fprimitive_undo, Sprimitive_undo, 2, 2, 0,
|
|
335 "Undo N records from the front of the list LIST.\n\
|
|
336 Return what remains of the list.")
|
3719
|
337 (n, list)
|
|
338 Lisp_Object n, list;
|
223
|
339 {
|
7671
|
340 struct gcpro gcpro1, gcpro2;
|
|
341 Lisp_Object next;
|
3696
|
342 int count = specpdl_ptr - specpdl;
|
7671
|
343 register int arg;
|
223
|
344 #if 0 /* This is a good feature, but would make undo-start
|
|
345 unable to do what is expected. */
|
|
346 Lisp_Object tem;
|
|
347
|
|
348 /* If the head of the list is a boundary, it is the boundary
|
|
349 preceding this command. Get rid of it and don't count it. */
|
|
350 tem = Fcar (list);
|
485
|
351 if (NILP (tem))
|
223
|
352 list = Fcdr (list);
|
|
353 #endif
|
|
354
|
7671
|
355 CHECK_NUMBER (n, 0);
|
|
356 arg = XINT (n);
|
|
357 next = Qnil;
|
|
358 GCPRO2 (next, list);
|
|
359
|
3696
|
360 /* Don't let read-only properties interfere with undo. */
|
|
361 if (NILP (current_buffer->read_only))
|
|
362 specbind (Qinhibit_read_only, Qt);
|
|
363
|
223
|
364 while (arg > 0)
|
|
365 {
|
|
366 while (1)
|
|
367 {
|
|
368 next = Fcar (list);
|
|
369 list = Fcdr (list);
|
1248
|
370 /* Exit inner loop at undo boundary. */
|
485
|
371 if (NILP (next))
|
223
|
372 break;
|
1248
|
373 /* Handle an integer by setting point to that value. */
|
9108
c0287cefc0f8
(record_insert, truncate_undo_list, Fprimitive_undo): Use type test macros.
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
374 if (INTEGERP (next))
|
1248
|
375 SET_PT (clip_to_bounds (BEGV, XINT (next), ZV));
|
9108
c0287cefc0f8
(record_insert, truncate_undo_list, Fprimitive_undo): Use type test macros.
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
376 else if (CONSP (next))
|
223
|
377 {
|
1248
|
378 Lisp_Object car, cdr;
|
|
379
|
|
380 car = Fcar (next);
|
|
381 cdr = Fcdr (next);
|
|
382 if (EQ (car, Qt))
|
223
|
383 {
|
1248
|
384 /* Element (t high . low) records previous modtime. */
|
|
385 Lisp_Object high, low;
|
|
386 int mod_time;
|
10300
|
387 struct buffer *base_buffer = current_buffer;
|
1248
|
388
|
|
389 high = Fcar (cdr);
|
|
390 low = Fcdr (cdr);
|
3687
|
391 mod_time = (XFASTINT (high) << 16) + XFASTINT (low);
|
10300
|
392
|
|
393 if (current_buffer->base_buffer)
|
|
394 base_buffer = current_buffer->base_buffer;
|
|
395
|
1248
|
396 /* If this records an obsolete save
|
|
397 (not matching the actual disk file)
|
|
398 then don't mark unmodified. */
|
10300
|
399 if (mod_time != base_buffer->modtime)
|
12649
|
400 continue;
|
1598
|
401 #ifdef CLASH_DETECTION
|
1248
|
402 Funlock_buffer ();
|
1598
|
403 #endif /* CLASH_DETECTION */
|
1248
|
404 Fset_buffer_modified_p (Qnil);
|
|
405 }
|
3687
|
406 #ifdef USE_TEXT_PROPERTIES
|
|
407 else if (EQ (car, Qnil))
|
1968
|
408 {
|
3687
|
409 /* Element (nil prop val beg . end) is property change. */
|
1968
|
410 Lisp_Object beg, end, prop, val;
|
|
411
|
|
412 prop = Fcar (cdr);
|
|
413 cdr = Fcdr (cdr);
|
|
414 val = Fcar (cdr);
|
|
415 cdr = Fcdr (cdr);
|
|
416 beg = Fcar (cdr);
|
|
417 end = Fcdr (cdr);
|
|
418
|
|
419 Fput_text_property (beg, end, prop, val, Qnil);
|
|
420 }
|
3687
|
421 #endif /* USE_TEXT_PROPERTIES */
|
9108
c0287cefc0f8
(record_insert, truncate_undo_list, Fprimitive_undo): Use type test macros.
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
422 else if (INTEGERP (car) && INTEGERP (cdr))
|
1248
|
423 {
|
|
424 /* Element (BEG . END) means range was inserted. */
|
|
425 Lisp_Object end;
|
|
426
|
|
427 if (XINT (car) < BEGV
|
|
428 || XINT (cdr) > ZV)
|
223
|
429 error ("Changes to be undone are outside visible portion of buffer");
|
1320
c45c4e0cae7d
(Fprimitive_undo): When undoing an insert, move point and then delete.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
430 /* Set point first thing, so that undoing this undo
|
c45c4e0cae7d
(Fprimitive_undo): When undoing an insert, move point and then delete.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
431 does not send point back to where it is now. */
|
c45c4e0cae7d
(Fprimitive_undo): When undoing an insert, move point and then delete.
Richard M. Stallman <rms@gnu.org>
diff
changeset
|
432 Fgoto_char (car);
|
1248
|
433 Fdelete_region (car, cdr);
|
223
|
434 }
|
9108
c0287cefc0f8
(record_insert, truncate_undo_list, Fprimitive_undo): Use type test macros.
Karl Heuer <kwzh@gnu.org>
diff
changeset
|
435 else if (STRINGP (car) && INTEGERP (cdr))
|
223
|
436 {
|
1248
|
437 /* Element (STRING . POS) means STRING was deleted. */
|
|
438 Lisp_Object membuf;
|
|
439 int pos = XINT (cdr);
|
544
|
440
|
1248
|
441 membuf = car;
|
|
442 if (pos < 0)
|
|
443 {
|
|
444 if (-pos < BEGV || -pos > ZV)
|
|
445 error ("Changes to be undone are outside visible portion of buffer");
|
|
446 SET_PT (-pos);
|
|
447 Finsert (1, &membuf);
|
|
448 }
|
|
449 else
|
|
450 {
|
|
451 if (pos < BEGV || pos > ZV)
|
|
452 error ("Changes to be undone are outside visible portion of buffer");
|
|
453 SET_PT (pos);
|
|
454
|
|
455 /* Insert before markers so that if the mark is
|
|
456 currently on the boundary of this deletion, it
|
|
457 ends up on the other side of the now-undeleted
|
|
458 text from point. Since undo doesn't even keep
|
|
459 track of the mark, this isn't really necessary,
|
|
460 but it may lead to better behavior in certain
|
|
461 situations. */
|
|
462 Finsert_before_markers (1, &membuf);
|
|
463 SET_PT (pos);
|
|
464 }
|
223
|
465 }
|
|
466 }
|
|
467 }
|
|
468 arg--;
|
|
469 }
|
|
470
|
7671
|
471 UNGCPRO;
|
3696
|
472 return unbind_to (count, list);
|
223
|
473 }
|
|
474
|
|
475 syms_of_undo ()
|
|
476 {
|
3696
|
477 Qinhibit_read_only = intern ("inhibit-read-only");
|
|
478 staticpro (&Qinhibit_read_only);
|
|
479
|
6254
|
480 pending_boundary = Qnil;
|
|
481 staticpro (&pending_boundary);
|
|
482
|
223
|
483 defsubr (&Sprimitive_undo);
|
|
484 defsubr (&Sundo_boundary);
|
|
485 }
|