misc parser and test fixes
This commit is contained in:
parent
5168e0b576
commit
52025ff030
10 changed files with 55 additions and 76 deletions
|
|
@ -1067,7 +1067,7 @@ class Screen:
|
|||
cursor_key_mode: bool
|
||||
auto_repeat_enabled: bool
|
||||
render_unfocused_cursor: int
|
||||
last_reported_cwd: Optional[str]
|
||||
last_reported_cwd: Optional[bytes]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
|
|
|||
|
|
@ -2196,11 +2196,13 @@ set_color_table_color(Screen *self, unsigned int code, PyObject *color) {
|
|||
}
|
||||
|
||||
void
|
||||
process_cwd_notification(Screen *self, unsigned int code, PyObject *cwd) {
|
||||
process_cwd_notification(Screen *self, unsigned int code, const char *data, size_t sz) {
|
||||
if (code == 7) {
|
||||
Py_CLEAR(self->last_reported_cwd);
|
||||
self->last_reported_cwd = cwd;
|
||||
Py_INCREF(self->last_reported_cwd);
|
||||
PyObject *x = PyBytes_FromStringAndSize(data, sz);
|
||||
if (x) {
|
||||
Py_CLEAR(self->last_reported_cwd);
|
||||
self->last_reported_cwd = x;
|
||||
} else { PyErr_Clear(); }
|
||||
} // we ignore OSC 6 document reporting as we dont have a use for it
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ void clipboard_control(Screen *self, int code, PyObject*);
|
|||
void shell_prompt_marking(Screen *self, char *buf);
|
||||
void file_transmission(Screen *self, PyObject*);
|
||||
void set_color_table_color(Screen *self, unsigned int code, PyObject*);
|
||||
void process_cwd_notification(Screen *self, unsigned int code, PyObject*);
|
||||
void process_cwd_notification(Screen *self, unsigned int code, const char*, size_t);
|
||||
void screen_request_capabilities(Screen *, char, const char *);
|
||||
void report_device_attributes(Screen *self, unsigned int UNUSED mode, char start_modifier);
|
||||
void select_graphic_rendition(Screen *self, int *params, unsigned int count, Region*);
|
||||
|
|
|
|||
|
|
@ -1050,7 +1050,9 @@ def cleanup_ssh_control_masters() -> None:
|
|||
os.remove(x)
|
||||
|
||||
|
||||
def path_from_osc7_url(url: str) -> str:
|
||||
def path_from_osc7_url(url: Union[str, bytes]) -> str:
|
||||
if isinstance(url, bytes):
|
||||
url = url.decode('utf-8')
|
||||
if url.startswith('kitty-shell-cwd://'):
|
||||
return '/' + url.split('/', 3)[-1]
|
||||
if url.startswith('file://'):
|
||||
|
|
|
|||
|
|
@ -311,7 +311,8 @@ dispatch_esc_mode_byte(PS *self) {
|
|||
case '0':
|
||||
case 'U':
|
||||
case 'V':
|
||||
REPORT_ERROR("Ignoring attempt to designate charset as we support only UTF-8");
|
||||
// dont report this error as fish shell designates charsets for some unholy reason, creating lot of noise in the tests
|
||||
/* REPORT_ERROR("Ignoring attempt to designate charset as we support only UTF-8"); */
|
||||
break;
|
||||
default:
|
||||
REPORT_ERROR("Unknown charset: 0x%x", ch); break;
|
||||
|
|
@ -466,7 +467,8 @@ dispatch_osc(PS *self) {
|
|||
case 6:
|
||||
case 7:
|
||||
START_DISPATCH
|
||||
DISPATCH_OSC_WITH_CODE(process_cwd_notification);
|
||||
REPORT_OSC2(shell_prompt_marking, code, mv);
|
||||
process_cwd_notification(self->screen, code, (char*)self->parser_buf + i, limit-i);
|
||||
END_DISPATCH
|
||||
case 8:
|
||||
dispatch_hyperlink(self, i, limit-i);
|
||||
|
|
@ -1047,7 +1049,11 @@ dispatch_csi(PS *self) {
|
|||
Region r = {0};
|
||||
unsigned int consumed = parse_region(&r, buf, num);
|
||||
num -= consumed; buf += consumed;
|
||||
#ifdef DUMP_COMMANDS
|
||||
parse_sgr_dump(self, buf, num, params, "deccara", &r);
|
||||
#else
|
||||
parse_sgr(self->screen, buf, num, params, "deccara", &r);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1474,7 +1480,7 @@ pending_csi(PS *self) {
|
|||
|
||||
static void
|
||||
queue_pending_bytes(PS *self) {
|
||||
for (; self->input_pos < self->input_sz; self->input_pos++) {
|
||||
while (self->input_pos < self->input_sz) {
|
||||
dispatch_single_byte(pending, if (!self->pending_mode.activated_at) goto end);
|
||||
}
|
||||
end:
|
||||
|
|
@ -1485,7 +1491,7 @@ static void
|
|||
parse_pending_bytes(PS *self) {
|
||||
SAVE_INPUT_DATA;
|
||||
self->input_data = self->pending_mode.buf; self->input_sz = self->pending_mode.used;
|
||||
for (self->input_pos = 0; self->input_pos < self->input_sz; self->input_pos++) {
|
||||
while (self->input_pos < self->input_sz) {
|
||||
dispatch_single_byte(dispatch, ;);
|
||||
}
|
||||
RESTORE_INPUT_DATA;
|
||||
|
|
@ -1504,7 +1510,7 @@ dump_partial_escape_code_to_pending(PS *self) {
|
|||
|
||||
static void
|
||||
parse_bytes_watching_for_pending(PS *self) {
|
||||
for (; self->input_pos < self->input_sz; self->input_pos++) {
|
||||
while (self->input_pos < self->input_sz) {
|
||||
dispatch_single_byte(dispatch, if (self->pending_mode.activated_at) goto end);
|
||||
}
|
||||
end:
|
||||
|
|
|
|||
|
|
@ -37,21 +37,21 @@ def __init__(self, pty=None) -> None:
|
|||
self.set_pointer_shape = lambda data: None
|
||||
|
||||
def write(self, data) -> None:
|
||||
self.wtcbuf += data
|
||||
self.wtcbuf += bytes(data)
|
||||
|
||||
def title_changed(self, data, is_base64=False) -> None:
|
||||
self.titlebuf.append(process_title_from_child(data, is_base64))
|
||||
self.titlebuf.append(process_title_from_child(data, is_base64, ''))
|
||||
|
||||
def icon_changed(self, data) -> None:
|
||||
self.iconbuf += data
|
||||
self.iconbuf += str(data, 'utf-8')
|
||||
|
||||
def set_dynamic_color(self, code, data) -> None:
|
||||
def set_dynamic_color(self, code, data='') -> None:
|
||||
if code == 22:
|
||||
self.set_pointer_shape(data)
|
||||
else:
|
||||
self.colorbuf += data or ''
|
||||
self.colorbuf += str(data or b'', 'utf-8')
|
||||
|
||||
def set_color_table_color(self, code, data) -> None:
|
||||
def set_color_table_color(self, code, data='') -> None:
|
||||
self.ctbuf += ''
|
||||
|
||||
def color_profile_popped(self, x) -> None:
|
||||
|
|
@ -65,23 +65,19 @@ def request_capabilities(self, q) -> None:
|
|||
for c in get_capabilities(q, None):
|
||||
self.write(c.encode('ascii'))
|
||||
|
||||
def use_utf8(self, on) -> None:
|
||||
self.iutf8 = on
|
||||
|
||||
def desktop_notify(self, osc_code: int, raw_data: str) -> None:
|
||||
self.notifications.append((osc_code, raw_data))
|
||||
def desktop_notify(self, osc_code: int, raw_data: memoryview) -> None:
|
||||
self.notifications.append((osc_code, str(raw_data, 'utf-8')))
|
||||
|
||||
def open_url(self, url: str, hyperlink_id: int) -> None:
|
||||
self.open_urls.append((url, hyperlink_id))
|
||||
|
||||
def clipboard_control(self, data: str, is_partial: bool = False) -> None:
|
||||
self.cc_buf.append((data, is_partial))
|
||||
def clipboard_control(self, data: memoryview, is_partial: bool = False) -> None:
|
||||
self.cc_buf.append((str(data, 'utf-8'), is_partial))
|
||||
|
||||
def clear(self) -> None:
|
||||
self.wtcbuf = b''
|
||||
self.iconbuf = self.colorbuf = self.ctbuf = ''
|
||||
self.titlebuf = []
|
||||
self.iutf8 = True
|
||||
self.notifications = []
|
||||
self.open_urls = []
|
||||
self.cc_buf = []
|
||||
|
|
@ -112,6 +108,7 @@ def handle_remote_print(self, msg):
|
|||
print(text, file=sys.__stdout__, end='', flush=True)
|
||||
|
||||
def handle_remote_clone(self, msg):
|
||||
msg = str(msg, 'utf-8')
|
||||
if not msg:
|
||||
if self.current_clone_data:
|
||||
cdata, self.current_clone_data = self.current_clone_data, ''
|
||||
|
|
|
|||
|
|
@ -9,13 +9,19 @@
|
|||
from kitty.fast_data_types import CURSOR_BLOCK, base64_decode, base64_encode
|
||||
from kitty.notify import NotificationCommand, handle_notification_cmd, notification_activated, reset_registry
|
||||
|
||||
from . import BaseTest
|
||||
from . import BaseTest, parse_bytes
|
||||
|
||||
|
||||
def cnv(x):
|
||||
if isinstance(x, memoryview):
|
||||
x = str(x, 'utf-8')
|
||||
return x
|
||||
|
||||
|
||||
class CmdDump(list):
|
||||
|
||||
def __call__(self, *a):
|
||||
self.append(a)
|
||||
self.append(tuple(map(cnv, a)))
|
||||
|
||||
|
||||
class TestParser(BaseTest):
|
||||
|
|
@ -24,7 +30,7 @@ def parse_bytes_dump(self, s, x, *cmds):
|
|||
cd = CmdDump()
|
||||
if isinstance(x, str):
|
||||
x = x.encode('utf-8')
|
||||
cmds = tuple(('draw', x) if isinstance(x, str) else x for x in cmds)
|
||||
cmds = tuple(('draw', x) if isinstance(x, str) else tuple(map(cnv, x)) for x in cmds)
|
||||
s.vt_parser.parse_bytes(s, x, cd)
|
||||
current = ''
|
||||
q = []
|
||||
|
|
@ -82,23 +88,6 @@ def test_esc_codes(self):
|
|||
pb('\033c123', ('screen_reset', ), '123')
|
||||
self.ae(str(s.line(0)), '123')
|
||||
|
||||
def test_charsets(self):
|
||||
s = self.create_screen()
|
||||
pb = partial(self.parse_bytes_dump, s)
|
||||
pb(b'\xc3')
|
||||
pb(b'\xa1', ('draw', b'\xc3\xa1'.decode('utf-8')))
|
||||
s = self.create_screen()
|
||||
pb = partial(self.parse_bytes_dump, s)
|
||||
pb('\033)0\x0e/_', ('screen_designate_charset', 1, ord('0')), ('screen_change_charset', 1), '/_')
|
||||
self.ae(str(s.line(0)), '/\xa0')
|
||||
self.assertTrue(s.callbacks.iutf8)
|
||||
pb('\033%@_', ('screen_use_latin1', 1), '_')
|
||||
self.assertFalse(s.callbacks.iutf8)
|
||||
s = self.create_screen()
|
||||
pb = partial(self.parse_bytes_dump, s)
|
||||
pb('\033(0/_', ('screen_designate_charset', 0, ord('0')), '/_')
|
||||
self.ae(str(s.line(0)), '/\xa0')
|
||||
|
||||
def test_csi_codes(self):
|
||||
s = self.create_screen()
|
||||
pb = partial(self.parse_bytes_dump, s)
|
||||
|
|
@ -218,7 +207,7 @@ def test_osc_codes(self):
|
|||
s = self.create_screen()
|
||||
pb = partial(self.parse_bytes_dump, s)
|
||||
c = s.callbacks
|
||||
pb('a\033]2;x\\ryz\x9cbcde', 'a', ('set_title', 'x\\ryz'), 'bcde')
|
||||
pb('a\033]2;x\\ryz\033\\bcde', 'a', ('set_title', 'x\\ryz'), 'bcde')
|
||||
self.ae(str(s.line(0)), 'abcde')
|
||||
self.ae(c.titlebuf, ['x\\ryz'])
|
||||
c.clear()
|
||||
|
|
@ -319,7 +308,7 @@ def test_dcs_codes(self):
|
|||
c = s.callbacks
|
||||
pb = partial(self.parse_bytes_dump, s)
|
||||
q = hexlify(b'kind').decode('ascii')
|
||||
pb(f'a\033P+q{q}\x9cbcde', 'a', ('screen_request_capabilities', 43, q), 'bcde')
|
||||
pb(f'a\033P+q{q}\033\\bcde', 'a', ('screen_request_capabilities', 43, q), 'bcde')
|
||||
self.ae(str(s.line(0)), 'abcde')
|
||||
self.ae(c.wtcbuf, '1+r{}={}'.format(q, '1b5b313b3242').encode('ascii'))
|
||||
c.clear()
|
||||
|
|
@ -331,24 +320,13 @@ def test_dcs_codes(self):
|
|||
for sgr in '0;34;102;1;2;3;4 0;38:5:200;58:2:10:11:12'.split():
|
||||
expected = set(sgr.split(';')) - {'0'}
|
||||
c.clear()
|
||||
s.vte_parser.parse_bytes(s, f'\033[{sgr}m\033P$qm\033\\'.encode('ascii'))
|
||||
parse_bytes(s, f'\033[{sgr}m\033P$qm\033\\'.encode('ascii'))
|
||||
r = c.wtcbuf.decode('ascii').partition('r')[2].partition('m')[0]
|
||||
self.ae(expected, set(r.split(';')))
|
||||
c.clear()
|
||||
pb('\033P$qr\033\\', ('screen_request_capabilities', ord('$'), 'r'))
|
||||
self.ae(c.wtcbuf, f'\033P1$r{s.margin_top + 1};{s.margin_bottom + 1}r\033\\'.encode('ascii'))
|
||||
|
||||
def test_sc81t(self):
|
||||
s = self.create_screen()
|
||||
pb = partial(self.parse_bytes_dump, s)
|
||||
pb('\033 G', ('screen_set_8bit_controls', 1))
|
||||
c = s.callbacks
|
||||
pb('\033P$qm\033\\', ('screen_request_capabilities', ord('$'), 'm'))
|
||||
self.ae(c.wtcbuf, b'\x901$rm\x9c')
|
||||
c.clear()
|
||||
pb('\033[0c', ('report_device_attributes', 0, 0))
|
||||
self.ae(c.wtcbuf, b'\x9b?62;c')
|
||||
|
||||
def test_pending(self):
|
||||
s = self.create_screen()
|
||||
timeout = 0.1
|
||||
|
|
@ -400,12 +378,8 @@ def test_pending(self):
|
|||
def test_oth_codes(self):
|
||||
s = self.create_screen()
|
||||
pb = partial(self.parse_bytes_dump, s)
|
||||
for prefix in '\033_', '\u009f':
|
||||
for suffix in '\u009c', '\033\\':
|
||||
pb(f'a{prefix}+\\++{suffix}bcde', ('draw', 'a'), ('Unrecognized APC code: 0x2b',), ('draw', 'bcde'))
|
||||
for prefix in '\033^', '\u009e':
|
||||
for suffix in '\u009c', '\033\\':
|
||||
pb(f'a{prefix}+\\++{suffix}bcde', ('draw', 'a'), ('Unrecognized PM code: 0x2b',), ('draw', 'bcde'))
|
||||
pb('a\033_+\\+\033\\bcde', ('draw', 'a'), ('Unrecognized APC code: 0x2b',), ('draw', 'bcde'))
|
||||
pb('a\033^+\\+\033\\bcde', ('draw', 'a'), ('Unrecognized PM code: 0x2b',), ('draw', 'bcde'))
|
||||
|
||||
def test_graphics_command(self):
|
||||
from base64 import standard_b64encode
|
||||
|
|
|
|||
|
|
@ -1188,7 +1188,7 @@ def test_pointer_shapes(self):
|
|||
|
||||
def cb(data):
|
||||
nonlocal response
|
||||
response = set_pointer_shape(s, data)
|
||||
response = set_pointer_shape(s, str(data, 'utf-8'))
|
||||
c.set_pointer_shape = cb
|
||||
|
||||
def send(a):
|
||||
|
|
|
|||
|
|
@ -152,12 +152,12 @@ def redrawn():
|
|||
pty.callbacks.clear()
|
||||
pty.send_cmd_to_child('printf "%s\x16\a%s" "a" "b"')
|
||||
pty.wait_till(lambda: 'ab' in pty.screen_contents())
|
||||
self.assertTrue(pty.screen.last_reported_cwd.endswith(self.home_dir))
|
||||
self.assertTrue(pty.screen.last_reported_cwd.decode().endswith(self.home_dir))
|
||||
self.assertIn('%s^G%s', pty.screen_contents())
|
||||
q = os.path.join(self.home_dir, 'testing-cwd-notification-🐱')
|
||||
os.mkdir(q)
|
||||
pty.send_cmd_to_child(f'cd {q}')
|
||||
pty.wait_till(lambda: pty.screen.last_reported_cwd.endswith(q))
|
||||
pty.wait_till(lambda: pty.screen.last_reported_cwd.decode().endswith(q))
|
||||
with self.run_shell(rc=f'''PS1="{ps1}"\nexport ES="a\n b c\nd"''') as pty:
|
||||
pty.callbacks.clear()
|
||||
pty.send_cmd_to_child('clone-in-kitty')
|
||||
|
|
@ -188,13 +188,13 @@ def test_fish_integration(self):
|
|||
pty.wait_till(lambda: 'XDD_OK' in pty.screen_contents())
|
||||
|
||||
# CWD reporting
|
||||
self.assertTrue(pty.screen.last_reported_cwd.endswith(self.home_dir))
|
||||
self.assertTrue(pty.screen.last_reported_cwd.decode().endswith(self.home_dir))
|
||||
q = os.path.join(self.home_dir, 'testing-cwd-notification-🐱')
|
||||
os.mkdir(q)
|
||||
pty.send_cmd_to_child(f'cd {q}')
|
||||
pty.wait_till(lambda: pty.screen.last_reported_cwd.endswith(q))
|
||||
pty.wait_till(lambda: pty.screen.last_reported_cwd.decode().endswith(q))
|
||||
pty.send_cmd_to_child('cd -')
|
||||
pty.wait_till(lambda: pty.screen.last_reported_cwd.endswith(self.home_dir))
|
||||
pty.wait_till(lambda: pty.screen.last_reported_cwd.decode().endswith(self.home_dir))
|
||||
|
||||
# completion and prompt marking
|
||||
pty.wait_till(lambda: 'cd -' not in pty.screen_contents().splitlines()[-1])
|
||||
|
|
@ -304,13 +304,13 @@ def redrawn():
|
|||
pty.send_cmd_to_child('printf "%s\x16\a%s" "a" "b"')
|
||||
pty.wait_till(lambda: pty.screen_contents().count(ps1) == 2)
|
||||
self.ae(pty.screen_contents(), f'{ps1}printf "%s^G%s" "a" "b"\nab{ps1}')
|
||||
self.assertTrue(pty.screen.last_reported_cwd.endswith(self.home_dir))
|
||||
self.assertTrue(pty.screen.last_reported_cwd.decode().endswith(self.home_dir))
|
||||
pty.send_cmd_to_child('echo $HISTFILE')
|
||||
pty.wait_till(lambda: '.bash_history' in pty.screen_contents())
|
||||
q = os.path.join(self.home_dir, 'testing-cwd-notification-🐱')
|
||||
os.mkdir(q)
|
||||
pty.send_cmd_to_child(f'cd {q}')
|
||||
pty.wait_till(lambda: pty.screen.last_reported_cwd.endswith(q))
|
||||
pty.wait_till(lambda: pty.screen.last_reported_cwd.decode().endswith(q))
|
||||
|
||||
for ps1 in ('line1\\nline\\2\\prompt> ', 'line1\nprompt> ', 'line1\\nprompt> ',):
|
||||
with self.subTest(ps1=ps1), self.run_shell(
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ const (
|
|||
const (
|
||||
SAVE_CURSOR = "\0337"
|
||||
RESTORE_CURSOR = "\0338"
|
||||
S7C1T = "\033 F"
|
||||
SAVE_PRIVATE_MODE_VALUES = "\033[?s"
|
||||
RESTORE_PRIVATE_MODE_VALUES = "\033[?r"
|
||||
SAVE_COLORS = "\033[#P"
|
||||
|
|
@ -115,7 +114,6 @@ func reset_modes(sb *strings.Builder, modes ...Mode) {
|
|||
func (self *TerminalStateOptions) SetStateEscapeCodes() string {
|
||||
var sb strings.Builder
|
||||
sb.Grow(256)
|
||||
sb.WriteString(S7C1T)
|
||||
if self.alternate_screen {
|
||||
sb.WriteString(SAVE_CURSOR)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue