forked from enlightenment/terminology
451 lines
10 KiB
C
451 lines
10 KiB
C
#include "private.h"
|
|
#include <Elementary.h>
|
|
#include "termio.h"
|
|
#include "termiolink.h"
|
|
#include "termpty.h"
|
|
#include "termptyops.h"
|
|
#include "termiointernals.h"
|
|
#include "tytest.h"
|
|
#include <assert.h>
|
|
|
|
#undef CRITICAL
|
|
#undef ERR
|
|
#undef WRN
|
|
#undef INF
|
|
#undef DBG
|
|
|
|
#define CRITICAL(...) EINA_LOG_DOM_CRIT(_termpty_log_dom, __VA_ARGS__)
|
|
#define ERR(...) EINA_LOG_DOM_ERR(_termpty_log_dom, __VA_ARGS__)
|
|
#define WRN(...) EINA_LOG_DOM_WARN(_termpty_log_dom, __VA_ARGS__)
|
|
#define INF(...) EINA_LOG_DOM_INFO(_termpty_log_dom, __VA_ARGS__)
|
|
#define DBG(...) EINA_LOG_DOM_DBG(_termpty_log_dom, __VA_ARGS__)
|
|
|
|
//// extended terminology escape handling goes in here
|
|
//
|
|
// this is where escapes get handled *IF* the termpty layer needs to interpret
|
|
// them itself for some reason. if it returns EINA_FALSE, it means the escape
|
|
// is to be passed onto termio layer as a callback and handled there after
|
|
// this code. an extended escape may be handled in here exclusively (return
|
|
// EINA_TRUE), handled here first, then in termio (EINA_FALSE return) or not
|
|
// handled here at all and just passed to termio to figure it out (return
|
|
// EINA_FALSE).
|
|
|
|
#if defined(ENABLE_TESTS) || defined(ENABLE_TEST_UI)
|
|
|
|
static int
|
|
_tytest_arg_get(const Eina_Unicode *buf, int *value)
|
|
{
|
|
int len = 0;
|
|
int sum = 0;
|
|
|
|
if (*buf == ';')
|
|
{
|
|
len++;
|
|
}
|
|
|
|
while (buf[len] >= '0' && buf[len] <= '9')
|
|
{
|
|
sum *= 10;
|
|
sum += buf[len] - '0';
|
|
len++;
|
|
}
|
|
*value = sum;
|
|
return len;
|
|
}
|
|
|
|
/**
|
|
* MODIFIERS is a bit field with the following values:
|
|
* - Alt
|
|
* - Shift
|
|
* - Ctrl
|
|
* - Super
|
|
* - Meta
|
|
* - Hyper
|
|
* - ISO_Level3_Shift
|
|
* - AltGr
|
|
*/
|
|
static int
|
|
_tytest_modifiers_get(const Eina_Unicode *buf, Termio_Modifiers *m)
|
|
{
|
|
Termio_Modifiers modifier = {};
|
|
int value = 0;
|
|
int len = _tytest_arg_get(buf, &value);
|
|
|
|
modifier.alt = !!(value & (1 << 0));
|
|
modifier.shift = !!(value & (1 << 1));
|
|
modifier.ctrl = !!(value & (1 << 2));
|
|
modifier.super = !!(value & (1 << 3));
|
|
modifier.meta = !!(value & (1 << 4));
|
|
modifier.hyper = !!(value & (1 << 5));
|
|
modifier.iso_level3_shift = !!(value & (1 << 6));
|
|
modifier.altgr = !!(value & (1 << 7));
|
|
|
|
*m = modifier;
|
|
return len;
|
|
}
|
|
|
|
/**
|
|
* FLAGS can be:
|
|
* - 0
|
|
* - 1: DOUBLE_CLICK
|
|
* - 2: TRIPLE_CLICK
|
|
*/
|
|
|
|
/*
|
|
* Format is td;X;Y;BUTTON;MODIFIERS;FLAGS
|
|
*/
|
|
static void
|
|
_handle_mouse_down(Termpty *ty,
|
|
const Eina_Unicode *buf)
|
|
{
|
|
Evas_Event_Mouse_Down ev = {};
|
|
Termio *sd = termio_get_from_obj(ty->obj);
|
|
Termio_Modifiers modifiers = {};
|
|
int value;
|
|
|
|
/* X */
|
|
value = 0;
|
|
buf += _tytest_arg_get(buf, &value);
|
|
ev.canvas.x = value;
|
|
/* Y */
|
|
value = 0;
|
|
buf += _tytest_arg_get(buf, &value);
|
|
ev.canvas.y = value;
|
|
/* BUTTON */
|
|
value = 0;
|
|
buf += _tytest_arg_get(buf, &value);
|
|
ev.button = value;
|
|
/* MODIFIERS */
|
|
buf += _tytest_modifiers_get(buf, &modifiers);
|
|
/* FLAGS */
|
|
value = 0;
|
|
buf +=_tytest_arg_get(buf, &value);
|
|
ev.flags = value;
|
|
|
|
termio_internal_mouse_down(sd, &ev, modifiers);
|
|
}
|
|
|
|
/*
|
|
* Format is tu;X;Y;BUTTON;MODIFIERS;FLAGS
|
|
*/
|
|
static void
|
|
_handle_mouse_up(Termpty *ty,
|
|
const Eina_Unicode *buf)
|
|
{
|
|
Evas_Event_Mouse_Up ev = {};
|
|
Termio *sd = termio_get_from_obj(ty->obj);
|
|
Termio_Modifiers modifiers = {};
|
|
int value;
|
|
|
|
/* X */
|
|
value = 0;
|
|
buf += _tytest_arg_get(buf, &value);
|
|
ev.canvas.x = value;
|
|
/* Y */
|
|
value = 0;
|
|
buf += _tytest_arg_get(buf, &value);
|
|
ev.canvas.y = value;
|
|
/* BUTTON */
|
|
value = 0;
|
|
buf += _tytest_arg_get(buf, &value);
|
|
ev.button = value;
|
|
/* MODIFIERS */
|
|
buf += _tytest_modifiers_get(buf, &modifiers);
|
|
/* FLAGS */
|
|
value = 0;
|
|
buf +=_tytest_arg_get(buf, &value);
|
|
ev.flags = value;
|
|
|
|
termio_internal_mouse_up(sd, &ev, modifiers);
|
|
}
|
|
|
|
/*
|
|
* Format is tm;X;Y;MODIFIERS
|
|
*/
|
|
static void
|
|
_handle_mouse_move(Termpty *ty,
|
|
const Eina_Unicode *buf)
|
|
{
|
|
Evas_Event_Mouse_Move ev = {};
|
|
Termio *sd = termio_get_from_obj(ty->obj);
|
|
Termio_Modifiers modifiers = {};
|
|
int value;
|
|
|
|
/* X */
|
|
value = 0;
|
|
buf += _tytest_arg_get(buf, &value);
|
|
ev.cur.canvas.x = value;
|
|
/* Y */
|
|
value = 0;
|
|
buf += _tytest_arg_get(buf, &value);
|
|
ev.cur.canvas.y = value;
|
|
/* MODIFIERS */
|
|
buf += _tytest_modifiers_get(buf, &modifiers);
|
|
|
|
termio_internal_mouse_move(sd, &ev, modifiers);
|
|
}
|
|
|
|
/*
|
|
* Format is tw;X;Y;DIRECTION;VALUE;MODIFIERS
|
|
* DIRECTION: 1 to go up, 0 to go down
|
|
*/
|
|
static void
|
|
_handle_mouse_wheel(Termpty *ty,
|
|
const Eina_Unicode *buf)
|
|
{
|
|
Evas_Event_Mouse_Wheel ev = {};
|
|
Termio *sd = termio_get_from_obj(ty->obj);
|
|
Termio_Modifiers modifiers = {};
|
|
int value;
|
|
|
|
/* X */
|
|
value = 0;
|
|
buf += _tytest_arg_get(buf, &value);
|
|
ev.canvas.x = value;
|
|
/* Y */
|
|
value = 0;
|
|
buf += _tytest_arg_get(buf, &value);
|
|
ev.canvas.y = value;
|
|
/* DIRECTION */
|
|
value = 0;
|
|
buf += _tytest_arg_get(buf, &value);
|
|
ev.z = (value == 0)? 1 : -1;
|
|
/* VALUE */
|
|
value = 0;
|
|
buf += _tytest_arg_get(buf, &value);
|
|
ev.z *= value;
|
|
/* MODIFIERS */
|
|
buf += _tytest_modifiers_get(buf, &modifiers);
|
|
|
|
termio_internal_mouse_wheel(sd, &ev, modifiers);
|
|
}
|
|
|
|
/*
|
|
* Format is:
|
|
* - ln : no link found under cursor
|
|
* - lT;X1;Y1;X2;Y2;LINK
|
|
* where T is
|
|
* e: link is an email
|
|
* u: link is an url
|
|
* p: link is a file path
|
|
*/
|
|
static void
|
|
_handle_link(Termpty *ty, const Eina_Unicode *buf)
|
|
{
|
|
const Eina_Unicode type = buf[0];
|
|
Termio *sd = termio_get_from_obj(ty->obj);
|
|
char *link, *c;
|
|
int x1 = -1, y1 = -1, x2 = -1, y2 = -1;
|
|
int value;
|
|
|
|
/* highlight where the mouse is */
|
|
{
|
|
Termcell *cells = NULL;
|
|
ssize_t w;
|
|
|
|
cells = termpty_cellrow_get(ty, sd->mouse.cy, &w);
|
|
termpty_reset_att(&cells[sd->mouse.cx].att);
|
|
cells[sd->mouse.cx].att.bold = 1;
|
|
cells[sd->mouse.cx].att.fg = COL_WHITE;
|
|
cells[sd->mouse.cx].att.bg = COL_RED;
|
|
}
|
|
|
|
link = termio_link_find(ty->obj, sd->mouse.cx, sd->mouse.cy,
|
|
&x1, &y1, &x2, &y2);
|
|
|
|
ERR("x1:%d y1:%d x2:%d y2:%d link:'%s'", x1, y1, x2, y2, link);
|
|
if (type == 'n')
|
|
{
|
|
assert (link == NULL);
|
|
return;
|
|
}
|
|
/* skip type */
|
|
buf++;
|
|
/* Get numeric values */
|
|
buf += _tytest_arg_get(buf, &value);
|
|
assert(x1 == value);
|
|
buf += _tytest_arg_get(buf, &value);
|
|
assert(y1 == value);
|
|
buf += _tytest_arg_get(buf, &value);
|
|
assert(x2 == value);
|
|
buf += _tytest_arg_get(buf, &value);
|
|
assert(y2 == value);
|
|
/* skip ; */
|
|
buf++;
|
|
/* Compare strings */
|
|
c = link;
|
|
while (*buf)
|
|
{
|
|
int idx = 0;
|
|
Eina_Unicode u = eina_unicode_utf8_next_get(c, &idx);
|
|
|
|
ERR("%c vs %c", *buf, u);
|
|
assert(*buf == u && "unexpected character in selection");
|
|
c += idx;
|
|
buf++;
|
|
}
|
|
|
|
switch (type)
|
|
{
|
|
case 'u':
|
|
assert(link_is_url(link));
|
|
break;
|
|
case 'p':
|
|
assert(link_is_file(link));
|
|
break;
|
|
case 'e':
|
|
assert(link_is_email(link));
|
|
break;
|
|
default:
|
|
abort();
|
|
}
|
|
free(link);
|
|
}
|
|
|
|
static void
|
|
_handle_selection_is(Termpty *ty,
|
|
const Eina_Unicode *buf)
|
|
{
|
|
size_t len = 0;
|
|
Termio *sd;
|
|
const char *sel, *s;
|
|
|
|
assert(ty->selection.is_active);
|
|
|
|
sd = termio_get_from_obj(ty->obj);
|
|
sel = s = termio_internal_get_selection(sd, &len);
|
|
|
|
assert(s != NULL && "no selection");
|
|
|
|
while (*buf)
|
|
{
|
|
int idx = 0;
|
|
Eina_Unicode u = eina_unicode_utf8_next_get(s, &idx);
|
|
|
|
/* skip spurious carriage returns */
|
|
if (*buf != '\r')
|
|
{
|
|
assert(*buf == u && "unexpected character in selection");
|
|
s += idx;
|
|
}
|
|
buf++;
|
|
}
|
|
eina_stringshare_del(sel);
|
|
}
|
|
|
|
static void
|
|
_handle_force_render(Termpty *ty)
|
|
{
|
|
int preedit_x = 0, preedit_y = 0;
|
|
Termio *sd = termio_get_from_obj(ty->obj);
|
|
|
|
termio_internal_render(sd, 0, 0, &preedit_x, &preedit_y);
|
|
}
|
|
|
|
/*
|
|
* Format is tc;C;V
|
|
* where C is 0 for top-left, 1 for down-right
|
|
* and V is 0 to unset, 1 to set
|
|
*/
|
|
static void
|
|
_handle_corner(Termpty *ty, const Eina_Unicode *buf)
|
|
{
|
|
Termio *sd = termio_get_from_obj(ty->obj);
|
|
int value;
|
|
int corner;
|
|
|
|
/* C */
|
|
corner = 0;
|
|
buf += _tytest_arg_get(buf, &corner);
|
|
|
|
/* V */
|
|
value = 0;
|
|
buf += _tytest_arg_get(buf, &value);
|
|
|
|
if (corner == 0)
|
|
{
|
|
sd->top_left = !! value;
|
|
}
|
|
else
|
|
{
|
|
sd->bottom_right = !! value;
|
|
}
|
|
}
|
|
|
|
/* Testing escape codes that start with '\033}t' and end with '\0'
|
|
* Then,
|
|
* - 'c': set/unset top-left/down-right
|
|
* - 'd': mouse down:
|
|
* - 'u': mouse up;
|
|
* - 'm': mouse move;
|
|
* - 'l': assert mouse is over a link
|
|
* - 'r': force rendering and possibly remove selection;
|
|
* - 'n': assert there is no selection
|
|
* - 's': assert selection is what follows till '\0'
|
|
*/
|
|
static void
|
|
tytest_handle_escape_codes(Termpty *ty,
|
|
const Eina_Unicode *buf)
|
|
{
|
|
switch (buf[0])
|
|
{
|
|
case 'c':
|
|
_handle_corner(ty, buf + 1);
|
|
break;
|
|
case 'd':
|
|
_handle_mouse_down(ty, buf + 1);
|
|
break;
|
|
case 'l':
|
|
_handle_link(ty, buf + 1);
|
|
break;
|
|
case 'm':
|
|
_handle_mouse_move(ty, buf + 1);
|
|
break;
|
|
case 'n':
|
|
assert(!ty->selection.is_active);
|
|
break;
|
|
case 'r':
|
|
_handle_force_render(ty);
|
|
break;
|
|
case 's':
|
|
_handle_selection_is(ty, buf + 1);
|
|
break;
|
|
case 'u':
|
|
_handle_mouse_up(ty, buf + 1);
|
|
break;
|
|
case 'w':
|
|
_handle_mouse_wheel(ty, buf + 1);
|
|
break;
|
|
default:
|
|
abort();
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(ENABLE_TESTS) || defined(ENABLE_TEST_UI)
|
|
#define ARG_USED_FOR_TESTS
|
|
#else
|
|
#define ARG_USED_FOR_TESTS EINA_UNUSED
|
|
#endif
|
|
|
|
Eina_Bool
|
|
termpty_ext_handle(Termpty *ty ARG_USED_FOR_TESTS,
|
|
const Eina_Unicode *buf ARG_USED_FOR_TESTS,
|
|
size_t blen EINA_UNUSED)
|
|
{
|
|
switch (buf[0]) // major opcode
|
|
{
|
|
#if defined(ENABLE_TESTS) || defined(ENABLE_TEST_UI)
|
|
case 't':
|
|
tytest_handle_escape_codes(ty, buf + 1);
|
|
return EINA_TRUE;
|
|
break;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
return EINA_FALSE;
|
|
}
|
|
#undef ARG_USED_FOR_TESTS
|