Skip to content

Commit 4020d5a

Browse files
authored
Merge pull request #124 from willmcgugan/path-highlight
Improve path highlight
2 parents 5f55063 + b584dd6 commit 4020d5a

File tree

7 files changed

+87
-20
lines changed

7 files changed

+87
-20
lines changed

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [2.3.0] - 2020-06-26
9+
10+
### Fixed
11+
12+
- Fixed highlighting of paths / filenames
13+
- Corrected docs for RichHandler which erroneously said default console writes to stderr
14+
15+
### Changed
16+
17+
- Allowed `style` parameter for `highlight_regex` to be a callable that returns a style
18+
19+
### Added
20+
21+
- Added optional highlighter parameter to RichHandler
22+
823
## [2.2.6] - 2020-06-24
924

1025
### Changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "rich"
33
homepage = "https://github.com/willmcgugan/rich"
44
documentation = "https://rich.readthedocs.io/en/latest/"
5-
version = "2.2.6"
5+
version = "2.3.0"
66
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
77
authors = ["Will McGugan <willmcgugan@gmail.com>"]
88
license = "MIT"

rich/default_styles.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
"rule.line": Style(color="bright_green"),
6666
"rule.text": Style(),
6767
"repr.path": Style(color="magenta"),
68-
"repr.filename": Style(color="bright_magenta", bold=True),
68+
"repr.filename": Style(color="bright_magenta"),
6969
"table.header": Style(bold=True),
7070
"table.footer": Style(bold=True),
7171
"table.cell": Style(),

rich/highlighter.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,11 @@ class ReprHighlighter(RegexHighlighter):
7373
highlights = [
7474
r"(?P<brace>[\{\[\(\)\]\}])",
7575
r"(?P<tag_start>\<)(?P<tag_name>\w*)(?P<tag_contents>.*?)(?P<tag_end>\>)",
76-
r"(?P<attrib_name>\w+?)=(?P<attrib_value>\"?\w+\"?)",
76+
r"(?P<attrib_name>\w+?)=(?P<attrib_value>\"?\S+\"?)",
7777
r"(?P<bool_true>True)|(?P<bool_false>False)|(?P<none>None)",
7878
r"(?P<number>(?<!\w)\-?[0-9]+\.?[0-9]*\b)",
7979
r"(?P<number>0x[0-9a-f]*)",
80-
r"(?P<path>(\/\w+)+\/)",
81-
r"(?P<filename>\/\w*\.\w{3,4})\s",
80+
r"(?P<path>\B(\/[\w\.\-\_\+]+)*\/)(?P<filename>[\w\.\-\_\+]*)?",
8281
r"(?<!\\)(?P<str>b?\'\'\'.*?(?<!\\)\'\'\'|b?\'.*?(?<!\\)\'|b?\"\"\".*?(?<!\\)\"\"\"|b?\".*?(?<!\\)\")",
8382
r"(?P<url>https?:\/\/[0-9a-zA-Z\$\-\_\+\!`\(\)\,\.\?\/\;\:\&\=\%]*)",
8483
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})",
@@ -91,3 +90,18 @@ class ReprHighlighter(RegexHighlighter):
9190
console = Console()
9291
console.print("[bold green]hello world![/bold green]")
9392
console.print("'[bold green]hello world![/bold green]'")
93+
94+
console.print(" /foo")
95+
console.print("/foo/")
96+
console.print("/foo/bar")
97+
console.print("foo/bar/baz")
98+
99+
console.print("/foo/bar/baz?foo=bar+egg&egg=baz")
100+
console.print("/foo/bar/baz/")
101+
console.print("/foo/bar/baz/egg")
102+
console.print("/foo/bar/baz/egg.py")
103+
console.print("/foo/bar/baz/egg.py word")
104+
console.print(" /foo/bar/baz/egg.py word")
105+
console.print("foo /foo/bar/baz/egg.py word")
106+
console.print("foo /foo/bar/ba._++z/egg+.py word")
107+
console.print("https://example.org?foo=bar")

rich/logging.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ class RichHandler(Handler):
1818
Args:
1919
level (int, optional): Log level. Defaults to logging.NOTSET.
2020
console (:class:`~rich.console.Console`, optional): Optional console instance to write logs.
21-
Default will create a new console writing to stderr.
22-
show_path (bool, optional): Show the path to the original logging message. Defaults to True.
21+
Default will use a global console instance writing to stdout.
22+
show_path (bool, optional): Show the path to the original log call. Defaults to True.
2323
enable_link_path (bool, optional): Enable terminal link of path column to file. Defaults to True.
24+
highlighter (Highlighter, optional): Highlighter to style log messages, or None to use ReprHighlighter. Defaults to None.
2425
2526
"""
2627

@@ -43,10 +44,11 @@ def __init__(
4344
*,
4445
show_path: bool = True,
4546
enable_link_path: bool = True,
47+
highlighter: Highlighter = None,
4648
) -> None:
4749
super().__init__(level=level)
4850
self.console = console or get_console()
49-
self.highlighter = self.HIGHLIGHTER_CLASS()
51+
self.highlighter = highlighter or self.HIGHLIGHTER_CLASS()
5052
self._log_render = LogRender(show_level=True, show_path=show_path)
5153
self.enable_link_path = enable_link_path
5254

rich/text.py

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from typing import (
44
TYPE_CHECKING,
55
Any,
6+
Callable,
67
Dict,
78
Iterable,
89
List,
@@ -40,6 +41,8 @@
4041

4142
TextType = Union[str, "Text"]
4243

44+
GetStyleCallable = Callable[[str], Optional[StyleType]]
45+
4346

4447
class Span(NamedTuple):
4548
"""A marked up region in some text."""
@@ -335,32 +338,37 @@ def get_style_at_offset(self, console: "Console", offset: int) -> Style:
335338
def highlight_regex(
336339
self,
337340
re_highlight: str,
338-
style: Union[str, Style] = None,
341+
style: Union[GetStyleCallable, StyleType] = None,
339342
*,
340343
style_prefix: str = "",
341344
) -> int:
342-
"""Highlight text with a regular expression, where group names are
345+
"""Highlight text with a regular expression, where group names are
343346
translated to styles.
344-
347+
345348
Args:
346349
re_highlight (str): A regular expression.
347-
style (Union[str, Style]): Optional style to apply to whole match.
348-
style_prefix (str, optional): Optional prefix to add to style group names.
349-
350+
style (Union[GetStyleCallable, StyleType]): Optional style to apply to whole match, or a callable
351+
which accepts the matched text and returns a style. Defaults to None.
352+
style_prefix (str, optional): Optional prefix to add to style group names.
353+
350354
Returns:
351355
int: Number of regex matches
352356
"""
353357
count = 0
354358
append_span = self._spans.append
355359
_Span = Span
356-
for match in re.finditer(re_highlight, self.plain):
357-
_span = match.span
360+
plain = self.plain
361+
for match in re.finditer(re_highlight, plain):
362+
get_span = match.span
358363
if style:
359-
start, end = _span()
360-
append_span(_Span(start, end, style))
364+
start, end = get_span()
365+
match_style = style(plain[start:end]) if callable(style) else style
366+
if match_style is not None:
367+
append_span(_Span(start, end, match_style))
368+
361369
count += 1
362-
for name, _ in match.groupdict().items():
363-
start, end = _span(name)
370+
for name in match.groupdict().keys():
371+
start, end = get_span(name)
364372
if start != -1:
365373
append_span(_Span(start, end, f"{style_prefix}{name}"))
366374
return count
@@ -852,3 +860,11 @@ def fit(self, width: int) -> Lines:
852860
console = Console()
853861
t = Text("foo bar", justify="left")
854862
print(repr(t.wrap(console, 4)))
863+
864+
test = Text("Vulnerability CVE-2018-6543 detected")
865+
866+
def get_style(text: str) -> str:
867+
return f"bold link https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword={text}"
868+
869+
test.highlight_regex(r"CVE-\d{4}-\d+", get_style)
870+
console.print(test)

tests/test_text.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,26 @@ def test_highlight_regex():
146146
]
147147

148148

149+
def test_highlight_regex_callable():
150+
test = Text("Vulnerability CVE-2018-6543 detected")
151+
re_cve = r"CVE-\d{4}-\d+"
152+
153+
def get_style(text: str) -> Style:
154+
return Style.parse(
155+
f"bold yellow link https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword={text}"
156+
)
157+
158+
count = test.highlight_regex(re_cve, get_style)
159+
assert count == 1
160+
assert len(test._spans) == 1
161+
assert test._spans[0].start == 14
162+
assert test._spans[0].end == 27
163+
assert (
164+
test._spans[0].style.link
165+
== "https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=CVE-2018-6543"
166+
)
167+
168+
149169
def test_highlight_words():
150170
test = Text("Do NOT! touch anything!")
151171
words = ["NOT", "!"]

0 commit comments

Comments
 (0)