markdown tests

This commit is contained in:
Will McGugan 2020-04-28 14:38:35 +01:00
parent 9cba2027f4
commit 5bf2abc203
5 changed files with 102 additions and 25 deletions

View File

@ -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/), 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). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.8.13] - 2020-04-38
### Fixed
- Fixed incorrect markdown rendering for quotes and changed style
## [0.8.12] - 2020-04-21 ## [0.8.12] - 2020-04-21
### Fixed ### Fixed

View File

@ -101,14 +101,12 @@ class TextElement(MarkdownElement):
self.text = Text(justify="left") self.text = Text(justify="left")
def on_text(self, context: "MarkdownContext", text: str) -> None: def on_text(self, context: "MarkdownContext", text: str) -> None:
text = text.replace("---", "").replace("--", "").replace("...", "")
self.text.append(text, context.current_style) self.text.append(text, context.current_style)
def on_leave(self, context: "MarkdownContext") -> None: def on_leave(self, context: "MarkdownContext") -> None:
context.leave_style() context.leave_style()
def __console__(self, console: Console, options: ConsoleOptions) -> RenderResult:
yield self.text
class Paragraph(TextElement): class Paragraph(TextElement):
"""A Paragraph.""" """A Paragraph."""
@ -165,10 +163,9 @@ class CodeBlock(TextElement):
@classmethod @classmethod
def create(cls, markdown: "Markdown", node: Any) -> "CodeBlock": def create(cls, markdown: "Markdown", node: Any) -> "CodeBlock":
if node.info is None: node_info = node.info or ""
return cls("default", markdown.code_theme) lexer_name = node_info.partition(" ")[0]
lexer_name, _, _ = node.info.partition(" ") return cls(lexer_name or "default", markdown.code_theme)
return cls(lexer_name, markdown.code_theme)
def __init__(self, lexer_name: str, theme: str) -> None: def __init__(self, lexer_name: str, theme: str) -> None:
self.lexer_name = lexer_name self.lexer_name = lexer_name
@ -195,20 +192,14 @@ class BlockQuote(TextElement):
return False return False
def __console__(self, console: Console, options: ConsoleOptions) -> RenderResult: def __console__(self, console: Console, options: ConsoleOptions) -> RenderResult:
# Render surrounded by quotes.
render_options = options.update(width=options.max_width - 4) render_options = options.update(width=options.max_width - 4)
lines = console.render_lines(self.elements, render_options, style=self.style) lines = console.render_lines(self.elements, render_options, style=self.style)
style = self.style style = self.style
new_line = Segment("\n") new_line = Segment("\n")
left_quote = Segment("", style) padding = Segment("", style)
right_quote = Segment("", style) for line in lines:
padding = Segment(" ", style) yield padding
for first, last, line in loop_first_last(lines):
yield left_quote if first else padding
yield from line yield from line
yield right_quote if last else padding
yield new_line yield new_line
@ -312,11 +303,6 @@ class MarkdownContext:
"""Current style which is the product of all styles on the stack.""" """Current style which is the product of all styles on the stack."""
return self.style_stack.current return self.style_stack.current
@property
def width(self) -> int:
"""The width of the console."""
return self.options.max_width
def on_text(self, text: str) -> None: def on_text(self, text: str) -> None:
"""Called when the parser visits text.""" """Called when the parser visits text."""
self.stack.top.on_text(self, text) self.stack.top.on_text(self, text)
@ -344,7 +330,7 @@ class Markdown:
"list": ListElement, "list": ListElement,
"item": ListItem, "item": ListItem,
} }
inlines = {"emph", "strong", "code", "link"} inlines = {"emph", "strong", "code", "link", "strike"}
def __init__( def __init__(
self, self,
@ -372,10 +358,13 @@ class Markdown:
# print(current, current.literal) # print(current, current.literal)
node_type = current.t node_type = current.t
if node_type in ("html_inline", "html_block", "text"): if node_type in ("html_inline", "html_block", "text"):
context.on_text(current.literal) context.on_text(current.literal.replace("\n", " "))
elif node_type == "softbreak": elif node_type == "linebreak":
if entering: if entering:
context.on_text("\n") context.on_text("\n")
elif node_type == "softbreak":
if entering:
context.on_text(" ")
elif node_type in inlines: elif node_type in inlines:
if current.is_container(): if current.is_container():
if entering: if entering:

File diff suppressed because one or more lines are too long

60
tests/_markdown.py Normal file
View File

@ -0,0 +1,60 @@
MARKDOWN = """Heading
=======
Sub-heading
-----------
### Heading
#### H4 Heading
##### H5 Heading
###### H6 Heading
Paragraphs are separated
by a blank line.
Two spaces at the end of a line
produces a line break.
Text attributes _italic_,
**bold**, `monospace`.
Horizontal rule:
---
Bullet list:
* apples
* oranges
* pears
Numbered list:
1. lather
2. rinse
3. repeat
An [example](http://example.com).
> Markdown uses email-style > characters for blockquoting.
>
> Lorem ipsum
```
a=1
```
```python
import this
```
```somelang
foobar
```
"""

22
tests/test_markdown.py Normal file
View File

@ -0,0 +1,22 @@
# coding=utf-8
from _markdown import MARKDOWN
from render import render
from rich.console import Console
from rich.markdown import Markdown
def test_markdown_render():
markdown = Markdown(MARKDOWN)
rendered_markdown = render(markdown)
expected = "╔══════════════════════════════════════════════════════════════════════════════════════════════════╗\n\x1b[1mHeading\x1b[0m ║\n╚══════════════════════════════════════════════════════════════════════════════════════════════════╝\n\n \x1b[1;4mSub-heading\x1b[0m \n\n \x1b[1mHeading\x1b[0m \n\n \x1b[1;2mH4 Heading\x1b[0m \n\n \x1b[4mH5 Heading\x1b[0m \n\n \x1b[3mH6 Heading\x1b[0m \n\nParagraphs are separated by a blank line. \n\nTwo spaces at the end of a line \nproduces a line break. \n\nText attributes \x1b[3mitalic\x1b[0m, \x1b[1mbold\x1b[0m, \x1b[38;5;15;40mmonospace\x1b[0m. \n\nHorizontal rule: \n\n\x1b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m\nBullet list: \n\n\x1b[1;33m • \x1b[0mapples \n\x1b[1;33m • \x1b[0moranges \n\x1b[1;33m • \x1b[0mpears \n\nNumbered list: \n\n\x1b[1;33m 1 \x1b[0mlather \n\x1b[1;33m 2 \x1b[0mrinse \n\x1b[1;33m 3 \x1b[0mrepeat \n\nAn \x1b[1mexample\x1b[0m (\x1b[4mhttp://example.com\x1b[0m) . \n\n\x1b[35m▌ \x1b[0m\x1b[35mMarkdown uses email-style > characters for blockquoting.\x1b[0m\x1b[35m \x1b[0m\n\x1b[35m▌ \x1b[0m\x1b[35mLorem ipsum\x1b[0m\x1b[35m \x1b[0m\n\n\x1b[38;2;248;248;242;48;2;39;40;34ma=1 \x1b[0m\n\n\x1b[38;2;249;38;114;48;2;39;40;34mimport\x1b[0m\x1b[38;2;248;248;242;48;2;39;40;34m \x1b[0m\x1b[38;2;248;248;242;48;2;39;40;34mthis\x1b[0m\x1b[38;2;248;248;242;48;2;39;40;34m \x1b[0m\n\n\x1b[38;2;248;248;242;48;2;39;40;34mfoobar \x1b[0m\n"
assert rendered_markdown == expected
if __name__ == "__main__":
markdown = Markdown(MARKDOWN)
rendered = render(markdown)
print(rendered)
print(repr(rendered))