4 * Structure of Undo list:
5 * The Undo structure follows any associated data, so the list
6 * can be read backwards: read the structure, then read whatever
7 * data is associated (insert string, file name) and precedes it.
8 * The structure includes the previous value of the modify bit
9 * and a sequence number; successive Undo structures with the
10 * same sequence number represent simultaneous changes.
13 typedef struct Undo Undo;
14 typedef struct Merge Merge;
18 short type; /* Delete, Insert, Filename, Dot, Mark */
19 short mod; /* modify bit */
20 uint seq; /* sequence number */
21 uint p0; /* location of change (unused in f) */
22 uint n; /* # runes in string or file name */
28 uint seq; /* of logged change */
29 uint p0; /* location of change (unused in f) */
30 uint n; /* # runes to delete */
31 uint nbuf; /* # runes to insert */
38 Undosize = sizeof(Undo)/sizeof(Rune)
48 f = emalloc(sizeof(File));
61 return f->seq != f->cleanseq;
65 wrinsert(Buffer *delta, int seq, int mod, uint p0, Rune *s, uint ns)
74 bufinsert(delta, delta->nc, s, ns);
75 bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
79 wrdelete(Buffer *delta, int seq, int mod, uint p0, uint p1)
88 bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
99 if(merge.seq != f->seq)
100 panic("flushmerge seq mismatch");
102 wrdelete(&f->epsilon, f->seq, TRUE, merge.p0, merge.p0+merge.n);
104 wrinsert(&f->epsilon, f->seq, TRUE, merge.p0+merge.n, merge.buf, merge.nbuf);
111 mergeextend(File *f, uint p0)
115 mp0n = merge.p0+merge.n;
117 bufread(&f->b, mp0n, merge.buf+merge.nbuf, p0-mp0n);
118 merge.nbuf += p0-mp0n;
119 merge.n = p0-merge.p0;
124 * like fileundelete, but get the data from arguments
127 loginsert(File *f, uint p0, Rune *s, uint ns)
133 if(ns<0 || ns>STRSIZE)
141 || p0-(merge.p0+merge.n)>Maxmerge /* too far */
142 || merge.nbuf+((p0+ns)-(merge.p0+merge.n))>RBUFSIZE) /* too long */
146 if(!(merge.n == 0 && merge.nbuf == 0 && merge.f == nil))
147 panic("loginsert bad merge state");
148 wrinsert(&f->epsilon, f->seq, TRUE, p0, s, ns);
157 /* append string to merge */
158 runemove(merge.buf+merge.nbuf, s, ns);
163 if(!f->unread && !f->mod)
168 logdelete(File *f, uint p0, uint p1)
180 || p0-(merge.p0+merge.n)>Maxmerge /* too far */
181 || merge.nbuf+(p0-(merge.p0+merge.n))>RBUFSIZE){ /* too long */
190 /* add to deletion */
191 merge.n = p1-merge.p0;
194 if(!f->unread && !f->mod)
199 * like fileunsetname, but get the data from arguments
202 logsetname(File *f, String *s)
210 if(f->unread){ /* This is setting initial file name */
218 /* undo a file name change by restoring old name */
223 u.p0 = 0; /* unused */
226 bufinsert(delta, delta->nc, s->s, s->n);
227 bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
228 if(!f->unread && !f->mod)
234 fileaddtext(File *f, Text *t)
237 f = emalloc(sizeof(File));
240 f->text = realloc(f->text, (f->ntext+1)*sizeof(Text*));
241 f->text[f->ntext++] = t;
247 filedeltext(File *f, Text *t)
251 for(i=0; i<f->ntext; i++)
254 panic("can't find text in filedeltext");
262 memmove(f->text+i, f->text+i+1, (f->ntext-i)*sizeof(Text*));
264 f->curtext = f->text[0];
269 fileinsert(File *f, uint p0, Rune *s, uint ns)
272 panic("internal error: fileinsert");
274 fileuninsert(f, &f->delta, p0, ns);
275 bufinsert(&f->b, p0, s, ns);
281 fileuninsert(File *f, Buffer *delta, uint p0, uint ns)
285 /* undo an insertion by deleting */
291 bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
295 filedelete(File *f, uint p0, uint p1)
297 if(!(p0<=p1 && p0<=f->b.nc && p1<=f->b.nc))
298 panic("internal error: filedelete");
300 fileundelete(f, &f->delta, p0, p1);
301 bufdelete(&f->b, p0, p1);
307 fileundelete(File *f, Buffer *delta, uint p0, uint p1)
313 /* undo a deletion by inserting */
320 for(i=p0; i<p1; i+=n){
324 bufread(&f->b, i, buf, n);
325 bufinsert(delta, delta->nc, buf, n);
328 bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
333 filereadc(File *f, uint q)
339 bufread(&f->b, q, &r, 1);
344 filesetname(File *f, String *s)
346 if(!f->unread) /* This is setting initial file name */
347 fileunsetname(f, &f->delta);
348 Strduplstr(&f->name, s);
354 fileunsetname(File *f, Buffer *delta)
359 /* undo a file name change by restoring old name */
363 u.p0 = 0; /* unused */
365 Strduplstr(&s, &f->name);
369 bufinsert(delta, delta->nc, s.s, s.n);
370 bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
375 fileunsetdot(File *f, Buffer *delta, Range dot)
383 u.n = dot.p2 - dot.p1;
384 bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
388 fileunsetmark(File *f, Buffer *delta, Range mark)
396 u.n = mark.p2 - mark.p1;
397 bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
401 fileload(File *f, uint p0, int fd, int *nulls)
404 panic("undo in file.load unimplemented");
405 return bufload(&f->b, p0, fd, nulls);
409 fileupdate(File *f, int notrans, int toterm)
420 * fix the modification bit
421 * subtle point: don't save it away in the log.
423 * if another change is made, the correct f->mod
424 * state is saved in the undo log by filemark
425 * when setting the dot and mark.
427 * if the change is undone, the correct state is
428 * saved from f in the fileun... routines.
435 fileunsetdot(f, &f->delta, f->prevdot);
436 fileunsetmark(f, &f->delta, f->prevmark);
439 fileundo(f, FALSE, !notrans, &p1, &p2, toterm);
466 bufread(b, up, (Rune*)&u, Undosize);
471 undoseq(File *f, int isundo)
476 return prevseq(&f->epsilon);
480 fileundo(File *f, int isundo, int canredo, uint *q0p, uint *q1p, int flag)
486 Buffer *delta, *epsilon;
489 /* undo; reverse delta onto epsilon, seq decreases */
491 epsilon = &f->epsilon;
494 /* redo; reverse epsilon onto delta, seq increases */
497 stop = 0; /* don't know yet */
501 while(delta->nc > 0){
502 up = delta->nc-Undosize;
503 bufread(delta, up, (Rune*)&u, Undosize);
520 panic("undo unknown u.type");
526 fileundelete(f, epsilon, u.p0, u.p0+u.n);
528 bufdelete(&f->b, u.p0, u.p0+u.n);
529 raspdelete(f, u.p0, u.p0+u.n, flag);
537 fileuninsert(f, epsilon, u.p0, u.n);
541 for(i=0; i<u.n; i+=n){
545 bufread(delta, up+i, buf, n);
546 bufinsert(&f->b, u.p0+i, buf, n);
547 raspinsert(f, u.p0+i, buf, n, flag);
557 fileunsetname(f, epsilon);
561 Strinsure(&f->name, u.n+1);
562 bufread(delta, up, f->name.s, u.n);
571 fileunsetdot(f, epsilon, f->dot.r);
574 f->dot.r.p2 = u.p0 + u.n;
579 fileunsetmark(f, epsilon, f->mark);
582 f->mark.p2 = u.p0 + u.n;
585 bufdelete(delta, up, delta->nc);
596 bufreset(&f->epsilon);
606 bufclose(&f->epsilon);
619 bufdelete(&f->epsilon, 0, f->epsilon.nc);
622 f->prevdot = f->dot.r;
623 f->prevmark = f->mark;