diff options
Diffstat (limited to 'appl/wm/samstub.b')
| -rw-r--r-- | appl/wm/samstub.b | 1338 |
1 files changed, 1338 insertions, 0 deletions
diff --git a/appl/wm/samstub.b b/appl/wm/samstub.b new file mode 100644 index 00000000..bdf708ff --- /dev/null +++ b/appl/wm/samstub.b @@ -0,0 +1,1338 @@ +implement Samstub; + +include "sys.m"; +sys: Sys; +fprint, FD, fildes: import sys; + +stderr: ref FD; + +include "draw.m"; +draw: Draw; + +include "samterm.m"; +samterm: Samterm; +Text, Menu, Context, Flayer, Section: import samterm; + +include "samtk.m"; +samtk: Samtk; +panic, whichtext, whichmenu: import samtk; + +include "samstub.m"; + +sendsam: chan of ref Sammsg; +recvsam: chan of ref Sammsg; + +snarflen: int; + +ctxt: ref Context; + +requested: list of (int, int); + +tname := array [] of { + "Tversion", + "Tstartcmdfile", + "Tcheck", + "Trequest", + "Torigin", + "Tstartfile", + "Tworkfile", + "Ttype", + "Tcut", + "Tpaste", + "Tsnarf", + "Tstartnewfile", + "Twrite", + "Tclose", + "Tlook", + "Tsearch", + "Tsend", + "Tdclick", + "Tstartsnarf", + "Tsetsnarf", + "Tack", + "Texit", +}; + +hname := array [] of { + "Hversion", + "Hbindname", + "Hcurrent", + "Hnewname", + "Hmovname", + "Hgrow", + "Hcheck0", + "Hcheck", + "Hunlock", + "Hdata", + "Horigin", + "Hunlockfile", + "Hsetdot", + "Hgrowdata", + "Hmoveto", + "Hclean", + "Hdirty", + "Hcut", + "Hsetpat", + "Hdelname", + "Hclose", + "Hsetsnarf", + "Hsnarflen", + "Hack", + "Hexit", +}; + +init(c: ref Context) +{ + ctxt = c; + sys = load Sys Sys->PATH; + draw = load Draw Draw->PATH; + + stderr = fildes(2); + + samterm = load Samterm Samterm->PATH; + + samtk = load Samtk Samtk->PATH; + samtk->init(ctxt); + + requested = nil; +} + +start(): (ref Samio, chan of ref Sammsg) +{ + sys = load Sys Sys->PATH; + + sys->bind("#C", "/", sys->MAFTER); + + # Allocate a cmd device + ctl := sys->open("/cmd/clone", sys->ORDWR); + if(ctl == nil) { + fprint(stderr, "can't open /cmd/clone\n"); + return (nil, nil); + } + + # Find out which one + buf := array[32] of byte; + n := sys->read(ctl, buf, len buf); + if(n <= 0) { + fprint(stderr, "can't read cmd device\n"); + return (nil, nil); + } + + dir := "/cmd/"+string buf[0:n]; + + # Start the Command + n = sys->fprint(ctl, "exec "+ SAM); + if(n <= 0) { + fprint(stderr, "can't exec %s\n", SAM); + return (nil, nil); + } + + data := sys->open(dir+"/data", sys->ORDWR); + if(data == nil) { + fprint(stderr, "can't open cmd data file\n"); + return (nil, nil); + } + + sendsam = chan of ref Sammsg; + recvsam = chan of ref Sammsg; + + samio := ref Samio(ctl, data, array[1] of byte, 0, 0); + + spawn sender(samio, sendsam); + spawn receiver(samio, recvsam); + + return (samio, recvsam); +} + +sender(samio: ref Samio, c: chan of ref Sammsg) +{ + fprint(ctxt.logfd, "sender started\n"); + for (;;) { + h := <- c; + if (h == nil) return; + buf := array[3 + len h.mdata] of byte; + buf[0] = byte h.mtype; + buf[1] = byte h.mcount; + buf[2] = byte (h.mcount >> 8); + buf[3:] = h.mdata; + sys->write(samio.data, buf, len buf); + } +} + +receiver(samio: ref Samio, msgchan: chan of ref Sammsg) +{ + c: int; + + fprint(ctxt.logfd, "receiver started\n"); + + state := 0; + i := 0; + errs := 0; + + h: ref Sammsg; + + for (;;) { + if (samio.count == 0) { + n := sys->read(samio.data, samio.buffer, len samio.buffer); + if (n <= 0) { + fprint(stderr, "Read error on sam's pipe\n"); + return; + } + samio.index = 0; + samio.count = n; + } + samio.count--; + + c = int samio.buffer[samio.index++]; + + case state { + 0 => + h = ref Sammsg(c, 0, nil); + state++; + continue; + 1 => + h.mcount = c; + state++; + continue; + 2 => + h.mcount = h.mcount|(c<<8); + if (h.mcount > DATASIZE || h.mcount < 0) + panic("receiver: count>DATASIZE"); + if(h.mcount != 0) { + h.mdata = array[h.mcount] of byte; + i = 0; + state++; + continue; + } + 3 => + h.mdata[i++] = byte c; + if(i < h.mcount){ + continue; + } + } + msgchan <- = h; + h = nil; + state = 0; + } +} + +inmesg(h: ref Sammsg): int +{ + + case h.mtype { + + Hversion => + m := h.inshort(0); + fprint(ctxt.logfd, "Hversion: %d\n", m); + + Hbindname => + m := h.inshort(0); + vl := h.invlong(2); + fprint(ctxt.logfd, "Hbindname: %ux, %bux\n", m, vl); + bindname(m, int vl); + + Hcurrent => + m := h.inshort(0); + fprint(ctxt.logfd, "Hcurrent: %d\n", m); + hcurrent(m); + + Hmovname => + m := h.inshort(0); + fprint(ctxt.logfd, "Hmovname: %d, %s\n", m, string h.mdata[2:]); + movename(m, string h.mdata[2:]); + + Hgrow => + m := h.inshort(0); + l1 := h.inlong(2); + l2 := h.inlong(6); + fprint(ctxt.logfd, "Hgrow: %d, %d, %d\n", m, l1, l2); + hgrow(m, l1, l2); + + Hnewname => + m := h.inshort(0); + fprint(ctxt.logfd, "Hnewname: %d\n", m); + newname(m); + + Hcheck0 => + m := h.inshort(0); + fprint(ctxt.logfd, "Hcheck0: %d\n", m); + i := whichmenu(m); + if (i >= 0) { + t := ctxt.menus[i].text; + if (t != nil) + t.lock++; + outTs(Tcheck, m); + } + + Hcheck => + m := h.inshort(0); + fprint(ctxt.logfd, "Hcheck: %d\n", m); + i := whichmenu(m); + if (i >= 0) { + t := ctxt.menus[i].text; + if (t != nil && t.lock) + t.lock--; + hcheck(t); + } + + Hunlock => + fprint(ctxt.logfd, "Hunlock\n"); + clrlock(); + + Hdata => + m := h.inshort(0); + l := h.inlong(2); + fprint(ctxt.logfd, "Hdata: %d, %d, %s\n", + m, l, contract(string h.mdata[6:])); + hdata(m, l, string h.mdata[6:]); + + Horigin => + m := h.inshort(0); + l := h.inlong(2); + fprint(ctxt.logfd, "Horigin: %d, %d\n", m, l); + horigin(m, l); + + Hunlockfile => + m := h.inshort(0); + fprint(ctxt.logfd, "Hunlockfile: %d\n", m); + clrlock(); + + Hsetdot => + m := h.inshort(0); + l1 := h.inlong(2); + l2 := h.inlong(6); + fprint(ctxt.logfd, "Hsetdot: %d, %d, %d\n", m, l1, l2); + hsetdot(m, l1, l2); + + Hgrowdata => + m := h.inshort(0); + l1 := h.inlong(2); + l2 := h.inlong(6); + fprint(ctxt.logfd, "Hgrowdata: %d, %d, %d, %s\n", + m, l1, l2, contract(string h.mdata[10:])); + hgrowdata(m, l1, l2, string h.mdata[10:]); + + Hmoveto => + m := h.inshort(0); + l := h.inlong(2); + fprint(ctxt.logfd, "Hmoveto: %d, %d\n", m, l); + hmoveto(m, l); + + Hclean => + m := h.inshort(0); + fprint(ctxt.logfd, "Hclean: %d\n", m); + hclean(m); + + Hdirty => + m := h.inshort(0); + fprint(ctxt.logfd, "Hdirty: %d\n", m); + hdirty(m); + + Hdelname => + m := h.inshort(0); + fprint(ctxt.logfd, "Hdelname: %d\n", m); + hdelname(m); + + Hcut => + m := h.inshort(0); + l1 := h.inlong(2); + l2 := h.inlong(6); + fprint(ctxt.logfd, "Hcut: %d, %d, %d\n", + m, l1, l2); + hcut(m, l1, l2); + + Hclose => + m := h.inshort(0); + fprint(ctxt.logfd, "Hclose: %d\n", m); + hclose(m); + + Hsetpat => + fprint(ctxt.logfd, "Hsetpat: %s\n", string h.mdata); + samtk->hsetpat(string h.mdata); + + Hsetsnarf => + m := h.inshort(0); + fprint(ctxt.logfd, "Hsetsnarf: %d\n", m); + + Hsnarflen => + snarflen = h.inlong(0); + fprint(ctxt.logfd, "Hsnarflen: %d\n", snarflen); + + Hack => + fprint(ctxt.logfd, "Hack\n"); + outT0(Tack); + + Hexit => + fprint(ctxt.logfd, "Hexit\n"); + return 1; + + -1 => + panic("rcv error"); + + * => + fprint(ctxt.logfd, "type %d\n", h.mtype); + panic("rcv unknown"); + } + return 0; +} + +Sammsg.inshort(h: self ref Sammsg, n: int): int +{ + return ((int h.mdata[n+1])<<8) | + ((int h.mdata[n])); +} + +Sammsg.inlong(h: self ref Sammsg, n: int): int +{ + return ((int h.mdata[n+3])<<24) | + ((int h.mdata[n+2])<<16) | + ((int h.mdata[n+1])<< 8) | + ((int h.mdata[n])); +} + +Sammsg.invlong(h: self ref Sammsg, n: int): big +{ + return ((big h.mdata[n+7])<<56) | + ((big h.mdata[n+6])<<48) | + ((big h.mdata[n+5])<<40) | + ((big h.mdata[n+4])<<32) | + ((big h.mdata[n+3])<<24) | + ((big h.mdata[n+2])<<16) | + ((big h.mdata[n+1])<< 8) | + ((big h.mdata[n])); +} + +Sammsg.outcopy(h: self ref Sammsg, pos: int, data: array of byte) +{ + h.mdata[pos:] = data; +} + +Sammsg.outshort(h: self ref Sammsg, pos: int, s: int) +{ + h.mdata[pos++] = byte s; + h.mdata[pos] = byte (s >> 8); +} + +Sammsg.outlong(h: self ref Sammsg, pos: int, s: int) +{ + h.mdata[pos++] = byte s; + h.mdata[pos++] = byte (s >> 8); + h.mdata[pos++] = byte (s >> 16); + h.mdata[pos] = byte (s >> 24); +} + +Sammsg.outvlong(h: self ref Sammsg, pos: int, s: big) +{ + h.mdata[pos++] = byte s; + h.mdata[pos++] = byte (s >> 8); + h.mdata[pos++] = byte (s >> 16); + h.mdata[pos++] = byte (s >> 24); + h.mdata[pos++] = byte (s >> 32); + h.mdata[pos++] = byte (s >> 40); + h.mdata[pos++] = byte (s >> 48); + h.mdata[pos] = byte (s >> 56); +} + +outT0(t: int) +{ + fprint(ctxt.logfd, "\t\t\t\t\t%s\n", tname[t]); + h := ref Sammsg(t, 0, nil); + sendsam <- = h; +} + +outTs(t, s: int) +{ + fprint(ctxt.logfd, "\t\t\t\t\t%s %ux\n", tname[t], s); + a := array[2] of byte; + h := ref Sammsg(t, 2, a); + h.outshort(0, s); + sendsam <- = h; +} + +outTv(t: int, i: big) +{ + fprint(ctxt.logfd, "\t\t\t\t\t%s %bux\n", tname[t], i); + a := array[8] of byte; + h := ref Sammsg(t, 8, a); + h.outvlong(0, i); + sendsam <- = h; +} + +outTsll(t, m, l1, l2: int) +{ fprint(ctxt.logfd, "\t\t\t\t\t%s %d %d %d\n", tname[t], m, l1, l2); + a := array[10] of byte; + h := ref Sammsg(t, 10, a); + h.outshort(0, m); + h.outlong(2, l1); + h.outlong(6, l2); + sendsam <- = h; +} + +outTsl(t, m, l: int) +{ fprint(ctxt.logfd, "\t\t\t\t\t%s %d %d\n", tname[t], m, l); + a := array[6] of byte; + h := ref Sammsg(t, 6, a); + h.outshort(0, m); + h.outlong(2, l); + sendsam <- = h; +} + +outTsls(t, m, l1, l2: int) +{ fprint(ctxt.logfd, "\t\t\t\t\t%s %d %d %d\n", tname[t], m, l1, l2); + a := array[8] of byte; + h := ref Sammsg(t, 8, a); + h.outshort(0, m); + h.outlong(2, l1); + h.outshort(6, l2); + sendsam <- = h; +} + +outTslS(t, s1, l1: int, s: string) +{ + fprint(ctxt.logfd, "\t\t\t\t\t%s %d %d %s\n", tname[t], s1, l1, s); + a := array[6 + len array of byte s] of byte; + h := ref Sammsg(t, len a, a); + h.outshort(0, s1); + h.outlong(2, l1); + h.outcopy(6, array of byte s); + sendsam <- = h; +} + +newname(tag: int) +{ + menuins(0, "dummy", nil, tag); +} + +bindname(tag, l: int) +{ + if ((m := whichmenu(tag)) < 0) panic("bindname: whichmenu"); + if ((l = whichtext(l)) < 0) panic("bindname: whichtext"); + if (ctxt.menus[m].text != nil) + return; # Already bound + t := ctxt.texts[l]; + t.tag = tag; + for (fls := t.flayers; fls != nil; fls = tl fls) (hd fls).tag = tag; + ctxt.menus[m].text = t; +} + +menuins(m: int, s: string, t: ref Text, tag: int) +{ + newmenus := array [len ctxt.menus+1] of ref Menu; + menu := ref Menu( + tag, # tag + s, # name + t # text + ); + if (m > 0) + newmenus[0:] = ctxt.menus[0:m]; + newmenus[m] = menu; + if (m < len ctxt.menus) + newmenus[m+1:] = ctxt.menus[m:]; + ctxt.menus = newmenus; + + samtk->menuins(m, s); +} + +menudel(m: int) +{ + if (len ctxt.menus == 0 || m >= len ctxt.menus || ctxt.menus[m].text != nil) + panic("menudel"); + newmenus := array [len ctxt.menus - 1] of ref Menu; + newmenus[0:] = ctxt.menus[0:m]; + newmenus[m:] = ctxt.menus[m+1:]; + ctxt.menus = newmenus; + samtk->menudel(m); +} + +outcmd() { + if(ctxt.work != nil) { + fl := ctxt.work; + outTsll(Tworkfile, fl.tag, fl.dot.first, fl.dot.last); + } +} + +hclose(m: int) +{ + i: int; + + # close LAST window of a file + if((m = whichmenu(m)) < 0) panic("hclose: whichmenu"); + t := ctxt.menus[m].text; + if (tl t.flayers != nil) panic("hclose: flayers"); + fl := hd t.flayers; + fl.t = nil; + for (i = 0; i< len ctxt.flayers; i++) + if (ctxt.flayers[i] == fl) break; + if (i == len ctxt.flayers) panic("hclose: ctxt.flayers"); + samtk->chandel(i); + t.flayers = nil; + for (i = 0; i< len ctxt.texts; i++) + if (ctxt.texts[i] == ctxt.menus[m].text) break; + if (i == len ctxt.texts) panic("hclose: ctxt.texts"); + ctxt.texts[i:] = ctxt.texts[i+1:]; + ctxt.texts = ctxt.texts[:len ctxt.texts - 1]; + ctxt.menus[m].text = nil; + ctxt.which = nil; + samtk->focus(hd ctxt.cmd.flayers); +} + +close(win, tag: int) +{ + nfls: list of ref Flayer; + + if ((m := whichtext(tag)) < 0) panic("close: text"); + t := ctxt.texts[m]; + if ((m = whichmenu(tag)) < 0) panic("close: menu"); + if (len t.flayers == 1) { + outTs(Tclose, tag); + setlock(); + return; + } + fl := ctxt.flayers[win]; + nfls = nil; + for (fls := t.flayers; fls != nil; fls = tl fls) + if (hd fls != fl) nfls = hd fls :: nfls; + t.flayers = nfls; + samtk->chandel(win); + fl.t = nil; + samtk->settitle(t, ctxt.menus[m].name); + ctxt.which = nil; +} + +hdelname(m: int) +{ + # close LAST window of a file + if((m = whichmenu(m)) < 0) panic("hdelname: whichmenu"); + if (ctxt.menus[m].text != nil) panic("hdelname: text"); + ctxt.menus[m:] = ctxt.menus[m+1:]; + ctxt.menus = ctxt.menus[:len ctxt.menus - 1]; + samtk->menudel(m); + ctxt.which = nil; +} + +hdirty(m: int) +{ + if((m = whichmenu(m)) < 0) panic("hdirty: whichmenu"); + if (ctxt.menus[m].text == nil) panic("hdirty: text"); + ctxt.menus[m].text.state |= Samterm->Dirty; + samtk->settitle(ctxt.menus[m].text, ctxt.menus[m].name); +} + +hclean(m: int) +{ + if((m = whichmenu(m)) < 0) panic("hclean: whichmenu"); + if (ctxt.menus[m].text == nil) panic("hclean: text"); + ctxt.menus[m].text.state &= ~Samterm->Dirty; + samtk->settitle(ctxt.menus[m].text, ctxt.menus[m].name); +} + +movename(tag: int, s: string) +{ + i := whichmenu(tag); + if (i < 0) panic("movename: whichmenu"); + + t := ctxt.menus[i].text; + + ctxt.menus[i].text = nil; # suppress panic in menudel + menudel(i); + + if(t == ctxt.cmd) + i = 0; + else { + if (len ctxt.menus > 0 && ctxt.menus[0].text == ctxt.cmd) + i = 1; + else + i = 0; + for(; i < len ctxt.menus; i++) { + if (s < ctxt.menus[i].name) + break; + } + } + if (t != nil) samtk->settitle(t, s); + menuins(i, s, t, tag); +} + +hcheck(t: ref Text) +{ + if (t == nil) { + fprint(ctxt.logfd, "hcheck: no text in menu entry\n"); + return; + } + for (fls := t.flayers; fls != nil; fls = tl fls) { + fl := hd fls; + scrollto(fl, fl.scope.first); + } +} + +setlock() +{ + ctxt.lock++; + samtk->allflayers("cursor -bitmap cursor.wait"); +} + +clrlock() +{ + if (ctxt.lock > 0) + ctxt.lock--; + else + fprint(ctxt.logfd, "lock: wasn't locked\n"); + if (ctxt.lock == 0) + samtk->allflayers("cursor -default; update"); +} + +hcut(m, where, howmuch: int) +{ + if((m = whichmenu(m)) < 0) panic("hcut: whichmenu"); + t := ctxt.menus[m].text; + if (t == nil) panic("hcut -- no text"); + +# sctdump(t.sects, "Hcut, before"); + t.nrunes -= howmuch; + t.sects = sctdelete(t.sects, where, howmuch); +# sctdump(t.sects, "Hcut, after"); + for (fls := t.flayers; fls != nil; fls = tl fls) { + fl := hd fls; + if (where < fl.scope.first) { + if (where + howmuch <= fl.scope.first) + fl.scope.first -= howmuch; + else + fl.scope.first = where; + } + if (where < fl.scope.last) { + if (where + howmuch <= fl.scope.last) + fl.scope.last -= howmuch; + else + fl.scope.last = where; + } + } +} + +hgrow(tag, l1, l2: int) +{ + if((m := whichmenu(tag)) < 0) panic("hgrow: whichmenu"); + t := ctxt.menus[m].text; + grow(t, l1, l2); +} + +hdata(m, l: int, s: string) +{ + nr: list of (int, int); + + if((m = whichmenu(m)) < 0) panic("hdata: whichmenu"); + t := ctxt.menus[m].text; + if (t == nil) panic("hdata -- no text"); + if (s != "") { + t.sects = sctput(t.sects, l, s); + updatefls(t, l, s); + } + for (nr = nil; requested != nil; requested = tl requested) { + (r1, r2) := hd requested; + if (r1 != m || r2 != l) + nr = (r1, r2) :: nr; + } + requested = nr; + clrlock(); +} + +hgrowdata(tag, l1, l2: int, s: string) +{ + if((m := whichmenu(tag)) < 0) panic("hgrow: whichmenu"); + t := ctxt.menus[m].text; + if (t == nil) panic("hdata -- no text"); + grow(t, l1, l2); + t.sects = sctput(t.sects, l1, s); + updatefls(t, l1, s); +} + +hsetdot(m, l1, l2: int) +{ + if((m = whichmenu(m)) < 0) panic("hsetdot: whichmenu"); + t := ctxt.menus[m].text; + if (t == nil || t.flayers == nil) panic("hsetdot -- no text"); + samtk->setdot(hd t.flayers, l1, l2); +} + +hcurrent(tag: int) +{ + if ((i := whichmenu(tag)) < 0) panic("hcurrent: whichmenu"); + if (ctxt.menus[i].text == nil) { + n := startfile(tag); + ctxt.menus[i].text = ctxt.texts[n]; + if (ctxt.menus[i].name != nil) + samtk->settitle(ctxt.texts[n], ctxt.menus[i].name); + } + ctxt.work = hd ctxt.menus[i].text.flayers; +} + +hmoveto(m, l: int) +{ + if((m = whichmenu(m)) < 0) panic("hmoveto: whichmenu"); + t := ctxt.menus[m].text; + fl := hd t.flayers; + if (fl.scope.first <= l && + (l < fl.scope.last || fl.scope.last == fl.scope.first)) + return; + (n, p) := sctrevcnt(t.sects, l, fl.lines/2); +# fprint(ctxt.logfd, "hmoveto: (n, p) = (%d, %d)\n", n, p); + if (n < 0) { + outTsll(Torigin, t.tag, l, fl.lines/2); + setlock(); + return; + } + scrollto(fl, p); +} + +startcmdfile() +{ + t := ctxt.tag++; + n := newtext(t, 1); + ctxt.cmd = ctxt.texts[n]; + outTv(Tstartcmdfile, big t); +} + +startnewfile() +{ + t := ctxt.tag++; + n := newtext(t, 0); + outTv(Tstartnewfile, big t); +} + +startfile(tag: int): int +{ + n := newtext(tag, 0); + outTv(Tstartfile, big tag); + setlock(); + return n; +} + +horigin(m, l: int) +{ + if((m = whichmenu(m)) < 0) panic("hmoveto: whichmenu"); + t := ctxt.menus[m].text; + fl := hd t.flayers; + scrollto(fl, l); + clrlock(); +} + +scrollto(fl: ref Flayer, where: int) +{ + s: string; + n: int; + + tag := fl.tag; + if ((i := whichtext(tag)) < 0) panic("scrollto: whichtext"); + t := ctxt.texts[i]; + + samtk->flclear(fl); + (n, s) = sctgetlines(t.sects, where, fl.lines); + fl.scope.first = where; + fl.scope.last = where + len s; + if (s != "") + samtk->flinsert(fl, where, s); + if (n == 0) { + samtk->setscrollbar(t, fl); + } else { + (h, l) := scthole(t, fl.scope.last); + fl.scope.last = h; + if (l > 0) + outrequest(tag, h, l); + else + if (fl.scope.first > t.nrunes) { + fl.scope.first = t.nrunes; + fl.scope.last = t.nrunes; + samtk->setscrollbar(t, fl); + } + } +} + +scthole(t: ref Text, f: int): (int, int) +{ + p := 0; + h := -1; + l := 0; + for (scts := t.sects; scts != nil; scts = tl scts) { + sct := hd scts; + nr := sct.nrunes; + nt := len sct.text; + if (h >= 0) { + if (sct.text == "") { + l += nr; + if (l >= 512) return (h,512); + } else + return (h,l); + } + if (h < 0 && f < nr) { + if (nt < nr) { + if (f < nt) { + h = p + nt; + l = nr - nt; + } else { + h = p + f; + l = nr - f; + } + if (l >= 512) return (h,512); + } + } + p += sct.nrunes; + f -= sct.nrunes; + } + if (h == -1) return (p, 0); + return (h, l); +} + +# return (x, p): x = -1: p -> hole; x = 0: p -> line n; x > 0: p -> eof +sctlinecount(t: ref Text, pos, n: int): (int, int) +{ + i: int; + + p := 0; + for (scts := t.sects; scts != nil; scts = tl scts) { + sct := hd scts; + nr := sct.nrunes; + nt := len sct.text; + if (pos < nr) { + if (pos > 0) i = pos; else i = 0; + while (i < nt) { + if (sct.text[i++] == '\n') n--; + if (n == 0) return (0, p + i); + } + if (nt < nr) return (-1, p + nt); + } + p += sct.nrunes; + pos -= sct.nrunes; + } + return (n, p); +} + +sctrevcnt(scts: list of ref Section, pos, n: int): (int, int) +{ + if (scts == nil) return (n, 0); + sct := hd scts; + scts = tl scts; + nt := len sct.text; + nr := sct.nrunes; + if (pos >= nr) { + (n, pos) = sctrevcnt(scts, pos - nr, n); + pos += nr; + } + if (n > 0) { + if (nt < nr && pos > nt) + return(-1, pos); + for (i := pos-1; i >= 0; i--) { + if (sct.text[i] == '\n') n--; + if (n == 0) break; + } + return (n, i + 1); + } + return (n, pos); +} + +insertfls(t: ref Text, l: int, s: string) +{ + for (fls := t.flayers; fls != nil; fls = tl fls) { + fl := hd fls; + if (l < fl.scope.first || l > fl.scope.last) continue; + samtk->flinsert(fl, l, s); + samtk->setscrollbar(t, fl); + fl.scope.last += len s; + } +} + +updatefls(t: ref Text, l: int, s: string) +{ + for (fls := t.flayers; fls != nil; fls = tl fls) { + fl := hd fls; + if (l < fl.scope.first || l > fl.scope.last) continue; + samtk->flinsert(fl, l, s); + (x, p) := sctlinecount(t, fl.scope.first, fl.lines); + fl.scope.last = p; + if (x >= 0) { + if (p > l + len s) { + samtk->flinsert(fl, l + len s, + sctget(t.sects, l + len s, p)); + } + if (x == 0) + samtk->fldelexcess(fl); + } else { + (h1, h2) := scthole(t, l); + fl.scope.last = h1; + if (h2 > 0) { + outrequest(t.tag, h1, h2); + continue; + } else { + panic("Can't happen ??"); + } + } + samtk->setscrollbar(t, fl); + } +} + +outrequest(tag, h1, h2: int) { + for (l := requested; l != nil; l = tl l) { + (r1, r2) := hd l; + if (r1 == tag && r2 == h1) return; + } + outTsls(Trequest, tag, h1, h2); + requested = (tag, h1) :: requested; + setlock(); +} + +deletefls(t: ref Text, pos, nbytes: int) +{ + for (fls := t.flayers; fls != nil; fls = tl fls) { + fl := hd fls; + if (pos >= fl.scope.last) continue; + if (pos + nbytes <= fl.scope.first || pos >= fl.scope.last) { + fl.scope.first -= nbytes; + fl.scope.last -= nbytes; + continue; + } + samtk->fldelete(fl, pos, pos + nbytes); + (x, p) := sctlinecount(t, fl.scope.first, fl.lines); + if (x >= 0 && p > fl.scope.last) { + samtk->flinsert(fl, fl.scope.last, + sctget(t.sects, fl.scope.last, p)); + fl.scope.last = p; + } else { + fl.scope.last = p; + (h1, h2) := scthole(t, fl.scope.last); + if (h2 > 0) + outrequest(t.tag, h1, h2); + } + samtk->setscrollbar(t, fl); + } +} + +contract(s: string): string +{ + if (len s < 32) + cs := s; + else + cs = s[0:16] + " ... " + s[len s - 16:]; + for (i := 0; i < len cs; i++) + if (cs[i] == '\n') cs[i] = '\u008a'; + return cs; +} + +cleanout() +{ + if ((fl := ctxt.which) == nil) return; + if ((i := whichtext(fl.tag)) < 0) panic("cleanout: whichtext"); + t := ctxt.texts[i]; + + if (fl.typepoint >= 0 && fl.dot.first > fl.typepoint) { + s := sctget(t.sects, fl.typepoint, fl.dot.first); + outTslS(Samstub->Ttype, fl.tag, fl.typepoint, s); + t.state &= ~Samterm->LDirty; + } + fl.typepoint = -1; +} + +newtext(tag, tp: int): int +{ + n := len ctxt.texts; + t := ref Text( + tag, # tag + 0, # lock + samtk->newflayer(tag, tp) :: nil, # flayers + 0, # nrunes + nil, # sects + 0 # state + ); + texts := array [n + 1] of ref Text; + texts[0:] = ctxt.texts; + texts[n] = t; + ctxt.texts = texts; + samtk->newcur(t, hd t.flayers); + return n; +} + +keypress(key: string) +{ + # Find text and flayer + fl := ctxt.which; + tag := fl.tag; + if ((i := whichtext(tag)) < 0) panic("keypress: whichtext"); + t := ctxt.texts[i]; + + if (fl.dot.last != fl.dot.first) { + cut(t, fl); + } + + case (key) { + "\b" => + if (t.nrunes == 0 || fl.dot.first == 0) + return; + fl.dot.first--; + if (fl.typepoint >= 0 && fl.dot.first >= fl.typepoint) { + t.nrunes -= fl.dot.last - fl.dot.first; + t.sects = sctdelete(t.sects, fl.dot.first, fl.dot.last - fl.dot.first); + deletefls(t, fl.dot.first, fl.dot.last - fl.dot.first); + if (fl.dot.first == fl.typepoint) { + fl.typepoint = -1; + t.state &= ~Samterm->LDirty; + if ((i = whichmenu(tag)) < 0) + panic("keypress: whichmenu"); + samtk->settitle(t, ctxt.menus[i].name); + } + } else { + cut(t, fl); + } + * => + if (fl.typepoint < 0) { + fl.typepoint = fl.dot.first; + t.state |= Samterm->LDirty; + if ((i = whichmenu(tag)) < 0) + panic("keypress: whichmenu"); + samtk->settitle(t, ctxt.menus[i].name); + } + if (fl.dot.first > t.nrunes) + panic("keypress -- cursor > file len"); + t.sects = sctmakeroom(t.sects, fl.dot.first, len key); + t.nrunes += len key; + t.sects = sctput(t.sects, fl.dot.first, key); + insertfls(t, fl.dot.first, key); + f := fl.dot.first + len key; + samtk->setdot(fl, f, f); + if (key == "\n") { + if (f >= fl.scope.last) { + (n, p) := sctrevcnt(t.sects, f-1, 2*fl.lines/3); + if (n < 0) { + outTsll(Torigin, t.tag, f-1, 2*fl.lines/3); + setlock(); + } else { + scrollto(fl, p); + } + } + if (t == ctxt.cmd && fl.dot.last == t.nrunes) { + outcmd(); + setlock(); + } + cleanout(); + } + } + return; +} + +cut(t: ref Text, fl: ref Flayer) +{ + if (fl.typepoint >= 0) panic("cut: typepoint"); + outTsll(Tcut, fl.tag, fl.dot.first, fl.dot.last); + t.nrunes -= fl.dot.last - fl.dot.first; + t.sects = sctdelete(t.sects, fl.dot.first, fl.dot.last - fl.dot.first); + deletefls(t, fl.dot.first, fl.dot.last - fl.dot.first); +} + +paste(t: ref Text, fl: ref Flayer) +{ + if (fl.typepoint >= 0) panic("paste: typepoint"); + if (snarflen == 0) return; + if (fl.dot.first < fl.dot.last) cut(t, fl); + outTsl(Tpaste, fl.tag, fl.dot.first); +} + +snarf(nil: ref Text, fl: ref Flayer) +{ + if (fl.typepoint >= 0) panic("snarf: typepoint"); + if (fl.dot.first == fl.dot.last) return; + snarflen = fl.dot.last - fl.dot.first; + outTsll(Tsnarf, fl.tag, fl.dot.first, fl.dot.last); +} + +look(nil: ref Text, fl: ref Flayer) +{ + if (fl.typepoint >= 0) panic("look: typepoint"); + outTsll(Tlook, fl.tag, fl.dot.first, fl.dot.last); + setlock(); +} + +send(nil: ref Text, fl: ref Flayer) +{ + if (fl.typepoint >= 0) panic("send: typepoint"); + outcmd(); + outTsll(Tsend, fl.tag, fl.dot.first, fl.dot.last); + setlock(); +} + +search(nil: ref Text, fl: ref Flayer) +{ + if (fl.typepoint >= 0) panic("search: typepoint"); + outcmd(); + outT0(Tsearch); + setlock(); +} + +zerox(t: ref Text) +{ + fl := samtk->newflayer(t.tag, ctxt.cmd == t); + t.flayers = fl :: t.flayers; + m := whichmenu(t.tag); + samtk->settitle(t, ctxt.menus[m].name); + samtk->newcur(t, fl); + scrollto(fl, 0); +} + +sctget(scts: list of ref Section, p1, p2: int): string +{ + while (scts != nil) { + sct := hd scts; scts = tl scts; + ln := len sct.text; + if (p1 < sct.nrunes) { + if (ln < sct.nrunes && p2 > ln) { + sctdump(scts, "panic"); + panic("sctget - asking for a hole"); + } + if (p2 > sct.nrunes) { + s := sct.text[p1:]; + return s + sctget(scts, 0, p2 - ln); + } + return sct.text[p1:p2]; + } + p1 -= sct.nrunes; + p2 -= sct.nrunes; + } + return ""; +} + +sctgetlines(scts: list of ref Section, p, n: int): (int, string) +{ + s := ""; + while (scts != nil) { + sct := hd scts; scts = tl scts; + ln := len sct.text; + if (p < sct.nrunes) { + if (p > ln) return (n, s); + if (p > 0) b := p; else b = 0; + for (i := b; i < ln && n > 0; ) { + if (sct.text[i++] == '\n') n--; + } + if ( i > b) + s = s + sct.text[b:i]; + if (n == 0 || ln < sct.nrunes) return (n, s); + } + p -= sct.nrunes; + } + return (n, s); +} + +sctput(scts: list of ref Section, pos: int, s: string): list of ref Section +{ + # There should be a hole to receive text + if (scts == nil && s != "") panic("sctput: scts is nil\n"); + sct := hd scts; + l := len sct.text; + if (sct.nrunes <= pos) { + return sct :: sctput(tl scts, pos-sct.nrunes, s); + } + if (pos < l) { + sctdump(scts, "panic"); + panic("sctput: overwriting"); + } + if (pos == l) { + if (sct.nrunes < l + len s) { + sct.text += s[:sct.nrunes-l]; + return sct :: sctput(tl scts, 0, s[sct.nrunes-l:]); + } + sct.text += s; + return sct :: tl scts; + } + nrunes := sct.nrunes; + sct.nrunes = pos; + if (nrunes < pos + len s) + return sct :: + ref Section(nrunes-pos, s[:nrunes-pos]) :: + sctput(tl scts, 0, s[nrunes-pos:]); + return sct :: ref Section(nrunes-pos, s) :: tl scts; +} + +sctmakeroom(scts: list of ref Section, pos: int, l: int): list of ref Section +{ + if (scts == nil) { + if (pos) panic("sctmakeroom: beyond end of sections"); + return ref Section(l, nil) :: nil; + } + sct := hd scts; + if (sct.nrunes < pos) + return sct :: sctmakeroom(tl scts, pos-sct.nrunes, l); + if (len sct.text <= pos) { + # just add to the hole at end of section + sct.nrunes += l; + return sct :: tl scts; + } + if (pos == 0) { + # text is non-nil! + bsct := ref Section(l, nil); + return bsct :: scts; + } + bsct := ref Section(pos + l, sct.text[0:pos]); + esct := ref Section(sct.nrunes-pos, sct.text[pos:]); + return bsct :: esct :: tl scts; +} + +sctdelete(scts: list of ref Section, start, nbytes: int): list of ref Section +{ + if (nbytes == 0) return scts; + if (scts == nil) panic("sctdelete: at eof"); + sct := hd scts; + scts = tl scts; + nrunes := sct.nrunes; + if (start + nbytes < len sct.text) { + sct.text = sct.text[0:start] + sct.text[start+nbytes:]; + sct.nrunes -= nbytes; + return sct :: scts; + } + if (start < nrunes) { + if (start > 0) { + if (start < len sct.text) + sct.text = sct.text[0:start]; + if (start + nbytes <= nrunes) { + sct.nrunes -= nbytes; + return sct :: scts; + } + sct.nrunes = start; + return sct :: sctdelete(scts, 0, nbytes-nrunes+start); + } + if (nbytes < nrunes) { + sct.text = ""; + sct.nrunes -= nbytes; + return sct :: scts; + } + return sctdelete(scts, 0, nbytes - nrunes); + } + return sct :: sctdelete(scts, start - nrunes, nbytes); +} + +grow(t: ref Text, at, l: int) +{ +# sctdump(t.sects, "grow, before"); + t.sects = sctmakeroom(t.sects, at, l); + t.nrunes += l; +# sctdump(t.sects, "grow, after"); + for (fls := t.flayers; fls != nil; fls = tl fls) { + fl := hd fls; + if (at < fl.scope.first) fl.scope.first += l; + if (at < fl.scope.last) fl.scope.last += l; + } +} + +findhole(t: ref Text): (int, int) +{ + for (fls := t.flayers; fls != nil; fls = tl fls) { + (h, l) := scthole(t, (hd fls).scope.first); + if (l > 0) return (h, l); + } + return (0, 0); +} + +sctdump(scts: list of ref Section, s: string) +{ + fprint(ctxt.logfd, "Sctdump: %s\n", s); + p := 0; + while (scts != nil) { + sct := hd scts; scts = tl scts; + fprint(ctxt.logfd, "\tsct@%4d len=%4d len txt=%4d: %s\n", + p, sct.nrunes, len sct.text, contract(sct.text)); + p += sct.nrunes; + } + fprint(ctxt.logfd, "\tend@%4d\n", p); +} |
