1*7ab27030SDavid du Colombier #include <u.h>
2*7ab27030SDavid du Colombier #include <libc.h>
3*7ab27030SDavid du Colombier #include <draw.h>
4*7ab27030SDavid du Colombier #include <memdraw.h>
5*7ab27030SDavid du Colombier #include <thread.h>
6*7ab27030SDavid du Colombier #include <cursor.h>
7*7ab27030SDavid du Colombier #include <mouse.h>
8*7ab27030SDavid du Colombier #include <keyboard.h>
9*7ab27030SDavid du Colombier #include <frame.h>
10*7ab27030SDavid du Colombier #include <plumb.h>
11*7ab27030SDavid du Colombier #include <html.h>
12*7ab27030SDavid du Colombier #include "dat.h"
13*7ab27030SDavid du Colombier #include "fns.h"
14*7ab27030SDavid du Colombier
15*7ab27030SDavid du Colombier Image *tagcols[NCOL];
16*7ab27030SDavid du Colombier Image *textcols[NCOL];
17*7ab27030SDavid du Colombier
18*7ab27030SDavid du Colombier
19*7ab27030SDavid du Colombier void
textinit(Text * t,Image * b,Rectangle r,Font * f,Image * cols[NCOL])20*7ab27030SDavid du Colombier textinit(Text *t, Image *b, Rectangle r, Font *f, Image *cols[NCOL])
21*7ab27030SDavid du Colombier {
22*7ab27030SDavid du Colombier t->all = r;
23*7ab27030SDavid du Colombier t->scrollr = r;
24*7ab27030SDavid du Colombier t->scrollr.max.x = r.min.x+Scrollsize;
25*7ab27030SDavid du Colombier t->lastsr = ZR;
26*7ab27030SDavid du Colombier r.min.x += Scrollsize+Scrollgap;
27*7ab27030SDavid du Colombier t->rs.nr = 0;
28*7ab27030SDavid du Colombier memmove(t->Frame.cols, cols, sizeof t->Frame.cols);
29*7ab27030SDavid du Colombier textredraw(t, r, f, b);
30*7ab27030SDavid du Colombier }
31*7ab27030SDavid du Colombier
32*7ab27030SDavid du Colombier void
textredraw(Text * t,Rectangle r,Font * f,Image * b)33*7ab27030SDavid du Colombier textredraw(Text *t, Rectangle r, Font *f, Image *b)
34*7ab27030SDavid du Colombier {
35*7ab27030SDavid du Colombier Rectangle r1;
36*7ab27030SDavid du Colombier
37*7ab27030SDavid du Colombier frinit(t, r, f, b, t->Frame.cols);
38*7ab27030SDavid du Colombier r1 = t->r;
39*7ab27030SDavid du Colombier r1.min.x -= Scrollsize+Scrollgap; /* back fill to scroll bar */
40*7ab27030SDavid du Colombier draw(t->b, r1, t->cols[BACK], nil, ZP);
41*7ab27030SDavid du Colombier t->maxtab = Maxtab*stringwidth(f, "0");
42*7ab27030SDavid du Colombier textfill(t);
43*7ab27030SDavid du Colombier textsetselect(t, t->q0, t->q1);
44*7ab27030SDavid du Colombier }
45*7ab27030SDavid du Colombier
46*7ab27030SDavid du Colombier int
textresize(Text * t,Image * b,Rectangle r)47*7ab27030SDavid du Colombier textresize(Text *t, Image *b, Rectangle r)
48*7ab27030SDavid du Colombier {
49*7ab27030SDavid du Colombier if(Dy(r) > 0)
50*7ab27030SDavid du Colombier r.max.y -= Dy(r)%t->font->height;
51*7ab27030SDavid du Colombier else
52*7ab27030SDavid du Colombier r.max.y = r.min.y;
53*7ab27030SDavid du Colombier
54*7ab27030SDavid du Colombier t->all = r;
55*7ab27030SDavid du Colombier t->scrollr = r;
56*7ab27030SDavid du Colombier t->scrollr.max.x = r.min.x+Scrollsize;
57*7ab27030SDavid du Colombier t->lastsr = ZR;
58*7ab27030SDavid du Colombier r.min.x += Scrollsize+Scrollgap;
59*7ab27030SDavid du Colombier frclear(t, 0);
60*7ab27030SDavid du Colombier textredraw(t, r, t->font, b);
61*7ab27030SDavid du Colombier if(t->what == Textarea)
62*7ab27030SDavid du Colombier textscrdraw(t);
63*7ab27030SDavid du Colombier return r.max.y;
64*7ab27030SDavid du Colombier }
65*7ab27030SDavid du Colombier
66*7ab27030SDavid du Colombier void
textclose(Text * t)67*7ab27030SDavid du Colombier textclose(Text *t)
68*7ab27030SDavid du Colombier {
69*7ab27030SDavid du Colombier closerunestr(&t->rs);
70*7ab27030SDavid du Colombier frclear(t, 1);
71*7ab27030SDavid du Colombier }
72*7ab27030SDavid du Colombier
73*7ab27030SDavid du Colombier void
textinsert(Text * t,uint q0,Rune * r,uint n)74*7ab27030SDavid du Colombier textinsert(Text *t, uint q0, Rune *r, uint n)
75*7ab27030SDavid du Colombier {
76*7ab27030SDavid du Colombier if(n == 0)
77*7ab27030SDavid du Colombier return;
78*7ab27030SDavid du Colombier
79*7ab27030SDavid du Colombier t->rs.r = runerealloc(t->rs.r, t->rs.nr+n);
80*7ab27030SDavid du Colombier runemove(t->rs.r+q0+n, t->rs.r+q0, t->rs.nr-q0);
81*7ab27030SDavid du Colombier runemove(t->rs.r+q0, r, n);
82*7ab27030SDavid du Colombier t->rs.nr += n;
83*7ab27030SDavid du Colombier if(q0 < t->q1)
84*7ab27030SDavid du Colombier t->q1 += n;
85*7ab27030SDavid du Colombier if(q0 < t->q0)
86*7ab27030SDavid du Colombier t->q0 += n;
87*7ab27030SDavid du Colombier if(q0 < t->org)
88*7ab27030SDavid du Colombier t->org += n;
89*7ab27030SDavid du Colombier else if(q0 <= t->org+t->nchars)
90*7ab27030SDavid du Colombier frinsert(t, r, r+n, q0-t->org);
91*7ab27030SDavid du Colombier }
92*7ab27030SDavid du Colombier
93*7ab27030SDavid du Colombier void
textfill(Text * t)94*7ab27030SDavid du Colombier textfill(Text *t)
95*7ab27030SDavid du Colombier {
96*7ab27030SDavid du Colombier Rune *rp;
97*7ab27030SDavid du Colombier int i, n, m, nl;
98*7ab27030SDavid du Colombier
99*7ab27030SDavid du Colombier if(t->lastlinefull)
100*7ab27030SDavid du Colombier return;
101*7ab27030SDavid du Colombier rp = runemalloc(BUFSIZE*8);
102*7ab27030SDavid du Colombier do{
103*7ab27030SDavid du Colombier n = t->rs.nr-(t->org+t->nchars);
104*7ab27030SDavid du Colombier if(n == 0)
105*7ab27030SDavid du Colombier break;
106*7ab27030SDavid du Colombier if(n > 2000) /* educated guess at reasonable amount */
107*7ab27030SDavid du Colombier n = 2000;
108*7ab27030SDavid du Colombier runemove(rp, t->rs.r+(t->org+t->nchars), n);
109*7ab27030SDavid du Colombier /*
110*7ab27030SDavid du Colombier * it's expensive to frinsert more than we need, so
111*7ab27030SDavid du Colombier * count newlines.
112*7ab27030SDavid du Colombier */
113*7ab27030SDavid du Colombier nl = t->maxlines-t->nlines;
114*7ab27030SDavid du Colombier m = 0;
115*7ab27030SDavid du Colombier for(i=0; i<n; ){
116*7ab27030SDavid du Colombier if(rp[i++] == '\n'){
117*7ab27030SDavid du Colombier m++;
118*7ab27030SDavid du Colombier if(m >= nl)
119*7ab27030SDavid du Colombier break;
120*7ab27030SDavid du Colombier }
121*7ab27030SDavid du Colombier }
122*7ab27030SDavid du Colombier frinsert(t, rp, rp+i, t->nchars);
123*7ab27030SDavid du Colombier }while(t->lastlinefull == FALSE);
124*7ab27030SDavid du Colombier free(rp);
125*7ab27030SDavid du Colombier }
126*7ab27030SDavid du Colombier
127*7ab27030SDavid du Colombier void
textdelete(Text * t,uint q0,uint q1)128*7ab27030SDavid du Colombier textdelete(Text *t, uint q0, uint q1)
129*7ab27030SDavid du Colombier {
130*7ab27030SDavid du Colombier uint n, p0, p1;
131*7ab27030SDavid du Colombier
132*7ab27030SDavid du Colombier n = q1-q0;
133*7ab27030SDavid du Colombier if(n == 0)
134*7ab27030SDavid du Colombier return;
135*7ab27030SDavid du Colombier
136*7ab27030SDavid du Colombier runemove(t->rs.r+q0, t->rs.r+q1, t->rs.nr-q1);
137*7ab27030SDavid du Colombier t->rs.nr -= n;
138*7ab27030SDavid du Colombier if(q0 < t->q0)
139*7ab27030SDavid du Colombier t->q0 -= min(n, t->q0-q0);
140*7ab27030SDavid du Colombier if(q0 < t->q1)
141*7ab27030SDavid du Colombier t->q1 -= min(n, t->q1-q0);
142*7ab27030SDavid du Colombier if(q1 <= t->org)
143*7ab27030SDavid du Colombier t->org -= n;
144*7ab27030SDavid du Colombier else if(q0 < t->org+t->nchars){
145*7ab27030SDavid du Colombier p1 = q1 - t->org;
146*7ab27030SDavid du Colombier if(p1 > t->nchars)
147*7ab27030SDavid du Colombier p1 = t->nchars;
148*7ab27030SDavid du Colombier if(q0 < t->org){
149*7ab27030SDavid du Colombier t->org = q0;
150*7ab27030SDavid du Colombier p0 = 0;
151*7ab27030SDavid du Colombier }else
152*7ab27030SDavid du Colombier p0 = q0 - t->org;
153*7ab27030SDavid du Colombier frdelete(t, p0, p1);
154*7ab27030SDavid du Colombier textfill(t);
155*7ab27030SDavid du Colombier }
156*7ab27030SDavid du Colombier t->rs.r[t->rs.nr] = L'\0';
157*7ab27030SDavid du Colombier }
158*7ab27030SDavid du Colombier
159*7ab27030SDavid du Colombier int
textbswidth(Text * t,Rune c)160*7ab27030SDavid du Colombier textbswidth(Text *t, Rune c)
161*7ab27030SDavid du Colombier {
162*7ab27030SDavid du Colombier uint q, eq;
163*7ab27030SDavid du Colombier Rune r;
164*7ab27030SDavid du Colombier int skipping;
165*7ab27030SDavid du Colombier
166*7ab27030SDavid du Colombier /* there is known to be at least one character to erase */
167*7ab27030SDavid du Colombier if(c == 0x08) /* ^H: erase character */
168*7ab27030SDavid du Colombier return 1;
169*7ab27030SDavid du Colombier q = t->q0;
170*7ab27030SDavid du Colombier skipping = TRUE;
171*7ab27030SDavid du Colombier while(q > 0){
172*7ab27030SDavid du Colombier r = t->rs.r[q-1];
173*7ab27030SDavid du Colombier if(r == '\n'){ /* eat at most one more character */
174*7ab27030SDavid du Colombier if(q == t->q0) /* eat the newline */
175*7ab27030SDavid du Colombier --q;
176*7ab27030SDavid du Colombier break;
177*7ab27030SDavid du Colombier }
178*7ab27030SDavid du Colombier if(c == 0x17){
179*7ab27030SDavid du Colombier eq = isalnum(r);
180*7ab27030SDavid du Colombier if(eq && skipping) /* found one; stop skipping */
181*7ab27030SDavid du Colombier skipping = FALSE;
182*7ab27030SDavid du Colombier else if(!eq && !skipping)
183*7ab27030SDavid du Colombier break;
184*7ab27030SDavid du Colombier }
185*7ab27030SDavid du Colombier --q;
186*7ab27030SDavid du Colombier }
187*7ab27030SDavid du Colombier return t->q0-q;
188*7ab27030SDavid du Colombier }
189*7ab27030SDavid du Colombier
190*7ab27030SDavid du Colombier void
texttype(Text * t,Rune r)191*7ab27030SDavid du Colombier texttype(Text *t, Rune r)
192*7ab27030SDavid du Colombier {
193*7ab27030SDavid du Colombier uint q0, q1;
194*7ab27030SDavid du Colombier int nb, n;
195*7ab27030SDavid du Colombier int nr;
196*7ab27030SDavid du Colombier Rune *rp;
197*7ab27030SDavid du Colombier
198*7ab27030SDavid du Colombier if(t->what!=Textarea && r=='\n'){
199*7ab27030SDavid du Colombier if(t->what==Urltag)
200*7ab27030SDavid du Colombier get(t, t, XXX, XXX, nil, 0);
201*7ab27030SDavid du Colombier return;
202*7ab27030SDavid du Colombier }
203*7ab27030SDavid du Colombier if(t->what==Tag && (r==Kscrollonedown || r==Kscrolloneup))
204*7ab27030SDavid du Colombier return;
205*7ab27030SDavid du Colombier
206*7ab27030SDavid du Colombier nr = 1;
207*7ab27030SDavid du Colombier rp = &r;
208*7ab27030SDavid du Colombier switch(r){
209*7ab27030SDavid du Colombier case Kleft:
210*7ab27030SDavid du Colombier if(t->q0 > 0)
211*7ab27030SDavid du Colombier textshow(t, t->q0-1, t->q0-1, TRUE);
212*7ab27030SDavid du Colombier return;
213*7ab27030SDavid du Colombier case Kright:
214*7ab27030SDavid du Colombier if(t->q1 < t->rs.nr)
215*7ab27030SDavid du Colombier textshow(t, t->q1+1, t->q1+1, TRUE);
216*7ab27030SDavid du Colombier return;
217*7ab27030SDavid du Colombier case Kdown:
218*7ab27030SDavid du Colombier n = t->maxlines/3;
219*7ab27030SDavid du Colombier goto case_Down;
220*7ab27030SDavid du Colombier case Kscrollonedown:
221*7ab27030SDavid du Colombier n = mousescrollsize(t->maxlines);
222*7ab27030SDavid du Colombier if(n <= 0)
223*7ab27030SDavid du Colombier n = 1;
224*7ab27030SDavid du Colombier goto case_Down;
225*7ab27030SDavid du Colombier case Kpgdown:
226*7ab27030SDavid du Colombier n = 2*t->maxlines/3;
227*7ab27030SDavid du Colombier case_Down:
228*7ab27030SDavid du Colombier q0 = t->org+frcharofpt(t, Pt(t->r.min.x, t->r.min.y+n*t->font->height));
229*7ab27030SDavid du Colombier textsetorigin(t, q0, TRUE);
230*7ab27030SDavid du Colombier return;
231*7ab27030SDavid du Colombier case Kup:
232*7ab27030SDavid du Colombier n = t->maxlines/3;
233*7ab27030SDavid du Colombier goto case_Up;
234*7ab27030SDavid du Colombier case Kscrolloneup:
235*7ab27030SDavid du Colombier n = mousescrollsize(t->maxlines);
236*7ab27030SDavid du Colombier goto case_Up;
237*7ab27030SDavid du Colombier case Kpgup:
238*7ab27030SDavid du Colombier n = 2*t->maxlines/3;
239*7ab27030SDavid du Colombier case_Up:
240*7ab27030SDavid du Colombier q0 = textbacknl(t, t->org, n);
241*7ab27030SDavid du Colombier textsetorigin(t, q0, TRUE);
242*7ab27030SDavid du Colombier return;
243*7ab27030SDavid du Colombier case Khome:
244*7ab27030SDavid du Colombier textshow(t, 0, 0, FALSE);
245*7ab27030SDavid du Colombier return;
246*7ab27030SDavid du Colombier case Kend:
247*7ab27030SDavid du Colombier textshow(t, t->rs.nr, t->rs.nr, FALSE);
248*7ab27030SDavid du Colombier return;
249*7ab27030SDavid du Colombier case 0x01: /* ^A: beginning of line */
250*7ab27030SDavid du Colombier /* go to where ^U would erase, if not already at BOL */
251*7ab27030SDavid du Colombier nb = 0;
252*7ab27030SDavid du Colombier if(t->q0>0 && t->rs.r[t->q0-1]!='\n')
253*7ab27030SDavid du Colombier nb = textbswidth(t, 0x15);
254*7ab27030SDavid du Colombier textshow(t, t->q0-nb, t->q0-nb, TRUE);
255*7ab27030SDavid du Colombier return;
256*7ab27030SDavid du Colombier case 0x05: /* ^E: end of line */
257*7ab27030SDavid du Colombier q0 = t->q0;
258*7ab27030SDavid du Colombier while(q0<t->rs.nr && t->rs.r[q0]!='\n')
259*7ab27030SDavid du Colombier q0++;
260*7ab27030SDavid du Colombier textshow(t, q0, q0, TRUE);
261*7ab27030SDavid du Colombier return;
262*7ab27030SDavid du Colombier }
263*7ab27030SDavid du Colombier if(t->q1 > t->q0)
264*7ab27030SDavid du Colombier cut(t, t, TRUE, TRUE, nil, 0);
265*7ab27030SDavid du Colombier
266*7ab27030SDavid du Colombier textshow(t, t->q0, t->q0, TRUE);
267*7ab27030SDavid du Colombier switch(r){
268*7ab27030SDavid du Colombier case 0x08: /* ^H: erase character */
269*7ab27030SDavid du Colombier case 0x15: /* ^U: erase line */
270*7ab27030SDavid du Colombier case 0x17: /* ^W: erase word */
271*7ab27030SDavid du Colombier if(t->q0 == 0) /* nothing to erase */
272*7ab27030SDavid du Colombier return;
273*7ab27030SDavid du Colombier nb = textbswidth(t, r);
274*7ab27030SDavid du Colombier q1 = t->q0;
275*7ab27030SDavid du Colombier q0 = q1-nb;
276*7ab27030SDavid du Colombier /* if selection is at beginning of window, avoid deleting invisible text */
277*7ab27030SDavid du Colombier if(q0 < t->org){
278*7ab27030SDavid du Colombier q0 = t->org;
279*7ab27030SDavid du Colombier nb = q1-q0;
280*7ab27030SDavid du Colombier }
281*7ab27030SDavid du Colombier if(nb > 0){
282*7ab27030SDavid du Colombier textdelete(t, q0, q0+nb);
283*7ab27030SDavid du Colombier textsetselect(t, q0, q0);
284*7ab27030SDavid du Colombier }
285*7ab27030SDavid du Colombier return;
286*7ab27030SDavid du Colombier }
287*7ab27030SDavid du Colombier /* otherwise ordinary character; just insert */
288*7ab27030SDavid du Colombier textinsert(t, t->q0, &r, 1);
289*7ab27030SDavid du Colombier if(rp != &r)
290*7ab27030SDavid du Colombier free(rp);
291*7ab27030SDavid du Colombier textsetselect(t, t->q0+nr, t->q0+nr);
292*7ab27030SDavid du Colombier if(t->what == Textarea)
293*7ab27030SDavid du Colombier textscrdraw(t);
294*7ab27030SDavid du Colombier }
295*7ab27030SDavid du Colombier
296*7ab27030SDavid du Colombier static Text *clicktext;
297*7ab27030SDavid du Colombier static uint clickmsec;
298*7ab27030SDavid du Colombier static Text *selecttext;
299*7ab27030SDavid du Colombier static uint selectq;
300*7ab27030SDavid du Colombier
301*7ab27030SDavid du Colombier /*
302*7ab27030SDavid du Colombier * called from frame library
303*7ab27030SDavid du Colombier */
304*7ab27030SDavid du Colombier void
framescroll(Frame * f,int dl)305*7ab27030SDavid du Colombier framescroll(Frame *f, int dl)
306*7ab27030SDavid du Colombier {
307*7ab27030SDavid du Colombier if(f != &selecttext->Frame)
308*7ab27030SDavid du Colombier error("frameselect not right frame");
309*7ab27030SDavid du Colombier textframescroll(selecttext, dl);
310*7ab27030SDavid du Colombier }
311*7ab27030SDavid du Colombier
312*7ab27030SDavid du Colombier void
textframescroll(Text * t,int dl)313*7ab27030SDavid du Colombier textframescroll(Text *t, int dl)
314*7ab27030SDavid du Colombier {
315*7ab27030SDavid du Colombier uint q0;
316*7ab27030SDavid du Colombier
317*7ab27030SDavid du Colombier if(dl == 0){
318*7ab27030SDavid du Colombier scrsleep(100);
319*7ab27030SDavid du Colombier return;
320*7ab27030SDavid du Colombier }
321*7ab27030SDavid du Colombier if(dl < 0){
322*7ab27030SDavid du Colombier q0 = textbacknl(t, t->org, -dl);
323*7ab27030SDavid du Colombier if(selectq > t->org+t->p0)
324*7ab27030SDavid du Colombier textsetselect(t, t->org+t->p0, selectq);
325*7ab27030SDavid du Colombier else
326*7ab27030SDavid du Colombier textsetselect(t, selectq, t->org+t->p0);
327*7ab27030SDavid du Colombier }else{
328*7ab27030SDavid du Colombier if(t->org+t->nchars == t->rs.nr)
329*7ab27030SDavid du Colombier return;
330*7ab27030SDavid du Colombier q0 = t->org+frcharofpt(t, Pt(t->r.min.x, t->r.min.y+dl*t->font->height));
331*7ab27030SDavid du Colombier if(selectq > t->org+t->p1)
332*7ab27030SDavid du Colombier textsetselect(t, t->org+t->p1, selectq);
333*7ab27030SDavid du Colombier else
334*7ab27030SDavid du Colombier textsetselect(t, selectq, t->org+t->p1);
335*7ab27030SDavid du Colombier }
336*7ab27030SDavid du Colombier textsetorigin(t, q0, TRUE);
337*7ab27030SDavid du Colombier }
338*7ab27030SDavid du Colombier
339*7ab27030SDavid du Colombier void
textselect(Text * t)340*7ab27030SDavid du Colombier textselect(Text *t)
341*7ab27030SDavid du Colombier {
342*7ab27030SDavid du Colombier uint q0, q1;
343*7ab27030SDavid du Colombier int b, x, y;
344*7ab27030SDavid du Colombier int state;
345*7ab27030SDavid du Colombier
346*7ab27030SDavid du Colombier selecttext = t;
347*7ab27030SDavid du Colombier /*
348*7ab27030SDavid du Colombier * To have double-clicking and chording, we double-click
349*7ab27030SDavid du Colombier * immediately if it might make sense.
350*7ab27030SDavid du Colombier */
351*7ab27030SDavid du Colombier b = mouse->buttons;
352*7ab27030SDavid du Colombier q0 = t->q0;
353*7ab27030SDavid du Colombier q1 = t->q1;
354*7ab27030SDavid du Colombier selectq = t->org+frcharofpt(t, mouse->xy);
355*7ab27030SDavid du Colombier if(clicktext==t && mouse->msec-clickmsec<500)
356*7ab27030SDavid du Colombier if(q0==q1 && selectq==q0){
357*7ab27030SDavid du Colombier textdoubleclick(t, &q0, &q1);
358*7ab27030SDavid du Colombier textsetselect(t, q0, q1);
359*7ab27030SDavid du Colombier flushimage(display, 1);
360*7ab27030SDavid du Colombier x = mouse->xy.x;
361*7ab27030SDavid du Colombier y = mouse->xy.y;
362*7ab27030SDavid du Colombier /* stay here until something interesting happens */
363*7ab27030SDavid du Colombier do
364*7ab27030SDavid du Colombier readmouse(mousectl);
365*7ab27030SDavid du Colombier while(mouse->buttons==b && abs(mouse->xy.x-x)<3 && abs(mouse->xy.y-y)<3);
366*7ab27030SDavid du Colombier mouse->xy.x = x; /* in case we're calling frselect */
367*7ab27030SDavid du Colombier mouse->xy.y = y;
368*7ab27030SDavid du Colombier q0 = t->q0; /* may have changed */
369*7ab27030SDavid du Colombier q1 = t->q1;
370*7ab27030SDavid du Colombier selectq = q0;
371*7ab27030SDavid du Colombier }
372*7ab27030SDavid du Colombier if(mouse->buttons == b){
373*7ab27030SDavid du Colombier t->Frame.scroll = framescroll;
374*7ab27030SDavid du Colombier frselect(t, mousectl);
375*7ab27030SDavid du Colombier /* horrible botch: while asleep, may have lost selection altogether */
376*7ab27030SDavid du Colombier if(selectq > t->rs.nr)
377*7ab27030SDavid du Colombier selectq = t->org + t->p0;
378*7ab27030SDavid du Colombier t->Frame.scroll = nil;
379*7ab27030SDavid du Colombier if(selectq < t->org)
380*7ab27030SDavid du Colombier q0 = selectq;
381*7ab27030SDavid du Colombier else
382*7ab27030SDavid du Colombier q0 = t->org + t->p0;
383*7ab27030SDavid du Colombier if(selectq > t->org+t->nchars)
384*7ab27030SDavid du Colombier q1 = selectq;
385*7ab27030SDavid du Colombier else
386*7ab27030SDavid du Colombier q1 = t->org+t->p1;
387*7ab27030SDavid du Colombier }
388*7ab27030SDavid du Colombier if(q0 == q1){
389*7ab27030SDavid du Colombier if(q0==t->q0 && clicktext==t && mouse->msec-clickmsec<500){
390*7ab27030SDavid du Colombier textdoubleclick(t, &q0, &q1);
391*7ab27030SDavid du Colombier clicktext = nil;
392*7ab27030SDavid du Colombier }else{
393*7ab27030SDavid du Colombier clicktext = t;
394*7ab27030SDavid du Colombier clickmsec = mouse->msec;
395*7ab27030SDavid du Colombier }
396*7ab27030SDavid du Colombier }else
397*7ab27030SDavid du Colombier clicktext = nil;
398*7ab27030SDavid du Colombier textsetselect(t, q0, q1);
399*7ab27030SDavid du Colombier flushimage(display, 1);
400*7ab27030SDavid du Colombier state = 0; /* undo when possible; +1 for cut, -1 for paste */
401*7ab27030SDavid du Colombier while(mouse->buttons){
402*7ab27030SDavid du Colombier mouse->msec = 0;
403*7ab27030SDavid du Colombier b = mouse->buttons;
404*7ab27030SDavid du Colombier if((b&1) && (b&6)){
405*7ab27030SDavid du Colombier if(b & 2){
406*7ab27030SDavid du Colombier if(state==-1 && t->what==Textarea){
407*7ab27030SDavid du Colombier textsetselect(t, q0, t->q0);
408*7ab27030SDavid du Colombier state = 0;
409*7ab27030SDavid du Colombier }else if(state != 1){
410*7ab27030SDavid du Colombier cut(t, t, TRUE, TRUE, nil, 0);
411*7ab27030SDavid du Colombier state = 1;
412*7ab27030SDavid du Colombier }
413*7ab27030SDavid du Colombier }else{
414*7ab27030SDavid du Colombier if(state==1 && t->what==Textarea){
415*7ab27030SDavid du Colombier textsetselect(t, q0, t->q1);
416*7ab27030SDavid du Colombier state = 0;
417*7ab27030SDavid du Colombier }else if(state != -1){
418*7ab27030SDavid du Colombier paste(t, t, TRUE, FALSE, nil, 0);
419*7ab27030SDavid du Colombier state = -1;
420*7ab27030SDavid du Colombier }
421*7ab27030SDavid du Colombier }
422*7ab27030SDavid du Colombier textscrdraw(t);
423*7ab27030SDavid du Colombier }
424*7ab27030SDavid du Colombier flushimage(display, 1);
425*7ab27030SDavid du Colombier while(mouse->buttons == b)
426*7ab27030SDavid du Colombier readmouse(mousectl);
427*7ab27030SDavid du Colombier clicktext = nil;
428*7ab27030SDavid du Colombier }
429*7ab27030SDavid du Colombier }
430*7ab27030SDavid du Colombier
431*7ab27030SDavid du Colombier void
textshow(Text * t,uint q0,uint q1,int doselect)432*7ab27030SDavid du Colombier textshow(Text *t, uint q0, uint q1, int doselect)
433*7ab27030SDavid du Colombier {
434*7ab27030SDavid du Colombier int qe;
435*7ab27030SDavid du Colombier int nl;
436*7ab27030SDavid du Colombier uint q;
437*7ab27030SDavid du Colombier
438*7ab27030SDavid du Colombier if(t->what != Textarea){
439*7ab27030SDavid du Colombier if(doselect)
440*7ab27030SDavid du Colombier textsetselect(t, q0, q1);
441*7ab27030SDavid du Colombier return;
442*7ab27030SDavid du Colombier }
443*7ab27030SDavid du Colombier if(doselect)
444*7ab27030SDavid du Colombier textsetselect(t, q0, q1);
445*7ab27030SDavid du Colombier qe = t->org+t->nchars;
446*7ab27030SDavid du Colombier if(t->org<=q0 && (q0<qe || (q0==qe && qe==t->rs.nr)))
447*7ab27030SDavid du Colombier textscrdraw(t);
448*7ab27030SDavid du Colombier else{
449*7ab27030SDavid du Colombier nl = t->maxlines/4;
450*7ab27030SDavid du Colombier q = textbacknl(t, q0, nl);
451*7ab27030SDavid du Colombier /* avoid going backwards if trying to go forwards - long lines! */
452*7ab27030SDavid du Colombier if(!(q0>t->org && q<t->org))
453*7ab27030SDavid du Colombier textsetorigin(t, q, TRUE);
454*7ab27030SDavid du Colombier while(q0 > t->org+t->nchars)
455*7ab27030SDavid du Colombier textsetorigin(t, t->org+1, FALSE);
456*7ab27030SDavid du Colombier }
457*7ab27030SDavid du Colombier }
458*7ab27030SDavid du Colombier
459*7ab27030SDavid du Colombier static
460*7ab27030SDavid du Colombier int
region(int a,int b)461*7ab27030SDavid du Colombier region(int a, int b)
462*7ab27030SDavid du Colombier {
463*7ab27030SDavid du Colombier if(a < b)
464*7ab27030SDavid du Colombier return -1;
465*7ab27030SDavid du Colombier if(a == b)
466*7ab27030SDavid du Colombier return 0;
467*7ab27030SDavid du Colombier return 1;
468*7ab27030SDavid du Colombier }
469*7ab27030SDavid du Colombier
470*7ab27030SDavid du Colombier void
selrestore(Frame * f,Point pt0,uint p0,uint p1)471*7ab27030SDavid du Colombier selrestore(Frame *f, Point pt0, uint p0, uint p1)
472*7ab27030SDavid du Colombier {
473*7ab27030SDavid du Colombier if(p1<=f->p0 || p0>=f->p1){
474*7ab27030SDavid du Colombier /* no overlap */
475*7ab27030SDavid du Colombier frdrawsel0(f, pt0, p0, p1, f->cols[BACK], f->cols[TEXT]);
476*7ab27030SDavid du Colombier return;
477*7ab27030SDavid du Colombier }
478*7ab27030SDavid du Colombier if(p0>=f->p0 && p1<=f->p1){
479*7ab27030SDavid du Colombier /* entirely inside */
480*7ab27030SDavid du Colombier frdrawsel0(f, pt0, p0, p1, f->cols[HIGH], f->cols[HTEXT]);
481*7ab27030SDavid du Colombier return;
482*7ab27030SDavid du Colombier }
483*7ab27030SDavid du Colombier
484*7ab27030SDavid du Colombier /* they now are known to overlap */
485*7ab27030SDavid du Colombier
486*7ab27030SDavid du Colombier /* before selection */
487*7ab27030SDavid du Colombier if(p0 < f->p0){
488*7ab27030SDavid du Colombier frdrawsel0(f, pt0, p0, f->p0, f->cols[BACK], f->cols[TEXT]);
489*7ab27030SDavid du Colombier p0 = f->p0;
490*7ab27030SDavid du Colombier pt0 = frptofchar(f, p0);
491*7ab27030SDavid du Colombier }
492*7ab27030SDavid du Colombier /* after selection */
493*7ab27030SDavid du Colombier if(p1 > f->p1){
494*7ab27030SDavid du Colombier frdrawsel0(f, frptofchar(f, f->p1), f->p1, p1, f->cols[BACK], f->cols[TEXT]);
495*7ab27030SDavid du Colombier p1 = f->p1;
496*7ab27030SDavid du Colombier }
497*7ab27030SDavid du Colombier /* inside selection */
498*7ab27030SDavid du Colombier frdrawsel0(f, pt0, p0, p1, f->cols[HIGH], f->cols[HTEXT]);
499*7ab27030SDavid du Colombier }
500*7ab27030SDavid du Colombier
501*7ab27030SDavid du Colombier void
textsetselect(Text * t,uint q0,uint q1)502*7ab27030SDavid du Colombier textsetselect(Text *t, uint q0, uint q1)
503*7ab27030SDavid du Colombier {
504*7ab27030SDavid du Colombier int p0, p1;
505*7ab27030SDavid du Colombier
506*7ab27030SDavid du Colombier /* t->p0 and t->p1 are always right; t->q0 and t->q1 may be off */
507*7ab27030SDavid du Colombier t->q0 = q0;
508*7ab27030SDavid du Colombier t->q1 = q1;
509*7ab27030SDavid du Colombier /* compute desired p0,p1 from q0,q1 */
510*7ab27030SDavid du Colombier p0 = q0-t->org;
511*7ab27030SDavid du Colombier p1 = q1-t->org;
512*7ab27030SDavid du Colombier if(p0 < 0)
513*7ab27030SDavid du Colombier p0 = 0;
514*7ab27030SDavid du Colombier if(p1 < 0)
515*7ab27030SDavid du Colombier p1 = 0;
516*7ab27030SDavid du Colombier if(p0 > t->nchars)
517*7ab27030SDavid du Colombier p0 = t->nchars;
518*7ab27030SDavid du Colombier if(p1 > t->nchars)
519*7ab27030SDavid du Colombier p1 = t->nchars;
520*7ab27030SDavid du Colombier if(p0==t->p0 && p1==t->p1)
521*7ab27030SDavid du Colombier return;
522*7ab27030SDavid du Colombier /* screen disagrees with desired selection */
523*7ab27030SDavid du Colombier if(t->p1<=p0 || p1<=t->p0 || p0==p1 || t->p1==t->p0){
524*7ab27030SDavid du Colombier /* no overlap or too easy to bother trying */
525*7ab27030SDavid du Colombier frdrawsel(t, frptofchar(t, t->p0), t->p0, t->p1, 0);
526*7ab27030SDavid du Colombier frdrawsel(t, frptofchar(t, p0), p0, p1, 1);
527*7ab27030SDavid du Colombier goto Return;
528*7ab27030SDavid du Colombier }
529*7ab27030SDavid du Colombier /* overlap; avoid unnecessary painting */
530*7ab27030SDavid du Colombier if(p0 < t->p0){
531*7ab27030SDavid du Colombier /* extend selection backwards */
532*7ab27030SDavid du Colombier frdrawsel(t, frptofchar(t, p0), p0, t->p0, 1);
533*7ab27030SDavid du Colombier }else if(p0 > t->p0){
534*7ab27030SDavid du Colombier /* trim first part of selection */
535*7ab27030SDavid du Colombier frdrawsel(t, frptofchar(t, t->p0), t->p0, p0, 0);
536*7ab27030SDavid du Colombier }
537*7ab27030SDavid du Colombier if(p1 > t->p1){
538*7ab27030SDavid du Colombier /* extend selection forwards */
539*7ab27030SDavid du Colombier frdrawsel(t, frptofchar(t, t->p1), t->p1, p1, 1);
540*7ab27030SDavid du Colombier }else if(p1 < t->p1){
541*7ab27030SDavid du Colombier /* trim last part of selection */
542*7ab27030SDavid du Colombier frdrawsel(t, frptofchar(t, p1), p1, t->p1, 0);
543*7ab27030SDavid du Colombier }
544*7ab27030SDavid du Colombier
545*7ab27030SDavid du Colombier Return:
546*7ab27030SDavid du Colombier t->p0 = p0;
547*7ab27030SDavid du Colombier t->p1 = p1;
548*7ab27030SDavid du Colombier }
549*7ab27030SDavid du Colombier
550*7ab27030SDavid du Colombier
551*7ab27030SDavid du Colombier /*
552*7ab27030SDavid du Colombier * Release the button in less than DELAY ms and it's considered a null selection
553*7ab27030SDavid du Colombier * if the mouse hardly moved, regardless of whether it crossed a char boundary.
554*7ab27030SDavid du Colombier */
555*7ab27030SDavid du Colombier enum {
556*7ab27030SDavid du Colombier DELAY = 2,
557*7ab27030SDavid du Colombier MINMOVE = 4,
558*7ab27030SDavid du Colombier };
559*7ab27030SDavid du Colombier
560*7ab27030SDavid du Colombier uint
xselect(Frame * f,Mousectl * mc,Image * col,uint * p1p)561*7ab27030SDavid du Colombier xselect(Frame *f, Mousectl *mc, Image *col, uint *p1p) /* when called, button is down */
562*7ab27030SDavid du Colombier {
563*7ab27030SDavid du Colombier uint p0, p1, q, tmp;
564*7ab27030SDavid du Colombier ulong msec;
565*7ab27030SDavid du Colombier Point mp, pt0, pt1, qt;
566*7ab27030SDavid du Colombier int reg, b;
567*7ab27030SDavid du Colombier
568*7ab27030SDavid du Colombier mp = mc->xy;
569*7ab27030SDavid du Colombier b = mc->buttons;
570*7ab27030SDavid du Colombier msec = mc->msec;
571*7ab27030SDavid du Colombier
572*7ab27030SDavid du Colombier /* remove tick */
573*7ab27030SDavid du Colombier if(f->p0 == f->p1)
574*7ab27030SDavid du Colombier frtick(f, frptofchar(f, f->p0), 0);
575*7ab27030SDavid du Colombier p0 = p1 = frcharofpt(f, mp);
576*7ab27030SDavid du Colombier pt0 = frptofchar(f, p0);
577*7ab27030SDavid du Colombier pt1 = frptofchar(f, p1);
578*7ab27030SDavid du Colombier reg = 0;
579*7ab27030SDavid du Colombier frtick(f, pt0, 1);
580*7ab27030SDavid du Colombier do{
581*7ab27030SDavid du Colombier q = frcharofpt(f, mc->xy);
582*7ab27030SDavid du Colombier if(p1 != q){
583*7ab27030SDavid du Colombier if(p0 == p1)
584*7ab27030SDavid du Colombier frtick(f, pt0, 0);
585*7ab27030SDavid du Colombier if(reg != region(q, p0)){ /* crossed starting point; reset */
586*7ab27030SDavid du Colombier if(reg > 0)
587*7ab27030SDavid du Colombier selrestore(f, pt0, p0, p1);
588*7ab27030SDavid du Colombier else if(reg < 0)
589*7ab27030SDavid du Colombier selrestore(f, pt1, p1, p0);
590*7ab27030SDavid du Colombier p1 = p0;
591*7ab27030SDavid du Colombier pt1 = pt0;
592*7ab27030SDavid du Colombier reg = region(q, p0);
593*7ab27030SDavid du Colombier if(reg == 0)
594*7ab27030SDavid du Colombier frdrawsel0(f, pt0, p0, p1, col, display->white);
595*7ab27030SDavid du Colombier }
596*7ab27030SDavid du Colombier qt = frptofchar(f, q);
597*7ab27030SDavid du Colombier if(reg > 0){
598*7ab27030SDavid du Colombier if(q > p1)
599*7ab27030SDavid du Colombier frdrawsel0(f, pt1, p1, q, col, display->white);
600*7ab27030SDavid du Colombier
601*7ab27030SDavid du Colombier else if(q < p1)
602*7ab27030SDavid du Colombier selrestore(f, qt, q, p1);
603*7ab27030SDavid du Colombier }else if(reg < 0){
604*7ab27030SDavid du Colombier if(q > p1)
605*7ab27030SDavid du Colombier selrestore(f, pt1, p1, q);
606*7ab27030SDavid du Colombier else
607*7ab27030SDavid du Colombier frdrawsel0(f, qt, q, p1, col, display->white);
608*7ab27030SDavid du Colombier }
609*7ab27030SDavid du Colombier p1 = q;
610*7ab27030SDavid du Colombier pt1 = qt;
611*7ab27030SDavid du Colombier }
612*7ab27030SDavid du Colombier if(p0 == p1)
613*7ab27030SDavid du Colombier frtick(f, pt0, 1);
614*7ab27030SDavid du Colombier flushimage(f->display, 1);
615*7ab27030SDavid du Colombier readmouse(mc);
616*7ab27030SDavid du Colombier }while(mc->buttons == b);
617*7ab27030SDavid du Colombier if(mc->msec-msec < DELAY && p0!=p1
618*7ab27030SDavid du Colombier && abs(mp.x-mc->xy.x)<MINMOVE
619*7ab27030SDavid du Colombier && abs(mp.y-mc->xy.y)<MINMOVE) {
620*7ab27030SDavid du Colombier if(reg > 0)
621*7ab27030SDavid du Colombier selrestore(f, pt0, p0, p1);
622*7ab27030SDavid du Colombier else if(reg < 0)
623*7ab27030SDavid du Colombier selrestore(f, pt1, p1, p0);
624*7ab27030SDavid du Colombier p1 = p0;
625*7ab27030SDavid du Colombier }
626*7ab27030SDavid du Colombier if(p1 < p0){
627*7ab27030SDavid du Colombier tmp = p0;
628*7ab27030SDavid du Colombier p0 = p1;
629*7ab27030SDavid du Colombier p1 = tmp;
630*7ab27030SDavid du Colombier }
631*7ab27030SDavid du Colombier pt0 = frptofchar(f, p0);
632*7ab27030SDavid du Colombier if(p0 == p1)
633*7ab27030SDavid du Colombier frtick(f, pt0, 0);
634*7ab27030SDavid du Colombier selrestore(f, pt0, p0, p1);
635*7ab27030SDavid du Colombier /* restore tick */
636*7ab27030SDavid du Colombier if(f->p0 == f->p1)
637*7ab27030SDavid du Colombier frtick(f, frptofchar(f, f->p0), 1);
638*7ab27030SDavid du Colombier flushimage(f->display, 1);
639*7ab27030SDavid du Colombier *p1p = p1;
640*7ab27030SDavid du Colombier return p0;
641*7ab27030SDavid du Colombier }
642*7ab27030SDavid du Colombier
643*7ab27030SDavid du Colombier int
textselect23(Text * t,uint * q0,uint * q1,Image * high,int mask)644*7ab27030SDavid du Colombier textselect23(Text *t, uint *q0, uint *q1, Image *high, int mask)
645*7ab27030SDavid du Colombier {
646*7ab27030SDavid du Colombier uint p0, p1;
647*7ab27030SDavid du Colombier int buts;
648*7ab27030SDavid du Colombier
649*7ab27030SDavid du Colombier p0 = xselect(t, mousectl, high, &p1);
650*7ab27030SDavid du Colombier buts = mousectl->buttons;
651*7ab27030SDavid du Colombier if((buts & mask) == 0){
652*7ab27030SDavid du Colombier *q0 = p0+t->org;
653*7ab27030SDavid du Colombier *q1 = p1+t->org;
654*7ab27030SDavid du Colombier }
655*7ab27030SDavid du Colombier
656*7ab27030SDavid du Colombier while(mousectl->buttons)
657*7ab27030SDavid du Colombier readmouse(mousectl);
658*7ab27030SDavid du Colombier return buts;
659*7ab27030SDavid du Colombier }
660*7ab27030SDavid du Colombier
661*7ab27030SDavid du Colombier int
textselect2(Text * t,uint * q0,uint * q1,Text ** tp)662*7ab27030SDavid du Colombier textselect2(Text *t, uint *q0, uint *q1, Text **tp)
663*7ab27030SDavid du Colombier {
664*7ab27030SDavid du Colombier int buts;
665*7ab27030SDavid du Colombier
666*7ab27030SDavid du Colombier *tp = nil;
667*7ab27030SDavid du Colombier buts = textselect23(t, q0, q1, but2col, 4);
668*7ab27030SDavid du Colombier if(buts & 4)
669*7ab27030SDavid du Colombier return 0;
670*7ab27030SDavid du Colombier if(buts & 1){ /* pick up argument */
671*7ab27030SDavid du Colombier *tp = argtext;
672*7ab27030SDavid du Colombier return 1;
673*7ab27030SDavid du Colombier }
674*7ab27030SDavid du Colombier return 1;
675*7ab27030SDavid du Colombier }
676*7ab27030SDavid du Colombier
677*7ab27030SDavid du Colombier int
textselect3(Text * t,uint * q0,uint * q1)678*7ab27030SDavid du Colombier textselect3(Text *t, uint *q0, uint *q1)
679*7ab27030SDavid du Colombier {
680*7ab27030SDavid du Colombier int h;
681*7ab27030SDavid du Colombier
682*7ab27030SDavid du Colombier h = (textselect23(t, q0, q1, but3col, 1|2) == 0);
683*7ab27030SDavid du Colombier return h;
684*7ab27030SDavid du Colombier }
685*7ab27030SDavid du Colombier
686*7ab27030SDavid du Colombier static Rune left1[] = { L'{', L'[', L'(', L'<', L'«', 0 };
687*7ab27030SDavid du Colombier static Rune right1[] = { L'}', L']', L')', L'>', L'»', 0 };
688*7ab27030SDavid du Colombier static Rune left2[] = { L'\n', 0 };
689*7ab27030SDavid du Colombier static Rune left3[] = { L'\'', L'"', L'`', 0 };
690*7ab27030SDavid du Colombier
691*7ab27030SDavid du Colombier static
692*7ab27030SDavid du Colombier Rune *left[] = {
693*7ab27030SDavid du Colombier left1,
694*7ab27030SDavid du Colombier left2,
695*7ab27030SDavid du Colombier left3,
696*7ab27030SDavid du Colombier nil
697*7ab27030SDavid du Colombier };
698*7ab27030SDavid du Colombier static
699*7ab27030SDavid du Colombier Rune *right[] = {
700*7ab27030SDavid du Colombier right1,
701*7ab27030SDavid du Colombier left2,
702*7ab27030SDavid du Colombier left3,
703*7ab27030SDavid du Colombier nil
704*7ab27030SDavid du Colombier };
705*7ab27030SDavid du Colombier
706*7ab27030SDavid du Colombier void
textdoubleclick(Text * t,uint * q0,uint * q1)707*7ab27030SDavid du Colombier textdoubleclick(Text *t, uint *q0, uint *q1)
708*7ab27030SDavid du Colombier {
709*7ab27030SDavid du Colombier int c, i;
710*7ab27030SDavid du Colombier Rune *r, *l, *p;
711*7ab27030SDavid du Colombier uint q;
712*7ab27030SDavid du Colombier
713*7ab27030SDavid du Colombier if(t->rs.nr == 0)
714*7ab27030SDavid du Colombier return;
715*7ab27030SDavid du Colombier
716*7ab27030SDavid du Colombier for(i=0; left[i]!=nil; i++){
717*7ab27030SDavid du Colombier q = *q0;
718*7ab27030SDavid du Colombier l = left[i];
719*7ab27030SDavid du Colombier r = right[i];
720*7ab27030SDavid du Colombier /* try matching character to left, looking right */
721*7ab27030SDavid du Colombier if(q == 0)
722*7ab27030SDavid du Colombier c = '\n';
723*7ab27030SDavid du Colombier else
724*7ab27030SDavid du Colombier c = t->rs.r[q-1];
725*7ab27030SDavid du Colombier p = runestrchr(l, c);
726*7ab27030SDavid du Colombier if(p != nil){
727*7ab27030SDavid du Colombier if(textclickmatch(t, c, t->rs.r[p-l], 1, &q))
728*7ab27030SDavid du Colombier *q1 = q-(c!='\n');
729*7ab27030SDavid du Colombier return;
730*7ab27030SDavid du Colombier }
731*7ab27030SDavid du Colombier /* try matching character to right, looking left */
732*7ab27030SDavid du Colombier if(q == t->rs.nr)
733*7ab27030SDavid du Colombier c = '\n';
734*7ab27030SDavid du Colombier else
735*7ab27030SDavid du Colombier c = t->rs.r[q];
736*7ab27030SDavid du Colombier p = runestrchr(r, c);
737*7ab27030SDavid du Colombier if(p != nil){
738*7ab27030SDavid du Colombier if(textclickmatch(t, c, l[p-r], -1, &q)){
739*7ab27030SDavid du Colombier *q1 = *q0+(*q0<t->rs.nr && c=='\n');
740*7ab27030SDavid du Colombier *q0 = q;
741*7ab27030SDavid du Colombier if(c!='\n' || q!=0 || t->rs.r[0]=='\n')
742*7ab27030SDavid du Colombier (*q0)++;
743*7ab27030SDavid du Colombier }
744*7ab27030SDavid du Colombier return;
745*7ab27030SDavid du Colombier }
746*7ab27030SDavid du Colombier }
747*7ab27030SDavid du Colombier /* try filling out word to right */
748*7ab27030SDavid du Colombier while(*q1<t->rs.nr && isalnum(t->rs.r[*q1]))
749*7ab27030SDavid du Colombier (*q1)++;
750*7ab27030SDavid du Colombier /* try filling out word to left */
751*7ab27030SDavid du Colombier while(*q0>0 && isalnum(t->rs.r[*q0-1]))
752*7ab27030SDavid du Colombier (*q0)--;
753*7ab27030SDavid du Colombier }
754*7ab27030SDavid du Colombier
755*7ab27030SDavid du Colombier int
textclickmatch(Text * t,int cl,int cr,int dir,uint * q)756*7ab27030SDavid du Colombier textclickmatch(Text *t, int cl, int cr, int dir, uint *q)
757*7ab27030SDavid du Colombier {
758*7ab27030SDavid du Colombier Rune c;
759*7ab27030SDavid du Colombier int nest;
760*7ab27030SDavid du Colombier
761*7ab27030SDavid du Colombier nest = 1;
762*7ab27030SDavid du Colombier for(;;){
763*7ab27030SDavid du Colombier if(dir > 0){
764*7ab27030SDavid du Colombier if(*q == t->rs.nr)
765*7ab27030SDavid du Colombier break;
766*7ab27030SDavid du Colombier c = t->rs.r[*q];
767*7ab27030SDavid du Colombier (*q)++;
768*7ab27030SDavid du Colombier }else{
769*7ab27030SDavid du Colombier if(*q == 0)
770*7ab27030SDavid du Colombier break;
771*7ab27030SDavid du Colombier (*q)--;
772*7ab27030SDavid du Colombier c = t->rs.r[*q];
773*7ab27030SDavid du Colombier }
774*7ab27030SDavid du Colombier if(c == cr){
775*7ab27030SDavid du Colombier if(--nest==0)
776*7ab27030SDavid du Colombier return 1;
777*7ab27030SDavid du Colombier }else if(c == cl)
778*7ab27030SDavid du Colombier nest++;
779*7ab27030SDavid du Colombier }
780*7ab27030SDavid du Colombier return cl=='\n' && nest==1;
781*7ab27030SDavid du Colombier }
782*7ab27030SDavid du Colombier
783*7ab27030SDavid du Colombier uint
textbacknl(Text * t,uint p,uint n)784*7ab27030SDavid du Colombier textbacknl(Text *t, uint p, uint n)
785*7ab27030SDavid du Colombier {
786*7ab27030SDavid du Colombier int i, j;
787*7ab27030SDavid du Colombier
788*7ab27030SDavid du Colombier /* look for start of this line if n==0 */
789*7ab27030SDavid du Colombier if(n==0 && p>0 && t->rs.r[p-1]!='\n')
790*7ab27030SDavid du Colombier n = 1;
791*7ab27030SDavid du Colombier i = n;
792*7ab27030SDavid du Colombier while(i-->0 && p>0){
793*7ab27030SDavid du Colombier --p; /* it's at a newline now; back over it */
794*7ab27030SDavid du Colombier if(p == 0)
795*7ab27030SDavid du Colombier break;
796*7ab27030SDavid du Colombier /* at 128 chars, call it a line anyway */
797*7ab27030SDavid du Colombier for(j=128; --j>0 && p>0; p--)
798*7ab27030SDavid du Colombier if(t->rs.r[p-1]=='\n')
799*7ab27030SDavid du Colombier break;
800*7ab27030SDavid du Colombier }
801*7ab27030SDavid du Colombier return p;
802*7ab27030SDavid du Colombier }
803*7ab27030SDavid du Colombier
804*7ab27030SDavid du Colombier void
textsetorigin(Text * t,uint org,int exact)805*7ab27030SDavid du Colombier textsetorigin(Text *t, uint org, int exact)
806*7ab27030SDavid du Colombier {
807*7ab27030SDavid du Colombier int i, a, fixup;
808*7ab27030SDavid du Colombier Rune *r;
809*7ab27030SDavid du Colombier uint n;
810*7ab27030SDavid du Colombier
811*7ab27030SDavid du Colombier if(org>0 && !exact){
812*7ab27030SDavid du Colombier /* org is an estimate of the char posn; find a newline */
813*7ab27030SDavid du Colombier /* don't try harder than 256 chars */
814*7ab27030SDavid du Colombier for(i=0; i<256 && org<t->rs.nr; i++){
815*7ab27030SDavid du Colombier if(t->rs.r[org] == '\n'){
816*7ab27030SDavid du Colombier org++;
817*7ab27030SDavid du Colombier break;
818*7ab27030SDavid du Colombier }
819*7ab27030SDavid du Colombier org++;
820*7ab27030SDavid du Colombier }
821*7ab27030SDavid du Colombier }
822*7ab27030SDavid du Colombier a = org-t->org;
823*7ab27030SDavid du Colombier fixup = 0;
824*7ab27030SDavid du Colombier if(a>=0 && a<t->nchars){
825*7ab27030SDavid du Colombier frdelete(t, 0, a);
826*7ab27030SDavid du Colombier fixup = 1; /* frdelete can leave end of last line in wrong selection mode; it doesn't know what follows */
827*7ab27030SDavid du Colombier }else if(a<0 && -a<t->nchars){
828*7ab27030SDavid du Colombier n = t->org - org;
829*7ab27030SDavid du Colombier r = runemalloc(n);
830*7ab27030SDavid du Colombier runemove(r, t->rs.r+org, n);
831*7ab27030SDavid du Colombier frinsert(t, r, r+n, 0);
832*7ab27030SDavid du Colombier free(r);
833*7ab27030SDavid du Colombier }else
834*7ab27030SDavid du Colombier frdelete(t, 0, t->nchars);
835*7ab27030SDavid du Colombier t->org = org;
836*7ab27030SDavid du Colombier textfill(t);
837*7ab27030SDavid du Colombier textscrdraw(t);
838*7ab27030SDavid du Colombier textsetselect(t, t->q0, t->q1);
839*7ab27030SDavid du Colombier if(fixup && t->p1 > t->p0)
840*7ab27030SDavid du Colombier frdrawsel(t, frptofchar(t, t->p1-1), t->p1-1, t->p1, 1);
841*7ab27030SDavid du Colombier }
842*7ab27030SDavid du Colombier
843*7ab27030SDavid du Colombier void
textset(Text * t,Rune * r,int n)844*7ab27030SDavid du Colombier textset(Text *t, Rune*r, int n)
845*7ab27030SDavid du Colombier {
846*7ab27030SDavid du Colombier textdelete(t, 0, t->rs.nr);
847*7ab27030SDavid du Colombier textinsert(t, 0, r, n);
848*7ab27030SDavid du Colombier textsetselect(t, t->q0, t->q1);
849*7ab27030SDavid du Colombier }
850*7ab27030SDavid du Colombier
851*7ab27030SDavid du Colombier void
textmouse(Text * t,Point xy,int but)852*7ab27030SDavid du Colombier textmouse(Text *t, Point xy, int but)
853*7ab27030SDavid du Colombier {
854*7ab27030SDavid du Colombier Text *argt;
855*7ab27030SDavid du Colombier uint q0, q1;
856*7ab27030SDavid du Colombier
857*7ab27030SDavid du Colombier if(ptinrect(xy, t->scrollr)){
858*7ab27030SDavid du Colombier if(t->what == Columntag)
859*7ab27030SDavid du Colombier rowdragcol(&row, t->col, but);
860*7ab27030SDavid du Colombier else if(t->what == Tag)
861*7ab27030SDavid du Colombier coldragwin(t->col, t->w, but);
862*7ab27030SDavid du Colombier else if(t->what == Textarea)
863*7ab27030SDavid du Colombier textscroll(t, but);
864*7ab27030SDavid du Colombier if(t->col)
865*7ab27030SDavid du Colombier activecol = t->col;
866*7ab27030SDavid du Colombier return;
867*7ab27030SDavid du Colombier }
868*7ab27030SDavid du Colombier if(but == 1){
869*7ab27030SDavid du Colombier selpage = nil;
870*7ab27030SDavid du Colombier textselect(t);
871*7ab27030SDavid du Colombier argtext = t;
872*7ab27030SDavid du Colombier seltext = t;
873*7ab27030SDavid du Colombier }else if(but == 2){
874*7ab27030SDavid du Colombier if(textselect2(t, &q0, &q1, &argt))
875*7ab27030SDavid du Colombier execute(t, q0, q1, argt);
876*7ab27030SDavid du Colombier }else if(but == 3){
877*7ab27030SDavid du Colombier if(textselect3(t, &q0, &q1))
878*7ab27030SDavid du Colombier look3(t, q0, q1);
879*7ab27030SDavid du Colombier }
880*7ab27030SDavid du Colombier }
881