def preferred_width(self, max_available_width: int) -> int: """ Return the preferred width for this control. That is the width of the longest line. """ text = fragment_list_to_text(self._get_formatted_text_cached()) line_lengths = [get_cwidth(l) for l in text.split('\n')] return max(line_lengths)
def apply_transformation( self, transformation_input: TransformationInput) -> Transformation: ( buffer_control, document, lineno, source_to_display, fragments, _, _, ) = transformation_input.unpack() search_text = self._get_search_text(buffer_control) searchmatch_fragment = " class:%s " % (self._classname, ) searchmatch_current_fragment = " class:%s " % ( self._classname_current, ) if search_text and not get_app().is_done: # For each search match, replace the style string. line_text = fragment_list_to_text(fragments) fragments = explode_text_fragments(fragments) if buffer_control.search_state.ignore_case(): flags = re.IGNORECASE else: flags = re.RegexFlag(0) # Get cursor column. cursor_column: Optional[int] if document.cursor_position_row == lineno: cursor_column = source_to_display(document.cursor_position_col) else: cursor_column = None for match in re.finditer(re.escape(search_text), line_text, flags=flags): if cursor_column is not None: on_cursor = match.start() <= cursor_column < match.end() else: on_cursor = False for i in range(match.start(), match.end()): old_fragment, text, *_ = fragments[i] if on_cursor: fragments[i] = ( old_fragment + searchmatch_current_fragment, fragments[i][1], ) else: fragments[i] = ( old_fragment + searchmatch_fragment, fragments[i][1], ) return Transformation(fragments)
def _find(event: E) -> None: # We first check values after the selected value, then all values. values = list(self.values) for value in values[self._selected_index + 1 :] + values: text = fragment_list_to_text(to_formatted_text(value[1])).lower() if text.startswith(event.data.lower()): self._selected_index = self.values.index(value) return
def show_result(self, result: object) -> None: """ Show __repr__ for an `eval` result. """ out_prompt = to_formatted_text(self.get_output_prompt()) # If the repr is valid Python code, use the Pygments lexer. result_repr = repr(result) try: compile(result_repr, "", "eval") except SyntaxError: formatted_result_repr = to_formatted_text(result_repr) else: formatted_result_repr = to_formatted_text( PygmentsTokens(list(_lex_python_result(result_repr)))) # If __pt_repr__ is present, take this. This can return # prompt_toolkit formatted text. if hasattr(result, "__pt_repr__"): try: formatted_result_repr = to_formatted_text( getattr(result, "__pt_repr__")()) if isinstance(formatted_result_repr, list): formatted_result_repr = FormattedText( formatted_result_repr) except: pass # Align every line to the prompt. line_sep = "\n" + " " * fragment_list_width(out_prompt) indented_repr: StyleAndTextTuples = [] lines = list(split_lines(formatted_result_repr)) for i, fragment in enumerate(lines): indented_repr.extend(fragment) # Add indentation separator between lines, not after the last line. if i != len(lines) - 1: indented_repr.append(("", line_sep)) # Write output tokens. if self.enable_syntax_highlighting: formatted_output = merge_formatted_text( [out_prompt, indented_repr]) else: formatted_output = FormattedText(out_prompt + [( "", fragment_list_to_text(formatted_result_repr))]) print_formatted_text( formatted_output, style=self._current_style, style_transformation=self.style_transformation, include_default_pygments_style=False, output=self.app.output, ) self.app.output.flush()
def apply_transformation(self, transformation_input): lineno = transformation_input.lineno fragments = transformation_input.fragments if (lineno < self._lines_before or lineno >= self._lines_before + len(self.history_mapping.selected_lines)): text = fragment_list_to_text(fragments) return Transformation(fragments=[('class:history.existing-input', text)]) else: return Transformation(fragments=fragments)
def apply_transformation(self, transformation_input): lineno = transformation_input.lineno fragments = transformation_input.fragments if (lineno < self._lines_before or lineno >= self._lines_before + len(self.history_mapping.selected_lines)): text = fragment_list_to_text(fragments) return Transformation(fragments=[('class:history.existing-input', text)]) else: return Transformation(fragments=fragments)
def get_width() -> AnyDimension: if width is None: text_fragments = to_formatted_text(self.text) text = fragment_list_to_text(text_fragments) if text: longest_line = max(get_cwidth(line) for line in text.splitlines()) else: return D(preferred=0) return D(preferred=longest_line) else: return width
def get_width(): if width is None: text_fragments = to_formatted_text(self.text) text = fragment_list_to_text(text_fragments) if text: longest_line = max(get_cwidth(line) for line in text.splitlines()) else: return D(preferred=0) return D(preferred=longest_line) else: return width
def apply_transformation(self, ti): try: fragments = to_formatted_text( HTML(fragment_list_to_text(ti.fragments))) except Exception as ex: # xml.parsers.expat.ExpatError # not well-formed (invalid token): line 1, column 138 logger.error('FormatText: {} {}'.format(type(ex), str(ex))) #return Transformation([('', ' ')]) return Transformation([]) return Transformation(fragments)
def apply_transformation(self, ti: TransformationInput) -> Transformation: from .controls import SearchBufferControl assert isinstance( ti.buffer_control, SearchBufferControl ), "`ReverseSearchProcessor` should be applied to a `SearchBufferControl` only." source_to_display: Optional[SourceToDisplay] display_to_source: Optional[DisplayToSource] main_control = self._get_main_buffer(ti.buffer_control) if ti.lineno == 0 and main_control: content = self._content(main_control, ti) # Get the line from the original document for this search. line_fragments = content.get_line(content.cursor_position.y) if main_control.search_state.direction == SearchDirection.FORWARD: direction_text = "i-search" else: direction_text = "reverse-i-search" fragments_before: StyleAndTextTuples = [ ("class:prompt.search", "("), ("class:prompt.search", direction_text), ("class:prompt.search", ")`"), ] fragments = ( fragments_before + [ ("class:prompt.search.text", fragment_list_to_text(ti.fragments)), ("", "': "), ] + line_fragments ) shift_position = fragment_list_len(fragments_before) source_to_display = lambda i: i + shift_position display_to_source = lambda i: i - shift_position else: source_to_display = None display_to_source = None fragments = ti.fragments return Transformation( fragments, source_to_display=source_to_display, display_to_source=display_to_source, )
def get_height_for_line(self, lineno, width): """ Return the height that a given line would need if it is rendered in a space with the given width. """ try: return self._line_heights[lineno, width] except KeyError: text = fragment_list_to_text(self.get_line(lineno)) result = self.get_height_for_text(text, width) # Cache and return self._line_heights[lineno, width] = result return result
def apply_transformation(self, ti): fragments = ti.fragments # Walk through all te fragments. if fragments and fragment_list_to_text(fragments).startswith(' '): t = (self.style, self.get_char()) fragments = explode_text_fragments(fragments) for i in range(len(fragments)): if fragments[i][1] == ' ': fragments[i] = t else: break return Transformation(fragments)
def apply_transformation(self, ti: TransformationInput) -> Transformation: fragments = ti.fragments # Walk through all te fragments. if fragments and fragment_list_to_text(fragments).startswith(' '): t = (self.style, self.get_char()) fragments = explode_text_fragments(fragments) for i in range(len(fragments)): if fragments[i][1] == ' ': fragments[i] = t else: break return Transformation(fragments)
def show_result(self, result: object) -> None: if hasattr(result, "__pt_repr__"): out_prompt = to_formatted_text(self.get_output_prompt()) try: formatted_result_repr = to_formatted_text( getattr(result, "__pt_repr__")()) if isinstance(formatted_result_repr, list): formatted_result_repr = FormattedText( formatted_result_repr) except: pass line_sep = "\n" + " " * fragment_list_width(out_prompt) indented_repr: StyleAndTextTuples = [] lines = list(split_lines(formatted_result_repr)) for i, fragment in enumerate(lines): indented_repr.extend(fragment) # Add indentation separator between lines, not after the last line. if i != len(lines) - 1: indented_repr.append(("", line_sep)) # Write output tokens. if self.enable_syntax_highlighting: formatted_output = merge_formatted_text( [out_prompt, indented_repr]) else: formatted_output = FormattedText(out_prompt + [( "", fragment_list_to_text(formatted_result_repr))]) if self.enable_pager: self.print_paginated_formatted_text( to_formatted_text(formatted_output)) else: self.print_formatted_text(to_formatted_text(formatted_output)) self.app.output.flush() if self.insert_blank_line_after_output: self.app.output.write("\n") else: if self._formatter: result = self._formatter(result) self.console.print(result)
def apply_transformation(self, ti: TransformationInput) -> Transformation: from .controls import SearchBufferControl assert isinstance(ti.buffer_control, SearchBufferControl), \ '`ReverseSearchProcessor` should be applied to a `SearchBufferControl` only.' source_to_display: Optional[SourceToDisplay] display_to_source: Optional[DisplayToSource] main_control = self._get_main_buffer(ti.buffer_control) if ti.lineno == 0 and main_control: content = self._content(main_control, ti) # Get the line from the original document for this search. line_fragments = content.get_line(content.cursor_position.y) if main_control.search_state.direction == SearchDirection.FORWARD: direction_text = 'i-search' else: direction_text = 'reverse-i-search' fragments_before: StyleAndTextTuples = [ ('class:prompt.search', '('), ('class:prompt.search', direction_text), ('class:prompt.search', ')`'), ] fragments = fragments_before + [ ('class:prompt.search.text', fragment_list_to_text(ti.fragments)), ('', "': "), ] + line_fragments shift_position = fragment_list_len(fragments_before) source_to_display = lambda i: i + shift_position display_to_source = lambda i: i - shift_position else: source_to_display = None display_to_source = None fragments = ti.fragments return Transformation(fragments, source_to_display=source_to_display, display_to_source=display_to_source)
def apply_transformation( self, transformation_input: TransformationInput) -> Transformation: buffer_control, document, lineno, source_to_display, fragments, _, _ = transformation_input.unpack() search_text = self._get_search_text(buffer_control) searchmatch_fragment = ' class:%s ' % (self._classname, ) searchmatch_current_fragment = ' class:%s ' % (self._classname_current, ) if search_text and not get_app().is_done: # For each search match, replace the style string. line_text = fragment_list_to_text(fragments) fragments = explode_text_fragments(fragments) if buffer_control.search_state.ignore_case(): flags = re.IGNORECASE else: flags = re.RegexFlag(0) # Get cursor column. cursor_column: Optional[int] if document.cursor_position_row == lineno: cursor_column = source_to_display(document.cursor_position_col) else: cursor_column = None for match in re.finditer(re.escape(search_text), line_text, flags=flags): if cursor_column is not None: on_cursor = match.start() <= cursor_column < match.end() else: on_cursor = False for i in range(match.start(), match.end()): old_fragment, text, *_ = fragments[i] if on_cursor: fragments[i] = (old_fragment + searchmatch_current_fragment, fragments[i][1]) else: fragments[i] = (old_fragment + searchmatch_fragment, fragments[i][1]) return Transformation(fragments)
def apply_transformation(self, ti): main_control = self._get_main_buffer(ti.buffer_control) if ti.lineno == 0 and main_control: content = self._content(main_control, ti) # Get the line from the original document for this search. line_fragments = content.get_line(content.cursor_position.y) if main_control.search_state.direction == SearchDirection.FORWARD: direction_text = 'i-search' else: direction_text = 'reverse-i-search' fragments_before = [ ('class:prompt.search', '('), ('class:prompt.search', direction_text), ('class:prompt.search', ')`'), ] fragments = fragments_before + [ ('class:prompt.search.text', fragment_list_to_text( ti.fragments)), ('', "': "), ] + line_fragments shift_position = fragment_list_len(fragments_before) source_to_display = lambda i: i + shift_position display_to_source = lambda i: i - shift_position else: source_to_display = None display_to_source = None fragments = ti.fragments return Transformation(fragments, source_to_display=source_to_display, display_to_source=display_to_source)
def get_width(self, ui_content): " Width to report to the `Window`. " # Take the width from the first line. text = fragment_list_to_text(self.get_prompt_fragments()) return get_cwidth(text)
def get_height_for_line( self, lineno: int, width: int, get_line_prefix: Optional[GetLinePrefixCallable], slice_stop: Optional[int] = None) -> int: """ Return the height that a given line would need if it is rendered in a space with the given width (using line wrapping). :param get_line_prefix: None or a `Window.get_line_prefix` callable that returns the prefix to be inserted before this line. :param slice_stop: Wrap only "line[:slice_stop]" and return that partial result. This is needed for scrolling the window correctly when line wrapping. :returns: The computed height. """ # Instead of using `get_line_prefix` as key, we use render_counter # instead. This is more reliable, because this function could still be # the same, while the content would change over time. key = get_app().render_counter, lineno, width, slice_stop try: return self._line_heights_cache[key] except KeyError: if width == 0: height = 10 ** 8 else: # Calculate line width first. line = fragment_list_to_text(self.get_line(lineno))[:slice_stop] text_width = get_cwidth(line) if get_line_prefix: # Add prefix width. text_width += fragment_list_width( to_formatted_text(get_line_prefix(lineno, 0))) # Slower path: compute path when there's a line prefix. height = 1 # Keep wrapping as long as the line doesn't fit. # Keep adding new prefixes for every wrapped line. while text_width > width: height += 1 text_width -= width fragments2 = to_formatted_text( get_line_prefix(lineno, height - 1)) prefix_width = get_cwidth(fragment_list_to_text(fragments2)) if prefix_width >= width: # Prefix doesn't fit. height = 10 ** 8 break text_width += prefix_width else: # Fast path: compute height when there's no line prefix. try: quotient, remainder = divmod(text_width, width) except ZeroDivisionError: height = 10 ** 8 else: if remainder: quotient += 1 # Like math.ceil. height = max(1, quotient) # Cache and return self._line_heights_cache[key] = height return height
def show_result(self, result: object) -> None: """ Show __repr__ for an `eval` result. Note: this can raise `KeyboardInterrupt` if either calling `__repr__`, `__pt_repr__` or formatting the output with "Black" takes to long and the user presses Control-C. """ out_prompt = to_formatted_text(self.get_output_prompt()) # If the repr is valid Python code, use the Pygments lexer. try: result_repr = repr(result) except KeyboardInterrupt: raise # Don't catch here. except BaseException as e: # Calling repr failed. self._handle_exception(e) return try: compile(result_repr, "", "eval") except SyntaxError: formatted_result_repr = to_formatted_text(result_repr) else: # Syntactically correct. Format with black and syntax highlight. if self.enable_output_formatting: # Inline import. Slightly speed up start-up time if black is # not used. import black result_repr = black.format_str( result_repr, mode=black.FileMode( line_length=self.app.output.get_size().columns), ) formatted_result_repr = to_formatted_text( PygmentsTokens(list(_lex_python_result(result_repr)))) # If __pt_repr__ is present, take this. This can return prompt_toolkit # formatted text. try: if hasattr(result, "__pt_repr__"): formatted_result_repr = to_formatted_text( getattr(result, "__pt_repr__")()) if isinstance(formatted_result_repr, list): formatted_result_repr = FormattedText( formatted_result_repr) except KeyboardInterrupt: raise # Don't catch here. except: # For bad code, `__getattr__` can raise something that's not an # `AttributeError`. This happens already when calling `hasattr()`. pass # Align every line to the prompt. line_sep = "\n" + " " * fragment_list_width(out_prompt) indented_repr: StyleAndTextTuples = [] lines = list(split_lines(formatted_result_repr)) for i, fragment in enumerate(lines): indented_repr.extend(fragment) # Add indentation separator between lines, not after the last line. if i != len(lines) - 1: indented_repr.append(("", line_sep)) # Write output tokens. if self.enable_syntax_highlighting: formatted_output = merge_formatted_text( [out_prompt, indented_repr]) else: formatted_output = FormattedText(out_prompt + [( "", fragment_list_to_text(formatted_result_repr))]) if self.enable_pager: self.print_paginated_formatted_text( to_formatted_text(formatted_output)) else: self.print_formatted_text(to_formatted_text(formatted_output)) self.app.output.flush() if self.insert_blank_line_after_output: self.app.output.write("\n")
def get_height_for_line( self, lineno: int, width: int, get_line_prefix: Optional[GetLinePrefixCallable], slice_stop: Optional[int] = None, ) -> int: """ Return the height that a given line would need if it is rendered in a space with the given width (using line wrapping). :param get_line_prefix: None or a `Window.get_line_prefix` callable that returns the prefix to be inserted before this line. :param slice_stop: Wrap only "line[:slice_stop]" and return that partial result. This is needed for scrolling the window correctly when line wrapping. :returns: The computed height. """ # Instead of using `get_line_prefix` as key, we use render_counter # instead. This is more reliable, because this function could still be # the same, while the content would change over time. key = get_app().render_counter, lineno, width, slice_stop try: return self._line_heights_cache[key] except KeyError: if width == 0: height = 10**8 else: # Calculate line width first. line = fragment_list_to_text( self.get_line(lineno))[:slice_stop] text_width = get_cwidth(line) if get_line_prefix: # Add prefix width. text_width += fragment_list_width( to_formatted_text(get_line_prefix(lineno, 0))) # Slower path: compute path when there's a line prefix. height = 1 # Keep wrapping as long as the line doesn't fit. # Keep adding new prefixes for every wrapped line. while text_width > width: height += 1 text_width -= width fragments2 = to_formatted_text( get_line_prefix(lineno, height - 1)) prefix_width = get_cwidth( fragment_list_to_text(fragments2)) if prefix_width >= width: # Prefix doesn't fit. height = 10**8 break text_width += prefix_width else: # Fast path: compute height when there's no line prefix. try: quotient, remainder = divmod(text_width, width) except ZeroDivisionError: height = 10**8 else: if remainder: quotient += 1 # Like math.ceil. height = max(1, quotient) # Cache and return self._line_heights_cache[key] = height return height
def __repr__(self) -> str: return fragment_list_to_text(to_formatted_text(cls.__pt_repr__(self)))