Output hyperlink markup when serializing as ANSI
This commit is contained in:
parent
e0f5c39297
commit
9d4246a285
@ -199,9 +199,12 @@ typedef struct {
|
||||
bool rewrap_needed;
|
||||
} PagerHistoryBuf;
|
||||
|
||||
typedef struct {int x;} *HYPERLINK_POOL_HANDLE;
|
||||
typedef struct {
|
||||
Py_UCS4 *buf;
|
||||
size_t len, capacity;
|
||||
HYPERLINK_POOL_HANDLE hyperlink_pool;
|
||||
hyperlink_id_type active_hyperlink_id;
|
||||
} ANSIBuf;
|
||||
|
||||
typedef struct {
|
||||
@ -254,7 +257,6 @@ typedef struct {
|
||||
typedef struct {int x;} *SPRITE_MAP_HANDLE;
|
||||
#define FONTS_DATA_HEAD SPRITE_MAP_HANDLE sprite_map; double logical_dpi_x, logical_dpi_y, font_sz_in_pts; unsigned int cell_width, cell_height;
|
||||
typedef struct {FONTS_DATA_HEAD} *FONTS_DATA_HANDLE;
|
||||
typedef struct {int x;} *HYPERLINK_POOL_HANDLE;
|
||||
|
||||
#define PARSER_BUF_SZ (8 * 1024)
|
||||
#define READ_BUF_SZ (1024*1024)
|
||||
|
||||
44
kitty/line.c
44
kitty/line.c
@ -277,11 +277,36 @@ write_sgr(const char *val, ANSIBuf *output) {
|
||||
#undef W
|
||||
}
|
||||
|
||||
static inline void
|
||||
write_hyperlink(hyperlink_id_type hid, ANSIBuf *output) {
|
||||
#define W(c) output->buf[output->len++] = c
|
||||
const char *key = hid ? get_hyperlink_for_id(output->hyperlink_pool, hid, false) : NULL;
|
||||
if (!key) hid = 0;
|
||||
output->active_hyperlink_id = hid;
|
||||
W(0x1b); W(']'); W('8');
|
||||
if (!hid) {
|
||||
W(';'); W(';');
|
||||
} else {
|
||||
const char* partition = strstr(key, ":");
|
||||
W(';');
|
||||
if (partition != key) {
|
||||
W('i'); W('d'); W('=');
|
||||
while (key != partition) W(*(key++));
|
||||
}
|
||||
W(';');
|
||||
while(*(++partition)) W(*partition);
|
||||
}
|
||||
W(0x1b); W('\\');
|
||||
#undef W
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
line_as_ansi(Line *self, ANSIBuf *output, const GPUCell** prev_cell) {
|
||||
#define ENSURE_SPACE(extra) ensure_space_for(output, buf, Py_UCS4, output->len + extra, capacity, 2048, false);
|
||||
#define WRITE_SGR(val) { ENSURE_SPACE(128); write_sgr(val, output); }
|
||||
#define WRITE_CH(val) { ENSURE_SPACE(1); output->buf[output->len++] = val; }
|
||||
#define WRITE_HYPERLINK(val) { ENSURE_SPACE(2256); write_hyperlink(val, output); }
|
||||
output->len = 0;
|
||||
index_type limit = xlimit_for_line(self);
|
||||
if (limit == 0) return;
|
||||
@ -297,6 +322,12 @@ line_as_ansi(Line *self, ANSIBuf *output, const GPUCell** prev_cell) {
|
||||
if (previous_width == 2) { previous_width = 0; continue; }
|
||||
ch = ' ';
|
||||
}
|
||||
if (output->hyperlink_pool) {
|
||||
hyperlink_id_type hid = self->cpu_cells[pos].hyperlink_id;
|
||||
if (hid != output->active_hyperlink_id) {
|
||||
WRITE_HYPERLINK(hid);
|
||||
}
|
||||
}
|
||||
|
||||
cell = &self->gpu_cells[pos];
|
||||
|
||||
@ -325,6 +356,7 @@ line_as_ansi(Line *self, ANSIBuf *output, const GPUCell** prev_cell) {
|
||||
#undef WRITE_SGR
|
||||
#undef WRITE_CH
|
||||
#undef ENSURE_SPACE
|
||||
#undef WRITE_HYPERLINK
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
@ -770,8 +802,9 @@ as_text_generic(PyObject *args, void *container, get_line_func get_line, index_t
|
||||
PyObject *nl = PyUnicode_FromString("\n");
|
||||
PyObject *cr = PyUnicode_FromString("\r");
|
||||
PyObject *sgr_reset = PyUnicode_FromString("\x1b[m");
|
||||
if (nl == NULL || cr == NULL || sgr_reset == NULL) goto end;
|
||||
const GPUCell *prev_cell = NULL;
|
||||
if (nl == NULL || cr == NULL) goto end;
|
||||
ansibuf->active_hyperlink_id = 0;
|
||||
for (index_type y = 0; y < lines; y++) {
|
||||
Line *line = get_line(container, y);
|
||||
if (!line->continued && y > 0) {
|
||||
@ -805,6 +838,15 @@ as_text_generic(PyObject *args, void *container, get_line_func get_line, index_t
|
||||
Py_CLEAR(ret);
|
||||
}
|
||||
}
|
||||
if (ansibuf->active_hyperlink_id) {
|
||||
ansibuf->active_hyperlink_id = 0;
|
||||
t = PyUnicode_FromString("\x1b]8;;\x1b\\");
|
||||
if (t) {
|
||||
ret = PyObject_CallFunctionObjArgs(callback, t, NULL);
|
||||
Py_CLEAR(t);
|
||||
Py_CLEAR(ret);
|
||||
}
|
||||
}
|
||||
end:
|
||||
Py_CLEAR(nl); Py_CLEAR(cr); Py_CLEAR(sgr_reset);
|
||||
if (PyErr_Occurred()) return NULL;
|
||||
|
||||
@ -137,6 +137,7 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
||||
if (!init_overlay_line(self, self->columns)) { Py_CLEAR(self); return NULL; }
|
||||
self->hyperlink_pool = alloc_hyperlink_pool();
|
||||
if (!self->hyperlink_pool) { Py_CLEAR(self); return PyErr_NoMemory(); }
|
||||
self->as_ansi_buf.hyperlink_pool = self->hyperlink_pool;
|
||||
}
|
||||
return (PyObject*) self;
|
||||
}
|
||||
|
||||
@ -467,6 +467,18 @@ class TestScreen(BaseTest):
|
||||
s.draw(f'{i}' * s.columns)
|
||||
self.ae(as_text(s, True, True), '\x1b[m\x1b[31m11\x1b[m\x1b[32m22\x1b[m\x1b[33m33\x1b[m\x1b[34m44\x1b[m\x1b[m\x1b[35m55\x1b[m\x1b[36m66')
|
||||
|
||||
def set_link(url=None, id=None):
|
||||
parse_bytes(s, '\x1b]8;id={};{}\x1b\\'.format(id or '', url or '').encode('utf-8'))
|
||||
|
||||
s = self.create_screen()
|
||||
s.draw('a')
|
||||
set_link('moo', 'foo')
|
||||
s.draw('bcdef')
|
||||
self.ae(as_text(s, True), '\x1b[ma\x1b]8;id=foo;moo\x1b\\bcde\x1b[mf\n\n\n\x1b]8;;\x1b\\')
|
||||
set_link()
|
||||
s.draw('gh')
|
||||
self.ae(as_text(s, True), '\x1b[ma\x1b]8;id=foo;moo\x1b\\bcde\x1b[mf\x1b]8;;\x1b\\gh\n\n\n')
|
||||
|
||||
def test_pagerhist(self):
|
||||
hsz = 8
|
||||
s = self.create_screen(cols=2, lines=2, scrollback=2, options={'scrollback_pager_history_size': hsz})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user