rasp.c - 9base - revived minimalist port of Plan 9 userland to Unix
 (HTM) git clone git://git.suckless.org/9base
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       rasp.c (5841B)
       ---
            1 #include "sam.h"
            2 /*
            3  * GROWDATASIZE must be big enough that all errors go out as Hgrowdata's,
            4  * so they will be scrolled into visibility in the ~~sam~~ window (yuck!).
            5  */
            6 #define        GROWDATASIZE        50        /* if size is <= this, send data with grow */
            7 
            8 void        rcut(List*, Posn, Posn);
            9 int        rterm(List*, Posn);
           10 void        rgrow(List*, Posn, Posn);
           11 
           12 static        Posn        growpos;
           13 static        Posn        grown;
           14 static        Posn        shrinkpos;
           15 static        Posn        shrunk;
           16 
           17 /*
           18  * rasp routines inform the terminal of changes to the file.
           19  *
           20  * a rasp is a list of spans within the file, and an indication
           21  * of whether the terminal knows about the span.
           22  *
           23  * optimize by coalescing multiple updates to the same span
           24  * if it is not known by the terminal.
           25  *
           26  * other possible optimizations: flush terminal's rasp by cut everything,
           27  * insert everything if rasp gets too large.
           28  */
           29 
           30 /*
           31  * only called for initial load of file
           32  */
           33 void
           34 raspload(File *f)
           35 {
           36         if(f->rasp == nil)
           37                 return;
           38         grown = f->b.nc;
           39         growpos = 0;
           40         if(f->b.nc)
           41                 rgrow(f->rasp, 0, f->b.nc);
           42         raspdone(f, 1);
           43 }
           44 
           45 void
           46 raspstart(File *f)
           47 {
           48         if(f->rasp == nil)
           49                 return;
           50         grown = 0;
           51         shrunk = 0;
           52         outbuffered = 1;
           53 }
           54 
           55 void
           56 raspdone(File *f, int toterm)
           57 {
           58         if(f->dot.r.p1 > f->b.nc)
           59                 f->dot.r.p1 = f->b.nc;
           60         if(f->dot.r.p2 > f->b.nc)
           61                 f->dot.r.p2 = f->b.nc;
           62         if(f->mark.p1 > f->b.nc)
           63                 f->mark.p1 = f->b.nc;
           64         if(f->mark.p2 > f->b.nc)
           65                 f->mark.p2 = f->b.nc;
           66         if(f->rasp == nil)
           67                 return;
           68         if(grown)
           69                 outTsll(Hgrow, f->tag, growpos, grown);
           70         else if(shrunk)
           71                 outTsll(Hcut, f->tag, shrinkpos, shrunk);
           72         if(toterm)
           73                 outTs(Hcheck0, f->tag);
           74         outflush();
           75         outbuffered = 0;
           76         if(f == cmd){
           77                 cmdpt += cmdptadv;
           78                 cmdptadv = 0;
           79         }
           80 }
           81 
           82 void
           83 raspflush(File *f)
           84 {
           85         if(grown){
           86                 outTsll(Hgrow, f->tag, growpos, grown);
           87                 grown = 0;
           88         }
           89         else if(shrunk){
           90                 outTsll(Hcut, f->tag, shrinkpos, shrunk);
           91                 shrunk = 0;
           92         }
           93         outflush();
           94 }
           95 
           96 void
           97 raspdelete(File *f, uint p1, uint p2, int toterm)
           98 {
           99         long n;
          100 
          101         n = p2 - p1;
          102         if(n == 0)
          103                 return;
          104 
          105         if(p2 <= f->dot.r.p1){
          106                 f->dot.r.p1 -= n;
          107                 f->dot.r.p2 -= n;
          108         }
          109         if(p2 <= f->mark.p1){
          110                 f->mark.p1 -= n;
          111                 f->mark.p2 -= n;
          112         }
          113 
          114         if(f->rasp == nil)
          115                 return;
          116 
          117         if(f==cmd && p1<cmdpt){
          118                 if(p2 <= cmdpt)
          119                         cmdpt -= n;
          120                 else
          121                         cmdpt = p1;
          122         }
          123         if(toterm){
          124                 if(grown){
          125                         outTsll(Hgrow, f->tag, growpos, grown);
          126                         grown = 0;
          127                 }else if(shrunk && shrinkpos!=p1 && shrinkpos!=p2){
          128                         outTsll(Hcut, f->tag, shrinkpos, shrunk);
          129                         shrunk = 0;
          130                 }
          131                 if(!shrunk || shrinkpos==p2)
          132                         shrinkpos = p1;
          133                 shrunk += n;
          134         }
          135         rcut(f->rasp, p1, p2);
          136 }
          137 
          138 void
          139 raspinsert(File *f, uint p1, Rune *buf, uint n, int toterm)
          140 {
          141         Range r;
          142 
          143         if(n == 0)
          144                 return;
          145 
          146         if(p1 < f->dot.r.p1){
          147                 f->dot.r.p1 += n;
          148                 f->dot.r.p2 += n;
          149         }
          150         if(p1 < f->mark.p1){
          151                 f->mark.p1 += n;
          152                 f->mark.p2 += n;
          153         }
          154 
          155 
          156         if(f->rasp == nil)
          157                 return;
          158         if(f==cmd && p1<cmdpt)
          159                 cmdpt += n;
          160         if(toterm){
          161                 if(shrunk){
          162                         outTsll(Hcut, f->tag, shrinkpos, shrunk);
          163                         shrunk = 0;
          164                 }
          165                 if(n>GROWDATASIZE || !rterm(f->rasp, p1)){
          166                         rgrow(f->rasp, p1, n);
          167                         if(grown && growpos+grown!=p1 && growpos!=p1){
          168                                 outTsll(Hgrow, f->tag, growpos, grown);
          169                                 grown = 0;
          170                         }
          171                         if(!grown)
          172                                 growpos = p1;
          173                         grown += n;
          174                 }else{
          175                         if(grown){
          176                                 outTsll(Hgrow, f->tag, growpos, grown);
          177                                 grown = 0;
          178                         }
          179                         rgrow(f->rasp, p1, n);
          180                         r = rdata(f->rasp, p1, n);
          181                         if(r.p1!=p1 || r.p2!=p1+n)
          182                                 panic("rdata in toterminal");
          183                         outTsllS(Hgrowdata, f->tag, p1, n, tmprstr(buf, n));
          184                 }
          185         }else{
          186                 rgrow(f->rasp, p1, n);
          187                 r = rdata(f->rasp, p1, n);
          188                 if(r.p1!=p1 || r.p2!=p1+n)
          189                         panic("rdata in toterminal");
          190         }
          191 }
          192 
          193 #define        M        0x80000000L
          194 #define        P(i)        r->posnptr[i]
          195 #define        T(i)        (P(i)&M)        /* in terminal */
          196 #define        L(i)        (P(i)&~M)        /* length of this piece */
          197 
          198 void
          199 rcut(List *r, Posn p1, Posn p2)
          200 {
          201         Posn p, x;
          202         int i;
          203 
          204         if(p1 == p2)
          205                 panic("rcut 0");
          206         for(p=0,i=0; i<r->nused && p+L(i)<=p1; p+=L(i++))
          207                 ;
          208         if(i == r->nused)
          209                 panic("rcut 1");
          210         if(p < p1){        /* chop this piece */
          211                 if(p+L(i) < p2){
          212                         x = p1-p;
          213                         p += L(i);
          214                 }else{
          215                         x = L(i)-(p2-p1);
          216                         p = p2;
          217                 }
          218                 if(T(i))
          219                         P(i) = x|M;
          220                 else
          221                         P(i) = x;
          222                 i++;
          223         }
          224         while(i<r->nused && p+L(i)<=p2){
          225                 p += L(i);
          226                 dellist(r, i);
          227         }
          228         if(p < p2){
          229                 if(i == r->nused)
          230                         panic("rcut 2");
          231                 x = L(i)-(p2-p);
          232                 if(T(i))
          233                         P(i) = x|M;
          234                 else
          235                         P(i) = x;
          236         }
          237         /* can we merge i and i-1 ? */
          238         if(i>0 && i<r->nused && T(i-1)==T(i)){
          239                 x = L(i-1)+L(i);
          240                 dellist(r, i--);
          241                 if(T(i))
          242                         P(i)=x|M;
          243                 else
          244                         P(i)=x;
          245         }
          246 }
          247 
          248 void
          249 rgrow(List *r, Posn p1, Posn n)
          250 {
          251         Posn p;
          252         int i;
          253 
          254         if(n == 0)
          255                 panic("rgrow 0");
          256         for(p=0,i=0; i<r->nused && p+L(i)<=p1; p+=L(i++))
          257                 ;
          258         if(i == r->nused){        /* stick on end of file */
          259                 if(p!=p1)
          260                         panic("rgrow 1");
          261                 if(i>0 && !T(i-1))
          262                         P(i-1)+=n;
          263                 else
          264                         inslist(r, i, n);
          265         }else if(!T(i))                /* goes in this empty piece */
          266                 P(i)+=n;
          267         else if(p==p1 && i>0 && !T(i-1))        /* special case; simplifies life */
          268                 P(i-1)+=n;
          269         else if(p==p1)
          270                 inslist(r, i, n);
          271         else{                        /* must break piece in terminal */
          272                 inslist(r, i+1, (L(i)-(p1-p))|M);
          273                 inslist(r, i+1, n);
          274                 P(i) = (p1-p)|M;
          275         }
          276 }
          277 
          278 int
          279 rterm(List *r, Posn p1)
          280 {
          281         Posn p;
          282         int i;
          283 
          284         for(p = 0,i = 0; i<r->nused && p+L(i)<=p1; p+=L(i++))
          285                 ;
          286         if(i==r->nused && (i==0 || !T(i-1)))
          287                 return 0;
          288         return T(i);
          289 }
          290 
          291 Range
          292 rdata(List *r, Posn p1, Posn n)
          293 {
          294         Posn p;
          295         int i;
          296         Range rg;
          297 
          298         if(n==0)
          299                 panic("rdata 0");
          300         for(p = 0,i = 0; i<r->nused && p+L(i)<=p1; p+=L(i++))
          301                 ;
          302         if(i==r->nused)
          303                 panic("rdata 1");
          304         if(T(i)){
          305                 n-=L(i)-(p1-p);
          306                 if(n<=0){
          307                         rg.p1 = rg.p2 = p1;
          308                         return rg;
          309                 }
          310                 p+=L(i++);
          311                 p1 = p;
          312         }
          313         if(T(i) || i==r->nused)
          314                 panic("rdata 2");
          315         if(p+L(i)<p1+n)
          316                 n = L(i)-(p1-p);
          317         rg.p1 = p1;
          318         rg.p2 = p1+n;
          319         if(p!=p1){
          320                 inslist(r, i+1, L(i)-(p1-p));
          321                 P(i)=p1-p;
          322                 i++;
          323         }
          324         if(L(i)!=n){
          325                 inslist(r, i+1, L(i)-n);
          326                 P(i)=n;
          327         }
          328         P(i)|=M;
          329         /* now i is set; can we merge? */
          330         if(i<r->nused-1 && T(i+1)){
          331                 P(i)=(n+=L(i+1))|M;
          332                 dellist(r, i+1);
          333         }
          334         if(i>0 && T(i-1)){
          335                 P(i)=(n+L(i-1))|M;
          336                 dellist(r, i-1);
          337         }
          338         return rg;
          339 }
          340