forked from enlightenment/terminology
link: rewrite link detection to be more efficient
This commit is contained in:
parent
c41fc2a56e
commit
0cbaaeec9d
|
@ -1,42 +1,10 @@
|
|||
#include "private.h"
|
||||
#include <Elementary.h>
|
||||
#include "termio.h"
|
||||
#include "sb.h"
|
||||
#include "utf8.h"
|
||||
#include "utils.h"
|
||||
|
||||
static Eina_Bool
|
||||
coord_back(int *x, int *y, int w, int _h EINA_UNUSED)
|
||||
{
|
||||
(*x)--;
|
||||
if ((*x) < 0)
|
||||
{
|
||||
if ((*y) <= 0)
|
||||
{
|
||||
(*x)++;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
(*x) = w - 1;
|
||||
(*y)--;
|
||||
}
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
coord_forward(int *x, int *y, int w, int h)
|
||||
{
|
||||
(*x)++;
|
||||
if ((*x) >= w)
|
||||
{
|
||||
if ((*y) >= (h - 1))
|
||||
{
|
||||
(*x)--;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
(*x) = 0;
|
||||
(*y)++;
|
||||
}
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static char *
|
||||
_cwd_path_get(const Evas_Object *obj, const char *relpath)
|
||||
{
|
||||
|
@ -95,144 +63,318 @@ _is_file(const char *str)
|
|||
}
|
||||
}
|
||||
|
||||
static int
|
||||
_txt_at(Termpty *ty, int *x, int *y, char *txt, int *txtlenp)
|
||||
{
|
||||
Termcell *cells = NULL;
|
||||
Termcell cell;
|
||||
ssize_t w;
|
||||
|
||||
cells = termpty_cellrow_get(ty, *y, &w);
|
||||
if (!cells || !w)
|
||||
goto bad;
|
||||
cell = cells[*x];
|
||||
if ((cell.codepoint == 0) && (cell.att.dblwidth))
|
||||
{
|
||||
(*x)--;
|
||||
if (*x < 0)
|
||||
goto bad;
|
||||
cell = cells[*x];
|
||||
}
|
||||
|
||||
if (cell.codepoint == 0)
|
||||
{
|
||||
txt[0] = '\0';
|
||||
*txtlenp = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*txtlenp = codepoint_to_utf8(cell.codepoint, txt);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
bad:
|
||||
*txtlenp = 0;
|
||||
txt[0] = '\0';
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
_txt_prev_at(Termpty *ty, int *x, int *y, char *txt, int *txtlenp)
|
||||
{
|
||||
Termcell *cells = NULL;
|
||||
Termcell cell;
|
||||
ssize_t w;
|
||||
|
||||
(*x)--;
|
||||
if ((*x) < 0)
|
||||
(*y)--;
|
||||
cells = termpty_cellrow_get(ty, *y, &w);
|
||||
if (!cells || !w)
|
||||
goto bad;
|
||||
if ((*x) < 0)
|
||||
*x = w-1;
|
||||
|
||||
cell = cells[*x];
|
||||
if ((cell.codepoint == 0) && (cell.att.dblwidth))
|
||||
{
|
||||
(*x)--;
|
||||
if (*x < 0)
|
||||
goto bad;
|
||||
cell = cells[*x];
|
||||
}
|
||||
|
||||
if (cell.codepoint == 0)
|
||||
{
|
||||
txt[0] = '\0';
|
||||
*txtlenp = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*txtlenp = codepoint_to_utf8(cell.codepoint, txt);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
bad:
|
||||
*txtlenp = 0;
|
||||
txt[0] = '\0';
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
_txt_next_at(Termpty *ty, int *x, int *y, char *txt, int *txtlenp)
|
||||
{
|
||||
Termcell *cells = NULL;
|
||||
Termcell cell;
|
||||
ssize_t w;
|
||||
|
||||
(*x)++;
|
||||
cells = termpty_cellrow_get(ty, *y, &w);
|
||||
if (!cells || !w)
|
||||
goto bad;
|
||||
if (*x >= w)
|
||||
{
|
||||
(*y)++;
|
||||
*x = 0;
|
||||
cells = termpty_cellrow_get(ty, *y, &w);
|
||||
if (!cells || !w)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
cell = cells[*x];
|
||||
if ((cell.codepoint == 0) && (cell.att.dblwidth))
|
||||
{
|
||||
(*x)++;
|
||||
if (*x >= w)
|
||||
{
|
||||
(*y)++;
|
||||
*x = 0;
|
||||
cells = termpty_cellrow_get(ty, *y, &w);
|
||||
if (!cells || !w)
|
||||
goto bad;
|
||||
}
|
||||
goto bad;
|
||||
}
|
||||
|
||||
cell = cells[*x];
|
||||
if (cell.codepoint == 0)
|
||||
{
|
||||
txt[0] = '\0';
|
||||
*txtlenp = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*txtlenp = codepoint_to_utf8(cell.codepoint, txt);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
bad:
|
||||
*txtlenp = 0;
|
||||
txt[0] = '\0';
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *
|
||||
termio_link_find(Evas_Object *obj, int cx, int cy,
|
||||
int *x1r, int *y1r, int *x2r, int *y2r)
|
||||
{
|
||||
char *s;
|
||||
char *s = NULL;
|
||||
char endmatch = 0;
|
||||
int x1, x2, y1, y2, w = 0, h = 0, sc;
|
||||
size_t len = 0, prev_len = 0;
|
||||
Eina_Bool goback = EINA_TRUE, goforward = EINA_FALSE, escaped = EINA_FALSE;
|
||||
struct ty_sb sb = {.buf = NULL, .gap = 0, .len = 0, .alloc = 0};
|
||||
Termpty *ty = termio_pty_get(obj);
|
||||
int res;
|
||||
char txt[8];
|
||||
int txtlen = 0;
|
||||
Eina_Bool was_protocol = EINA_FALSE;
|
||||
|
||||
x1 = x2 = cx;
|
||||
y1 = y2 = cy;
|
||||
termio_size_get(obj, &w, &h);
|
||||
if ((w <= 0) || (h <= 0)) return NULL;
|
||||
if ((w <= 0) || (h <= 0)) goto end;
|
||||
|
||||
sc = termio_scroll_get(obj);
|
||||
for (;;)
|
||||
|
||||
termpty_backlog_lock();
|
||||
|
||||
y1 -= sc;
|
||||
y2 -= sc;
|
||||
|
||||
res = _txt_at(ty, &x1, &y1, txt, &txtlen);
|
||||
if ((res != 0) || (txtlen == 0)) goto end;
|
||||
ty_sb_add(&sb, txt, txtlen);
|
||||
|
||||
while (goback)
|
||||
{
|
||||
prev_len = len;
|
||||
s = termio_selection_get(obj, x1, y1 - sc, x2, y2 - sc, &len, EINA_FALSE);
|
||||
if (!s) break;
|
||||
if (goback)
|
||||
{
|
||||
if (link_is_protocol(s))
|
||||
{
|
||||
goback = EINA_FALSE;
|
||||
goforward = EINA_TRUE;
|
||||
int new_x1 = x1, new_y1 = y1;
|
||||
|
||||
/* Check if the previous char is a delimiter */
|
||||
coord_back(&x1, &y1, w, h);
|
||||
free(s);
|
||||
s = termio_selection_get(obj, x1, y1 - sc, x2, y2 - sc,
|
||||
&len, EINA_FALSE);
|
||||
if (!s) break;
|
||||
switch (s[0])
|
||||
{
|
||||
case '"': endmatch = '"'; break;
|
||||
case '\'': endmatch = '\''; break;
|
||||
case '`': endmatch = '`'; break;
|
||||
case '<': endmatch = '>'; break;
|
||||
case '[': endmatch = ']'; break;
|
||||
case '{': endmatch = '}'; break;
|
||||
case '(': endmatch = ')'; break;
|
||||
}
|
||||
if (!(x1 == 0 && y1 == 0))
|
||||
{
|
||||
coord_forward(&x1, &y1, w, h);
|
||||
|
||||
free(s);
|
||||
prev_len = len;
|
||||
s = termio_selection_get(obj, x1, y1 - sc, x2, y2 - sc,
|
||||
&len, EINA_FALSE);
|
||||
if (!s) break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (s[0])
|
||||
{
|
||||
case '"': endmatch = '"'; break;
|
||||
case '\'': endmatch = '\''; break;
|
||||
case '`': endmatch = '`'; break;
|
||||
case '<': endmatch = '>'; break;
|
||||
case '[': endmatch = ']'; break;
|
||||
case '{': endmatch = '}'; break;
|
||||
case '(': endmatch = ')'; break;
|
||||
}
|
||||
if ((endmatch) || (isspace(s[0])))
|
||||
{
|
||||
goback = EINA_FALSE;
|
||||
coord_forward(&x1, &y1, w, h);
|
||||
goforward = EINA_TRUE;
|
||||
free(s);
|
||||
s = termio_selection_get(obj, x1, y1 - sc, x2, y2 - sc,
|
||||
&len, EINA_FALSE);
|
||||
if (!s) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((goforward) && (len >= 1))
|
||||
{
|
||||
char end = s[len - 1];
|
||||
if (len - prev_len == 2 && len >= 2)
|
||||
end = s[len - 2];
|
||||
|
||||
if ((end == endmatch) ||
|
||||
((!escaped) && (isspace(end))))
|
||||
{
|
||||
goforward = EINA_FALSE;
|
||||
coord_back(&x2, &y2, w, h);
|
||||
endmatch = 0;
|
||||
}
|
||||
escaped = (end == '\\');
|
||||
}
|
||||
if ((goback) && (!coord_back(&x1, &y1, w, h)))
|
||||
res = _txt_prev_at(ty, &new_x1, &new_y1, txt, &txtlen);
|
||||
if ((res != 0) || (txtlen == 0))
|
||||
{
|
||||
goback = EINA_FALSE;
|
||||
goforward = EINA_TRUE;
|
||||
}
|
||||
if ((goforward) && (!coord_forward(&x2, &y2, w, h)))
|
||||
ty_sb_prepend(&sb, txt, txtlen);
|
||||
if (isspace(sb.buf[0]))
|
||||
{
|
||||
goforward = EINA_FALSE;
|
||||
}
|
||||
if ((!goback) && (!goforward))
|
||||
{
|
||||
free(s);
|
||||
s = termio_selection_get(obj, x1, y1 - sc, x2, y2 - sc, &len,
|
||||
EINA_FALSE);
|
||||
break;
|
||||
}
|
||||
free(s);
|
||||
s = NULL;
|
||||
}
|
||||
if (s)
|
||||
{
|
||||
if ((len > 1) && (!endmatch))
|
||||
{
|
||||
Eina_Bool is_file = _is_file(s);
|
||||
|
||||
if (is_file ||
|
||||
link_is_email(s) ||
|
||||
link_is_url(s))
|
||||
int old_txtlen = txtlen;
|
||||
res = _txt_prev_at(ty, &new_x1, &new_y1, txt, &txtlen);
|
||||
if ((res != 0) || (txtlen == 0))
|
||||
{
|
||||
if (x1r) *x1r = x1;
|
||||
if (y1r) *y1r = y1;
|
||||
if (x2r) *x2r = x2;
|
||||
if (y2r) *y2r = y2;
|
||||
|
||||
if (is_file && (s[0] != '/'))
|
||||
{
|
||||
char *ret = _local_path_get(obj, s);
|
||||
free(s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return s;
|
||||
goback = EINA_FALSE;
|
||||
goforward = EINA_TRUE;
|
||||
break;
|
||||
}
|
||||
if (txt[0] != '\\')
|
||||
{
|
||||
ty_sb_lskip(&sb, old_txtlen);
|
||||
goback = EINA_FALSE;
|
||||
goforward = EINA_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(s);
|
||||
switch (sb.buf[0])
|
||||
{
|
||||
case '"': endmatch = '"'; break;
|
||||
case '\'': endmatch = '\''; break;
|
||||
case '`': endmatch = '`'; break;
|
||||
case '<': endmatch = '>'; break;
|
||||
case '[': endmatch = ']'; break;
|
||||
case '{': endmatch = '}'; break;
|
||||
case '(': endmatch = ')'; break;
|
||||
case '|': endmatch = '|'; break;
|
||||
}
|
||||
if (endmatch)
|
||||
{
|
||||
ty_sb_lskip(&sb, txtlen);
|
||||
goback = EINA_FALSE;
|
||||
goforward = EINA_TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!link_is_protocol(sb.buf))
|
||||
{
|
||||
if (was_protocol)
|
||||
{
|
||||
if (!isspace(sb.buf[0]))
|
||||
endmatch = sb.buf[0];
|
||||
ty_sb_lskip(&sb, txtlen);
|
||||
goback = EINA_FALSE;
|
||||
goforward = EINA_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
was_protocol = EINA_TRUE;
|
||||
}
|
||||
x1 = new_x1;
|
||||
y1 = new_y1;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
while (goforward)
|
||||
{
|
||||
int new_x2 = x2, new_y2 = y2;
|
||||
/* Check if the previous char is a delimiter */
|
||||
res = _txt_next_at(ty, &new_x2, &new_y2, txt, &txtlen);
|
||||
if ((res != 0) || (txtlen == 0))
|
||||
{
|
||||
goforward = EINA_FALSE;
|
||||
break;
|
||||
}
|
||||
/* escaping */
|
||||
if (txt[0] == '\\')
|
||||
{
|
||||
x2 = new_x2;
|
||||
y2 = new_y2;
|
||||
escaped = EINA_TRUE;
|
||||
continue;
|
||||
}
|
||||
if (escaped)
|
||||
{
|
||||
x2 = new_x2;
|
||||
y2 = new_y2;
|
||||
escaped = EINA_FALSE;
|
||||
}
|
||||
|
||||
if (isspace(txt[0]) || txt[0] == endmatch)
|
||||
{
|
||||
goforward = EINA_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
ty_sb_add(&sb, txt, txtlen);
|
||||
|
||||
if (!link_is_protocol(sb.buf))
|
||||
{
|
||||
if (was_protocol)
|
||||
{
|
||||
ty_sb_rskip(&sb, txtlen);
|
||||
goback = EINA_FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
was_protocol = EINA_TRUE;
|
||||
}
|
||||
x2 = new_x2;
|
||||
y2 = new_y2;
|
||||
}
|
||||
|
||||
if (sb.len)
|
||||
{
|
||||
Eina_Bool is_file = _is_file(sb.buf);
|
||||
|
||||
if (is_file ||
|
||||
link_is_email(sb.buf) ||
|
||||
link_is_url(sb.buf))
|
||||
{
|
||||
if (x1r) *x1r = x1;
|
||||
if (y1r) *y1r = y1 + sc;
|
||||
if (x2r) *x2r = x2;
|
||||
if (y2r) *y2r = y2 + sc;
|
||||
|
||||
if (is_file && (sb.buf[0] != '/'))
|
||||
{
|
||||
char *local= _local_path_get(obj, (const char*)sb.buf);
|
||||
ty_sb_free(&sb);
|
||||
s = local;
|
||||
goto end;
|
||||
}
|
||||
else
|
||||
{
|
||||
s = ty_sb_steal_buf(&sb);
|
||||
}
|
||||
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
end:
|
||||
termpty_backlog_unlock();
|
||||
ty_sb_free(&sb);
|
||||
return s;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue