diff --git a/kitty/utils.py b/kitty/utils.py index dbd4444b3..2c0127afd 100644 --- a/kitty/utils.py +++ b/kitty/utils.py @@ -1022,7 +1022,7 @@ def reload_conf_in_all_kitties() -> None: @run_once def control_codes_pat() -> 'Pattern[str]': - return re.compile('[\x00-\x09\x0b-\x1f\x7f\x80-\x9f]') + return re.compile('[\x00-\x09\x0b-\x1f\x7f-\x9f]') def sanitize_control_codes(text: str, replace_with: str = '') -> str: diff --git a/kitty/window.py b/kitty/window.py index 1029f8ead..f8747e9d0 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -479,6 +479,18 @@ class GlobalWatchers: global_watchers = GlobalWatchers() +def replace_control_codes(text: str) -> str: + # Replace all control codes other than tab, newline and space with their graphical counterparts + def sub(m: re.Match[str]) -> str: + c = ord(m.group()) + if c < 0x20: + return chr(0x2400 + c) + if c == 0x7f: + return '\u2421' + return '\u2426' + return re.sub(r'[\0-\x08\x0b-\x19\x7f-\x9f]', sub, text) + + class Window: window_custom_type: str = '' @@ -1499,12 +1511,14 @@ class Window: text = shlex.quote(text) btext = text.encode('utf-8') if 'confirm' in opts.paste_actions: - sanitized = sanitize_control_codes(text) + sanitized = replace_control_codes(text) if not self.screen.in_bracketed_paste_mode: # \n is converted to \r and \r is interpreted as the enter key # by legacy programs that dont support the full kitty keyboard protocol, - # which in the case of shells can lead to command execution - sanitized = re.sub(r'[\r\n]', ' ', sanitized) + # which in the case of shells can lead to command execution. + # \eE has the same visual effect as \r\n but without the + # command execution risk. + sanitized = sanitized.replace('\n', '\x1bE') if sanitized != text: msg = _('The text to be pasted contains terminal control codes.\n\nIf the terminal program you are pasting into does not properly' ' sanitize pasted text, this can lead to \x1b[31mcode execution vulnerabilities\x1b[39m.\n\nHow would you like to proceed?')