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