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)
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 fileuninsert(File *f, Buffer *delta, uint p0, uint ns)
273 /* undo an insertion by deleting */
279 bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
283 fileundelete(File *f, Buffer *delta, uint p0, uint p1)
289 /* undo a deletion by inserting */
296 for(i=p0; i<p1; i+=n){
300 bufread(&f->b, i, buf, n);
301 bufinsert(delta, delta->nc, buf, n);
304 bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
309 filereadc(File *f, uint q)
315 bufread(&f->b, q, &r, 1);
320 filesetname(File *f, String *s)
322 if(!f->unread) /* This is setting initial file name */
323 fileunsetname(f, &f->delta);
324 Strduplstr(&f->name, s);
330 fileunsetname(File *f, Buffer *delta)
335 /* undo a file name change by restoring old name */
339 u.p0 = 0; /* unused */
341 Strduplstr(&s, &f->name);
345 bufinsert(delta, delta->nc, s.s, s.n);
346 bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
351 fileunsetdot(File *f, Buffer *delta, Range dot)
359 u.n = dot.p2 - dot.p1;
360 bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
364 fileunsetmark(File *f, Buffer *delta, Range mark)
372 u.n = mark.p2 - mark.p1;
373 bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
377 fileload(File *f, uint p0, int fd, int *nulls)
380 panic("undo in file.load unimplemented");
381 return bufload(&f->b, p0, fd, nulls);
385 fileupdate(File *f, int notrans, int toterm)
396 * fix the modification bit
397 * subtle point: don't save it away in the log.
399 * if another change is made, the correct f->mod
400 * state is saved in the undo log by filemark
401 * when setting the dot and mark.
403 * if the change is undone, the correct state is
404 * saved from f in the fileun... routines.
411 fileunsetdot(f, &f->delta, f->prevdot);
412 fileunsetmark(f, &f->delta, f->prevmark);
415 fileundo(f, FALSE, !notrans, &p1, &p2, toterm);
442 bufread(b, up, (Rune*)&u, Undosize);
447 undoseq(File *f, int isundo)
452 return prevseq(&f->epsilon);
456 fileundo(File *f, int isundo, int canredo, uint *q0p, uint *q1p, int flag)
462 Buffer *delta, *epsilon;
465 /* undo; reverse delta onto epsilon, seq decreases */
467 epsilon = &f->epsilon;
470 /* redo; reverse epsilon onto delta, seq increases */
473 stop = 0; /* don't know yet */
477 while(delta->nc > 0){
478 /* rasp and buffer are in sync; sync with wire if needed */
481 up = delta->nc-Undosize;
482 bufread(delta, up, (Rune*)&u, Undosize);
499 panic("undo unknown u.type");
505 fileundelete(f, epsilon, u.p0, u.p0+u.n);
507 bufdelete(&f->b, u.p0, u.p0+u.n);
508 raspdelete(f, u.p0, u.p0+u.n, flag);
516 fileuninsert(f, epsilon, u.p0, u.n);
520 for(i=0; i<u.n; i+=n){
524 bufread(delta, up+i, buf, n);
525 bufinsert(&f->b, u.p0+i, buf, n);
526 raspinsert(f, u.p0+i, buf, n, flag);
536 fileunsetname(f, epsilon);
540 Strinsure(&f->name, u.n+1);
541 bufread(delta, up, f->name.s, u.n);
550 fileunsetdot(f, epsilon, f->dot.r);
553 f->dot.r.p2 = u.p0 + u.n;
558 fileunsetmark(f, epsilon, f->mark);
561 f->mark.p2 = u.p0 + u.n;
564 bufdelete(delta, up, delta->nc);
575 bufreset(&f->epsilon);
585 bufclose(&f->epsilon);
598 bufdelete(&f->epsilon, 0, f->epsilon.nc);
601 f->prevdot = f->dot.r;
602 f->prevmark = f->mark;