|
|
1.1 root 1: /* Support routines for the undo facility.
2: Copyright (C) 1985, 1986 Free Software Foundation, Inc.
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:
22: #include "config.h"
23: #include "lisp.h"
24: #include "undo.h"
25: #include "commands.h"
26: #include "buffer.h"
27:
28: /* Access undo records of current buffer */
29: /* These assume that `u' points to the buffer's undodata */
30: #define UndoRQ (u->undorecs)
31: #define UndoCQ (u->undochars)
32: #define FillRQ (u->nextrec)
33: #define FillCQ (u->nextchar)
34:
35: /* Record last undo record made, and what buffer made in */
36: static struct UndoRec *LastUndoRec;
37: static struct buffer *LastUndoBuf;
38:
39: /* Record progress of undoing */
40: static int NUndone;
41: static int NCharsLeft;
42: static int LastUndoneC;
43: static int LastUndone;
44: static struct buffer *LastUndoneBuf;
45:
46: Lisp_Object Fundo_boundary ();
47:
48: make_undo_records (b)
49: struct buffer *b;
50: {
51: register struct UndoData *u;
52: b->undodata = u = (struct UndoData *) xmalloc (sizeof (struct UndoData));
53: u->undorecs
54: = (struct UndoRec *) xmalloc (sizeof (struct UndoRec) * InitNUndoR);
55: u->undochars = (char *) xmalloc (InitNUndoC);
56: u->undorecs[InitNUndoR - 1].kind = Unundoable;
57: u->nextrec = 0;
58: u->nextchar = 0;
59: u->num_undorecs = InitNUndoR;
60: u->num_undochars = InitNUndoC;
61: }
62:
63: free_undo_records (b)
64: struct buffer *b;
65: {
66: register struct UndoData *u = b->undodata;
67: free (u->undorecs);
68: free (u->undochars);
69: free (u);
70: }
71:
72: struct UndoRec *
73: record_undo (kind, pos, len)
74: enum Ukinds kind;
75: {
76: register struct UndoData *u = bf_cur->undodata;
77: register struct UndoRec *p = &UndoRQ[FillRQ];
78: register struct UndoRec *np;
79:
80: FillRQ++;
81: if (FillRQ >= NUndoR)
82: FillRQ = 0;
83: else if (FillRQ >= u->num_undorecs)
84: {
85: np = (struct UndoRec *) xrealloc (UndoRQ, NUndoR * sizeof *p);
86: if (np)
87: {
88: UndoRQ = np;
89: p = &UndoRQ[FillRQ-1];
90: u->num_undorecs = NUndoR;
91: np[NUndoR - 1].kind = Unundoable;
92: }
93: else
94: FillRQ = 0;
95: }
96: UndoRQ[FillRQ].kind = Unundoable;
97: p -> kind = kind;
98: p -> pos = pos;
99: p -> len = len;
100: LastUndoRec = p;
101: LastUndoBuf = bf_cur;
102: if (kind != Uboundary)
103: LastUndone = -1;
104: return p;
105: }
106:
107: record_insert (pos, n)
108: {
109: register struct UndoRec *p = LastUndoRec;
110: if (!bf_cur->undodata)
111: return;
112: if (LastUndoBuf != bf_cur)
113: {
114: Fundo_boundary ();
115: p = 0;
116: }
117:
118: if (bf_modified <= bf_cur->save_modified)
119: record_undo (Uunmod, pos, bf_cur->modtime);
120:
121: if (p && p -> kind == Udelete && p -> pos + p -> len == pos)
122: p -> len += n;
123: else
124: record_undo (Udelete, pos, n);
125: }
126:
127: record_delete (pos, n)
128: int pos, n;
129: {
130: register struct UndoRec *p = LastUndoRec;
131:
132: if (!bf_cur->undodata)
133: return;
134: if (LastUndoBuf != bf_cur)
135: {
136: Fundo_boundary ();
137: p = 0;
138: }
139:
140: if (bf_modified <= bf_cur->save_modified)
141: record_undo (Uunmod, pos, bf_cur->modtime);
142:
143: if (p && p->kind == Uinsert && p->pos == pos && p->len > 0)
144: p->len += n;
145: else if (point == pos + n)
146: record_undo (Uinsert, pos + n, - n);
147: else
148: record_undo (Uinsert, pos, n);
149:
150: record_chars (pos, n);
151: }
152:
153: record_chars (pos, n)
154: register int pos, n;
155: {
156: if (pos < bf_s1 + 1 && pos + n > bf_s1 + 1)
157: {
158: record_block (&CharAt (pos), bf_s1 + 1 - pos);
159: n -= bf_s1 + 1 - pos;
160: pos = bf_s1 + 1;
161: }
162:
163: record_block (&CharAt (pos), n);
164: }
165:
166: record_block (p, n)
167: register char *p;
168: register int n;
169: {
170: register char *cp;
171: register struct UndoData *u = bf_cur->undodata;
172: register int i;
173:
174: NCharsLeft -= n;
175: cp = &UndoCQ[FillCQ];
176:
177: while (n > 0)
178: {
179: i = u->num_undochars - FillCQ;
180: if (i > n) i = n;
181: if (i > 0)
182: {
183: bcopy (p, cp, i);
184: p += i;
185: FillCQ += i;
186: n -= i;
187: }
188:
189: if (n == 0)
190: break;
191:
192: if (FillCQ >= NUndoC)
193: {
194: FillCQ = 0;
195: cp = UndoCQ;
196: }
197: else
198: {
199: cp = (char *) xrealloc (UndoCQ, NUndoC);
200: UndoCQ = cp;
201: cp += FillCQ;
202: NCharsLeft += NUndoC - u->num_undochars;
203: u->num_undochars = NUndoC;
204: }
205: }
206: }
207:
208: record_change (pos, n)
209: int pos, n;
210: {
211: register struct UndoRec *p = LastUndoRec;
212: if (!bf_cur->undodata)
213: return;
214: if (LastUndoBuf != bf_cur)
215: {
216: Fundo_boundary ();
217: p = 0;
218: }
219:
220: if (bf_modified <= bf_cur->save_modified)
221: record_undo (Uunmod, pos, bf_cur->modtime);
222:
223: if (p && p->kind == Uchange && p->len > 0 && p->pos + p->len == pos)
224: p->len += n;
225: else if (point == pos + n)
226: record_undo (Uchange, pos + n, -n);
227: else
228: record_undo (Uchange, pos, n);
229:
230: record_chars (pos, n);
231: }
232:
233: record_change1 (pos, bufp, n)
234: int pos;
235: char *bufp;
236: int n;
237: {
238: register struct UndoRec *p = LastUndoRec;
239: if (!bf_cur->undodata)
240: return;
241: if (LastUndoBuf != bf_cur)
242: {
243: Fundo_boundary ();
244: p = 0;
245: }
246: if (p && p->kind == Uchange && p->len > 0 && p->pos + p->len == pos)
247: p -> len += n;
248: else
249: record_undo (Uchange, pos, n);
250:
251: record_block (bufp, n);
252: }
253:
254: DoneIsDone ()
255: {
256: register struct UndoData *u = bf_cur->undodata;
257: register struct UndoRec *p;
258:
259: if (!u)
260: return 0;
261:
262: p = &UndoRQ[(FillRQ + u->num_undorecs - 1) % u->num_undorecs];
263: if (p->kind != Unundoable)
264: record_undo (Unundoable, point, 0);
265: return 0;
266: }
267:
268: DEFUN ("undo-boundary", Fundo_boundary, Sundo_boundary, 0, 0, 0,
269: "Mark a boundary between units of undo.\n\
270: An undo command will stop at this point,\n\
271: but another undo command will undo to the previous boundary.")
272: ()
273: {
274: register struct UndoData *u = bf_cur->undodata;
275: register struct UndoRec *p;
276:
277: if (!u)
278: return Qnil;
279:
280: p = &UndoRQ[(FillRQ + u->num_undorecs - 1) % u->num_undorecs];
281: if (p->kind != Uboundary)
282: record_undo (Uboundary, point, 0);
283: return Qnil;
284: }
285:
286: DEFUN ("undo-more", Fundo_more, Sundo_more, 1, 1, 0,
287: "Undo back N undo-boundaries beyond what was already undone recently.\n\
288: Call undo-start to get ready to undo recent changes,\n\
289: then call undo-more one or more times to undo them.")
290: (pfxarg)
291: Lisp_Object pfxarg;
292: {
293: register struct UndoData *u = bf_cur->undodata;
294: register int n = 0;
295: register int chars;
296: register int i = LastUndone;
297: register int arg = XINT (pfxarg);
298: register int len, pos;
299: char tembuf[NUndoC];
300:
301: if (!u)
302: return Qnil;
303:
304: if (LastUndoneBuf != bf_cur ||
305: i == -1)
306: error ("Cannot undo more: changes have been made since the last undo");
307:
308: while (1)
309: {
310: while (UndoRQ[i = (!i ? u->num_undorecs-1 : i-1)].kind != Uboundary)
311: {
312: len = UndoRQ[i].len;
313: if (len < 0) len = - len;
314: if (((UndoRQ[i].kind == Uinsert || UndoRQ[i].kind == Uchange)
315: && (NCharsLeft -= len) < 0)
316: || UndoRQ[i].kind == Unundoable || NUndone >= u->num_undorecs)
317: error ("No further undo information available");
318: NUndone++;
319: n++;
320: }
321: NUndone++;
322: n++;
323: if (--arg <= 0)
324: break;
325: }
326:
327: i = LastUndone;
328: chars = LastUndoneC;
329: while (--n >= 0)
330: {
331: if (!i)
332: i = u->num_undorecs;
333: i--;
334:
335: len = UndoRQ[i].len;
336: pos = UndoRQ[i].pos;
337:
338: if (UndoRQ[i].kind == Uchange || UndoRQ[i].kind == Uinsert)
339: if (len < 0)
340: {
341: pos += len;
342: len = - len;
343: }
344:
345: #ifdef SWITCH_ENUM_BUG
346: switch ((int) UndoRQ[i].kind)
347: #else
348: switch (UndoRQ[i].kind)
349: #endif
350: {
351: case Uchange:
352: case Udelete:
353: if (pos < FirstCharacter || pos + len > NumCharacters + 1)
354: error ("Changes to be undone are outside visible portion of buffer");
355: SetPoint (pos);
356: break;
357:
358: case Uinsert:
359: if (pos < FirstCharacter || pos > NumCharacters + 1)
360: error ("Changes to be undone are outside visible portion of buffer");
361: SetPoint (pos);
362: }
363:
364: #ifdef SWITCH_ENUM_BUG
365: switch ((int) UndoRQ[i].kind)
366: #else
367: switch (UndoRQ[i].kind)
368: #endif
369: {
370: case Uboundary:
371: break;
372:
373: case Udelete:
374: del_range (point, point + len);
375: break;
376:
377: case Uchange:
378: if (len > NUndoC)
379: /* Should have already said "No more undo info available" */
380: abort ();
381: save_undone_chars (pos, len, tembuf);
382: chars -= len;
383: if (chars < 0)
384: {
385: replace_chars (point - chars, len + chars, UndoCQ);
386: replace_chars (point, - chars, UndoCQ + chars + u->num_undochars);
387: chars += u->num_undochars;
388: }
389: else
390: replace_chars (point, len, UndoCQ + chars);
391: record_change1 (point, tembuf, len);
392: SetPoint (UndoRQ[i].pos);
393: break;
394:
395: case Uinsert:
396: chars -= len;
397: if (chars < 0)
398: {
399: InsCStr (UndoCQ + chars + u->num_undochars, - chars);
400: InsCStr (UndoCQ, len + chars);
401: chars += u->num_undochars;
402: }
403: else
404: InsCStr (UndoCQ + chars, len);
405: SetPoint (UndoRQ[i].pos);
406: break;
407:
408: case Uunmod:
409: /* If this Uunmod records an obsolete save
410: (not matching the actual disk file)
411: then don't mark unmodified. */
412: if (len != bf_cur->modtime)
413: break;
414: #ifdef CLASH_DETECTION
415: Funlock_buffer ();
416: #endif /* CLASH_DETECTION */
417: bf_cur->save_modified = bf_modified;
418: RedoModes++;
419: break;
420:
421: default:
422: error ("Changes to great to be undone");
423: return Qnil;
424: }
425: }
426: LastUndone = i;
427: LastUndoneC = chars;
428: return Qnil;
429: }
430:
431: replace_chars (pos, n, string)
432: register int pos, n;
433: register unsigned char *string;
434: {
435: modify_region (pos, pos + n);
436: while (--n >= 0)
437: {
438: CharAt (pos) = *string++;
439: pos++;
440: }
441: }
442:
443: save_undone_chars (pos, n, p)
444: register int pos, n;
445: register char *p;
446: {
447: if (pos < bf_s1 + 1 && pos + n > bf_s1 + 1)
448: {
449: bcopy (&CharAt (pos), p, bf_s1 + 1 - pos);
450: p += bf_s1 + 1 - pos;
451: n -= bf_s1 + 1 - pos;
452: pos = bf_s1 + 1;
453: }
454:
455: bcopy (&CharAt (pos), p, n);
456: }
457:
458: DEFUN ("undo-start", Fundo_start, Sundo_start, 0, 0, 0,
459: "Move undo-pointer to front of undo records.\n\
460: The next call to undo-more will undo the most recently made change.")
461: ()
462: {
463: register struct UndoData *u = bf_cur->undodata;
464:
465: if (!u)
466: error ("Undo information not kept for this buffer");
467: LastUndoneBuf = bf_cur;
468: NCharsLeft = u->num_undochars;
469: NUndone = 0;
470: LastUndone = FillRQ;
471: LastUndoneC = FillCQ;
472: return Qnil;
473: }
474:
475: syms_of_undo ()
476: {
477: defsubr (&Sundo_start);
478: defsubr (&Sundo_boundary);
479: defsubr (&Sundo_more);
480: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.