frinsert.c - sam - An updated version of the sam text editor. | |
git clone git://vernunftzentrum.de/sam.git | |
Log | |
Files | |
Refs | |
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 … | |
125 * insertion is complete. pt0 is current location of insertion posit… | |
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 … | |
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 stu… | |
195 * between the insertion and the point where the x's lined up. | |
196 * The bitblt2 above moved everything down after the point they line… | |
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… | |
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 } |