Start work on handling multicell escape code
This commit is contained in:
parent
b5dff921c4
commit
540e030f96
9 changed files with 323 additions and 51 deletions
1
.gitattributes
vendored
1
.gitattributes
vendored
|
|
@ -9,6 +9,7 @@ kitty/srgb_gamma.* linguist-generated=true
|
|||
kitty/gl-wrapper.* linguist-generated=true
|
||||
kitty/glfw-wrapper.* linguist-generated=true
|
||||
kitty/parse-graphics-command.h linguist-generated=true
|
||||
kitty/parse-multicell-command.h linguist-generated=true
|
||||
kitty/options/types.py linguist-generated=true
|
||||
kitty/options/parse.py linguist-generated=true
|
||||
kitty/options/to-c-generated.h linguist-generated=true
|
||||
|
|
|
|||
|
|
@ -85,12 +85,17 @@ def group(atype: str, conv: str) -> tuple[str, str]:
|
|||
|
||||
fmt = f'{flag_fmt} {uint_fmt} {int_fmt}'
|
||||
if payload_allowed:
|
||||
ans = [f'REPORT_VA_COMMAND("K s {{{fmt} sI}} y#", self->window_id, "{report_name}", ']
|
||||
ans = [f'REPORT_VA_COMMAND("K s {{{fmt} sI}} y#", self->window_id, "{report_name}",\n']
|
||||
else:
|
||||
ans = [f'REPORT_VA_COMMAND("K s {{{fmt}}}", self->window_id, "{report_name}", ']
|
||||
ans.append(',\n '.join((flag_attrs, uint_attrs, int_attrs)))
|
||||
ans = [f'REPORT_VA_COMMAND("K s {{{fmt}}}", self->window_id, "{report_name}",\n']
|
||||
if flag_attrs:
|
||||
ans.append(f'{flag_attrs},\n')
|
||||
if uint_attrs:
|
||||
ans.append(f'{uint_attrs},\n')
|
||||
if int_attrs:
|
||||
ans.append(f'{int_attrs},\n')
|
||||
if payload_allowed:
|
||||
ans.append(', "payload_sz", g.payload_sz, parser_buf, g.payload_sz')
|
||||
ans.append('"payload_sz", g.payload_sz, parser_buf, g.payload_sz')
|
||||
ans.append(');')
|
||||
return '\n'.join(ans)
|
||||
|
||||
|
|
@ -102,7 +107,9 @@ def generate(
|
|||
keymap: KeymapType,
|
||||
command_class: str,
|
||||
initial_key: str = 'a',
|
||||
payload_allowed: bool = True
|
||||
payload_allowed: bool = True,
|
||||
payload_is_base64: bool = True,
|
||||
start_parsing_at: int = 1,
|
||||
) -> str:
|
||||
type_map = resolve_keys(keymap)
|
||||
keys_enum = enum(keymap)
|
||||
|
|
@ -110,38 +117,51 @@ def generate(
|
|||
flag_keys = parse_flag(keymap, type_map, command_class)
|
||||
int_keys, uint_keys = parse_number(keymap)
|
||||
report_cmd = cmd_for_report(report_name, keymap, type_map, payload_allowed)
|
||||
extra_init = ''
|
||||
if payload_allowed:
|
||||
payload_after_value = "case ';': state = PAYLOAD; break;"
|
||||
payload = ', PAYLOAD'
|
||||
payload_case = f'''
|
||||
case PAYLOAD: {{
|
||||
sz = parser_buf_pos - pos;
|
||||
g.payload_sz = MAX(BUF_EXTRA, sz);
|
||||
if (!base64_decode8(parser_buf + pos, sz, parser_buf, &g.payload_sz)) {{
|
||||
if payload_is_base64:
|
||||
payload_case = f'''
|
||||
case PAYLOAD: {{
|
||||
sz = parser_buf_pos - pos;
|
||||
g.payload_sz = MAX(BUF_EXTRA, sz);
|
||||
REPORT_ERROR("Failed to parse {command_class} command payload with error: \
|
||||
invalid base64 data in chunk of size: %zu with output buffer size: %zu", sz, g.payload_sz); return; }}
|
||||
pos = parser_buf_pos;
|
||||
}}
|
||||
break;
|
||||
'''
|
||||
callback = f'{callback_name}(self->screen, &g, parser_buf)'
|
||||
if (!base64_decode8(parser_buf + pos, sz, parser_buf, &g.payload_sz)) {{
|
||||
g.payload_sz = MAX(BUF_EXTRA, sz);
|
||||
REPORT_ERROR("Failed to parse {command_class} command payload with error: \
|
||||
invalid base64 data in chunk of size: %zu with output buffer size: %zu", sz, g.payload_sz); return; }}
|
||||
pos = parser_buf_pos;
|
||||
}} break;
|
||||
'''
|
||||
callback = f'{callback_name}(self->screen, &g, parser_buf)'
|
||||
else:
|
||||
payload_case = '''
|
||||
case PAYLOAD: {
|
||||
sz = parser_buf_pos - pos;
|
||||
payload_start = pos;
|
||||
g.payload_sz = MAX(BUF_EXTRA, sz);
|
||||
} break;
|
||||
'''
|
||||
extra_init = 'size_t payload_start = 0;'
|
||||
callback = f'{callback_name}(self->screen, &g, parser_buf + payload_start)'
|
||||
|
||||
else:
|
||||
payload_after_value = payload = payload_case = ''
|
||||
callback = f'{callback_name}(self->screen, &g)'
|
||||
|
||||
return f'''
|
||||
#include "base64.h"
|
||||
|
||||
static inline void
|
||||
{function_name}(PS *self, uint8_t *parser_buf, const size_t parser_buf_pos) {{
|
||||
unsigned int pos = 1;
|
||||
unsigned int pos = {start_parsing_at};
|
||||
{extra_init}
|
||||
enum PARSER_STATES {{ KEY, EQUAL, UINT, INT, FLAG, AFTER_VALUE {payload} }};
|
||||
enum PARSER_STATES state = KEY, value_state = FLAG;
|
||||
static {command_class} g;
|
||||
{command_class} g = {{0}};
|
||||
unsigned int i, code;
|
||||
uint64_t lcode; int64_t accumulator;
|
||||
bool is_negative;
|
||||
memset(&g, 0, sizeof(g));
|
||||
bool is_negative; (void)is_negative;
|
||||
size_t sz;
|
||||
{keys_enum}
|
||||
enum KEYS key = '{initial_key}';
|
||||
|
|
@ -256,7 +276,7 @@ def write_header(text: str, path: str) -> None:
|
|||
subprocess.check_call(['clang-format', '-i', path])
|
||||
|
||||
|
||||
def graphics_parser() -> None:
|
||||
def parsers() -> None:
|
||||
flag = frozenset
|
||||
keymap: KeymapType = {
|
||||
'a': ('action', flag('tTqpdfac')),
|
||||
|
|
@ -291,10 +311,19 @@ def graphics_parser() -> None:
|
|||
}
|
||||
text = generate('parse_graphics_code', 'screen_handle_graphics_command', 'graphics_command', keymap, 'GraphicsCommand')
|
||||
write_header(text, 'kitty/parse-graphics-command.h')
|
||||
keymap = {
|
||||
'w': ('width', 'uint'),
|
||||
's': ('scale', 'uint'),
|
||||
'f': ('subscale', 'uint'),
|
||||
}
|
||||
text = generate(
|
||||
'parse_multicell_code', 'screen_handle_multicell_command', 'multicell_command', keymap, 'MultiCellCommand',
|
||||
payload_is_base64=False, start_parsing_at=0)
|
||||
write_header(text, 'kitty/parse-multicell-command.h')
|
||||
|
||||
|
||||
def main(args: list[str]=sys.argv) -> None:
|
||||
graphics_parser()
|
||||
parsers()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
|
|
|||
13
kitty/line.h
13
kitty/line.h
|
|
@ -16,6 +16,7 @@
|
|||
// TODO: URL detection with multicell
|
||||
// TODO: Cursor rendering over multicell
|
||||
// TODO: Test the escape codes to delete and insert characters and lines with multicell
|
||||
// TODO: Handle replay of dumped graphics_command and multicell_command
|
||||
|
||||
typedef union CellAttrs {
|
||||
struct {
|
||||
|
|
@ -54,7 +55,8 @@ typedef union MultiCellData {
|
|||
char_type width: 3;
|
||||
char_type subscale: 2;
|
||||
char_type vertical_align: 2;
|
||||
char_type : 21;
|
||||
char_type explicitly_set: 1;
|
||||
char_type : 20;
|
||||
char_type msb : 1;
|
||||
};
|
||||
char_type val;
|
||||
|
|
@ -67,10 +69,10 @@ typedef union CPUCell {
|
|||
char_type ch_is_idx: 1;
|
||||
char_type hyperlink_id: sizeof(hyperlink_id_type) * 8;
|
||||
char_type x : 8;
|
||||
char_type y : 3;
|
||||
char_type y : 4;
|
||||
char_type is_multicell : 1;
|
||||
char_type next_char_was_wrapped : 1;
|
||||
char_type : 3;
|
||||
char_type : 2;
|
||||
};
|
||||
struct {
|
||||
char_type ch_and_idx: sizeof(char_type) * 8;
|
||||
|
|
@ -104,6 +106,11 @@ typedef struct {
|
|||
TextCache *text_cache;
|
||||
} Line;
|
||||
|
||||
typedef struct MultiCellCommand {
|
||||
unsigned int width, scale, subscale;
|
||||
size_t payload_sz;
|
||||
} MultiCellCommand;
|
||||
|
||||
Line* alloc_line(TextCache *text_cache);
|
||||
void apply_sgr_to_cells(GPUCell *first_cell, unsigned int cell_count, int *params, unsigned int count, bool is_group);
|
||||
const char* cell_as_sgr(const GPUCell *, const GPUCell *);
|
||||
|
|
|
|||
53
kitty/parse-graphics-command.h
generated
53
kitty/parse-graphics-command.h
generated
|
|
@ -3,17 +3,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "base64.h"
|
||||
|
||||
static inline void parse_graphics_code(PS *self, uint8_t *parser_buf,
|
||||
const size_t parser_buf_pos) {
|
||||
unsigned int pos = 1;
|
||||
|
||||
enum PARSER_STATES { KEY, EQUAL, UINT, INT, FLAG, AFTER_VALUE, PAYLOAD };
|
||||
enum PARSER_STATES state = KEY, value_state = FLAG;
|
||||
static GraphicsCommand g;
|
||||
GraphicsCommand g = {0};
|
||||
unsigned int i, code;
|
||||
uint64_t lcode;
|
||||
int64_t accumulator;
|
||||
bool is_negative;
|
||||
memset(&g, 0, sizeof(g));
|
||||
(void)is_negative;
|
||||
size_t sz;
|
||||
|
||||
enum KEYS {
|
||||
|
|
@ -327,8 +329,8 @@ static inline void parse_graphics_code(PS *self, uint8_t *parser_buf,
|
|||
if (!base64_decode8(parser_buf + pos, sz, parser_buf, &g.payload_sz)) {
|
||||
g.payload_sz = MAX(BUF_EXTRA, sz);
|
||||
REPORT_ERROR("Failed to parse GraphicsCommand command payload with "
|
||||
"error: invalid base64 data in chunk of size: %zu with "
|
||||
"output buffer size: %zu",
|
||||
"error: invalid base64 data in chunk of size: %zu "
|
||||
"with output buffer size: %zu",
|
||||
sz, g.payload_sz);
|
||||
return;
|
||||
}
|
||||
|
|
@ -336,7 +338,7 @@ static inline void parse_graphics_code(PS *self, uint8_t *parser_buf,
|
|||
} break;
|
||||
|
||||
} // end switch
|
||||
} // end while
|
||||
} // end while
|
||||
|
||||
switch (state) {
|
||||
case EQUAL:
|
||||
|
|
@ -358,26 +360,31 @@ static inline void parse_graphics_code(PS *self, uint8_t *parser_buf,
|
|||
REPORT_VA_COMMAND(
|
||||
"K s {sc sc sc sc sI sI sI sI sI sI sI sI sI sI sI sI sI sI sI sI sI sI "
|
||||
"sI sI sI sI si si si sI} y#",
|
||||
self->window_id, "graphics_command", "action", g.action, "delete_action",
|
||||
g.delete_action, "transmission_type", g.transmission_type, "compressed",
|
||||
g.compressed, "format", (unsigned int)g.format, "more",
|
||||
(unsigned int)g.more, "id", (unsigned int)g.id, "image_number",
|
||||
(unsigned int)g.image_number, "placement_id",
|
||||
(unsigned int)g.placement_id, "quiet", (unsigned int)g.quiet, "width",
|
||||
(unsigned int)g.width, "height", (unsigned int)g.height, "x_offset",
|
||||
(unsigned int)g.x_offset, "y_offset", (unsigned int)g.y_offset,
|
||||
"data_height", (unsigned int)g.data_height, "data_width",
|
||||
(unsigned int)g.data_width, "data_sz", (unsigned int)g.data_sz,
|
||||
"data_offset", (unsigned int)g.data_offset, "num_cells",
|
||||
(unsigned int)g.num_cells, "num_lines", (unsigned int)g.num_lines,
|
||||
"cell_x_offset", (unsigned int)g.cell_x_offset, "cell_y_offset",
|
||||
(unsigned int)g.cell_y_offset, "cursor_movement",
|
||||
self->window_id, "graphics_command",
|
||||
|
||||
"action", g.action, "delete_action", g.delete_action, "transmission_type",
|
||||
g.transmission_type, "compressed", g.compressed,
|
||||
|
||||
"format", (unsigned int)g.format, "more", (unsigned int)g.more, "id",
|
||||
(unsigned int)g.id, "image_number", (unsigned int)g.image_number,
|
||||
"placement_id", (unsigned int)g.placement_id, "quiet",
|
||||
(unsigned int)g.quiet, "width", (unsigned int)g.width, "height",
|
||||
(unsigned int)g.height, "x_offset", (unsigned int)g.x_offset, "y_offset",
|
||||
(unsigned int)g.y_offset, "data_height", (unsigned int)g.data_height,
|
||||
"data_width", (unsigned int)g.data_width, "data_sz",
|
||||
(unsigned int)g.data_sz, "data_offset", (unsigned int)g.data_offset,
|
||||
"num_cells", (unsigned int)g.num_cells, "num_lines",
|
||||
(unsigned int)g.num_lines, "cell_x_offset", (unsigned int)g.cell_x_offset,
|
||||
"cell_y_offset", (unsigned int)g.cell_y_offset, "cursor_movement",
|
||||
(unsigned int)g.cursor_movement, "unicode_placement",
|
||||
(unsigned int)g.unicode_placement, "parent_id", (unsigned int)g.parent_id,
|
||||
"parent_placement_id", (unsigned int)g.parent_placement_id, "z_index",
|
||||
(int)g.z_index, "offset_from_parent_x", (int)g.offset_from_parent_x,
|
||||
"offset_from_parent_y", (int)g.offset_from_parent_y, "payload_sz",
|
||||
g.payload_sz, parser_buf, g.payload_sz);
|
||||
"parent_placement_id", (unsigned int)g.parent_placement_id,
|
||||
|
||||
"z_index", (int)g.z_index, "offset_from_parent_x",
|
||||
(int)g.offset_from_parent_x, "offset_from_parent_y",
|
||||
(int)g.offset_from_parent_y,
|
||||
|
||||
"payload_sz", g.payload_sz, parser_buf, g.payload_sz);
|
||||
|
||||
screen_handle_graphics_command(self->screen, &g, parser_buf);
|
||||
}
|
||||
|
|
|
|||
179
kitty/parse-multicell-command.h
generated
Normal file
179
kitty/parse-multicell-command.h
generated
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
// This file is generated by apc_parsers.py do not edit!
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base64.h"
|
||||
|
||||
static inline void parse_multicell_code(PS *self, uint8_t *parser_buf,
|
||||
const size_t parser_buf_pos) {
|
||||
unsigned int pos = 0;
|
||||
size_t payload_start = 0;
|
||||
enum PARSER_STATES { KEY, EQUAL, UINT, INT, FLAG, AFTER_VALUE, PAYLOAD };
|
||||
enum PARSER_STATES state = KEY, value_state = FLAG;
|
||||
MultiCellCommand g = {0};
|
||||
unsigned int i, code;
|
||||
uint64_t lcode;
|
||||
int64_t accumulator;
|
||||
bool is_negative;
|
||||
(void)is_negative;
|
||||
size_t sz;
|
||||
|
||||
enum KEYS { width = 'w', scale = 's', subscale = 'f' };
|
||||
|
||||
enum KEYS key = 'a';
|
||||
if (parser_buf[pos] == ';')
|
||||
state = AFTER_VALUE;
|
||||
|
||||
while (pos < parser_buf_pos) {
|
||||
switch (state) {
|
||||
case KEY:
|
||||
key = parser_buf[pos++];
|
||||
state = EQUAL;
|
||||
switch (key) {
|
||||
case width:
|
||||
value_state = UINT;
|
||||
break;
|
||||
case scale:
|
||||
value_state = UINT;
|
||||
break;
|
||||
case subscale:
|
||||
value_state = UINT;
|
||||
break;
|
||||
default:
|
||||
REPORT_ERROR("Malformed MultiCellCommand control block, invalid key "
|
||||
"character: 0x%x",
|
||||
key);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case EQUAL:
|
||||
if (parser_buf[pos++] != '=') {
|
||||
REPORT_ERROR("Malformed MultiCellCommand control block, no = after "
|
||||
"key, found: 0x%x instead",
|
||||
parser_buf[pos - 1]);
|
||||
return;
|
||||
}
|
||||
state = value_state;
|
||||
break;
|
||||
|
||||
case FLAG:
|
||||
switch (key) {
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
state = AFTER_VALUE;
|
||||
break;
|
||||
|
||||
case INT:
|
||||
#define READ_UINT \
|
||||
for (i = pos, accumulator = 0; i < MIN(parser_buf_pos, pos + 10); i++) { \
|
||||
int64_t n = parser_buf[i] - '0'; \
|
||||
if (n < 0 || n > 9) \
|
||||
break; \
|
||||
accumulator += n * digit_multipliers[i - pos]; \
|
||||
} \
|
||||
if (i == pos) { \
|
||||
REPORT_ERROR("Malformed MultiCellCommand control block, expecting an " \
|
||||
"integer value for key: %c", \
|
||||
key & 0xFF); \
|
||||
return; \
|
||||
} \
|
||||
lcode = accumulator / digit_multipliers[i - pos - 1]; \
|
||||
pos = i; \
|
||||
if (lcode > UINT32_MAX) { \
|
||||
REPORT_ERROR( \
|
||||
"Malformed MultiCellCommand control block, number is too large"); \
|
||||
return; \
|
||||
} \
|
||||
code = lcode;
|
||||
|
||||
is_negative = false;
|
||||
if (parser_buf[pos] == '-') {
|
||||
is_negative = true;
|
||||
pos++;
|
||||
}
|
||||
#define I(x) \
|
||||
case x: \
|
||||
g.x = is_negative ? 0 - (int32_t)code : (int32_t)code; \
|
||||
break
|
||||
READ_UINT;
|
||||
switch (key) {
|
||||
;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
state = AFTER_VALUE;
|
||||
break;
|
||||
#undef I
|
||||
case UINT:
|
||||
READ_UINT;
|
||||
#define U(x) \
|
||||
case x: \
|
||||
g.x = code; \
|
||||
break
|
||||
switch (key) {
|
||||
U(width);
|
||||
U(scale);
|
||||
U(subscale);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
state = AFTER_VALUE;
|
||||
break;
|
||||
#undef U
|
||||
#undef READ_UINT
|
||||
|
||||
case AFTER_VALUE:
|
||||
switch (parser_buf[pos++]) {
|
||||
default:
|
||||
REPORT_ERROR("Malformed MultiCellCommand control block, expecting a "
|
||||
"comma or semi-colon after a value, found: 0x%x",
|
||||
parser_buf[pos - 1]);
|
||||
return;
|
||||
case ',':
|
||||
state = KEY;
|
||||
break;
|
||||
case ';':
|
||||
state = PAYLOAD;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case PAYLOAD: {
|
||||
sz = parser_buf_pos - pos;
|
||||
payload_start = pos;
|
||||
g.payload_sz = MAX(BUF_EXTRA, sz);
|
||||
} break;
|
||||
|
||||
} // end switch
|
||||
} // end while
|
||||
|
||||
switch (state) {
|
||||
case EQUAL:
|
||||
REPORT_ERROR("Malformed MultiCellCommand control block, no = after key");
|
||||
return;
|
||||
case INT:
|
||||
case UINT:
|
||||
REPORT_ERROR(
|
||||
"Malformed MultiCellCommand control block, expecting an integer value");
|
||||
return;
|
||||
case FLAG:
|
||||
REPORT_ERROR(
|
||||
"Malformed MultiCellCommand control block, expecting a flag value");
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
REPORT_VA_COMMAND("K s { sI sI sI sI} y#", self->window_id,
|
||||
"multicell_command",
|
||||
|
||||
"width", (unsigned int)g.width, "scale",
|
||||
(unsigned int)g.scale, "subscale", (unsigned int)g.subscale,
|
||||
|
||||
"payload_sz", g.payload_sz, parser_buf, g.payload_sz);
|
||||
|
||||
screen_handle_multicell_command(self->screen, &g, parser_buf + payload_start);
|
||||
}
|
||||
|
|
@ -879,7 +879,7 @@ draw_combining_char(Screen *self, text_loop_state *s, char_type ch) {
|
|||
self->lc->chars[self->lc->count++] = mcd.val;
|
||||
} else {
|
||||
ensure_space_for_chars(self->lc, self->lc->count + 1);
|
||||
MultiCellData mcd = {.width=2, .scale=1};
|
||||
MultiCellData mcd = {.width=2, .scale=1, .msb=1};
|
||||
self->lc->chars[self->lc->count++] = mcd.val;
|
||||
cpu_cell->is_multicell = true;
|
||||
}
|
||||
|
|
@ -1040,7 +1040,7 @@ draw_text_loop(Screen *self, const uint32_t *chars, size_t num_chars, text_loop_
|
|||
CPUCell *fc = s->cp + self->cursor->x;
|
||||
zero_cells(s, fc, s->gp + self->cursor->x);
|
||||
if (char_width == 2) {
|
||||
MultiCellData mcd = {.width = 2, .scale = 1};
|
||||
MultiCellData mcd = {.width = 2, .scale = 1, .msb = 1};
|
||||
RAII_ListOfChars(lc);
|
||||
lc.chars[lc.count++] = ch;
|
||||
lc.chars[lc.count++] = mcd.val;
|
||||
|
|
@ -1094,6 +1094,48 @@ screen_align(Screen *self) {
|
|||
linebuf_clear(self->linebuf, 'E');
|
||||
}
|
||||
|
||||
static size_t
|
||||
decode_utf8_safe_string(const uint8_t *src, size_t sz, uint32_t *dest) {
|
||||
// dest must be an array of size at least sz
|
||||
uint32_t codep = 0;
|
||||
UTF8State state = 0, prev = UTF8_ACCEPT;
|
||||
size_t i, d;
|
||||
for (i = 0, d = 0; i < sz; i++) {
|
||||
switch(decode_utf8(&state, &codep, src[i])) {
|
||||
case UTF8_ACCEPT:
|
||||
// Ignore C0 and C1 chars
|
||||
if (codep >= ' ' && !(codep >= DEL && codep <= 159)) dest[d++] = codep;
|
||||
break;
|
||||
case UTF8_REJECT:
|
||||
state = UTF8_ACCEPT;
|
||||
if (prev != UTF8_ACCEPT && i > 0) i--;
|
||||
break;
|
||||
}
|
||||
prev = state;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
void
|
||||
screen_handle_multicell_command(Screen *self, const MultiCellCommand *cmd, const uint8_t *payload) {
|
||||
if (!cmd->payload_sz) return;
|
||||
ensure_space_for_chars(self->lc, cmd->payload_sz + 1);
|
||||
self->lc->count = decode_utf8_safe_string(payload, cmd->payload_sz, self->lc->chars);
|
||||
if (!self->lc->count) return;
|
||||
unsigned width = cmd->width;
|
||||
if (!width) {
|
||||
self->lc->chars[self->lc->count] = 0;
|
||||
width = wcswidth_string(self->lc->chars);
|
||||
}
|
||||
if (!width) return;
|
||||
MultiCellData mcd = {
|
||||
.width=MIN(width, 15), .scale=MAX(1, MIN(cmd->scale, 15)), .subscale=MIN(cmd->subscale, 3),
|
||||
.explicitly_set=1, .msb=1
|
||||
};
|
||||
self->lc->chars[self->lc->count++] = mcd.val;
|
||||
width = mcd.width * mcd.scale;
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
// Graphics {{{
|
||||
|
|
|
|||
|
|
@ -265,6 +265,7 @@ void screen_mark_url(Screen *self, index_type start_x, index_type start_y, index
|
|||
void set_active_hyperlink(Screen*, char*, char*);
|
||||
hyperlink_id_type screen_mark_hyperlink(Screen*, index_type, index_type);
|
||||
void screen_handle_graphics_command(Screen *self, const GraphicsCommand *cmd, const uint8_t *payload);
|
||||
void screen_handle_multicell_command(Screen *self, const MultiCellCommand *cmd, const uint8_t *payload);
|
||||
bool screen_open_url(Screen*);
|
||||
bool screen_set_last_visited_prompt(Screen*, index_type);
|
||||
bool screen_select_cmd_output(Screen*, index_type);
|
||||
|
|
|
|||
|
|
@ -377,6 +377,8 @@ find_st_terminator(PS *self, size_t *end_pos) {
|
|||
|
||||
// OSC {{{
|
||||
|
||||
#include "parse-multicell-command.h"
|
||||
|
||||
static bool
|
||||
is_osc_52(PS *self) {
|
||||
return memcmp(self->buf + self->read.consumed, "52;", 3) == 0;
|
||||
|
|
@ -537,6 +539,9 @@ dispatch_osc(PS *self, uint8_t *buf, size_t limit, bool is_extended_osc) {
|
|||
if (is_extended_osc && code == 52) code = -52;
|
||||
DISPATCH_OSC_WITH_CODE(clipboard_control);
|
||||
END_DISPATCH
|
||||
case 66:
|
||||
parse_multicell_code(self, buf + i, limit - 1);
|
||||
break;
|
||||
case 133:
|
||||
#ifdef DUMP_COMMANDS
|
||||
START_DISPATCH
|
||||
|
|
|
|||
Loading…
Reference in a new issue