diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-01-06 01:32:59 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-01-06 01:32:59 +0100 |
| commit | 7b4d4d6002a9c3da8fafd912f3c7b2da617f19c0 (patch) | |
| tree | e491f5fcf33c1032c63746003ac7bef6c3c5478f /src/syntax/node.rs | |
| parent | 2e77b1c836220766398e379ae0157736fb448874 (diff) | |
Pretty printing 🦋
- Syntax tree and value pretty printing
- Better value evaluation (top-level strings and content are evaluated plainly, everything else is pretty printed)
Diffstat (limited to 'src/syntax/node.rs')
| -rw-r--r-- | src/syntax/node.rs | 100 |
1 files changed, 99 insertions, 1 deletions
diff --git a/src/syntax/node.rs b/src/syntax/node.rs index d64d4fed..91fa72d7 100644 --- a/src/syntax/node.rs +++ b/src/syntax/node.rs @@ -27,15 +27,62 @@ pub enum Node { Expr(Expr), } +impl Pretty for Node { + fn pretty(&self, p: &mut Printer) { + match self { + Self::Text(text) => p.push_str(&text), + Self::Space => p.push_str(" "), + Self::Linebreak => p.push_str(r"\"), + Self::Parbreak => p.push_str("\n\n"), + Self::Strong => p.push_str("*"), + Self::Emph => p.push_str("_"), + Self::Heading(heading) => heading.pretty(p), + Self::Raw(raw) => raw.pretty(p), + Self::Expr(expr) => pretty_expr_node(expr, p), + } + } +} + +/// Pretty print an expression in a node context. +pub fn pretty_expr_node(expr: &Expr, p: &mut Printer) { + match expr { + // Prefer bracket calls over expression blocks with just a single paren + // call. + // + // Example: Transforms "{v()}" => "[v]". + Expr::Call(call) => pretty_bracket_call(call, p, false), + + // Remove unncessary nesting of content and expression blocks. + // + // Example: Transforms "{{Hi}}" => "Hi". + Expr::Content(content) => content.pretty(p), + + _ => { + p.push_str("{"); + expr.pretty(p); + p.push_str("}"); + } + } +} + /// A section heading: `# Introduction`. #[derive(Debug, Clone, PartialEq)] pub struct NodeHeading { - /// The section depth (numer of hashtags minus 1). + /// The section depth (numer of hashtags minus 1, capped at 5). pub level: Spanned<u8>, /// The contents of the heading. pub contents: Tree, } +impl Pretty for NodeHeading { + fn pretty(&self, p: &mut Printer) { + for _ in 0 ..= self.level.v { + p.push_str("#"); + } + self.contents.pretty(p); + } +} + /// A raw block with optional syntax highlighting: `` `raw` ``. /// /// Raw blocks start with an arbitrary number of backticks and end with the same @@ -114,3 +161,54 @@ pub struct NodeRaw { /// are inline-level when they contain no newlines. pub inline: bool, } + +impl Pretty for NodeRaw { + fn pretty(&self, p: &mut Printer) { + p.push_str("`"); + if let Some(lang) = &self.lang { + p.push_str(&lang); + p.push_str(" "); + } + // TODO: Technically, we should handle backticks in the lines + // by wrapping with more backticks and possibly adding space + // before the first or after the last line. + p.join(&self.lines, "\n", |line, p| p.push_str(line)); + p.push_str("`"); + } +} + +#[cfg(test)] +mod tests { + use super::super::tests::test_pretty; + + #[test] + fn test_pretty_print_removes_nesting() { + // Even levels of nesting do not matter. + test_pretty("{{Hi}}", "Hi"); + test_pretty("{{{{Hi}}}}", "Hi"); + } + + #[test] + fn test_pretty_print_prefers_bracket_calls() { + // All reduces to a simple bracket call. + test_pretty("{v()}", "[v]"); + test_pretty("[v]", "[v]"); + test_pretty("{[v]}", "[v]"); + test_pretty("{{[v]}}", "[v]"); + } + + #[test] + fn test_pretty_print_nodes() { + // Basic text and markup. + test_pretty(r"*Hi_\", r"*Hi_\"); + + // Whitespace. + test_pretty(" ", " "); + test_pretty("\n\n\n", "\n\n"); + + // Heading and raw. + test_pretty("# Ok", "# Ok"); + test_pretty("``\none\ntwo\n``", "`one\ntwo`"); + test_pretty("`lang one\ntwo`", "`lang one\ntwo`"); + } +} |
