diff --git a/examples/full-screen/simple-demos/word-wrapping.py b/examples/full-screen/simple-demos/word-wrapping.py index 44f15c922..cdc6e1a8a 100755 --- a/examples/full-screen/simple-demos/word-wrapping.py +++ b/examples/full-screen/simple-demos/word-wrapping.py @@ -81,8 +81,7 @@ def get_line_prefix(lineno, wrap_count): BufferControl(buffer=buff), wrap_lines=True, wrap_finder=Window._whitespace_wrap_finder( - lambda n: [] if n else to_formatted_text(LIPSUM), - continuation=to_formatted_text(" ⮠"), + continuation=to_formatted_text(" ⮠") ), get_line_prefix=lambda lineno, wrap_count: to_formatted_text(" ⭢ ") if wrap_count @@ -92,15 +91,14 @@ def get_line_prefix(lineno, wrap_count): Window( BufferControl(buffer=buff), wrap_lines=True, - wrap_finder=lambda lineno, + wrap_finder=lambda line, + lineno, wrap_count, start, end, - fallback=Window._whitespace_wrap_finder( - lambda n: [] if n else to_formatted_text(LIPSUM), - ): (end - 3, -1, "...") + fallback=Window._whitespace_wrap_finder(): (end - 3, -1, "...") if wrap_count > 0 - else fallback(lineno, wrap_count, start, end), + else fallback(line, lineno, wrap_count, start, end), ), ] ), diff --git a/src/prompt_toolkit/layout/containers.py b/src/prompt_toolkit/layout/containers.py index 049849324..f347373ba 100644 --- a/src/prompt_toolkit/layout/containers.py +++ b/src/prompt_toolkit/layout/containers.py @@ -1784,9 +1784,7 @@ def _write_to_screen_at_index( ui_content, write_position.width - total_margin_width, write_position.height ) wrap_finder = self.wrap_finder or ( - self._whitespace_wrap_finder(ui_content.get_line) - if self.word_wrap() - else None + self._whitespace_wrap_finder() if self.word_wrap() else None ) # Erase background and fill with `char`. @@ -1946,7 +1944,6 @@ def render_margin(m: Margin, width: int) -> UIContent: @classmethod def _whitespace_wrap_finder( cls, - get_line: Callable[[int], StyleAndTextTuples], sep: str | re.Pattern[str] = r"[ \t]", # Don’t include \xA0 by default (in \s) split: str = "remove", continuation: StyleAndTextTuples = [], @@ -1969,9 +1966,9 @@ def _whitespace_wrap_finder( cont_width = fragment_list_width(continuation) def wrap_finder( - lineno: int, wrap_count: int, start: int, end: int + line: AnyFormattedText, lineno: int, wrap_count: int, start: int, end: int ) -> tuple[int, int, AnyFormattedText]: - line = explode_text_fragments(get_line(lineno)) + line = explode_text_fragments(to_formatted_text(line)) cont_reserved = 0 while cont_reserved < cont_width: style, char, *_ = line[end - 1] @@ -2027,6 +2024,7 @@ def _copy_body( rowcol_to_yx: dict[tuple[int, int], tuple[int, int]] = {} def find_next_wrap( + line: StyleAndTextTuples, remaining_width: int, is_input: bool, lineno: int, @@ -2037,7 +2035,6 @@ def find_next_wrap( if not wrap_lines: return sys.maxsize, 0, [] - line = ui_content.get_line(lineno) try: style0, text0, *more = line[fragment] except IndexError: @@ -2069,7 +2066,7 @@ def find_next_wrap( max_wrap_pos += 1 return ( - wrap_finder(lineno, wrap_count, min_wrap_pos, max_wrap_pos) + wrap_finder(line, lineno, wrap_count, min_wrap_pos, max_wrap_pos) if is_input and wrap_finder else None ) or ( @@ -2126,7 +2123,11 @@ def copy_line( new_buffer_row = new_buffer[y + ypos] wrap_start, wrap_replaced, continuation = find_next_wrap( - width - x, is_input, lineno, 0 + line, + width - x, + is_input, + lineno, + 0, ) continuation = to_formatted_text(continuation) @@ -2183,6 +2184,7 @@ def copy_line( new_buffer_row = new_buffer[y + ypos] wrap_start, wrap_replaced, continuation = find_next_wrap( + line, width - x, is_input, lineno, diff --git a/src/prompt_toolkit/layout/controls.py b/src/prompt_toolkit/layout/controls.py index 56877a14e..d9f5c68c3 100644 --- a/src/prompt_toolkit/layout/controls.py +++ b/src/prompt_toolkit/layout/controls.py @@ -58,7 +58,9 @@ ] GetLinePrefixCallable = Callable[[int, int], AnyFormattedText] -WrapFinderCallable = Callable[[int, int, int, int], Tuple[int, int, AnyFormattedText]] +WrapFinderCallable = Callable[ + [AnyFormattedText, int, int, int, int], Tuple[int, int, AnyFormattedText] +] class UIControl(metaclass=ABCMeta): @@ -206,9 +208,10 @@ def get_height_for_line( height = 10**8 else: # Calculate line width first. - line = fragment_list_to_text(self.get_line(lineno))[:slice_stop] + line = self.get_line(lineno) + line_text = fragment_list_to_text(line)[:slice_stop] start = 0 - text_width = get_cwidth(line[start:]) + text_width = get_cwidth(line_text[start:]) if get_line_prefix or wrap_finder: # Add prefix width. @@ -229,17 +232,17 @@ def get_height_for_line( if wrap_finder: # Decent guess for max breakpoint place? end = start + width - prefix_width - start_end_width = get_cwidth(line[start:end]) + start_end_width = get_cwidth(line_text[start:end]) while start_end_width >= width - prefix_width: - start_end_width -= get_cwidth(line[end - 1]) + start_end_width -= get_cwidth(line_text[end - 1]) end -= 1 wrap, skip, cont = wrap_finder( - lineno, height - 1, start, end + line, lineno, height - 1, start, end ) if skip < 0: break # Truncate line start = wrap + skip - text_width = get_cwidth(line[start:]) + text_width = get_cwidth(line_text[start:]) else: text_width -= width