ref: 2aec1f8a09ae0bc9fb269d84ef53defebc47eede
dir: /sys/src/cmd/sam/rasp.c/
#include "sam.h" /* * GROWDATASIZE must be big enough that all errors go out as Hgrowdata's, * so they will be scrolled into visibility in the ~~sam~~ window (yuck!). */ #define GROWDATASIZE 50 /* if size is > this, send data with grow */ void rcut(List*, Posn, Posn); int rterm(List*, Posn); void rgrow(List*, Posn, Posn); static Posn growpos; static Posn grown; static Posn shrinkpos; static Posn shrunk; /* * rasp routines inform the terminal of changes to the file. * * a rasp is a list of spans within the file, and an indication * of whether the terminal knows about the span. * * optimize by coalescing multiple updates to the same span * if it is not known by the terminal. * * other possible optimizations: flush terminal's rasp by cut everything, * insert everything if rasp gets too large. */ /* * only called for initial load of file */ void raspload(File *f) { if(f->rasp == nil) return; grown = f->nc; growpos = 0; if(f->nc) rgrow(f->rasp, 0, f->nc); raspdone(f, 1); } void raspstart(File *f) { if(f->rasp == nil) return; grown = 0; shrunk = 0; outbuffered = 1; } void raspdone(File *f, int toterm) { if(f->dot.r.p1 > f->nc) f->dot.r.p1 = f->nc; if(f->dot.r.p2 > f->nc) f->dot.r.p2 = f->nc; if(f->mark.p1 > f->nc) f->mark.p1 = f->nc; if(f->mark.p2 > f->nc) f->mark.p2 = f->nc; if(f->rasp == nil) return; if(grown) outTsll(Hgrow, f->tag, growpos, grown); else if(shrunk) outTsll(Hcut, f->tag, shrinkpos, shrunk); if(toterm) outTs(Hcheck0, f->tag); outflush(); outbuffered = 0; if(f == cmd){ cmdpt += cmdptadv; cmdptadv = 0; } } void raspflush(File *f) { if(grown){ outTsll(Hgrow, f->tag, growpos, grown); grown = 0; } else if(shrunk){ outTsll(Hcut, f->tag, shrinkpos, shrunk); shrunk = 0; } outflush(); } void raspdelete(File *f, uint p1, uint p2, int toterm) { long n; n = p2 - p1; if(n == 0) return; if(p2 <= f->dot.r.p1){ f->dot.r.p1 -= n; f->dot.r.p2 -= n; } if(p2 <= f->mark.p1){ f->mark.p1 -= n; f->mark.p2 -= n; } if(f->rasp == nil) return; if(f==cmd && p1<cmdpt){ if(p2 <= cmdpt) cmdpt -= n; else cmdpt = p1; } if(toterm){ if(grown){ outTsll(Hgrow, f->tag, growpos, grown); grown = 0; }else if(shrunk && shrinkpos!=p1 && shrinkpos!=p2){ outTsll(Hcut, f->tag, shrinkpos, shrunk); shrunk = 0; } if(!shrunk || shrinkpos==p2) shrinkpos = p1; shrunk += n; } rcut(f->rasp, p1, p2); } void raspinsert(File *f, uint p1, Rune *buf, uint n, int toterm) { Range r; if(n == 0) return; if(p1 < f->dot.r.p1){ f->dot.r.p1 += n; f->dot.r.p2 += n; } if(p1 < f->mark.p1){ f->mark.p1 += n; f->mark.p2 += n; } if(f->rasp == nil) return; if(f==cmd && p1<cmdpt) cmdpt += n; if(toterm){ if(shrunk){ outTsll(Hcut, f->tag, shrinkpos, shrunk); shrunk = 0; } if(n>GROWDATASIZE || !rterm(f->rasp, p1)){ rgrow(f->rasp, p1, n); if(grown && growpos+grown!=p1 && growpos!=p1){ outTsll(Hgrow, f->tag, growpos, grown); grown = 0; } if(!grown) growpos = p1; grown += n; }else{ if(grown){ outTsll(Hgrow, f->tag, growpos, grown); grown = 0; } rgrow(f->rasp, p1, n); r = rdata(f->rasp, p1, n); if(r.p1!=p1 || r.p2!=p1+n) panic("rdata in toterminal"); outTsllS(Hgrowdata, f->tag, p1, n, tmprstr(buf, n)); } }else{ rgrow(f->rasp, p1, n); r = rdata(f->rasp, p1, n); if(r.p1!=p1 || r.p2!=p1+n) panic("rdata in toterminal"); } } #define M 0x80000000L #define P(i) r->posnptr[i] #define T(i) (P(i)&M) /* in terminal */ #define L(i) (P(i)&~M) /* length of this piece */ void rcut(List *r, Posn p1, Posn p2) { Posn p, x; int i; if(p1 == p2) panic("rcut 0"); for(p=0,i=0; i<r->nused && p+L(i)<=p1; p+=L(i++)) ; if(i == r->nused) panic("rcut 1"); if(p < p1){ /* chop this piece */ if(p+L(i) < p2){ x = p1-p; p += L(i); }else{ x = L(i)-(p2-p1); p = p2; } if(T(i)) P(i) = x|M; else P(i) = x; i++; } while(i<r->nused && p+L(i)<=p2){ p += L(i); dellist(r, i); } if(p < p2){ if(i == r->nused) panic("rcut 2"); x = L(i)-(p2-p); if(T(i)) P(i) = x|M; else P(i) = x; } /* can we merge i and i-1 ? */ if(i>0 && i<r->nused && T(i-1)==T(i)){ x = L(i-1)+L(i); dellist(r, i--); if(T(i)) P(i)=x|M; else P(i)=x; } } void rgrow(List *r, Posn p1, Posn n) { Posn p; int i; if(n == 0) panic("rgrow 0"); for(p=0,i=0; i<r->nused && p+L(i)<=p1; p+=L(i++)) ; if(i == r->nused){ /* stick on end of file */ if(p!=p1) panic("rgrow 1"); if(i>0 && !T(i-1)) P(i-1)+=n; else inslist(r, i, n); }else if(!T(i)) /* goes in this empty piece */ P(i)+=n; else if(p==p1 && i>0 && !T(i-1)) /* special case; simplifies life */ P(i-1)+=n; else if(p==p1) inslist(r, i, n); else{ /* must break piece in terminal */ inslist(r, i+1, (L(i)-(p1-p))|M); inslist(r, i+1, n); P(i) = (p1-p)|M; } } int rterm(List *r, Posn p1) { Posn p; int i; for(p = 0,i = 0; i<r->nused && p+L(i)<=p1; p+=L(i++)) ; if(i==r->nused && (i==0 || !T(i-1))) return 0; return T(i); } Range rdata(List *r, Posn p1, Posn n) { Posn p; int i; Range rg; if(n==0) panic("rdata 0"); for(p = 0,i = 0; i<r->nused && p+L(i)<=p1; p+=L(i++)) ; if(i==r->nused) panic("rdata 1"); if(T(i)){ n-=L(i)-(p1-p); if(n<=0){ rg.p1 = rg.p2 = p1; return rg; } p+=L(i++); p1 = p; } if(T(i) || i==r->nused) panic("rdata 2"); if(p+L(i)<p1+n) n = L(i)-(p1-p); rg.p1 = p1; rg.p2 = p1+n; if(p!=p1){ inslist(r, i+1, L(i)-(p1-p)); P(i)=p1-p; i++; } if(L(i)!=n){ inslist(r, i+1, L(i)-n); P(i)=n; } P(i)|=M; /* now i is set; can we merge? */ if(i<r->nused-1 && T(i+1)){ P(i)=(n+=L(i+1))|M; dellist(r, i+1); } if(i>0 && T(i-1)){ P(i)=(n+L(i-1))|M; dellist(r, i-1); } return rg; }