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