|
|
1.1 root 1: /* Support routines for the undo facility.
2: Copyright (C) 1985 Fen Labalme and Richard M. Stallman.
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 NUndone;
41: static NCharsLeft;
42: static LastUndoneC;
43: static 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: NewUndo (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: RecordInsert (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: NewUndo (Uunmod, pos, 0);
120:
121: if (p && p -> kind == Udelete && p -> pos + p -> len == pos)
122: p -> len += n;
123: else
124: NewUndo (Udelete, pos, n);
125: }
126:
127: RecordDelete (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: NewUndo (Uunmod, pos, 0);
142:
143: if (p && p->kind == Uinsert && p->pos == pos)
144: p->len += n;
145: else
146: NewUndo (Uinsert, pos, n);
147:
148: record_chars (pos, n);
149: }
150:
151: record_chars (pos, n)
152: register int pos, n;
153: {
154: if (pos < bf_s1 + 1 && pos + n > bf_s1 + 1)
155: {
156: record_block (&CharAt (pos), bf_s1 + 1 - pos);
157: n -= bf_s1 + 1 - pos;
158: pos = bf_s1 + 1;
159: }
160:
161: record_block (&CharAt (pos), n);
162: }
163:
164: record_block (p, n)
165: register char *p;
166: register int n;
167: {
168: register char *cp;
169: register struct UndoData *u = bf_cur->undodata;
170: register int i;
171:
172: NCharsLeft -= n;
173: cp = &UndoCQ[FillCQ];
174:
175: while (n > 0)
176: {
177: i = u->num_undochars - FillCQ;
178: if (i > n) i = n;
179: if (i > 0)
180: {
181: bcopy (p, cp, i);
182: p += i;
183: cp += i;
184: FillCQ += i;
185: n -= i;
186: }
187:
188: if (FillCQ >= NUndoC)
189: {
190: FillCQ = 0;
191: cp = UndoCQ;
192: }
193: else
194: {
195: cp = (char *) xrealloc (UndoCQ, NUndoC);
196: UndoCQ = cp;
197: cp += FillCQ;
198: NCharsLeft += NUndoC - u->num_undochars;
199: u->num_undochars = NUndoC;
200: }
201: }
202: }
203:
204: RecordChange (pos, n)
205: int pos, n;
206: {
207: register struct UndoRec *p = LastUndoRec;
208: if (!bf_cur->undodata)
209: return;
210: if (LastUndoBuf != bf_cur)
211: {
212: Fundo_boundary ();
213: p = 0;
214: }
215:
216: if (bf_modified <= bf_cur->save_modified)
217: NewUndo (Uunmod, pos, 0);
218:
219: if (p && p -> kind == Uchange && p -> pos + p -> len == pos)
220: p -> len += n;
221: else
222: NewUndo (Uchange, pos, n);
223:
224: record_chars (pos, n);
225: }
226:
227: RecordChange1 (pos, bufp, n)
228: int pos;
229: char *bufp;
230: int n;
231: {
232: register struct UndoRec *p = LastUndoRec;
233: if (!bf_cur->undodata)
234: return;
235: if (LastUndoBuf != bf_cur)
236: {
237: Fundo_boundary ();
238: p = 0;
239: }
240: if (p && p -> kind == Uchange && p -> pos + p -> len == pos)
241: p -> len += n;
242: else
243: NewUndo (Uchange, pos, n);
244:
245: record_block (bufp, n);
246: }
247:
248: DoneIsDone ()
249: {
250: register struct UndoData *u = bf_cur->undodata;
251: register struct UndoRec *p;
252:
253: if (!u)
254: return 0;
255:
256: p = &UndoRQ[(FillRQ + u->num_undorecs - 1) % u->num_undorecs];
257: if (p->kind != Unundoable)
258: NewUndo (Unundoable, point, 0);
259: return 0;
260: }
261:
262: DEFUN ("undo-boundary", Fundo_boundary, Sundo_boundary, 0, 0, 0,
263: "Mark a boundary between units of undo.\n\
264: An undo command will stop at this point,\n\
265: but another undo command will undo to the previous boundary.")
266: ()
267: {
268: register struct UndoData *u = bf_cur->undodata;
269: register struct UndoRec *p;
270:
271: if (!u)
272: return Qnil;
273:
274: p = &UndoRQ[(FillRQ + u->num_undorecs - 1) % u->num_undorecs];
275: if (p->kind != Uboundary)
276: NewUndo (Uboundary, point, 0);
277: return Qnil;
278: }
279:
280: DEFUN ("undo-more", Fundo_more, Sundo_more, 1, 1, 0,
281: "Undo back N undo-boundaries beyond what was already undone recently.\n\
282: Call undo-start to get ready to undo recent changes,\n\
283: then call undo-more one or more times to undo them.")
284: (pfxarg)
285: Lisp_Object pfxarg;
286: {
287: register struct UndoData *u = bf_cur->undodata;
288: register int n = 0;
289: register int chars;
290: register int i = LastUndone;
291: register int arg = XINT (pfxarg);
292: register int len, pos;
293: char tembuf[NUndoC];
294:
295: if (!u)
296: return Qnil;
297:
298: if (LastUndoneBuf != bf_cur ||
299: i == -1)
300: error ("Cannot undo more: changes have been made since the last undo");
301:
302: while (1)
303: {
304: while (UndoRQ[i = (!i ? u->num_undorecs-1 : i-1)].kind != Uboundary)
305: {
306: if (((UndoRQ[i].kind == Uinsert || UndoRQ[i].kind == Uchange)
307: && (NCharsLeft -= UndoRQ[i].len) < 0)
308: || UndoRQ[i].kind == Unundoable || NUndone >= u->num_undorecs)
309: error ("No further undo information available");
310: NUndone++;
311: n++;
312: }
313: NUndone++;
314: n++;
315: if (--arg <= 0)
316: break;
317: }
318:
319: i = LastUndone;
320: chars = LastUndoneC;
321: while (--n >= 0)
322: {
323: if (!i)
324: i = u->num_undorecs;
325: i--;
326:
327: len = UndoRQ[i].len;
328: pos = UndoRQ[i].pos;
329: #ifdef SWITCH_ENUM_BUG
330: switch ((int) UndoRQ[i].kind)
331: #else
332: switch (UndoRQ[i].kind)
333: #endif
334: {
335: case Uboundary:
336: break;
337:
338: case Udelete:
339: if (pos < FirstCharacter
340: || pos + len > NumCharacters + 1)
341: error ("Changes to be undone are outside visible portion of buffer");
342: SetPoint (pos);
343: del_range (point, point + len);
344: break;
345:
346: case Uchange:
347: if (pos < FirstCharacter
348: || pos + len > NumCharacters + 1)
349: error ("Changes to be undone are outside visible portion of buffer");
350: SetPoint (pos);
351: if (len > NUndoC)
352: /* Should have already said "No more undo info available" */
353: abort ();
354: save_undone_chars (pos, len, tembuf);
355: chars -= len;
356: if (chars < 0)
357: {
358: replace_chars (point - chars, len + chars, UndoCQ);
359: replace_chars (point, - chars, UndoCQ + chars + u->num_undochars);
360: chars += u->num_undochars;
361: }
362: else
363: replace_chars (point, len, UndoCQ + chars);
364: RecordChange1 (point, tembuf, len);
365: break;
366:
367: case Uinsert:
368: if (pos < FirstCharacter
369: || pos > NumCharacters + 1)
370: error ("Changes to be undone are outside visible portion of buffer");
371: SetPoint (pos);
372: chars -= len;
373: if (chars < 0)
374: {
375: InsCStr (UndoCQ + chars + u->num_undochars, - chars);
376: InsCStr (UndoCQ, len + chars);
377: chars += u->num_undochars;
378: }
379: else
380: InsCStr (UndoCQ + chars, len);
381: SetPoint (pos);
382: break;
383:
384: case Uunmod:
385: #ifdef CLASH_DETECTION
386: Funlock_buffer ();
387: #endif /* CLASH_DETECTION */
388: bf_cur->save_modified = bf_modified;
389: RedoModes++;
390: break;
391:
392: default:
393: error ("Something rotten in undo");
394: return Qnil;
395: }
396: }
397: LastUndone = i;
398: LastUndoneC = chars;
399: return Qnil;
400: }
401:
402: replace_chars (pos, n, string)
403: register int pos, n;
404: register unsigned char *string;
405: {
406: modify_region (pos, pos + n);
407: while (--n >= 0)
408: {
409: CharAt (pos) = *string++;
410: pos++;
411: }
412: }
413:
414: save_undone_chars (pos, n, p)
415: register int pos, n;
416: register char *p;
417: {
418: if (pos < bf_s1 + 1 && pos + n > bf_s1 + 1)
419: {
420: bcopy (&CharAt (pos), p, bf_s1 + 1 - pos);
421: p += bf_s1 + 1 - pos;
422: n -= bf_s1 + 1 - pos;
423: pos = bf_s1 + 1;
424: }
425:
426: bcopy (&CharAt (pos), p, n);
427: }
428:
429: DEFUN ("undo-start", Fundo_start, Sundo_start, 0, 0, 0,
430: "Move undo-pointer to front of undo records.\n\
431: The next call to undo-more will undo the most recently made change.")
432: ()
433: {
434: register struct UndoData *u = bf_cur->undodata;
435:
436: if (!u)
437: error ("Undo information not kept for this buffer");
438: LastUndoneBuf = bf_cur;
439: NCharsLeft = u->num_undochars;
440: NUndone = 0;
441: LastUndone = FillRQ;
442: LastUndoneC = FillCQ;
443: return Qnil;
444: }
445:
446: syms_of_undo ()
447: {
448: defsubr (&Sundo_start);
449: defsubr (&Sundo_boundary);
450: defsubr (&Sundo_more);
451: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.