summaryrefslogtreecommitdiff
path: root/venv/lib/python3.11/site-packages/rich/syntax.py
diff options
context:
space:
mode:
Diffstat (limited to 'venv/lib/python3.11/site-packages/rich/syntax.py')
-rw-r--r--venv/lib/python3.11/site-packages/rich/syntax.py958
1 files changed, 0 insertions, 958 deletions
diff --git a/venv/lib/python3.11/site-packages/rich/syntax.py b/venv/lib/python3.11/site-packages/rich/syntax.py
deleted file mode 100644
index 618e045..0000000
--- a/venv/lib/python3.11/site-packages/rich/syntax.py
+++ /dev/null
@@ -1,958 +0,0 @@
-import os.path
-import platform
-import re
-import sys
-import textwrap
-from abc import ABC, abstractmethod
-from pathlib import Path
-from typing import (
- Any,
- Dict,
- Iterable,
- List,
- NamedTuple,
- Optional,
- Sequence,
- Set,
- Tuple,
- Type,
- Union,
-)
-
-from pygments.lexer import Lexer
-from pygments.lexers import get_lexer_by_name, guess_lexer_for_filename
-from pygments.style import Style as PygmentsStyle
-from pygments.styles import get_style_by_name
-from pygments.token import (
- Comment,
- Error,
- Generic,
- Keyword,
- Name,
- Number,
- Operator,
- String,
- Token,
- Whitespace,
-)
-from pygments.util import ClassNotFound
-
-from rich.containers import Lines
-from rich.padding import Padding, PaddingDimensions
-
-from ._loop import loop_first
-from .cells import cell_len
-from .color import Color, blend_rgb
-from .console import Console, ConsoleOptions, JustifyMethod, RenderResult
-from .jupyter import JupyterMixin
-from .measure import Measurement
-from .segment import Segment, Segments
-from .style import Style, StyleType
-from .text import Text
-
-TokenType = Tuple[str, ...]
-
-WINDOWS = platform.system() == "Windows"
-DEFAULT_THEME = "monokai"
-
-# The following styles are based on https://github.com/pygments/pygments/blob/master/pygments/formatters/terminal.py
-# A few modifications were made
-
-ANSI_LIGHT: Dict[TokenType, Style] = {
- Token: Style(),
- Whitespace: Style(color="white"),
- Comment: Style(dim=True),
- Comment.Preproc: Style(color="cyan"),
- Keyword: Style(color="blue"),
- Keyword.Type: Style(color="cyan"),
- Operator.Word: Style(color="magenta"),
- Name.Builtin: Style(color="cyan"),
- Name.Function: Style(color="green"),
- Name.Namespace: Style(color="cyan", underline=True),
- Name.Class: Style(color="green", underline=True),
- Name.Exception: Style(color="cyan"),
- Name.Decorator: Style(color="magenta", bold=True),
- Name.Variable: Style(color="red"),
- Name.Constant: Style(color="red"),
- Name.Attribute: Style(color="cyan"),
- Name.Tag: Style(color="bright_blue"),
- String: Style(color="yellow"),
- Number: Style(color="blue"),
- Generic.Deleted: Style(color="bright_red"),
- Generic.Inserted: Style(color="green"),
- Generic.Heading: Style(bold=True),
- Generic.Subheading: Style(color="magenta", bold=True),
- Generic.Prompt: Style(bold=True),
- Generic.Error: Style(color="bright_red"),
- Error: Style(color="red", underline=True),
-}
-
-ANSI_DARK: Dict[TokenType, Style] = {
- Token: Style(),
- Whitespace: Style(color="bright_black"),
- Comment: Style(dim=True),
- Comment.Preproc: Style(color="bright_cyan"),
- Keyword: Style(color="bright_blue"),
- Keyword.Type: Style(color="bright_cyan"),
- Operator.Word: Style(color="bright_magenta"),
- Name.Builtin: Style(color="bright_cyan"),
- Name.Function: Style(color="bright_green"),
- Name.Namespace: Style(color="bright_cyan", underline=True),
- Name.Class: Style(color="bright_green", underline=True),
- Name.Exception: Style(color="bright_cyan"),
- Name.Decorator: Style(color="bright_magenta", bold=True),
- Name.Variable: Style(color="bright_red"),
- Name.Constant: Style(color="bright_red"),
- Name.Attribute: Style(color="bright_cyan"),
- Name.Tag: Style(color="bright_blue"),
- String: Style(color="yellow"),
- Number: Style(color="bright_blue"),
- Generic.Deleted: Style(color="bright_red"),
- Generic.Inserted: Style(color="bright_green"),
- Generic.Heading: Style(bold=True),
- Generic.Subheading: Style(color="bright_magenta", bold=True),
- Generic.Prompt: Style(bold=True),
- Generic.Error: Style(color="bright_red"),
- Error: Style(color="red", underline=True),
-}
-
-RICH_SYNTAX_THEMES = {"ansi_light": ANSI_LIGHT, "ansi_dark": ANSI_DARK}
-NUMBERS_COLUMN_DEFAULT_PADDING = 2
-
-
-class SyntaxTheme(ABC):
- """Base class for a syntax theme."""
-
- @abstractmethod
- def get_style_for_token(self, token_type: TokenType) -> Style:
- """Get a style for a given Pygments token."""
- raise NotImplementedError # pragma: no cover
-
- @abstractmethod
- def get_background_style(self) -> Style:
- """Get the background color."""
- raise NotImplementedError # pragma: no cover
-
-
-class PygmentsSyntaxTheme(SyntaxTheme):
- """Syntax theme that delegates to Pygments theme."""
-
- def __init__(self, theme: Union[str, Type[PygmentsStyle]]) -> None:
- self._style_cache: Dict[TokenType, Style] = {}
- if isinstance(theme, str):
- try:
- self._pygments_style_class = get_style_by_name(theme)
- except ClassNotFound:
- self._pygments_style_class = get_style_by_name("default")
- else:
- self._pygments_style_class = theme
-
- self._background_color = self._pygments_style_class.background_color
- self._background_style = Style(bgcolor=self._background_color)
-
- def get_style_for_token(self, token_type: TokenType) -> Style:
- """Get a style from a Pygments class."""
- try:
- return self._style_cache[token_type]
- except KeyError:
- try:
- pygments_style = self._pygments_style_class.style_for_token(token_type)
- except KeyError:
- style = Style.null()
- else:
- color = pygments_style["color"]
- bgcolor = pygments_style["bgcolor"]
- style = Style(
- color="#" + color if color else "#000000",
- bgcolor="#" + bgcolor if bgcolor else self._background_color,
- bold=pygments_style["bold"],
- italic=pygments_style["italic"],
- underline=pygments_style["underline"],
- )
- self._style_cache[token_type] = style
- return style
-
- def get_background_style(self) -> Style:
- return self._background_style
-
-
-class ANSISyntaxTheme(SyntaxTheme):
- """Syntax theme to use standard colors."""
-
- def __init__(self, style_map: Dict[TokenType, Style]) -> None:
- self.style_map = style_map
- self._missing_style = Style.null()
- self._background_style = Style.null()
- self._style_cache: Dict[TokenType, Style] = {}
-
- def get_style_for_token(self, token_type: TokenType) -> Style:
- """Look up style in the style map."""
- try:
- return self._style_cache[token_type]
- except KeyError:
- # Styles form a hierarchy
- # We need to go from most to least specific
- # e.g. ("foo", "bar", "baz") to ("foo", "bar") to ("foo",)
- get_style = self.style_map.get
- token = tuple(token_type)
- style = self._missing_style
- while token:
- _style = get_style(token)
- if _style is not None:
- style = _style
- break
- token = token[:-1]
- self._style_cache[token_type] = style
- return style
-
- def get_background_style(self) -> Style:
- return self._background_style
-
-
-SyntaxPosition = Tuple[int, int]
-
-
-class _SyntaxHighlightRange(NamedTuple):
- """
- A range to highlight in a Syntax object.
- `start` and `end` are 2-integers tuples, where the first integer is the line number
- (starting from 1) and the second integer is the column index (starting from 0).
- """
-
- style: StyleType
- start: SyntaxPosition
- end: SyntaxPosition
-
-
-class Syntax(JupyterMixin):
- """Construct a Syntax object to render syntax highlighted code.
-
- Args:
- code (str): Code to highlight.
- lexer (Lexer | str): Lexer to use (see https://pygments.org/docs/lexers/)
- theme (str, optional): Color theme, aka Pygments style (see https://pygments.org/docs/styles/#getting-a-list-of-available-styles). Defaults to "monokai".
- dedent (bool, optional): Enable stripping of initial whitespace. Defaults to False.
- line_numbers (bool, optional): Enable rendering of line numbers. Defaults to False.
- start_line (int, optional): Starting number for line numbers. Defaults to 1.
- line_range (Tuple[int | None, int | None], optional): If given should be a tuple of the start and end line to render.
- A value of None in the tuple indicates the range is open in that direction.
- highlight_lines (Set[int]): A set of line numbers to highlight.
- code_width: Width of code to render (not including line numbers), or ``None`` to use all available width.
- tab_size (int, optional): Size of tabs. Defaults to 4.
- word_wrap (bool, optional): Enable word wrapping.
- background_color (str, optional): Optional background color, or None to use theme color. Defaults to None.
- indent_guides (bool, optional): Show indent guides. Defaults to False.
- padding (PaddingDimensions): Padding to apply around the syntax. Defaults to 0 (no padding).
- """
-
- _pygments_style_class: Type[PygmentsStyle]
- _theme: SyntaxTheme
-
- @classmethod
- def get_theme(cls, name: Union[str, SyntaxTheme]) -> SyntaxTheme:
- """Get a syntax theme instance."""
- if isinstance(name, SyntaxTheme):
- return name
- theme: SyntaxTheme
- if name in RICH_SYNTAX_THEMES:
- theme = ANSISyntaxTheme(RICH_SYNTAX_THEMES[name])
- else:
- theme = PygmentsSyntaxTheme(name)
- return theme
-
- def __init__(
- self,
- code: str,
- lexer: Union[Lexer, str],
- *,
- theme: Union[str, SyntaxTheme] = DEFAULT_THEME,
- dedent: bool = False,
- line_numbers: bool = False,
- start_line: int = 1,
- line_range: Optional[Tuple[Optional[int], Optional[int]]] = None,
- highlight_lines: Optional[Set[int]] = None,
- code_width: Optional[int] = None,
- tab_size: int = 4,
- word_wrap: bool = False,
- background_color: Optional[str] = None,
- indent_guides: bool = False,
- padding: PaddingDimensions = 0,
- ) -> None:
- self.code = code
- self._lexer = lexer
- self.dedent = dedent
- self.line_numbers = line_numbers
- self.start_line = start_line
- self.line_range = line_range
- self.highlight_lines = highlight_lines or set()
- self.code_width = code_width
- self.tab_size = tab_size
- self.word_wrap = word_wrap
- self.background_color = background_color
- self.background_style = (
- Style(bgcolor=background_color) if background_color else Style()
- )
- self.indent_guides = indent_guides
- self.padding = padding
-
- self._theme = self.get_theme(theme)
- self._stylized_ranges: List[_SyntaxHighlightRange] = []
-
- @classmethod
- def from_path(
- cls,
- path: str,
- encoding: str = "utf-8",
- lexer: Optional[Union[Lexer, str]] = None,
- theme: Union[str, SyntaxTheme] = DEFAULT_THEME,
- dedent: bool = False,
- line_numbers: bool = False,
- line_range: Optional[Tuple[int, int]] = None,
- start_line: int = 1,
- highlight_lines: Optional[Set[int]] = None,
- code_width: Optional[int] = None,
- tab_size: int = 4,
- word_wrap: bool = False,
- background_color: Optional[str] = None,
- indent_guides: bool = False,
- padding: PaddingDimensions = 0,
- ) -> "Syntax":
- """Construct a Syntax object from a file.
-
- Args:
- path (str): Path to file to highlight.
- encoding (str): Encoding of file.
- lexer (str | Lexer, optional): Lexer to use. If None, lexer will be auto-detected from path/file content.
- theme (str, optional): Color theme, aka Pygments style (see https://pygments.org/docs/styles/#getting-a-list-of-available-styles). Defaults to "emacs".
- dedent (bool, optional): Enable stripping of initial whitespace. Defaults to True.
- line_numbers (bool, optional): Enable rendering of line numbers. Defaults to False.
- start_line (int, optional): Starting number for line numbers. Defaults to 1.
- line_range (Tuple[int, int], optional): If given should be a tuple of the start and end line to render.
- highlight_lines (Set[int]): A set of line numbers to highlight.
- code_width: Width of code to render (not including line numbers), or ``None`` to use all available width.
- tab_size (int, optional): Size of tabs. Defaults to 4.
- word_wrap (bool, optional): Enable word wrapping of code.
- background_color (str, optional): Optional background color, or None to use theme color. Defaults to None.
- indent_guides (bool, optional): Show indent guides. Defaults to False.
- padding (PaddingDimensions): Padding to apply around the syntax. Defaults to 0 (no padding).
-
- Returns:
- [Syntax]: A Syntax object that may be printed to the console
- """
- code = Path(path).read_text(encoding=encoding)
-
- if not lexer:
- lexer = cls.guess_lexer(path, code=code)
-
- return cls(
- code,
- lexer,
- theme=theme,
- dedent=dedent,
- line_numbers=line_numbers,
- line_range=line_range,
- start_line=start_line,
- highlight_lines=highlight_lines,
- code_width=code_width,
- tab_size=tab_size,
- word_wrap=word_wrap,
- background_color=background_color,
- indent_guides=indent_guides,
- padding=padding,
- )
-
- @classmethod
- def guess_lexer(cls, path: str, code: Optional[str] = None) -> str:
- """Guess the alias of the Pygments lexer to use based on a path and an optional string of code.
- If code is supplied, it will use a combination of the code and the filename to determine the
- best lexer to use. For example, if the file is ``index.html`` and the file contains Django
- templating syntax, then "html+django" will be returned. If the file is ``index.html``, and no
- templating language is used, the "html" lexer will be used. If no string of code
- is supplied, the lexer will be chosen based on the file extension..
-
- Args:
- path (AnyStr): The path to the file containing the code you wish to know the lexer for.
- code (str, optional): Optional string of code that will be used as a fallback if no lexer
- is found for the supplied path.
-
- Returns:
- str: The name of the Pygments lexer that best matches the supplied path/code.
- """
- lexer: Optional[Lexer] = None
- lexer_name = "default"
- if code:
- try:
- lexer = guess_lexer_for_filename(path, code)
- except ClassNotFound:
- pass
-
- if not lexer:
- try:
- _, ext = os.path.splitext(path)
- if ext:
- extension = ext.lstrip(".").lower()
- lexer = get_lexer_by_name(extension)
- except ClassNotFound:
- pass
-
- if lexer:
- if lexer.aliases:
- lexer_name = lexer.aliases[0]
- else:
- lexer_name = lexer.name
-
- return lexer_name
-
- def _get_base_style(self) -> Style:
- """Get the base style."""
- default_style = self._theme.get_background_style() + self.background_style
- return default_style
-
- def _get_token_color(self, token_type: TokenType) -> Optional[Color]:
- """Get a color (if any) for the given token.
-
- Args:
- token_type (TokenType): A token type tuple from Pygments.
-
- Returns:
- Optional[Color]: Color from theme, or None for no color.
- """
- style = self._theme.get_style_for_token(token_type)
- return style.color
-
- @property
- def lexer(self) -> Optional[Lexer]:
- """The lexer for this syntax, or None if no lexer was found.
-
- Tries to find the lexer by name if a string was passed to the constructor.
- """
-
- if isinstance(self._lexer, Lexer):
- return self._lexer
- try:
- return get_lexer_by_name(
- self._lexer,
- stripnl=False,
- ensurenl=True,
- tabsize=self.tab_size,
- )
- except ClassNotFound:
- return None
-
- @property
- def default_lexer(self) -> Lexer:
- """A Pygments Lexer to use if one is not specified or invalid."""
- return get_lexer_by_name(
- "text",
- stripnl=False,
- ensurenl=True,
- tabsize=self.tab_size,
- )
-
- def highlight(
- self,
- code: str,
- line_range: Optional[Tuple[Optional[int], Optional[int]]] = None,
- ) -> Text:
- """Highlight code and return a Text instance.
-
- Args:
- code (str): Code to highlight.
- line_range(Tuple[int, int], optional): Optional line range to highlight.
-
- Returns:
- Text: A text instance containing highlighted syntax.
- """
-
- base_style = self._get_base_style()
- justify: JustifyMethod = (
- "default" if base_style.transparent_background else "left"
- )
-
- text = Text(
- justify=justify,
- style=base_style,
- tab_size=self.tab_size,
- no_wrap=not self.word_wrap,
- )
- _get_theme_style = self._theme.get_style_for_token
-
- lexer = self.lexer or self.default_lexer
-
- if lexer is None:
- text.append(code)
- else:
- if line_range:
- # More complicated path to only stylize a portion of the code
- # This speeds up further operations as there are less spans to process
- line_start, line_end = line_range
-
- def line_tokenize() -> Iterable[Tuple[Any, str]]:
- """Split tokens to one per line."""
- assert lexer # required to make MyPy happy - we know lexer is not None at this point
-
- for token_type, token in lexer.get_tokens(code):
- while token:
- line_token, new_line, token = token.partition("\n")
- yield token_type, line_token + new_line
-
- def tokens_to_spans() -> Iterable[Tuple[str, Optional[Style]]]:
- """Convert tokens to spans."""
- tokens = iter(line_tokenize())
- line_no = 0
- _line_start = line_start - 1 if line_start else 0
-
- # Skip over tokens until line start
- while line_no < _line_start:
- try:
- _token_type, token = next(tokens)
- except StopIteration:
- break
- yield (token, None)
- if token.endswith("\n"):
- line_no += 1
- # Generate spans until line end
- for token_type, token in tokens:
- yield (token, _get_theme_style(token_type))
- if token.endswith("\n"):
- line_no += 1
- if line_end and line_no >= line_end:
- break
-
- text.append_tokens(tokens_to_spans())
-
- else:
- text.append_tokens(
- (token, _get_theme_style(token_type))
- for token_type, token in lexer.get_tokens(code)
- )
- if self.background_color is not None:
- text.stylize(f"on {self.background_color}")
-
- if self._stylized_ranges:
- self._apply_stylized_ranges(text)
-
- return text
-
- def stylize_range(
- self, style: StyleType, start: SyntaxPosition, end: SyntaxPosition
- ) -> None:
- """
- Adds a custom style on a part of the code, that will be applied to the syntax display when it's rendered.
- Line numbers are 1-based, while column indexes are 0-based.
-
- Args:
- style (StyleType): The style to apply.
- start (Tuple[int, int]): The start of the range, in the form `[line number, column index]`.
- end (Tuple[int, int]): The end of the range, in the form `[line number, column index]`.
- """
- self._stylized_ranges.append(_SyntaxHighlightRange(style, start, end))
-
- def _get_line_numbers_color(self, blend: float = 0.3) -> Color:
- background_style = self._theme.get_background_style() + self.background_style
- background_color = background_style.bgcolor
- if background_color is None or background_color.is_system_defined:
- return Color.default()
- foreground_color = self._get_token_color(Token.Text)
- if foreground_color is None or foreground_color.is_system_defined:
- return foreground_color or Color.default()
- new_color = blend_rgb(
- background_color.get_truecolor(),
- foreground_color.get_truecolor(),
- cross_fade=blend,
- )
- return Color.from_triplet(new_color)
-
- @property
- def _numbers_column_width(self) -> int:
- """Get the number of characters used to render the numbers column."""
- column_width = 0
- if self.line_numbers:
- column_width = (
- len(str(self.start_line + self.code.count("\n")))
- + NUMBERS_COLUMN_DEFAULT_PADDING
- )
- return column_width
-
- def _get_number_styles(self, console: Console) -> Tuple[Style, Style, Style]:
- """Get background, number, and highlight styles for line numbers."""
- background_style = self._get_base_style()
- if background_style.transparent_background:
- return Style.null(), Style(dim=True), Style.null()
- if console.color_system in ("256", "truecolor"):
- number_style = Style.chain(
- background_style,
- self._theme.get_style_for_token(Token.Text),
- Style(color=self._get_line_numbers_color()),
- self.background_style,
- )
- highlight_number_style = Style.chain(
- background_style,
- self._theme.get_style_for_token(Token.Text),
- Style(bold=True, color=self._get_line_numbers_color(0.9)),
- self.background_style,
- )
- else:
- number_style = background_style + Style(dim=True)
- highlight_number_style = background_style + Style(dim=False)
- return background_style, number_style, highlight_number_style
-
- def __rich_measure__(
- self, console: "Console", options: "ConsoleOptions"
- ) -> "Measurement":
- _, right, _, left = Padding.unpack(self.padding)
- padding = left + right
- if self.code_width is not None:
- width = self.code_width + self._numbers_column_width + padding + 1
- return Measurement(self._numbers_column_width, width)
- lines = self.code.splitlines()
- width = (
- self._numbers_column_width
- + padding
- + (max(cell_len(line) for line in lines) if lines else 0)
- )
- if self.line_numbers:
- width += 1
- return Measurement(self._numbers_column_width, width)
-
- def __rich_console__(
- self, console: Console, options: ConsoleOptions
- ) -> RenderResult:
- segments = Segments(self._get_syntax(console, options))
- if self.padding:
- yield Padding(
- segments, style=self._theme.get_background_style(), pad=self.padding
- )
- else:
- yield segments
-
- def _get_syntax(
- self,
- console: Console,
- options: ConsoleOptions,
- ) -> Iterable[Segment]:
- """
- Get the Segments for the Syntax object, excluding any vertical/horizontal padding
- """
- transparent_background = self._get_base_style().transparent_background
- code_width = (
- (
- (options.max_width - self._numbers_column_width - 1)
- if self.line_numbers
- else options.max_width
- )
- if self.code_width is None
- else self.code_width
- )
-
- ends_on_nl, processed_code = self._process_code(self.code)
- text = self.highlight(processed_code, self.line_range)
-
- if not self.line_numbers and not self.word_wrap and not self.line_range:
- if not ends_on_nl:
- text.remove_suffix("\n")
- # Simple case of just rendering text
- style = (
- self._get_base_style()
- + self._theme.get_style_for_token(Comment)
- + Style(dim=True)
- + self.background_style
- )
- if self.indent_guides and not options.ascii_only:
- text = text.with_indent_guides(self.tab_size, style=style)
- text.overflow = "crop"
- if style.transparent_background:
- yield from console.render(
- text, options=options.update(width=code_width)
- )
- else:
- syntax_lines = console.render_lines(
- text,
- options.update(width=code_width, height=None, justify="left"),
- style=self.background_style,
- pad=True,
- new_lines=True,
- )
- for syntax_line in syntax_lines:
- yield from syntax_line
- return
-
- start_line, end_line = self.line_range or (None, None)
- line_offset = 0
- if start_line:
- line_offset = max(0, start_line - 1)
- lines: Union[List[Text], Lines] = text.split("\n", allow_blank=ends_on_nl)
- if self.line_range:
- if line_offset > len(lines):
- return
- lines = lines[line_offset:end_line]
-
- if self.indent_guides and not options.ascii_only:
- style = (
- self._get_base_style()
- + self._theme.get_style_for_token(Comment)
- + Style(dim=True)
- + self.background_style
- )
- lines = (
- Text("\n")
- .join(lines)
- .with_indent_guides(self.tab_size, style=style + Style(italic=False))
- .split("\n", allow_blank=True)
- )
-
- numbers_column_width = self._numbers_column_width
- render_options = options.update(width=code_width)
-
- highlight_line = self.highlight_lines.__contains__
- _Segment = Segment
- new_line = _Segment("\n")
-
- line_pointer = "> " if options.legacy_windows else "❱ "
-
- (
- background_style,
- number_style,
- highlight_number_style,
- ) = self._get_number_styles(console)
-
- for line_no, line in enumerate(lines, self.start_line + line_offset):
- if self.word_wrap:
- wrapped_lines = console.render_lines(
- line,
- render_options.update(height=None, justify="left"),
- style=background_style,
- pad=not transparent_background,
- )
- else:
- segments = list(line.render(console, end=""))
- if options.no_wrap:
- wrapped_lines = [segments]
- else:
- wrapped_lines = [
- _Segment.adjust_line_length(
- segments,
- render_options.max_width,
- style=background_style,
- pad=not transparent_background,
- )
- ]
-
- if self.line_numbers:
- wrapped_line_left_pad = _Segment(
- " " * numbers_column_width + " ", background_style
- )
- for first, wrapped_line in loop_first(wrapped_lines):
- if first:
- line_column = str(line_no).rjust(numbers_column_width - 2) + " "
- if highlight_line(line_no):
- yield _Segment(line_pointer, Style(color="red"))
- yield _Segment(line_column, highlight_number_style)
- else:
- yield _Segment(" ", highlight_number_style)
- yield _Segment(line_column, number_style)
- else:
- yield wrapped_line_left_pad
- yield from wrapped_line
- yield new_line
- else:
- for wrapped_line in wrapped_lines:
- yield from wrapped_line
- yield new_line
-
- def _apply_stylized_ranges(self, text: Text) -> None:
- """
- Apply stylized ranges to a text instance,
- using the given code to determine the right portion to apply the style to.
-
- Args:
- text (Text): Text instance to apply the style to.
- """
- code = text.plain
- newlines_offsets = [
- # Let's add outer boundaries at each side of the list:
- 0,
- # N.B. using "\n" here is much faster than using metacharacters such as "^" or "\Z":
- *[
- match.start() + 1
- for match in re.finditer("\n", code, flags=re.MULTILINE)
- ],
- len(code) + 1,
- ]
-
- for stylized_range in self._stylized_ranges:
- start = _get_code_index_for_syntax_position(
- newlines_offsets, stylized_range.start
- )
- end = _get_code_index_for_syntax_position(
- newlines_offsets, stylized_range.end
- )
- if start is not None and end is not None:
- text.stylize(stylized_range.style, start, end)
-
- def _process_code(self, code: str) -> Tuple[bool, str]:
- """
- Applies various processing to a raw code string
- (normalises it so it always ends with a line return, dedents it if necessary, etc.)
-
- Args:
- code (str): The raw code string to process
-
- Returns:
- Tuple[bool, str]: the boolean indicates whether the raw code ends with a line return,
- while the string is the processed code.
- """
- ends_on_nl = code.endswith("\n")
- processed_code = code if ends_on_nl else code + "\n"
- processed_code = (
- textwrap.dedent(processed_code) if self.dedent else processed_code
- )
- processed_code = processed_code.expandtabs(self.tab_size)
- return ends_on_nl, processed_code
-
-
-def _get_code_index_for_syntax_position(
- newlines_offsets: Sequence[int], position: SyntaxPosition
-) -> Optional[int]:
- """
- Returns the index of the code string for the given positions.
-
- Args:
- newlines_offsets (Sequence[int]): The offset of each newline character found in the code snippet.
- position (SyntaxPosition): The position to search for.
-
- Returns:
- Optional[int]: The index of the code string for this position, or `None`
- if the given position's line number is out of range (if it's the column that is out of range
- we silently clamp its value so that it reaches the end of the line)
- """
- lines_count = len(newlines_offsets)
-
- line_number, column_index = position
- if line_number > lines_count or len(newlines_offsets) < (line_number + 1):
- return None # `line_number` is out of range
- line_index = line_number - 1
- line_length = newlines_offsets[line_index + 1] - newlines_offsets[line_index] - 1
- # If `column_index` is out of range: let's silently clamp it:
- column_index = min(line_length, column_index)
- return newlines_offsets[line_index] + column_index
-
-
-if __name__ == "__main__": # pragma: no cover
- import argparse
- import sys
-
- parser = argparse.ArgumentParser(
- description="Render syntax to the console with Rich"
- )
- parser.add_argument(
- "path",
- metavar="PATH",
- help="path to file, or - for stdin",
- )
- parser.add_argument(
- "-c",
- "--force-color",
- dest="force_color",
- action="store_true",
- default=None,
- help="force color for non-terminals",
- )
- parser.add_argument(
- "-i",
- "--indent-guides",
- dest="indent_guides",
- action="store_true",
- default=False,
- help="display indent guides",
- )
- parser.add_argument(
- "-l",
- "--line-numbers",
- dest="line_numbers",
- action="store_true",
- help="render line numbers",
- )
- parser.add_argument(
- "-w",
- "--width",
- type=int,
- dest="width",
- default=None,
- help="width of output (default will auto-detect)",
- )
- parser.add_argument(
- "-r",
- "--wrap",
- dest="word_wrap",
- action="store_true",
- default=False,
- help="word wrap long lines",
- )
- parser.add_argument(
- "-s",
- "--soft-wrap",
- action="store_true",
- dest="soft_wrap",
- default=False,
- help="enable soft wrapping mode",
- )
- parser.add_argument(
- "-t", "--theme", dest="theme", default="monokai", help="pygments theme"
- )
- parser.add_argument(
- "-b",
- "--background-color",
- dest="background_color",
- default=None,
- help="Override background color",
- )
- parser.add_argument(
- "-x",
- "--lexer",
- default=None,
- dest="lexer_name",
- help="Lexer name",
- )
- parser.add_argument(
- "-p", "--padding", type=int, default=0, dest="padding", help="Padding"
- )
- parser.add_argument(
- "--highlight-line",
- type=int,
- default=None,
- dest="highlight_line",
- help="The line number (not index!) to highlight",
- )
- args = parser.parse_args()
-
- from rich.console import Console
-
- console = Console(force_terminal=args.force_color, width=args.width)
-
- if args.path == "-":
- code = sys.stdin.read()
- syntax = Syntax(
- code=code,
- lexer=args.lexer_name,
- line_numbers=args.line_numbers,
- word_wrap=args.word_wrap,
- theme=args.theme,
- background_color=args.background_color,
- indent_guides=args.indent_guides,
- padding=args.padding,
- highlight_lines={args.highlight_line},
- )
- else:
- syntax = Syntax.from_path(
- args.path,
- lexer=args.lexer_name,
- line_numbers=args.line_numbers,
- word_wrap=args.word_wrap,
- theme=args.theme,
- background_color=args.background_color,
- indent_guides=args.indent_guides,
- padding=args.padding,
- highlight_lines={args.highlight_line},
- )
- console.print(syntax, soft_wrap=args.soft_wrap)