Blame


1 b3994ec5 2003-12-11 devnull #include <u.h>
2 b3994ec5 2003-12-11 devnull #include <libc.h>
3 b3994ec5 2003-12-11 devnull #include <draw.h>
4 b3994ec5 2003-12-11 devnull #include <thread.h>
5 b3994ec5 2003-12-11 devnull #include <cursor.h>
6 b3994ec5 2003-12-11 devnull #include <mouse.h>
7 b3994ec5 2003-12-11 devnull #include <keyboard.h>
8 b3994ec5 2003-12-11 devnull #include <frame.h>
9 b3994ec5 2003-12-11 devnull #include <fcall.h>
10 b3994ec5 2003-12-11 devnull #include <plumb.h>
11 67dbeee5 2017-10-10 rsc #include <libsec.h>
12 c1973705 2004-02-09 devnull #include <complete.h>
13 b3994ec5 2003-12-11 devnull #include "dat.h"
14 b3994ec5 2003-12-11 devnull #include "fns.h"
15 b3994ec5 2003-12-11 devnull
16 b3994ec5 2003-12-11 devnull Image *tagcols[NCOL];
17 b3994ec5 2003-12-11 devnull Image *textcols[NCOL];
18 c1973705 2004-02-09 devnull static Rune Ldot[] = { '.', 0 };
19 b3994ec5 2003-12-11 devnull
20 b3994ec5 2003-12-11 devnull enum{
21 b3994ec5 2003-12-11 devnull TABDIR = 3 /* width of tabs in directory windows */
22 b3994ec5 2003-12-11 devnull };
23 b3994ec5 2003-12-11 devnull
24 b3994ec5 2003-12-11 devnull void
25 b3994ec5 2003-12-11 devnull textinit(Text *t, File *f, Rectangle r, Reffont *rf, Image *cols[NCOL])
26 b3994ec5 2003-12-11 devnull {
27 b3994ec5 2003-12-11 devnull t->file = f;
28 b3994ec5 2003-12-11 devnull t->all = r;
29 b3994ec5 2003-12-11 devnull t->scrollr = r;
30 b3994ec5 2003-12-11 devnull t->scrollr.max.x = r.min.x+Scrollwid;
31 b3994ec5 2003-12-11 devnull t->lastsr = nullrect;
32 b3994ec5 2003-12-11 devnull r.min.x += Scrollwid+Scrollgap;
33 b3994ec5 2003-12-11 devnull t->eq0 = ~0;
34 b3994ec5 2003-12-11 devnull t->ncache = 0;
35 b3994ec5 2003-12-11 devnull t->reffont = rf;
36 b3994ec5 2003-12-11 devnull t->tabstop = maxtab;
37 b3994ec5 2003-12-11 devnull memmove(t->fr.cols, cols, sizeof t->fr.cols);
38 b3994ec5 2003-12-11 devnull textredraw(t, r, rf->f, screen, -1);
39 b3994ec5 2003-12-11 devnull }
40 b3994ec5 2003-12-11 devnull
41 b3994ec5 2003-12-11 devnull void
42 b3994ec5 2003-12-11 devnull textredraw(Text *t, Rectangle r, Font *f, Image *b, int odx)
43 b3994ec5 2003-12-11 devnull {
44 b3994ec5 2003-12-11 devnull int maxt;
45 b3994ec5 2003-12-11 devnull Rectangle rr;
46 b3994ec5 2003-12-11 devnull
47 b3994ec5 2003-12-11 devnull frinit(&t->fr, r, f, b, t->fr.cols);
48 b3994ec5 2003-12-11 devnull rr = t->fr.r;
49 6d7fdb24 2004-12-27 devnull rr.min.x -= Scrollwid+Scrollgap; /* back fill to scroll bar */
50 cb92a1b4 2009-07-15 rsc if(!t->fr.noredraw)
51 cb92a1b4 2009-07-15 rsc draw(t->fr.b, rr, t->fr.cols[BACK], nil, ZP);
52 b3994ec5 2003-12-11 devnull /* use no wider than 3-space tabs in a directory */
53 b3994ec5 2003-12-11 devnull maxt = maxtab;
54 b3994ec5 2003-12-11 devnull if(t->what == Body){
55 b3994ec5 2003-12-11 devnull if(t->w->isdir)
56 b3994ec5 2003-12-11 devnull maxt = min(TABDIR, maxtab);
57 b3994ec5 2003-12-11 devnull else
58 b3994ec5 2003-12-11 devnull maxt = t->tabstop;
59 b3994ec5 2003-12-11 devnull }
60 b3994ec5 2003-12-11 devnull t->fr.maxtab = maxt*stringwidth(f, "0");
61 b3994ec5 2003-12-11 devnull if(t->what==Body && t->w->isdir && odx!=Dx(t->all)){
62 b3994ec5 2003-12-11 devnull if(t->fr.maxlines > 0){
63 b3994ec5 2003-12-11 devnull textreset(t);
64 b3994ec5 2003-12-11 devnull textcolumnate(t, t->w->dlp, t->w->ndl);
65 b3994ec5 2003-12-11 devnull textshow(t, 0, 0, 1);
66 b3994ec5 2003-12-11 devnull }
67 b3994ec5 2003-12-11 devnull }else{
68 b3994ec5 2003-12-11 devnull textfill(t);
69 b3994ec5 2003-12-11 devnull textsetselect(t, t->q0, t->q1);
70 b3994ec5 2003-12-11 devnull }
71 b3994ec5 2003-12-11 devnull }
72 b3994ec5 2003-12-11 devnull
73 b3994ec5 2003-12-11 devnull int
74 33dc4226 2005-10-31 devnull textresize(Text *t, Rectangle r, int keepextra)
75 b3994ec5 2003-12-11 devnull {
76 0cd1385d 2008-03-07 rsc int odx;
77 0cd1385d 2008-03-07 rsc
78 33dc4226 2005-10-31 devnull if(Dy(r) <= 0)
79 b3994ec5 2003-12-11 devnull r.max.y = r.min.y;
80 a2db69c8 2008-03-07 rsc else if(!keepextra)
81 33dc4226 2005-10-31 devnull r.max.y -= Dy(r)%t->fr.font->height;
82 0cd1385d 2008-03-07 rsc odx = Dx(t->all);
83 b3994ec5 2003-12-11 devnull t->all = r;
84 b3994ec5 2003-12-11 devnull t->scrollr = r;
85 b3994ec5 2003-12-11 devnull t->scrollr.max.x = r.min.x+Scrollwid;
86 b3994ec5 2003-12-11 devnull t->lastsr = nullrect;
87 b3994ec5 2003-12-11 devnull r.min.x += Scrollwid+Scrollgap;
88 b3994ec5 2003-12-11 devnull frclear(&t->fr, 0);
89 a2db69c8 2008-03-07 rsc textredraw(t, r, t->fr.font, t->fr.b, odx);
90 cb92a1b4 2009-07-15 rsc if(keepextra && t->fr.r.max.y < t->all.max.y && !t->fr.noredraw){
91 a2db69c8 2008-03-07 rsc /* draw background in bottom fringe of window */
92 33dc4226 2005-10-31 devnull r.min.x -= Scrollgap;
93 33dc4226 2005-10-31 devnull r.min.y = t->fr.r.max.y;
94 33dc4226 2005-10-31 devnull r.max.y = t->all.max.y;
95 33dc4226 2005-10-31 devnull draw(screen, r, t->fr.cols[BACK], nil, ZP);
96 33dc4226 2005-10-31 devnull }
97 33dc4226 2005-10-31 devnull return t->all.max.y;
98 b3994ec5 2003-12-11 devnull }
99 b3994ec5 2003-12-11 devnull
100 b3994ec5 2003-12-11 devnull void
101 b3994ec5 2003-12-11 devnull textclose(Text *t)
102 b3994ec5 2003-12-11 devnull {
103 b3994ec5 2003-12-11 devnull free(t->cache);
104 b3994ec5 2003-12-11 devnull frclear(&t->fr, 1);
105 b3994ec5 2003-12-11 devnull filedeltext(t->file, t);
106 b3994ec5 2003-12-11 devnull t->file = nil;
107 b3994ec5 2003-12-11 devnull rfclose(t->reffont);
108 b3994ec5 2003-12-11 devnull if(argtext == t)
109 b3994ec5 2003-12-11 devnull argtext = nil;
110 b3994ec5 2003-12-11 devnull if(typetext == t)
111 b3994ec5 2003-12-11 devnull typetext = nil;
112 b3994ec5 2003-12-11 devnull if(seltext == t)
113 b3994ec5 2003-12-11 devnull seltext = nil;
114 b3994ec5 2003-12-11 devnull if(mousetext == t)
115 b3994ec5 2003-12-11 devnull mousetext = nil;
116 b3994ec5 2003-12-11 devnull if(barttext == t)
117 b3994ec5 2003-12-11 devnull barttext = nil;
118 b3994ec5 2003-12-11 devnull }
119 b3994ec5 2003-12-11 devnull
120 b3994ec5 2003-12-11 devnull int
121 b3994ec5 2003-12-11 devnull dircmp(const void *a, const void *b)
122 b3994ec5 2003-12-11 devnull {
123 b3994ec5 2003-12-11 devnull Dirlist *da, *db;
124 b3994ec5 2003-12-11 devnull int i, n;
125 b3994ec5 2003-12-11 devnull
126 b3994ec5 2003-12-11 devnull da = *(Dirlist**)a;
127 b3994ec5 2003-12-11 devnull db = *(Dirlist**)b;
128 b3994ec5 2003-12-11 devnull n = min(da->nr, db->nr);
129 b3994ec5 2003-12-11 devnull i = memcmp(da->r, db->r, n*sizeof(Rune));
130 b3994ec5 2003-12-11 devnull if(i)
131 b3994ec5 2003-12-11 devnull return i;
132 b3994ec5 2003-12-11 devnull return da->nr - db->nr;
133 b3994ec5 2003-12-11 devnull }
134 b3994ec5 2003-12-11 devnull
135 b3994ec5 2003-12-11 devnull void
136 b3994ec5 2003-12-11 devnull textcolumnate(Text *t, Dirlist **dlp, int ndl)
137 b3994ec5 2003-12-11 devnull {
138 b3994ec5 2003-12-11 devnull int i, j, w, colw, mint, maxt, ncol, nrow;
139 b3994ec5 2003-12-11 devnull Dirlist *dl;
140 b3994ec5 2003-12-11 devnull uint q1;
141 b3994ec5 2003-12-11 devnull static Rune Lnl[] = { '\n', 0 };
142 b3994ec5 2003-12-11 devnull static Rune Ltab[] = { '\t', 0 };
143 b3994ec5 2003-12-11 devnull
144 b3994ec5 2003-12-11 devnull if(t->file->ntext > 1)
145 b3994ec5 2003-12-11 devnull return;
146 b3994ec5 2003-12-11 devnull mint = stringwidth(t->fr.font, "0");
147 b3994ec5 2003-12-11 devnull /* go for narrower tabs if set more than 3 wide */
148 b3994ec5 2003-12-11 devnull t->fr.maxtab = min(maxtab, TABDIR)*mint;
149 b3994ec5 2003-12-11 devnull maxt = t->fr.maxtab;
150 b3994ec5 2003-12-11 devnull colw = 0;
151 b3994ec5 2003-12-11 devnull for(i=0; i<ndl; i++){
152 b3994ec5 2003-12-11 devnull dl = dlp[i];
153 b3994ec5 2003-12-11 devnull w = dl->wid;
154 b3994ec5 2003-12-11 devnull if(maxt-w%maxt < mint || w%maxt==0)
155 b3994ec5 2003-12-11 devnull w += mint;
156 b3994ec5 2003-12-11 devnull if(w % maxt)
157 b3994ec5 2003-12-11 devnull w += maxt-(w%maxt);
158 b3994ec5 2003-12-11 devnull if(w > colw)
159 b3994ec5 2003-12-11 devnull colw = w;
160 b3994ec5 2003-12-11 devnull }
161 b3994ec5 2003-12-11 devnull if(colw == 0)
162 b3994ec5 2003-12-11 devnull ncol = 1;
163 b3994ec5 2003-12-11 devnull else
164 b3994ec5 2003-12-11 devnull ncol = max(1, Dx(t->fr.r)/colw);
165 b3994ec5 2003-12-11 devnull nrow = (ndl+ncol-1)/ncol;
166 b3994ec5 2003-12-11 devnull
167 b3994ec5 2003-12-11 devnull q1 = 0;
168 b3994ec5 2003-12-11 devnull for(i=0; i<nrow; i++){
169 b3994ec5 2003-12-11 devnull for(j=i; j<ndl; j+=nrow){
170 b3994ec5 2003-12-11 devnull dl = dlp[j];
171 b3994ec5 2003-12-11 devnull fileinsert(t->file, q1, dl->r, dl->nr);
172 b3994ec5 2003-12-11 devnull q1 += dl->nr;
173 b3994ec5 2003-12-11 devnull if(j+nrow >= ndl)
174 b3994ec5 2003-12-11 devnull break;
175 b3994ec5 2003-12-11 devnull w = dl->wid;
176 b3994ec5 2003-12-11 devnull if(maxt-w%maxt < mint){
177 b3994ec5 2003-12-11 devnull fileinsert(t->file, q1, Ltab, 1);
178 b3994ec5 2003-12-11 devnull q1++;
179 b3994ec5 2003-12-11 devnull w += mint;
180 b3994ec5 2003-12-11 devnull }
181 b3994ec5 2003-12-11 devnull do{
182 b3994ec5 2003-12-11 devnull fileinsert(t->file, q1, Ltab, 1);
183 b3994ec5 2003-12-11 devnull q1++;
184 b3994ec5 2003-12-11 devnull w += maxt-(w%maxt);
185 b3994ec5 2003-12-11 devnull }while(w < colw);
186 b3994ec5 2003-12-11 devnull }
187 b3994ec5 2003-12-11 devnull fileinsert(t->file, q1, Lnl, 1);
188 b3994ec5 2003-12-11 devnull q1++;
189 b3994ec5 2003-12-11 devnull }
190 b3994ec5 2003-12-11 devnull }
191 b3994ec5 2003-12-11 devnull
192 daea2c7d 2009-09-25 russcox int
193 b3994ec5 2003-12-11 devnull textload(Text *t, uint q0, char *file, int setqid)
194 b3994ec5 2003-12-11 devnull {
195 b3994ec5 2003-12-11 devnull Rune *rp;
196 b3994ec5 2003-12-11 devnull Dirlist *dl, **dlp;
197 b3994ec5 2003-12-11 devnull int fd, i, j, n, ndl, nulls;
198 b3994ec5 2003-12-11 devnull uint q, q1;
199 b3994ec5 2003-12-11 devnull Dir *d, *dbuf;
200 b3994ec5 2003-12-11 devnull char *tmp;
201 b3994ec5 2003-12-11 devnull Text *u;
202 67dbeee5 2017-10-10 rsc DigestState *h;
203 b3994ec5 2003-12-11 devnull
204 a2db69c8 2008-03-07 rsc if(t->ncache!=0 || t->file->b.nc || t->w==nil || t!=&t->w->body)
205 b3994ec5 2003-12-11 devnull error("text.load");
206 2189e55c 2004-12-27 devnull if(t->w->isdir && t->file->nname==0){
207 6d7fdb24 2004-12-27 devnull warning(nil, "empty directory name");
208 daea2c7d 2009-09-25 russcox return -1;
209 cd5a7378 2008-04-17 rsc }
210 cd5a7378 2008-04-17 rsc if(ismtpt(file)){
211 cd5a7378 2008-04-17 rsc warning(nil, "will not open self mount point %s\n", file);
212 daea2c7d 2009-09-25 russcox return -1;
213 6d7fdb24 2004-12-27 devnull }
214 b3994ec5 2003-12-11 devnull fd = open(file, OREAD);
215 b3994ec5 2003-12-11 devnull if(fd < 0){
216 b3994ec5 2003-12-11 devnull warning(nil, "can't open %s: %r\n", file);
217 daea2c7d 2009-09-25 russcox return -1;
218 b3994ec5 2003-12-11 devnull }
219 b3994ec5 2003-12-11 devnull d = dirfstat(fd);
220 b3994ec5 2003-12-11 devnull if(d == nil){
221 b3994ec5 2003-12-11 devnull warning(nil, "can't fstat %s: %r\n", file);
222 b3994ec5 2003-12-11 devnull goto Rescue;
223 b3994ec5 2003-12-11 devnull }
224 b3994ec5 2003-12-11 devnull nulls = FALSE;
225 67dbeee5 2017-10-10 rsc h = nil;
226 b3994ec5 2003-12-11 devnull if(d->qid.type & QTDIR){
227 b3994ec5 2003-12-11 devnull /* this is checked in get() but it's possible the file changed underfoot */
228 b3994ec5 2003-12-11 devnull if(t->file->ntext > 1){
229 b3994ec5 2003-12-11 devnull warning(nil, "%s is a directory; can't read with multiple windows on it\n", file);
230 b3994ec5 2003-12-11 devnull goto Rescue;
231 b3994ec5 2003-12-11 devnull }
232 b3994ec5 2003-12-11 devnull t->w->isdir = TRUE;
233 b3994ec5 2003-12-11 devnull t->w->filemenu = FALSE;
234 d2131891 2014-04-18 rsc if(t->file->nname > 0 && t->file->name[t->file->nname-1] != '/'){
235 b3994ec5 2003-12-11 devnull rp = runemalloc(t->file->nname+1);
236 b3994ec5 2003-12-11 devnull runemove(rp, t->file->name, t->file->nname);
237 b3994ec5 2003-12-11 devnull rp[t->file->nname] = '/';
238 b3994ec5 2003-12-11 devnull winsetname(t->w, rp, t->file->nname+1);
239 b3994ec5 2003-12-11 devnull free(rp);
240 b3994ec5 2003-12-11 devnull }
241 b3994ec5 2003-12-11 devnull dlp = nil;
242 b3994ec5 2003-12-11 devnull ndl = 0;
243 b3994ec5 2003-12-11 devnull dbuf = nil;
244 b3994ec5 2003-12-11 devnull while((n=dirread(fd, &dbuf)) > 0){
245 b3994ec5 2003-12-11 devnull for(i=0; i<n; i++){
246 b3994ec5 2003-12-11 devnull dl = emalloc(sizeof(Dirlist));
247 b3994ec5 2003-12-11 devnull j = strlen(dbuf[i].name);
248 b3994ec5 2003-12-11 devnull tmp = emalloc(j+1+1);
249 b3994ec5 2003-12-11 devnull memmove(tmp, dbuf[i].name, j);
250 b3994ec5 2003-12-11 devnull if(dbuf[i].qid.type & QTDIR)
251 b3994ec5 2003-12-11 devnull tmp[j++] = '/';
252 b3994ec5 2003-12-11 devnull tmp[j] = '\0';
253 b3994ec5 2003-12-11 devnull dl->r = bytetorune(tmp, &dl->nr);
254 b3994ec5 2003-12-11 devnull dl->wid = stringwidth(t->fr.font, tmp);
255 b3994ec5 2003-12-11 devnull free(tmp);
256 b3994ec5 2003-12-11 devnull ndl++;
257 b3994ec5 2003-12-11 devnull dlp = realloc(dlp, ndl*sizeof(Dirlist*));
258 b3994ec5 2003-12-11 devnull dlp[ndl-1] = dl;
259 b3994ec5 2003-12-11 devnull }
260 b3994ec5 2003-12-11 devnull free(dbuf);
261 b3994ec5 2003-12-11 devnull }
262 b3994ec5 2003-12-11 devnull qsort(dlp, ndl, sizeof(Dirlist*), dircmp);
263 b3994ec5 2003-12-11 devnull t->w->dlp = dlp;
264 b3994ec5 2003-12-11 devnull t->w->ndl = ndl;
265 b3994ec5 2003-12-11 devnull textcolumnate(t, dlp, ndl);
266 b3994ec5 2003-12-11 devnull q1 = t->file->b.nc;
267 b3994ec5 2003-12-11 devnull }else{
268 b3994ec5 2003-12-11 devnull t->w->isdir = FALSE;
269 b3994ec5 2003-12-11 devnull t->w->filemenu = TRUE;
270 67dbeee5 2017-10-10 rsc if(q0 == 0)
271 67dbeee5 2017-10-10 rsc h = sha1(nil, 0, nil, nil);
272 67dbeee5 2017-10-10 rsc q1 = q0 + fileload(t->file, q0, fd, &nulls, h);
273 b3994ec5 2003-12-11 devnull }
274 b3994ec5 2003-12-11 devnull if(setqid){
275 67dbeee5 2017-10-10 rsc if(h != nil) {
276 67dbeee5 2017-10-10 rsc sha1(nil, 0, t->file->sha1, h);
277 67dbeee5 2017-10-10 rsc h = nil;
278 67dbeee5 2017-10-10 rsc } else {
279 67dbeee5 2017-10-10 rsc memset(t->file->sha1, 0, sizeof t->file->sha1);
280 67dbeee5 2017-10-10 rsc }
281 b3994ec5 2003-12-11 devnull t->file->dev = d->dev;
282 b3994ec5 2003-12-11 devnull t->file->mtime = d->mtime;
283 b3994ec5 2003-12-11 devnull t->file->qidpath = d->qid.path;
284 b3994ec5 2003-12-11 devnull }
285 b3994ec5 2003-12-11 devnull close(fd);
286 b3994ec5 2003-12-11 devnull rp = fbufalloc();
287 b3994ec5 2003-12-11 devnull for(q=q0; q<q1; q+=n){
288 b3994ec5 2003-12-11 devnull n = q1-q;
289 b3994ec5 2003-12-11 devnull if(n > RBUFSIZE)
290 b3994ec5 2003-12-11 devnull n = RBUFSIZE;
291 b3994ec5 2003-12-11 devnull bufread(&t->file->b, q, rp, n);
292 b3994ec5 2003-12-11 devnull if(q < t->org)
293 b3994ec5 2003-12-11 devnull t->org += n;
294 b3994ec5 2003-12-11 devnull else if(q <= t->org+t->fr.nchars)
295 b3994ec5 2003-12-11 devnull frinsert(&t->fr, rp, rp+n, q-t->org);
296 b3994ec5 2003-12-11 devnull if(t->fr.lastlinefull)
297 b3994ec5 2003-12-11 devnull break;
298 b3994ec5 2003-12-11 devnull }
299 b3994ec5 2003-12-11 devnull fbuffree(rp);
300 b3994ec5 2003-12-11 devnull for(i=0; i<t->file->ntext; i++){
301 b3994ec5 2003-12-11 devnull u = t->file->text[i];
302 b3994ec5 2003-12-11 devnull if(u != t){
303 b3994ec5 2003-12-11 devnull if(u->org > u->file->b.nc) /* will be 0 because of reset(), but safety first */
304 b3994ec5 2003-12-11 devnull u->org = 0;
305 33dc4226 2005-10-31 devnull textresize(u, u->all, TRUE);
306 b3994ec5 2003-12-11 devnull textbacknl(u, u->org, 0); /* go to beginning of line */
307 b3994ec5 2003-12-11 devnull }
308 b3994ec5 2003-12-11 devnull textsetselect(u, q0, q0);
309 b3994ec5 2003-12-11 devnull }
310 b3994ec5 2003-12-11 devnull if(nulls)
311 b3994ec5 2003-12-11 devnull warning(nil, "%s: NUL bytes elided\n", file);
312 b3994ec5 2003-12-11 devnull free(d);
313 b3994ec5 2003-12-11 devnull return q1-q0;
314 b3994ec5 2003-12-11 devnull
315 b3994ec5 2003-12-11 devnull Rescue:
316 b3994ec5 2003-12-11 devnull close(fd);
317 daea2c7d 2009-09-25 russcox return -1;
318 b3994ec5 2003-12-11 devnull }
319 b3994ec5 2003-12-11 devnull
320 b3994ec5 2003-12-11 devnull uint
321 b3994ec5 2003-12-11 devnull textbsinsert(Text *t, uint q0, Rune *r, uint n, int tofile, int *nrp)
322 b3994ec5 2003-12-11 devnull {
323 b3994ec5 2003-12-11 devnull Rune *bp, *tp, *up;
324 b3994ec5 2003-12-11 devnull int i, initial;
325 b3994ec5 2003-12-11 devnull
326 b3994ec5 2003-12-11 devnull if(t->what == Tag){ /* can't happen but safety first: mustn't backspace over file name */
327 b3994ec5 2003-12-11 devnull Err:
328 b3994ec5 2003-12-11 devnull textinsert(t, q0, r, n, tofile);
329 b3994ec5 2003-12-11 devnull *nrp = n;
330 b3994ec5 2003-12-11 devnull return q0;
331 b3994ec5 2003-12-11 devnull }
332 b3994ec5 2003-12-11 devnull bp = r;
333 b3994ec5 2003-12-11 devnull for(i=0; i<n; i++)
334 b3994ec5 2003-12-11 devnull if(*bp++ == '\b'){
335 b3994ec5 2003-12-11 devnull --bp;
336 b3994ec5 2003-12-11 devnull initial = 0;
337 b3994ec5 2003-12-11 devnull tp = runemalloc(n);
338 b3994ec5 2003-12-11 devnull runemove(tp, r, i);
339 b3994ec5 2003-12-11 devnull up = tp+i;
340 b3994ec5 2003-12-11 devnull for(; i<n; i++){
341 b3994ec5 2003-12-11 devnull *up = *bp++;
342 b3994ec5 2003-12-11 devnull if(*up == '\b')
343 b3994ec5 2003-12-11 devnull if(up == tp)
344 b3994ec5 2003-12-11 devnull initial++;
345 b3994ec5 2003-12-11 devnull else
346 b3994ec5 2003-12-11 devnull --up;
347 b3994ec5 2003-12-11 devnull else
348 b3994ec5 2003-12-11 devnull up++;
349 b3994ec5 2003-12-11 devnull }
350 b3994ec5 2003-12-11 devnull if(initial){
351 b3994ec5 2003-12-11 devnull if(initial > q0)
352 b3994ec5 2003-12-11 devnull initial = q0;
353 b3994ec5 2003-12-11 devnull q0 -= initial;
354 b3994ec5 2003-12-11 devnull textdelete(t, q0, q0+initial, tofile);
355 b3994ec5 2003-12-11 devnull }
356 b3994ec5 2003-12-11 devnull n = up-tp;
357 b3994ec5 2003-12-11 devnull textinsert(t, q0, tp, n, tofile);
358 b3994ec5 2003-12-11 devnull free(tp);
359 b3994ec5 2003-12-11 devnull *nrp = n;
360 b3994ec5 2003-12-11 devnull return q0;
361 b3994ec5 2003-12-11 devnull }
362 b3994ec5 2003-12-11 devnull goto Err;
363 b3994ec5 2003-12-11 devnull }
364 b3994ec5 2003-12-11 devnull
365 b3994ec5 2003-12-11 devnull void
366 b3994ec5 2003-12-11 devnull textinsert(Text *t, uint q0, Rune *r, uint n, int tofile)
367 b3994ec5 2003-12-11 devnull {
368 b3994ec5 2003-12-11 devnull int c, i;
369 b3994ec5 2003-12-11 devnull Text *u;
370 b3994ec5 2003-12-11 devnull
371 b3994ec5 2003-12-11 devnull if(tofile && t->ncache != 0)
372 b3994ec5 2003-12-11 devnull error("text.insert");
373 b3994ec5 2003-12-11 devnull if(n == 0)
374 b3994ec5 2003-12-11 devnull return;
375 b3994ec5 2003-12-11 devnull if(tofile){
376 b3994ec5 2003-12-11 devnull fileinsert(t->file, q0, r, n);
377 b3994ec5 2003-12-11 devnull if(t->what == Body){
378 b3994ec5 2003-12-11 devnull t->w->dirty = TRUE;
379 b3994ec5 2003-12-11 devnull t->w->utflastqid = -1;
380 b3994ec5 2003-12-11 devnull }
381 b3994ec5 2003-12-11 devnull if(t->file->ntext > 1)
382 b3994ec5 2003-12-11 devnull for(i=0; i<t->file->ntext; i++){
383 b3994ec5 2003-12-11 devnull u = t->file->text[i];
384 b3994ec5 2003-12-11 devnull if(u != t){
385 b3994ec5 2003-12-11 devnull u->w->dirty = TRUE; /* always a body */
386 b3994ec5 2003-12-11 devnull textinsert(u, q0, r, n, FALSE);
387 b3994ec5 2003-12-11 devnull textsetselect(u, u->q0, u->q1);
388 b3994ec5 2003-12-11 devnull textscrdraw(u);
389 b3994ec5 2003-12-11 devnull }
390 b3994ec5 2003-12-11 devnull }
391 fa325e9b 2020-01-10 cross
392 b3994ec5 2003-12-11 devnull }
393 76864eb6 2011-08-02 rsc if(q0 < t->iq1)
394 76864eb6 2011-08-02 rsc t->iq1 += n;
395 b3994ec5 2003-12-11 devnull if(q0 < t->q1)
396 b3994ec5 2003-12-11 devnull t->q1 += n;
397 b3994ec5 2003-12-11 devnull if(q0 < t->q0)
398 b3994ec5 2003-12-11 devnull t->q0 += n;
399 b3994ec5 2003-12-11 devnull if(q0 < t->org)
400 b3994ec5 2003-12-11 devnull t->org += n;
401 b3994ec5 2003-12-11 devnull else if(q0 <= t->org+t->fr.nchars)
402 b3994ec5 2003-12-11 devnull frinsert(&t->fr, r, r+n, q0-t->org);
403 b3994ec5 2003-12-11 devnull if(t->w){
404 b3994ec5 2003-12-11 devnull c = 'i';
405 b3994ec5 2003-12-11 devnull if(t->what == Body)
406 b3994ec5 2003-12-11 devnull c = 'I';
407 b3994ec5 2003-12-11 devnull if(n <= EVENTSIZE)
408 b3994ec5 2003-12-11 devnull winevent(t->w, "%c%d %d 0 %d %.*S\n", c, q0, q0+n, n, n, r);
409 b3994ec5 2003-12-11 devnull else
410 b3994ec5 2003-12-11 devnull winevent(t->w, "%c%d %d 0 0 \n", c, q0, q0+n, n);
411 b3994ec5 2003-12-11 devnull }
412 b3994ec5 2003-12-11 devnull }
413 b3994ec5 2003-12-11 devnull
414 2a373ea4 2005-03-18 devnull void
415 2a373ea4 2005-03-18 devnull typecommit(Text *t)
416 2a373ea4 2005-03-18 devnull {
417 2a373ea4 2005-03-18 devnull if(t->w != nil)
418 2a373ea4 2005-03-18 devnull wincommit(t->w, t);
419 2a373ea4 2005-03-18 devnull else
420 2a373ea4 2005-03-18 devnull textcommit(t, TRUE);
421 2a373ea4 2005-03-18 devnull }
422 b3994ec5 2003-12-11 devnull
423 b3994ec5 2003-12-11 devnull void
424 b3994ec5 2003-12-11 devnull textfill(Text *t)
425 b3994ec5 2003-12-11 devnull {
426 b3994ec5 2003-12-11 devnull Rune *rp;
427 b3994ec5 2003-12-11 devnull int i, n, m, nl;
428 b3994ec5 2003-12-11 devnull
429 b3994ec5 2003-12-11 devnull if(t->fr.lastlinefull || t->nofill)
430 b3994ec5 2003-12-11 devnull return;
431 2a373ea4 2005-03-18 devnull if(t->ncache > 0)
432 2a373ea4 2005-03-18 devnull typecommit(t);
433 b3994ec5 2003-12-11 devnull rp = fbufalloc();
434 b3994ec5 2003-12-11 devnull do{
435 b3994ec5 2003-12-11 devnull n = t->file->b.nc-(t->org+t->fr.nchars);
436 b3994ec5 2003-12-11 devnull if(n == 0)
437 b3994ec5 2003-12-11 devnull break;
438 b3994ec5 2003-12-11 devnull if(n > 2000) /* educated guess at reasonable amount */
439 b3994ec5 2003-12-11 devnull n = 2000;
440 b3994ec5 2003-12-11 devnull bufread(&t->file->b, t->org+t->fr.nchars, rp, n);
441 b3994ec5 2003-12-11 devnull /*
442 b3994ec5 2003-12-11 devnull * it's expensive to frinsert more than we need, so
443 b3994ec5 2003-12-11 devnull * count newlines.
444 b3994ec5 2003-12-11 devnull */
445 b3994ec5 2003-12-11 devnull nl = t->fr.maxlines-t->fr.nlines;
446 b3994ec5 2003-12-11 devnull m = 0;
447 b3994ec5 2003-12-11 devnull for(i=0; i<n; ){
448 b3994ec5 2003-12-11 devnull if(rp[i++] == '\n'){
449 b3994ec5 2003-12-11 devnull m++;
450 b3994ec5 2003-12-11 devnull if(m >= nl)
451 b3994ec5 2003-12-11 devnull break;
452 b3994ec5 2003-12-11 devnull }
453 b3994ec5 2003-12-11 devnull }
454 b3994ec5 2003-12-11 devnull frinsert(&t->fr, rp, rp+i, t->fr.nchars);
455 b3994ec5 2003-12-11 devnull }while(t->fr.lastlinefull == FALSE);
456 b3994ec5 2003-12-11 devnull fbuffree(rp);
457 b3994ec5 2003-12-11 devnull }
458 b3994ec5 2003-12-11 devnull
459 b3994ec5 2003-12-11 devnull void
460 b3994ec5 2003-12-11 devnull textdelete(Text *t, uint q0, uint q1, int tofile)
461 b3994ec5 2003-12-11 devnull {
462 b3994ec5 2003-12-11 devnull uint n, p0, p1;
463 b3994ec5 2003-12-11 devnull int i, c;
464 b3994ec5 2003-12-11 devnull Text *u;
465 b3994ec5 2003-12-11 devnull
466 b3994ec5 2003-12-11 devnull if(tofile && t->ncache != 0)
467 b3994ec5 2003-12-11 devnull error("text.delete");
468 b3994ec5 2003-12-11 devnull n = q1-q0;
469 b3994ec5 2003-12-11 devnull if(n == 0)
470 b3994ec5 2003-12-11 devnull return;
471 b3994ec5 2003-12-11 devnull if(tofile){
472 b3994ec5 2003-12-11 devnull filedelete(t->file, q0, q1);
473 b3994ec5 2003-12-11 devnull if(t->what == Body){
474 b3994ec5 2003-12-11 devnull t->w->dirty = TRUE;
475 b3994ec5 2003-12-11 devnull t->w->utflastqid = -1;
476 b3994ec5 2003-12-11 devnull }
477 b3994ec5 2003-12-11 devnull if(t->file->ntext > 1)
478 b3994ec5 2003-12-11 devnull for(i=0; i<t->file->ntext; i++){
479 b3994ec5 2003-12-11 devnull u = t->file->text[i];
480 b3994ec5 2003-12-11 devnull if(u != t){
481 b3994ec5 2003-12-11 devnull u->w->dirty = TRUE; /* always a body */
482 b3994ec5 2003-12-11 devnull textdelete(u, q0, q1, FALSE);
483 b3994ec5 2003-12-11 devnull textsetselect(u, u->q0, u->q1);
484 b3994ec5 2003-12-11 devnull textscrdraw(u);
485 b3994ec5 2003-12-11 devnull }
486 b3994ec5 2003-12-11 devnull }
487 b3994ec5 2003-12-11 devnull }
488 da7e3a5d 2011-08-02 rsc if(q0 < t->iq1)
489 76864eb6 2011-08-02 rsc t->iq1 -= min(n, t->iq1-q0);
490 b3994ec5 2003-12-11 devnull if(q0 < t->q0)
491 b3994ec5 2003-12-11 devnull t->q0 -= min(n, t->q0-q0);
492 b3994ec5 2003-12-11 devnull if(q0 < t->q1)
493 b3994ec5 2003-12-11 devnull t->q1 -= min(n, t->q1-q0);
494 b3994ec5 2003-12-11 devnull if(q1 <= t->org)
495 b3994ec5 2003-12-11 devnull t->org -= n;
496 b3994ec5 2003-12-11 devnull else if(q0 < t->org+t->fr.nchars){
497 b3994ec5 2003-12-11 devnull p1 = q1 - t->org;
498 b3994ec5 2003-12-11 devnull if(p1 > t->fr.nchars)
499 b3994ec5 2003-12-11 devnull p1 = t->fr.nchars;
500 b3994ec5 2003-12-11 devnull if(q0 < t->org){
501 b3994ec5 2003-12-11 devnull t->org = q0;
502 b3994ec5 2003-12-11 devnull p0 = 0;
503 b3994ec5 2003-12-11 devnull }else
504 b3994ec5 2003-12-11 devnull p0 = q0 - t->org;
505 b3994ec5 2003-12-11 devnull frdelete(&t->fr, p0, p1);
506 b3994ec5 2003-12-11 devnull textfill(t);
507 b3994ec5 2003-12-11 devnull }
508 b3994ec5 2003-12-11 devnull if(t->w){
509 b3994ec5 2003-12-11 devnull c = 'd';
510 b3994ec5 2003-12-11 devnull if(t->what == Body)
511 b3994ec5 2003-12-11 devnull c = 'D';
512 b3994ec5 2003-12-11 devnull winevent(t->w, "%c%d %d 0 0 \n", c, q0, q1);
513 b3994ec5 2003-12-11 devnull }
514 b3994ec5 2003-12-11 devnull }
515 b3994ec5 2003-12-11 devnull
516 b3994ec5 2003-12-11 devnull void
517 b3994ec5 2003-12-11 devnull textconstrain(Text *t, uint q0, uint q1, uint *p0, uint *p1)
518 b3994ec5 2003-12-11 devnull {
519 b3994ec5 2003-12-11 devnull *p0 = min(q0, t->file->b.nc);
520 b3994ec5 2003-12-11 devnull *p1 = min(q1, t->file->b.nc);
521 b3994ec5 2003-12-11 devnull }
522 b3994ec5 2003-12-11 devnull
523 b3994ec5 2003-12-11 devnull Rune
524 b3994ec5 2003-12-11 devnull textreadc(Text *t, uint q)
525 b3994ec5 2003-12-11 devnull {
526 b3994ec5 2003-12-11 devnull Rune r;
527 b3994ec5 2003-12-11 devnull
528 b3994ec5 2003-12-11 devnull if(t->cq0<=q && q<t->cq0+t->ncache)
529 b3994ec5 2003-12-11 devnull r = t->cache[q-t->cq0];
530 b3994ec5 2003-12-11 devnull else
531 b3994ec5 2003-12-11 devnull bufread(&t->file->b, q, &r, 1);
532 b3994ec5 2003-12-11 devnull return r;
533 b3994ec5 2003-12-11 devnull }
534 b3994ec5 2003-12-11 devnull
535 b3994ec5 2003-12-11 devnull int
536 b3994ec5 2003-12-11 devnull textbswidth(Text *t, Rune c)
537 b3994ec5 2003-12-11 devnull {
538 b3994ec5 2003-12-11 devnull uint q, eq;
539 b3994ec5 2003-12-11 devnull Rune r;
540 b3994ec5 2003-12-11 devnull int skipping;
541 b3994ec5 2003-12-11 devnull
542 b3994ec5 2003-12-11 devnull /* there is known to be at least one character to erase */
543 b3994ec5 2003-12-11 devnull if(c == 0x08) /* ^H: erase character */
544 b3994ec5 2003-12-11 devnull return 1;
545 b3994ec5 2003-12-11 devnull q = t->q0;
546 b3994ec5 2003-12-11 devnull skipping = TRUE;
547 b3994ec5 2003-12-11 devnull while(q > 0){
548 b3994ec5 2003-12-11 devnull r = textreadc(t, q-1);
549 b3994ec5 2003-12-11 devnull if(r == '\n'){ /* eat at most one more character */
550 b3994ec5 2003-12-11 devnull if(q == t->q0) /* eat the newline */
551 b3994ec5 2003-12-11 devnull --q;
552 fa325e9b 2020-01-10 cross break;
553 b3994ec5 2003-12-11 devnull }
554 b3994ec5 2003-12-11 devnull if(c == 0x17){
555 b3994ec5 2003-12-11 devnull eq = isalnum(r);
556 b3994ec5 2003-12-11 devnull if(eq && skipping) /* found one; stop skipping */
557 b3994ec5 2003-12-11 devnull skipping = FALSE;
558 b3994ec5 2003-12-11 devnull else if(!eq && !skipping)
559 b3994ec5 2003-12-11 devnull break;
560 b3994ec5 2003-12-11 devnull }
561 b3994ec5 2003-12-11 devnull --q;
562 b3994ec5 2003-12-11 devnull }
563 b3994ec5 2003-12-11 devnull return t->q0-q;
564 c1973705 2004-02-09 devnull }
565 c1973705 2004-02-09 devnull
566 c1973705 2004-02-09 devnull int
567 c1973705 2004-02-09 devnull textfilewidth(Text *t, uint q0, int oneelement)
568 c1973705 2004-02-09 devnull {
569 c1973705 2004-02-09 devnull uint q;
570 c1973705 2004-02-09 devnull Rune r;
571 c1973705 2004-02-09 devnull
572 c1973705 2004-02-09 devnull q = q0;
573 c1973705 2004-02-09 devnull while(q > 0){
574 c1973705 2004-02-09 devnull r = textreadc(t, q-1);
575 5a8e63b2 2004-02-29 devnull if(r <= ' ')
576 c1973705 2004-02-09 devnull break;
577 c1973705 2004-02-09 devnull if(oneelement && r=='/')
578 c1973705 2004-02-09 devnull break;
579 c1973705 2004-02-09 devnull --q;
580 c1973705 2004-02-09 devnull }
581 c1973705 2004-02-09 devnull return q0-q;
582 c1973705 2004-02-09 devnull }
583 c1973705 2004-02-09 devnull
584 c1973705 2004-02-09 devnull Rune*
585 c1973705 2004-02-09 devnull textcomplete(Text *t)
586 c1973705 2004-02-09 devnull {
587 c1973705 2004-02-09 devnull int i, nstr, npath;
588 c1973705 2004-02-09 devnull uint q;
589 c1973705 2004-02-09 devnull Rune tmp[200];
590 c1973705 2004-02-09 devnull Rune *str, *path;
591 c1973705 2004-02-09 devnull Rune *rp;
592 c1973705 2004-02-09 devnull Completion *c;
593 c1973705 2004-02-09 devnull char *s, *dirs;
594 c1973705 2004-02-09 devnull Runestr dir;
595 c1973705 2004-02-09 devnull
596 c1973705 2004-02-09 devnull /* control-f: filename completion; works back to white space or / */
597 c1973705 2004-02-09 devnull if(t->q0<t->file->b.nc && textreadc(t, t->q0)>' ') /* must be at end of word */
598 c1973705 2004-02-09 devnull return nil;
599 c1973705 2004-02-09 devnull nstr = textfilewidth(t, t->q0, TRUE);
600 c1973705 2004-02-09 devnull str = runemalloc(nstr);
601 c1973705 2004-02-09 devnull npath = textfilewidth(t, t->q0-nstr, FALSE);
602 c1973705 2004-02-09 devnull path = runemalloc(npath);
603 c1973705 2004-02-09 devnull
604 c1973705 2004-02-09 devnull c = nil;
605 c1973705 2004-02-09 devnull rp = nil;
606 c1973705 2004-02-09 devnull dirs = nil;
607 c1973705 2004-02-09 devnull
608 c1973705 2004-02-09 devnull q = t->q0-nstr;
609 c1973705 2004-02-09 devnull for(i=0; i<nstr; i++)
610 c1973705 2004-02-09 devnull str[i] = textreadc(t, q++);
611 c1973705 2004-02-09 devnull q = t->q0-nstr-npath;
612 c1973705 2004-02-09 devnull for(i=0; i<npath; i++)
613 c1973705 2004-02-09 devnull path[i] = textreadc(t, q++);
614 c1973705 2004-02-09 devnull /* is path rooted? if not, we need to make it relative to window path */
615 c1973705 2004-02-09 devnull if(npath>0 && path[0]=='/')
616 8ad51794 2004-03-25 devnull dir = runestr(path, npath);
617 c1973705 2004-02-09 devnull else{
618 c1973705 2004-02-09 devnull dir = dirname(t, nil, 0);
619 c1973705 2004-02-09 devnull if(dir.nr + 1 + npath > nelem(tmp)){
620 c1973705 2004-02-09 devnull free(dir.r);
621 c1973705 2004-02-09 devnull goto Return;
622 c1973705 2004-02-09 devnull }
623 c1973705 2004-02-09 devnull if(dir.nr == 0){
624 c1973705 2004-02-09 devnull dir.nr = 1;
625 c1973705 2004-02-09 devnull dir.r = runestrdup(Ldot);
626 c1973705 2004-02-09 devnull }
627 c1973705 2004-02-09 devnull runemove(tmp, dir.r, dir.nr);
628 c1973705 2004-02-09 devnull tmp[dir.nr] = '/';
629 c1973705 2004-02-09 devnull runemove(tmp+dir.nr+1, path, npath);
630 c1973705 2004-02-09 devnull free(dir.r);
631 c1973705 2004-02-09 devnull dir.r = tmp;
632 c1973705 2004-02-09 devnull dir.nr += 1+npath;
633 c1973705 2004-02-09 devnull dir = cleanrname(dir);
634 c1973705 2004-02-09 devnull }
635 c1973705 2004-02-09 devnull
636 c1973705 2004-02-09 devnull s = smprint("%.*S", nstr, str);
637 c1973705 2004-02-09 devnull dirs = smprint("%.*S", dir.nr, dir.r);
638 c1973705 2004-02-09 devnull c = complete(dirs, s);
639 c1973705 2004-02-09 devnull free(s);
640 c1973705 2004-02-09 devnull if(c == nil){
641 c1973705 2004-02-09 devnull warning(nil, "error attempting completion: %r\n");
642 c1973705 2004-02-09 devnull goto Return;
643 c1973705 2004-02-09 devnull }
644 c1973705 2004-02-09 devnull
645 c1973705 2004-02-09 devnull if(!c->advance){
646 5a8e63b2 2004-02-29 devnull warning(nil, "%.*S%s%.*S*%s\n",
647 c1973705 2004-02-09 devnull dir.nr, dir.r,
648 c1973705 2004-02-09 devnull dir.nr>0 && dir.r[dir.nr-1]!='/' ? "/" : "",
649 5a8e63b2 2004-02-29 devnull nstr, str,
650 5a8e63b2 2004-02-29 devnull c->nmatch ? "" : ": no matches in:");
651 c1973705 2004-02-09 devnull for(i=0; i<c->nfile; i++)
652 c1973705 2004-02-09 devnull warning(nil, " %s\n", c->filename[i]);
653 c1973705 2004-02-09 devnull }
654 c1973705 2004-02-09 devnull
655 c1973705 2004-02-09 devnull if(c->advance)
656 c1973705 2004-02-09 devnull rp = runesmprint("%s", c->string);
657 c1973705 2004-02-09 devnull else
658 c1973705 2004-02-09 devnull rp = nil;
659 c1973705 2004-02-09 devnull Return:
660 c1973705 2004-02-09 devnull freecompletion(c);
661 c1973705 2004-02-09 devnull free(dirs);
662 c1973705 2004-02-09 devnull free(str);
663 c1973705 2004-02-09 devnull free(path);
664 c1973705 2004-02-09 devnull return rp;
665 b3994ec5 2003-12-11 devnull }
666 b3994ec5 2003-12-11 devnull
667 b3994ec5 2003-12-11 devnull void
668 b3994ec5 2003-12-11 devnull texttype(Text *t, Rune r)
669 b3994ec5 2003-12-11 devnull {
670 b3994ec5 2003-12-11 devnull uint q0, q1;
671 b3994ec5 2003-12-11 devnull int nnb, nb, n, i;
672 c1973705 2004-02-09 devnull int nr;
673 c1973705 2004-02-09 devnull Rune *rp;
674 b3994ec5 2003-12-11 devnull Text *u;
675 b3994ec5 2003-12-11 devnull
676 f8dea3c1 2005-12-16 devnull if(t->what!=Body && t->what!=Tag && r=='\n')
677 b3994ec5 2003-12-11 devnull return;
678 f8dea3c1 2005-12-16 devnull if(t->what == Tag)
679 f8dea3c1 2005-12-16 devnull t->w->tagsafe = FALSE;
680 f8dea3c1 2005-12-16 devnull
681 c1973705 2004-02-09 devnull nr = 1;
682 c1973705 2004-02-09 devnull rp = &r;
683 b3994ec5 2003-12-11 devnull switch(r){
684 b3994ec5 2003-12-11 devnull case Kleft:
685 81c30b5a 2011-11-17 rsc typecommit(t);
686 81c30b5a 2011-11-17 rsc if(t->q0 > 0)
687 c1973705 2004-02-09 devnull textshow(t, t->q0-1, t->q0-1, TRUE);
688 c1973705 2004-02-09 devnull return;
689 b3994ec5 2003-12-11 devnull case Kright:
690 81c30b5a 2011-11-17 rsc typecommit(t);
691 81c30b5a 2011-11-17 rsc if(t->q1 < t->file->b.nc)
692 c1973705 2004-02-09 devnull textshow(t, t->q1+1, t->q1+1, TRUE);
693 c1973705 2004-02-09 devnull return;
694 c1973705 2004-02-09 devnull case Kdown:
695 f8dea3c1 2005-12-16 devnull if(t->what == Tag)
696 f8dea3c1 2005-12-16 devnull goto Tagdown;
697 5a8e63b2 2004-02-29 devnull n = t->fr.maxlines/3;
698 c16f1f73 2004-06-09 devnull goto case_Down;
699 c16f1f73 2004-06-09 devnull case Kscrollonedown:
700 f8dea3c1 2005-12-16 devnull if(t->what == Tag)
701 f8dea3c1 2005-12-16 devnull goto Tagdown;
702 64055489 2004-06-20 devnull n = mousescrollsize(t->fr.maxlines);
703 038aa022 2004-06-11 devnull if(n <= 0)
704 038aa022 2004-06-11 devnull n = 1;
705 5a8e63b2 2004-02-29 devnull goto case_Down;
706 c1973705 2004-02-09 devnull case Kpgdown:
707 5a8e63b2 2004-02-29 devnull n = 2*t->fr.maxlines/3;
708 5a8e63b2 2004-02-29 devnull case_Down:
709 b3994ec5 2003-12-11 devnull q0 = t->org+frcharofpt(&t->fr, Pt(t->fr.r.min.x, t->fr.r.min.y+n*t->fr.font->height));
710 64055489 2004-06-20 devnull textsetorigin(t, q0, TRUE);
711 b3994ec5 2003-12-11 devnull return;
712 b3994ec5 2003-12-11 devnull case Kup:
713 f8dea3c1 2005-12-16 devnull if(t->what == Tag)
714 f8dea3c1 2005-12-16 devnull goto Tagup;
715 5a8e63b2 2004-02-29 devnull n = t->fr.maxlines/3;
716 5a8e63b2 2004-02-29 devnull goto case_Up;
717 c16f1f73 2004-06-09 devnull case Kscrolloneup:
718 f8dea3c1 2005-12-16 devnull if(t->what == Tag)
719 f8dea3c1 2005-12-16 devnull goto Tagup;
720 64055489 2004-06-20 devnull n = mousescrollsize(t->fr.maxlines);
721 c16f1f73 2004-06-09 devnull goto case_Up;
722 c1973705 2004-02-09 devnull case Kpgup:
723 5a8e63b2 2004-02-29 devnull n = 2*t->fr.maxlines/3;
724 5a8e63b2 2004-02-29 devnull case_Up:
725 b3994ec5 2003-12-11 devnull q0 = textbacknl(t, t->org, n);
726 64055489 2004-06-20 devnull textsetorigin(t, q0, TRUE);
727 b3994ec5 2003-12-11 devnull return;
728 5a8e63b2 2004-02-29 devnull case Khome:
729 2a373ea4 2005-03-18 devnull typecommit(t);
730 76864eb6 2011-08-02 rsc if(t->org > t->iq1) {
731 76864eb6 2011-08-02 rsc q0 = textbacknl(t, t->iq1, 1);
732 76864eb6 2011-08-02 rsc textsetorigin(t, q0, TRUE);
733 76864eb6 2011-08-02 rsc } else
734 76864eb6 2011-08-02 rsc textshow(t, 0, 0, FALSE);
735 5a8e63b2 2004-02-29 devnull return;
736 5a8e63b2 2004-02-29 devnull case Kend:
737 2a373ea4 2005-03-18 devnull typecommit(t);
738 76864eb6 2011-08-02 rsc if(t->iq1 > t->org+t->fr.nchars) {
739 50ababbd 2014-06-03 rsc if(t->iq1 > t->file->b.nc) {
740 50ababbd 2014-06-03 rsc // should not happen, but does. and it will crash textbacknl.
741 50ababbd 2014-06-03 rsc t->iq1 = t->file->b.nc;
742 50ababbd 2014-06-03 rsc }
743 76864eb6 2011-08-02 rsc q0 = textbacknl(t, t->iq1, 1);
744 76864eb6 2011-08-02 rsc textsetorigin(t, q0, TRUE);
745 76864eb6 2011-08-02 rsc } else
746 76864eb6 2011-08-02 rsc textshow(t, t->file->b.nc, t->file->b.nc, FALSE);
747 5a8e63b2 2004-02-29 devnull return;
748 2a373ea4 2005-03-18 devnull case 0x01: /* ^A: beginning of line */
749 2a373ea4 2005-03-18 devnull typecommit(t);
750 2a373ea4 2005-03-18 devnull /* go to where ^U would erase, if not already at BOL */
751 2a373ea4 2005-03-18 devnull nnb = 0;
752 2a373ea4 2005-03-18 devnull if(t->q0>0 && textreadc(t, t->q0-1)!='\n')
753 2a373ea4 2005-03-18 devnull nnb = textbswidth(t, 0x15);
754 2a373ea4 2005-03-18 devnull textshow(t, t->q0-nnb, t->q0-nnb, TRUE);
755 2a373ea4 2005-03-18 devnull return;
756 2a373ea4 2005-03-18 devnull case 0x05: /* ^E: end of line */
757 2a373ea4 2005-03-18 devnull typecommit(t);
758 2a373ea4 2005-03-18 devnull q0 = t->q0;
759 2a373ea4 2005-03-18 devnull while(q0<t->file->b.nc && textreadc(t, q0)!='\n')
760 2a373ea4 2005-03-18 devnull q0++;
761 2a373ea4 2005-03-18 devnull textshow(t, q0, q0, TRUE);
762 4aad1a32 2009-04-30 rsc return;
763 4aad1a32 2009-04-30 rsc case Kcmd+'c': /* %C: copy */
764 4aad1a32 2009-04-30 rsc typecommit(t);
765 4aad1a32 2009-04-30 rsc cut(t, t, nil, TRUE, FALSE, nil, 0);
766 a287dbab 2011-09-06 rsc return;
767 a287dbab 2011-09-06 rsc case Kcmd+'z': /* %Z: undo */
768 a287dbab 2011-09-06 rsc typecommit(t);
769 a287dbab 2011-09-06 rsc undo(t, nil, nil, TRUE, 0, nil, 0);
770 f8dea3c1 2005-12-16 devnull return;
771 b15fd976 2017-07-16 rsc case Kcmd+'Z': /* %-shift-Z: redo */
772 b15fd976 2017-07-16 rsc typecommit(t);
773 b15fd976 2017-07-16 rsc undo(t, nil, nil, FALSE, 0, nil, 0);
774 fa325e9b 2020-01-10 cross return;
775 4aad1a32 2009-04-30 rsc
776 f8dea3c1 2005-12-16 devnull Tagdown:
777 f8dea3c1 2005-12-16 devnull /* expand tag to show all text */
778 f8dea3c1 2005-12-16 devnull if(!t->w->tagexpand){
779 f8dea3c1 2005-12-16 devnull t->w->tagexpand = TRUE;
780 f8dea3c1 2005-12-16 devnull winresize(t->w, t->w->r, FALSE, TRUE);
781 f8dea3c1 2005-12-16 devnull }
782 f8dea3c1 2005-12-16 devnull return;
783 fa325e9b 2020-01-10 cross
784 f8dea3c1 2005-12-16 devnull Tagup:
785 f8dea3c1 2005-12-16 devnull /* shrink tag to single line */
786 f8dea3c1 2005-12-16 devnull if(t->w->tagexpand){
787 f8dea3c1 2005-12-16 devnull t->w->tagexpand = FALSE;
788 f8dea3c1 2005-12-16 devnull t->w->taglines = 1;
789 f8dea3c1 2005-12-16 devnull winresize(t->w, t->w->r, FALSE, TRUE);
790 f8dea3c1 2005-12-16 devnull }
791 2a373ea4 2005-03-18 devnull return;
792 b3994ec5 2003-12-11 devnull }
793 b3994ec5 2003-12-11 devnull if(t->what == Body){
794 b3994ec5 2003-12-11 devnull seq++;
795 b3994ec5 2003-12-11 devnull filemark(t->file);
796 4aad1a32 2009-04-30 rsc }
797 4aad1a32 2009-04-30 rsc /* cut/paste must be done after the seq++/filemark */
798 4aad1a32 2009-04-30 rsc switch(r){
799 4aad1a32 2009-04-30 rsc case Kcmd+'x': /* %X: cut */
800 4aad1a32 2009-04-30 rsc typecommit(t);
801 4aad1a32 2009-04-30 rsc if(t->what == Body){
802 4aad1a32 2009-04-30 rsc seq++;
803 4aad1a32 2009-04-30 rsc filemark(t->file);
804 4aad1a32 2009-04-30 rsc }
805 4aad1a32 2009-04-30 rsc cut(t, t, nil, TRUE, TRUE, nil, 0);
806 4aad1a32 2009-04-30 rsc textshow(t, t->q0, t->q0, 1);
807 76864eb6 2011-08-02 rsc t->iq1 = t->q0;
808 4aad1a32 2009-04-30 rsc return;
809 4aad1a32 2009-04-30 rsc case Kcmd+'v': /* %V: paste */
810 4aad1a32 2009-04-30 rsc typecommit(t);
811 4aad1a32 2009-04-30 rsc if(t->what == Body){
812 4aad1a32 2009-04-30 rsc seq++;
813 4aad1a32 2009-04-30 rsc filemark(t->file);
814 4aad1a32 2009-04-30 rsc }
815 4aad1a32 2009-04-30 rsc paste(t, t, nil, TRUE, FALSE, nil, 0);
816 4aad1a32 2009-04-30 rsc textshow(t, t->q0, t->q1, 1);
817 76864eb6 2011-08-02 rsc t->iq1 = t->q1;
818 4aad1a32 2009-04-30 rsc return;
819 b3994ec5 2003-12-11 devnull }
820 b3994ec5 2003-12-11 devnull if(t->q1 > t->q0){
821 b3994ec5 2003-12-11 devnull if(t->ncache != 0)
822 b3994ec5 2003-12-11 devnull error("text.type");
823 b3994ec5 2003-12-11 devnull cut(t, t, nil, TRUE, TRUE, nil, 0);
824 b3994ec5 2003-12-11 devnull t->eq0 = ~0;
825 b3994ec5 2003-12-11 devnull }
826 b3994ec5 2003-12-11 devnull textshow(t, t->q0, t->q0, 1);
827 b3994ec5 2003-12-11 devnull switch(r){
828 c1973705 2004-02-09 devnull case 0x06: /* ^F: complete */
829 c1973705 2004-02-09 devnull case Kins:
830 5a69e405 2013-10-22 robpike typecommit(t);
831 c1973705 2004-02-09 devnull rp = textcomplete(t);
832 c1973705 2004-02-09 devnull if(rp == nil)
833 c1973705 2004-02-09 devnull return;
834 c1973705 2004-02-09 devnull nr = runestrlen(rp);
835 c1973705 2004-02-09 devnull break; /* fall through to normal insertion case */
836 b3994ec5 2003-12-11 devnull case 0x1B:
837 fff818fe 2014-12-02 rsc if(t->eq0 != ~0) {
838 fff818fe 2014-12-02 rsc if(t->eq0 <= t->q0)
839 fff818fe 2014-12-02 rsc textsetselect(t, t->eq0, t->q0);
840 fff818fe 2014-12-02 rsc else
841 fff818fe 2014-12-02 rsc textsetselect(t, t->q0, t->eq0);
842 fff818fe 2014-12-02 rsc }
843 5544aaf9 2005-03-18 devnull if(t->ncache > 0)
844 5544aaf9 2005-03-18 devnull typecommit(t);
845 76864eb6 2011-08-02 rsc t->iq1 = t->q0;
846 b3994ec5 2003-12-11 devnull return;
847 b3994ec5 2003-12-11 devnull case 0x08: /* ^H: erase character */
848 b3994ec5 2003-12-11 devnull case 0x15: /* ^U: erase line */
849 b3994ec5 2003-12-11 devnull case 0x17: /* ^W: erase word */
850 b3994ec5 2003-12-11 devnull if(t->q0 == 0) /* nothing to erase */
851 b3994ec5 2003-12-11 devnull return;
852 b3994ec5 2003-12-11 devnull nnb = textbswidth(t, r);
853 b3994ec5 2003-12-11 devnull q1 = t->q0;
854 b3994ec5 2003-12-11 devnull q0 = q1-nnb;
855 b3994ec5 2003-12-11 devnull /* if selection is at beginning of window, avoid deleting invisible text */
856 b3994ec5 2003-12-11 devnull if(q0 < t->org){
857 b3994ec5 2003-12-11 devnull q0 = t->org;
858 b3994ec5 2003-12-11 devnull nnb = q1-q0;
859 b3994ec5 2003-12-11 devnull }
860 b3994ec5 2003-12-11 devnull if(nnb <= 0)
861 b3994ec5 2003-12-11 devnull return;
862 b3994ec5 2003-12-11 devnull for(i=0; i<t->file->ntext; i++){
863 b3994ec5 2003-12-11 devnull u = t->file->text[i];
864 b3994ec5 2003-12-11 devnull u->nofill = TRUE;
865 b3994ec5 2003-12-11 devnull nb = nnb;
866 b3994ec5 2003-12-11 devnull n = u->ncache;
867 b3994ec5 2003-12-11 devnull if(n > 0){
868 b3994ec5 2003-12-11 devnull if(q1 != u->cq0+n)
869 b3994ec5 2003-12-11 devnull error("text.type backspace");
870 b3994ec5 2003-12-11 devnull if(n > nb)
871 b3994ec5 2003-12-11 devnull n = nb;
872 b3994ec5 2003-12-11 devnull u->ncache -= n;
873 b3994ec5 2003-12-11 devnull textdelete(u, q1-n, q1, FALSE);
874 b3994ec5 2003-12-11 devnull nb -= n;
875 b3994ec5 2003-12-11 devnull }
876 b3994ec5 2003-12-11 devnull if(u->eq0==q1 || u->eq0==~0)
877 b3994ec5 2003-12-11 devnull u->eq0 = q0;
878 b3994ec5 2003-12-11 devnull if(nb && u==t)
879 b3994ec5 2003-12-11 devnull textdelete(u, q0, q0+nb, TRUE);
880 b3994ec5 2003-12-11 devnull if(u != t)
881 b3994ec5 2003-12-11 devnull textsetselect(u, u->q0, u->q1);
882 b3994ec5 2003-12-11 devnull else
883 b3994ec5 2003-12-11 devnull textsetselect(t, q0, q0);
884 b3994ec5 2003-12-11 devnull u->nofill = FALSE;
885 b3994ec5 2003-12-11 devnull }
886 b3994ec5 2003-12-11 devnull for(i=0; i<t->file->ntext; i++)
887 b3994ec5 2003-12-11 devnull textfill(t->file->text[i]);
888 76864eb6 2011-08-02 rsc t->iq1 = t->q0;
889 b3994ec5 2003-12-11 devnull return;
890 5a8e63b2 2004-02-29 devnull case '\n':
891 5a8e63b2 2004-02-29 devnull if(t->w->autoindent){
892 5a8e63b2 2004-02-29 devnull /* find beginning of previous line using backspace code */
893 5a8e63b2 2004-02-29 devnull nnb = textbswidth(t, 0x15); /* ^U case */
894 5a8e63b2 2004-02-29 devnull rp = runemalloc(nnb + 1);
895 5a8e63b2 2004-02-29 devnull nr = 0;
896 5a8e63b2 2004-02-29 devnull rp[nr++] = r;
897 5a8e63b2 2004-02-29 devnull for(i=0; i<nnb; i++){
898 5a8e63b2 2004-02-29 devnull r = textreadc(t, t->q0-nnb+i);
899 5a8e63b2 2004-02-29 devnull if(r != ' ' && r != '\t')
900 5a8e63b2 2004-02-29 devnull break;
901 5a8e63b2 2004-02-29 devnull rp[nr++] = r;
902 5a8e63b2 2004-02-29 devnull }
903 5a8e63b2 2004-02-29 devnull }
904 5a8e63b2 2004-02-29 devnull break; /* fall through to normal code */
905 b3994ec5 2003-12-11 devnull }
906 b3994ec5 2003-12-11 devnull /* otherwise ordinary character; just insert, typically in caches of all texts */
907 b3994ec5 2003-12-11 devnull for(i=0; i<t->file->ntext; i++){
908 b3994ec5 2003-12-11 devnull u = t->file->text[i];
909 b3994ec5 2003-12-11 devnull if(u->eq0 == ~0)
910 b3994ec5 2003-12-11 devnull u->eq0 = t->q0;
911 b3994ec5 2003-12-11 devnull if(u->ncache == 0)
912 b3994ec5 2003-12-11 devnull u->cq0 = t->q0;
913 b3994ec5 2003-12-11 devnull else if(t->q0 != u->cq0+u->ncache)
914 b3994ec5 2003-12-11 devnull error("text.type cq1");
915 cd1d0ab0 2006-01-12 devnull /*
916 cd1d0ab0 2006-01-12 devnull * Change the tag before we add to ncache,
917 cd1d0ab0 2006-01-12 devnull * so that if the window body is resized the
918 cd1d0ab0 2006-01-12 devnull * commit will not find anything in ncache.
919 cd1d0ab0 2006-01-12 devnull */
920 cd1d0ab0 2006-01-12 devnull if(u->what==Body && u->ncache == 0){
921 cd1d0ab0 2006-01-12 devnull u->needundo = TRUE;
922 cd1d0ab0 2006-01-12 devnull winsettag(t->w);
923 cd1d0ab0 2006-01-12 devnull u->needundo = FALSE;
924 cd1d0ab0 2006-01-12 devnull }
925 c1973705 2004-02-09 devnull textinsert(u, t->q0, rp, nr, FALSE);
926 b3994ec5 2003-12-11 devnull if(u != t)
927 b3994ec5 2003-12-11 devnull textsetselect(u, u->q0, u->q1);
928 c1973705 2004-02-09 devnull if(u->ncache+nr > u->ncachealloc){
929 c1973705 2004-02-09 devnull u->ncachealloc += 10 + nr;
930 b3994ec5 2003-12-11 devnull u->cache = runerealloc(u->cache, u->ncachealloc);
931 b3994ec5 2003-12-11 devnull }
932 c1973705 2004-02-09 devnull runemove(u->cache+u->ncache, rp, nr);
933 c1973705 2004-02-09 devnull u->ncache += nr;
934 b3994ec5 2003-12-11 devnull }
935 c1973705 2004-02-09 devnull if(rp != &r)
936 c1973705 2004-02-09 devnull free(rp);
937 c1973705 2004-02-09 devnull textsetselect(t, t->q0+nr, t->q0+nr);
938 b3994ec5 2003-12-11 devnull if(r=='\n' && t->w!=nil)
939 b3994ec5 2003-12-11 devnull wincommit(t->w, t);
940 76864eb6 2011-08-02 rsc t->iq1 = t->q0;
941 b3994ec5 2003-12-11 devnull }
942 b3994ec5 2003-12-11 devnull
943 b3994ec5 2003-12-11 devnull void
944 b3994ec5 2003-12-11 devnull textcommit(Text *t, int tofile)
945 b3994ec5 2003-12-11 devnull {
946 b3994ec5 2003-12-11 devnull if(t->ncache == 0)
947 b3994ec5 2003-12-11 devnull return;
948 b3994ec5 2003-12-11 devnull if(tofile)
949 b3994ec5 2003-12-11 devnull fileinsert(t->file, t->cq0, t->cache, t->ncache);
950 b3994ec5 2003-12-11 devnull if(t->what == Body){
951 b3994ec5 2003-12-11 devnull t->w->dirty = TRUE;
952 b3994ec5 2003-12-11 devnull t->w->utflastqid = -1;
953 b3994ec5 2003-12-11 devnull }
954 b3994ec5 2003-12-11 devnull t->ncache = 0;
955 b3994ec5 2003-12-11 devnull }
956 b3994ec5 2003-12-11 devnull
957 b3994ec5 2003-12-11 devnull static Text *clicktext;
958 b3994ec5 2003-12-11 devnull static uint clickmsec;
959 b3994ec5 2003-12-11 devnull static Text *selecttext;
960 b3994ec5 2003-12-11 devnull static uint selectq;
961 b3994ec5 2003-12-11 devnull
962 b3994ec5 2003-12-11 devnull /*
963 b3994ec5 2003-12-11 devnull * called from frame library
964 b3994ec5 2003-12-11 devnull */
965 b3994ec5 2003-12-11 devnull void
966 b3994ec5 2003-12-11 devnull framescroll(Frame *f, int dl)
967 b3994ec5 2003-12-11 devnull {
968 b3994ec5 2003-12-11 devnull if(f != &selecttext->fr)
969 b3994ec5 2003-12-11 devnull error("frameselect not right frame");
970 b3994ec5 2003-12-11 devnull textframescroll(selecttext, dl);
971 b3994ec5 2003-12-11 devnull }
972 b3994ec5 2003-12-11 devnull
973 b3994ec5 2003-12-11 devnull void
974 b3994ec5 2003-12-11 devnull textframescroll(Text *t, int dl)
975 b3994ec5 2003-12-11 devnull {
976 b3994ec5 2003-12-11 devnull uint q0;
977 b3994ec5 2003-12-11 devnull
978 b3994ec5 2003-12-11 devnull if(dl == 0){
979 b3994ec5 2003-12-11 devnull scrsleep(100);
980 b3994ec5 2003-12-11 devnull return;
981 b3994ec5 2003-12-11 devnull }
982 b3994ec5 2003-12-11 devnull if(dl < 0){
983 b3994ec5 2003-12-11 devnull q0 = textbacknl(t, t->org, -dl);
984 b3994ec5 2003-12-11 devnull if(selectq > t->org+t->fr.p0)
985 b3994ec5 2003-12-11 devnull textsetselect(t, t->org+t->fr.p0, selectq);
986 b3994ec5 2003-12-11 devnull else
987 b3994ec5 2003-12-11 devnull textsetselect(t, selectq, t->org+t->fr.p0);
988 b3994ec5 2003-12-11 devnull }else{
989 b3994ec5 2003-12-11 devnull if(t->org+t->fr.nchars == t->file->b.nc)
990 b3994ec5 2003-12-11 devnull return;
991 b3994ec5 2003-12-11 devnull q0 = t->org+frcharofpt(&t->fr, Pt(t->fr.r.min.x, t->fr.r.min.y+dl*t->fr.font->height));
992 b3994ec5 2003-12-11 devnull if(selectq > t->org+t->fr.p1)
993 b3994ec5 2003-12-11 devnull textsetselect(t, t->org+t->fr.p1, selectq);
994 b3994ec5 2003-12-11 devnull else
995 b3994ec5 2003-12-11 devnull textsetselect(t, selectq, t->org+t->fr.p1);
996 b3994ec5 2003-12-11 devnull }
997 b3994ec5 2003-12-11 devnull textsetorigin(t, q0, TRUE);
998 b3994ec5 2003-12-11 devnull }
999 b3994ec5 2003-12-11 devnull
1000 b3994ec5 2003-12-11 devnull
1001 b3994ec5 2003-12-11 devnull void
1002 b3994ec5 2003-12-11 devnull textselect(Text *t)
1003 b3994ec5 2003-12-11 devnull {
1004 b3994ec5 2003-12-11 devnull uint q0, q1;
1005 b3994ec5 2003-12-11 devnull int b, x, y;
1006 4ca53ff0 2006-02-08 devnull int state;
1007 4ca53ff0 2006-02-08 devnull enum { None, Cut, Paste };
1008 b3994ec5 2003-12-11 devnull
1009 b3994ec5 2003-12-11 devnull selecttext = t;
1010 b3994ec5 2003-12-11 devnull /*
1011 b3994ec5 2003-12-11 devnull * To have double-clicking and chording, we double-click
1012 b3994ec5 2003-12-11 devnull * immediately if it might make sense.
1013 b3994ec5 2003-12-11 devnull */
1014 b3994ec5 2003-12-11 devnull b = mouse->buttons;
1015 b3994ec5 2003-12-11 devnull q0 = t->q0;
1016 b3994ec5 2003-12-11 devnull q1 = t->q1;
1017 b3994ec5 2003-12-11 devnull selectq = t->org+frcharofpt(&t->fr, mouse->xy);
1018 b3994ec5 2003-12-11 devnull if(clicktext==t && mouse->msec-clickmsec<500)
1019 b3994ec5 2003-12-11 devnull if(q0==q1 && selectq==q0){
1020 b3994ec5 2003-12-11 devnull textdoubleclick(t, &q0, &q1);
1021 b3994ec5 2003-12-11 devnull textsetselect(t, q0, q1);
1022 b3994ec5 2003-12-11 devnull flushimage(display, 1);
1023 b3994ec5 2003-12-11 devnull x = mouse->xy.x;
1024 b3994ec5 2003-12-11 devnull y = mouse->xy.y;
1025 b3994ec5 2003-12-11 devnull /* stay here until something interesting happens */
1026 b3994ec5 2003-12-11 devnull do
1027 b3994ec5 2003-12-11 devnull readmouse(mousectl);
1028 b3994ec5 2003-12-11 devnull while(mouse->buttons==b && abs(mouse->xy.x-x)<3 && abs(mouse->xy.y-y)<3);
1029 b3994ec5 2003-12-11 devnull mouse->xy.x = x; /* in case we're calling frselect */
1030 b3994ec5 2003-12-11 devnull mouse->xy.y = y;
1031 b3994ec5 2003-12-11 devnull q0 = t->q0; /* may have changed */
1032 b3994ec5 2003-12-11 devnull q1 = t->q1;
1033 b3994ec5 2003-12-11 devnull selectq = q0;
1034 b3994ec5 2003-12-11 devnull }
1035 b3994ec5 2003-12-11 devnull if(mouse->buttons == b){
1036 b3994ec5 2003-12-11 devnull t->fr.scroll = framescroll;
1037 b3994ec5 2003-12-11 devnull frselect(&t->fr, mousectl);
1038 b3994ec5 2003-12-11 devnull /* horrible botch: while asleep, may have lost selection altogether */
1039 b3994ec5 2003-12-11 devnull if(selectq > t->file->b.nc)
1040 b3994ec5 2003-12-11 devnull selectq = t->org + t->fr.p0;
1041 5544aaf9 2005-03-18 devnull t->fr.scroll = nil;
1042 b3994ec5 2003-12-11 devnull if(selectq < t->org)
1043 b3994ec5 2003-12-11 devnull q0 = selectq;
1044 b3994ec5 2003-12-11 devnull else
1045 b3994ec5 2003-12-11 devnull q0 = t->org + t->fr.p0;
1046 b3994ec5 2003-12-11 devnull if(selectq > t->org+t->fr.nchars)
1047 b3994ec5 2003-12-11 devnull q1 = selectq;
1048 b3994ec5 2003-12-11 devnull else
1049 b3994ec5 2003-12-11 devnull q1 = t->org+t->fr.p1;
1050 b3994ec5 2003-12-11 devnull }
1051 b3994ec5 2003-12-11 devnull if(q0 == q1){
1052 b3994ec5 2003-12-11 devnull if(q0==t->q0 && clicktext==t && mouse->msec-clickmsec<500){
1053 b3994ec5 2003-12-11 devnull textdoubleclick(t, &q0, &q1);
1054 b3994ec5 2003-12-11 devnull clicktext = nil;
1055 b3994ec5 2003-12-11 devnull }else{
1056 b3994ec5 2003-12-11 devnull clicktext = t;
1057 b3994ec5 2003-12-11 devnull clickmsec = mouse->msec;
1058 b3994ec5 2003-12-11 devnull }
1059 b3994ec5 2003-12-11 devnull }else
1060 b3994ec5 2003-12-11 devnull clicktext = nil;
1061 b3994ec5 2003-12-11 devnull textsetselect(t, q0, q1);
1062 b3994ec5 2003-12-11 devnull flushimage(display, 1);
1063 4ca53ff0 2006-02-08 devnull state = None; /* what we've done; undo when possible */
1064 b3994ec5 2003-12-11 devnull while(mouse->buttons){
1065 b3994ec5 2003-12-11 devnull mouse->msec = 0;
1066 b3994ec5 2003-12-11 devnull b = mouse->buttons;
1067 8b9a1d4c 2006-02-06 devnull if((b&1) && (b&6)){
1068 4ca53ff0 2006-02-08 devnull if(state==None && t->what==Body){
1069 b3994ec5 2003-12-11 devnull seq++;
1070 b3994ec5 2003-12-11 devnull filemark(t->w->body.file);
1071 b3994ec5 2003-12-11 devnull }
1072 b3994ec5 2003-12-11 devnull if(b & 2){
1073 4ca53ff0 2006-02-08 devnull if(state==Paste && t->what==Body){
1074 b3994ec5 2003-12-11 devnull winundo(t->w, TRUE);
1075 4ca53ff0 2006-02-08 devnull textsetselect(t, q0, t->q1);
1076 4ca53ff0 2006-02-08 devnull state = None;
1077 4ca53ff0 2006-02-08 devnull }else if(state != Cut){
1078 b3994ec5 2003-12-11 devnull cut(t, t, nil, TRUE, TRUE, nil, 0);
1079 4ca53ff0 2006-02-08 devnull state = Cut;
1080 b3994ec5 2003-12-11 devnull }
1081 b3994ec5 2003-12-11 devnull }else{
1082 4ca53ff0 2006-02-08 devnull if(state==Cut && t->what==Body){
1083 b3994ec5 2003-12-11 devnull winundo(t->w, TRUE);
1084 b3994ec5 2003-12-11 devnull textsetselect(t, q0, t->q1);
1085 4ca53ff0 2006-02-08 devnull state = None;
1086 4ca53ff0 2006-02-08 devnull }else if(state != Paste){
1087 b3994ec5 2003-12-11 devnull paste(t, t, nil, TRUE, FALSE, nil, 0);
1088 4ca53ff0 2006-02-08 devnull state = Paste;
1089 b3994ec5 2003-12-11 devnull }
1090 b3994ec5 2003-12-11 devnull }
1091 b3994ec5 2003-12-11 devnull textscrdraw(t);
1092 b3994ec5 2003-12-11 devnull clearmouse();
1093 b3994ec5 2003-12-11 devnull }
1094 b3994ec5 2003-12-11 devnull flushimage(display, 1);
1095 b3994ec5 2003-12-11 devnull while(mouse->buttons == b)
1096 b3994ec5 2003-12-11 devnull readmouse(mousectl);
1097 b3994ec5 2003-12-11 devnull clicktext = nil;
1098 b3994ec5 2003-12-11 devnull }
1099 b3994ec5 2003-12-11 devnull }
1100 b3994ec5 2003-12-11 devnull
1101 b3994ec5 2003-12-11 devnull void
1102 b3994ec5 2003-12-11 devnull textshow(Text *t, uint q0, uint q1, int doselect)
1103 b3994ec5 2003-12-11 devnull {
1104 b3994ec5 2003-12-11 devnull int qe;
1105 b3994ec5 2003-12-11 devnull int nl;
1106 5a69e405 2013-10-22 robpike int tsd;
1107 5a69e405 2013-10-22 robpike int nc;
1108 b3994ec5 2003-12-11 devnull uint q;
1109 b3994ec5 2003-12-11 devnull
1110 1a8f27c3 2004-05-14 devnull if(t->what != Body){
1111 1a8f27c3 2004-05-14 devnull if(doselect)
1112 1a8f27c3 2004-05-14 devnull textsetselect(t, q0, q1);
1113 b3994ec5 2003-12-11 devnull return;
1114 1a8f27c3 2004-05-14 devnull }
1115 b3994ec5 2003-12-11 devnull if(t->w!=nil && t->fr.maxlines==0)
1116 b3994ec5 2003-12-11 devnull colgrow(t->col, t->w, 1);
1117 b3994ec5 2003-12-11 devnull if(doselect)
1118 b3994ec5 2003-12-11 devnull textsetselect(t, q0, q1);
1119 b3994ec5 2003-12-11 devnull qe = t->org+t->fr.nchars;
1120 5a69e405 2013-10-22 robpike tsd = FALSE; /* do we call textscrdraw? */
1121 5a69e405 2013-10-22 robpike nc = t->file->b.nc+t->ncache;
1122 5a69e405 2013-10-22 robpike if(t->org <= q0){
1123 5a69e405 2013-10-22 robpike if(nc==0 || q0<qe)
1124 5a69e405 2013-10-22 robpike tsd = TRUE;
1125 5a69e405 2013-10-22 robpike else if(q0==qe && qe==nc){
1126 5a69e405 2013-10-22 robpike if(textreadc(t, nc-1) == '\n'){
1127 5a69e405 2013-10-22 robpike if(t->fr.nlines<t->fr.maxlines)
1128 5a69e405 2013-10-22 robpike tsd = TRUE;
1129 5a69e405 2013-10-22 robpike }else
1130 5a69e405 2013-10-22 robpike tsd = TRUE;
1131 5a69e405 2013-10-22 robpike }
1132 5a69e405 2013-10-22 robpike }
1133 5a69e405 2013-10-22 robpike if(tsd)
1134 b3994ec5 2003-12-11 devnull textscrdraw(t);
1135 b3994ec5 2003-12-11 devnull else{
1136 b3994ec5 2003-12-11 devnull if(t->w->nopen[QWevent] > 0)
1137 b3994ec5 2003-12-11 devnull nl = 3*t->fr.maxlines/4;
1138 b3994ec5 2003-12-11 devnull else
1139 b3994ec5 2003-12-11 devnull nl = t->fr.maxlines/4;
1140 b3994ec5 2003-12-11 devnull q = textbacknl(t, q0, nl);
1141 b3994ec5 2003-12-11 devnull /* avoid going backwards if trying to go forwards - long lines! */
1142 b3994ec5 2003-12-11 devnull if(!(q0>t->org && q<t->org))
1143 b3994ec5 2003-12-11 devnull textsetorigin(t, q, TRUE);
1144 b3994ec5 2003-12-11 devnull while(q0 > t->org+t->fr.nchars)
1145 b3994ec5 2003-12-11 devnull textsetorigin(t, t->org+1, FALSE);
1146 b3994ec5 2003-12-11 devnull }
1147 b3994ec5 2003-12-11 devnull }
1148 b3994ec5 2003-12-11 devnull
1149 b3994ec5 2003-12-11 devnull static
1150 b3994ec5 2003-12-11 devnull int
1151 b3994ec5 2003-12-11 devnull region(int a, int b)
1152 b3994ec5 2003-12-11 devnull {
1153 b3994ec5 2003-12-11 devnull if(a < b)
1154 b3994ec5 2003-12-11 devnull return -1;
1155 b3994ec5 2003-12-11 devnull if(a == b)
1156 b3994ec5 2003-12-11 devnull return 0;
1157 b3994ec5 2003-12-11 devnull return 1;
1158 b3994ec5 2003-12-11 devnull }
1159 b3994ec5 2003-12-11 devnull
1160 b3994ec5 2003-12-11 devnull void
1161 b3994ec5 2003-12-11 devnull selrestore(Frame *f, Point pt0, uint p0, uint p1)
1162 b3994ec5 2003-12-11 devnull {
1163 b3994ec5 2003-12-11 devnull if(p1<=f->p0 || p0>=f->p1){
1164 b3994ec5 2003-12-11 devnull /* no overlap */
1165 b3994ec5 2003-12-11 devnull frdrawsel0(f, pt0, p0, p1, f->cols[BACK], f->cols[TEXT]);
1166 b3994ec5 2003-12-11 devnull return;
1167 b3994ec5 2003-12-11 devnull }
1168 b3994ec5 2003-12-11 devnull if(p0>=f->p0 && p1<=f->p1){
1169 b3994ec5 2003-12-11 devnull /* entirely inside */
1170 b3994ec5 2003-12-11 devnull frdrawsel0(f, pt0, p0, p1, f->cols[HIGH], f->cols[HTEXT]);
1171 b3994ec5 2003-12-11 devnull return;
1172 b3994ec5 2003-12-11 devnull }
1173 b3994ec5 2003-12-11 devnull
1174 b3994ec5 2003-12-11 devnull /* they now are known to overlap */
1175 b3994ec5 2003-12-11 devnull
1176 b3994ec5 2003-12-11 devnull /* before selection */
1177 b3994ec5 2003-12-11 devnull if(p0 < f->p0){
1178 b3994ec5 2003-12-11 devnull frdrawsel0(f, pt0, p0, f->p0, f->cols[BACK], f->cols[TEXT]);
1179 b3994ec5 2003-12-11 devnull p0 = f->p0;
1180 b3994ec5 2003-12-11 devnull pt0 = frptofchar(f, p0);
1181 b3994ec5 2003-12-11 devnull }
1182 b3994ec5 2003-12-11 devnull /* after selection */
1183 b3994ec5 2003-12-11 devnull if(p1 > f->p1){
1184 b3994ec5 2003-12-11 devnull frdrawsel0(f, frptofchar(f, f->p1), f->p1, p1, f->cols[BACK], f->cols[TEXT]);
1185 b3994ec5 2003-12-11 devnull p1 = f->p1;
1186 b3994ec5 2003-12-11 devnull }
1187 b3994ec5 2003-12-11 devnull /* inside selection */
1188 b3994ec5 2003-12-11 devnull frdrawsel0(f, pt0, p0, p1, f->cols[HIGH], f->cols[HTEXT]);
1189 b3994ec5 2003-12-11 devnull }
1190 b3994ec5 2003-12-11 devnull
1191 b3994ec5 2003-12-11 devnull void
1192 b3994ec5 2003-12-11 devnull textsetselect(Text *t, uint q0, uint q1)
1193 b3994ec5 2003-12-11 devnull {
1194 97e44323 2007-05-10 devnull int p0, p1, ticked;
1195 fa325e9b 2020-01-10 cross
1196 b3994ec5 2003-12-11 devnull /* t->fr.p0 and t->fr.p1 are always right; t->q0 and t->q1 may be off */
1197 b3994ec5 2003-12-11 devnull t->q0 = q0;
1198 b3994ec5 2003-12-11 devnull t->q1 = q1;
1199 b3994ec5 2003-12-11 devnull /* compute desired p0,p1 from q0,q1 */
1200 b3994ec5 2003-12-11 devnull p0 = q0-t->org;
1201 b3994ec5 2003-12-11 devnull p1 = q1-t->org;
1202 97e44323 2007-05-10 devnull ticked = 1;
1203 97e44323 2007-05-10 devnull if(p0 < 0){
1204 97e44323 2007-05-10 devnull ticked = 0;
1205 b3994ec5 2003-12-11 devnull p0 = 0;
1206 97e44323 2007-05-10 devnull }
1207 b3994ec5 2003-12-11 devnull if(p1 < 0)
1208 b3994ec5 2003-12-11 devnull p1 = 0;
1209 b3994ec5 2003-12-11 devnull if(p0 > t->fr.nchars)
1210 b3994ec5 2003-12-11 devnull p0 = t->fr.nchars;
1211 97e44323 2007-05-10 devnull if(p1 > t->fr.nchars){
1212 97e44323 2007-05-10 devnull ticked = 0;
1213 97e44323 2007-05-10 devnull p1 = t->fr.nchars;
1214 97e44323 2007-05-10 devnull }
1215 97e44323 2007-05-10 devnull if(p0==t->fr.p0 && p1==t->fr.p1){
1216 97e44323 2007-05-10 devnull if(p0 == p1 && ticked != t->fr.ticked)
1217 97e44323 2007-05-10 devnull frtick(&t->fr, frptofchar(&t->fr, p0), ticked);
1218 b3994ec5 2003-12-11 devnull return;
1219 97e44323 2007-05-10 devnull }
1220 fff818fe 2014-12-02 rsc if(p0 > p1)
1221 fff818fe 2014-12-02 rsc sysfatal("acme: textsetselect p0=%d p1=%d q0=%ud q1=%ud t->org=%d nchars=%d", p0, p1, q0, q1, (int)t->org, (int)t->fr.nchars);
1222 b3994ec5 2003-12-11 devnull /* screen disagrees with desired selection */
1223 b3994ec5 2003-12-11 devnull if(t->fr.p1<=p0 || p1<=t->fr.p0 || p0==p1 || t->fr.p1==t->fr.p0){
1224 b3994ec5 2003-12-11 devnull /* no overlap or too easy to bother trying */
1225 b3994ec5 2003-12-11 devnull frdrawsel(&t->fr, frptofchar(&t->fr, t->fr.p0), t->fr.p0, t->fr.p1, 0);
1226 97e44323 2007-05-10 devnull if(p0 != p1 || ticked)
1227 97e44323 2007-05-10 devnull frdrawsel(&t->fr, frptofchar(&t->fr, p0), p0, p1, 1);
1228 b3994ec5 2003-12-11 devnull goto Return;
1229 b3994ec5 2003-12-11 devnull }
1230 b3994ec5 2003-12-11 devnull /* overlap; avoid unnecessary painting */
1231 b3994ec5 2003-12-11 devnull if(p0 < t->fr.p0){
1232 b3994ec5 2003-12-11 devnull /* extend selection backwards */
1233 b3994ec5 2003-12-11 devnull frdrawsel(&t->fr, frptofchar(&t->fr, p0), p0, t->fr.p0, 1);
1234 b3994ec5 2003-12-11 devnull }else if(p0 > t->fr.p0){
1235 b3994ec5 2003-12-11 devnull /* trim first part of selection */
1236 b3994ec5 2003-12-11 devnull frdrawsel(&t->fr, frptofchar(&t->fr, t->fr.p0), t->fr.p0, p0, 0);
1237 b3994ec5 2003-12-11 devnull }
1238 b3994ec5 2003-12-11 devnull if(p1 > t->fr.p1){
1239 b3994ec5 2003-12-11 devnull /* extend selection forwards */
1240 b3994ec5 2003-12-11 devnull frdrawsel(&t->fr, frptofchar(&t->fr, t->fr.p1), t->fr.p1, p1, 1);
1241 b3994ec5 2003-12-11 devnull }else if(p1 < t->fr.p1){
1242 b3994ec5 2003-12-11 devnull /* trim last part of selection */
1243 b3994ec5 2003-12-11 devnull frdrawsel(&t->fr, frptofchar(&t->fr, p1), p1, t->fr.p1, 0);
1244 b3994ec5 2003-12-11 devnull }
1245 b3994ec5 2003-12-11 devnull
1246 b3994ec5 2003-12-11 devnull Return:
1247 b3994ec5 2003-12-11 devnull t->fr.p0 = p0;
1248 b3994ec5 2003-12-11 devnull t->fr.p1 = p1;
1249 b3994ec5 2003-12-11 devnull }
1250 b3994ec5 2003-12-11 devnull
1251 b3994ec5 2003-12-11 devnull /*
1252 b3994ec5 2003-12-11 devnull * Release the button in less than DELAY ms and it's considered a null selection
1253 b3994ec5 2003-12-11 devnull * if the mouse hardly moved, regardless of whether it crossed a char boundary.
1254 b3994ec5 2003-12-11 devnull */
1255 b3994ec5 2003-12-11 devnull enum {
1256 b3994ec5 2003-12-11 devnull DELAY = 2,
1257 cbeb0b26 2006-04-01 devnull MINMOVE = 4
1258 b3994ec5 2003-12-11 devnull };
1259 b3994ec5 2003-12-11 devnull
1260 b3994ec5 2003-12-11 devnull uint
1261 b3994ec5 2003-12-11 devnull xselect(Frame *f, Mousectl *mc, Image *col, uint *p1p) /* when called, button is down */
1262 b3994ec5 2003-12-11 devnull {
1263 b3994ec5 2003-12-11 devnull uint p0, p1, q, tmp;
1264 b3994ec5 2003-12-11 devnull ulong msec;
1265 b3994ec5 2003-12-11 devnull Point mp, pt0, pt1, qt;
1266 b3994ec5 2003-12-11 devnull int reg, b;
1267 b3994ec5 2003-12-11 devnull
1268 b3994ec5 2003-12-11 devnull mp = mc->m.xy;
1269 b3994ec5 2003-12-11 devnull b = mc->m.buttons;
1270 b3994ec5 2003-12-11 devnull msec = mc->m.msec;
1271 b3994ec5 2003-12-11 devnull
1272 b3994ec5 2003-12-11 devnull /* remove tick */
1273 b3994ec5 2003-12-11 devnull if(f->p0 == f->p1)
1274 b3994ec5 2003-12-11 devnull frtick(f, frptofchar(f, f->p0), 0);
1275 b3994ec5 2003-12-11 devnull p0 = p1 = frcharofpt(f, mp);
1276 b3994ec5 2003-12-11 devnull pt0 = frptofchar(f, p0);
1277 b3994ec5 2003-12-11 devnull pt1 = frptofchar(f, p1);
1278 b3994ec5 2003-12-11 devnull reg = 0;
1279 b3994ec5 2003-12-11 devnull frtick(f, pt0, 1);
1280 b3994ec5 2003-12-11 devnull do{
1281 b3994ec5 2003-12-11 devnull q = frcharofpt(f, mc->m.xy);
1282 b3994ec5 2003-12-11 devnull if(p1 != q){
1283 b3994ec5 2003-12-11 devnull if(p0 == p1)
1284 b3994ec5 2003-12-11 devnull frtick(f, pt0, 0);
1285 b3994ec5 2003-12-11 devnull if(reg != region(q, p0)){ /* crossed starting point; reset */
1286 b3994ec5 2003-12-11 devnull if(reg > 0)
1287 b3994ec5 2003-12-11 devnull selrestore(f, pt0, p0, p1);
1288 b3994ec5 2003-12-11 devnull else if(reg < 0)
1289 b3994ec5 2003-12-11 devnull selrestore(f, pt1, p1, p0);
1290 b3994ec5 2003-12-11 devnull p1 = p0;
1291 b3994ec5 2003-12-11 devnull pt1 = pt0;
1292 b3994ec5 2003-12-11 devnull reg = region(q, p0);
1293 b3994ec5 2003-12-11 devnull if(reg == 0)
1294 b3994ec5 2003-12-11 devnull frdrawsel0(f, pt0, p0, p1, col, display->white);
1295 b3994ec5 2003-12-11 devnull }
1296 b3994ec5 2003-12-11 devnull qt = frptofchar(f, q);
1297 b3994ec5 2003-12-11 devnull if(reg > 0){
1298 b3994ec5 2003-12-11 devnull if(q > p1)
1299 b3994ec5 2003-12-11 devnull frdrawsel0(f, pt1, p1, q, col, display->white);
1300 b3994ec5 2003-12-11 devnull
1301 b3994ec5 2003-12-11 devnull else if(q < p1)
1302 b3994ec5 2003-12-11 devnull selrestore(f, qt, q, p1);
1303 b3994ec5 2003-12-11 devnull }else if(reg < 0){
1304 b3994ec5 2003-12-11 devnull if(q > p1)
1305 b3994ec5 2003-12-11 devnull selrestore(f, pt1, p1, q);
1306 b3994ec5 2003-12-11 devnull else
1307 b3994ec5 2003-12-11 devnull frdrawsel0(f, qt, q, p1, col, display->white);
1308 b3994ec5 2003-12-11 devnull }
1309 b3994ec5 2003-12-11 devnull p1 = q;
1310 b3994ec5 2003-12-11 devnull pt1 = qt;
1311 b3994ec5 2003-12-11 devnull }
1312 b3994ec5 2003-12-11 devnull if(p0 == p1)
1313 b3994ec5 2003-12-11 devnull frtick(f, pt0, 1);
1314 b3994ec5 2003-12-11 devnull flushimage(f->display, 1);
1315 b3994ec5 2003-12-11 devnull readmouse(mc);
1316 b3994ec5 2003-12-11 devnull }while(mc->m.buttons == b);
1317 b3994ec5 2003-12-11 devnull if(mc->m.msec-msec < DELAY && p0!=p1
1318 b3994ec5 2003-12-11 devnull && abs(mp.x-mc->m.xy.x)<MINMOVE
1319 b3994ec5 2003-12-11 devnull && abs(mp.y-mc->m.xy.y)<MINMOVE) {
1320 b3994ec5 2003-12-11 devnull if(reg > 0)
1321 b3994ec5 2003-12-11 devnull selrestore(f, pt0, p0, p1);
1322 b3994ec5 2003-12-11 devnull else if(reg < 0)
1323 b3994ec5 2003-12-11 devnull selrestore(f, pt1, p1, p0);
1324 b3994ec5 2003-12-11 devnull p1 = p0;
1325 b3994ec5 2003-12-11 devnull }
1326 b3994ec5 2003-12-11 devnull if(p1 < p0){
1327 b3994ec5 2003-12-11 devnull tmp = p0;
1328 b3994ec5 2003-12-11 devnull p0 = p1;
1329 b3994ec5 2003-12-11 devnull p1 = tmp;
1330 b3994ec5 2003-12-11 devnull }
1331 b3994ec5 2003-12-11 devnull pt0 = frptofchar(f, p0);
1332 b3994ec5 2003-12-11 devnull if(p0 == p1)
1333 b3994ec5 2003-12-11 devnull frtick(f, pt0, 0);
1334 b3994ec5 2003-12-11 devnull selrestore(f, pt0, p0, p1);
1335 b3994ec5 2003-12-11 devnull /* restore tick */
1336 b3994ec5 2003-12-11 devnull if(f->p0 == f->p1)
1337 b3994ec5 2003-12-11 devnull frtick(f, frptofchar(f, f->p0), 1);
1338 b3994ec5 2003-12-11 devnull flushimage(f->display, 1);
1339 b3994ec5 2003-12-11 devnull *p1p = p1;
1340 b3994ec5 2003-12-11 devnull return p0;
1341 b3994ec5 2003-12-11 devnull }
1342 b3994ec5 2003-12-11 devnull
1343 b3994ec5 2003-12-11 devnull int
1344 b3994ec5 2003-12-11 devnull textselect23(Text *t, uint *q0, uint *q1, Image *high, int mask)
1345 b3994ec5 2003-12-11 devnull {
1346 b3994ec5 2003-12-11 devnull uint p0, p1;
1347 b3994ec5 2003-12-11 devnull int buts;
1348 fa325e9b 2020-01-10 cross
1349 b3994ec5 2003-12-11 devnull p0 = xselect(&t->fr, mousectl, high, &p1);
1350 b3994ec5 2003-12-11 devnull buts = mousectl->m.buttons;
1351 b3994ec5 2003-12-11 devnull if((buts & mask) == 0){
1352 b3994ec5 2003-12-11 devnull *q0 = p0+t->org;
1353 b3994ec5 2003-12-11 devnull *q1 = p1+t->org;
1354 b3994ec5 2003-12-11 devnull }
1355 b3994ec5 2003-12-11 devnull
1356 b3994ec5 2003-12-11 devnull while(mousectl->m.buttons)
1357 b3994ec5 2003-12-11 devnull readmouse(mousectl);
1358 b3994ec5 2003-12-11 devnull return buts;
1359 b3994ec5 2003-12-11 devnull }
1360 b3994ec5 2003-12-11 devnull
1361 b3994ec5 2003-12-11 devnull int
1362 b3994ec5 2003-12-11 devnull textselect2(Text *t, uint *q0, uint *q1, Text **tp)
1363 b3994ec5 2003-12-11 devnull {
1364 b3994ec5 2003-12-11 devnull int buts;
1365 b3994ec5 2003-12-11 devnull
1366 b3994ec5 2003-12-11 devnull *tp = nil;
1367 b3994ec5 2003-12-11 devnull buts = textselect23(t, q0, q1, but2col, 4);
1368 b3994ec5 2003-12-11 devnull if(buts & 4)
1369 b3994ec5 2003-12-11 devnull return 0;
1370 b3994ec5 2003-12-11 devnull if(buts & 1){ /* pick up argument */
1371 b3994ec5 2003-12-11 devnull *tp = argtext;
1372 b3994ec5 2003-12-11 devnull return 1;
1373 b3994ec5 2003-12-11 devnull }
1374 b3994ec5 2003-12-11 devnull return 1;
1375 b3994ec5 2003-12-11 devnull }
1376 b3994ec5 2003-12-11 devnull
1377 b3994ec5 2003-12-11 devnull int
1378 b3994ec5 2003-12-11 devnull textselect3(Text *t, uint *q0, uint *q1)
1379 b3994ec5 2003-12-11 devnull {
1380 b3994ec5 2003-12-11 devnull int h;
1381 b3994ec5 2003-12-11 devnull
1382 b3994ec5 2003-12-11 devnull h = (textselect23(t, q0, q1, but3col, 1|2) == 0);
1383 b3994ec5 2003-12-11 devnull return h;
1384 b3994ec5 2003-12-11 devnull }
1385 b3994ec5 2003-12-11 devnull
1386 b3994ec5 2003-12-11 devnull static Rune left1[] = { '{', '[', '(', '<', 0xab, 0 };
1387 b3994ec5 2003-12-11 devnull static Rune right1[] = { '}', ']', ')', '>', 0xbb, 0 };
1388 b3994ec5 2003-12-11 devnull static Rune left2[] = { '\n', 0 };
1389 b3994ec5 2003-12-11 devnull static Rune left3[] = { '\'', '"', '`', 0 };
1390 b3994ec5 2003-12-11 devnull
1391 b3994ec5 2003-12-11 devnull static
1392 b3994ec5 2003-12-11 devnull Rune *left[] = {
1393 b3994ec5 2003-12-11 devnull left1,
1394 b3994ec5 2003-12-11 devnull left2,
1395 b3994ec5 2003-12-11 devnull left3,
1396 b3994ec5 2003-12-11 devnull nil
1397 b3994ec5 2003-12-11 devnull };
1398 b3994ec5 2003-12-11 devnull static
1399 b3994ec5 2003-12-11 devnull Rune *right[] = {
1400 b3994ec5 2003-12-11 devnull right1,
1401 b3994ec5 2003-12-11 devnull left2,
1402 b3994ec5 2003-12-11 devnull left3,
1403 b3994ec5 2003-12-11 devnull nil
1404 b3994ec5 2003-12-11 devnull };
1405 b3994ec5 2003-12-11 devnull
1406 b3994ec5 2003-12-11 devnull void
1407 b3994ec5 2003-12-11 devnull textdoubleclick(Text *t, uint *q0, uint *q1)
1408 b3994ec5 2003-12-11 devnull {
1409 b3994ec5 2003-12-11 devnull int c, i;
1410 b3994ec5 2003-12-11 devnull Rune *r, *l, *p;
1411 b3994ec5 2003-12-11 devnull uint q;
1412 b3994ec5 2003-12-11 devnull
1413 4dbf2556 2009-09-11 russcox if(textclickhtmlmatch(t, q0, q1))
1414 4dbf2556 2009-09-11 russcox return;
1415 fa325e9b 2020-01-10 cross
1416 b3994ec5 2003-12-11 devnull for(i=0; left[i]!=nil; i++){
1417 b3994ec5 2003-12-11 devnull q = *q0;
1418 b3994ec5 2003-12-11 devnull l = left[i];
1419 b3994ec5 2003-12-11 devnull r = right[i];
1420 b3994ec5 2003-12-11 devnull /* try matching character to left, looking right */
1421 b3994ec5 2003-12-11 devnull if(q == 0)
1422 b3994ec5 2003-12-11 devnull c = '\n';
1423 b3994ec5 2003-12-11 devnull else
1424 b3994ec5 2003-12-11 devnull c = textreadc(t, q-1);
1425 b3994ec5 2003-12-11 devnull p = runestrchr(l, c);
1426 b3994ec5 2003-12-11 devnull if(p != nil){
1427 b3994ec5 2003-12-11 devnull if(textclickmatch(t, c, r[p-l], 1, &q))
1428 b3994ec5 2003-12-11 devnull *q1 = q-(c!='\n');
1429 b3994ec5 2003-12-11 devnull return;
1430 b3994ec5 2003-12-11 devnull }
1431 b3994ec5 2003-12-11 devnull /* try matching character to right, looking left */
1432 b3994ec5 2003-12-11 devnull if(q == t->file->b.nc)
1433 b3994ec5 2003-12-11 devnull c = '\n';
1434 b3994ec5 2003-12-11 devnull else
1435 b3994ec5 2003-12-11 devnull c = textreadc(t, q);
1436 b3994ec5 2003-12-11 devnull p = runestrchr(r, c);
1437 b3994ec5 2003-12-11 devnull if(p != nil){
1438 b3994ec5 2003-12-11 devnull if(textclickmatch(t, c, l[p-r], -1, &q)){
1439 b3994ec5 2003-12-11 devnull *q1 = *q0+(*q0<t->file->b.nc && c=='\n');
1440 b3994ec5 2003-12-11 devnull *q0 = q;
1441 b3994ec5 2003-12-11 devnull if(c!='\n' || q!=0 || textreadc(t, 0)=='\n')
1442 b3994ec5 2003-12-11 devnull (*q0)++;
1443 b3994ec5 2003-12-11 devnull }
1444 b3994ec5 2003-12-11 devnull return;
1445 b3994ec5 2003-12-11 devnull }
1446 b3994ec5 2003-12-11 devnull }
1447 fa325e9b 2020-01-10 cross
1448 b3994ec5 2003-12-11 devnull /* try filling out word to right */
1449 b3994ec5 2003-12-11 devnull while(*q1<t->file->b.nc && isalnum(textreadc(t, *q1)))
1450 b3994ec5 2003-12-11 devnull (*q1)++;
1451 b3994ec5 2003-12-11 devnull /* try filling out word to left */
1452 b3994ec5 2003-12-11 devnull while(*q0>0 && isalnum(textreadc(t, *q0-1)))
1453 b3994ec5 2003-12-11 devnull (*q0)--;
1454 b3994ec5 2003-12-11 devnull }
1455 b3994ec5 2003-12-11 devnull
1456 b3994ec5 2003-12-11 devnull int
1457 b3994ec5 2003-12-11 devnull textclickmatch(Text *t, int cl, int cr, int dir, uint *q)
1458 b3994ec5 2003-12-11 devnull {
1459 b3994ec5 2003-12-11 devnull Rune c;
1460 b3994ec5 2003-12-11 devnull int nest;
1461 b3994ec5 2003-12-11 devnull
1462 b3994ec5 2003-12-11 devnull nest = 1;
1463 b3994ec5 2003-12-11 devnull for(;;){
1464 b3994ec5 2003-12-11 devnull if(dir > 0){
1465 b3994ec5 2003-12-11 devnull if(*q == t->file->b.nc)
1466 b3994ec5 2003-12-11 devnull break;
1467 b3994ec5 2003-12-11 devnull c = textreadc(t, *q);
1468 b3994ec5 2003-12-11 devnull (*q)++;
1469 b3994ec5 2003-12-11 devnull }else{
1470 b3994ec5 2003-12-11 devnull if(*q == 0)
1471 b3994ec5 2003-12-11 devnull break;
1472 b3994ec5 2003-12-11 devnull (*q)--;
1473 b3994ec5 2003-12-11 devnull c = textreadc(t, *q);
1474 b3994ec5 2003-12-11 devnull }
1475 b3994ec5 2003-12-11 devnull if(c == cr){
1476 b3994ec5 2003-12-11 devnull if(--nest==0)
1477 b3994ec5 2003-12-11 devnull return 1;
1478 b3994ec5 2003-12-11 devnull }else if(c == cl)
1479 b3994ec5 2003-12-11 devnull nest++;
1480 b3994ec5 2003-12-11 devnull }
1481 b3994ec5 2003-12-11 devnull return cl=='\n' && nest==1;
1482 e47d0a1e 2009-07-26 rsc }
1483 e47d0a1e 2009-07-26 rsc
1484 e47d0a1e 2009-07-26 rsc // Is the text starting at location q an html tag?
1485 e47d0a1e 2009-07-26 rsc // Return 1 for <a>, -1 for </a>, 0 for no tag or <a />.
1486 e47d0a1e 2009-07-26 rsc // Set *q1, if non-nil, to the location after the tag.
1487 e47d0a1e 2009-07-26 rsc static int
1488 e47d0a1e 2009-07-26 rsc ishtmlstart(Text *t, uint q, uint *q1)
1489 e47d0a1e 2009-07-26 rsc {
1490 e47d0a1e 2009-07-26 rsc int c, c1, c2;
1491 e47d0a1e 2009-07-26 rsc
1492 e47d0a1e 2009-07-26 rsc if(q+2 > t->file->b.nc)
1493 e47d0a1e 2009-07-26 rsc return 0;
1494 e47d0a1e 2009-07-26 rsc if(textreadc(t, q++) != '<')
1495 e47d0a1e 2009-07-26 rsc return 0;
1496 e47d0a1e 2009-07-26 rsc c = textreadc(t, q++);
1497 e47d0a1e 2009-07-26 rsc c1 = c;
1498 e47d0a1e 2009-07-26 rsc c2 = c;
1499 e47d0a1e 2009-07-26 rsc while(c != '>') {
1500 e47d0a1e 2009-07-26 rsc if(q >= t->file->b.nc)
1501 e47d0a1e 2009-07-26 rsc return 0;
1502 e47d0a1e 2009-07-26 rsc c2 = c;
1503 e47d0a1e 2009-07-26 rsc c = textreadc(t, q++);
1504 e47d0a1e 2009-07-26 rsc }
1505 e47d0a1e 2009-07-26 rsc if(q1)
1506 e47d0a1e 2009-07-26 rsc *q1 = q;
1507 e47d0a1e 2009-07-26 rsc if(c1 == '/') // closing tag
1508 e47d0a1e 2009-07-26 rsc return -1;
1509 e47d0a1e 2009-07-26 rsc if(c2 == '/' || c2 == '!') // open + close tag or comment
1510 e47d0a1e 2009-07-26 rsc return 0;
1511 e47d0a1e 2009-07-26 rsc return 1;
1512 e47d0a1e 2009-07-26 rsc }
1513 e47d0a1e 2009-07-26 rsc
1514 e47d0a1e 2009-07-26 rsc // Is the text ending at location q an html tag?
1515 e47d0a1e 2009-07-26 rsc // Return 1 for <a>, -1 for </a>, 0 for no tag or <a />.
1516 e47d0a1e 2009-07-26 rsc // Set *q0, if non-nil, to the start of the tag.
1517 e47d0a1e 2009-07-26 rsc static int
1518 e47d0a1e 2009-07-26 rsc ishtmlend(Text *t, uint q, uint *q0)
1519 e47d0a1e 2009-07-26 rsc {
1520 e47d0a1e 2009-07-26 rsc int c, c1, c2;
1521 fa325e9b 2020-01-10 cross
1522 e47d0a1e 2009-07-26 rsc if(q < 2)
1523 e47d0a1e 2009-07-26 rsc return 0;
1524 e47d0a1e 2009-07-26 rsc if(textreadc(t, --q) != '>')
1525 e47d0a1e 2009-07-26 rsc return 0;
1526 e47d0a1e 2009-07-26 rsc c = textreadc(t, --q);
1527 e47d0a1e 2009-07-26 rsc c1 = c;
1528 e47d0a1e 2009-07-26 rsc c2 = c;
1529 e47d0a1e 2009-07-26 rsc while(c != '<') {
1530 e47d0a1e 2009-07-26 rsc if(q == 0)
1531 e47d0a1e 2009-07-26 rsc return 0;
1532 e47d0a1e 2009-07-26 rsc c1 = c;
1533 e47d0a1e 2009-07-26 rsc c = textreadc(t, --q);
1534 e47d0a1e 2009-07-26 rsc }
1535 e47d0a1e 2009-07-26 rsc if(q0)
1536 e47d0a1e 2009-07-26 rsc *q0 = q;
1537 e47d0a1e 2009-07-26 rsc if(c1 == '/') // closing tag
1538 e47d0a1e 2009-07-26 rsc return -1;
1539 e47d0a1e 2009-07-26 rsc if(c2 == '/' || c2 == '!') // open + close tag or comment
1540 e47d0a1e 2009-07-26 rsc return 0;
1541 e47d0a1e 2009-07-26 rsc return 1;
1542 b3994ec5 2003-12-11 devnull }
1543 b3994ec5 2003-12-11 devnull
1544 e47d0a1e 2009-07-26 rsc int
1545 e47d0a1e 2009-07-26 rsc textclickhtmlmatch(Text *t, uint *q0, uint *q1)
1546 e47d0a1e 2009-07-26 rsc {
1547 e47d0a1e 2009-07-26 rsc int depth, n;
1548 e47d0a1e 2009-07-26 rsc uint q, nq;
1549 fa325e9b 2020-01-10 cross
1550 e47d0a1e 2009-07-26 rsc q = *q0;
1551 e47d0a1e 2009-07-26 rsc // after opening tag? scan forward for closing tag
1552 e47d0a1e 2009-07-26 rsc if(ishtmlend(t, q, nil) == 1) {
1553 e47d0a1e 2009-07-26 rsc depth = 1;
1554 e47d0a1e 2009-07-26 rsc while(q < t->file->b.nc) {
1555 e47d0a1e 2009-07-26 rsc n = ishtmlstart(t, q, &nq);
1556 e47d0a1e 2009-07-26 rsc if(n != 0) {
1557 e47d0a1e 2009-07-26 rsc depth += n;
1558 e47d0a1e 2009-07-26 rsc if(depth == 0) {
1559 e47d0a1e 2009-07-26 rsc *q1 = q;
1560 e47d0a1e 2009-07-26 rsc return 1;
1561 e47d0a1e 2009-07-26 rsc }
1562 e47d0a1e 2009-07-26 rsc q = nq;
1563 e47d0a1e 2009-07-26 rsc continue;
1564 e47d0a1e 2009-07-26 rsc }
1565 e47d0a1e 2009-07-26 rsc q++;
1566 e47d0a1e 2009-07-26 rsc }
1567 e47d0a1e 2009-07-26 rsc }
1568 e47d0a1e 2009-07-26 rsc
1569 e47d0a1e 2009-07-26 rsc // before closing tag? scan backward for opening tag
1570 e47d0a1e 2009-07-26 rsc if(ishtmlstart(t, q, nil) == -1) {
1571 e47d0a1e 2009-07-26 rsc depth = -1;
1572 e47d0a1e 2009-07-26 rsc while(q > 0) {
1573 e47d0a1e 2009-07-26 rsc n = ishtmlend(t, q, &nq);
1574 e47d0a1e 2009-07-26 rsc if(n != 0) {
1575 e47d0a1e 2009-07-26 rsc depth += n;
1576 e47d0a1e 2009-07-26 rsc if(depth == 0) {
1577 e47d0a1e 2009-07-26 rsc *q0 = q;
1578 e47d0a1e 2009-07-26 rsc return 1;
1579 e47d0a1e 2009-07-26 rsc }
1580 e47d0a1e 2009-07-26 rsc q = nq;
1581 e47d0a1e 2009-07-26 rsc continue;
1582 e47d0a1e 2009-07-26 rsc }
1583 e47d0a1e 2009-07-26 rsc q--;
1584 e47d0a1e 2009-07-26 rsc }
1585 e47d0a1e 2009-07-26 rsc }
1586 fa325e9b 2020-01-10 cross
1587 e47d0a1e 2009-07-26 rsc return 0;
1588 e47d0a1e 2009-07-26 rsc }
1589 e47d0a1e 2009-07-26 rsc
1590 b3994ec5 2003-12-11 devnull uint
1591 b3994ec5 2003-12-11 devnull textbacknl(Text *t, uint p, uint n)
1592 b3994ec5 2003-12-11 devnull {
1593 b3994ec5 2003-12-11 devnull int i, j;
1594 b3994ec5 2003-12-11 devnull
1595 b3994ec5 2003-12-11 devnull /* look for start of this line if n==0 */
1596 b3994ec5 2003-12-11 devnull if(n==0 && p>0 && textreadc(t, p-1)!='\n')
1597 b3994ec5 2003-12-11 devnull n = 1;
1598 b3994ec5 2003-12-11 devnull i = n;
1599 b3994ec5 2003-12-11 devnull while(i-->0 && p>0){
1600 b3994ec5 2003-12-11 devnull --p; /* it's at a newline now; back over it */
1601 b3994ec5 2003-12-11 devnull if(p == 0)
1602 b3994ec5 2003-12-11 devnull break;
1603 b3994ec5 2003-12-11 devnull /* at 128 chars, call it a line anyway */
1604 b3994ec5 2003-12-11 devnull for(j=128; --j>0 && p>0; p--)
1605 b3994ec5 2003-12-11 devnull if(textreadc(t, p-1)=='\n')
1606 b3994ec5 2003-12-11 devnull break;
1607 b3994ec5 2003-12-11 devnull }
1608 b3994ec5 2003-12-11 devnull return p;
1609 b3994ec5 2003-12-11 devnull }
1610 b3994ec5 2003-12-11 devnull
1611 b3994ec5 2003-12-11 devnull void
1612 b3994ec5 2003-12-11 devnull textsetorigin(Text *t, uint org, int exact)
1613 b3994ec5 2003-12-11 devnull {
1614 b3994ec5 2003-12-11 devnull int i, a, fixup;
1615 b3994ec5 2003-12-11 devnull Rune *r;
1616 b3994ec5 2003-12-11 devnull uint n;
1617 b3994ec5 2003-12-11 devnull
1618 3d6e5cb5 2017-11-02 rsc if(org>0 && !exact && textreadc(t, org-1) != '\n'){
1619 b3994ec5 2003-12-11 devnull /* org is an estimate of the char posn; find a newline */
1620 b3994ec5 2003-12-11 devnull /* don't try harder than 256 chars */
1621 b3994ec5 2003-12-11 devnull for(i=0; i<256 && org<t->file->b.nc; i++){
1622 b3994ec5 2003-12-11 devnull if(textreadc(t, org) == '\n'){
1623 b3994ec5 2003-12-11 devnull org++;
1624 b3994ec5 2003-12-11 devnull break;
1625 b3994ec5 2003-12-11 devnull }
1626 b3994ec5 2003-12-11 devnull org++;
1627 b3994ec5 2003-12-11 devnull }
1628 b3994ec5 2003-12-11 devnull }
1629 b3994ec5 2003-12-11 devnull a = org-t->org;
1630 b3994ec5 2003-12-11 devnull fixup = 0;
1631 b3994ec5 2003-12-11 devnull if(a>=0 && a<t->fr.nchars){
1632 b3994ec5 2003-12-11 devnull frdelete(&t->fr, 0, a);
1633 b3994ec5 2003-12-11 devnull fixup = 1; /* frdelete can leave end of last line in wrong selection mode; it doesn't know what follows */
1634 b3994ec5 2003-12-11 devnull }
1635 b3994ec5 2003-12-11 devnull else if(a<0 && -a<t->fr.nchars){
1636 b3994ec5 2003-12-11 devnull n = t->org - org;
1637 b3994ec5 2003-12-11 devnull r = runemalloc(n);
1638 b3994ec5 2003-12-11 devnull bufread(&t->file->b, org, r, n);
1639 b3994ec5 2003-12-11 devnull frinsert(&t->fr, r, r+n, 0);
1640 b3994ec5 2003-12-11 devnull free(r);
1641 b3994ec5 2003-12-11 devnull }else
1642 b3994ec5 2003-12-11 devnull frdelete(&t->fr, 0, t->fr.nchars);
1643 b3994ec5 2003-12-11 devnull t->org = org;
1644 b3994ec5 2003-12-11 devnull textfill(t);
1645 b3994ec5 2003-12-11 devnull textscrdraw(t);
1646 b3994ec5 2003-12-11 devnull textsetselect(t, t->q0, t->q1);
1647 b3994ec5 2003-12-11 devnull if(fixup && t->fr.p1 > t->fr.p0)
1648 b3994ec5 2003-12-11 devnull frdrawsel(&t->fr, frptofchar(&t->fr, t->fr.p1-1), t->fr.p1-1, t->fr.p1, 1);
1649 b3994ec5 2003-12-11 devnull }
1650 b3994ec5 2003-12-11 devnull
1651 b3994ec5 2003-12-11 devnull void
1652 b3994ec5 2003-12-11 devnull textreset(Text *t)
1653 b3994ec5 2003-12-11 devnull {
1654 b3994ec5 2003-12-11 devnull t->file->seq = 0;
1655 b3994ec5 2003-12-11 devnull t->eq0 = ~0;
1656 b3994ec5 2003-12-11 devnull /* do t->delete(0, t->nc, TRUE) without building backup stuff */
1657 b3994ec5 2003-12-11 devnull textsetselect(t, t->org, t->org);
1658 b3994ec5 2003-12-11 devnull frdelete(&t->fr, 0, t->fr.nchars);
1659 b3994ec5 2003-12-11 devnull t->org = 0;
1660 b3994ec5 2003-12-11 devnull t->q0 = 0;
1661 b3994ec5 2003-12-11 devnull t->q1 = 0;
1662 b3994ec5 2003-12-11 devnull filereset(t->file);
1663 b3994ec5 2003-12-11 devnull bufreset(&t->file->b);
1664 b3994ec5 2003-12-11 devnull }