2222from __future__ import annotations
2323
2424import sys
25+ import _colorize
2526
2627from contextlib import contextmanager
2728from dataclasses import dataclass , field , fields
28- from _colorize import can_colorize , ANSIColors
29-
3029
3130from . import commands , console , input
32- from .utils import wlen , unbracket , disp_str
31+ from .utils import wlen , unbracket , disp_str , gen_colors
3332from .trace import trace
3433
3534
3837from .types import Callback , SimpleContextManager , KeySpec , CommandName
3938
4039
41- # syntax classes:
42-
40+ # syntax classes
4341SYNTAX_WHITESPACE , SYNTAX_WORD , SYNTAX_SYMBOL = range (3 )
4442
4543
@@ -105,8 +103,7 @@ def make_default_commands() -> dict[CommandName, type[Command]]:
105103 (r"\M-9" , "digit-arg" ),
106104 (r"\M-\n" , "accept" ),
107105 ("\\ \\ " , "self-insert" ),
108- (r"\x1b[200~" , "enable_bracketed_paste" ),
109- (r"\x1b[201~" , "disable_bracketed_paste" ),
106+ (r"\x1b[200~" , "perform-bracketed-paste" ),
110107 (r"\x03" , "ctrl-c" ),
111108 ]
112109 + [(c , "self-insert" ) for c in map (chr , range (32 , 127 )) if c != "\\ " ]
@@ -144,16 +141,17 @@ class Reader:
144141 Instance variables of note include:
145142
146143 * buffer:
147- A * list* (*not* a string at the moment :-) containing all the
148- characters that have been entered .
144+ A per-character list containing all the characters that have been
145+ entered. Does not include color information .
149146 * console:
150147 Hopefully encapsulates the OS dependent stuff.
151148 * pos:
152149 A 0-based index into 'buffer' for where the insertion point
153150 is.
154151 * screeninfo:
155- Ahem. This list contains some info needed to move the
156- insertion point around reasonably efficiently.
152+ A list of screen position tuples. Each list element is a tuple
153+ representing information on visible line length for a given line.
154+ Allows for efficient skipping of color escape sequences.
157155 * cxy, lxy:
158156 the position of the insertion point in screen ...
159157 * syntax_table:
@@ -203,7 +201,6 @@ class Reader:
203201 dirty : bool = False
204202 finished : bool = False
205203 paste_mode : bool = False
206- in_bracketed_paste : bool = False
207204 commands : dict [str , type [Command ]] = field (default_factory = make_default_commands )
208205 last_command : type [Command ] | None = None
209206 syntax_table : dict [str , int ] = field (default_factory = make_default_syntax_table )
@@ -221,7 +218,6 @@ class Reader:
221218 ## cached metadata to speed up screen refreshes
222219 @dataclass
223220 class RefreshCache :
224- in_bracketed_paste : bool = False
225221 screen : list [str ] = field (default_factory = list )
226222 screeninfo : list [tuple [int , list [int ]]] = field (init = False )
227223 line_end_offsets : list [int ] = field (default_factory = list )
@@ -235,7 +231,6 @@ def update_cache(self,
235231 screen : list [str ],
236232 screeninfo : list [tuple [int , list [int ]]],
237233 ) -> None :
238- self .in_bracketed_paste = reader .in_bracketed_paste
239234 self .screen = screen .copy ()
240235 self .screeninfo = screeninfo .copy ()
241236 self .pos = reader .pos
@@ -248,8 +243,7 @@ def valid(self, reader: Reader) -> bool:
248243 return False
249244 dimensions = reader .console .width , reader .console .height
250245 dimensions_changed = dimensions != self .dimensions
251- paste_changed = reader .in_bracketed_paste != self .in_bracketed_paste
252- return not (dimensions_changed or paste_changed )
246+ return not dimensions_changed
253247
254248 def get_cached_location (self , reader : Reader ) -> tuple [int , int ]:
255249 if self .invalidated :
@@ -279,7 +273,7 @@ def __post_init__(self) -> None:
279273 self .screeninfo = [(0 , [])]
280274 self .cxy = self .pos2xy ()
281275 self .lxy = (self .pos , 0 )
282- self .can_colorize = can_colorize ()
276+ self .can_colorize = _colorize . can_colorize ()
283277
284278 self .last_refresh_cache .screeninfo = self .screeninfo
285279 self .last_refresh_cache .pos = self .pos
@@ -316,6 +310,12 @@ def calc_screen(self) -> list[str]:
316310 pos -= offset
317311
318312 prompt_from_cache = (offset and self .buffer [offset - 1 ] != "\n " )
313+
314+ if self .can_colorize :
315+ colors = list (gen_colors (self .get_unicode ()))
316+ else :
317+ colors = None
318+ trace ("colors = {colors}" , colors = colors )
319319 lines = "" .join (self .buffer [offset :]).split ("\n " )
320320 cursor_found = False
321321 lines_beyond_cursor = 0
@@ -343,9 +343,8 @@ def calc_screen(self) -> list[str]:
343343 screeninfo .append ((0 , []))
344344 pos -= line_len + 1
345345 prompt , prompt_len = self .process_prompt (prompt )
346- chars , char_widths = disp_str (line )
346+ chars , char_widths = disp_str (line , colors , offset )
347347 wrapcount = (sum (char_widths ) + prompt_len ) // self .console .width
348- trace ("wrapcount = {wrapcount}" , wrapcount = wrapcount )
349348 if wrapcount == 0 or not char_widths :
350349 offset += line_len + 1 # Takes all of the line plus the newline
351350 last_refresh_line_end_offsets .append (offset )
@@ -479,7 +478,7 @@ def get_prompt(self, lineno: int, cursor_on_line: bool) -> str:
479478 'lineno'."""
480479 if self .arg is not None and cursor_on_line :
481480 prompt = f"(arg: { self .arg } ) "
482- elif self .paste_mode and not self . in_bracketed_paste :
481+ elif self .paste_mode :
483482 prompt = "(paste) "
484483 elif "\n " in self .buffer :
485484 if lineno == 0 :
@@ -492,7 +491,11 @@ def get_prompt(self, lineno: int, cursor_on_line: bool) -> str:
492491 prompt = self .ps1
493492
494493 if self .can_colorize :
495- prompt = f"{ ANSIColors .BOLD_MAGENTA } { prompt } { ANSIColors .RESET } "
494+ prompt = (
495+ f"{ _colorize .theme ["PROMPT" ]} "
496+ f"{ prompt } "
497+ f"{ _colorize .theme ["RESET" ]} "
498+ )
496499 return prompt
497500
498501 def push_input_trans (self , itrans : input .KeymapTranslator ) -> None :
@@ -567,6 +570,7 @@ def insert(self, text: str | list[str]) -> None:
567570 def update_cursor (self ) -> None :
568571 """Move the cursor to reflect changes in self.pos"""
569572 self .cxy = self .pos2xy ()
573+ trace ("update_cursor({pos}) = {cxy}" , pos = self .pos , cxy = self .cxy )
570574 self .console .move_cursor (* self .cxy )
571575
572576 def after_command (self , cmd : Command ) -> None :
@@ -633,9 +637,6 @@ def update_screen(self) -> None:
633637
634638 def refresh (self ) -> None :
635639 """Recalculate and refresh the screen."""
636- if self .in_bracketed_paste and self .buffer and not self .buffer [- 1 ] == "\n " :
637- return
638-
639640 # this call sets up self.cxy, so call it first.
640641 self .screen = self .calc_screen ()
641642 self .console .refresh (self .screen , self .cxy )
0 commit comments