implement Edit; include "common.m"; sys: Sys;dat: Dat;utils: Utils;textm: Textm;windowm: Windowm;rowm: Rowm;scroll: Scroll;editlog: Editlog;editcomd: Editcmd; sprint, print: import sys;FALSE, TRUE, BUFSIZE, Null, Empty, Inactive: import Dat;warning, error, strchr: import utils;Text: import textm;File: import Filem;Window: import windowm;allwindows: import rowm;scrdraw: import scroll;elogterm, elogapply: import editlog;cmdexec, resetxec: import editcomd; init(mods : ref Dat->Mods){ sys = mods.sys; dat = mods.dat; utils = mods.utils; textm = mods.textm; windowm = mods.windowm; rowm = mods.rowm; scroll = mods.scroll; editlog = mods.editlog; editcomd = mods.editcmd; editing = Inactive;} linex: con "\n";wordx: con "\t\n"; cmdtab = array[28] of {# cmdc text regexp addr defcmd defaddr count token fn Cmdt ( '\n', 0, 0, 0, 0, aDot, 0, nil, C_nl ), Cmdt ( 'a', 1, 0, 0, 0, aDot, 0, nil, C_a ), Cmdt ( 'b', 0, 0, 0, 0, aNo, 0, linex, C_b ), Cmdt ( 'c', 1, 0, 0, 0, aDot, 0, nil, C_c ), Cmdt ( 'd', 0, 0, 0, 0, aDot, 0, nil, C_d ), Cmdt ( 'e', 0, 0, 0, 0, aNo, 0, wordx, C_e ), Cmdt ( 'f', 0, 0, 0, 0, aNo, 0, wordx, C_f ), Cmdt ( 'g', 0, 1, 0, 'p', aDot, 0, nil, C_g ), Cmdt ( 'i', 1, 0, 0, 0, aDot, 0, nil, C_i ), Cmdt ( 'm', 0, 0, 1, 0, aDot, 0, nil, C_m ), Cmdt ( 'p', 0, 0, 0, 0, aDot, 0, nil, C_p ), Cmdt ( 'r', 0, 0, 0, 0, aDot, 0, wordx, C_e ), Cmdt ( 's', 0, 1, 0, 0, aDot, 1, nil, C_s ), Cmdt ( 't', 0, 0, 1, 0, aDot, 0, nil, C_m ), Cmdt ( 'u', 0, 0, 0, 0, aNo, 2, nil, C_u ), Cmdt ( 'v', 0, 1, 0, 'p', aDot, 0, nil, C_g ), Cmdt ( 'w', 0, 0, 0, 0, aAll, 0, wordx, C_w ), Cmdt ( 'x', 0, 1, 0, 'p', aDot, 0, nil, C_x ), Cmdt ( 'y', 0, 1, 0, 'p', aDot, 0, nil, C_x ), Cmdt ( '=', 0, 0, 0, 0, aDot, 0, linex, C_eq ), Cmdt ( 'B', 0, 0, 0, 0, aNo, 0, linex, C_B ), Cmdt ( 'D', 0, 0, 0, 0, aNo, 0, linex, C_D ), Cmdt ( 'X', 0, 1, 0, 'f', aNo, 0, nil, C_X ), Cmdt ( 'Y', 0, 1, 0, 'f', aNo, 0, nil, C_X ), Cmdt ( '<', 0, 0, 0, 0, aDot, 0, linex, C_pipe ), Cmdt ( '|', 0, 0, 0, 0, aDot, 0, linex, C_pipe ), Cmdt ( '>', 0, 0, 0, 0, aDot, 0, linex, C_pipe ), # deliberately unimplemented # Cmdt ( 'k', 0, 0, 0, 0, aDot, 0, nil, C_k ), # Cmdt ( 'n', 0, 0, 0, 0, aNo, 0, nil, C_n ), # Cmdt ( 'q', 0, 0, 0, 0, aNo, 0, nil, C_q ), # Cmdt ( '!', 0, 0, 0, 0, aNo, 0, linex, C_plan9 ), Cmdt (0, 0, 0, 0, 0, 0, 0, nil, -1 )}; cmdstartp: string;cmdendp: int;cmdp: int;editerrc: chan of string; lastpat : ref String;patset: int; # cmdlist: ref List;# addrlist: ref List;# stringlist: ref List; editwaitproc(pid : int, sync: chan of int){ fd : ref Sys->FD; n : int; sys->pctl(Sys->FORKFD, nil); w := sprint("#p/%d/wait", pid); fd = sys->open(w, Sys->OREAD); if (fd == nil) error("fd == nil in editwaitproc"); sync <-= sys->pctl(0, nil); buf := array[Sys->WAITLEN] of byte; status := ""; for(;;){ if ((n = sys->read(fd, buf, len buf))<0) error("bad read in editwaitproc"); status = string buf[0:n]; dat->cwait <-= status; }} editthread(){ cmdp: ref Cmd; mypid := sys->pctl(0, nil); sync := chan of int; spawn editwaitproc(mypid, sync); yourpid := <- sync; while((cmdp=parsecmd(0)) != nil){# ocurfile = curfile;# loaded = curfile && !curfile->unread; if(cmdexec(curtext, cmdp) == 0) break; freecmd(); } editerrc <-= nil; utils->postnote(Utils->PNPROC, mypid, yourpid, "kill");} allelogterm(w: ref Window){ elogterm(w.body.file);} alleditinit(w: ref Window){ w.tag.commit(TRUE); w.body.commit(TRUE); w.body.file.editclean = FALSE;} allupdate(w: ref Window){ t: ref Text; i: int; f: ref File; t = w.body; f = t.file; if(f.curtext != t) # do curtext only return; if(f.elog.typex == Null) elogterm(f); else if(f.elog.typex != Empty){ elogapply(f); if(f.editclean){ f.mod = FALSE; for(i=0; i<f.ntext; i++) f.text[i].w.dirty = FALSE; } t.setselect(t.q0, t.q1); scrdraw(t); w.settag(); }} editerror(s: string){ # print("%s", s); freecmd(); allwindows(ALLELOGTERM, nil); # truncate the edit logs editerrc <-= s; exit;} editcmd(ct: ref Text, r: string, n: int){ err: string; if(n == 0) return; if(2*n > BUFSIZE){ warning(nil, "string too long\n"); return; } allwindows(ALLEDITINIT, nil); cmdstartp = r[0:n]; if(r[n-1] != '\n') cmdstartp[n++] = '\n'; cmdendp = n; cmdp = 0; if(ct.w == nil) curtext = nil; else curtext = ct.w.body; resetxec(); if(editerrc == nil){ editerrc = chan of string; lastpat = allocstring(0); } spawn editthread(); err = <- editerrc; editing = Inactive; if(err != nil) warning(nil, sprint("Edit: %s\n", err)); # update everyone whose edit log has data allwindows(ALLUPDATE, nil);} getch(): int{ if(cmdp == cmdendp) return -1; return cmdstartp[cmdp++];} nextc(): int{ if(cmdp == cmdendp) return -1; return cmdstartp[cmdp];} ungetch(){ if(--cmdp < 0) error("ungetch");} getnum(signok: int): int{ n: int; c, sign: int; n = 0; sign = 1; if(signok>1 && nextc()=='-'){ sign = -1; getch(); } if((c=nextc())<'0' || '9'<c) # no number defaults to 1 return sign; while('0'<=(c=getch()) && c<='9') n = n*10 + (c-'0'); ungetch(); return sign*n;} cmdskipbl(): int{ c: int; do c = getch(); while(c==' ' || c=='\t'); if(c >= 0) ungetch(); return c;} # Check that list has room for one more element.# growlist(l: ref List)# {# if(l.elems == nil || l.nalloc==0){# l.nalloc = INCR;# l.elems = array[INCR] of Listelement;# l.nused = 0;# }else if(l.nused == l.nalloc){# old := l.elems;# l.elems = array[l.nalloc+INCR] of Listelement;# l.elems[0:] = old[0:l.nalloc];# l.nalloc += INCR;# }# } # Remove the ith element from the list# dellist(l: ref List, i: int)# {# l.elems[i:] = l.elems[i+1:l.nused];# l.nused--;# } # Add a new element, whose position is i, to the list# inslist(l: ref List, i: int, val: int)# {# growlist(l);# l.elems[i+1:] = l.elems[i:l.nused];# l.elems[i] = val;# l.nused++;# } # listfree(l: ref List)# {# l.elems = nil;# } allocstring(n: int): ref String{ s: ref String; s = ref String; s.n = n; s.r = string array[s.n] of { * => byte '\0' }; return s;} freestring(s: ref String){ s.r = nil;} newcmd(): ref Cmd{ p: ref Cmd; p = ref Cmd; # inslist(cmdlist, cmdlist.nused, p); return p;} newstring(n: int): ref String{ p: ref String; p = allocstring(n); # inslist(stringlist, stringlist.nused, p); return p;} newaddr(): ref Addr{ p: ref Addr; p = ref Addr; # inslist(addrlist, addrlist.nused, p); return p;} freecmd(){ # i: int; # cmdlist.elems = nil; # addrlist.elems = nil; # stringlist.elems = nil; # cmdlist.nused = addrlist.nused = stringlist.nused = 0;} okdelim(c: int){ if(c=='\\' || ('a'<=c && c<='z') || ('A'<=c && c<='Z') || ('0'<=c && c<='9')) editerror(sprint("bad delimiter %c\n", c));} atnl(){ c: int; cmdskipbl(); c = getch(); if(c != '\n') editerror(sprint("newline expected (saw %c)", c));} Straddc(s: ref String, c: int){ s.r[s.n++] = c;} getrhs(s: ref String, delim: int, cmd: int){ c: int; while((c = getch())>0 && c!=delim && c!='\n'){ if(c == '\\'){ if((c=getch()) <= 0) error("bad right hand side"); if(c == '\n'){ ungetch(); c='\\'; }else if(c == 'n') c='\n'; else if(c!=delim && (cmd=='s' || c!='\\')) # s does its own Straddc(s, '\\'); } Straddc(s, c); } ungetch(); # let client read whether delimiter, '\n' or whatever} collecttoken(end: string): ref String{ c: int; s := newstring(0); while((c=nextc())==' ' || c=='\t') Straddc(s, getch()); # blanks significant for getname() while((c=getch())>0 && strchr(end, c)<0) Straddc(s, c); if(c != '\n') atnl(); return s;} collecttext(): ref String{ s: ref String; begline, i, c, delim: int; s = newstring(0); if(cmdskipbl()=='\n'){ getch(); i = 0; do{ begline = i; while((c = getch())>0 && c!='\n'){ i++; Straddc(s, c); } i++; Straddc(s, '\n'); if(c < 0) return s; }while(s.r[begline]!='.' || s.r[begline+1]!='\n'); s.r[s.n-2] = '\0'; }else{ okdelim(delim = getch()); getrhs(s, delim, 'a'); if(nextc()==delim) getch(); atnl(); } return s;} cmdlookup(c: int): int{ i: int; for(i=0; cmdtab[i].cmdc; i++) if(cmdtab[i].cmdc == c) return i; return -1;} parsecmd(nest: int): ref Cmd{ i, c: int; cp, ncp: ref Cmd; cmd: ref Cmd; cmd = ref Cmd; cmd.next = cmd.cmd = nil; cmd.re = nil; cmd.flag = cmd.num = 0; cmd.addr = compoundaddr(); if(cmdskipbl() == -1) return nil; if((c=getch())==-1) return nil; cmd.cmdc = c; if(cmd.cmdc=='c' && nextc()=='d'){ # sleazy two-character case getch(); # the 'd' cmd.cmdc='c'|16r100; } i = cmdlookup(cmd.cmdc); if(i >= 0){ if(cmd.cmdc == '\n'){ cp = newcmd(); *cp = *cmd; return cp; # let nl_cmd work it all out } ct := cmdtab[i]; if(ct.defaddr==aNo && cmd.addr != nil) editerror("command takes no address"); if(ct.count) cmd.num = getnum(ct.count); if(ct.regexp){ # x without pattern -> .*\n, indicated by cmd.re==0 # X without pattern is all files if((ct.cmdc!='x' && ct.cmdc!='X') || ((c = nextc())!=' ' && c!='\t' && c!='\n')){ cmdskipbl(); if((c = getch())=='\n' || c<0) editerror("no address"); okdelim(c); cmd.re = getregexp(c); if(ct.cmdc == 's'){ cmd.text = newstring(0); getrhs(cmd.text, c, 's'); if(nextc() == c){ getch(); if(nextc() == 'g') cmd.flag = getch();Lines 1–500 of 676. Load more
implement Edit; include "common.m"; sys: Sys; dat: Dat; utils: Utils; textm: Textm; windowm: Windowm; rowm: Rowm; scroll: Scroll; editlog: Editlog; editcomd: Editcmd; sprint, print: import sys; FALSE, TRUE, BUFSIZE, Null, Empty, Inactive: import Dat; warning, error, strchr: import utils; Text: import textm; File: import Filem; Window: import windowm; allwindows: import rowm; scrdraw: import scroll; elogterm, elogapply: import editlog; cmdexec, resetxec: import editcomd; init(mods : ref Dat->Mods) { sys = mods.sys; dat = mods.dat; utils = mods.utils; textm = mods.textm; windowm = mods.windowm; rowm = mods.rowm; scroll = mods.scroll; editlog = mods.editlog; editcomd = mods.editcmd; editing = Inactive; } linex: con "\n"; wordx: con "\t\n"; cmdtab = array[28] of { # cmdc text regexp addr defcmd defaddr count token fn Cmdt ( '\n', 0, 0, 0, 0, aDot, 0, nil, C_nl ), Cmdt ( 'a', 1, 0, 0, 0, aDot, 0, nil, C_a ), Cmdt ( 'b', 0, 0, 0, 0, aNo, 0, linex, C_b ), Cmdt ( 'c', 1, 0, 0, 0, aDot, 0, nil, C_c ), Cmdt ( 'd', 0, 0, 0, 0, aDot, 0, nil, C_d ), Cmdt ( 'e', 0, 0, 0, 0, aNo, 0, wordx, C_e ), Cmdt ( 'f', 0, 0, 0, 0, aNo, 0, wordx, C_f ), Cmdt ( 'g', 0, 1, 0, 'p', aDot, 0, nil, C_g ), Cmdt ( 'i', 1, 0, 0, 0, aDot, 0, nil, C_i ), Cmdt ( 'm', 0, 0, 1, 0, aDot, 0, nil, C_m ), Cmdt ( 'p', 0, 0, 0, 0, aDot, 0, nil, C_p ), Cmdt ( 'r', 0, 0, 0, 0, aDot, 0, wordx, C_e ), Cmdt ( 's', 0, 1, 0, 0, aDot, 1, nil, C_s ), Cmdt ( 't', 0, 0, 1, 0, aDot, 0, nil, C_m ), Cmdt ( 'u', 0, 0, 0, 0, aNo, 2, nil, C_u ), Cmdt ( 'v', 0, 1, 0, 'p', aDot, 0, nil, C_g ), Cmdt ( 'w', 0, 0, 0, 0, aAll, 0, wordx, C_w ), Cmdt ( 'x', 0, 1, 0, 'p', aDot, 0, nil, C_x ), Cmdt ( 'y', 0, 1, 0, 'p', aDot, 0, nil, C_x ), Cmdt ( '=', 0, 0, 0, 0, aDot, 0, linex, C_eq ), Cmdt ( 'B', 0, 0, 0, 0, aNo, 0, linex, C_B ), Cmdt ( 'D', 0, 0, 0, 0, aNo, 0, linex, C_D ), Cmdt ( 'X', 0, 1, 0, 'f', aNo, 0, nil, C_X ), Cmdt ( 'Y', 0, 1, 0, 'f', aNo, 0, nil, C_X ), Cmdt ( '<', 0, 0, 0, 0, aDot, 0, linex, C_pipe ), Cmdt ( '|', 0, 0, 0, 0, aDot, 0, linex, C_pipe ), Cmdt ( '>', 0, 0, 0, 0, aDot, 0, linex, C_pipe ), # deliberately unimplemented # Cmdt ( 'k', 0, 0, 0, 0, aDot, 0, nil, C_k ), # Cmdt ( 'n', 0, 0, 0, 0, aNo, 0, nil, C_n ), # Cmdt ( 'q', 0, 0, 0, 0, aNo, 0, nil, C_q ), # Cmdt ( '!', 0, 0, 0, 0, aNo, 0, linex, C_plan9 ), Cmdt (0, 0, 0, 0, 0, 0, 0, nil, -1 ) }; cmdstartp: string; cmdendp: int; cmdp: int; editerrc: chan of string; lastpat : ref String; patset: int; # cmdlist: ref List; # addrlist: ref List; # stringlist: ref List; editwaitproc(pid : int, sync: chan of int) { fd : ref Sys->FD; n : int; sys->pctl(Sys->FORKFD, nil); w := sprint("#p/%d/wait", pid); fd = sys->open(w, Sys->OREAD); if (fd == nil) error("fd == nil in editwaitproc"); sync <-= sys->pctl(0, nil); buf := array[Sys->WAITLEN] of byte; status := ""; for(;;){ if ((n = sys->read(fd, buf, len buf))<0) error("bad read in editwaitproc"); status = string buf[0:n]; dat->cwait <-= status; } } editthread() { cmdp: ref Cmd; mypid := sys->pctl(0, nil); sync := chan of int; spawn editwaitproc(mypid, sync); yourpid := <- sync; while((cmdp=parsecmd(0)) != nil){ # ocurfile = curfile; # loaded = curfile && !curfile->unread; if(cmdexec(curtext, cmdp) == 0) break; freecmd(); } editerrc <-= nil; utils->postnote(Utils->PNPROC, mypid, yourpid, "kill"); } allelogterm(w: ref Window) { elogterm(w.body.file); } alleditinit(w: ref Window) { w.tag.commit(TRUE); w.body.commit(TRUE); w.body.file.editclean = FALSE; } allupdate(w: ref Window) { t: ref Text; i: int; f: ref File; t = w.body; f = t.file; if(f.curtext != t) # do curtext only return; if(f.elog.typex == Null) elogterm(f); else if(f.elog.typex != Empty){ elogapply(f); if(f.editclean){ f.mod = FALSE; for(i=0; i<f.ntext; i++) f.text[i].w.dirty = FALSE; } t.setselect(t.q0, t.q1); scrdraw(t); w.settag(); } } editerror(s: string) { # print("%s", s); freecmd(); allwindows(ALLELOGTERM, nil); # truncate the edit logs editerrc <-= s; exit; } editcmd(ct: ref Text, r: string, n: int) { err: string; if(n == 0) return; if(2*n > BUFSIZE){ warning(nil, "string too long\n"); return; } allwindows(ALLEDITINIT, nil); cmdstartp = r[0:n]; if(r[n-1] != '\n') cmdstartp[n++] = '\n'; cmdendp = n; cmdp = 0; if(ct.w == nil) curtext = nil; else curtext = ct.w.body; resetxec(); if(editerrc == nil){ editerrc = chan of string; lastpat = allocstring(0); } spawn editthread(); err = <- editerrc; editing = Inactive; if(err != nil) warning(nil, sprint("Edit: %s\n", err)); # update everyone whose edit log has data allwindows(ALLUPDATE, nil); } getch(): int { if(cmdp == cmdendp) return -1; return cmdstartp[cmdp++]; } nextc(): int { if(cmdp == cmdendp) return -1; return cmdstartp[cmdp]; } ungetch() { if(--cmdp < 0) error("ungetch"); } getnum(signok: int): int { n: int; c, sign: int; n = 0; sign = 1; if(signok>1 && nextc()=='-'){ sign = -1; getch(); } if((c=nextc())<'0' || '9'<c) # no number defaults to 1 return sign; while('0'<=(c=getch()) && c<='9') n = n*10 + (c-'0'); ungetch(); return sign*n; } cmdskipbl(): int { c: int; do c = getch(); while(c==' ' || c=='\t'); if(c >= 0) ungetch(); return c; } # Check that list has room for one more element. # growlist(l: ref List) # { # if(l.elems == nil || l.nalloc==0){ # l.nalloc = INCR; # l.elems = array[INCR] of Listelement; # l.nused = 0; # }else if(l.nused == l.nalloc){ # old := l.elems; # l.elems = array[l.nalloc+INCR] of Listelement; # l.elems[0:] = old[0:l.nalloc]; # l.nalloc += INCR; # } # } # Remove the ith element from the list # dellist(l: ref List, i: int) # { # l.elems[i:] = l.elems[i+1:l.nused]; # l.nused--; # } # Add a new element, whose position is i, to the list # inslist(l: ref List, i: int, val: int) # { # growlist(l); # l.elems[i+1:] = l.elems[i:l.nused]; # l.elems[i] = val; # l.nused++; # } # listfree(l: ref List) # { # l.elems = nil; # } allocstring(n: int): ref String { s: ref String; s = ref String; s.n = n; s.r = string array[s.n] of { * => byte '\0' }; return s; } freestring(s: ref String) { s.r = nil; } newcmd(): ref Cmd { p: ref Cmd; p = ref Cmd; # inslist(cmdlist, cmdlist.nused, p); return p; } newstring(n: int): ref String { p: ref String; p = allocstring(n); # inslist(stringlist, stringlist.nused, p); return p; } newaddr(): ref Addr { p: ref Addr; p = ref Addr; # inslist(addrlist, addrlist.nused, p); return p; } freecmd() { # i: int; # cmdlist.elems = nil; # addrlist.elems = nil; # stringlist.elems = nil; # cmdlist.nused = addrlist.nused = stringlist.nused = 0; } okdelim(c: int) { if(c=='\\' || ('a'<=c && c<='z') || ('A'<=c && c<='Z') || ('0'<=c && c<='9')) editerror(sprint("bad delimiter %c\n", c)); } atnl() { c: int; cmdskipbl(); c = getch(); if(c != '\n') editerror(sprint("newline expected (saw %c)", c)); } Straddc(s: ref String, c: int) { s.r[s.n++] = c; } getrhs(s: ref String, delim: int, cmd: int) { c: int; while((c = getch())>0 && c!=delim && c!='\n'){ if(c == '\\'){ if((c=getch()) <= 0) error("bad right hand side"); if(c == '\n'){ ungetch(); c='\\'; }else if(c == 'n') c='\n'; else if(c!=delim && (cmd=='s' || c!='\\')) # s does its own Straddc(s, '\\'); } Straddc(s, c); } ungetch(); # let client read whether delimiter, '\n' or whatever } collecttoken(end: string): ref String { c: int; s := newstring(0); while((c=nextc())==' ' || c=='\t') Straddc(s, getch()); # blanks significant for getname() while((c=getch())>0 && strchr(end, c)<0) Straddc(s, c); if(c != '\n') atnl(); return s; } collecttext(): ref String { s: ref String; begline, i, c, delim: int; s = newstring(0); if(cmdskipbl()=='\n'){ getch(); i = 0; do{ begline = i; while((c = getch())>0 && c!='\n'){ i++; Straddc(s, c); } i++; Straddc(s, '\n'); if(c < 0) return s; }while(s.r[begline]!='.' || s.r[begline+1]!='\n'); s.r[s.n-2] = '\0'; }else{ okdelim(delim = getch()); getrhs(s, delim, 'a'); if(nextc()==delim) getch(); atnl(); } return s; } cmdlookup(c: int): int { i: int; for(i=0; cmdtab[i].cmdc; i++) if(cmdtab[i].cmdc == c) return i; return -1; } parsecmd(nest: int): ref Cmd { i, c: int; cp, ncp: ref Cmd; cmd: ref Cmd; cmd = ref Cmd; cmd.next = cmd.cmd = nil; cmd.re = nil; cmd.flag = cmd.num = 0; cmd.addr = compoundaddr(); if(cmdskipbl() == -1) return nil; if((c=getch())==-1) return nil; cmd.cmdc = c; if(cmd.cmdc=='c' && nextc()=='d'){ # sleazy two-character case getch(); # the 'd' cmd.cmdc='c'|16r100; } i = cmdlookup(cmd.cmdc); if(i >= 0){ if(cmd.cmdc == '\n'){ cp = newcmd(); *cp = *cmd; return cp; # let nl_cmd work it all out } ct := cmdtab[i]; if(ct.defaddr==aNo && cmd.addr != nil) editerror("command takes no address"); if(ct.count) cmd.num = getnum(ct.count); if(ct.regexp){ # x without pattern -> .*\n, indicated by cmd.re==0 # X without pattern is all files if((ct.cmdc!='x' && ct.cmdc!='X') || ((c = nextc())!=' ' && c!='\t' && c!='\n')){ cmdskipbl(); if((c = getch())=='\n' || c<0) editerror("no address"); okdelim(c); cmd.re = getregexp(c); if(ct.cmdc == 's'){ cmd.text = newstring(0); getrhs(cmd.text, c, 's'); if(nextc() == c){ getch(); if(nextc() == 'g') cmd.flag = getch();