summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Faure <billiob@gmail.com>2016-11-06 19:45:46 +0100
committerBoris Faure <billiob@gmail.com>2016-11-06 20:04:02 +0100
commit0cbaaeec9d991ca41576b780dbb1564707bc3a8d (patch)
tree39a9145d17fc7e3b01f1912f96151fbb57f1ae6d
parentc41fc2a56e5da4a07ea693ad5c55fea86101119c (diff)
link: rewrite link detection to be more efficient
-rw-r--r--src/bin/termiolink.c406
1 files changed, 274 insertions, 132 deletions
diff --git a/src/bin/termiolink.c b/src/bin/termiolink.c
index a324bf4..3f31789 100644
--- a/src/bin/termiolink.c
+++ b/src/bin/termiolink.c
@@ -1,42 +1,10 @@
1#include "private.h" 1#include "private.h"
2#include <Elementary.h> 2#include <Elementary.h>
3#include "termio.h" 3#include "termio.h"
4#include "sb.h"
5#include "utf8.h"
4#include "utils.h" 6#include "utils.h"
5 7
6static Eina_Bool
7coord_back(int *x, int *y, int w, int _h EINA_UNUSED)
8{
9 (*x)--;
10 if ((*x) < 0)
11 {
12 if ((*y) <= 0)
13 {
14 (*x)++;
15 return EINA_FALSE;
16 }
17 (*x) = w - 1;
18 (*y)--;
19 }
20 return EINA_TRUE;
21}
22
23static Eina_Bool
24coord_forward(int *x, int *y, int w, int h)
25{
26 (*x)++;
27 if ((*x) >= w)
28 {
29 if ((*y) >= (h - 1))
30 {
31 (*x)--;
32 return EINA_FALSE;
33 }
34 (*x) = 0;
35 (*y)++;
36 }
37 return EINA_TRUE;
38}
39
40static char * 8static char *
41_cwd_path_get(const Evas_Object *obj, const char *relpath) 9_cwd_path_get(const Evas_Object *obj, const char *relpath)
42{ 10{
@@ -95,144 +63,318 @@ _is_file(const char *str)
95 } 63 }
96} 64}
97 65
66static int
67_txt_at(Termpty *ty, int *x, int *y, char *txt, int *txtlenp)
68{
69 Termcell *cells = NULL;
70 Termcell cell;
71 ssize_t w;
72
73 cells = termpty_cellrow_get(ty, *y, &w);
74 if (!cells || !w)
75 goto bad;
76 cell = cells[*x];
77 if ((cell.codepoint == 0) && (cell.att.dblwidth))
78 {
79 (*x)--;
80 if (*x < 0)
81 goto bad;
82 cell = cells[*x];
83 }
84
85 if (cell.codepoint == 0)
86 {
87 txt[0] = '\0';
88 *txtlenp = 0;
89 }
90 else
91 {
92 *txtlenp = codepoint_to_utf8(cell.codepoint, txt);
93 }
94
95 return 0;
96
97bad:
98 *txtlenp = 0;
99 txt[0] = '\0';
100 return -1;
101}
102
103static int
104_txt_prev_at(Termpty *ty, int *x, int *y, char *txt, int *txtlenp)
105{
106 Termcell *cells = NULL;
107 Termcell cell;
108 ssize_t w;
109
110 (*x)--;
111 if ((*x) < 0)
112 (*y)--;
113 cells = termpty_cellrow_get(ty, *y, &w);
114 if (!cells || !w)
115 goto bad;
116 if ((*x) < 0)
117 *x = w-1;
118
119 cell = cells[*x];
120 if ((cell.codepoint == 0) && (cell.att.dblwidth))
121 {
122 (*x)--;
123 if (*x < 0)
124 goto bad;
125 cell = cells[*x];
126 }
127
128 if (cell.codepoint == 0)
129 {
130 txt[0] = '\0';
131 *txtlenp = 0;
132 }
133 else
134 {
135 *txtlenp = codepoint_to_utf8(cell.codepoint, txt);
136 }
137
138 return 0;
139
140bad:
141 *txtlenp = 0;
142 txt[0] = '\0';
143 return -1;
144}
145
146static int
147_txt_next_at(Termpty *ty, int *x, int *y, char *txt, int *txtlenp)
148{
149 Termcell *cells = NULL;
150 Termcell cell;
151 ssize_t w;
152
153 (*x)++;
154 cells = termpty_cellrow_get(ty, *y, &w);
155 if (!cells || !w)
156 goto bad;
157 if (*x >= w)
158 {
159 (*y)++;
160 *x = 0;
161 cells = termpty_cellrow_get(ty, *y, &w);
162 if (!cells || !w)
163 goto bad;
164 }
165
166 cell = cells[*x];
167 if ((cell.codepoint == 0) && (cell.att.dblwidth))
168 {
169 (*x)++;
170 if (*x >= w)
171 {
172 (*y)++;
173 *x = 0;
174 cells = termpty_cellrow_get(ty, *y, &w);
175 if (!cells || !w)
176 goto bad;
177 }
178 goto bad;
179 }
180
181 cell = cells[*x];
182 if (cell.codepoint == 0)
183 {
184 txt[0] = '\0';
185 *txtlenp = 0;
186 }
187 else
188 {
189 *txtlenp = codepoint_to_utf8(cell.codepoint, txt);
190 }
191
192 return 0;
193
194bad:
195 *txtlenp = 0;
196 txt[0] = '\0';
197 return -1;
198}
199
98char * 200char *
99termio_link_find(Evas_Object *obj, int cx, int cy, 201termio_link_find(Evas_Object *obj, int cx, int cy,
100 int *x1r, int *y1r, int *x2r, int *y2r) 202 int *x1r, int *y1r, int *x2r, int *y2r)
101{ 203{
102 char *s; 204 char *s = NULL;
103 char endmatch = 0; 205 char endmatch = 0;
104 int x1, x2, y1, y2, w = 0, h = 0, sc; 206 int x1, x2, y1, y2, w = 0, h = 0, sc;
105 size_t len = 0, prev_len = 0;
106 Eina_Bool goback = EINA_TRUE, goforward = EINA_FALSE, escaped = EINA_FALSE; 207 Eina_Bool goback = EINA_TRUE, goforward = EINA_FALSE, escaped = EINA_FALSE;
208 struct ty_sb sb = {.buf = NULL, .gap = 0, .len = 0, .alloc = 0};
209 Termpty *ty = termio_pty_get(obj);
210 int res;
211 char txt[8];
212 int txtlen = 0;
213 Eina_Bool was_protocol = EINA_FALSE;
107 214
108 x1 = x2 = cx; 215 x1 = x2 = cx;
109 y1 = y2 = cy; 216 y1 = y2 = cy;
110 termio_size_get(obj, &w, &h); 217 termio_size_get(obj, &w, &h);
111 if ((w <= 0) || (h <= 0)) return NULL; 218 if ((w <= 0) || (h <= 0)) goto end;
219
112 sc = termio_scroll_get(obj); 220 sc = termio_scroll_get(obj);
113 for (;;) 221
222 termpty_backlog_lock();
223
224 y1 -= sc;
225 y2 -= sc;
226
227 res = _txt_at(ty, &x1, &y1, txt, &txtlen);
228 if ((res != 0) || (txtlen == 0)) goto end;
229 ty_sb_add(&sb, txt, txtlen);
230
231 while (goback)
114 { 232 {
115 prev_len = len; 233 int new_x1 = x1, new_y1 = y1;
116 s = termio_selection_get(obj, x1, y1 - sc, x2, y2 - sc, &len, EINA_FALSE); 234
117 if (!s) break; 235 res = _txt_prev_at(ty, &new_x1, &new_y1, txt, &txtlen);
118 if (goback) 236 if ((res != 0) || (txtlen == 0))
237 {
238 goback = EINA_FALSE;
239 goforward = EINA_TRUE;
240 }
241 ty_sb_prepend(&sb, txt, txtlen);
242 if (isspace(sb.buf[0]))
119 { 243 {
120 if (link_is_protocol(s)) 244 int old_txtlen = txtlen;
245 res = _txt_prev_at(ty, &new_x1, &new_y1, txt, &txtlen);
246 if ((res != 0) || (txtlen == 0))
121 { 247 {
122 goback = EINA_FALSE; 248 goback = EINA_FALSE;
123 goforward = EINA_TRUE; 249 goforward = EINA_TRUE;
124 250 break;
125 /* Check if the previous char is a delimiter */
126 coord_back(&x1, &y1, w, h);
127 free(s);
128 s = termio_selection_get(obj, x1, y1 - sc, x2, y2 - sc,
129 &len, EINA_FALSE);
130 if (!s) break;
131 switch (s[0])
132 {
133 case '"': endmatch = '"'; break;
134 case '\'': endmatch = '\''; break;
135 case '`': endmatch = '`'; break;
136 case '<': endmatch = '>'; break;
137 case '[': endmatch = ']'; break;
138 case '{': endmatch = '}'; break;
139 case '(': endmatch = ')'; break;
140 }
141 if (!(x1 == 0 && y1 == 0))
142 {
143 coord_forward(&x1, &y1, w, h);
144
145 free(s);
146 prev_len = len;
147 s = termio_selection_get(obj, x1, y1 - sc, x2, y2 - sc,
148 &len, EINA_FALSE);
149 if (!s) break;
150 }
151 } 251 }
152 else 252 if (txt[0] != '\\')
153 { 253 {
154 switch (s[0]) 254 ty_sb_lskip(&sb, old_txtlen);
155 { 255 goback = EINA_FALSE;
156 case '"': endmatch = '"'; break; 256 goforward = EINA_TRUE;
157 case '\'': endmatch = '\''; break; 257 break;
158 case '`': endmatch = '`'; break;
159 case '<': endmatch = '>'; break;
160 case '[': endmatch = ']'; break;
161 case '{': endmatch = '}'; break;
162 case '(': endmatch = ')'; break;
163 }
164 if ((endmatch) || (isspace(s[0])))
165 {
166 goback = EINA_FALSE;
167 coord_forward(&x1, &y1, w, h);
168 goforward = EINA_TRUE;
169 free(s);
170 s = termio_selection_get(obj, x1, y1 - sc, x2, y2 - sc,
171 &len, EINA_FALSE);
172 if (!s) break;
173 }
174 } 258 }
175 } 259 }
176 if ((goforward) && (len >= 1)) 260 switch (sb.buf[0])
261 {
262 case '"': endmatch = '"'; break;
263 case '\'': endmatch = '\''; break;
264 case '`': endmatch = '`'; break;
265 case '<': endmatch = '>'; break;
266 case '[': endmatch = ']'; break;
267 case '{': endmatch = '}'; break;
268 case '(': endmatch = ')'; break;
269 case '|': endmatch = '|'; break;
270 }
271 if (endmatch)
177 { 272 {
178 char end = s[len - 1]; 273 ty_sb_lskip(&sb, txtlen);
179 if (len - prev_len == 2 && len >= 2) 274 goback = EINA_FALSE;
180 end = s[len - 2]; 275 goforward = EINA_TRUE;
276 break;
277 }
181 278
182 if ((end == endmatch) || 279 if (!link_is_protocol(sb.buf))
183 ((!escaped) && (isspace(end)))) 280 {
281 if (was_protocol)
184 { 282 {
185 goforward = EINA_FALSE; 283 if (!isspace(sb.buf[0]))
186 coord_back(&x2, &y2, w, h); 284 endmatch = sb.buf[0];
187 endmatch = 0; 285 ty_sb_lskip(&sb, txtlen);
286 goback = EINA_FALSE;
287 goforward = EINA_TRUE;
288 break;
188 } 289 }
189 escaped = (end == '\\');
190 } 290 }
191 if ((goback) && (!coord_back(&x1, &y1, w, h))) 291 else
192 { 292 {
193 goback = EINA_FALSE; 293 was_protocol = EINA_TRUE;
194 goforward = EINA_TRUE;
195 } 294 }
196 if ((goforward) && (!coord_forward(&x2, &y2, w, h))) 295 x1 = new_x1;
296 y1 = new_y1;
297 }
298
299 while (goforward)
300 {
301 int new_x2 = x2, new_y2 = y2;
302 /* Check if the previous char is a delimiter */
303 res = _txt_next_at(ty, &new_x2, &new_y2, txt, &txtlen);
304 if ((res != 0) || (txtlen == 0))
197 { 305 {
198 goforward = EINA_FALSE; 306 goforward = EINA_FALSE;
307 break;
308 }
309 /* escaping */
310 if (txt[0] == '\\')
311 {
312 x2 = new_x2;
313 y2 = new_y2;
314 escaped = EINA_TRUE;
315 continue;
199 } 316 }
200 if ((!goback) && (!goforward)) 317 if (escaped)
201 { 318 {
202 free(s); 319 x2 = new_x2;
203 s = termio_selection_get(obj, x1, y1 - sc, x2, y2 - sc, &len, 320 y2 = new_y2;
204 EINA_FALSE); 321 escaped = EINA_FALSE;
322 }
323
324 if (isspace(txt[0]) || txt[0] == endmatch)
325 {
326 goforward = EINA_FALSE;
205 break; 327 break;
206 } 328 }
207 free(s); 329
208 s = NULL; 330 ty_sb_add(&sb, txt, txtlen);
331
332 if (!link_is_protocol(sb.buf))
333 {
334 if (was_protocol)
335 {
336 ty_sb_rskip(&sb, txtlen);
337 goback = EINA_FALSE;
338 }
339 }
340 else
341 {
342 was_protocol = EINA_TRUE;
343 }
344 x2 = new_x2;
345 y2 = new_y2;
209 } 346 }
210 if (s) 347
348 if (sb.len)
211 { 349 {
212 if ((len > 1) && (!endmatch)) 350 Eina_Bool is_file = _is_file(sb.buf);
351
352 if (is_file ||
353 link_is_email(sb.buf) ||
354 link_is_url(sb.buf))
213 { 355 {
214 Eina_Bool is_file = _is_file(s); 356 if (x1r) *x1r = x1;
357 if (y1r) *y1r = y1 + sc;
358 if (x2r) *x2r = x2;
359 if (y2r) *y2r = y2 + sc;
215 360
216 if (is_file || 361 if (is_file && (sb.buf[0] != '/'))
217 link_is_email(s) ||
218 link_is_url(s))
219 { 362 {
220 if (x1r) *x1r = x1; 363 char *local= _local_path_get(obj, (const char*)sb.buf);
221 if (y1r) *y1r = y1; 364 ty_sb_free(&sb);
222 if (x2r) *x2r = x2; 365 s = local;
223 if (y2r) *y2r = y2; 366 goto end;
224
225 if (is_file && (s[0] != '/'))
226 {
227 char *ret = _local_path_get(obj, s);
228 free(s);
229 return ret;
230 }
231
232 return s;
233 } 367 }
368 else
369 {
370 s = ty_sb_steal_buf(&sb);
371 }
372
373 goto end;
234 } 374 }
235 free(s);
236 } 375 }
237 return NULL; 376end:
377 termpty_backlog_unlock();
378 ty_sb_free(&sb);
379 return s;
238} 380}