head 1.1;A access ; symbols ; locks ; strict; comment @ * @; 1.1 date 85.03.31.18.11.40; author bbanerje; state Exp; branches ; next ; desc @@ 1.1 log @Initial revision @ text @/* Support routines for the undo facility. Copyright (C) 1984 Fen Labalme and Richard Stallman This file is part of GNU Emacs. GNU Emacs is distributed in the hope that it will be useful, but without any warranty. No author or distributor accepts responsibility to anyone for the consequences of using it or for whether it serves any particular purpose or works at all, unless he says so in writing. Everyone is granted permission to copy, modify and redistribute GNU Emacs, but only under the conditions described in the document "GNU Emacs copying permission notice". An exact copy of the document is supposed to have been given to you along with GNU Emacs so that you can know how you may redistribute it all. It should be in a file named COPYING. Among other things, the copyright notice and this notice must be preserved on all copies. */ #include "config.h" #include "undo.h" #include "lisp.h" #include "commands.h" #include "buffer.h" /* Access undo records of current buffer */ /* These assume that `u' points to the buffer's undodata */ #define UndoRQ (u->undorecs) #define UndoCQ (u->undochars) #define FillRQ (u->nextrec) #define FillCQ (u->nextchar) /* Record last undo record made, and what buffer made in */ static struct UndoRec *LastUndoRec; static struct buffer *LastUndoBuf; /* Record progress of undoing */ static NUndone; static NCharsLeft; static LastUndoneC; static LastUndone; static struct buffer *LastUndoneBuf; Lisp_Object Fundo_boundary (); make_undo_records (b) struct buffer *b; { register struct UndoData *u; b->undodata = u = (struct UndoData *) malloc (sizeof (struct UndoData)); u->undorecs = (struct UndoRec *) malloc (sizeof (struct UndoRec) * InitNUndoR); u->undochars = (char *) malloc (InitNUndoC); u->undorecs[InitNUndoR - 1].kind = Unundoable; u->nextrec = 0; u->nextchar = 0; u->num_undorecs = InitNUndoR; u->num_undochars = InitNUndoC; } free_undo_records (b) struct buffer *b; { register struct UndoData *u = b->undodata; free (u->undorecs); free (u->undochars); free (u); } struct UndoRec * NewUndo (kind, pos, len) enum Ukinds kind; { register struct UndoData *u = bf_cur->undodata; register struct UndoRec *p = &UndoRQ[FillRQ]; register struct UndoRec *np; FillRQ++; if (FillRQ >= NUndoR) FillRQ = 0; else if (FillRQ >= u->num_undorecs) { np = (struct UndoRec *) realloc (UndoRQ, NUndoR * sizeof *p); if (np) { UndoRQ = np; p = &UndoRQ[FillRQ-1]; u->num_undorecs = NUndoR; np[NUndoR - 1].kind = Unundoable; } else FillRQ = 0; } UndoRQ[FillRQ].kind = Unundoable; p -> kind = kind; p -> pos = pos; p -> len = len; LastUndoRec = p; LastUndoBuf = bf_cur; if (kind != Uboundary) LastUndone = -1; return p; } RecordInsert (pos, n) { register struct UndoRec *p = LastUndoRec; if (!bf_cur->undodata) return; if (LastUndoBuf != bf_cur) { Fundo_boundary (); p = 0; } if (p && p -> kind == Udelete && p -> pos + p -> len == pos) p -> len += n; else NewUndo (Udelete, pos, n); } RecordDelete (pos, n) int pos, n; { register struct UndoRec *p = LastUndoRec; register char *cp; if (!bf_cur->undodata) return; if (LastUndoBuf != bf_cur) { Fundo_boundary (); p = 0; } if (p && p -> kind == Uinsert && p -> pos + p -> len == pos) p -> len += n; else NewUndo (Uinsert, pos, n); record_chars (pos, n); } record_chars (pos, n) register int pos, n; { register char *cp; register struct UndoData *u = bf_cur->undodata; NCharsLeft -= n; cp = &UndoCQ[FillCQ]; while (--n >= 0) { *cp++ = CharAt (pos); if (++FillCQ >= u->num_undochars) { if (FillCQ >= NUndoC) { FillCQ = 0; cp = UndoCQ; } else { cp = (char *) realloc (UndoCQ, NUndoC); if (!cp) memory_full (); UndoCQ = cp; cp += FillCQ; NCharsLeft += NUndoC - u->num_undochars; u->num_undochars = NUndoC; } } pos++; } } RecordChange (pos, n) int pos, n; { register struct UndoRec *p = LastUndoRec; if (!bf_cur->undodata) return; if (LastUndoBuf != bf_cur) { Fundo_boundary (); p = 0; } if (p && p -> kind == Uchange && p -> pos + p -> len == pos) p -> len += n; else NewUndo (Uchange, pos, n); record_chars (pos, n); } ReplaceChars (pos, n, string) register int pos, n; register unsigned char *string; { modify_region (pos, pos + n); while (--n >= 0) { CharAt (pos) = *string++; pos++; } } DoneIsDone () { register struct UndoData *u = bf_cur->undodata; register struct UndoRec *p; if (!u) return 0; p = &UndoRQ[(FillRQ + u->num_undorecs - 1) % u->num_undorecs]; if (p->kind != Unundoable) NewUndo (Unundoable, dot, 0); return 0; } DEFUN ("undo-boundary", Fundo_boundary, Sundo_boundary, 0, 0, 0, "Mark a boundary between units of undo.\n\ An undo command will stop at this point,\n\ but another undo command will undo to the previous boundary.") () { register struct UndoData *u = bf_cur->undodata; register struct UndoRec *p; if (!u) return Qnil; p = &UndoRQ[(FillRQ + u->num_undorecs - 1) % u->num_undorecs]; if (p->kind != Uboundary) NewUndo (Uboundary, dot, 0); return Qnil; } DEFUN ("undo-more", Fundo_more, Sundo_more, 1, 1, 0, "Undo back N undo-boundaries beyond what was already undone recently.\n\ Call undo-start to get ready to undo recent changes,\n\ then call undo-more one or more times to undo them.") (pfxarg) Lisp_Object pfxarg; { register struct UndoData *u = bf_cur->undodata; register int n = 0; register int chars; register int i = LastUndone; register int arg = XINT (pfxarg); register int len, pos; if (!u) return Qnil; if (LastUndoneBuf != bf_cur || i == -1) error ("Cannot undo more: changes have been made since the last undo"); while (1) { while (UndoRQ[i = (!i ? u->num_undorecs-1 : i-1)].kind != Uboundary) { if (UndoRQ[i].kind == Uinsert && (NCharsLeft -= UndoRQ[i].len) < 0 || UndoRQ[i].kind == Unundoable || NUndone >= u->num_undorecs) error ("No further undo information available"); NUndone++; n++; } NUndone++; n++; if (--arg <= 0) break; } i = LastUndone; chars = LastUndoneC; while (--n >= 0) { if (!i) i = u->num_undorecs; i--; len = UndoRQ[i].len; pos = UndoRQ[i].pos; switch (UndoRQ[i].kind) { case Uboundary: break; case Udelete: if (pos < FirstCharacter || pos + len > NumCharacters + 1) error ("Changes to be undone are outside visible portion of buffer"); SetDot (pos); del_range (dot, dot + len); break; case Uchange: if (pos < FirstCharacter || pos + len > NumCharacters + 1) error ("Changes to be undone are outside visible portion of buffer"); SetDot (pos); RecordChange (dot, len); chars -= len; if (chars < 0) { ReplaceChars (dot, len + chars, UndoCQ); DotRight (len + chars); len = -chars; chars += u->num_undochars; } ReplaceChars (dot, len, UndoCQ + chars); break; case Uinsert: if (pos < FirstCharacter || pos > NumCharacters + 1) error ("Changes to be undone are outside visible portion of buffer"); SetDot (pos); chars -= len; if (chars < 0) { InsCStr (UndoCQ, len + chars); len = -chars; chars += u->num_undochars; } InsCStr (UndoCQ + chars, len); break; default: error ("Something rotten in undo"); return Qnil; } } LastUndone = i; LastUndoneC = chars; return Qnil; } DEFUN ("undo-start", Fundo_start, Sundo_start, 0, 0, 0, "Move undo-pointer to front of undo records.\n\ The next call to undo-more will undo the most recently made change.") () { register struct UndoData *u = bf_cur->undodata; register int nundorecs = u->num_undorecs; if (!u) error ("Undo information not kept for this buffer"); LastUndoneBuf = bf_cur; NCharsLeft = u->num_undochars; NUndone = 0; LastUndone = FillRQ; LastUndoneC = FillCQ; return Qnil; } syms_of_undo () { defsubr (&Sundo_start); defsubr (&Sundo_boundary); defsubr (&Sundo_more); } @