frinsert.c - sam - An updated version of the sam text editor.
 (HTM) git clone git://vernunftzentrum.de/sam.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) LICENSE
       ---
       frinsert.c (7163B)
       ---
            1 /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */
            2 #include <u.h>
            3 #include <libg.h>
            4 #include <frame.h>
            5 
            6 #define DELTA   25
            7 #define TMPSIZE 256
            8 static Frame        frame;
            9 
           10 static
           11 Point
           12 bxscan(Frame *f, wchar_t *sp, wchar_t *ep, Point *ppt)
           13 {
           14     int w, c, nb, delta, nl, nr, rw;
           15     Frbox *b;
           16     char *s, tmp[TMPSIZE+3];    /* +3 for rune overflow */
           17     uint8_t *p;
           18 
           19     frame.r = f->r;
           20     frame.b = f->b;
           21     frame.font = f->font;
           22     frame.fheight = f->font->ascent + f->font->descent;
           23     frame.maxtab = f->maxtab;
           24     frame.left = f->left;
           25     frame.nbox = 0;
           26     frame.nchars = 0;
           27     delta = DELTA;
           28     nl = 0;
           29     for(nb=0; sp<ep && nl<=f->maxlines; nb++,frame.nbox++){
           30         if(nb == frame.nalloc){
           31             _frgrowbox(&frame, delta);
           32             if(delta < 10000)
           33                 delta *= 2;
           34         }
           35         b = &frame.box[nb];
           36         c = *sp;
           37         if(c=='\t' || c=='\n'){
           38             b->a.b.bc = c;
           39             b->wid = 5000;
           40             b->a.b.minwid = (c=='\n')? 0 : charwidth(frame.font, ' ');
           41             b->nrune = -1;
           42             if(c=='\n')
           43                 nl++;
           44             frame.nchars++;
           45             sp++;
           46         }else{
           47             s = tmp;
           48             nr = 0;
           49             w = 0;
           50             while(sp < ep){
           51                 c = *sp;
           52                 if(c=='\t' || c=='\n')
           53                     break;
           54                 rw = runetochar(s, *sp);
           55                 if(s+rw >= tmp+TMPSIZE)
           56                     break;
           57                 w += charwidth(frame.font, c);
           58                 sp++;
           59                 s += rw;
           60                 nr++;
           61             }
           62             *s++ = 0;
           63             p = _frallocstr(s-tmp);
           64             b = &frame.box[nb];
           65             b->a.ptr = p;
           66             memmove(p, tmp, s-tmp);
           67             b->wid = w;
           68             b->nrune = nr;
           69             frame.nchars += nr;
           70         }
           71     }
           72     _frcklinewrap0(f, ppt, &frame.box[0]);
           73     return _frdraw(&frame, *ppt);
           74 }
           75 
           76 static
           77 void
           78 chopframe(Frame *f, Point pt, uint64_t p, int bn)
           79 {
           80     Frbox *b;
           81 
           82     for(b = &f->box[bn]; ; b++){
           83         if(b >= &f->box[f->nbox])
           84             berror("endofframe");
           85         _frcklinewrap(f, &pt, b);
           86         if(pt.y >= f->r.max.y)
           87             break;
           88         p += NRUNE(b);
           89         _fradvance(f, &pt, b);
           90     }
           91     f->nchars = p;
           92     f->nlines = f->maxlines;
           93     if(b<&f->box[f->nbox])              /* BUG */
           94         _frdelbox(f, (int)(b-f->box), f->nbox-1);
           95 }
           96 
           97 void
           98 frinsert(Frame *f, wchar_t *sp, wchar_t *ep, uint64_t p0)
           99 {
          100     Point pt0, pt1, ppt0, ppt1, pt;
          101     Frbox *b;
          102     int n, n0, nn0, y;
          103     Rectangle r;
          104     static struct{
          105         Point pt0, pt1;
          106     }*pts;
          107     static int nalloc=0;
          108     int npts;
          109 
          110     if(p0>f->nchars || sp==ep || f->b==0)
          111         return;
          112     n0 = _frfindbox(f, 0, 0, p0);
          113     nn0 = n0;
          114     pt0 = _frptofcharnb(f, p0, n0);
          115     ppt0 = pt0;
          116     pt1 = bxscan(f, sp, ep, &ppt0);
          117     ppt1 = pt1;
          118     if(n0 < f->nbox){
          119         _frcklinewrap(f, &pt0, b = &f->box[n0]);    /* for frselectf() */
          120         _frcklinewrap0(f, &ppt1, b);
          121     }
          122     f->modified = true;
          123     /*
          124      * ppt0 and ppt1 are start and end of insertion as they will appear when
          125      * insertion is complete. pt0 is current location of insertion position
          126      * (p0); pt1 is terminal point (without line wrap) of insertion.
          127      */
          128     if(p0==f->p0 && p0==f->p1)      /* quite likely */
          129         frselectf(f, pt0, pt0, F&~D);
          130     else
          131         frselectp(f, F&~D);
          132     /*
          133      * Find point where old and new x's line up
          134      * Invariants:
          135      *  pt0 is where the next box (b, n0) is now
          136      *  pt1 is where it will be after then insertion
          137      * If pt1 goes off the rectangle, we can toss everything from there on
          138      */
          139     for(b = &f->box[n0],npts=0;
          140          pt1.x!=pt0.x && pt1.y!=f->r.max.y && n0<f->nbox; b++,n0++,npts++){
          141         _frcklinewrap(f, &pt0, b);
          142         _frcklinewrap0(f, &pt1, b);
          143         if(b->nrune > 0){
          144             n = _frcanfit(f, pt1, b);
          145             if(n == 0)
          146                 berror("_frcanfit==0");
          147             if(n != b->nrune){
          148                 _frsplitbox(f, n0, n);
          149                 b = &f->box[n0];
          150             }
          151         }
          152         if(npts == nalloc){
          153             pts = realloc(pts, (npts+DELTA)*sizeof(pts[0]));
          154             nalloc += DELTA;
          155             b = &f->box[n0];
          156         }
          157         pts[npts].pt0 = pt0;
          158         pts[npts].pt1 = pt1;
          159         /* has a text box overflowed off the frame? */
          160         if(pt1.y == f->r.max.y)
          161             break;
          162         _fradvance(f, &pt0, b);
          163         pt1.x += _frnewwid(f, pt1, b);
          164     }
          165     if(pt1.y > f->r.max.y)
          166         berror("frinsert pt1 too far");
          167     if(pt1.y==f->r.max.y && n0<f->nbox){
          168         f->nchars -= _frstrlen(f, n0);
          169         _frdelbox(f, n0, f->nbox-1);
          170     }
          171     if(n0 == f->nbox)
          172         f->nlines = (pt1.y-f->r.min.y)/f->fheight+(pt1.x>f->left);
          173     else if(pt1.y!=pt0.y){
          174         int q0, q1;
          175 
          176         y = f->r.max.y;
          177         q0 = pt0.y+f->fheight;
          178         q1 = pt1.y+f->fheight;
          179         f->nlines += (q1-q0)/f->fheight;
          180         if(f->nlines > f->maxlines)
          181             chopframe(f, ppt1, p0, nn0);
          182         if(pt1.y < y){
          183             r = f->r;
          184             r.min.y = q0;
          185             r.max.y = y-(q1-q0);
          186             if(q1 < y)
          187                 bitblt2(f->b, Pt(f->r.min.x, q1), f->b, r, S, 0, f->bg);
          188             r.min = pt0;
          189             r.max.y = q0;
          190             bitblt2(f->b, pt1, f->b, r, S, 0, f->bg);
          191         }
          192     }
          193     /*
          194      * Move the old stuff down to make room.  The loop will move the stuff
          195      * between the insertion and the point where the x's lined up.
          196      * The bitblt2 above moved everything down after the point they lined up.
          197      */
          198     for((y=pt1.y==f->r.max.y?pt1.y:0),b = &f->box[n0-1]; --npts>=0; --b){
          199         pt = pts[npts].pt1;
          200         if(b->nrune > 0){
          201             r.min = pts[npts].pt0;
          202             r.max = r.min;
          203             r.max.x += b->wid;
          204             r.max.y += f->fheight;
          205             bitblt2(f->b, pt, f->b, r, S, 0, f->bg);
          206             if(pt.y < y){   /* clear bit hanging off right */
          207                 r.min = pt;
          208                 r.max = pt;
          209                 r.min.x += b->wid;
          210                 r.max.x = f->r.max.x;
          211                 r.max.y += f->fheight;
          212                 bitblt2(f->b, r.min, f->b, r, 0, 0, f->bg);
          213             }
          214             y = pt.y;
          215         }else{
          216             r.min = pt;
          217             r.max = pt;
          218             r.max.x += b->wid;
          219             r.max.y += f->fheight;
          220             if(r.max.x >= f->r.max.x)
          221                 r.max.x = f->r.max.x;
          222             bitblt2(f->b, r.min, f->b, r, 0, 0, f->bg);
          223             y = (pt.x == f->left)? pt.y : 0;
          224         }
          225     }
          226     frselectf(f, ppt0, ppt1, 0);
          227     _frredraw(&frame, ppt0);
          228     _fraddbox(f, nn0, frame.nbox);
          229     for(n=0; n<frame.nbox; n++)
          230         f->box[nn0+n] = frame.box[n];
          231     if(nn0>0 && f->box[nn0-1].nrune>=0 && ppt0.x-f->box[nn0-1].wid>=(int)f->left){
          232         --nn0;
          233         ppt0.x -= f->box[nn0].wid;
          234     }
          235     n0 += frame.nbox;
          236     _frclean(f, ppt0, nn0, n0<f->nbox-1? n0+1 : n0);
          237     f->nchars += frame.nchars;
          238     if(f->p0 >= p0)
          239         f->p0 += frame.nchars;
          240     if(f->p0 > f->nchars)
          241         f->p0 = f->nchars;
          242     if(f->p1 >= p0)
          243         f->p1 += frame.nchars;
          244     if(f->p1 > f->nchars)
          245         f->p1 = f->nchars;
          246     frselectp(f, F&~D);
          247 }