mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	gh-111201: Speed up paste mode in the REPL (#119341)
Co-authored-by: Łukasz Langa <lukasz@langa.pl>
This commit is contained in:
		
							parent
							
								
									cd516cd1f5
								
							
						
					
					
						commit
						e6572e8f98
					
				
					 6 changed files with 21 additions and 16 deletions
				
			
		|  | @ -461,8 +461,6 @@ def do(self) -> None: | |||
| class paste_mode(Command): | ||||
| 
 | ||||
|     def do(self) -> None: | ||||
|         if not self.reader.paste_mode: | ||||
|             self.reader.was_paste_mode_activated = True | ||||
|         self.reader.paste_mode = not self.reader.paste_mode | ||||
|         self.reader.dirty = True | ||||
| 
 | ||||
|  | @ -470,9 +468,10 @@ def do(self) -> None: | |||
| class enable_bracketed_paste(Command): | ||||
|     def do(self) -> None: | ||||
|         self.reader.paste_mode = True | ||||
|         self.reader.was_paste_mode_activated = True | ||||
|         self.reader.in_bracketed_paste = True | ||||
| 
 | ||||
| class disable_bracketed_paste(Command): | ||||
|     def do(self) -> None: | ||||
|         self.reader.paste_mode = False | ||||
|         self.reader.in_bracketed_paste = False | ||||
|         self.reader.dirty = True | ||||
|  |  | |||
|  | @ -54,7 +54,7 @@ def disp_str(buffer: str) -> tuple[str, list[int]]: | |||
|     b: list[int] = [] | ||||
|     s: list[str] = [] | ||||
|     for c in buffer: | ||||
|         if unicodedata.category(c).startswith("C"): | ||||
|         if ord(c) > 128 and unicodedata.category(c).startswith("C"): | ||||
|             c = r"\u%04x" % ord(c) | ||||
|         s.append(c) | ||||
|         b.append(wlen(c)) | ||||
|  | @ -225,7 +225,7 @@ class Reader: | |||
|     dirty: bool = False | ||||
|     finished: bool = False | ||||
|     paste_mode: bool = False | ||||
|     was_paste_mode_activated: bool = False | ||||
|     in_bracketed_paste: bool = False | ||||
|     commands: dict[str, type[Command]] = field(default_factory=make_default_commands) | ||||
|     last_command: type[Command] | None = None | ||||
|     syntax_table: dict[str, int] = field(default_factory=make_default_syntax_table) | ||||
|  | @ -448,7 +448,7 @@ def get_prompt(self, lineno: int, cursor_on_line: bool) -> str: | |||
|         elif "\n" in self.buffer: | ||||
|             if lineno == 0: | ||||
|                 prompt = self.ps2 | ||||
|             elif lineno == self.buffer.count("\n"): | ||||
|             elif self.ps4 and lineno == self.buffer.count("\n"): | ||||
|                 prompt = self.ps4 | ||||
|             else: | ||||
|                 prompt = self.ps3 | ||||
|  | @ -611,7 +611,7 @@ def do_cmd(self, cmd: tuple[str, list[str]]) -> None: | |||
| 
 | ||||
|         self.after_command(command) | ||||
| 
 | ||||
|         if self.dirty: | ||||
|         if self.dirty and not self.in_bracketed_paste: | ||||
|             self.refresh() | ||||
|         else: | ||||
|             self.update_cursor() | ||||
|  |  | |||
|  | @ -328,7 +328,7 @@ def input(self, prompt: object = "") -> str: | |||
|         reader.ps1 = str(prompt) | ||||
|         return reader.readline(startup_hook=self.startup_hook) | ||||
| 
 | ||||
|     def multiline_input(self, more_lines: MoreLinesCallable, ps1: str, ps2: str) -> tuple[str, bool]: | ||||
|     def multiline_input(self, more_lines: MoreLinesCallable, ps1: str, ps2: str) -> str: | ||||
|         """Read an input on possibly multiple lines, asking for more | ||||
|         lines as long as 'more_lines(unicodetext)' returns an object whose | ||||
|         boolean value is true. | ||||
|  | @ -337,14 +337,15 @@ def multiline_input(self, more_lines: MoreLinesCallable, ps1: str, ps2: str) -> | |||
|         saved = reader.more_lines | ||||
|         try: | ||||
|             reader.more_lines = more_lines | ||||
|             reader.ps1 = reader.ps2 = ps1 | ||||
|             reader.ps3 = reader.ps4 = ps2 | ||||
|             reader.ps1 = ps1 | ||||
|             reader.ps2 = ps1 | ||||
|             reader.ps3 = ps2 | ||||
|             reader.ps4 = "" | ||||
|             with warnings.catch_warnings(action="ignore"): | ||||
|                 return reader.readline(), reader.was_paste_mode_activated | ||||
|                 return reader.readline() | ||||
|         finally: | ||||
|             reader.more_lines = saved | ||||
|             reader.paste_mode = False | ||||
|             reader.was_paste_mode_activated = False | ||||
| 
 | ||||
|     def parse_and_bind(self, string: str) -> None: | ||||
|         pass  # XXX we don't support parsing GNU-readline-style init files | ||||
|  |  | |||
|  | @ -62,6 +62,7 @@ def _strip_final_indent(text: str) -> str: | |||
|     "quit": _sitebuiltins.Quitter('quit' ,''), | ||||
|     "copyright": _sitebuiltins._Printer('copyright', sys.copyright), | ||||
|     "help": "help", | ||||
|     "clear": "clear_screen", | ||||
| } | ||||
| 
 | ||||
| class InteractiveColoredConsole(code.InteractiveConsole): | ||||
|  | @ -163,7 +164,7 @@ def more_lines(unicodetext: str) -> bool: | |||
|             ps1 = getattr(sys, "ps1", ">>> ") | ||||
|             ps2 = getattr(sys, "ps2", "... ") | ||||
|             try: | ||||
|                 statement, contains_pasted_code = multiline_input(more_lines, ps1, ps2) | ||||
|                 statement = multiline_input(more_lines, ps1, ps2) | ||||
|             except EOFError: | ||||
|                 break | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,10 +1,14 @@ | |||
| import re | ||||
| import unicodedata | ||||
| import functools | ||||
| 
 | ||||
| ANSI_ESCAPE_SEQUENCE = re.compile(r"\x1b\[[ -@]*[A-~]") | ||||
| 
 | ||||
| 
 | ||||
| @functools.cache | ||||
| def str_width(c: str) -> int: | ||||
|     if ord(c) < 128: | ||||
|         return 1 | ||||
|     w = unicodedata.east_asian_width(c) | ||||
|     if w in ('N', 'Na', 'H', 'A'): | ||||
|         return 1 | ||||
|  | @ -13,6 +17,6 @@ def str_width(c: str) -> int: | |||
| 
 | ||||
| def wlen(s: str) -> int: | ||||
|     length = sum(str_width(i) for i in s) | ||||
| 
 | ||||
|     # remove lengths of any escape sequences | ||||
|     return length - sum(len(i) for i in ANSI_ESCAPE_SEQUENCE.findall(s)) | ||||
|     sequence = ANSI_ESCAPE_SEQUENCE.findall(s) | ||||
|     return length - sum(len(i) for i in sequence) | ||||
|  |  | |||
|  | @ -578,7 +578,7 @@ def test_func(self): | |||
|         reader = self.prepare_reader(events, namespace) | ||||
|         mock_get_reader.return_value = reader | ||||
|         output = readline_multiline_input(more_lines, ">>>", "...") | ||||
|         self.assertEqual(output[0], "dummy.test_func.__") | ||||
|         self.assertEqual(output, "dummy.test_func.__") | ||||
|         self.assertEqual(mock_stderr.getvalue(), "") | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Pablo Galindo Salgado
						Pablo Galindo Salgado