123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331 |
- implement Filem;
- include "common.m";
- sys : Sys;
- dat : Dat;
- utils : Utils;
- buffm : Bufferm;
- textm : Textm;
- editlog: Editlog;
- FALSE, TRUE, XXX, Delete, Insert, Filename, BUFSIZE, Astring : import Dat;
- Buffer, newbuffer : import buffm;
- Text : import textm;
- error : import utils;
- init(mods : ref Dat->Mods)
- {
- sys = mods.sys;
- dat = mods.dat;
- utils = mods.utils;
- buffm = mods.bufferm;
- textm = mods.textm;
- editlog = mods.editlog;
- }
- #
- # Structure of Undo list:
- # The Undo structure follows any associated data, so the list
- # can be read backwards: read the structure, then read whatever
- # data is associated (insert string, file name) and precedes it.
- # The structure includes the previous value of the modify bit
- # and a sequence number; successive Undo structures with the
- # same sequence number represent simultaneous changes.
- #
-
- Undo : adt
- {
- typex : int; # Delete, Insert, Filename
- mod : int; # modify bit
- seq : int; # sequence number
- p0 : int; # location of change (unused in f)
- n : int; # # runes in string or file name
- };
- Undosize : con 8;
- SHM : con 16rffff;
- undotostr(t, m, s, p, n : int) : string
- {
- a := "01234567";
- a[0] = t;
- a[1] = m;
- a[2] = s&SHM;
- a[3] = (s>>16)&SHM;
- a[4] = p&SHM;
- a[5] = (p>>16)&SHM;
- a[6] = n&SHM;
- a[7] = (n>>16)&SHM;
- return a;
- }
- strtoundo(s: string): Undo
- {
- u: Undo;
- u.typex = s[0];
- u.mod = s[1];
- u.seq = s[2]|(s[3]<<16);
- u.p0 = s[4]|(s[5]<<16);
- u.n = s[6]|(s[7]<<16);
- return u;
- }
- nullfile : File;
- File.addtext(f : self ref File, t : ref Text) : ref File
- {
- if(f == nil) {
- f = ref nullfile;
- f.buf = newbuffer();
- f.delta = newbuffer();
- f.epsilon = newbuffer();
- f.ntext = 0;
- f.unread = TRUE;
- }
- oft := f.text;
- f.text = array[f.ntext+1] of ref Text;
- f.text[0:] = oft[0:f.ntext];
- oft = nil;
- f.text[f.ntext++] = t;
- f.curtext = t;
- return f;
- }
- File.deltext(f : self ref File, t : ref Text)
- {
- i : int;
- for(i=0; i<f.ntext; i++)
- if(f.text[i] == t)
- break;
- if (i == f.ntext)
- error("can't find text in File.deltext");
- f.ntext--;
- if(f.ntext == 0){
- f.close();
- return;
- }
- f.text[i:] = f.text[i+1:f.ntext+1];
- if(f.curtext == t)
- f.curtext = f.text[0];
- }
- File.insert(f : self ref File, p0 : int, s : string, ns : int)
- {
- if (p0 > f.buf.nc)
- error("bad assert in File.insert");
- if(f.seq > 0)
- f.uninsert(f.delta, p0, ns);
- f.buf.insert(p0, s, ns);
- if(ns)
- f.mod = TRUE;
- }
- File.uninsert(f : self ref File, delta : ref Buffer, p0 : int, ns : int)
- {
- # undo an insertion by deleting
- a := undotostr(Delete, f.mod, f.seq, p0, ns);
- delta.insert(delta.nc, a, Undosize);
- }
- File.delete(f : self ref File, p0 : int, p1 : int)
- {
- if (p0>p1 || p0>f.buf.nc || p1>f.buf.nc)
- error("bad assert in File.delete");
- if(f.seq > 0)
- f.undelete(f.delta, p0, p1);
- f.buf.delete(p0, p1);
- if(p1 > p0)
- f.mod = TRUE;
- }
- File.undelete(f : self ref File, delta : ref Buffer, p0 : int, p1 : int)
- {
- buf : ref Astring;
- i, n : int;
- # undo a deletion by inserting
- a := undotostr(Insert, f.mod, f.seq, p0, p1-p0);
- m := p1-p0;
- if(m > BUFSIZE)
- m = BUFSIZE;
- buf = utils->stralloc(m);
- for(i=p0; i<p1; i+=n){
- n = p1 - i;
- if(n > BUFSIZE)
- n = BUFSIZE;
- f.buf.read(i, buf, 0, n);
- delta.insert(delta.nc, buf.s, n);
- }
- utils->strfree(buf);
- buf = nil;
- delta.insert(delta.nc, a, Undosize);
- }
- File.setname(f : self ref File, name : string, n : int)
- {
- if(f.seq > 0)
- f.unsetname(f.delta);
- f.name = name[0:n];
- f.unread = TRUE;
- }
- File.unsetname(f : self ref File, delta : ref Buffer)
- {
- # undo a file name change by restoring old name
- a := undotostr(Filename, f.mod, f.seq, 0, len f.name);
- if(f.name != nil)
- delta.insert(delta.nc, f.name, len f.name);
- delta.insert(delta.nc, a, Undosize);
- }
- File.loadx(f : self ref File, p0 : int, fd : ref Sys->FD) : int
- {
- if(f.seq > 0)
- error("undo in file.load unimplemented");
- return f.buf.loadx(p0, fd);
- }
- File.undo(f : self ref File, isundo : int, q0 : int, q1 : int) : (int, int)
- {
- buf : ref Astring;
- i, j, n, up : int;
- stop : int;
- delta, epsilon : ref Buffer;
- u : Undo;
- a := utils->stralloc(Undosize);
- if(isundo){
- # undo; reverse delta onto epsilon, seq decreases
- delta = f.delta;
- epsilon = f.epsilon;
- stop = f.seq;
- }else{
- # redo; reverse epsilon onto delta, seq increases
- delta = f.epsilon;
- epsilon = f.delta;
- stop = 0; # don't know yet
- }
- buf = utils->stralloc(BUFSIZE);
- while(delta.nc > 0){
- up = delta.nc-Undosize;
- delta.read(up, a, 0, Undosize);
- u = strtoundo(a.s);
- if(isundo){
- if(u.seq < stop){
- f.seq = u.seq;
- utils->strfree(buf);
- utils->strfree(a);
- return (q0, q1);
- }
- }else{
- if(stop == 0)
- stop = u.seq;
- if(u.seq > stop){
- utils->strfree(buf);
- utils->strfree(a);
- return (q0, q1);
- }
- }
- case(u.typex){
- Delete =>
- f.seq = u.seq;
- f.undelete(epsilon, u.p0, u.p0+u.n);
- f.mod = u.mod;
- f.buf.delete(u.p0, u.p0+u.n);
- for(j=0; j<f.ntext; j++)
- f.text[j].delete(u.p0, u.p0+u.n, FALSE);
- q0 = u.p0;
- q1 = u.p0;
- Insert =>
- f.seq = u.seq;
- f.uninsert(epsilon, u.p0, u.n);
- f.mod = u.mod;
- up -= u.n;
- # buf = utils->stralloc(BUFSIZE);
- for(i=0; i<u.n; i+=n){
- n = u.n - i;
- if(n > BUFSIZE)
- n = BUFSIZE;
- delta.read(up+i, buf, 0, n);
- f.buf.insert(u.p0+i, buf.s, n);
- for(j=0; j<f.ntext; j++)
- f.text[j].insert(u.p0+i, buf.s, n, FALSE, 0);
- }
- # utils->strfree(buf);
- # buf = nil;
- q0 = u.p0;
- q1 = u.p0+u.n;
- Filename =>
- f.seq = u.seq;
- f.unsetname(epsilon);
- f.mod = u.mod;
- up -= u.n;
- f.name = nil;
- if(u.n == 0)
- f.name = nil;
- else {
- fn0 := utils->stralloc(u.n);
- delta.read(up, fn0, 0, u.n);
- f.name = fn0.s;
- utils->strfree(fn0);
- fn0 = nil;
- }
- * =>
- error(sys->sprint("undo: 0x%ux", u.typex));
- error("");
- }
- delta.delete(up, delta.nc);
- }
- utils->strfree(buf);
- utils->strfree(a);
- buf = nil;
- if(isundo)
- f.seq = 0;
- return (q0, q1);
- }
- File.reset(f : self ref File)
- {
- f.delta.reset();
- f.epsilon.reset();
- f.seq = 0;
- }
- File.close(f : self ref File)
- {
- f.name = nil;
- f.ntext = 0;
- f.text = nil;
- f.buf.close();
- f.delta.close();
- f.epsilon.close();
- editlog->elogclose(f);
- f = nil;
- }
- File.mark(f : self ref File)
- {
- if(f.epsilon.nc)
- f.epsilon.delete(0, f.epsilon.nc);
- f.seq = dat->seq;
- }
- File.redoseq(f : self ref File): int
- {
- u: Undo;
- delta: ref Buffer;
- delta = f.epsilon;
- if(delta.nc == 0)
- return ~0;
- buf := utils->stralloc(Undosize);
- delta.read(delta.nc-Undosize, buf, 0, Undosize);
- u = strtoundo(buf.s);
- utils->strfree(buf);
- return u.seq;
- }
|