Start work on dumping non-UTF-8 charset support
This commit is contained in:
parent
4b0e8fcb49
commit
f14e7037e2
@ -55,13 +55,13 @@
|
||||
// *Delete*: Is ignored.
|
||||
#define DEL 0x7f
|
||||
|
||||
// *Control sequence introducer*: An equivalent for ``ESC [``.
|
||||
#define IND 0x84
|
||||
#define NEL 0x85
|
||||
#define HTS 0x88
|
||||
#define RI 0x8d
|
||||
#define DCS 0x90
|
||||
#define CSI 0x9b
|
||||
|
||||
// *String terminator*.
|
||||
#define ST 0x9c
|
||||
|
||||
// *Operating system command*.
|
||||
#define OSC 0x9d
|
||||
|
||||
// Sharp control codes
|
||||
@ -73,38 +73,43 @@
|
||||
// Esc control codes
|
||||
// ------------------
|
||||
|
||||
#define ESC_DCS 'P'
|
||||
#define ESC_OSC ']'
|
||||
#define ESC_CSI '['
|
||||
#define ESC_ST '\\'
|
||||
|
||||
// *Reset*.
|
||||
#define RIS 'c'
|
||||
#define ESC_RIS 'c'
|
||||
|
||||
// *Index*: Move cursor down one line in same column. If the cursor is
|
||||
// at the bottom margin, the screen performs a scroll-up.
|
||||
#define IND 'D'
|
||||
#define ESC_IND 'D'
|
||||
|
||||
// *Next line*: Same as LF.
|
||||
#define NEL 'E'
|
||||
#define ESC_NEL 'E'
|
||||
|
||||
// Tabulation set: Set a horizontal tab stop at cursor position.
|
||||
#define HTS 'H'
|
||||
#define ESC_HTS 'H'
|
||||
|
||||
// *Reverse index*: Move cursor up one line in same column. If the
|
||||
// cursor is at the top margin, the screen performs a scroll-down.
|
||||
#define RI 'M'
|
||||
#define ESC_RI 'M'
|
||||
|
||||
// Save cursor: Save cursor position, character attribute (graphic
|
||||
// rendition), character set, and origin mode selection (see
|
||||
// :data:`DECRC`).
|
||||
#define DECSC '7'
|
||||
#define ESC_DECSC '7'
|
||||
|
||||
// *Restore cursor*: Restore previously saved cursor position, character
|
||||
// attribute (graphic rendition), character set, and origin mode
|
||||
// selection. If none were saved, move cursor to home position.
|
||||
#define DECRC '8'
|
||||
#define ESC_DECRC '8'
|
||||
|
||||
// Set normal keypad mode
|
||||
#define DECPNM '>'
|
||||
#define ESC_DECPNM '>'
|
||||
|
||||
// Set alternate keypad mode
|
||||
#define DECPAM '='
|
||||
#define ESC_DECPAM '='
|
||||
|
||||
// ECMA-48 CSI sequences.
|
||||
// ---------------------
|
||||
|
||||
@ -227,8 +227,6 @@ PyTypeObject ScreenModes_Type;
|
||||
#define SAVEPOINTS_SZ 256
|
||||
|
||||
typedef struct {
|
||||
unsigned int current_charset;
|
||||
uint16_t *g0_charset, *g1_charset;
|
||||
uint32_t utf8_state;
|
||||
Cursor cursor;
|
||||
bool mDECOM;
|
||||
@ -243,16 +241,14 @@ typedef struct {
|
||||
} SavepointBuffer;
|
||||
|
||||
|
||||
#define PARSER_BUF_SZ 8192
|
||||
#define PARSER_BUF_SZ (8 * 1024)
|
||||
#define READ_BUF_SZ (1024*1024)
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
|
||||
unsigned int columns, lines, margin_top, margin_bottom;
|
||||
unsigned int current_charset;
|
||||
uint32_t utf8_state;
|
||||
uint16_t *g0_charset, *g1_charset;
|
||||
Cursor *cursor;
|
||||
SavepointBuffer main_savepoints, alt_savepoints;
|
||||
PyObject *callbacks;
|
||||
@ -262,7 +258,7 @@ typedef struct {
|
||||
ChangeTracker *change_tracker;
|
||||
ScreenModes modes;
|
||||
|
||||
uint8_t parser_buf[PARSER_BUF_SZ];
|
||||
uint32_t parser_buf[PARSER_BUF_SZ];
|
||||
unsigned int parser_state, parser_text_start, parser_buf_pos;
|
||||
bool parser_has_pending_text;
|
||||
uint8_t read_buf[READ_BUF_SZ];
|
||||
@ -334,14 +330,12 @@ void screen_cursor_position(Screen*, unsigned int, unsigned int);
|
||||
void screen_cursor_back(Screen *self, unsigned int count/*=1*/, int move_direction/*=-1*/);
|
||||
void screen_erase_in_line(Screen *, unsigned int, bool);
|
||||
void screen_erase_in_display(Screen *, unsigned int, bool);
|
||||
void screen_draw(Screen *screen, uint8_t *buf, unsigned int buflen);
|
||||
void screen_draw(Screen *screen, uint32_t codepoint);
|
||||
void screen_ensure_bounds(Screen *self, bool use_margins);
|
||||
void screen_toggle_screen_buffer(Screen *self);
|
||||
void screen_normal_keypad_mode(Screen *self);
|
||||
void screen_alternate_keypad_mode(Screen *self);
|
||||
void screen_change_default_color(Screen *self, unsigned int which, uint32_t col);
|
||||
void screen_define_charset(Screen *self, uint8_t code, uint8_t mode);
|
||||
void screen_select_other_charset(Screen *self, uint8_t code, uint8_t mode);
|
||||
void screen_alignment_display(Screen *self);
|
||||
void screen_reverse_index(Screen *self);
|
||||
void screen_index(Screen *self);
|
||||
@ -370,11 +364,9 @@ void set_dynamic_color(Screen *self, unsigned int code, const char *buf, unsigne
|
||||
void report_device_attributes(Screen *self, unsigned int UNUSED mode, bool UNUSED secondary);
|
||||
void select_graphic_rendition(Screen *self, unsigned int *params, unsigned int count);
|
||||
void report_device_status(Screen *self, unsigned int which, bool UNUSED);
|
||||
#define DECLARE_CH_SCREEN_HANDLER(name) void screen_##name(Screen *screen, uint8_t ch);
|
||||
#define DECLARE_CH_SCREEN_HANDLER(name) void screen_##name(Screen *screen);
|
||||
DECLARE_CH_SCREEN_HANDLER(bell)
|
||||
DECLARE_CH_SCREEN_HANDLER(backspace)
|
||||
DECLARE_CH_SCREEN_HANDLER(tab)
|
||||
DECLARE_CH_SCREEN_HANDLER(linefeed)
|
||||
DECLARE_CH_SCREEN_HANDLER(carriage_return)
|
||||
DECLARE_CH_SCREEN_HANDLER(shift_out)
|
||||
DECLARE_CH_SCREEN_HANDLER(shift_in)
|
||||
|
||||
686
kitty/parser.c
686
kitty/parser.c
@ -1,35 +1,13 @@
|
||||
/*
|
||||
* parser.c
|
||||
* Copyright (C) 2016 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "data-types.h"
|
||||
#include "control-codes.h"
|
||||
|
||||
#define NORMAL_STATE 0
|
||||
#define ESC_STATE 1
|
||||
#define CSI_STATE 2
|
||||
#define OSC_STATE 3
|
||||
#define DCS_STATE 4
|
||||
|
||||
#define IS_DIGIT \
|
||||
case '0': \
|
||||
case '1': \
|
||||
case '2': \
|
||||
case '3': \
|
||||
case '4': \
|
||||
case '5': \
|
||||
case '6': \
|
||||
case '7': \
|
||||
case '8': \
|
||||
case '9':
|
||||
|
||||
// Macros {{{
|
||||
#ifdef DUMP_COMMANDS
|
||||
static void _report_error(PyObject *dump_callback, const char *fmt, ...) {
|
||||
va_list argptr;
|
||||
@ -42,6 +20,8 @@ static void _report_error(PyObject *dump_callback, const char *fmt, ...) {
|
||||
}
|
||||
}
|
||||
|
||||
#define DUMP_UNUSED
|
||||
|
||||
#define REPORT_ERROR(...) _report_error(dump_callback, __VA_ARGS__);
|
||||
|
||||
#define REPORT_COMMAND1(name) \
|
||||
@ -56,527 +36,244 @@ static void _report_error(PyObject *dump_callback, const char *fmt, ...) {
|
||||
#define GET_MACRO(_1,_2,_3,NAME,...) NAME
|
||||
#define REPORT_COMMAND(...) GET_MACRO(__VA_ARGS__, REPORT_COMMAND3, REPORT_COMMAND2, REPORT_COMMAND1, SENTINEL)(__VA_ARGS__)
|
||||
|
||||
#define REPORT_DRAW(start, sz) \
|
||||
Py_XDECREF(PyObject_CallFunction(dump_callback, "sy#", "draw", start, sz)); PyErr_Clear();
|
||||
|
||||
#define REPORT_DCS \
|
||||
Py_XDECREF(PyObject_CallFunction(dump_callback, "sy#", "dcs", screen->parser_buf, screen->parser_buf_pos)); PyErr_Clear();
|
||||
|
||||
#define HANDLER(name) \
|
||||
static inline void read_##name(Screen *screen, uint8_t UNUSED *buf, unsigned int UNUSED buflen, unsigned int UNUSED *pos, PyObject UNUSED *dump_callback)
|
||||
#define REPORT_DRAW(ch) \
|
||||
Py_XDECREF(PyObject_CallFunction(dump_callback, "sC", "draw", ch)); PyErr_Clear();
|
||||
|
||||
#else
|
||||
|
||||
#define DUMP_UNUSED UNUSED
|
||||
|
||||
#define REPORT_ERROR(...) fprintf(stderr, "[PARSE ERROR] "); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n");
|
||||
|
||||
#define REPORT_COMMAND(...)
|
||||
#define REPORT_DRAW(...)
|
||||
#define REPORT_DCS
|
||||
|
||||
#define HANDLER(name) \
|
||||
static inline void read_##name(Screen *screen, uint8_t UNUSED *buf, unsigned int UNUSED buflen, unsigned int UNUSED *pos)
|
||||
#define REPORT_DRAW(ch)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define SET_STATE(state) screen->parser_state = state; screen->parser_buf_pos = 0;
|
||||
|
||||
// Parse text {{{
|
||||
|
||||
|
||||
HANDLER(text) {
|
||||
uint8_t ch;
|
||||
unsigned int sz;
|
||||
|
||||
while(*pos < buflen) {
|
||||
ch = buf[(*pos)++];
|
||||
#define DRAW_TEXT(limit) \
|
||||
if (screen->parser_has_pending_text) { \
|
||||
screen->parser_has_pending_text = false; \
|
||||
sz = (limit) > screen->parser_text_start ? (limit) - screen->parser_text_start : 0; \
|
||||
REPORT_DRAW(buf + screen->parser_text_start, sz); \
|
||||
screen_draw(screen, buf + screen->parser_text_start, sz); \
|
||||
screen->parser_text_start = 0; \
|
||||
}
|
||||
|
||||
#define CALL_SCREEN_HANDLER(name) \
|
||||
DRAW_TEXT((*pos) - 1); REPORT_COMMAND(name, ch); \
|
||||
name(screen, ch); break;
|
||||
|
||||
switch(ch) {
|
||||
case BEL:
|
||||
CALL_SCREEN_HANDLER(screen_bell);
|
||||
case BS:
|
||||
CALL_SCREEN_HANDLER(screen_backspace);
|
||||
case HT:
|
||||
CALL_SCREEN_HANDLER(screen_tab);
|
||||
case LF:
|
||||
case VT:
|
||||
case FF:
|
||||
CALL_SCREEN_HANDLER(screen_linefeed);
|
||||
case CR:
|
||||
CALL_SCREEN_HANDLER(screen_carriage_return);
|
||||
case SO:
|
||||
CALL_SCREEN_HANDLER(screen_shift_out);
|
||||
case SI:
|
||||
CALL_SCREEN_HANDLER(screen_shift_in);
|
||||
case ESC:
|
||||
DRAW_TEXT((*pos)-1); SET_STATE(ESC_STATE); return;
|
||||
case CSI:
|
||||
DRAW_TEXT((*pos)-1); SET_STATE(CSI_STATE); return;
|
||||
case OSC:
|
||||
DRAW_TEXT((*pos)-1); SET_STATE(OSC_STATE); return;
|
||||
case NUL:
|
||||
case DEL:
|
||||
break; // no-op
|
||||
default:
|
||||
if (!screen->parser_has_pending_text) {
|
||||
screen->parser_has_pending_text = true;
|
||||
screen->parser_text_start = (*pos) - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
DRAW_TEXT(*pos);
|
||||
}
|
||||
#undef DRAW_TEXT
|
||||
// }}}
|
||||
|
||||
// Parse ESC {{{
|
||||
|
||||
static inline void screen_linefeed2(Screen *screen) { screen_linefeed(screen, '\n'); }
|
||||
|
||||
static inline void escape_dispatch(Screen *screen, uint8_t ch, PyObject UNUSED *dump_callback) {
|
||||
#define CALL_ED(name) REPORT_COMMAND(name); name(screen); break;
|
||||
switch (ch) {
|
||||
case RIS:
|
||||
CALL_ED(screen_reset);
|
||||
// Normal mode {{{
|
||||
static inline void
|
||||
handle_normal_mode_char(Screen *screen, uint32_t ch, PyObject DUMP_UNUSED *dump_callback) {
|
||||
#define CALL_SCREEN_HANDLER(name) REPORT_COMMAND(#name, ch); name(screen); break;
|
||||
switch(ch) {
|
||||
case BEL:
|
||||
CALL_SCREEN_HANDLER(screen_bell);
|
||||
case BS:
|
||||
CALL_SCREEN_HANDLER(screen_backspace);
|
||||
case HT:
|
||||
CALL_SCREEN_HANDLER(screen_tab);
|
||||
case LF:
|
||||
case VT:
|
||||
case FF:
|
||||
CALL_SCREEN_HANDLER(screen_linefeed);
|
||||
case CR:
|
||||
CALL_SCREEN_HANDLER(screen_carriage_return);
|
||||
case SO:
|
||||
REPORT_ERROR("Unhandled charset change command (SO), ignoring"); break;
|
||||
case SI:
|
||||
REPORT_ERROR("Unhandled charset change command (SI), ignoring"); break;
|
||||
case IND:
|
||||
CALL_ED(screen_index);
|
||||
case NEL:
|
||||
CALL_ED(screen_linefeed2);
|
||||
CALL_SCREEN_HANDLER(screen_index);
|
||||
case RI:
|
||||
CALL_ED(screen_reverse_index);
|
||||
CALL_SCREEN_HANDLER(screen_reverse_index);
|
||||
case NEL:
|
||||
CALL_SCREEN_HANDLER(screen_linefeed);
|
||||
case HTS:
|
||||
CALL_ED(screen_set_tab_stop);
|
||||
case DECSC:
|
||||
CALL_ED(screen_save_cursor);
|
||||
case DECRC:
|
||||
CALL_ED(screen_restore_cursor);
|
||||
case DECPNM:
|
||||
CALL_ED(screen_normal_keypad_mode);
|
||||
case DECPAM:
|
||||
CALL_ED(screen_alternate_keypad_mode);
|
||||
CALL_SCREEN_HANDLER(screen_set_tab_stop);
|
||||
case ESC:
|
||||
case CSI:
|
||||
case OSC:
|
||||
case DCS:
|
||||
SET_STATE(ch); break;
|
||||
case NUL:
|
||||
case DEL:
|
||||
break; // no-op
|
||||
default:
|
||||
REPORT_ERROR("%s%d", "Unknown char in escape_dispatch: ", ch);
|
||||
REPORT_DRAW(ch);
|
||||
screen_draw(screen, ch);
|
||||
break;
|
||||
}
|
||||
#undef CALL_SCREEN_HANDLER
|
||||
} // }}}
|
||||
|
||||
// Esc mode {{{
|
||||
static inline void
|
||||
handle_esc_mode_char(Screen *screen, uint32_t ch, PyObject DUMP_UNUSED *dump_callback) {
|
||||
#define CALL_ED(name) REPORT_COMMAND(name, ch); name(screen); SET_STATE(0); break;
|
||||
switch(screen->parser_buf_pos) {
|
||||
case 0:
|
||||
switch (ch) {
|
||||
case ESC_DCS:
|
||||
SET_STATE(DCS); break;
|
||||
case ESC_OSC:
|
||||
SET_STATE(OSC); break;
|
||||
case ESC_CSI:
|
||||
SET_STATE(CSI); break;
|
||||
case ESC_RIS:
|
||||
CALL_ED(screen_reset);
|
||||
case ESC_IND:
|
||||
CALL_ED(screen_index);
|
||||
case ESC_NEL:
|
||||
CALL_ED(screen_linefeed);
|
||||
case ESC_RI:
|
||||
CALL_ED(screen_reverse_index);
|
||||
case ESC_HTS:
|
||||
CALL_ED(screen_set_tab_stop);
|
||||
case ESC_DECSC:
|
||||
CALL_ED(screen_save_cursor);
|
||||
case ESC_DECRC:
|
||||
CALL_ED(screen_restore_cursor);
|
||||
case ESC_DECPNM:
|
||||
CALL_ED(screen_normal_keypad_mode);
|
||||
case ESC_DECPAM:
|
||||
CALL_ED(screen_alternate_keypad_mode);
|
||||
case '%':
|
||||
case '(':
|
||||
case ')':
|
||||
case '*':
|
||||
case '+':
|
||||
case '-':
|
||||
case '.':
|
||||
case '/':
|
||||
case ' ':
|
||||
screen->parser_buf[screen->parser_buf_pos++] = ch;
|
||||
break;
|
||||
default:
|
||||
REPORT_ERROR("%s0x%x", "Unknown char after ESC: ", ch);
|
||||
SET_STATE(0); break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (screen->parser_buf[0] == '%' && ch == 'G') {
|
||||
// switch to utf-8, since we are always in utf-8, ignore.
|
||||
} else {
|
||||
REPORT_ERROR("Unhandled charset related escape code: 0x%x 0x%x", screen->parser_buf[0], screen->parser_buf[1]);
|
||||
}
|
||||
SET_STATE(0); break;
|
||||
}
|
||||
#undef CALL_ED
|
||||
}
|
||||
} // }}}
|
||||
|
||||
static inline void sharp_dispatch(Screen *screen, uint8_t ch, PyObject UNUSED *dump_callback) {
|
||||
switch(ch) {
|
||||
case DECALN:
|
||||
REPORT_COMMAND(screen_alignment_display);
|
||||
screen_alignment_display(screen);
|
||||
break;
|
||||
default:
|
||||
REPORT_ERROR("%s%d", "Unknown char in sharp_dispatch: ", ch);
|
||||
}
|
||||
// OSC mode {{{
|
||||
static inline void
|
||||
dispatch_osc(Screen *screen) {
|
||||
screen->parser_buf_pos++;
|
||||
}
|
||||
|
||||
HANDLER(esc) {
|
||||
#define ESC_DISPATCH(which, extra) REPORT_COMMAND(which, ch, extra); which(screen, ch, extra); SET_STATE(NORMAL_STATE); return;
|
||||
#ifdef DUMP_COMMANDS
|
||||
#define ESC_DELEGATE(which) which(screen, ch, dump_callback); SET_STATE(NORMAL_STATE); return;
|
||||
#else
|
||||
#define ESC_DELEGATE(which) which(screen, ch, NULL); SET_STATE(NORMAL_STATE); return;
|
||||
#endif
|
||||
uint8_t ch = buf[(*pos)++];
|
||||
switch(screen->parser_buf_pos) {
|
||||
case 0:
|
||||
switch(ch) {
|
||||
case '[':
|
||||
SET_STATE(CSI_STATE); return;
|
||||
case ']':
|
||||
SET_STATE(OSC_STATE); return;
|
||||
case 'P':
|
||||
SET_STATE(DCS_STATE); return;
|
||||
case '#':
|
||||
case '%':
|
||||
case '(':
|
||||
case ')':
|
||||
screen->parser_buf[0] = ch; screen->parser_buf_pos++; return;
|
||||
default:
|
||||
ESC_DELEGATE(escape_dispatch);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
switch(screen->parser_buf[0]) {
|
||||
case '#':
|
||||
ESC_DELEGATE(sharp_dispatch);
|
||||
case '%':
|
||||
ESC_DISPATCH(screen_select_other_charset, 0);
|
||||
case '(':
|
||||
case ')':
|
||||
ESC_DISPATCH(screen_define_charset, screen->parser_buf[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#undef ESC_DISPATCH
|
||||
#undef ESC_DELEGATE
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
// Parse CSI {{{
|
||||
|
||||
#define MAX_PARAMS 100
|
||||
|
||||
static inline unsigned int fill_params(Screen *screen, unsigned int *params, unsigned int expect) {
|
||||
unsigned int start_pos = 2, i = 2, pi = 0;
|
||||
uint8_t ch = 1;
|
||||
screen->parser_buf[screen->parser_buf_pos] = 0;
|
||||
|
||||
while (pi < MIN(MAX_PARAMS, expect) && i < PARSER_BUF_SZ - 1 && ch != 0) {
|
||||
ch = screen->parser_buf[i++];
|
||||
if (ch == 0 || ch == ';') {
|
||||
if (start_pos < i - 1) {
|
||||
params[pi++] = atoi((const char *)screen->parser_buf + start_pos);
|
||||
}
|
||||
start_pos = i;
|
||||
}
|
||||
}
|
||||
return pi;
|
||||
// DCS mode {{{
|
||||
static inline void
|
||||
dispatch_dcs(Screen *screen) {
|
||||
screen->parser_buf_pos++;
|
||||
}
|
||||
|
||||
static inline void screen_cursor_up2(Screen *s, unsigned int count) { screen_cursor_up(s, count, false, -1); }
|
||||
static inline void screen_cursor_back1(Screen *s, unsigned int count) { screen_cursor_back(s, count, -1); }
|
||||
|
||||
HANDLER(csi) {
|
||||
#define CALL_BASIC_HANDLER(name) REPORT_COMMAND(screen, ch); name(screen, ch); break;
|
||||
#define HANDLE_BASIC_CH \
|
||||
case BEL: \
|
||||
CALL_BASIC_HANDLER(screen_bell); \
|
||||
case BS: \
|
||||
CALL_BASIC_HANDLER(screen_backspace); \
|
||||
case HT: \
|
||||
CALL_BASIC_HANDLER(screen_tab); \
|
||||
case LF: \
|
||||
case VT: \
|
||||
case FF: \
|
||||
CALL_BASIC_HANDLER(screen_linefeed); \
|
||||
case CR: \
|
||||
CALL_BASIC_HANDLER(screen_carriage_return); \
|
||||
case NUL: \
|
||||
case DEL: \
|
||||
break; // no-op
|
||||
|
||||
#define END_DISPATCH SET_STATE(NORMAL_STATE); break;
|
||||
|
||||
#define CALL_CSI_HANDLER1(name, defval) \
|
||||
p1 = fill_params(screen, params, 1) > 0 ? params[0] : defval; \
|
||||
REPORT_COMMAND(name, p1); \
|
||||
name(screen, p1); \
|
||||
END_DISPATCH;
|
||||
|
||||
#define CALL_CSI_HANDLER1P(name, defval, qch) \
|
||||
p1 = fill_params(screen, params, 1) > 0 ? params[0] : defval; \
|
||||
private = screen->parser_buf[0] == qch; \
|
||||
REPORT_COMMAND(name, p1, private); \
|
||||
name(screen, p1, private); \
|
||||
END_DISPATCH;
|
||||
|
||||
#define CALL_CSI_HANDLER1M(name, defval) \
|
||||
p1 = fill_params(screen, params, 1) > 0 ? params[0] : defval; \
|
||||
REPORT_COMMAND(name, p1, screen->parser_buf[1]); \
|
||||
name(screen, p1, screen->parser_buf[1]); \
|
||||
END_DISPATCH;
|
||||
|
||||
#define CALL_CSI_HANDLER2(name, defval1, defval2) \
|
||||
count = fill_params(screen, params, 2); \
|
||||
p1 = count > 0 ? params[0] : defval1; \
|
||||
p2 = count > 1 ? params[1] : defval2; \
|
||||
REPORT_COMMAND(name, p1, p2); \
|
||||
name(screen, p1, p2); \
|
||||
END_DISPATCH;
|
||||
|
||||
#define SET_MODE(func) \
|
||||
count = fill_params(screen, params, MAX_PARAMS); \
|
||||
p1 = screen->parser_buf[0] == '?' ? 5 : 0; \
|
||||
for (i = 0; i < count; i++) { \
|
||||
REPORT_COMMAND(func, params[i] << p1); \
|
||||
func(screen, params[i] << p1); \
|
||||
} \
|
||||
END_DISPATCH;
|
||||
|
||||
#define CSI_HANDLER_MULTIPLE(name) \
|
||||
count = fill_params(screen, params, MAX_PARAMS); \
|
||||
REPORT_COMMAND(name, count); \
|
||||
name(screen, params, count); \
|
||||
END_DISPATCH;
|
||||
|
||||
|
||||
#define DISPATCH_CSI \
|
||||
case ICH: \
|
||||
CALL_CSI_HANDLER1(screen_insert_characters, 1); \
|
||||
case CUU: \
|
||||
CALL_CSI_HANDLER1(screen_cursor_up2, 1); \
|
||||
case CUD: \
|
||||
case VPR: \
|
||||
CALL_CSI_HANDLER1(screen_cursor_down, 1); \
|
||||
case CUF: \
|
||||
case HPR: \
|
||||
CALL_CSI_HANDLER1(screen_cursor_forward, 1); \
|
||||
case CUB: \
|
||||
CALL_CSI_HANDLER1(screen_cursor_back1, 1); \
|
||||
case CNL: \
|
||||
CALL_CSI_HANDLER1(screen_cursor_down1, 1); \
|
||||
case CPL: \
|
||||
CALL_CSI_HANDLER1(screen_cursor_up1, 1); \
|
||||
case CHA: \
|
||||
case HPA: \
|
||||
CALL_CSI_HANDLER1(screen_cursor_to_column, 1); \
|
||||
case VPA: \
|
||||
CALL_CSI_HANDLER1(screen_cursor_to_line, 1); \
|
||||
case CUP: \
|
||||
case HVP: \
|
||||
CALL_CSI_HANDLER2(screen_cursor_position, 1, 1); \
|
||||
case ED: \
|
||||
CALL_CSI_HANDLER1P(screen_erase_in_display, 0, '?'); \
|
||||
case EL: \
|
||||
CALL_CSI_HANDLER1P(screen_erase_in_line, 0, '?'); \
|
||||
case IL: \
|
||||
CALL_CSI_HANDLER1(screen_insert_lines, 1); \
|
||||
case DL: \
|
||||
CALL_CSI_HANDLER1(screen_delete_lines, 1); \
|
||||
case DCH: \
|
||||
CALL_CSI_HANDLER1(screen_delete_characters, 1); \
|
||||
case ECH: \
|
||||
CALL_CSI_HANDLER1(screen_erase_characters, 1); \
|
||||
case DA: \
|
||||
CALL_CSI_HANDLER1P(report_device_attributes, 0, '>'); \
|
||||
case TBC: \
|
||||
CALL_CSI_HANDLER1(screen_clear_tab_stop, 0); \
|
||||
case SM: \
|
||||
SET_MODE(screen_set_mode); \
|
||||
case RM: \
|
||||
SET_MODE(screen_reset_mode); \
|
||||
case SGR: \
|
||||
CSI_HANDLER_MULTIPLE(select_graphic_rendition); \
|
||||
case DSR: \
|
||||
CALL_CSI_HANDLER1P(report_device_status, 0, '?'); \
|
||||
case DECSTBM: \
|
||||
CALL_CSI_HANDLER2(screen_set_margins, 0, 0); \
|
||||
case DECSCUSR: \
|
||||
CALL_CSI_HANDLER1M(screen_set_cursor, 1); \
|
||||
|
||||
uint8_t ch = buf[(*pos)++];
|
||||
unsigned int params[MAX_PARAMS], p1, p2, count, i;
|
||||
bool private;
|
||||
switch(screen->parser_buf_pos) {
|
||||
case 0: // CSI starting
|
||||
screen->parser_buf[0] = 0;
|
||||
screen->parser_buf[1] = 0;
|
||||
screen->parser_buf[2] = 0;
|
||||
switch(ch) {
|
||||
IS_DIGIT
|
||||
screen->parser_buf_pos = 3;
|
||||
screen->parser_buf[2] = ch;
|
||||
break;
|
||||
case '?':
|
||||
case '>':
|
||||
case '!':
|
||||
screen->parser_buf[0] = ch; screen->parser_buf_pos = 1;
|
||||
break;
|
||||
HANDLE_BASIC_CH
|
||||
DISPATCH_CSI
|
||||
default:
|
||||
REPORT_ERROR("Invalid first character for CSI: 0x%x", ch);
|
||||
SET_STATE(NORMAL_STATE);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
screen->parser_buf_pos = 2; // we start params at 2
|
||||
default: // CSI started
|
||||
switch(ch) {
|
||||
IS_DIGIT
|
||||
case ';':
|
||||
if (screen->parser_buf_pos >= PARSER_BUF_SZ - 1) {
|
||||
REPORT_ERROR("%s", "CSI sequence too long, ignoring.");
|
||||
SET_STATE(NORMAL_STATE);
|
||||
} else screen->parser_buf[screen->parser_buf_pos++] = ch;
|
||||
break;
|
||||
case ' ':
|
||||
case '"':
|
||||
screen->parser_buf[1] = ch;
|
||||
break;
|
||||
HANDLE_BASIC_CH
|
||||
DISPATCH_CSI
|
||||
default:
|
||||
REPORT_ERROR("Invalid character for CSI: 0x%x", ch);
|
||||
SET_STATE(NORMAL_STATE);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#undef CALL_BASIC_HANDLER
|
||||
#undef HANDLE_BASIC_CH
|
||||
#undef CALL_CSI_HANDLER1
|
||||
}
|
||||
#undef MAX_PARAMS
|
||||
// }}}
|
||||
|
||||
// Parse OSC {{{
|
||||
// Parse loop {{{
|
||||
|
||||
static inline void handle_osc(Screen *screen, PyObject UNUSED *dump_callback) {
|
||||
unsigned int code = 0;
|
||||
unsigned int start = screen->parser_buf[0] ? screen->parser_buf[0] : 2;
|
||||
unsigned int sz = screen->parser_buf_pos > start ? screen->parser_buf_pos - start : 0;
|
||||
screen->parser_buf[screen->parser_buf_pos] = 0;
|
||||
if (screen->parser_buf[0] && screen->parser_buf[1]) code = (unsigned int)atoi((const char*)screen->parser_buf + 2);
|
||||
#define DISPATCH_OSC(name) \
|
||||
REPORT_COMMAND(name, sz); \
|
||||
name(screen, (const char*)(screen->parser_buf + start), sz);
|
||||
|
||||
switch(code) {
|
||||
case 0:
|
||||
DISPATCH_OSC(set_title);
|
||||
DISPATCH_OSC(set_icon);
|
||||
break;
|
||||
case 1:
|
||||
DISPATCH_OSC(set_icon);
|
||||
break;
|
||||
case 2:
|
||||
DISPATCH_OSC(set_title);
|
||||
break;
|
||||
case 10:
|
||||
case 11:
|
||||
case 110:
|
||||
case 111:
|
||||
REPORT_COMMAND(set_dynamic_color, code, sz);
|
||||
set_dynamic_color(screen, code, (const char*)(screen->parser_buf + start), sz);
|
||||
break;
|
||||
default:
|
||||
REPORT_ERROR("Unknown OSC code: %u", code);
|
||||
}
|
||||
#undef DISPATCH_OSC
|
||||
}
|
||||
|
||||
|
||||
HANDLER(osc) {
|
||||
#ifdef DUMP_COMMANDS
|
||||
#define HANDLE_OSC handle_osc(screen, dump_callback);
|
||||
#else
|
||||
#define HANDLE_OSC handle_osc(screen, NULL);
|
||||
#endif
|
||||
uint8_t ch = buf[(*pos)++];
|
||||
if (screen->parser_buf_pos == 0) {
|
||||
screen->parser_buf[0] = 0;
|
||||
screen->parser_buf[1] = 1;
|
||||
screen->parser_buf_pos = 2;
|
||||
}
|
||||
static inline bool
|
||||
accumulate_osc(Screen *screen, uint32_t ch, PyObject DUMP_UNUSED *dump_callback) {
|
||||
switch(ch) {
|
||||
case ST:
|
||||
return true;
|
||||
case ESC_ST:
|
||||
if (screen->parser_buf_pos > 0 && screen->parser_buf[screen->parser_buf_pos - 1] == ESC) {
|
||||
screen->parser_buf_pos--;
|
||||
return true;
|
||||
}
|
||||
case BEL:
|
||||
if(!screen->parser_buf[0] && screen->parser_buf[1]) {
|
||||
// Only a numeric component
|
||||
screen->parser_buf[0] = screen->parser_buf_pos;
|
||||
}
|
||||
HANDLE_OSC;
|
||||
SET_STATE(NORMAL_STATE);
|
||||
return true;
|
||||
case NUL:
|
||||
case DEL:
|
||||
break;
|
||||
case 0:
|
||||
break; // ignore null bytes
|
||||
case ';':
|
||||
if (!screen->parser_buf[0] && screen->parser_buf_pos < 10) {
|
||||
// Initial numeric parameter found
|
||||
screen->parser_buf[0] = screen->parser_buf_pos;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (!screen->parser_buf[0] && (ch < '0' || ch > '9')) {
|
||||
screen->parser_buf[1] = 0; // No initial numeric parameter
|
||||
}
|
||||
if (screen->parser_buf_pos >= PARSER_BUF_SZ - 1) {
|
||||
REPORT_ERROR("OSC control sequence too long, truncating");
|
||||
HANDLE_OSC;
|
||||
SET_STATE(NORMAL_STATE);
|
||||
break;
|
||||
REPORT_ERROR("OSC sequence too long, truncating.");
|
||||
return true;
|
||||
}
|
||||
screen->parser_buf[screen->parser_buf_pos++] = ch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// }}}
|
||||
|
||||
// Parse DCS {{{
|
||||
|
||||
static void handle_dcs(Screen *screen, PyObject UNUSED *dump_callback) {
|
||||
screen->parser_buf_pos = 0;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
HANDLER(dcs) {
|
||||
// http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Device-Control-functions
|
||||
#ifndef DUMP_COMMANDS
|
||||
PyObject *dump_callback = NULL;
|
||||
#endif
|
||||
#define DISPATCH_DCS \
|
||||
SET_STATE(NORMAL_STATE); \
|
||||
if (screen->parser_buf_pos == 0) { REPORT_ERROR("Empty DCS sequence, ignoring."); return; } \
|
||||
REPORT_DCS; \
|
||||
handle_dcs(screen, dump_callback);
|
||||
|
||||
uint8_t ch = buf[(*pos)++];
|
||||
switch (ch) {
|
||||
static inline bool
|
||||
accumulate_dcs(Screen *screen, uint32_t ch, PyObject DUMP_UNUSED *dump_callback) {
|
||||
switch(ch) {
|
||||
case ST:
|
||||
DISPATCH_DCS;
|
||||
return true;
|
||||
case NUL:
|
||||
case DEL:
|
||||
break;
|
||||
case ESC:
|
||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||
case 32 ... 126:
|
||||
#pragma GCC diagnostic pop
|
||||
if (screen->parser_buf_pos > 0 && screen->parser_buf[screen->parser_buf_pos-1] == ESC) {
|
||||
if (ch == '\\') { screen->parser_buf_pos--; return true; }
|
||||
REPORT_ERROR("DCS sequence contained non-printable character: 0x%x ignoring the sequence", ESC);
|
||||
SET_STATE(ESC); return false;
|
||||
}
|
||||
if (screen->parser_buf_pos >= PARSER_BUF_SZ - 1) {
|
||||
REPORT_ERROR("DCS sequence too long, truncating.");
|
||||
return true;
|
||||
}
|
||||
screen->parser_buf[screen->parser_buf_pos++] = ch;
|
||||
break;
|
||||
default:
|
||||
if (screen->parser_buf_pos >= PARSER_BUF_SZ - 1) {
|
||||
DISPATCH_DCS;
|
||||
} else screen->parser_buf[screen->parser_buf_pos++] = ch;
|
||||
break;
|
||||
REPORT_ERROR("DCS sequence contained non-printable character: 0x%x ignoring the sequence", ch);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_parse_bytes(Screen *screen, uint8_t *buf, Py_ssize_t len, PyObject DUMP_UNUSED *dump_callback) {
|
||||
#define HANDLE(name) handle_##name(screen, codepoint, dump_callback); break
|
||||
uint32_t prev = screen->utf8_state, codepoint = 0;
|
||||
for (unsigned int i = 0; i < len; i++, prev = screen->utf8_state) {
|
||||
switch (decode_utf8(&screen->utf8_state, &codepoint, buf[i])) {
|
||||
case UTF8_ACCEPT:
|
||||
switch(screen->parser_state) {
|
||||
case ESC:
|
||||
HANDLE(esc_mode_char);
|
||||
/* case CSI_STATE: */
|
||||
/* CALL_HANDLER(csi); */
|
||||
case OSC:
|
||||
if (accumulate_osc(screen, codepoint, dump_callback)) { dispatch_osc(screen); SET_STATE(0); }
|
||||
break;
|
||||
case DCS:
|
||||
if (accumulate_dcs(screen, codepoint, dump_callback)) { dispatch_dcs(screen); SET_STATE(0); }
|
||||
if (screen->parser_state == ESC) { HANDLE(esc_mode_char); }
|
||||
break;
|
||||
default:
|
||||
HANDLE(normal_mode_char);
|
||||
}
|
||||
break;
|
||||
case UTF8_REJECT:
|
||||
screen->utf8_state = UTF8_ACCEPT;
|
||||
if (prev != UTF8_ACCEPT) i--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#undef HANDLE
|
||||
}
|
||||
// }}}
|
||||
|
||||
static inline void _parse_bytes(Screen *screen, uint8_t *buf, Py_ssize_t len, PyObject UNUSED *dump_callback) {
|
||||
unsigned int i = 0;
|
||||
// Boilerplate {{{
|
||||
#ifdef DUMP_COMMANDS
|
||||
#define CALL_HANDLER(name) read_##name(screen, buf, len, &i, dump_callback); break;
|
||||
#define FNAME(x) x##_dump
|
||||
#else
|
||||
#define CALL_HANDLER(name) read_##name(screen, buf, len, &i); break;
|
||||
#define FNAME(x) x
|
||||
#endif
|
||||
/* PyObject_Print(Py_BuildValue("y#", buf, len), stdout, 0); */
|
||||
|
||||
while (i < len) {
|
||||
switch(screen->parser_state) {
|
||||
case ESC_STATE:
|
||||
CALL_HANDLER(esc);
|
||||
case CSI_STATE:
|
||||
CALL_HANDLER(csi);
|
||||
case OSC_STATE:
|
||||
CALL_HANDLER(osc);
|
||||
case DCS_STATE:
|
||||
CALL_HANDLER(dcs);
|
||||
default:
|
||||
CALL_HANDLER(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PyObject*
|
||||
#ifdef DUMP_COMMANDS
|
||||
parse_bytes_dump(PyObject UNUSED *self, PyObject *args) {
|
||||
#else
|
||||
parse_bytes(PyObject UNUSED *self, PyObject *args) {
|
||||
#endif
|
||||
FNAME(parse_bytes)(PyObject UNUSED *self, PyObject *args) {
|
||||
PyObject *dump_callback = NULL;
|
||||
Py_buffer pybuf;
|
||||
Screen *screen;
|
||||
#ifdef DUMP_COMMANDS
|
||||
if (!PyArg_ParseTuple(args, "OO!y*", &dump_callback, &Screen_Type, &screen, &pybuf)) return NULL;
|
||||
if (!PyCallable_Check(dump_callback)) { PyErr_SetString(PyExc_TypeError, "The dump callback must be a callable object"); return NULL; }
|
||||
#else
|
||||
if (!PyArg_ParseTuple(args, "O!y*", &Screen_Type, &screen, &pybuf)) return NULL;
|
||||
#endif
|
||||
@ -585,11 +282,7 @@ parse_bytes(PyObject UNUSED *self, PyObject *args) {
|
||||
}
|
||||
|
||||
PyObject*
|
||||
#ifdef DUMP_COMMANDS
|
||||
read_bytes_dump(PyObject UNUSED *self, PyObject *args) {
|
||||
#else
|
||||
read_bytes(PyObject UNUSED *self, PyObject *args) {
|
||||
#endif
|
||||
FNAME(read_bytes)(PyObject UNUSED *self, PyObject *args) {
|
||||
PyObject *dump_callback = NULL;
|
||||
Py_ssize_t len;
|
||||
Screen *screen;
|
||||
@ -613,4 +306,5 @@ read_bytes(PyObject UNUSED *self, PyObject *args) {
|
||||
if(len > 0) { Py_RETURN_TRUE; }
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
#undef FNAME
|
||||
// }}}
|
||||
|
||||
128
kitty/screen.c
128
kitty/screen.c
@ -23,9 +23,6 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
||||
|
||||
self = (Screen *)type->tp_alloc(type, 0);
|
||||
if (self != NULL) {
|
||||
self->current_charset = 2;
|
||||
self->g0_charset = translation_table('B');
|
||||
self->g1_charset = translation_table('0');
|
||||
self->columns = columns; self->lines = lines;
|
||||
self->modes = empty_modes;
|
||||
self->utf8_state = 0;
|
||||
@ -47,9 +44,6 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
||||
void screen_reset(Screen *self) {
|
||||
if (self->linebuf == self->alt_linebuf) screen_toggle_screen_buffer(self);
|
||||
linebuf_clear(self->linebuf);
|
||||
self->current_charset = 2;
|
||||
self->g0_charset = translation_table('B');
|
||||
self->g1_charset = translation_table('0');
|
||||
self->modes = empty_modes;
|
||||
self->utf8_state = 0;
|
||||
self->margin_top = 0; self->margin_bottom = self->lines - 1;
|
||||
@ -126,52 +120,22 @@ dealloc(Screen* self) {
|
||||
|
||||
// Draw text {{{
|
||||
|
||||
void screen_shift_out(Screen *self, uint8_t UNUSED ch) {
|
||||
self->current_charset = 1;
|
||||
self->utf8_state = 0;
|
||||
}
|
||||
|
||||
void screen_shift_in(Screen *self, uint8_t UNUSED ch) {
|
||||
self->current_charset = 0;
|
||||
self->utf8_state = 0;
|
||||
}
|
||||
|
||||
void screen_define_charset(Screen *self, uint8_t code, uint8_t mode) {
|
||||
switch(mode) {
|
||||
case '(':
|
||||
self->g0_charset = translation_table(code);
|
||||
break;
|
||||
default:
|
||||
self->g1_charset = translation_table(code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void screen_select_other_charset(Screen *self, uint8_t code, uint8_t UNUSED unused) {
|
||||
switch(code) {
|
||||
case '@':
|
||||
self->current_charset = 0;
|
||||
break;
|
||||
default:
|
||||
self->current_charset = 2;
|
||||
self->utf8_state = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned int safe_wcwidth(uint32_t ch) {
|
||||
static inline unsigned int
|
||||
safe_wcwidth(uint32_t ch) {
|
||||
int ans = wcwidth(ch);
|
||||
if (ans < 0) ans = 1;
|
||||
return MIN(2, ans);
|
||||
}
|
||||
|
||||
static inline void
|
||||
draw_codepoint(Screen UNUSED *self, uint32_t ch) {
|
||||
void
|
||||
screen_draw(Screen *self, uint32_t ch) {
|
||||
if (is_ignored_char(ch)) return;
|
||||
unsigned int x = self->cursor->x, y = self->cursor->y;
|
||||
unsigned int char_width = safe_wcwidth(ch);
|
||||
if (self->columns - self->cursor->x < char_width) {
|
||||
if (self->modes.mDECAWM) {
|
||||
screen_carriage_return(self, 13);
|
||||
screen_linefeed(self, 10);
|
||||
screen_carriage_return(self);
|
||||
screen_linefeed(self);
|
||||
self->linebuf->continued_map[self->cursor->y] = true;
|
||||
} else {
|
||||
self->cursor->x = self->columns - char_width;
|
||||
@ -202,43 +166,9 @@ draw_codepoint(Screen UNUSED *self, uint32_t ch) {
|
||||
tracker_update_cell_range(self->change_tracker, self->cursor->y - 1, self->columns - 1, self->columns - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
screen_draw_utf8(Screen *self, uint8_t *buf, unsigned int buflen) {
|
||||
uint32_t prev = UTF8_ACCEPT, codepoint = 0;
|
||||
for (unsigned int i = 0; i < buflen; i++, prev = self->utf8_state) {
|
||||
switch (decode_utf8(&self->utf8_state, &codepoint, buf[i])) {
|
||||
case UTF8_ACCEPT:
|
||||
draw_codepoint(self, codepoint);
|
||||
break;
|
||||
case UTF8_REJECT:
|
||||
self->utf8_state = UTF8_ACCEPT;
|
||||
if (prev != UTF8_ACCEPT) i--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
screen_draw_charset(Screen *self, unsigned short *table, uint8_t *buf, unsigned int buflen) {
|
||||
for (unsigned int i = 0; i < buflen; i++) {
|
||||
draw_codepoint(self, table[buf[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
void screen_draw(Screen *self, uint8_t *buf, unsigned int buflen) {
|
||||
unsigned int x = self->cursor->x, y = self->cursor->y;
|
||||
switch(self->current_charset) {
|
||||
case 0:
|
||||
screen_draw_charset(self, self->g0_charset, buf, buflen); break;
|
||||
case 1:
|
||||
screen_draw_charset(self, self->g1_charset, buf, buflen); break;
|
||||
default:
|
||||
screen_draw_utf8(self, buf, buflen); break;
|
||||
}
|
||||
if (x != self->cursor->x || y != self->cursor->y) tracker_cursor_changed(self->change_tracker);
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
// Graphics {{{
|
||||
@ -451,10 +381,10 @@ void screen_reset_mode(Screen *self, unsigned int mode) {
|
||||
|
||||
// Cursor {{{
|
||||
|
||||
void screen_backspace(Screen *self, uint8_t UNUSED ch) {
|
||||
void screen_backspace(Screen *self) {
|
||||
screen_cursor_back(self, 1, -1);
|
||||
}
|
||||
void screen_tab(Screen *self, uint8_t UNUSED ch) {
|
||||
void screen_tab(Screen *self) {
|
||||
// Move to the next tab space, or the end of the screen if there aren't anymore left.
|
||||
unsigned int found = 0;
|
||||
for (unsigned int i = self->cursor->x + 1; i < self->columns; i++) {
|
||||
@ -556,16 +486,16 @@ void screen_reverse_index(Screen *self) {
|
||||
}
|
||||
|
||||
|
||||
void screen_carriage_return(Screen *self, uint8_t UNUSED ch) {
|
||||
void screen_carriage_return(Screen *self) {
|
||||
if (self->cursor->x != 0) {
|
||||
self->cursor->x = 0;
|
||||
tracker_cursor_changed(self->change_tracker);
|
||||
}
|
||||
}
|
||||
|
||||
void screen_linefeed(Screen *self, uint8_t UNUSED ch) {
|
||||
void screen_linefeed(Screen *self) {
|
||||
screen_index(self);
|
||||
if (self->modes.mLNM) screen_carriage_return(self, 13);
|
||||
if (self->modes.mLNM) screen_carriage_return(self);
|
||||
screen_ensure_bounds(self, false);
|
||||
}
|
||||
|
||||
@ -586,9 +516,6 @@ void screen_save_cursor(Screen *self) {
|
||||
SavepointBuffer *pts = self->linebuf == self->main_linebuf ? &self->main_savepoints : &self->alt_savepoints;
|
||||
Savepoint *sp = savepoints_push(pts);
|
||||
cursor_copy_to(self->cursor, &(sp->cursor));
|
||||
sp->g0_charset = self->g0_charset;
|
||||
sp->g1_charset = self->g1_charset;
|
||||
sp->current_charset = self->current_charset;
|
||||
sp->mDECOM = self->modes.mDECOM;
|
||||
sp->mDECAWM = self->modes.mDECAWM;
|
||||
sp->utf8_state = self->utf8_state;
|
||||
@ -601,13 +528,7 @@ void screen_restore_cursor(Screen *self) {
|
||||
screen_cursor_position(self, 1, 1);
|
||||
tracker_cursor_changed(self->change_tracker);
|
||||
screen_reset_mode(self, DECOM);
|
||||
self->current_charset = 2;
|
||||
self->g0_charset = translation_table('B');
|
||||
self->g1_charset = translation_table('0');
|
||||
} else {
|
||||
self->g0_charset = sp->g0_charset;
|
||||
self->g1_charset = sp->g1_charset;
|
||||
self->current_charset = sp->current_charset;
|
||||
self->utf8_state = sp->utf8_state;
|
||||
if (sp->mDECOM) screen_set_mode(self, DECOM);
|
||||
if (sp->mDECAWM) screen_set_mode(self, DECAWM);
|
||||
@ -739,7 +660,7 @@ void screen_insert_lines(Screen *self, unsigned int count) {
|
||||
if (top <= self->cursor->y && self->cursor->y <= bottom) {
|
||||
linebuf_insert_lines(self->linebuf, count, self->cursor->y, bottom);
|
||||
tracker_update_line_range(self->change_tracker, self->cursor->y, bottom);
|
||||
screen_carriage_return(self, 13);
|
||||
screen_carriage_return(self);
|
||||
}
|
||||
}
|
||||
|
||||
@ -749,7 +670,7 @@ void screen_delete_lines(Screen *self, unsigned int count) {
|
||||
if (top <= self->cursor->y && self->cursor->y <= bottom) {
|
||||
linebuf_delete_lines(self->linebuf, count, self->cursor->y, bottom);
|
||||
tracker_update_line_range(self->change_tracker, self->cursor->y, bottom);
|
||||
screen_carriage_return(self, 13);
|
||||
screen_carriage_return(self);
|
||||
}
|
||||
}
|
||||
|
||||
@ -794,10 +715,11 @@ void screen_erase_characters(Screen *self, unsigned int count) {
|
||||
|
||||
// Device control {{{
|
||||
|
||||
void screen_bell(Screen UNUSED *self, uint8_t ch) {
|
||||
void screen_bell(Screen UNUSED *self) {
|
||||
FILE *f = fopen("/dev/tty", "w");
|
||||
static const char *bell = "\007";
|
||||
if (f != NULL) {
|
||||
fwrite(&ch, 1, 1, f);
|
||||
fwrite(bell, 1, 1, f);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
@ -901,11 +823,14 @@ line(Screen *self, PyObject *val) {
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
draw(Screen *self, PyObject *args) {
|
||||
draw(Screen *self, PyObject *src) {
|
||||
#define draw_doc ""
|
||||
Py_buffer pybuf;
|
||||
if(!PyArg_ParseTuple(args, "y*", &pybuf)) return NULL;
|
||||
screen_draw(self, pybuf.buf, pybuf.len);
|
||||
if (!PyUnicode_Check(src)) { PyErr_SetString(PyExc_TypeError, "A unicode string is required"); return NULL; }
|
||||
if (PyUnicode_READY(src) != 0) { return PyErr_NoMemory(); }
|
||||
int kind = PyUnicode_KIND(src);
|
||||
void *buf = PyUnicode_DATA(src);
|
||||
Py_ssize_t sz = PyUnicode_GET_LENGTH(src);
|
||||
for (Py_ssize_t i = 0; i < sz; i++) screen_draw(self, PyUnicode_READ(kind, buf, i));
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
@ -1097,7 +1022,7 @@ COUNT_WRAP(cursor_forward)
|
||||
|
||||
static PyMethodDef methods[] = {
|
||||
METHOD(line, METH_O)
|
||||
METHOD(draw, METH_VARARGS)
|
||||
METHOD(draw, METH_O)
|
||||
METHOD(set_mode, METH_VARARGS)
|
||||
METHOD(reset_mode, METH_VARARGS)
|
||||
METHOD(enable_focus_tracking, METH_NOARGS)
|
||||
@ -1139,7 +1064,6 @@ static PyMemberDef members[] = {
|
||||
{"columns", T_UINT, offsetof(Screen, columns), READONLY, "columns"},
|
||||
{"margin_top", T_UINT, offsetof(Screen, margin_top), READONLY, "margin_top"},
|
||||
{"margin_bottom", T_UINT, offsetof(Screen, margin_bottom), READONLY, "margin_bottom"},
|
||||
{"current_charset", T_UINT, offsetof(Screen, current_charset), READONLY, "current_charset"},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ class Callbacks:
|
||||
self.wtcbuf = self.iconbuf = self.titlebuf = self.colorbuf = b''
|
||||
|
||||
|
||||
class TestScreen(BaseTest):
|
||||
class TestParser(BaseTest):
|
||||
|
||||
def parse_bytes_dump(self, s, x, *cmds):
|
||||
cd = CmdDump()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user