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 }