Skip to content

Commit

Permalink
Support style mapping for highlights
Browse files Browse the repository at this point in the history
  • Loading branch information
mwilliamson committed Jun 13, 2024
1 parent 0d5b276 commit 4a779b8
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 1 deletion.
2 changes: 1 addition & 1 deletion NEWS
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 1.8.0

* Support parsing of run highlights.
* Add style mapping for highlights.

# 1.7.1

Expand Down
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,43 @@ small-caps
Note that this matches text that has had small caps explicitly applied to it.
It will not match any text that is small caps because of its paragraph or run style.

#### Highlight

Match explicitly highlighted text:

```
highlight
```

Note that this matches text that has had a highlight explicitly applied to it.
It will not match any text that is highlighted because of its paragraph or run style.

It's also possible to match specific colours.
For instance, to match yellow highlights:

```
highlight[color='yellow']
```

The set of colours typically used are:

* `black`
* `blue`
* `cyan`
* `green`
* `magenta`
* `red`
* `yellow`
* `white`
* `darkBlue`
* `darkCyan`
* `darkGreen`
* `darkMagenta`
* `darkRed`
* `darkYellow`
* `darkGray`
* `lightGray`

#### Ignoring document elements

Use `!` to ignore a document element.
Expand Down
14 changes: 14 additions & 0 deletions mammoth/conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ def children():
def visit_run(self, run, context):
nodes = lambda: self._visit_all(run.children, context)
paths = []
if run.highlight is not None:
style = self._find_style(Highlight(color=run.highlight), "highlight")
if style is not None:
paths.append(style.html_path)
if run.is_small_caps:
paths.append(self._find_style_for_run_property("small_caps"))
if run.is_all_caps:
Expand Down Expand Up @@ -354,9 +358,19 @@ def _html_id(self, suffix):
return "{0}{1}".format(self._id_prefix, suffix)


@cobble.data
class Highlight:
color = cobble.field()


def _document_matcher_matches(matcher, element, element_type):
if matcher.element_type in ["underline", "strikethrough", "all_caps", "small_caps", "bold", "italic", "comment_reference"]:
return matcher.element_type == element_type
elif matcher.element_type == "highlight":
return (
matcher.element_type == element_type and
(matcher.color is None or matcher.color == element.color)
)
elif matcher.element_type == "break":
return (
matcher.element_type == element_type and
Expand Down
7 changes: 7 additions & 0 deletions mammoth/document_matchers.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ class small_caps(object):
element_type = "small_caps"


def highlight(color=None):
return HighlightMatcher(color=color)


HighlightMatcher = collections.namedtuple("HighlightMatcher", ["color"])
HighlightMatcher.element_type = "highlight"

class comment_reference(object):
element_type = "comment_reference"

Expand Down
15 changes: 15 additions & 0 deletions mammoth/styles/parser/document_matcher_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ def parse_document_matcher(tokens):
elif tokens.try_skip(TokenType.IDENTIFIER, "small-caps"):
return document_matchers.small_caps

elif tokens.try_skip(TokenType.IDENTIFIER, "highlight"):
return _parse_highlight(tokens)

elif tokens.try_skip(TokenType.IDENTIFIER, "comment-reference"):
return document_matchers.comment_reference

Expand Down Expand Up @@ -98,6 +101,18 @@ def _parse_list_type(tokens):
raise LineParseError("Unrecognised list type: {0}".format(list_type))


def _parse_highlight(tokens):
if tokens.try_skip(TokenType.SYMBOL, "["):
tokens.skip(TokenType.IDENTIFIER, "color")
tokens.skip(TokenType.SYMBOL, "=")
color = parse_string(tokens)
tokens.skip(TokenType.SYMBOL, "]");
else:
color = None

return document_matchers.highlight(color=color)


def _parse_break(tokens):
tokens.skip(TokenType.SYMBOL, "[")
tokens.skip(TokenType.IDENTIFIER, "type")
Expand Down
31 changes: 31 additions & 0 deletions tests/conversion_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,37 @@ def test_small_caps_runs_can_be_mapped_using_style_mapping():
assert_equal("<span>Hello</span>", result.value)


def test_highlighted_runs_are_ignored_by_default():
result = convert_document_element_to_html(
documents.run(children=[documents.text("Hello")], highlight="yellow"),
)
assert_equal("Hello", result.value)


def test_highlighted_runs_can_be_configured_with_style_mapping_for_all_highlights():
result = convert_document_element_to_html(
documents.run(children=[documents.text("Hello")], highlight="yellow"),
style_map=[
_style_mapping("highlight => mark"),
],
)
assert_equal("<mark>Hello</mark>", result.value)


def test_highlighted_runs_can_be_configured_with_style_mapping_for_specific_highlight_color():
result = convert_document_element_to_html(
documents.paragraph(children=[
documents.run(children=[documents.text("Yellow")], highlight="yellow"),
documents.run(children=[documents.text("Red")], highlight="red"),
]),
style_map=[
_style_mapping("highlight[color='yellow'] => mark.yellow"),
_style_mapping("highlight => mark"),
]
)
assert_equal('<p><mark class="yellow">Yellow</mark><mark>Red</mark></p>', result.value)


def test_superscript_runs_are_wrapped_in_sup_tags():
result = convert_document_element_to_html(
documents.run(
Expand Down
12 changes: 12 additions & 0 deletions tests/styles/parser/document_matcher_parser_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,18 @@ def test_reads_small_caps():
read_document_matcher("small-caps")
)

def test_reads_highlight_without_color():
assert_equal(
document_matchers.highlight(),
read_document_matcher("highlight")
)

def test_reads_highlight_with_color():
assert_equal(
document_matchers.highlight(color="yellow"),
read_document_matcher("highlight[color='yellow']")
)

def test_reads_comment_reference():
assert_equal(
document_matchers.comment_reference,
Expand Down

0 comments on commit 4a779b8

Please sign in to comment.