123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676 |
- 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();
- }
-
- }
- }
- }
- if(ct.addr && (cmd.mtaddr=simpleaddr())==nil)
- editerror("bad address");
- if(ct.defcmd){
- if(cmdskipbl() == '\n'){
- getch();
- cmd.cmd = newcmd();
- cmd.cmd.cmdc = ct.defcmd;
- }else if((cmd.cmd = parsecmd(nest))==nil)
- error("defcmd");
- }else if(ct.text)
- cmd.text = collecttext();
- else if(ct.token != nil)
- cmd.text = collecttoken(ct.token);
- else
- atnl();
- }else
- case(cmd.cmdc){
- '{' =>
- cp = nil;
- do{
- if(cmdskipbl()=='\n')
- getch();
- ncp = parsecmd(nest+1);
- if(cp != nil)
- cp.next = ncp;
- else
- cmd.cmd = ncp;
- }while((cp = ncp) != nil);
- break;
- '}' =>
- atnl();
- if(nest==0)
- editerror("right brace with no left brace");
- return nil;
- 'c'|16r100 =>
- editerror("unimplemented command cd");
- * =>
- editerror(sprint("unknown command %c", cmd.cmdc));
- }
- cp = newcmd();
- *cp = *cmd;
- return cp;
- }
- getregexp(delim: int): ref String
- {
- buf, r: ref String;
- i, c: int;
- buf = allocstring(0);
- for(i=0; ; i++){
- if((c = getch())=='\\'){
- if(nextc()==delim)
- c = getch();
- else if(nextc()=='\\'){
- Straddc(buf, c);
- c = getch();
- }
- }else if(c==delim || c=='\n')
- break;
- if(i >= BUFSIZE)
- editerror("regular expression too long");
- Straddc(buf, c);
- }
- if(c!=delim && c)
- ungetch();
- if(buf.n > 0){
- patset = TRUE;
- freestring(lastpat);
- lastpat = buf;
- }else
- freestring(buf);
- if(lastpat.n == 0)
- editerror("no regular expression defined");
- r = newstring(lastpat.n);
- k := lastpat.n;
- for(j := 0; j < k; j++)
- r.r[j] = lastpat.r[j]; # newstring put \0 at end
- return r;
- }
- simpleaddr(): ref Addr
- {
- addr: Addr;
- ap, nap: ref Addr;
- addr.next = nil;
- addr.left = nil;
- case(cmdskipbl()){
- '#' =>
- addr.typex = getch();
- addr.num = getnum(1);
- break;
- '0' to '9' =>
- addr.num = getnum(1);
- addr.typex='l';
- break;
- '/' or '?' or '"' =>
- addr.re = getregexp(addr.typex = getch());
- break;
- '.' or
- '$' or
- '+' or
- '-' or
- '\'' =>
- addr.typex = getch();
- break;
- * =>
- return nil;
- }
- if((addr.next = simpleaddr()) != nil)
- case(addr.next.typex){
- '.' or
- '$' or
- '\'' =>
- if(addr.typex!='"')
- editerror("bad address syntax");
- break;
- '"' =>
- editerror("bad address syntax");
- break;
- 'l' or
- '#' =>
- if(addr.typex=='"')
- break;
- if(addr.typex!='+' && addr.typex!='-'){
- # insert the missing '+'
- nap = newaddr();
- nap.typex='+';
- nap.next = addr.next;
- addr.next = nap;
- }
- break;
- '/' or
- '?' =>
- if(addr.typex!='+' && addr.typex!='-'){
- # insert the missing '+'
- nap = newaddr();
- nap.typex='+';
- nap.next = addr.next;
- addr.next = nap;
- }
- break;
- '+' or
- '-' =>
- break;
- * =>
- error("simpleaddr");
- }
- ap = newaddr();
- *ap = addr;
- return ap;
- }
- compoundaddr(): ref Addr
- {
- addr: Addr;
- ap, next: ref Addr;
- addr.left = simpleaddr();
- if((addr.typex = cmdskipbl())!=',' && addr.typex!=';')
- return addr.left;
- getch();
- next = addr.next = compoundaddr();
- if(next != nil && (next.typex==',' || next.typex==';') && next.left==nil)
- editerror("bad address syntax");
- ap = newaddr();
- *ap = addr;
- return ap;
- }
|