home *** CD-ROM | disk | FTP | other *** search
- /* This file is KEYF.CC */
- #include "em.h"
- extern char*offscreen;
- int compare(line*X,line*Y);
- /*-----*/
- int caseq(val a,val b){reg int i;if(a.n<0?:b.n<0?:a.n!=b.n?:!a.s?:!b.s)return 0;
- for(i=a.n-1;i>=0;i--)if(to_upper(a.s[i])!=to_upper(b.s[i])) return 0; return 1;}
- /*-----*/
- char Filename[strsize]={0}; val Fn(Filename,0);
- /*-----*/
- int fileexists(char*s){int F=open(s,1);
- if(F>=0) {close(F); return 1;} else return 0;}
- /*-----*/
- char*keyname(int c,int alt/*=0*/){
- int i; val s; static char cc[2]=" ",ct[6]="ctrl ";
- if(alt) return altnames[c&255]?:"(unidentified code)";
- for(i=0;s=keynames[i],s.s;i++) if(c==s.n) return s.s;
- if(c<32) {ct[4]=c+64; return ct;} cc[0]=c; return cc;}
- /*-----*/
- int yesno(char*pt){char*yn[]={"Yes","No"}; return 1-bottommenu(pt,1,"YN",yn,4);}
- /*----- bind key to needing another key typed after it */
- void keyarray::subarray(){a=0; n=0;}
- void val::subarray(){k=new keyarray; k->subarray(); n=_keyarray;}
- /*-----*/
- val key0; keyarray keys; /* head of lookup tree of key bindings */
- /*----- keyarray[int] : look up key */
- val&keyarray::operator[](int N){int i,j; val *Q; if(N<n) return a[N];
- j=(N+8)&~7; Q=new val[j]; /* if out of bounds, lengthen array */
- for(i=n-1;i>=0;i--) Q[i]=a[i]; for(i=n;i<j;i++) Q[i]=val();
- n=j; delete a; a=Q; return a[N]; }
- /*----- val[int]: ditto */
- val&val::operator[](int N){
- if(n!=_keyarray) MOAN("BUG: this is not a keyarray"); return (*k)[N];}
- /*----- obey a macstep bound to a char */
- void Insert(int N,byte c){int i; for(i=0;i<N;i++) *B+=c;}
- /*----- list key binding info in current buffer */
- void keyarray::print(int N/*=1*/,int i/*=1*/,int deep/*=1*/){
- val*k; int I,j,alt=i?0:1;
- for(I=0;I<n;I++) {k=&a[I]; keyseqc[deep]=I; keyseqc[0]=deep+1;
- if(N) {if(!i) if(!altnames[I]) if(!k->n) if(!k->k) continue;
- if(deep>alt) if(!k->k) continue;
- for(j=0;j<deep;j++) *B+=(char)9; /* tab */
- pb("%3d = '%s': %3d %8x ",I,keyname(I,alt),k->n,k->k);}
- else {if(!N) if(!k->k) continue; pb("%k :: ",&keyseq);}
- macstep(*k,1,0).print(); ::newline();
- if(k->n==_char) k->m->print();
- else if(k->n==_keyarray) k->k->print(N,I,deep+1);}}
- /*-----*/
- void keyarray::search(void(*fn)(val&ka)){val*k; int I;
- for(I=0;I<n;I++) if(k=&a[I], k->n==_keyarray) k->k->search(fn); else (*fn)(*k);}
- /*-----*/
- KF(newline) {reg int i; for(i=0;i<N.i;i++) B->dot/1;}
- /*-----*/
- KF(linefeed) {reg int i; for(i=0;i<N.i;i++) {B->dot/1; B->dot.r->no_cr(1);}}
- /*-----*/
- KF(copykill) {(B->Mark(N.i)-B->dot).copykill();}
- /*-----*/
- KF(page_down) {int i,j=(B->nrows-3)>?1,k=j*N.i; B->dotcc=B->dotcc2;
- /* if(!play) if(cursor.r!=255) k+=(B->row1+B->nrows/2-cursor.r); */
- if(B->longlines) {B->dispfold(k); return;}
- if(N.i>0) for(i=N.i*j;i>0;i--) {if(!(B->start.Down())) break;}
- else for(i=N.i*j;i<0;i++) {if(!(B->start.Up ())) break;}
- if(i>0) {B->dot=B->eof(); MOAN("hit end of buffer");}
- if(i<0) {B->dot=B->bof(); MOAN("hit start of buffer");}
- B->dot=B->start; for(i=B->nrows/2;i>0;i--) B->down();}
- /*-----*/
- KF(page_up) {page_down(-N);}
- /*-----*/
- KF(gotobof) {B->dot.r=B->text.next; B->dot.c=0; B->dotcc=B->dotcc2=-1;}
- /*-----*/
- KF(gotoeof) {line*L=B->dot.r=B->text.prev; B->dot.c=L->n;}
- /*----- remove final CR char and clear 'no CR' bit, if both found */
- void crcheck(line*L){if(L->no_cr()) if(L->n) if(L->s[L->n-1]==CR) {
- *L=L->n-1; L->no_cr(0); /* L->la(1); B->changed=1; */ }}
- /*-----*/
- KF(finalcr) {region R=B->Mark(N.i)-B->dot; line*L; B->changed=1;
- for(L=R.beg.r;!L?0:L!=R.end.r;L=L->next) {L->no_cr(0); crcheck(L); L->la(1);}}
- /*-----*/
- KF(nofinalcr) {region R=B->Mark(N.i)-B->dot; line*L; B->changed=1;
- for(L=R.beg.r;!L?0:L!=R.end.r;L=L->next) {L->no_cr(1); crcheck(L); L->la(1);}}
- /*-----*/
- KF(delet) {int i;
- if(N.i>=0) for(i=0;i<N.i;i++) !B->dot; else for(i=0;i>N.i;i--) *B+=' ';}
- /*-----*/
- KF(insertspaces) {delet(-N);}
- /*-----*/
- KF(goright) {int i;
- if(N.i>=0) for(i=0;i<N.i;i++) B->right(); else for(i=0;i>N.i;i--) B->left();}
- /*-----*/
- KF(goleft) {goright(-N);}
- /*-----*/
- KF(godown) {int i; B->dotcc=B->dotcc2;
- if(N.i>=0) for(i=0;i<N.i;i++) B->down(); else for(i=0;i>N.i;i--) B->up();}
- /*-----*/
- KF(goup) {godown(-N);}
- /*-----*/
- KF(godownpart){int i=0,j,k,n=N.i,p; line*L;
- if(!B->longlines) {godown(N); return;} if(n<0) {gouppart(-N,T1); return;}
- j=linewhere(B->dot); if(!n) goto X; p=B->dot.r->nparts();
- LOOP: i++; j+=gp_Cols; if(k=(j<p*gp_Cols)) if(i<n) goto LOOP;
- if(!k) if(L=B->dot.r->next) {
- B->dot.r=L; j%=gp_Cols; if(i<n) {p=L->nparts(); goto LOOP;}}
- X: if(T1.n==_int) j=(j/gp_Cols)*gp_Cols+(T1.i>?0);
- B->dot.c=B->dot.r->from_tabexp(j-2*(j/gp_Cols));}
- /*-----*/
- KF(gouppart){int i=0,j,n=N.i; line*L;
- if(!B->longlines) {goup(N); return;} if(n<0) {godownpart(-N,T1); return;}
- j=linewhere(B->dot); if(!n) goto X;
- LOOP: i++; j-=gp_Cols; if(j>=0) if(i<n) goto LOOP;
- if(j<0) if(L=B->dot.r->prev) {
- B->dot.r=L; j+=L->nparts()*gp_Cols; if(i<n) goto LOOP;}
- X: if(T1.n==_int) j=(j/gp_Cols)*gp_Cols+(T1.i>?0);
- B->dot.c=B->dot.r->from_tabexp(j-2*(j/gp_Cols));}
- /*-----*/
- KF(gotobol) {B->dot.c=0; B->dotcc=B->dotcc2=-1;}
- /*-----*/
- KF(gotoeol) {B->dot.c=B->dot.r->n; B->dotcc=B->dotcc2=-1;}
- /*-----*/
- KF(gotocol) {if(N.i<=0 ?1: B->twod ?0: N.i>B->dot.r->n) MOAN("no such column");
- goright(N.i-B->dot.c-1,1); B->dotcc=B->dotcc2=-1;}
- /*-----*/
- KF(whoa) {beep(); MOAN("aborted");}
- /*-----*/
- KF(backspace) {int i; for(i=0;i<N.i;i++) B->dot.bs();}
- /*-----*/
- KF(tabulate) {int i; if(B->tabtype) Insert(N.i,9);
- else for(i=N.i;i>0;i--) Insert(sptotab(B->dot.c)+1,' ');}
- /*-----*/
- KF(kill_to_eol) {int i,j; line*L; obtype=ob_kill; mark Q=B->dot;
- if(N.i>=0) {for(i=0;i<N.i;i++) if(Q.c<(j=Q.r->n)) Q.c=j;
- else if(L=Q.r->next) {Q.r=L; Q.c=0;} else break;}
- else {for(i=0;i>N.i;i--) if(Q.c>0) Q.c=0;
- else if(L=Q.r->prev) Q.c=(Q.r=L)->n; else break;} (B->dot-Q).kill();}
- /*-----*/
- KF(refresh_display){line*L;
- if(!N.n){if(B->longlines) B->refresh=1; N.i=B->nrows/2;}
- if(N.i>=0) {for(L=B->dot.r;L->prev?N.i>1:0;N.i--,L=L->prev); B->start.r=L;}
- int i; if(!N.n?1:N.i<0) for(i=0;i<gp_Rows;i++) Sl[i].ok=0;}
- /*-----*/
- KF(openline) {int i; for(i=0;i<N.i;i++) B->dot/0;}
- /*-----*/
- int charfrommenu() {int i,j,K,k,m,n,z=0; mousestate ms; ms=Jerry; Jerry.mc=1;
- short ss[gp_Cols*gp_Rows]; c_get(ss,screen,gp_Cols*gp_Rows);
- for(i=0;i<=16;i++) gp_clear(i); /* menu */
- display("\030 \031 \033 \032 select which char, End aborts, Return chooses",
- 16,0,Cyan+8); Jerry.range(16,64);
- for(i=0;i<8;i++) for(j=0;j<32;j++) scr(i+i,j+j+j/8)=sch(i*32+j,Orange); K=k=112;
- A: k&=0xff; if(z!=-mousemove) Jerry.move(2*(k>>5),2*(k&31));
- m=(k/16)|1; n=2*(k&31)+(k&24)/8; scr(m,n)=sch('\030',Green+8); K=k;
- switch(z=getkey()) {
- case -leftarrow: k--; break;
- case -rightarrow: k++; break;
- case -uparrow: k-=32; break;
- case -downarrow: k+=32; break;
- case -mousemove: k=(Jerry.x/2)+32*(Jerry.y/2); break;
- case -end_: case -rbutton: case -mbutton: Jerry=ms; k=-1; goto OUT;
- case CR: case -lbutton: Jerry=ms; goto OUT;}
- if(K!=k) scr(m,n)=sch(' ',White); goto A;
- OUT: c_put(screen,ss,gp_Cols*gp_Rows); return k;}
- /*-----*/
- KF(literalchar) {int c,i; if(play) return; mousestate ms; ms=Jerry;
- display("literal character (alt-0 for ascii-zero, ctrl-tab for menu of chars)",
- B->lastrow,0,Cyan); c=getkey(); B->redraw_info();
- Y: switch(c) {
- case -mousemove: case -lbuttond: case -mbuttond: case -rbuttond:
- c=getkey(); goto Y;
- case LF: for(i=0;i<N.i;i++) {B->dot/1; B->dot.r->prev->no_cr(1);}
- setref(f,&linefeed); Jerry=ms; return;
- case -ctrl_tab: case -lbutton: case -mbutton: case -rbutton:
- if((c=charfrommenu())<0) {basemi.rec=0; Jerry=ms; return;} goto X;
- case -alt_0: c=0; X:
- default: Jerry=ms;
- if(c>=0) {setref(f,&insert); setrek(T1,(char)c); Insert(N.i,c); return;}
- pr(CW,"%s is not an ASCII char",altnames[-c]?:"this"); MOAN(CW);}}
- /*-----*/
- KF(times4) {int j; if(play) return;
- j=B->lastrow; pr(CW,"numeric arg: %1d",N.i*4); display(CW,j,0,Cyan);
- Sl[j].ok=0; Obey(val(N.i*4,_int));}
- /*-----*/
- KF(killregion) {obtype=ob_kill; (B->Mark(N.i)-B->dot).kill();}
- /*----- convert char to as in C string */
- KF(cstrchr) {line*L=B->dot.r; int i,n=B->dot.c;
- if(n>=L->n) {*B+='\\'; *B+='n'; !B->dot;}
- else if(!iscntrl(i=L->s[n]&255)) {if(i=='"' ?1: i=='\\') *B+='\\'; B->right();}
- else {*B+='\\'; *B+='0'+i/64; i%=64; *B+='0'+i/8; *B+='0'+i%8; !B->dot;}}
- /*----- convert char from as in C string */
- KF(cchrstr) {int i,j,n; line*L; if((n=B->dot.c)>=(L=B->dot.r)->n) return;
- if(L->s[n]!='\\') {B->right(); return;} !B->dot; if(n>=L->n) return;
- switch(i=L->s[n]){
- case 'n': !B->dot; *B+=char(LF); break;
- case 't': !B->dot; *B+='\011'; break;
- case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
- !B->dot; j=i-'0';
- if(n<L->n) if(i=L->s[n]-'0',i>=0) if(i<8) {!B->dot; j=j*8+i;
- if(n<L->n) if(i=L->s[n]-'0',i>=0) if(i<8) {!B->dot; j=j*8+i;}}
- *B+=(char)j; break;
- default: !B->dot; B->right(); break;}}
- /*-----*/
- KF(showinfo) {line*L,*K=B->dot.r; int i=0,j=0,k=0,n,w; char*T;
- for(L=B->text.next;L;L=L->next) {i++; j+=(L->n+(L->no_cr()?1:2)); if(K==L) k=i;}
- j-=2; L=B->dot.r; T=L->s; n=B->dot.c; w=L->to_tabexp(L->n);
- pr(disp,"line %1d of %1d, char %1d of %1d(%1d), %1d bytes, at ",
- k,B->text.prev->n?i:i-1,n+1,L->n,w,j);
- if(n<L->n) pa(disp,"`%c' = %1d",T[n]?:' ',(byte)T[n]);
- else pa(disp,k==i?"eof":"eol"); pa(disp,"; altM gives modes"); Display=disp;}
- /*-----*/
- KF(savebuffer) {B->write();}
- /*-----*/
- KF(writebuffer) {T1.getifn(Fn,"file to write to",_buffer); setrek(T1,T1.copy());
- if(fileexists(T1.s)) if(!yesno("file exists: OK to overwrite it?")) return;
- if(buf_named(T1)) MOAN("this file already has a buffer");
- buffer *BB=B; Text U; (new buffer(T1.s,0))->go_to();
- U=Text(BB->text.next,BB->text.prev).copy(); B->text.next->del();
- B->text.next=U.beg; B->text.prev=U.end; B->dot=mark(B->text.next,0);
- if(N.i>0) B->write(); BB->go_to();}
- /*-----*/
- static buffer *buffertolose=0;
- /*-----*/
- void losebuffer(val&k){if(k.n==_buffer) if(k.b==buffertolose) {k.b=0; k.n=0;}}
- /*-----*/
- int deletebuffer(buffer*C) {buffer*A,*BB; if(!C->nrows) goto Y;
- for(BB=B->next;BB;BB=BB->next) if(!BB->nrows) goto Y;
- for(BB=bhead;BB?BB!=B:0;BB=BB->next) if(!BB->nrows) goto Y; beep(); return 0;
- Y: if(C->changed) if(!yesno(
- "This buffer changed since saved last: shall I still drop it?")) return 0;
- buffertolose=C; keys.search(&losebuffer);
- if(C->nrows) {A=B; B=C; BB->go_to(); if(A!=C) B=A;} delete C; return 1;}
- /*-----*/
- KF(delbuf) {deletebuffer(B);}
- /*-----*/
- KF(finish) {buffer *BB; char*q="%s changed: exit without saving it?";
- A: forallbufs(BB) if(BB->changed) break;
- if(BB) {pr(CW,q,BB->name); if(!yesno(CW)) return; BB->changed=0; goto A;}
- if(appendixsize>1) if(!yesno("exit without saving the dictionary's appendix?"))
- return;
- clearscreen(); gp_cursor(gp_cur(0,0)); longjmp(Exit,1);}
- /*-----*/
- KF(setrightmargin) {
- if(N.n) B->rmargin=N.i<0?(N.i>-11?-gp_Cols:N.i):N.i>11?N.i:gp_Cols;
- if(B->rmargin>=0) pr(disp,"right margin = %1d",B->rmargin);
- else pr(disp,"right margin = %1d 'n'-widths proportional",-B->rmargin);
- Display=disp;}
- /*-----*/
- KF(pushmark) {if(B->nmarks()>16) MOAN("this buffer has too many marks");
- B->dot.push();}
- /*-----*/
- KF(swopmark) {if(N.i-1==B->nmarks()) B->dot.hsup();
- else {mark*M=&B->Mark(N.i),Q=B->dot; B->dot=*M; *M=Q;}}
- /*-----*/
- KF(setmark) {if(N.i-1==B->nmarks()) B->dot.hsup(); else B->Mark(N.i)=B->dot;}
- /*-----*/
- KF(markbof) {mark Q=B->bof();
- if(N.i-1==B->nmarks()) Q.hsup(); else B->Mark(N.i)=Q;}
- /*-----*/
- KF(markeof) {mark Q=B->eof();
- if(N.i-1==B->nmarks()) Q.hsup(); else B->Mark(N.i)=Q;}
- /*-----*/
- KF(popmark) {B->dot.pop();}
- /*-----*/
- KF(remmark) {int i; for(i=0;i<N.i;i++) B->rem1mark();}
- /*-----*/
- KF(showregion) {if(!N.i) (B->Mark(1)-B->Mark(2)).color(White,Magenta);
- else (B->Mark(N.i)-B->dot).color(White,Magenta);}
- /*-----*/
- KF(yank) {obtype=ob_yank;
- lastyank=B->dot.yank(killring[nkill]); lastyank.color(White,Magenta);
- if(N.n) if(N.i-1==B->nmarks()) lastyank.beg.hsup();
- else B->Mark(N.i)=lastyank.beg;}
- /*-----*/
- KF(replyank) {if(prevobtype!=ob_yank) {yank(val(1,0),T1,T2); return;}
- obtype=ob_yank; nkill-=N.i; nkill&=15;
- lastyank=lastyank.repl(killring[nkill],1); lastyank.color(White,Magenta);}
- /*-----*//* still no way in Gnu C to tell if a drive is there/usable or not */
- int attrib(char*file){if(isalpha(file[0]))if(file[1]==':')if(!file[2])return 16;
- _ax=0x4300; _dx=(int)file; int21(); if(_carry) return 256*_ax; return _cx;}
- /*----- replace all T1 by T2 between dot and Nth mark */
- void Replace(val N,val T1,val T2,char *prompt,int ask,int word){
- T1.getifn(T1t,prompt,_magic); setrek(T1,T1.copy());
- T2.getifn(T2t,"by:"); setrek(T2,T2.copy());
- mark M=B->Mark(N.i); (M-B->dot).replace(T1,T2,ask,word);}
- /*-----*/
- KF(repl) {Replace(N,T1,T2,"rep:" ,0,0);}
- KF(replword) {Replace(N,T1,T2,"rep word:" ,0,1);}
- KF(replask) {Replace(N,T1,T2,"rep ask:" ,1,0);}
- KF(replwordask) {Replace(N,T1,T2,"rep word ask:",1,1);}
- /*----- move char by N.i positions */
- KF(twiddle) {int i,j,n; line*L=B->dot.r; char*T=L->s;
- if(N.i>0) for(i=0;i<N.i;i++) {L->la(1);
- if((n=B->dot.c)+1>=L->n) MOAN("can't twiddle-chars across line end");
- j=T[n]; T[n]=T[n+1]; T[n+1]=j; B->dot.c++; }
- else for(i=0;i>N.i;i--) {
- if((n=B->dot.c)<=0) MOAN("can't twiddle-chars across line end");
- j=T[n]; T[n]=T[n-1]; T[n-1]=j; B->dot.c--; L->la(1); }; B->changed=1;}
- /*----- look for T1 starting at dot. If N.i set, stop at Nth mark */
- void search(val N,val T1,char*prompt,int back=0,int word=0){int i,n;
- T1.getifn(T1t,prompt,_magic); setrek(T1,T1.copy());
- if((B->dot-(N.n?B->Mark(N.i):back?B->bof():B->eof())).hunt(T1,back,word)) {
- B->dot=back?Found.beg:Found.end; Found.color(White,Magenta);}
- else {strcpy(CW,"not found '"); /* display /000 as space here */
- for(n=(T1.n&0x00ffffff)<?(strsize-12),i=0;i<n;i++) CW[i+11]=T1.s[i]?:' ';
- strcpy(CW+n+11,"'"); MOAN(CW);}}
- /*-----*/
- KF(findf) {search(N,T1,"find:" ,0,0);}
- KF(findb) {search(N,T1,"find back:" ,1,0);}
- KF(findwordf) {search(N,T1,"find word:" ,0,1);}
- KF(findwordb) {search(N,T1,"find word back:",1,1);}
- /*----- incremental search starting at dot. If N.i set, stop at Nth mark */
- void incrsearch(val N,char*pt,int back=0){region where[64+1];
- int p=strlen(pt),sl=B->lastrow,at=gp_Attr,c; mark whoa,start,dot,M;
- where[0]=B->dot-B->dot; Found=where[0]; T1t.n=0; T1t.s=T1w;
- whoa=N.n?B->Mark(N.i):back?B->bof():B->eof(); start=B->start; dot=B->dot;
- GETCHAR: displayn(pt,sl,0,Magenta); display(T1t,sl,p,Cyan);
- cursor.r=sl; cursor.c=(p+T1t.n)<?(gp_Cols-1); gp_cursor(cursor);
- switch(c=getkey()) {
- case -ins: if(!T1t.n) goto GETCHAR; M=back?Found.beg:Found.end; goto HUNT;
- case -del_: if(!T1t.n) goto GETCHAR; Found=where[--T1t.n]; goto DISP;
- case -alt_end: Moan="user abort"; goto OUT;
- case -alt_ret: c=CR; goto C;
- case -pagedown: goto OUT; /* end input */
- default: if(c<=0) goto GETCHAR; if(c==CR) c=LF; /* so RET gives newline */
- C: if(T1t.n>=64) {Moan="incremental search string too long"; goto OUT;}
- if(back) {M=Found.end; ++M; if(!M.r) M=Found.end;} else M=Found.beg;
- T1t.s[T1t.n++]=c;}
- HUNT: if(Moan==offscreen) Moan=0;
- if(!(M-whoa).hunt(T1t,back,0)) beep(); where[T1t.n]=Found;
- DISP: gp_Attr=at; B->dot=back?Found.beg:Found.end; Found.color(White,Magenta);
- B->dotcc=B->dotcc2=-1; Sl[B->lastrow].ok=1; B->display(); goto GETCHAR;
- OUT: gp_Attr=at; Sl[sl].ok=0; T1t.s[T1t.n]=0; B->start=start;
- B->dotcc=B->dotcc2=-1; if(Moan) {Found=where[0]; B->dot=dot; MOAN(Moan);}
- Sl[B->lastrow].ok=0; if(back) setref(f,&findb); else setref(f,&findf);
- setrec(T1,T1t.copy());}
- /*-----*/
- KF(incrfindf) {incrsearch(N,"incr find:" ,0);}
- KF(incrfindb) {incrsearch(N,"incr find back:",1);}
- /*----- read esc-and-number */
- void readescno(short c){if(play) return; int i,j,N; short d=c;
- i=-1; B->display(); N=c=='-'?0:c-'0'; j=B->row1+B->nrows-1;
- CC: i++; pr(CW,"numeric arg: %c%1d",d=='-'?'-':' ',c=='-'?1:N);
- display(CW,j,0,Cyan); gp_cursor(cursor); c=getkey();
- if(c<'0'?0:c<='9') {N=10*N+c-'0'; goto CC;} else nextch=c;
- Sl[j].ok=0; if(d=='-') if(!i) N=-1; else N=-N; Obey(val(N,_int));}
- /*-----*/
- KF(esc0) {readescno('0');} KF(esc1) {readescno('1');} KF(esc2) {readescno('2');}
- KF(esc3) {readescno('3');} KF(esc4) {readescno('4');} KF(esc5) {readescno('5');}
- KF(esc6) {readescno('6');} KF(esc7) {readescno('7');} KF(esc8) {readescno('8');}
- KF(esc9) {readescno('9');} KF(escminus) {readescno('-');}
- /*----- read alt-number */
- void readaltno(short c){if(play) return; int i,j,N; short d=c;
- i=-1; B->display(); N=c=='-'?0:c-'0'; j=B->row1+B->nrows-1;
- C: i++; pr(CW,"numeric arg: %c%1d",d=='-'?'-':' ',c=='-'?1:N);
- display(CW,j,0,Cyan); gp_cursor(cursor); c=getkey();
- if(c==-alt_0) {N=10*N; goto C;}
- else if(-c>=alt_1?-c<=alt_9:0) {N=10*N-c+1-alt_1; goto C;} else nextch=c;
- Sl[j].ok=0; if(d=='-') if(!i) N=-1; else N=-N; Obey(val(N,_int));}
- /*-----*/
- KF(alt0) {readaltno('0');} KF(alt1) {readaltno('1');} KF(alt2) {readaltno('2');}
- KF(alt3) {readaltno('3');} KF(alt4) {readaltno('4');} KF(alt5) {readaltno('5');}
- KF(alt6) {readaltno('6');} KF(alt7) {readaltno('7');} KF(alt8) {readaltno('8');}
- KF(alt9) {readaltno('9');} KF(altminus) {readaltno('-');}
- /*----- modemenu recorded in macro as calls of these */
- KF(tabmode) {int i; B->tabtype=(N.i>?0)<?2; for(i=0;i<gp_Rows;i++) Sl[i].ok=0;}
- KF(twodmode) {B->twod=(N.i>?0)<?1;}
- KF(overlaymode) {B->overlay=(N.i>?0)<?2;}
- KF(wrapmode) {B->wrap=(N.i>?0)<?1;}
- KF(casemode) {B->Case=(N.i>?0)<?1;}
- KF(longlinesmode) {int i;
- B->longlines=(N.i>?0)<?1; for(i=0;i<gp_Rows;i++) Sl[i].ok=0;}
- KF(skipafterwordmode) {B->skip_after_word=(N.i>?0)<?3;}
- KF(cccmode) {ccc=(N.i>?0)<?1;}
- /*----- ith mode */
- byte &bufmode(int i,buffer*BB/*=0*/){if(!BB) BB=B;
- switch(i<0?0:i%buffer_nmodes){
- case 0: return BB->tabtype;
- case 1: return BB->twod;
- case 2: return BB->overlay;
- case 3: return BB->wrap;
- case 4: return BB->Case;
- case 5: return BB->longlines;
- case 6: return BB->skip_after_word;} return BB->tabtype;}
- /*-----*/
- char**dispmode[]={
- (char*[]){" tab shown as one char",
- " tab obeyed",
- " tab shown and obeyed",0},
- (char*[]){" going off end of line goes to next line",
- " going off end of line appends spaces to line",0},
- (char*[]){" typed char inserted",
- " typed char overlays, cursor moves",
- " typed char overlays, cursor stays still",0},
- (char*[]){" no auto newline on typing long text lines",
- " auto newline on typing long text lines",0},
- (char*[]){" in search, ignore case of letters",
- " in search, don't ignore case of letters",0},
- (char*[]){" horiz scroll to show cursor in long lines",
- " display long lines folded",0},
- (char*[]){" don't skip nonword chars after skipping word",
- " nonword chars belong to word to left",
- " nonword chars belong to word to right",
- " skip nonword chars after skipping word",0},0};
- /*-----*/
- KF(modemenu) {int c=0,i,j,n; byte *T; B->dotcc=B->dotcc2=-1; mousestate ms;
- if(play) MOAN("modemenu called by macro"); macstep step; basemi.rec=0;
- static subr *mf[]={&tabmode, &twodmode, &overlaymode, &wrapmode, &casemode,
- &longlinesmode, &skipafterwordmode}; step=macstep();
- for(i=0;i<gp_Cols;i++) Sl[i].ok=0; j=0; n=buffer_nmodes; ms=Jerry; Jerry.mc=1;
- C: for(i=0;i<buffer_nmodes;i++) display(dispmode[i][bufmode(i)],i,0,Orange+8);
- display("(\030 and \031 move, ret changes mode, any other key exits)",
- i,0,Green+8); Jerry.range(buffer_nmodes,4); Jerry.bd=0;
- display("(ctrl-B copies all the modes from some other buffer's modes)",i+1,0,
- Green+8);
- A: if(step.f.n) if(record) {(*record)+=step.copy(); step.del(); step.clear();}
- if(c!=-mousemove) Jerry.move(j,0); scr(j,0)=sch(2,White);
- switch(c=getkey()) {
- case -mousemove: scr(j,0)=sch(' ',White); j=Jerry.y; goto A;
- case -downarrow: scr(j,0)=sch(' ',White); j=(j+1 )%n; goto A;
- case -uparrow: scr(j,0)=sch(' ',White); j=(j-1+n)%n; goto A;
- case 'B'-64: Fn.s[0]=0; Fn.n=0; copybufmodes(val(1,0),Fn);
- step.f=kf(©bufmodes); step.N=val(1,0); step.T1=val("",0); step.T2=val();
- display(" ",B->lastrow,0,0); Fn.s=0; goto C;
- case CR: case -lbutton: T=&bufmode(j,B); (*T)++; if(!dispmode[j][*T]) *T=0;
- display(dispmode[j][*T],j,0,Orange+8);
- step.f=kf(mf[j]); step.N=val(*T,_int);step.T1=val();step.T2=val(); goto A;}
- Jerry=ms;}
- /*-----*/
- KF(copybufmodes){int i; buffer*C=get_file(T1,"copy modes from buffer:");
- if(!C) MOAN("copybufmodes can't find buffer");
- for(i=0;i<buffer_nmodes;i++) bufmode(i,B)=bufmode(i,C);
- setrek(T1,val(copyof(C->name)));}
- /*-----*/
- void insert_(int N,byte c){Insert(N,c);}
- /*-----*/
- void overlay_(int N,byte c){int i; for(i=0;i<N;i++) {B->dot=c; goright(1,1);}}
- /*-----*/
- void nomove_(int N,byte c){int i; for(i=0;i<N;i++) B->dot=c;}
- /*-----*/
- KF(insert) {int i,j,k; if(T1.n==_char) {insert_(N.i,val(T1).i); return;}
- T1.getifn(T1t,"text to insert:"); setrek(T1,T1.copy()); j=T1.n; char*s;
- for(k=0;k<N.i;k++) for(s=T1.s,i=0;i<j;i++) *B+=*s++;}
- /*-----*/
- KF(overlay) {int i,j,k; if(T1.n==_char) {overlay_(N.i,val(T1).i); return;}
- T1.getifn(T1t,"text to overlay:"); setrek(T1,T1.copy()); j=T1.n; char*s;
- for(k=0;k<N.i;k++) for(s=T1.s,i=0;i<j;i++) {B->dot=*s++; goright(1,1);}}
- /*-----*/
- KF(nomove) {int i,j,k; if(T1.n==_char) {nomove_(N.i,val(T1).i); return;}
- T1.getifn(T1t,"text to overlay_no_move:"); setrek(T1,T1.copy()); j=T1.n; char*s;
- for(k=0;k<N.i;k++) for(s=T1.s,i=0;i<j;i++) B->dot=*s++;}
- /*-----*/
- /* int Gets(char*s,int n,FILE*F){int i; fgets(s,n,F);
- if(i=strlen(s)) if(s[i-1]==LF) s[--i]=0; return i;} */
- /*-----*/
- char*helphelp[]={"which key to type now to get what help:-",
- "? this information",
- "a all 'one-line help' lines which contain a particular string",
- "d help about use of special keys in directory menus",
- "i help about use of special keys in incremental search",
- "L explanation of symbols used in help information",
- "l menu to call any one subroutine or get long help about it",
- "m help about magic characters",
- "o help about allowed operator uses in macros",
- "r help about the replace commands",
- "s help about use of alt- and special keys when inputting a string argument",
- "(Any other keysequence gets one-line help about that keysequence)",
- "(For the mouse, see section [MOUSE] in file README)",0};
- /*-----*/
- char*incrhelp[]={"effect of alt- and special keys in incremental search:-",
- "insert look again for this same string",
- "delete cancel effect of typing last displayed character",
- "altend abort search",
- "pagedown exit from search (NB. The search string can't be > 64 chars long)",
- "altret look for CR stored as byte (not as bit) in AAEMACS's line image",
- "ret or ctrl-J or ctrl-M look for end-of-line",
- 0};
- /*-----*/
- char*replhelp[]={"effect of replies to 'shall I replace here?' in replace:-",
- "space yes and look for the next replacing or left mouse button",
- "N or n no and look for the next replacing or middle or right mouse \
- button",
- ". yes and exit",
- "altend no and exit",
- "end no and exit and leave the cursor here",
- 0};
- /*-----*/
- char*dirmenuhelp[]={"effect of alt- and special keys in directory-menus:-",
- "\030 \031 move pointer in menu",
- "pageup move pointer in menu",
- "pagedown move pointer in menu",
- "insert select new buffer (you will be asked for its name)",
- "ctrlinsert create new directory (you will be asked for its name)",
- "delete delete this PC file or directory (if directory, must be empty)",
- "home go to parent directory",
- "alt-K copy this directory to kill ring (online & with ctrl-X ctrl-F)",
- "ctrl_K copy this file's full pathname into a kill",
- "alt-R rename file (not buffer)",
- "alt-del drop this file's buffer, if it has one",
- "ctrl-N sort by name",
- "ctrl-S sort by size",
- "ctrl-D sort by date",
- "ctrl-X don't sort",
- "altend abort",
- "return choose this file or left mouse button",
- "F1 get submenu of these commands or right mouse button",
- 0};
- /*-----*/
- char*magichelp[]={"effect of magic characters in searching:-",
- ". any one character except LF",
- ", any one letter or number or _",
- "space one or more spaces and/or tabs (Note how magic space is shown)",
- "\011 (tab) one or more spaces and/or tabs and/or LF's",
- "| separates alternatives",
- "[ ] start & end of a set of alternatives",
- "# any one character not a letter or number or '_'",
- "\\ beginning or end of file",
- "/ LF or beginning or end of file",
- "{ } set start & end of 'string found' (default = all matched chars)",
- "lowercase letter uppercase or lowercase of that letter",
- "= the rest of the current line (not any LF at its end)",
- "Magic search is quicker if the first character in the search string is not \
- magic",
- 0};
- /*-----*/
- char**infohelp=0,**infobig=0;
- char**Subrhelp(char*name){int i,n=strlen(name); char*s;
- if(!infobig) {infobig=readtext(bighelpfile);
- if(!infobig) {pr(CW,"I can't find %s",bighelpfile); Moan=CW; return 0;}}
- for(i=0;s=infobig[i];i++) if(s[0]=='{') if(!strncmp(s+1,name,n))
- if(s[n+1]==','?1:s[n+1]=='}') return infobig+i;
- pr(CW,"no long help for subroutine %s",name); Moan=CW; return 0;}
- /*-----*/
- KF(help) {int i,j,k,kc,l,m,n,p; char *s,*T,cw[256],*y,**u;
- if(!play) basemi.rec=0;
- val f; Subr*sub; char*Z="type '?', or key sequence that help is wanted for:";
- if(T1.s) f=T1.keyseq(); else f=getkeyseq(Z); if(f.n==_bad) MOAN(f.s);
- LOOP: pr(cw,"%k :: ",&keyseq); n=strlen(cw); kc=keyseqc[keyseqc[0]-1];
- if(keyseqc[0]!=2 ?: kc<32) switch(f.n){ /* if not printable */
- default:cw[n-3]=0;pr(CW,"BUG: %sbound to a %s",cw,f.n>0?"string":keysort[-f.n]);
- Display=CW; return;
- case 0: pr(CW,f.s?"BUG: %sbound to empty string":"%sis unbound",cw);
- Display=CW; return;
- case _subr: if(!infohelp) {infohelp=readtext(helpfile);
- if(!infohelp) {pr(CW,"I can't find %s",helpfile); Moan=CW; return;}}
- for(i=0;s=infohelp[i];i++) if(!strncmp(s,cw,n)) {Display=s; return;}
- Moan="no help for this key"; return;
- case _macro: pr(CW,"%sbound to a macro",cw); Display=CW; return;
- case _keyarray: Display="BUG: this key sequence is not complete"; return;
- case _buffer: pr(CW,"%sbound to buffer %s",cw,f.b->name); Display=CW; return;
- case _int: pr(CW,"BUG: %sbound to integer %1d",cw,f.i); Display=CW; return;}
- display(" ",B->lastrow,0,Orange);
- switch(kc){ /* if printable */
- default: pr(CW,"inserts or overlays '%c' according to mode of buffer",kc);
- Display=CW; return;
- case '?': for(j=0;T=helphelp[j];j++) display(T,j,0,Green);
- f=getkeyseq(Z); refreshscreen(); goto LOOP;
- case 'a': if(!infohelp) {infohelp=readtext(helpfile);
- if(!infohelp) {pr(CW,"I can't find %s",helpfile); Moan=CW; return;}}
- for(m=0;infohelp[m];m++); y=new char[m]; for(i=0;i<m;i++) y[i]=0; T1.n=0;
- T1.s=0; T1.getifn(T1t,"apropos:"); for(p=j=i=0;s=infohelp[i];i++) {
- for(k=strlen(s)-T1.n,l=0;l<=k;l++) if(caseq(T1,val(s+l,T1.n))) goto X;
- continue; X: y[i]=1; p++;}
- if(!p) {pr(CW,"Nothing found. For help, read file %s\\README",DIR); Moan=CW;
- delete y; return;}
- for(j=i=0;i<m;i++) if(y[i]) {
- if(j==gp_Rows-1){display("(More)",j,0,Green); getkey(); j=0;}
- display(infohelp[i],j++,0,Orange);}
- delete y; break;
- case 'd': for(j=0;T=dirmenuhelp[j];j++) display(T,j,0,Orange); break;
- case 'i': for(j=0;T=incrhelp[j];j++) display(T,j,0,Orange); break;
- case 'l': sub=subrmenu("subroutine to get help for?"); if(!sub) goto LOOP;
- B->display(); if(!(u=Subrhelp(sub->name))) return; j=0;
- display(*u++,j++,0,Orange); while(*u?**u!='{':0) display(*u++,j++,0,Orange);
- display("(type 'ctrl-_ L' to find about the symbols)",j++,0,Green); break;
- case 'L': if(!infobig) {infobig=readtext(bighelpfile);
- if(!infobig) {pr(CW,"I can't find %s",bighelpfile); Moan=CW; return;}}
- for(j=i=0;(s=infobig[i])?strncmp(s,"----",4):0;i++) display(s,j++,0,Orange);
- break;
- case 'm': for(j=0;T=magichelp[j];j++) display(T,j,0,Orange); break;
- case 'o': j=display_op_uses(); break;
- case 'r': for(j=0;T=replhelp[j];j++) display(T,j,0,Orange); break;
- case 's': for(j=0;T=getstringhelp[j];j++) display(T,j,0,Orange); break;}
- display("(type ctrl-_ for more help, any other char to continue)",j,0,Green);
- if(getkey()=='_'-64) {f=getkeyseq(Z); refreshscreen(); goto LOOP;}}
- /*----- obey subr for all bound key entries */
- void forallkeys(void fn(val*),int L/*=1*/,keyarray&K/*=keys*/){int k; val*f;
- for(k=0;k<K.n;k++){keyseqc[0]=L+1; f=&K.a[(byte)(keyseqc[L]=k)];
- if(f->n) if(f->n==_keyarray) forallkeys(fn,L+1,*f->k); else fn(f);}}
- /*-----*/
- void moan_if_no_help(val*f){char **info,*s,cw[128]; int i,j;
- pr(cw,"%k :: ",&keyseq); j=strlen(cw);
- info=readtext(helpfile); if(!info){pr(CW,"I can't find %s",helpfile); MOAN(CW);}
- for(i=0;s=info[i];i++) if(!strncmp(s,cw,j)) goto E;
- *B+=cw; *B+=" has no help\n"; E: delete info[0]; delete info;}
- /*-----*/
- void prbuffer(buffer*C){
- if(C->bound.n) pb("#buffer(%S,%K);\n",C->name,&C->bound);
- else pb("#buffer(%S);\n",C->name);}
- /*-----*/
- void print_subr(val*f){pb("%k :: ",&keyseq);macstep(*f,1,0).print(); newline();}
- /*-----*/
- KF(checkhelp) {forallkeys(moan_if_no_help);}
- /*-----*/
- KF(prbuffers) {buffer*C; forallbufs(C) prbuffer(C);}
- /*-----*/
- KF(prbindings) {forallkeys(print_subr);}
- /*-----*/
- Subr*namedsubr(val name){reg int i,j,n=name.n; reg Subr*T; reg char*s,*S=name.s;
- if(!n) return subrmenu("subr to call?");
- for(i=0;s=(T=&subrname[i])->name;i++) {if(T->n!=n) goto NO;
- for(j=0;j<n;j++) if(s[j]!=S[j]) goto NO; return subrname+i; NO:;} return 0;}
- /*-----*/
- int keyseqeq(val a,val b){if(a.n==_keyseq) if(b.n==_keyseq)
- if(a.s[0]==b.s[0]) if(byteq(a.s+1,b.s+1,a.s[0]-1)) return 1; return 0;}
- /*-----*/
- val*getk(val arg,char*prompt/*=0*/){val *f; byte i; AGAIN:
- if(arg.s) f=&arg.keyseq(); else f=&getkeyseq(prompt); if(f->n==_bad) MOAN(f->s);
- if(keyseqc[0]==2) if((byte)keyseqc[1]>=32) MOAN("can't bind a printable char");
- if(keyseqc[0]==3) if(!keyseqc[1])
- if(i=keyseqc[2],i==lbuttond?:i==mbuttond?:i==rbuttond?:i==mousemove)
- goto AGAIN; return f;}
- /*-----*/
- char*val::moanifbound(val K,int jump/*=1*/){char*x=0; if(n==_bad) x=s;
- else if(K.n==_char ? (K.i<32 ?0: K.i<256) : K.s[0]!=2 ?0: (byte)K.s[1]>=32)
- x="can't bind a printable char";
- else if(n?:s!=0) pr(x=CW,"%k is already bound to a %t",&K,n);
- if(jump) if(x) MOAN(x); return x;}
- /*-----*/
- KF(bindkeymacro) {val*f; if(!Macro) MOAN("no macro to bind");
- if(Macro->bound.n) {
- pr(CW,"this macro is already bound to %k",&Macro->bound); MOAN(CW);}
- f=getk(T1,"type key sequence to bind to current macro");
- setrek(T1,keyseq.copy()); f->moanifbound(keyseq);
- *f=*Macro; Macro->bound=keyseq.copy();}
- /*-----*/
- KF(bindkeysubr) {val*f,g;
- g=T1.getifn(T1t,"name of subroutine to bind to key:",_subr);
- f=getk(T2,"type key sequence to bind to subroutine");
- f->moanifbound(keyseq); if(!g.n) MOAN("no such subroutine");
- setrek(T1,T1.copy()); setrek(T2,keyseq.copy()); *f=kf(g.S->f);}
- /*-----*/
- void buffer::bind(val*f,val T1) {if(keyseqeq(T1,bound)) return;
- if(bound.n) {pr(CW,"this buffer is already bound to %k",&bound); MOAN(CW);}
- f->moanifbound(T1); *f=this; bound=T1.copy(); if(nrows) Sl[lastrow].ok=0;}
- /*-----*/
- KF(bindkeybuf){
- val*f=getk(T1,"type key sequence to bind to current buffer"); B->bind(f,keyseq);
- setrek(T1,keyseq.copy());}
- /*-----*/
- void val::unbind() {switch(n) {
- case _keyarray: MOAN("can't unbind a keyarray");
- case _buffer: delete b->bound.s; b->bound=val(); break;
- case _macro: if(m!=Macro) delete m;
- else {delete m->bound.s; m->bound=val();} break;
- case 0: MOAN("this key is already unbound");};
- s=0; n=0;}
- /*-----*/
- KF(unbindkey) {val *f;
- if(T1.s) f=&T1.keyseq(); else f=&getkeyseq("type key sequence to unbind");
- if(f->n==_bad) MOAN(f->s); setrek(T1,keyseq.copy()); f->unbind();}
- /*----- buffer(char*) : find/get buffer with this filename */
- buffer::buffer(char*F,int rd/*=1*/){buffer *BB=B; B=this; initbuffer();
- ncols=gp_Cols; linkin();
- if(F?F[0]:0) {name=copyof(F); if(rd) read();} else name=copyof("(no file)");
- B=BB;}
- /*----- returns buffer with this name (0 if no buffer has this name) */
- buffer*buf_named(val name){buffer*C;
- forallbufs(C) if(C->name) if(!strcmp(C->name,name.s)) return C; return 0;}
- /*-----*/
- buffer*findbuf(val name){buffer*C;
- forallbufs(C) if(!strcmp(C->name,name.s)) return C; return new buffer(name.s);}
- /*-----*/
- KF(renamebuffer) {
- T1.getifn(Fn,"new filename for buffer?",_buffer); setrek(T1,T1.copy());
- if(buf_named(T1)) {pr(CW,"%s already has a buffer",Filename); MOAN(CW);}
- delete B->name; B->name=new char[strlen(T1.s)+1]; strcpy(B->name,T1.s);
- Sl[B->lastrow].ok=0;}
- /*-----*/
- KF(onewindow) {int i;
- for(i=0;i<nwindows;i++) window[i]->row1=window[i]->nrows=window[i]->lastrow=0;
- nwindows=1; window[0]=B; B->row1=0; B->nrows=gp_Rows; B->lastrow=gp_Rows-1;
- for(i=0;i<gp_Rows;i++) Sl[i].ok=0; currentwindow=0;}
- /*-----*/
- KF(splitwindow) {
- get_file(T1,"file for new window:")->split_window_with(N.n?N.i:B->nrows/2);}
- /*-----*/
- KF(nextwindow) {int i;
- if(N.i<0) for(i=0;i>N.i;i--) {if(--currentwindow<0) currentwindow=nwindows-1;}
- else for(i=0;i<N.i;i++) {if(++currentwindow>=nwindows) currentwindow=0;}
- B=window[currentwindow]; B->dotcc=B->dotcc2=-1;}
- /*-----*/
- KF(prevwindow) {nextwindow(-N.i,1);}
- /*-----*/
- buffer*get_file(val&T1,char*p) {buffer*C=T1.getifn(Fn,p,_buffer).b?:findbuf(T1);
- if(!thisstep.T1.n) setrek(T1,T1.copy()); return C;}
- /*-----*/
- void buffer::operator()(int N/*=0*/){
- if(N<0) split_window_with(N==-1?B->nrows/2:-N);
- else if(!N) B->dot+=this; else go_to();}
- /*-----*/
- KF(buffer_){buffer*C=T1.n==_buffer?T1.b:get_file(T1,"go to file:"); (*C)(N.i);
- if(T2.n==_keyseq) {
- C->bind(getk(T2,"type key sequence to bind to current buffer"),T2);
- setrek(T2,keyseq.copy());}}
- /*-----*/
- KF(openfile) {get_file(T1,"go to file:")->go_to();}
- /*-----*/
- KF(restorebuf) {int i; B->deltext(); B->read();
- for(i=B->row1;i<=B->lastrow;i++) Sl[i].ok=0;}
- /*-----*/
- buffer*buffer_menu(char*prompt) {mousestate ms; ms=Jerry; Jerry.mc=1;
- int i,j=0,k,m,n,w=gp_Rows-1,Y=0; val F; buffer *D,**C; B->dotcc=-1;
- Z: for(n=0,D=bhead;D;D=D->next,n++); C=(buffer**)myalloc(n*sizeof(buffer*));
- for(i=0,D=bhead;D;D=D->next,i++) if(B==(C[i]=D)) j=i;
- Jerry.range(n,80); Jerry.move(j,0);
- E: k=w/2; k=j<w?0:((j-w/4)/k)*k;
- for(i=k;i<n;i++) {if(i-k>=w) break;
- pr(CW," %c%2d %s",C[i]->changed?'*':' ',i,C[i]->name);
- if(C[i]->bound.n) pa(CW," (%k)",&C[i]->bound);
- CW[gp_Cols]=0; display(CW,i-k,0,Orange);}
- for(i=(w<?n)-1;i>=n-k;i--) display(" ",i,0,Orange);
- display("(\030\031 move, esc \032 file not listed, del removes buffer, \
- RET chooses)", w<?n,0,Orange);
- A: i=k; k=w/2; k=j<w?0:((j-w/4)/k)*k; if(i!=k) goto E;
- scr(j-k,0)=sch(2,White); m=j-k; switch(Y=getkey()) {
- case -mousemove: j=Jerry.y; break;
- case -downarrow: j=(j+1 )%n; break;
- case -uparrow: j=(j-1+n)%n; break;
- case -del_: if(deletebuffer(C[j])) {j=0; free(C); goto Z;} goto A;
- case -rbutton: case -mbutton: case '['-64: scr(j-k,0)=sch(' ',White); F.n=0;
- D=F.getifn(Fn,prompt,_buffer).b?:findbuf(F); goto Q;
- case -alt_end: D=B; goto Q;
- case CR: case -lbutton: D=C[j]; Q: free(C); Jerry=ms; return D;}
- scr(m,0)=sch(' ',White); if(Y!=mousemove) Jerry.move(j,0); goto A;}
- /*-----*/
- KF(buffermenu) {if(play) MOAN("BUG: obeyed buffermenu from macro");
- buffer*C=buffer_menu("file:"); setref(f,&openfile); setrec(N,val(1,0));
- setrek(T1,val(C->name).copy()); C->go_to();}
- /*----- insert copy of buffer at mark */
- void mark::operator+=(buffer*BB){
- if(B==BB) MOAN("can't insert buffer into itself");
- B->dot.yank(Text(BB->text.next,BB->text.prev),1);}
- /*-----*/
- KF(insertfile) {buffer *C,*Y=B; Text KK; /* don't create new buffer specially */
- C=T1.getifn(Fn,"insert file:",_buffer).b?:buf_named(T1.s); setrek(T1,T1.copy());
- B=Y; if(B==C) MOAN("can't insert buffer into itself");
- if(C) KK=Text(C->text.next,C->text.prev).copy(); else KK.read(T1.s);
- region Z=B->dot.yank(KK,0); B->changed=1; if(N.n) B->Mark(N.i)=Z.beg;}
- /*-----*/
- KF(mergefile) {buffer *C; Text K; line*U,*V,*W,*X,*Y,*Z; int c;
- C=T1.getifn(Fn,"merge into region file:",_buffer).b?:buf_named(T1.s);
- setrek(T1,T1.copy()); if(B==C) MOAN("can't merge buffer with itself");
- if(C) K=Text(C->text.next,C->text.prev).copy(); else K.read(T1.s);
- if(!K.end->n) if(K.beg==K.end) return; /* no lines to merge in */
- else {K.end=(X=K.end)->prev; X->del();} /* final empty line */
- X=B->dot.r; Z=B->Mark(N.i).r?:X; if(c=Z<X) {W=Z; Z=X; X=W;} K.end->next=0;
- U=X=X->prev?:&B->text; Y=K.beg;
- L: if(Breakin()) goto END; if(X->next==Z) {*X-*Y; *K.end-*Z; goto END;}
- if(compare(X->next,Y)<0) {X=X->next; goto L;}
- W=Y; V=X->next; while(W->next?compare(V,W->next)>=0:0) W=W->next;
- *X-*Y; Y=W->next; *W-*V; X=V; if(Y) goto L;
- END: if(c) B->Mark(N.i)=mark(U->next,0); else B->dot=mark(U->next,0);
- B->text.prev->next=B->text.next->prev=0; B->changed=1;}
- /*-----*/
- KF(readmacros) {
- buffer*C=T1.getifn(Fn,"file to read macros from:",_buffer).b?:findbuf(Fn);
- val T=T1.copy(),U=T2.copy(); translate(C); setrek(T1,T); setrek(T2,U);}
- /*-----*/
- KF(accentedletters) {int i; static
- char accuc[39]="\200\232\220\203\216\205\217\200\210\211\212\213\214\215\216\
- \217\220\222\222\223\231\225\226\227\230\231\23200000\240\241\242\243\245\245";
- static
- char acclc[39]="\207\201\202\203\204\205\206\207\210\211\212\213\214\215\204\
- \206\202\221\221\223\224\225\226\227\230\224\20100000\240\241\242\243\244\244";
- for(i=128;i<256;i++) {chtype[i]&=~c_alnum; to__upper[i]=to__lower[i]=i;}
- if(N.i) {for(i=0;i<39;i++) if(accuc[i]) {chtype[i+128]|=c_alnum;
- to__upper[i+128]=accuc[i]; to__lower[i+128]=acclc[i];}}}
- /*-----*/
- void mark::skipword(int N){int i;
- if(N>=0) {for(i=0;i<N;i++) {find_alnum(0,1); skip_alnum(0);}
- if(B->skip_after_word&1) find_alnum(0,1);}
- else {for(i=0;i>N;i--) {find_alnum(1,1); skip_alnum(1);}
- if(B->skip_after_word&2) find_alnum(1,1);}}
- /*-----*/
- KF(skipwordf){B->dot.skipword(N.i);}
- KF(skipwordb){B->dot.skipword(-N.i);}
- KF(killwordf){obtype=ob_kill;mark Q=B->dot;Q.skipword( N.i); (B->dot-Q).kill();}
- KF(killwordb){obtype=ob_kill;mark Q=B->dot;Q.skipword(-N.i); (Q-B->dot).kill();}
- /*-----*/
- region thisword(int N/*=1*/){mark L,M=B->dot;
- if(N<0) {if(M.is_alnum()) M.skip_alnum(0); else M.find_alnum(1,1);
- if(!(B->skip_after_word&2)) M.find_alnum(0,1); L=M; L.skipword(N);}
- else {L=M; if(L.is_alnum()) L.skip_alnum(1); else L.find_alnum(0,1);
- if(!(B->skip_after_word&1)) L.find_alnum(1,1); M=L; M.skipword(N);}
- return L-M;}
- /*-----*/
- region thispara(){line *K=B->dot.r,*L;
- while(!K->is_bop()) K=K->prev;
- if(L=K->next) while(!L->is_eop()) if(!(L=L->next)) break;
- if(!L) L=(*B->text.prev)/val("",0); return mark(K,0)-mark(L,0);}
- /*-----*/
- KF(twiddlewords) {region TW=thisword(N.i>=0?1:-1); mark Q=N.i>=0?TW.end:TW.beg;
- Q.skipword(N.i); TW.moveto(Q).color(White,Magenta); B->changed=1;}
- /*-----*/
- KF(twiddlelines) {int i; line *X,*Y,*Z,*U,*V; if(!N.i) return;
- Y=B->dot.r; X=Y->prev?:&B->text; Z=Y->next?:&B->text;
- if(N.i>0) {U=Y; for(i=0;i<N.i;i++) if(V=U->next) U=V; else break;
- if(Y==U) MOAN("end of buffer"); V=U->next?:&B->text;}
- else {V=Y; for(i=0;i>N.i;i--) if(U=V->prev) V=U; else break;
- if(Y==V) MOAN("start of buffer"); U=V->prev?:&B->text;}
- *X-*Z; *U-*Y; *Y-*V; Y->la(1); B->text.prev->next=B->text.next->prev=0;
- (mark(Y,0)-mark(Y,Y->n)).color(White,Magenta); B->changed=1;}
- /*-----*/
- void casechange(int N,line*L,int b,int e){
- int i; char t,*s=L->s; byte*cs=N?to__upper:to__lower;
- for(i=b;i<e;i++) {t=s[i]; s[i]=cs[(byte)t]; if(t!=s[i]) L->la(1);}}
- /*-----*/
- void region::Case(int N){line *L; if(beg==end) return; B->changed=1;
- for(L=beg.r;L;L=L->next) {if(!L) return;
- casechange(N,L,L==beg.r?beg.c:0,L==end.r?end.c:L->n);
- if(L==end.r) break;}}
- /*-----*/
- void region::format(){line *K,*L; if(beg==end) return; B->changed=1;
- if(beg.c) {end.push(); L=beg/1; end.pop();} else L=beg.r;
- if(end.c) {end.push(); end/1; end.pop();}
- A: K=L->next; L->de_trailing_space(); L->split_if_long(); if(!K) return;
- if(K==end.r) return; L=K->prev; (*L)+=' '; --*L; goto A;}
- /*-----*/
- KF(formatregion) {(B->Mark(N.i)-B->dot).format();}
- KF(upcaseregion) {(B->Mark(N.i)-B->dot).Case(1);}
- KF(lwcaseregion) {(B->Mark(N.i)-B->dot).Case(0);}
- KF(upcasewords) {region TW=thisword(N.i);
- TW.Case(1); B->dot=N.i<=0?TW.beg:TW.end;}
- KF(lwcasewords) {region TW=thisword(N.i);
- TW.Case(0); B->dot=N.i<=0?TW.beg:TW.end;}
- KF(capitalize){region TW=thisword(); TW.Case(0); mark Q=TW.end; Q.skip_alnum(1);
- if(!Q.eol()) {char*T=&Q.r->s[Q.c]; *T=to_upper(*T); Q.r->la(1);}
- B->dot.skipword(1);}
- /*-----*//* reformat with left margin */
- KF(formatinsetregion) {char*D=Display; region F=Found; int i;
- region R(B->Mark(N.i),B->dot); if(R.beg==R.end) return; R.right_order();
- T1.getifn(T1t,"chars to prefix to each line:"); setrek(T1,T1.copy());
- T2.getifn(T2t,"chars prefixing each line now:",0,T1.s); setrek(T2,T2.copy());
- if(T2.n) {char s[T2.n+4]="/{"; val T(s,T2.n+2+0x80000000); s[T2.n+2]=0;
- s[T2.n+3]=0xc0; /*magic*/ memcpy(s+2,T2.s,T2.n); R.replace(T,val("",0));}
- i=B->rmargin; B->rmargin=((i>0?i:-i)-T1.n)>?11; R.format(); B->rmargin=i;
- if(T1.n) (R.beg-mark(R.end.r->prev,0)).replace(val("/{\000\300",0x80000002),T1);
- Found=F; Display=D;}
- /*-----*/
- val eosentchars(".!?",3);
- /*-----*/
- void mark::skipsentence(int N){mark Q; int i=0xfff,j,k;
- if(N>0) for(k=0;k<N;k++) {A: Q=*this; ++*this; if(!r) {*this=Q; return;}
- j=i; i=**this; if(eosentchars>>j) if(iswhite(i)) continue; goto A;}
- else for(k=0;k>N;k--) {C: Q=*this; --*this; if(!r) {*this=Q; return;}
- j=i; i=**this; if(eosentchars>>i) if(iswhite(j)) continue; goto C;}}
- /*-----*/
- KF(killsent) {
- obtype=ob_kill; mark Q=B->dot; Q.skipsentence(N.i); (B->dot-Q).kill();}
- /*-----*/
- int line::is_bop(){if(n) if(iswhite(s[0])) return 1;
- if(!prev) return 1; return prev->blank();}
- /*-----*/
- int line::is_eop(){if(!n) return 1; return iswhite(s[0]);}
- /*-----*/
- void mark::skippara(int N){line *K,*L; int i;
- if(N>0){for(i=0;i<N;i++) {for(L=r;K=L->next;L=K){if(L!=r)if(K->is_eop()) break;}
- if(!K) K=*L/val("",0); r=K; c=0;}}
- else {for(i=0;i>N;i--) {for(L=r;K=L->prev;L=K) if(L!=r) if(K->is_bop()) break;
- r=K?:L; c=0;}}}
- /*-----*/
- KF(skipsentf) {B->dot.skipsentence(N.i);}
- KF(skipsentb) {B->dot.skipsentence(-N.i);}
- KF(skipparaf) {B->dot.skippara(N.i);}
- KF(skipparab) {B->dot.skippara(-N.i);}
- KF(formatpara) {thispara().format();}
- /*-----*/
- KF(callsubr) {val f=T1.getifn(T1t,"subr name:",_subr);
- if(!f.n) MOAN("no such subroutine or macro");
- if(f.n==_macro) {(*f.m)(N); setrec(f,f.m);}
- else {setref(f,f.S->f); f.S->f(N,val(),val());}}
- /*-----*/
- KF(gotoline) {int i; gotobof(); for(i=1;i<N.i;i++) godown();}
- /*-----*/
- KF(prkeys) {keys.print(N.i);}
- /*-----*/
- KF(prkeynames) {int i; char *s;
- for(i=0;i<256;i++) if(s=altnames[i]) {*B+=s; newline();}
- for(i=0;i<255;i++) if(s=keyname(i,0), strlen(s)>1) {*B+=s; newline();}
- *B+="(the other printable characters represent themselves)\n";}
- /*-----*/
- KF(prsubrnames) {int i; char *s;
- for(i=0;s=subrname[i].name;i++) {*B+=s; newline();}}
- /*-----*/
- KF(gotonbuf) {buffer*A;
- if(!N.n) {A=B; do{A=A->next?:bhead;} while(A->nrows?A!=B:0); A->go_to();}
- else {int i; A=bhead; for(i=0;i<N.i;i++) if(!(A=A->next)) break;
- if(A) A->go_to();
- else {pr(CW,"there are < %1d buffers",N.i); MOAN(CW);}}}
- /*-----*/
- KF(copytext){(B->Mark(N.i)-B->Mark(N.i+1)).copyto(B->dot).color(White,Magenta);}
- /*-----*/
- KF(movetext){(B->Mark(N.i)-B->Mark(N.i+1)).moveto(B->dot).color(White,Magenta);}
- /*-----*/
- KF(delblanklines) {line*K,*L,*Z; K=L=Z=B->dot.r; if(!K->blank()) return;
- while(L=K->prev,L?L->blank():0) K=L; while(Z->next?Z->blank():0) Z=Z->next;
- (mark(K,0)-mark(Z,0)).Delete(0); B->changed=1;}
- /*-----*/
- KF(deletewhite) {int i,j,k; line*L=B->dot.r; j=k=B->dot.c;
- while(!j ?0:((i=L->s[j-1]),i==' '?1:i==9)) j--;
- while(k>=L->n?0:((i=L->s[k ]),i==' '?1:i==9)) k++;
- (mark(L,j)-mark(L,k)).Delete(0); B->dot.r->la(1); B->changed=1;}
- /*-----*/
- KF(leaveonewhite) {deletewhite(N,T1,T2); B->dot+=' ';}
- /*-----*/
- KF(calldos) {T1.getifn(T1t,"DOS command:"); setrek(T1,T1.copy()); clearscreen();
- int i=system(T1.s); getkey(); if(i) Moan="DOS command error";}
- /*-----*/
- int compare(line*X,line*Y){reg int i; reg char *x=X->s,*y=Y->s;
- i=B->sortcol; if(i>=X->n) return i>=Y->n?0:-1; else if(i>=Y->n) return 1;
- x+=i; y+=i; reg char *z=x+(X->n<?Y->n);
- if(B->Case) {
- for(;i=(byte)*x-(byte)*y,x<z;x++,y++) if(i) return i; return X->n-Y->n;}
- else {
- for(;i=(byte)to__lower[(byte)*x]-(byte)to__lower[(byte)*y],x<z;x++,y++)
- if(i) return i; return X->n-Y->n;}}
- /*-----*/
- KF(sortlines){int i,j,k; mark x=B->dot,y=B->Mark(N.i),z,*M;
- if(y<x) {z=x; x=y; y=z;} line*a=x.r,*b=y.r,*X,*Y,*e; if(a==b?:a->next==b)return;
- B->changed=1; z=B->dot; for(j=1,e=a;e?e!=b:0;e=e->next) j++;
- for(k=0,i=1;Breakin()?0:i?k<=j:0;k++) {reg int n; reg char*s;
- if(a==b?:a->next==b) goto Z; e=a; i=0;
- for(Y=(X=a)->next;Y!=b;X=Y,Y=Y->next) if(compare(X,Y)>0) {
- e=Y; i=1; X->la(1); Y->la(1);
- n=X->n; X->n=Y->n; Y->n=n; s=X->s; X->s=Y->s; Y->s=s;}
- B->dot=mark(e,0); B->start.c<?=B->start.r->n;
- forallmarks(M) M->c<?=M->r->n; B->display();
- for(X=(Y=b->prev)->prev;;Y=X,X=X->prev) {if(compare(X,Y)>0) {
- e=Y; i=1; X->la(1); Y->la(1);
- n=X->n; X->n=Y->n; Y->n=n; s=X->s; X->s=Y->s; Y->s=s;} if(X==a) break;}
- B->dot=mark(e,0); B->start.c<?=B->start.r->n; b=b->prev; if(a!=b) a=a->next;
- Z: forallmarks(M) M->c<?=M->r->n; B->display();}
- z.c<?=z.r->n; B->dot=z;}
- /*-----*/
- KF(setsortcol) {if(N.n) B->sortcol=N.i>?0;
- pr(disp,"sortlines will ignore the first %1d chars in lines",B->sortcol);
- Display=disp;}
- /*-----*/
- KF(expandtabs) {(B->dot-B->Mark(N.i)).expandtabs();}
- /*-----*/
- KF(maketabs) {(B->dot-B->Mark(N.i)).maketabs();}
- /*-----*/
- KF(displayhex) {mark M=B->dot; int i=0,j; static char d[17]="0123456789abcdef";
- char*e=CW+512;
- A: if(M.c>=M.r->n) {if(!M.r->next) goto Z;
- if(!M.r->no_cr()) {e[i]=CR; CW[i++]='0'; e[i]=' '; CW[i++]=d[CR];}
- e[i]=LF; CW[i++]='0'; e[i]=' '; CW[i++]=d[LF];
- M.r=M.r->next; M.c=0; goto A;}
- j=M.r->s[M.c++]; e[i]=j?:' '; CW[i++]=d[(j>>4)&15]; e[i]=' '; CW[i++]=d[j&15];
- if(i<256) goto A;
- Z: e[i]=0; CW[i]=0; Moan=e; Display=CW;}
- /*-----*/
- KF(version) {Display=VERSION;}
- /*-----*/
- KF(dis_play) {T1.getifn(T1t,"text to display?"); setrek(T1,T1.copy());
- display(T1.s,B->lastrow,0,Cyan);}
-