Skip to content

Commit

Permalink
fixes, markdown, docs
Browse files Browse the repository at this point in the history
  • Loading branch information
willmcgugan committed May 8, 2020
1 parent 41cc14d commit 3617dc4
Show file tree
Hide file tree
Showing 25 changed files with 383 additions and 109 deletions.
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,29 @@ 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).

## [1.0.1] - 2020-05-08

### Changed

- Applied console markup after highlighting
- Documented highlighting
- Changed Markup parser to handle overlapping styles
- Relaxed dependency on colorama
- Allowed Theme to accept values as style definitions (str) as well as Style instances
- Added a panel to emphasize code in Markdown

### Added

- Added markup.escape
- Added `python -m rich.theme` command
- Added `python -m rich.markdown` command
- Added rendering of images in Readme (links only)

### Fixed

- Fixed Text.assemble not working with strings https://github.com/willmcgugan/rich/issues/57
- Fixed table when column widths must be compressed to fit

## [1.0.0] - 2020-05-03

### Changed
Expand Down
64 changes: 64 additions & 0 deletions docs/source/highlighting.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
Higlighting
===========

Rich can apply styles to patterns in text which you :meth:`~rich.console.Console.print` or :meth:`~rich.console.Console.log`. With the default settings, Rich will highlight things such as numbers, strings, collections, booleans, None, and a few more exotic patterns such as URLs and UUIDs.

You can disable highlighting either by setting ``highlight=False`` on :meth:`~rich.console.Console.print` or :meth:`~rich.console.Console.log`, or by setting ``highlight=False`` on the :class:`~rich.console.Console` constructor which disables it everywhere. If you disable highlighting on the constructor, you can still selectively enable highlighting with ``highlight=True`` on print/log.


Custom Highlighters
-------------------

If the default highlighting doesn't fit your needs, you can define a custom highlighter. The easiest way to do this is to extend the :class:`~rich.highlighter.RegexHighlighter` class which applies a style to any text matching a list of regular expressions.

Here's an example which highlights text that looks like an email address::


from rich.highlighter import RegexHighlighter


class EmailHighlighter(RegexHighlighter):
"""Apply style to anything that looks like an email."""

base_style = "example."
highlights = [r"(?P<email>[\w-]+@([\w-]+\.)+[\w-]+)"]


from rich.console import Console
from rich.style import Style
from rich.theme import Theme

theme = Theme({"example.email": "bold magenta"})
console = Console(highlighter=EmailHighlighter(), theme=theme)

console.print("Send funds to [email protected]")


The ``highlights`` class variable should contain a list of regular expressions. The group names of any matching expressions are prefixed with the ``base_style`` attribute and used as styles for matching text. In the example above, any email addresses will have the style "example.email" applied, which we've defined in a custom :ref:`Theme <themes>`.

Setting the highlighter on the Console will apply highlighting to all text you print (if enabled). You can also use a highlighter on a more granular level by using the instance as a callable and printing the result. For example, we could use the email highlighter class like this::


console = Console(theme=theme)
highlight_emails = EmailHighlighter()
console.print(highlight_emails("Send funds to [email protected]"))


While :class:`~rich.highlighter.RegexHighlighter` is quite powerful, you can also extend its base class :class:`~rich.highlighter.Highlighter` which you can use to implement any scheme for highlighting. It contains a single method :class:`~rich.highlighter.Highlighter.highlight` which is passed the :class:`~rich.text.Text` to highlight.

Here's an silly example that highlights every character with a different color::

from random import randint

from rich import print
from rich.highlighter import Highlighter


class RainbowHighlighter(Highlighter):
def highlight(self, text):
for index in range(len(text)):
text.stylize(index, index + 1, str(randint(16, 255)))


rainbow = RainbowHighlighter()
print(rainbow("I must not fear. Fear is the mind-killer."))
5 changes: 3 additions & 2 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ Welcome to Rich's documentation!
introduction.rst
console.rst
style.rst
text.rst
highlighting.rst
markup.rst
tables.rst
panel.rst
logging.rst
progress.rst
markdown.rst
syntax.rst
text.rst
syntax.rst
traceback.rst
protocol.rst

Expand Down
6 changes: 4 additions & 2 deletions docs/source/markup.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Console markup uses a syntax inspired by `bbcode <https://en.wikipedia.org/wiki/
Here's a simple example::

from rich import print
print("[bold red]alert![/bold red] *Something happened*")
print("[bold red]alert![/bold red] Something happened")

If you don't close a style, it will apply until the end of the string. Which is sometimes convenient if you want to style a single line. For example::

Expand All @@ -30,7 +30,9 @@ Escaping

Occasionally you may want to print something that Rich would interpret as markup. You can *escape* square brackets by doubling them up. Here's an example::

print("foo[[bar]]")
>>> from rich import print
>>> print("foo[[bar]]")
foo[bar]


Rendering Markup
Expand Down
19 changes: 16 additions & 3 deletions docs/source/style.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ Style attributes and colors may be used in combination with each other. For exam

console.print("Danger, Will Robinson!", style="blink bold red underline on white")

Styles may be negated by prefixing the attribute with the word "not". This can be used to turn off styles if they overlap. For example::

console.print("foo [not bold]bar[/not bold] baz", style="bold")

This will print "foo" and "baz" in bold, but "bar" will be in normal text.


Style Class
-----------
Expand All @@ -63,6 +69,9 @@ It is slightly quicker to construct a Style class like this, since a style defin
You can parse a style definition explicitly with the :meth:`~rich.style.Style.parse` method.


.. _themes:


Style Themes
------------

Expand All @@ -75,9 +84,9 @@ To use a style theme, construct a :class:`rich.theme.Theme` instance and pass it
from rich.console import Console
from rich.theme import Theme
custom_theme = Theme({
"info" : Style.parse("dim cyan"),
"warning": Style.parse("magenta"),
"danger": Style.parse("bold red")
"info" : "dim cyan",
"warning": "magenta",
"danger": "bold red"
})
console = Console(theme=custom_theme)
console.print("This is information", style="info")
Expand All @@ -95,3 +104,7 @@ If you prefer you can write your styles in an external config file rather than i
danger = bold red

You can read these files with the :meth:`~rich.theme.Theme.read` method.

To see the default theme, run the following command::

python -m rich.theme
2 changes: 2 additions & 0 deletions docs/source/syntax.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ To syntax highlight code, construct a :class:`~rich.syntax.Syntax` object and pr
console = Console()
syntax = Syntax.from_path("syntax.py", line_numbers=True)
console.print(syntax)

The Syntax constructor (and :meth:`~rich.syntax.Syntax.from_path`) accept a ``theme`` attribute which should be the name of a `Pygments theme <https://pygments.org/demo/>`_.
2 changes: 1 addition & 1 deletion docs/source/text.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Rich Text
=========

Rich has a :class:`~rich.text.Text` class for text that may be marked up with color and style attributes. You can consider this class to be like a mutable string with additional style information. The methods on the Text() instance are similar to a Python ``str`` but are designed to preserve the styles.
Rich has a :class:`~rich.text.Text` class which you can use to mark up strings with color and style attributes. You can consider this class to be like a mutable string with additional style information.

One way to add a style to Text is the :meth:`~rich.text.Text.stylize` method which applies a style to a start and end offset. Here is an example::

Expand Down
18 changes: 18 additions & 0 deletions examples/highlighter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from rich.highlighter import RegexHighlighter


class EmailHighlighter(RegexHighlighter):
"""Apply style to anything that looks like an email."""

base_style = "example."
highlights = [r"(?P<email>[\w-]+@([\w-]+\.)+[\w-]+)"]


from rich.console import Console
from rich.style import Style
from rich.theme import Theme

theme = Theme({"example.email": "bold magenta"})
console = Console(highlighter=EmailHighlighter(), theme=theme)

console.print("Send funds to [email protected]")
14 changes: 14 additions & 0 deletions examples/rainbow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from random import randint

from rich import print
from rich.highlighter import Highlighter


class RainbowHighlighter(Highlighter):
def highlight(self, text):
for index in range(len(text)):
text.stylize(index, index + 1, str(randint(16, 255)))


rainbow = RainbowHighlighter()
print(rainbow("I must not fear. Fear is the mind-killer."))
3 changes: 1 addition & 2 deletions examples/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

table = Table(title="Star Wars Movies")

table.add_column("Released", justify="right", style="cyan", no_wrap=True)
table.add_column("Released", style="cyan", no_wrap=True)
table.add_column("Title", style="magenta")
table.add_column("Box Office", justify="right", style="green")

Expand All @@ -20,4 +20,3 @@

console = Console()
console.print(table)

8 changes: 4 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
name = "rich"
homepage = "https://github.com/willmcgugan/rich"
documentation = "https://rich.readthedocs.io/en/latest/"
version = "1.0.0"
version = "1.0.1"
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
authors = ["Will McGugan <[email protected]>"]
license = "MIT"
readme = "README.md"
classifiers = [
"Development Status :: 3 - Alpha",
"Development Status :: 5 - Production/Stable",
"Environment :: Console",
"Intended Audience :: Developers",
"Operating System :: Microsoft :: Windows",
Expand All @@ -26,9 +26,9 @@ python = "^3.6"
pprintpp = "^0.4.0"
typing-extensions = "^3.7.4"
dataclasses = {version="^0.7", python = "~3.6"}
pygments = "^2.6.1"
pygments = "^2.6.0"
commonmark = "^0.9.0"
colorama = "^0.4.3"
colorama = "^0.4.0"


[tool.poetry.dev-dependencies]
Expand Down
25 changes: 15 additions & 10 deletions rich/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,7 @@ def render_str(
style: Union[str, Style] = "",
emoji: bool = None,
markup: bool = None,
highlighter: HighlighterType = None,
) -> "Text":
"""Convert a string to a Text instance.
Expand All @@ -552,23 +553,27 @@ def render_str(
style (Union[str, Style], optional): Style to apply to rendered text.
emoji (Optional[bool], optional): Enable emoji, or ``None`` to use Console default.
markup (Optional[bool], optional): Enable markup, or ``None`` to use Console default.
highlighter (HighlighterType, optional): Optional highlighter to apply.
Returns:
ConsoleRenderable: Renderable object.
"""
emoji_enabled = emoji or (emoji is None and self._emoji)
markup_enabled = markup or (markup is None and self._markup)

if emoji_enabled:
if markup_enabled:
return render_markup(text, style=style)
else:
text = _emoji_replace(text)
if markup_enabled:
rich_text = render_markup(text, style=style, emoji=emoji_enabled)
else:
if markup_enabled:
return render_markup(text, style=style, emoji=False)
rich_text = Text(
_emoji_replace(text) if emoji_enabled else text, style=style
)

if highlighter is not None:
highlight_text = highlighter(str(rich_text))
highlight_text.copy_styles(rich_text)
return highlight_text

return Text(text, style=style)
return rich_text

def get_style(
self, name: Union[str, Style], *, default: Union[Style, str] = None
Expand Down Expand Up @@ -638,8 +643,8 @@ def check_text() -> None:
renderable = rich_cast()
if isinstance(renderable, str):
append_text(
_highlighter(
self.render_str(renderable, emoji=emoji, markup=markup)
self.render_str(
renderable, emoji=emoji, markup=markup, highlighter=_highlighter
)
)
elif isinstance(renderable, Text):
Expand Down
2 changes: 1 addition & 1 deletion rich/default_styles.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@
"markdown.item.number": Style(color="yellow", bold=True),
"markdown.hr": Style(dim=True),
"markdown.h1.border": Style(),
"markdown.h1": Style(bold=True),
"markdown.h1": Style(bold=True,),
"markdown.h2": Style(bold=True, underline=True),
"markdown.h3": Style(bold=True),
"markdown.h4": Style(bold=True, dim=True),
Expand Down
8 changes: 8 additions & 0 deletions rich/highlighter.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,11 @@ class ReprHighlighter(RegexHighlighter):
r"(?P<url>https?:\/\/[0-9a-zA-Z\$\-\_\+\!`\(\)\,\.\?\/\;\:\&\=\%]*)",
r"(?P<uuid>[a-fA-F0-9]{8}\-[a-fA-F0-9]{4}\-[a-fA-F0-9]{4}\-[a-fA-F0-9]{4}\-[a-fA-F0-9]{12})",
]


if __name__ == "__main__": # pragma: no cover
from .console import Console

console = Console()
console.print("[bold green]hello world![/bold green]")
console.print("'[bold green]hello world![/bold green]'")
Loading

0 comments on commit 3617dc4

Please sign in to comment.