parent
43ad696570
commit
cc83e6b6f2
|
@ -1,5 +1,6 @@
|
|||
#include "private.h"
|
||||
#include <Elementary.h>
|
||||
#include "termiolink.h"
|
||||
#include "termio.h"
|
||||
#include "sb.h"
|
||||
#include "utf8.h"
|
||||
|
@ -429,3 +430,101 @@ end:
|
|||
ty_sb_free(&sb);
|
||||
return s;
|
||||
}
|
||||
|
||||
/* 0 means error here */
|
||||
static uint16_t
|
||||
_find_empty_slot(const Termpty *ty)
|
||||
{
|
||||
int pos;
|
||||
int max_pos = HL_LINKS_MAX / 8;
|
||||
|
||||
for (pos = 0; pos < max_pos && ty->hl.bitmap[pos] == 0xff; pos++)
|
||||
{
|
||||
}
|
||||
|
||||
if (pos <= max_pos)
|
||||
{
|
||||
int bit;
|
||||
for (bit = 0; bit < 8; bit++)
|
||||
{
|
||||
if (!(ty->hl.bitmap[pos] & (1<<bit)))
|
||||
{
|
||||
return pos * 8 + bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
hl_bitmap_set_bit(Termpty *ty, uint16_t id)
|
||||
{
|
||||
uint8_t *pos = &ty->hl.bitmap[id / 8];
|
||||
uint8_t bit = 1 << (id % 8);
|
||||
|
||||
*pos |= bit;
|
||||
}
|
||||
|
||||
static void
|
||||
hl_bitmap_clear_bit(Termpty *ty, uint16_t id)
|
||||
{
|
||||
uint8_t *pos = &ty->hl.bitmap[id / 8];
|
||||
uint8_t bit = 1 << (id % 8);
|
||||
|
||||
*pos &= ~bit;
|
||||
}
|
||||
|
||||
Term_Link *
|
||||
term_link_new(Termpty *ty)
|
||||
{
|
||||
uint16_t id;
|
||||
Term_Link *link;
|
||||
|
||||
/* 1st/ Find empty slot in bitmap */
|
||||
id = _find_empty_slot(ty);
|
||||
if (!id)
|
||||
{
|
||||
ERR("hyper links: can't find empty slot");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 2nd/ Do we need to realloc? */
|
||||
if (id >= ty->hl.size)
|
||||
{
|
||||
Term_Link *links;
|
||||
uint16_t old_size = ty->hl.size;
|
||||
|
||||
if (!ty->hl.size)
|
||||
ty->hl.size = 256;
|
||||
links = realloc(ty->hl.links,
|
||||
ty->hl.size * 2 * sizeof(Term_Link));
|
||||
if (!links)
|
||||
return NULL;
|
||||
ty->hl.size *= 2;
|
||||
ty->hl.links = links;
|
||||
memset(ty->hl.links + old_size,
|
||||
0,
|
||||
(ty->hl.size - old_size) * sizeof(Term_Link));
|
||||
}
|
||||
|
||||
link = ty->hl.links + id;
|
||||
link->key = NULL;
|
||||
link->url = NULL;
|
||||
link->refcount = 0;
|
||||
|
||||
/* Mark in bitmap */
|
||||
hl_bitmap_set_bit(ty, id);
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
void
|
||||
term_link_free(Term_Link *link, Termpty *ty)
|
||||
{
|
||||
if (!link)
|
||||
return;
|
||||
uint16_t id = (link - ty->hl.links);
|
||||
|
||||
/* Remove from bitmap */
|
||||
hl_bitmap_clear_bit(ty, id);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
#ifndef _TERMIO_LINK_H__
|
||||
#define _TERMIO_LINK_H__ 1
|
||||
|
||||
#define HL_LINKS_MAX (1 << 16)
|
||||
|
||||
typedef struct _Termlink Term_Link;
|
||||
|
||||
struct _Termlink
|
||||
{
|
||||
char *key;
|
||||
char *url;
|
||||
unsigned int refcount;
|
||||
};
|
||||
|
||||
|
||||
char *termio_link_find(const Evas_Object *obj, int cx, int cy, int *x1r, int *y1r, int *x2r, int *y2r);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -509,6 +509,16 @@ termpty_new(const char *cmd, Eina_Bool login_shell, const char *cd,
|
|||
goto err;
|
||||
}
|
||||
|
||||
ty->hl.bitmap = calloc(1, HL_LINKS_MAX / 8); /* bit map for 1 << 16 elements */
|
||||
if (!ty->hl.bitmap)
|
||||
{
|
||||
ERR("Allocation of %d bytes failed: %s",
|
||||
HL_LINKS_MAX / 8, strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
/* Mark id 0 as set */
|
||||
ty->hl.bitmap[0] = 1;
|
||||
|
||||
termpty_resize_tabs(ty, 0, w);
|
||||
|
||||
termpty_reset_state(ty);
|
||||
|
@ -739,6 +749,7 @@ termpty_new(const char *cmd, Eina_Bool login_shell, const char *cd,
|
|||
err:
|
||||
free(ty->screen);
|
||||
free(ty->screen2);
|
||||
free(ty->hl.bitmap);
|
||||
if (ty->fd >= 0) close(ty->fd);
|
||||
if (ty->slavefd >= 0) close(ty->slavefd);
|
||||
free(ty);
|
||||
|
@ -811,6 +822,20 @@ termpty_free(Termpty *ty)
|
|||
}
|
||||
free(ty->screen);
|
||||
free(ty->screen2);
|
||||
if (ty->hl.links)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
for (i = 0; i < ty->hl.size; i++)
|
||||
{
|
||||
Term_Link *l = ty->hl.links + i;
|
||||
|
||||
free(l->key);
|
||||
free(l->url);
|
||||
}
|
||||
free(ty->hl.links);
|
||||
}
|
||||
free(ty->hl.bitmap);
|
||||
free(ty->buf);
|
||||
free(ty->tabs);
|
||||
free(ty);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "config.h"
|
||||
#include "media.h"
|
||||
#include "termiolink.h"
|
||||
|
||||
typedef struct _Termpty Termpty;
|
||||
typedef struct _Termcell Termcell;
|
||||
|
@ -74,6 +75,7 @@ struct _Termatt
|
|||
#else
|
||||
unsigned short bit_padding : 12;
|
||||
#endif
|
||||
uint16_t link_id;
|
||||
};
|
||||
|
||||
struct _Termpty
|
||||
|
@ -175,13 +177,17 @@ struct _Termpty
|
|||
unsigned int mouse_mode : 3;
|
||||
unsigned int mouse_ext : 2;
|
||||
unsigned int bracketed_paste : 1;
|
||||
struct {
|
||||
Term_Link *links;
|
||||
uint8_t *bitmap;
|
||||
uint16_t size;
|
||||
} hl;
|
||||
};
|
||||
|
||||
struct _Termcell
|
||||
{
|
||||
Eina_Unicode codepoint;
|
||||
Termatt att;
|
||||
unsigned char padding[2];
|
||||
};
|
||||
|
||||
struct _Termsave
|
||||
|
@ -310,4 +316,10 @@ do { \
|
|||
} while (0)
|
||||
|
||||
|
||||
Term_Link *
|
||||
term_link_new(Termpty *ty);
|
||||
|
||||
void
|
||||
term_link_free(Term_Link *link, Termpty *ty);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1801,6 +1801,94 @@ err:
|
|||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
_handle_hyperlink(Termpty *ty,
|
||||
char *s,
|
||||
int len)
|
||||
{
|
||||
char *url = NULL;
|
||||
char *key = NULL;
|
||||
Term_Link *hl = NULL;
|
||||
|
||||
if (!s || len <= 0)
|
||||
{
|
||||
ERR("invalid hyperlink escape code (len:%d s:%p)",
|
||||
len, s);
|
||||
return;
|
||||
}
|
||||
|
||||
if (len == 1 && *s == ';')
|
||||
{
|
||||
/* Closing escape code */
|
||||
if (ty->termstate.att.link_id)
|
||||
{
|
||||
ty->termstate.att.link_id = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("invalid hyperlink escape code: no hyperlink to close"
|
||||
" (len:%d s:%.*s)", len, len, s);
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (*s != ';')
|
||||
{
|
||||
/* Parse parameters */
|
||||
char *end;
|
||||
|
||||
/* /!\ we expect ';' and ':' to be escaped in params */
|
||||
end = memchr(s+1, ';', len);
|
||||
*end = '\0';
|
||||
do
|
||||
{
|
||||
char *end_param;
|
||||
|
||||
end_param = strchrnul(s, ':');
|
||||
|
||||
if (len > 3 && strncmp(s, "id=", 3) == 0)
|
||||
{
|
||||
free(key);
|
||||
|
||||
s += 3;
|
||||
len -= 3;
|
||||
key = strndup(s, end_param - s);
|
||||
}
|
||||
len -= end_param - s;
|
||||
s = end_param;
|
||||
if (*end_param)
|
||||
{
|
||||
s++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
while (s < end);
|
||||
*end = ';';
|
||||
}
|
||||
s++;
|
||||
len--;
|
||||
|
||||
url = strndup(s, len);
|
||||
if (!url)
|
||||
goto end;
|
||||
|
||||
hl = term_link_new(ty);
|
||||
if (!hl)
|
||||
goto end;
|
||||
hl->key = key;
|
||||
hl->url = url;
|
||||
key = NULL;
|
||||
url = NULL;
|
||||
|
||||
ty->termstate.att.link_id = hl - ty->hl.links;
|
||||
hl = NULL;
|
||||
|
||||
end:
|
||||
term_link_free(hl, ty);
|
||||
free(url);
|
||||
free(key);
|
||||
}
|
||||
|
||||
static void
|
||||
_handle_xterm_50_command(Termpty *ty,
|
||||
char *s,
|
||||
|
@ -1994,6 +2082,11 @@ _handle_esc_xterm(Termpty *ty, const Eina_Unicode *c, const Eina_Unicode *ce)
|
|||
WRN("set palette, not supported");
|
||||
if ((cc - c) < 3) return 0;
|
||||
break;
|
||||
case 8:
|
||||
DBG("hyperlink");
|
||||
s = eina_unicode_unicode_to_utf8(p, &len);
|
||||
_handle_hyperlink(ty, s, len);
|
||||
break;
|
||||
case 10:
|
||||
if (!*p)
|
||||
goto err;
|
||||
|
|
|
@ -421,6 +421,7 @@ termpty_reset_att(Termatt *att)
|
|||
att->framed = 0;
|
||||
att->encircled = 0;
|
||||
att->overlined = 0;
|
||||
att->link_id = 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
Loading…
Reference in New Issue