implement Pimpl; include "sys.m"; sys: Sys; sprint, fprint: import sys; include "styx.m"; include "styxservers.m"; Styxserver: import Styxservers; include "daytime.m"; include "dat.m"; dat: Dat; mnt, evc, Qdir, debug, appl, slash: import dat; include "string.m"; str: String; splitl: import str; include "names.m"; names: Names; dirname: import names; include "error.m"; err: Error; checkload, panic, stderr: import err; include "tbl.m"; tbl: Tbl; Table: import tbl; include "mpanel.m"; Amax, Panel, Repl, Tappl, Trepl: import Panels; Aclean, Afont, Asel, Amark, Ascroll, Atab: con Amax + iota; init(d: Dat): list of string { dat = d; sys = dat->sys; err = dat->err; str = dat->str; names = dat->names; return list of {"text:", "button:", "label:", "tag:", "tbl:"}; } pinit(p: ref Panel) { (t, n) := splitl(p.name, ":"); if (n != nil) n = n[1:]; else n = ""; case t { * => p.data = array of byte ""; "button" or "label" => p.data = array of byte n; } } rinit(p: ref Panel, r: ref Repl) { (t, nil) := splitl(p.name, ":"); nfont := "font R"; case t { "tbl" => nfont = "font R"; "label" or "button" or "tag" => nfont = "font B"; * => nfont = "font R"; } attrs := array[] of { "clean", nfont, "sel 0 0", "mark 0", "noscroll", "tab 4"}; nattrs := array[len r.attrs + len attrs] of string; nattrs[0:] = r.attrs; nattrs[len r.attrs:] = attrs; r.attrs = nattrs; } newdata(p: ref Panel): string { for (i := 0; i < len p.data; i++) if (p.data[i] == byte 0) return "UTF 0 not allowed"; return nil; } sel(p: ref Panel, r: ref Repl, args: list of string): (int, string) { n := int hd tl args; n2:= int hd tl tl args; if (n < 0 || n2 < 0) return (0, "negative pos"); if (n > len p.data) n = len p.data; if (n2 > len p.data) n2 = len p.data; r.attrs[Asel] = sprint("sel %d %d", n, n2); if (r.id == 0){ for (rn := 0; rn < len p.repl; rn++) if ((pr := p.repl[rn]) != nil) pr.attrs[Asel] = r.attrs[Asel]; return (1, nil); } else return (0, nil); } dirtyclean(p: ref Panel, r: ref Repl, args: list of string): (int, string) { r.attrs[Aclean] = hd args; for (rn := 0; rn < len p.repl; rn++) if ((pr := p.repl[rn]) != nil) pr.attrs[Aclean] = r.attrs[Aclean]; return (1, nil); } font(p: ref Panel, r: ref Repl, args: list of string): (int, string) { fonts := array[] of { "L", "B", "S", "R", "I", "T" }; for (x := 0; x < len fonts; x++) if (hd tl args == fonts[x]) break; if (x == len fonts) return (0, "not a font"); r.attrs[Afont] = "font " + fonts[x]; if (r.id == 0){ for (rn := 0; rn < len p.repl; rn++) if ((pr := p.repl[rn]) != nil) pr.attrs[Afont] = r.attrs[Afont]; return (1, nil); } else return (0, nil); } mark(p: ref Panel, r: ref Repl, args: list of string): (int, string) { n := int hd tl args; if (n < 0) return (0, "negative mark"); if (n > len p.data) n = len p.data; r.attrs[Amark] = sprint("mark %d", n); if (r.id == 0){ for (rn := 0; rn < len p.repl; rn++) if ((pr := p.repl[rn]) != nil) pr.attrs[Amark] = r.attrs[Amark]; return (1, nil); } else return (0, nil); } tab(p: ref Panel, r: ref Repl, args: list of string): (int, string) { n := int hd tl args; if (n < 3 || n > 10) return (0, "tab must be in [3:10]"); r.attrs[Atab] = sprint("tab %d", n); if (r.id == 0){ for (rn := 0; rn < len p.repl; rn++) if ((pr := p.repl[rn]) != nil) pr.attrs[Atab] = r.attrs[Atab]; return (1, nil); } else return (0, nil); } # Both ins and del need special update rules. They return (2, *) # to signal fswrite to update other replicas by sending just the # ctl data via events, and not by posting update events using the # conventional rules. # Also, although we store data as array of byte, positions refer # to runes. # BUG: converting to string and back to array of byte was fine # for testing, but it's not reasonable. Convert offsets instead. del(p: ref Panel, nil: ref Repl, args: list of string): (int, string) { pos := int hd tl args; n := int hd tl tl args; data := string p.data; if (pos > len data) pos = len data; if (pos < 0) return (0, "negative pos"); if (pos + n > len data) n = len data - pos; if (n == 0) return (0, nil); if (n < 0) return (0, "negative del"); data = data[0:pos] + data[pos+n:]; p.data = array of byte data; return (2, nil); # see comment above } ins(p: ref Panel, nil: ref Repl, args: list of string): (int, string) { pos := int hd tl args; b := hd tl tl args; data := string p.data; if (pos+1 > len data) pos = len data; if (pos < 0) return (0, "negative pos"); data = data[0:pos] + b + data [pos:]; p.data = array of byte data; return (2, nil); # see comment above } ctl(p: ref Panels->Panel, r: ref Panels->Repl, ctl: list of string): (int, string) { case hd ctl { "clean" or "dirty" => if (len ctl != 1) return (0, "no arguments needed"); return dirtyclean(p, r, ctl); "font" => if (len ctl != 2) return (0, "1 argument needed"); return font(p, r, ctl); "sel" => if (len ctl != 3) return (0, "2 arguments needed"); return sel(p, r, ctl); "mark" => if (len ctl != 2) return (0, "1 argument needed"); return mark(p, r, ctl); "ins" => if (len ctl != 3) return (0, "2 arguments needed"); return ins(p, r, ctl); "del" => if (len ctl != 3) return (0, "2 arguments needed"); return del(p, r, ctl); "tab" => if (len ctl != 2) return(0, "1 argument needed"); return tab(p, r, ctl); * => return (0, "not mine"); } }