From c50751c77425bb996429aa735f9109fe87a0994d Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sun, 13 Sep 2020 12:57:45 +0100 Subject: [PATCH 01/13] inline code in Markdown --- rich/markdown.py | 200 +++++++++++++++++++++++++++-------------------- rich/syntax.py | 19 +++-- 2 files changed, 130 insertions(+), 89 deletions(-) diff --git a/rich/markdown.py b/rich/markdown.py index 1e622776..991ad60b 100644 --- a/rich/markdown.py +++ b/rich/markdown.py @@ -18,7 +18,7 @@ from .panel import Panel from .rule import Rule from .style import Style, StyleStack from .syntax import Syntax -from .text import Text +from .text import Text, TextType class MarkdownElement: @@ -45,7 +45,7 @@ class MarkdownElement: context (MarkdownContext): The markdown context. """ - def on_text(self, context: "MarkdownContext", text: str) -> None: + def on_text(self, context: "MarkdownContext", text: TextType) -> None: """Called when text is parsed. Args: @@ -99,8 +99,9 @@ class TextElement(MarkdownElement): self.style = context.enter_style(self.style_name) self.text = Text(justify="left") - def on_text(self, context: "MarkdownContext", text: str) -> None: - self.text.append(text, context.current_style) + def on_text(self, context: "MarkdownContext", text: TextType) -> None: + + self.text.append(text, context.current_style if isinstance(text, str) else None) def on_leave(self, context: "MarkdownContext") -> None: context.leave_style() @@ -349,20 +350,36 @@ class ImageItem(TextElement): class MarkdownContext: """Manages the console render state.""" - def __init__(self, console: Console, options: ConsoleOptions, style: Style) -> None: + def __init__( + self, + console: Console, + options: ConsoleOptions, + style: Style, + inline_code_theme: str = None, + inline_code_lexer: str = "python", + ) -> None: self.console = console self.options = options self.style_stack: StyleStack = StyleStack(style) self.stack: Stack[MarkdownElement] = Stack() + self._syntax: Optional[Syntax] = None + if inline_code_theme is not None: + self._syntax = Syntax("", inline_code_lexer, theme=inline_code_theme) + @property def current_style(self) -> Style: """Current style which is the product of all styles on the stack.""" return self.style_stack.current - def on_text(self, text: str) -> None: + def on_text(self, text: str, node_type: str) -> None: """Called when the parser visits text.""" - self.stack.top.on_text(self, text) + if node_type == "code" and self._syntax is not None: + highlight_text = self._syntax.highlight(text) + highlight_text.rstrip() + self.stack.top.on_text(self, highlight_text) + else: + self.stack.top.on_text(self, text) def enter_style(self, style_name: Union[str, Style]) -> Style: """Enter a style context.""" @@ -406,6 +423,8 @@ class Markdown(JupyterMixin): justify: JustifyMethod = None, style: Union[str, Style] = "none", hyperlinks: bool = True, + inline_code_theme: Optional[str] = "monokai", + inline_code_lexer: str = "python", ) -> None: self.markup = markup parser = Parser() @@ -414,26 +433,34 @@ class Markdown(JupyterMixin): self.justify = justify self.style = style self.hyperlinks = hyperlinks + self.inline_code_lexer = inline_code_lexer + self.inline_code_theme = inline_code_theme def __rich_console__( self, console: Console, options: ConsoleOptions ) -> RenderResult: """Render markdown to the console.""" style = console.get_style(self.style, default="none") - context = MarkdownContext(console, options, style) + context = MarkdownContext( + console, + options, + style, + inline_code_theme=self.inline_code_theme, + inline_code_lexer=self.inline_code_lexer, + ) nodes = self.parsed.walker() inlines = self.inlines new_line = False for current, entering in nodes: node_type = current.t if node_type in ("html_inline", "html_block", "text"): - context.on_text(current.literal.replace("\n", " ")) + context.on_text(current.literal.replace("\n", " "), node_type) elif node_type == "linebreak": if entering: - context.on_text("\n") + context.on_text("\n", node_type) elif node_type == "softbreak": if entering: - context.on_text(" ") + context.on_text(" ", node_type) elif node_type == "link": if entering: link_style = console.get_style("markdown.link", default="none") @@ -443,14 +470,14 @@ class Markdown(JupyterMixin): else: context.leave_style() if not self.hyperlinks: - context.on_text(" (") + context.on_text(" (", node_type) style = Style(underline=True) + console.get_style( "markdown.link_url", default="none" ) context.enter_style(style) - context.on_text(current.destination) + context.on_text(current.destination, node_type) context.leave_style() - context.on_text(")") + context.on_text(")", node_type) elif node_type in inlines: if current.is_container(): if entering: @@ -460,7 +487,7 @@ class Markdown(JupyterMixin): else: context.enter_style(f"markdown.{node_type}") if current.literal: - context.on_text(current.literal) + context.on_text(current.literal, node_type) context.leave_style() else: element_class = self.elements.get(node_type) or UnknownElement @@ -500,77 +527,84 @@ class Markdown(JupyterMixin): if __name__ == "__main__": # pragma: no cover - import argparse + test = """# Hello +This is a test of inline code: `import this` , `for a in range(10):`""" + from rich import print - parser = argparse.ArgumentParser( - description="Render Markdown to the console with Rich" - ) - parser.add_argument("path", metavar="PATH", help="path to markdown file") - parser.add_argument( - "-c", - "--force-color", - dest="force_color", - action="store_true", - default=None, - help="force color for non-terminals", - ) - parser.add_argument( - "-t", - "--code-theme", - dest="code_theme", - default="monokai", - help="pygments code theme", - ) - parser.add_argument( - "-y", - "--hyperlinks", - dest="hyperlinks", - action="store_true", - help="enable hyperlinks", - ) - parser.add_argument( - "-w", - "--width", - type=int, - dest="width", - default=None, - help="width of output (default will auto-detect)", - ) - parser.add_argument( - "-j", - "--justify", - dest="justify", - action="store_true", - help="enable full text justify", - ) - parser.add_argument( - "-p", - "--page", - dest="page", - action="store_true", - help="use pager to scroll output", - ) - args = parser.parse_args() + print(Markdown(test, inline_code_theme="emacs")) - from rich.console import Console + if 0: + import argparse - with open(args.path, "rt", encoding="utf-8") as markdown_file: - markdown = Markdown( - markdown_file.read(), - justify="full" if args.justify else "left", - code_theme=args.code_theme, - hyperlinks=args.hyperlinks, + parser = argparse.ArgumentParser( + description="Render Markdown to the console with Rich" ) - if args.page: - import pydoc - import io - - console = Console( - file=io.StringIO(), force_terminal=args.force_color, width=args.width + parser.add_argument("path", metavar="PATH", help="path to markdown file") + parser.add_argument( + "-c", + "--force-color", + dest="force_color", + action="store_true", + default=None, + help="force color for non-terminals", ) - console.print(markdown) - pydoc.pager(console.file.getvalue()) # type: ignore + parser.add_argument( + "-t", + "--code-theme", + dest="code_theme", + default="monokai", + help="pygments code theme", + ) + parser.add_argument( + "-y", + "--hyperlinks", + dest="hyperlinks", + action="store_true", + help="enable hyperlinks", + ) + parser.add_argument( + "-w", + "--width", + type=int, + dest="width", + default=None, + help="width of output (default will auto-detect)", + ) + parser.add_argument( + "-j", + "--justify", + dest="justify", + action="store_true", + help="enable full text justify", + ) + parser.add_argument( + "-p", + "--page", + dest="page", + action="store_true", + help="use pager to scroll output", + ) + args = parser.parse_args() - else: - console = Console(force_terminal=args.force_color, width=args.width) - console.print(markdown) + from rich.console import Console + + with open(args.path, "rt", encoding="utf-8") as markdown_file: + markdown = Markdown( + markdown_file.read(), + justify="full" if args.justify else "left", + code_theme=args.code_theme, + hyperlinks=args.hyperlinks, + ) + if args.page: + import pydoc + import io + + console = Console( + file=io.StringIO(), force_terminal=args.force_color, width=args.width + ) + console.print(markdown) + pydoc.pager(console.file.getvalue()) # type: ignore + + else: + console = Console(force_terminal=args.force_color, width=args.width) + console.print(markdown) diff --git a/rich/syntax.py b/rich/syntax.py index c5dc951a..81628de8 100644 --- a/rich/syntax.py +++ b/rich/syntax.py @@ -11,7 +11,7 @@ from pygments.util import ClassNotFound from ._loop import loop_first from .color import Color, blend_rgb, parse_rgb_hex -from .console import Console, ConsoleOptions, RenderResult, Segment +from .console import Console, ConsoleOptions, JustifyMethod, RenderResult, Segment from .jupyter import JupyterMixin from .measure import Measurement from .style import Style @@ -173,18 +173,25 @@ class Syntax(JupyterMixin): style = style + Style(bgcolor=self._pygments_style_class.background_color) return style - def _highlight(self, lexer_name: str) -> Text: + def highlight(self, code: str = None) -> Text: + """Highlight a string with the given lexter and return a Text instance. + + Returns: + Text: A text instance containing highlights. + """ + if code is None: + code = self.code default_style = self._get_default_style() try: - lexer = get_lexer_by_name(lexer_name) + lexer = get_lexer_by_name(self.lexer_name) except ClassNotFound: return Text( - self.code, justify="left", style=default_style, tab_size=self.tab_size + code, justify="left", style=default_style, tab_size=self.tab_size ) text = Text(justify="left", style=default_style, tab_size=self.tab_size) append = text.append _get_theme_style = self._get_theme_style - for token_type, token in lexer.get_tokens(self.code): + for token_type, token in lexer.get_tokens(code): append(token, _get_theme_style(token_type)) return text @@ -244,7 +251,7 @@ class Syntax(JupyterMixin): code = self.code if self.dedent: code = textwrap.dedent(code) - text = self._highlight(self.lexer_name) + text = self.highlight() if text.plain.endswith("\n"): text.plain = text.plain[:-1] if not self.line_numbers: From 28c016a142078ba390e489a78b626057f2a5b98a Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sun, 13 Sep 2020 13:08:27 +0100 Subject: [PATCH 02/13] docstring --- CHANGELOG.md | 6 ++ rich/console.py | 2 +- rich/markdown.py | 150 +++++++++++++++++++++++------------------------ 3 files changed, 80 insertions(+), 78 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0dfb0c09..aa337e2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [6.2.0] - 2020-09-13 + +### Added + +- Added inline code highlighting to Markdown + ## [6.1.2] - 2020-09-11 ### Added diff --git a/rich/console.py b/rich/console.py index d8f63e21..5fca0280 100644 --- a/rich/console.py +++ b/rich/console.py @@ -182,7 +182,7 @@ class RenderGroup: def render_group(fit: bool = False) -> Callable: """A decorator that turns an iterable of renderables in to a group.""" - + def decorator(method): """Convert a method that returns an iterable of renderables in to a RenderGroup.""" diff --git a/rich/markdown.py b/rich/markdown.py index 991ad60b..3d13334a 100644 --- a/rich/markdown.py +++ b/rich/markdown.py @@ -100,7 +100,6 @@ class TextElement(MarkdownElement): self.text = Text(justify="left") def on_text(self, context: "MarkdownContext", text: TextType) -> None: - self.text.append(text, context.current_style if isinstance(text, str) else None) def on_leave(self, context: "MarkdownContext") -> None: @@ -402,6 +401,10 @@ class Markdown(JupyterMixin): justify (JustifyMethod, optional): Justify value for paragraphs. Defaults to None. style (Union[str, Style], optional): Optional style to apply to markdown. hyperlinks (bool, optional): Enable hyperlinks. Defaults to ``True``. + inline_code_theme: (Optional[str], optional): Pygments theme for inline code + highlighting, or None for no highlighting. Defaults to None. + inline_code_lexter: (str, optional): Lexer to use if inline code highlighting is + enabled. Defaults to "python". """ elements: ClassVar[Dict[str, Type[MarkdownElement]]] = { @@ -423,7 +426,7 @@ class Markdown(JupyterMixin): justify: JustifyMethod = None, style: Union[str, Style] = "none", hyperlinks: bool = True, - inline_code_theme: Optional[str] = "monokai", + inline_code_theme: Optional[str] = None, inline_code_lexer: str = "python", ) -> None: self.markup = markup @@ -527,84 +530,77 @@ class Markdown(JupyterMixin): if __name__ == "__main__": # pragma: no cover - test = """# Hello -This is a test of inline code: `import this` , `for a in range(10):`""" - from rich import print + import argparse - print(Markdown(test, inline_code_theme="emacs")) + parser = argparse.ArgumentParser( + description="Render Markdown to the console with Rich" + ) + parser.add_argument("path", metavar="PATH", help="path to markdown file") + parser.add_argument( + "-c", + "--force-color", + dest="force_color", + action="store_true", + default=None, + help="force color for non-terminals", + ) + parser.add_argument( + "-t", + "--code-theme", + dest="code_theme", + default="monokai", + help="pygments code theme", + ) + parser.add_argument( + "-y", + "--hyperlinks", + dest="hyperlinks", + action="store_true", + help="enable hyperlinks", + ) + parser.add_argument( + "-w", + "--width", + type=int, + dest="width", + default=None, + help="width of output (default will auto-detect)", + ) + parser.add_argument( + "-j", + "--justify", + dest="justify", + action="store_true", + help="enable full text justify", + ) + parser.add_argument( + "-p", + "--page", + dest="page", + action="store_true", + help="use pager to scroll output", + ) + args = parser.parse_args() - if 0: - import argparse + from rich.console import Console - parser = argparse.ArgumentParser( - description="Render Markdown to the console with Rich" + with open(args.path, "rt", encoding="utf-8") as markdown_file: + markdown = Markdown( + markdown_file.read(), + justify="full" if args.justify else "left", + code_theme=args.code_theme, + hyperlinks=args.hyperlinks, ) - parser.add_argument("path", metavar="PATH", help="path to markdown file") - parser.add_argument( - "-c", - "--force-color", - dest="force_color", - action="store_true", - default=None, - help="force color for non-terminals", - ) - parser.add_argument( - "-t", - "--code-theme", - dest="code_theme", - default="monokai", - help="pygments code theme", - ) - parser.add_argument( - "-y", - "--hyperlinks", - dest="hyperlinks", - action="store_true", - help="enable hyperlinks", - ) - parser.add_argument( - "-w", - "--width", - type=int, - dest="width", - default=None, - help="width of output (default will auto-detect)", - ) - parser.add_argument( - "-j", - "--justify", - dest="justify", - action="store_true", - help="enable full text justify", - ) - parser.add_argument( - "-p", - "--page", - dest="page", - action="store_true", - help="use pager to scroll output", - ) - args = parser.parse_args() + if args.page: + import pydoc + import io - from rich.console import Console + console = Console( + file=io.StringIO(), force_terminal=args.force_color, width=args.width + ) + console.print(markdown) + pydoc.pager(console.file.getvalue()) # type: ignore - with open(args.path, "rt", encoding="utf-8") as markdown_file: - markdown = Markdown( - markdown_file.read(), - justify="full" if args.justify else "left", - code_theme=args.code_theme, - hyperlinks=args.hyperlinks, - ) - if args.page: - import pydoc - import io - - console = Console( - file=io.StringIO(), force_terminal=args.force_color, width=args.width - ) - console.print(markdown) - pydoc.pager(console.file.getvalue()) # type: ignore - - else: - console = Console(force_terminal=args.force_color, width=args.width) - console.print(markdown) + else: + console = Console(force_terminal=args.force_color, width=args.width) + console.print(markdown) From 7593e4b2710440a462fbf1f68725da920cccbc49 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sun, 13 Sep 2020 13:11:37 +0100 Subject: [PATCH 03/13] test --- tests/test_markdown.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_markdown.py b/tests/test_markdown.py index af008f11..4d0b4765 100644 --- a/tests/test_markdown.py +++ b/tests/test_markdown.py @@ -97,6 +97,15 @@ def test_markdown_render(): assert rendered_markdown == expected +def test_inline_code(): + markdown = Markdown("inline `import this` code", inline_code_theme="emacs") + result = render(markdown) + expected = "inline \x1b[1;38;2;170;34;255;48;2;248;248;248mimport\x1b[0m\x1b[38;2;0;0;0;48;2;248;248;248m \x1b[0m\x1b[1;38;2;0;0;255;48;2;248;248;248mthis\x1b[0m code \n" + print(result) + print(repr(result)) + assert result == expected + + if __name__ == "__main__": markdown = Markdown(MARKDOWN) rendered = render(markdown) From d21823440fdbe011746f759525bcf776e94fe92e Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sun, 13 Sep 2020 13:12:34 +0100 Subject: [PATCH 04/13] formatting --- examples/group2.py | 2 ++ examples/padding.py | 1 + 2 files changed, 3 insertions(+) diff --git a/examples/group2.py b/examples/group2.py index f48ad15e..13be0704 100644 --- a/examples/group2.py +++ b/examples/group2.py @@ -2,9 +2,11 @@ from rich import print from rich.console import render_group from rich.panel import Panel + @render_group() def get_panels(): yield Panel("Hello", style="on blue") yield Panel("World", style="on red") + print(Panel(get_panels())) diff --git a/examples/padding.py b/examples/padding.py index 024ff5d1..b01d2743 100644 --- a/examples/padding.py +++ b/examples/padding.py @@ -1,4 +1,5 @@ from rich import print from rich.padding import Padding + test = Padding("Hello", (2, 4), style="on blue", expand=False) print(test) From 2dda2e80b258087f01f44a0a37ffbdf69412d65e Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sun, 13 Sep 2020 13:16:55 +0100 Subject: [PATCH 05/13] docs --- rich/syntax.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/rich/syntax.py b/rich/syntax.py index 81628de8..fe0a03f5 100644 --- a/rich/syntax.py +++ b/rich/syntax.py @@ -174,10 +174,14 @@ class Syntax(JupyterMixin): return style def highlight(self, code: str = None) -> Text: - """Highlight a string with the given lexter and return a Text instance. + """Highlight code and return a Text instance. + + Args: + code (Optional[str], optional). Highlight code if a str is given, or + None to use self.code. Returns: - Text: A text instance containing highlights. + Text: A text instance containing syntax highlight. """ if code is None: code = self.code From 5ca3db6aa92eec1b18e5bbd2fb65c0604feaeb5b Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sun, 13 Sep 2020 13:38:56 +0100 Subject: [PATCH 06/13] markdown renderer --- rich/markdown.py | 24 +++++++++++++++++------- tests/test_markdown.py | 6 +++++- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/rich/markdown.py b/rich/markdown.py index 3d13334a..5aefaa96 100644 --- a/rich/markdown.py +++ b/rich/markdown.py @@ -354,8 +354,8 @@ class MarkdownContext: console: Console, options: ConsoleOptions, style: Style, - inline_code_theme: str = None, - inline_code_lexer: str = "python", + inline_code_theme: str, + inline_code_lexer: str = None, ) -> None: self.console = console self.options = options @@ -363,7 +363,7 @@ class MarkdownContext: self.stack: Stack[MarkdownElement] = Stack() self._syntax: Optional[Syntax] = None - if inline_code_theme is not None: + if inline_code_lexer is not None: self._syntax = Syntax("", inline_code_lexer, theme=inline_code_theme) @property @@ -376,7 +376,9 @@ class MarkdownContext: if node_type == "code" and self._syntax is not None: highlight_text = self._syntax.highlight(text) highlight_text.rstrip() - self.stack.top.on_text(self, highlight_text) + self.stack.top.on_text( + self, Text.assemble(highlight_text, style=self.style_stack.current) + ) else: self.stack.top.on_text(self, text) @@ -426,8 +428,8 @@ class Markdown(JupyterMixin): justify: JustifyMethod = None, style: Union[str, Style] = "none", hyperlinks: bool = True, - inline_code_theme: Optional[str] = None, - inline_code_lexer: str = "python", + inline_code_theme: str = None, + inline_code_lexer: str = None, ) -> None: self.markup = markup parser = Parser() @@ -437,7 +439,7 @@ class Markdown(JupyterMixin): self.style = style self.hyperlinks = hyperlinks self.inline_code_lexer = inline_code_lexer - self.inline_code_theme = inline_code_theme + self.inline_code_theme = inline_code_theme or code_theme def __rich_console__( self, console: Console, options: ConsoleOptions @@ -551,6 +553,13 @@ if __name__ == "__main__": # pragma: no cover default="monokai", help="pygments code theme", ) + parser.add_argument( + "-i", + "--inline-code-lexer", + dest="inline_code_lexer", + default=None, + help="inline_code_lexer", + ) parser.add_argument( "-y", "--hyperlinks", @@ -590,6 +599,7 @@ if __name__ == "__main__": # pragma: no cover justify="full" if args.justify else "left", code_theme=args.code_theme, hyperlinks=args.hyperlinks, + inline_code_lexer=args.inline_code_lexer, ) if args.page: import pydoc diff --git a/tests/test_markdown.py b/tests/test_markdown.py index 4d0b4765..2e09b6f2 100644 --- a/tests/test_markdown.py +++ b/tests/test_markdown.py @@ -98,7 +98,11 @@ def test_markdown_render(): def test_inline_code(): - markdown = Markdown("inline `import this` code", inline_code_theme="emacs") + markdown = Markdown( + "inline `import this` code", + inline_code_lexer="python", + inline_code_theme="emacs", + ) result = render(markdown) expected = "inline \x1b[1;38;2;170;34;255;48;2;248;248;248mimport\x1b[0m\x1b[38;2;0;0;0;48;2;248;248;248m \x1b[0m\x1b[1;38;2;0;0;255;48;2;248;248;248mthis\x1b[0m code \n" print(result) From 85e28f1641bdc3744072939c181c836b405ced84 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sun, 13 Sep 2020 15:12:37 +0100 Subject: [PATCH 07/13] rearragement --- rich/markdown.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/rich/markdown.py b/rich/markdown.py index 5aefaa96..44782e19 100644 --- a/rich/markdown.py +++ b/rich/markdown.py @@ -5,13 +5,7 @@ from commonmark.blocks import Parser from . import box from ._loop import loop_first from ._stack import Stack -from .console import ( - Console, - ConsoleOptions, - JustifyMethod, - RenderResult, - Segment, -) +from .console import Console, ConsoleOptions, JustifyMethod, RenderResult, Segment from .containers import Renderables from .jupyter import JupyterMixin from .panel import Panel @@ -354,8 +348,8 @@ class MarkdownContext: console: Console, options: ConsoleOptions, style: Style, - inline_code_theme: str, inline_code_lexer: str = None, + inline_code_theme: str = "monokai", ) -> None: self.console = console self.options = options @@ -428,8 +422,8 @@ class Markdown(JupyterMixin): justify: JustifyMethod = None, style: Union[str, Style] = "none", hyperlinks: bool = True, - inline_code_theme: str = None, inline_code_lexer: str = None, + inline_code_theme: str = None, ) -> None: self.markup = markup parser = Parser() @@ -450,8 +444,8 @@ class Markdown(JupyterMixin): console, options, style, - inline_code_theme=self.inline_code_theme, inline_code_lexer=self.inline_code_lexer, + inline_code_theme=self.inline_code_theme, ) nodes = self.parsed.walker() inlines = self.inlines From 025fe68e56ebeb2935b2e0ff31eff91293657484 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sun, 13 Sep 2020 15:14:50 +0100 Subject: [PATCH 08/13] docstring --- rich/markdown.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rich/markdown.py b/rich/markdown.py index 44782e19..8074356f 100644 --- a/rich/markdown.py +++ b/rich/markdown.py @@ -397,10 +397,10 @@ class Markdown(JupyterMixin): justify (JustifyMethod, optional): Justify value for paragraphs. Defaults to None. style (Union[str, Style], optional): Optional style to apply to markdown. hyperlinks (bool, optional): Enable hyperlinks. Defaults to ``True``. + inline_code_lexer: (str, optional): Lexer to use if inline code highlighting is + enabled. Defaults to "python". inline_code_theme: (Optional[str], optional): Pygments theme for inline code highlighting, or None for no highlighting. Defaults to None. - inline_code_lexter: (str, optional): Lexer to use if inline code highlighting is - enabled. Defaults to "python". """ elements: ClassVar[Dict[str, Type[MarkdownElement]]] = { From 7b2d9bee75c61bd8f030a94c2a2c5be8ae764360 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sun, 13 Sep 2020 22:30:19 +0100 Subject: [PATCH 09/13] simplify --- rich/text.py | 1 - 1 file changed, 1 deletion(-) diff --git a/rich/text.py b/rich/text.py index d8a5b139..602881bb 100644 --- a/rich/text.py +++ b/rich/text.py @@ -506,7 +506,6 @@ class Text(JupyterMixin): """ text = self.plain - style_map: Dict[int, Style] = {} null_style = Style() def get_style(style: Union[str, Style]) -> Style: From 142c64ea629bff3ae0b966e3617d90b34aa80aa5 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sun, 13 Sep 2020 22:42:58 +0100 Subject: [PATCH 10/13] simplify and optimize --- rich/text.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/rich/text.py b/rich/text.py index 602881bb..44181111 100644 --- a/rich/text.py +++ b/rich/text.py @@ -1,3 +1,4 @@ +from functools import partial import re from operator import itemgetter from typing import ( @@ -363,7 +364,7 @@ class Text(JupyterMixin): offset = len(self) + offset get_style = console.get_style - style = console.get_style(self.style).copy() + style = get_style(self.style).copy() for start, end, span_style in self._spans: if offset >= start and offset < end: style += get_style(span_style) @@ -507,12 +508,8 @@ class Text(JupyterMixin): text = self.plain null_style = Style() - - def get_style(style: Union[str, Style]) -> Style: - return console.get_style(style, default=null_style) - enumerated_spans = list(enumerate(self._spans, 1)) - + get_style = partial(console.get_style, default=null_style) style_map = {index: get_style(span.style) for index, span in enumerated_spans} style_map[0] = get_style(self.style) @@ -529,7 +526,6 @@ class Text(JupyterMixin): stack_pop = stack.remove _Segment = Segment - style_cache: Dict[Tuple[int, ...], Style] = {} combine = Style.combine From f0868ccebef331eca60ab1ebdaa2fefe6273b1e0 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sun, 13 Sep 2020 22:46:18 +0100 Subject: [PATCH 11/13] optimize --- rich/text.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rich/text.py b/rich/text.py index 44181111..b64908dc 100644 --- a/rich/text.py +++ b/rich/text.py @@ -527,12 +527,13 @@ class Text(JupyterMixin): _Segment = Segment style_cache: Dict[Tuple[int, ...], Style] = {} + style_cache_get = style_cache.get combine = Style.combine def get_current_style() -> Style: """Construct current style from stack.""" style_ids = tuple(sorted(stack)) - cached_style = style_cache.get(style_ids) + cached_style = style_cache_get(style_ids) if cached_style is not None: return cached_style current_style = combine(style_map[_style_id] for _style_id in style_ids) From d8665942d07de5807edd89e8bfbeb4c1b93b159e Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Mon, 14 Sep 2020 11:30:10 +0100 Subject: [PATCH 12/13] simplify highlight method --- rich/syntax.py | 10 ++++------ rich/text.py | 1 - 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/rich/syntax.py b/rich/syntax.py index fe0a03f5..d060ab30 100644 --- a/rich/syntax.py +++ b/rich/syntax.py @@ -173,18 +173,16 @@ class Syntax(JupyterMixin): style = style + Style(bgcolor=self._pygments_style_class.background_color) return style - def highlight(self, code: str = None) -> Text: + def highlight(self, code: str) -> Text: """Highlight code and return a Text instance. Args: - code (Optional[str], optional). Highlight code if a str is given, or - None to use self.code. + code (str). Code to highlight. Returns: Text: A text instance containing syntax highlight. """ - if code is None: - code = self.code + default_style = self._get_default_style() try: lexer = get_lexer_by_name(self.lexer_name) @@ -255,7 +253,7 @@ class Syntax(JupyterMixin): code = self.code if self.dedent: code = textwrap.dedent(code) - text = self.highlight() + text = self.highlight(self.code) if text.plain.endswith("\n"): text.plain = text.plain[:-1] if not self.line_numbers: diff --git a/rich/text.py b/rich/text.py index b64908dc..bd3c7ce5 100644 --- a/rich/text.py +++ b/rich/text.py @@ -875,7 +875,6 @@ class Text(JupyterMixin): (offset, offset + len(line)) for offset, line in zip(divide_offsets, new_lines) ] - for span in self._spans: line_index = (span.start // average_line_length) % len(line_ranges) From a27a3ee20bff6c6aa0642f31fb736e72d16abbce Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Mon, 14 Sep 2020 17:44:18 +0100 Subject: [PATCH 13/13] bump --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index dda3ad1c..ec97f67e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ name = "rich" homepage = "https://github.com/willmcgugan/rich" documentation = "https://rich.readthedocs.io/en/latest/" -version = "6.1.2" +version = "6.2.0" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" authors = ["Will McGugan "] license = "MIT"