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