aboutsummaryrefslogtreecommitdiffstats
path: root/src/bin/termiolink.c
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 /src/bin/termiolink.c
parentsb: add some utilities like prepend, free, steal… (diff)
downloadterminology-0cbaaeec9d991ca41576b780dbb1564707bc3a8d.tar.gz
link: rewrite link detection to be more efficient
Diffstat (limited to 'src/bin/termiolink.c')
-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 @@
#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)
+ int new_x1 = x1, new_y1 = y1;
+
+ res = _txt_prev_at(ty, &new_x1, &new_y1, txt, &txtlen);
+ if ((res != 0) || (txtlen == 0))
+ {
+ goback = EINA_FALSE;
+ goforward = EINA_TRUE;
+ }
+ ty_sb_prepend(&sb, txt, txtlen);
+ if (isspace(sb.buf[0]))
{
- if (link_is_protocol(s))
+ int old_txtlen = txtlen;
+ res = _txt_prev_at(ty, &new_x1, &new_y1, txt, &txtlen);
+ if ((res != 0) || (txtlen == 0))
{
goback = EINA_FALSE;
goforward = EINA_TRUE;
-
- /* 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;
- }
+ break;
}
- else
+ if (txt[0] != '\\')
{
- 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;
- }
+ ty_sb_lskip(&sb, old_txtlen);
+ goback = EINA_FALSE;
+ goforward = EINA_TRUE;
+ break;
}
}
- if ((goforward) && (len >= 1))
+ 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)
{
- char end = s[len - 1];
- if (len - prev_len == 2 && len >= 2)
- end = s[len - 2];
+ ty_sb_lskip(&sb, txtlen);
+ goback = EINA_FALSE;
+ goforward = EINA_TRUE;
+ break;
+ }
- if ((end == endmatch) ||
- ((!escaped) && (isspace(end))))
+ if (!link_is_protocol(sb.buf))
+ {
+ if (was_protocol)
{
- goforward = EINA_FALSE;
- coord_back(&x2, &y2, w, h);
- endmatch = 0;
+ if (!isspace(sb.buf[0]))
+ endmatch = sb.buf[0];
+ ty_sb_lskip(&sb, txtlen);
+ goback = EINA_FALSE;
+ goforward = EINA_TRUE;
+ break;
}
- escaped = (end == '\\');
}
- if ((goback) && (!coord_back(&x1, &y1, w, h)))
+ else
{
- goback = EINA_FALSE;
- goforward = EINA_TRUE;
+ was_protocol = EINA_TRUE;
}
- if ((goforward) && (!coord_forward(&x2, &y2, w, h)))
+ x1 = new_x1;
+ y1 = new_y1;
+ }
+
+ 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 ((!goback) && (!goforward))
+ if (escaped)
{
- free(s);
- s = termio_selection_get(obj, x1, y1 - sc, x2, y2 - sc, &len,
- EINA_FALSE);
+ x2 = new_x2;
+ y2 = new_y2;
+ escaped = EINA_FALSE;
+ }
+
+ if (isspace(txt[0]) || txt[0] == endmatch)
+ {
+ goforward = EINA_FALSE;
break;
}
- free(s);
- s = NULL;
+
+ 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 (s)
+
+ if (sb.len)
{
- if ((len > 1) && (!endmatch))
+ Eina_Bool is_file = _is_file(sb.buf);
+
+ if (is_file ||
+ link_is_email(sb.buf) ||
+ link_is_url(sb.buf))
{
- Eina_Bool is_file = _is_file(s);
+ if (x1r) *x1r = x1;
+ if (y1r) *y1r = y1 + sc;
+ if (x2r) *x2r = x2;
+ if (y2r) *y2r = y2 + sc;
- if (is_file ||
- link_is_email(s) ||
- link_is_url(s))
+ if (is_file && (sb.buf[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;
+ 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;
}
- free(s);
}
- return NULL;
+end:
+ termpty_backlog_unlock();
+ ty_sb_free(&sb);
+ return s;
}