Add custom markdown syntax for coloring text

<color>(text to color) where color can be a SVG color name,
3 characters hex or 6 characters hex code.

Can be used to send colored message from the composer. Other clients
that follow the matrix spec should be able to display them (e.g. riot,
even if it can't send them)
This commit is contained in:
miruka 2019-12-20 14:44:31 -04:00
parent be61a34ec0
commit b0d77d74a9
2 changed files with 41 additions and 2 deletions

View File

@ -92,7 +92,6 @@
- Way to open context menus without a right mouse button - Way to open context menus without a right mouse button
- `smartVerticalFlick()` gradual acceleration - `smartVerticalFlick()` gradual acceleration
- Make banner buttons look better - Make banner buttons look better
- Way to color HTML from the composer
- Choose a better default easing type for animations - Choose a better default easing type for animations
- Make HListView scrollbars visible - Make HListView scrollbars visible

View File

@ -16,17 +16,41 @@ class MarkdownInlineGrammar(mistune.InlineGrammar):
Modifications: Modifications:
- Disable underscores for bold/italics (e.g. `__bold__`) - Disable underscores for bold/italics (e.g. `__bold__`)
- Add syntax for coloring text: `<color>(text)`,
e.g. `<red>(Lorem ipsum)` or `<#000040>(sit dolor amet...)`
""" """
escape = re.compile(r"^\\([\\`*{}\[\]()#+\-.!_<>~|])") # Add <
emphasis = re.compile(r"^\*((?:\*\*|[^\*])+?)\*(?!\*)") emphasis = re.compile(r"^\*((?:\*\*|[^\*])+?)\*(?!\*)")
double_emphasis = re.compile(r"^\*{2}([\s\S]+?)\*{2}(?!\*)") double_emphasis = re.compile(r"^\*{2}([\s\S]+?)\*{2}(?!\*)")
# test string: r"<b>(x) <r>(x) \<a>b>(x) <a\>b>(x) <b>(\(z) <c>(foo\)xyz)"
color = re.compile(
r"^<(.+?)>" # capture the color in `<color>`
r"\((.+?)" # capture text in `(text`
r"(?<!\\)(?:\\\\)*" # ignore the next `)` if it's \escaped
r"\)", # finish on a `)`
)
class MarkdownInlineLexer(mistune.InlineLexer): class MarkdownInlineLexer(mistune.InlineLexer):
"""Apply the changes from `MarkdownInlineGrammar` for Mistune.""" """Apply the changes from `MarkdownInlineGrammar` for Mistune."""
grammar_class = MarkdownInlineGrammar grammar_class = MarkdownInlineGrammar
default_rules = [
"escape", "color", "autolink", "url", # Add color
"footnote", "link", "reflink", "nolink",
"double_emphasis", "emphasis", "code",
"linebreak", "strikethrough", "text",
]
inline_html_rules = [
"escape", "color", "autolink", "url", "link", "reflink", # Add color
"nolink", "double_emphasis", "emphasis", "code",
"linebreak", "strikethrough", "text",
]
def output_double_emphasis(self, m): def output_double_emphasis(self, m):
return self.renderer.double_emphasis(self.output(m.group(1))) return self.renderer.double_emphasis(self.output(m.group(1)))
@ -36,6 +60,19 @@ class MarkdownInlineLexer(mistune.InlineLexer):
return self.renderer.emphasis(self.output(m.group(1))) return self.renderer.emphasis(self.output(m.group(1)))
def output_color(self, m):
color = m.group(1)
text = self.output(m.group(2))
return self.renderer.color(color, text)
class MarkdownRenderer(mistune.Renderer):
def color(self, color: str, text: str):
"""Render given text with a color using `<span data-mx-color=...>`."""
return f'<span data-mx-color="{color}">{text}</span>'
class HTMLProcessor: class HTMLProcessor:
"""Provide HTML filtering and conversion from Markdown. """Provide HTML filtering and conversion from Markdown.
@ -95,7 +132,10 @@ class HTMLProcessor:
# hard_wrap: convert all \n to <br> without required two spaces # hard_wrap: convert all \n to <br> without required two spaces
# escape: escape HTML characters in the input string, e.g. tags # escape: escape HTML characters in the input string, e.g. tags
self._markdown_to_html = mistune.Markdown( self._markdown_to_html = mistune.Markdown(
hard_wrap=True, escape=True, inline=MarkdownInlineLexer, hard_wrap=True,
escape=True,
inline=MarkdownInlineLexer,
renderer=MarkdownRenderer(),
) )
self._markdown_to_html.block.default_rules = [ self._markdown_to_html.block.default_rules = [