]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/sam/moveto.c
triple click selection in sam
[plan9front.git] / sys / src / cmd / sam / moveto.c
1 #include "sam.h"
2
3 void
4 moveto(File *f, Range r)
5 {
6         Posn p1 = r.p1, p2 = r.p2;
7
8         f->dot.r.p1 = p1;
9         f->dot.r.p2 = p2;
10         if(f->rasp){
11                 telldot(f);
12                 outTsl(Hmoveto, f->tag, f->dot.r.p1);
13         }
14 }
15
16 void
17 telldot(File *f)
18 {
19         if(f->rasp == 0)
20                 panic("telldot");
21         if(f->dot.r.p1==f->tdot.p1 && f->dot.r.p2==f->tdot.p2)
22                 return;
23         outTsll(Hsetdot, f->tag, f->dot.r.p1, f->dot.r.p2);
24         f->tdot = f->dot.r;
25 }
26
27 void
28 tellpat(void)
29 {
30         outTS(Hsetpat, &lastpat);
31         patset = FALSE;
32 }
33
34 #define CHARSHIFT       128
35
36 void
37 lookorigin(File *f, Posn p0, Posn ls)
38 {
39         int nl, nc, c;
40         Posn p, oldp0;
41
42         if(p0 > f->nc)
43                 p0 = f->nc;
44         oldp0 = p0;
45         p = p0;
46         for(nl=nc=c=0; c!=-1 && nl<ls && nc<ls*CHARSHIFT; nc++)
47                 if((c=filereadc(f, --p)) == '\n'){
48                         nl++;
49                         oldp0 = p0-nc;
50                 }
51         if(c == -1)
52                 p0 = 0;
53         else if(nl==0){
54                 if(p0>=CHARSHIFT/2)
55                         p0-=CHARSHIFT/2;
56                 else
57                         p0 = 0;
58         }else
59                 p0 = oldp0;
60         outTsl(Horigin, f->tag, p0);
61 }
62
63 int
64 isalnum(int c)
65 {
66         /*
67          * Hard to get absolutely right.  Use what we know about ASCII
68          * and assume anything above the Latin control characters is
69          * potentially an alphanumeric.
70          */
71         if(c<=' ')
72                 return 0;
73         if(0x7F<=c && c<=0xA0)
74                 return 0;
75         if(utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c))
76                 return 0;
77         return 1;
78 }
79
80 int
81 isspace(Rune c)
82 {
83         return c == 0 || c == ' ' || c == '\t' ||
84                 c == '\n' || c == '\r' || c == '\v';
85 }
86
87 int
88 inmode(Rune r, int mode)
89 {
90         return (mode == 0) ? isalnum(r) : r && !isspace(r);
91 }
92
93 int
94 clickmatch(File *f, int cl, int cr, int dir, Posn *p)
95 {
96         int c;
97         int nest = 1;
98
99         for(;;){
100                 if(dir > 0){
101                         if(*p >= f->nc)
102                                 break;
103                         c = filereadc(f, (*p)++);
104                 }else{
105                         if(*p == 0)
106                                 break;
107                         c = filereadc(f, --(*p));
108                 }
109                 if(c == cr){
110                         if(--nest==0)
111                                 return 1;
112                 }else if(c == cl)
113                         nest++;
114         }
115         return cl=='\n' && nest==1;
116 }
117
118 Rune*
119 strrune(Rune *s, Rune c)
120 {
121         Rune c1;
122
123         if(c == 0) {
124                 while(*s++)
125                         ;
126                 return s-1;
127         }
128
129         while(c1 = *s++)
130                 if(c1 == c)
131                         return s-1;
132         return 0;
133 }
134
135 /*
136  * Stretches a selection out over current text,
137  * selecting matching range if possible.
138  * If there's no matching range, mode 0 selects
139  * a single alphanumeric region. Mode 1 selects
140  * a non-whitespace region.
141  */
142 void
143 stretchsel(File *f, Posn p1, int mode)
144 {
145         int c, i;
146         Rune *r, *l;
147         Posn p;
148
149         if(p1 > f->nc)
150                 return;
151         f->dot.r.p1 = f->dot.r.p2 = p1;
152         for(i=0; left[i]; i++){
153                 l = left[i];
154                 r = right[i];
155                 /* try left match */
156                 p = p1;
157                 if(p1 == 0)
158                         c = '\n';
159                 else
160                         c = filereadc(f, p - 1);
161                 if(strrune(l, c)){
162                         if(clickmatch(f, c, r[strrune(l, c)-l], 1, &p)){
163                                 f->dot.r.p1 = p1;
164                                 f->dot.r.p2 = p-(c!='\n');
165                         }
166                         return;
167                 }
168                 /* try right match */
169                 p = p1;
170                 if(p1 == f->nc)
171                         c = '\n';
172                 else
173                         c = filereadc(f, p);
174                 if(strrune(r, c)){
175                         if(clickmatch(f, c, l[strrune(r, c)-r], -1, &p)){
176                                 f->dot.r.p1 = p;
177                                 if(c!='\n' || p!=0 || filereadc(f, 0)=='\n')
178                                         f->dot.r.p1++;
179                                 f->dot.r.p2 = p1+(p1<f->nc && c=='\n');
180                         }
181                         return;
182                 }
183         }
184         /* try filling out word to right */
185         p = p1;
186         while(p < f->nc && inmode(filereadc(f, p++), mode))
187                 f->dot.r.p2++;
188         /* try filling out word to left */
189         p = p1;
190         while(--p >= 0 && inmode(filereadc(f, p), mode))
191                 f->dot.r.p1--;
192 }
193