diff --git a/kitty/bash.py b/kitty/bash.py index 320041643..ae47bb794 100644 --- a/kitty/bash.py +++ b/kitty/bash.py @@ -1,82 +1,13 @@ #!/usr/bin/env python # License: GPLv3 Copyright: 2022, Kovid Goyal -import string from typing import Dict, List, Tuple -ansi_c_escapes = { - 'a': '\a', - 'b': '\b', - 'e': '\x1b', - 'E': '\x1b', - 'f': '\f', - 'n': '\n', - 'r': '\r', - 't': '\t', - 'v': '\v', - '\\': '\\', - "'": "'", - '"': '"', - '?': '?', -} +from .utils import shlex_split -def ctrl_mask_char(ch: str) -> str: - try: - o = ord(ch) - except Exception: - return ch - return chr(o & 0b0011111) - - -def read_digit(text: str, pos: int, max_len: int, valid_digits: str, base: int) -> Tuple[str, int]: - epos = pos - while (epos - pos) <= max_len and epos < len(text) and text[epos] in valid_digits: - epos += 1 - raw = text[pos:epos] - try: - return chr(int(raw, base)), epos - except Exception: - return raw, epos - - -def read_hex_digit(text: str, pos: int, max_len: int) -> Tuple[str, int]: - return read_digit(text, pos, max_len, string.digits + 'abcdefABCDEF', 16) - - -def read_octal_digit(text: str, pos: int) -> Tuple[str, int]: - return read_digit(text, pos, 3, '01234567', 8) - - -def decode_ansi_c_quoted_string(text: str, pos: int) -> Tuple[str, int]: - buf: List[str] = [] - a = buf.append - while pos < len(text): - ch = text[pos] - pos += 1 - if ch == '\\': - ec = text[pos] - pos += 1 - ev = ansi_c_escapes.get(ec) - if ev is None: - if ec == 'c' and pos + 1 < len(text): - a(ctrl_mask_char(text[pos])) - pos += 1 - elif ec in 'xuU' and pos + 1 < len(text): - hd, pos = read_hex_digit(text, pos, {'x': 2, 'u': 4, 'U': 8}[ec]) - a(hd) - elif ec.isdigit(): - hd, pos = read_octal_digit(text, pos-1) - a(hd) - else: - a(ec) - else: - a(ev) - elif ch == "'": - break - else: - a(ch) - return ''.join(buf), pos +def decode_ansi_c_quoted_string(text: str) -> str: + return next(shlex_split(text, True)) def decode_double_quoted_string(text: str, pos: int) -> Tuple[str, int]: @@ -110,7 +41,7 @@ def parse_modern_bash_env(text: str) -> Dict[str, str]: if val.startswith('"'): val = decode_double_quoted_string(val, 1)[0] else: - val = decode_ansi_c_quoted_string(val, 2)[0] + val = decode_ansi_c_quoted_string(val) ans[key] = val return ans diff --git a/kitty_tests/shell_integration.py b/kitty_tests/shell_integration.py index 5ba56919c..acf43e330 100644 --- a/kitty_tests/shell_integration.py +++ b/kitty_tests/shell_integration.py @@ -382,6 +382,7 @@ def run_test(argv, *expected, excluded=(), rc='', wait_string='PROMPT $', assert env = pty.callbacks.clone_cmds[0].env self.ae(env.get('ES'), 'a\n `b` c\n$d', f'Screen contents: {pty.screen_contents()!r}') self.ae(env.get('ES2'), 'XXX', f'Screen contents: {pty.screen_contents()!r}') + for q, e in { 'a': 'a', r'a\ab': 'a\ab', @@ -390,8 +391,7 @@ def run_test(argv, *expected, excluded=(), rc='', wait_string='PROMPT $', assert r'a\U1f345x': 'a🍅x', r'a\c b': 'a\0b', }.items(): - q = q + "'" - self.ae(decode_ansi_c_quoted_string(q, 0)[0], e, f'Failed to decode: {q!r}') + self.ae(decode_ansi_c_quoted_string(f"$'{q}'"), e, f'Failed to decode: {q!r}') class ShellIntegrationWithKitten(ShellIntegration):