Skip to content

Commit

Permalink
feat: better handling for content block
Browse files Browse the repository at this point in the history
  • Loading branch information
Enter-tainer committed Mar 24, 2024
1 parent 0d96c96 commit 2a7d9d4
Show file tree
Hide file tree
Showing 42 changed files with 661 additions and 388 deletions.
118 changes: 118 additions & 0 deletions src/pretty/markup.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
use std::collections::VecDeque;

use pretty::BoxDoc;
use typst_syntax::ast::*;
use typst_syntax::{ast, SyntaxNode};

use crate::pretty::trivia;
use crate::PrettyPrinter;

impl PrettyPrinter {
pub fn convert_markup<'a>(&'a self, root: Markup<'a>) -> BoxDoc<'a, ()> {
let mut doc: BoxDoc<()> = BoxDoc::nil();
#[derive(Debug, Default)]
struct Line<'a> {
has_text: bool,
nodes: VecDeque<&'a SyntaxNode>,
}
// break markup into lines, split by stmt, parbreak, newline, multiline raw, equation
// if a line contains text, it will be skipped by the formatter to keep the original format
let mut lines = {

Check warning on line 20 in src/pretty/markup.rs

View check run for this annotation

Codecov / codecov/patch

src/pretty/markup.rs#L20

Added line #L20 was not covered by tests
let mut lines: VecDeque<Line> = VecDeque::new();
let mut current_line = Line {
has_text: false,
nodes: VecDeque::new(),
};
for node in root.to_untyped().children() {
let mut break_line = false;
if let Some(space) = node.cast::<Space>() {
if space.to_untyped().text().contains('\n') {
break_line = true;
}
} else if let Some(pb) = node.cast::<Parbreak>() {
if pb.to_untyped().text().contains('\n') {
break_line = true;
}
} else if node.kind().is_stmt() {
break_line = true;
} else if let Some(expr) = node.cast::<Expr>() {
match expr {
ast::Expr::Text(_) => current_line.has_text = true,
ast::Expr::Raw(r) => {
if r.block() {
break_line = true;
} else {
current_line.has_text = true;
}
}
ast::Expr::Strong(_) | ast::Expr::Emph(_) => current_line.has_text = true,
ast::Expr::Code(_) => break_line = true,
ast::Expr::Equation(e) if e.block() => break_line = true,
_ => (),

Check warning on line 51 in src/pretty/markup.rs

View check run for this annotation

Codecov / codecov/patch

src/pretty/markup.rs#L51

Added line #L51 was not covered by tests
}
}
current_line.nodes.push_back(node);
if break_line {
lines.push_back(current_line);
current_line = Line::default();
}
}
if !current_line.nodes.is_empty() {
lines.push_back(current_line);
}
lines
};

// remove prefix and postfix spaces
while let Some(Line { has_text: _, nodes }) = lines.front() {
if nodes.len() == 1 {
if let Some(_space) = nodes[0].cast::<Space>() {
lines.pop_front();
continue;

Check warning on line 71 in src/pretty/markup.rs

View check run for this annotation

Codecov / codecov/patch

src/pretty/markup.rs#L71

Added line #L71 was not covered by tests
}
}
break;

Check warning on line 74 in src/pretty/markup.rs

View check run for this annotation

Codecov / codecov/patch

src/pretty/markup.rs#L74

Added line #L74 was not covered by tests
}
while let Some(Line { has_text: _, nodes }) = lines.back() {
if nodes.len() == 1 {
if let Some(_space) = nodes[0].cast::<Space>() {
lines.pop_back();
continue;

Check warning on line 80 in src/pretty/markup.rs

View check run for this annotation

Codecov / codecov/patch

src/pretty/markup.rs#L80

Added line #L80 was not covered by tests
}
}
break;

Check warning on line 83 in src/pretty/markup.rs

View check run for this annotation

Codecov / codecov/patch

src/pretty/markup.rs#L83

Added line #L83 was not covered by tests
}
if let Some(Line { has_text: _, nodes }) = lines.front_mut() {
if let Some(_space) = nodes.front().and_then(|node| node.cast::<Space>()) {
nodes.pop_front();
}
}
if let Some(Line { has_text: _, nodes }) = lines.back_mut() {
if let Some(_space) = nodes.back().and_then(|node| node.cast::<Space>()) {
nodes.pop_back();
}
}

for Line { has_text, nodes } in lines.into_iter() {
for node in nodes {
if let Some(space) = node.cast::<Space>() {
doc = doc.append(self.convert_space(space));
continue;

Check warning on line 100 in src/pretty/markup.rs

View check run for this annotation

Codecov / codecov/patch

src/pretty/markup.rs#L100

Added line #L100 was not covered by tests
}
if let Some(pb) = node.cast::<Parbreak>() {
doc = doc.append(self.convert_parbreak(pb));
continue;

Check warning on line 104 in src/pretty/markup.rs

View check run for this annotation

Codecov / codecov/patch

src/pretty/markup.rs#L104

Added line #L104 was not covered by tests
}
if has_text {
doc = doc.append(self.format_disabled(node));
} else if let Some(expr) = node.cast::<Expr>() {
let expr_doc = self.convert_expr(expr);
doc = doc.append(expr_doc);
} else {
doc = doc.append(trivia(node));
}
}
}
doc
}
}
87 changes: 8 additions & 79 deletions src/pretty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use typst_syntax::{ast::*, SyntaxKind};

use crate::util::{self, pretty_items};

pub mod markup;

#[derive(Debug, Default)]
pub struct PrettyPrinter {
disabled_nodes: HashSet<SyntaxNode>,
Expand All @@ -20,83 +22,6 @@ impl PrettyPrinter {
}

impl PrettyPrinter {
pub fn convert_markup<'a>(&'a self, root: Markup<'a>) -> BoxDoc<'a, ()> {
let mut doc: BoxDoc<()> = BoxDoc::nil();
#[derive(Debug, Default)]
struct Line<'a> {
has_text: bool,
nodes: Vec<&'a SyntaxNode>,
}
// break markup into lines, split by stmt, parbreak, newline, multiline raw, equation
// if a line contains text, it will be skipped by the formatter to keep the original format
let lines = {
let mut lines: Vec<Line> = vec![];
let mut current_line = Line {
has_text: false,
nodes: vec![],
};
for node in root.to_untyped().children() {
let mut break_line = false;
if let Some(space) = node.cast::<Space>() {
if space.to_untyped().text().contains('\n') {
break_line = true;
}
} else if let Some(pb) = node.cast::<Parbreak>() {
if pb.to_untyped().text().contains('\n') {
break_line = true;
}
} else if node.kind().is_stmt() {
break_line = true;
} else if let Some(expr) = node.cast::<Expr>() {
match expr {
ast::Expr::Text(_) => current_line.has_text = true,
ast::Expr::Raw(r) => {
if r.block() {
break_line = true;
} else {
current_line.has_text = true;
}
}
ast::Expr::Strong(_) | ast::Expr::Emph(_) => current_line.has_text = true,
ast::Expr::Code(_) => break_line = true,
ast::Expr::Equation(e) if e.block() => break_line = true,
_ => (),
}
}
current_line.nodes.push(node);
if break_line {
lines.push(current_line);
current_line = Line::default();
}
}
if !current_line.nodes.is_empty() {
lines.push(current_line);
}
lines
};
for Line { has_text, nodes } in lines {
for node in nodes {
if let Some(space) = node.cast::<Space>() {
doc = doc.append(self.convert_space(space));
continue;
}
if let Some(pb) = node.cast::<Parbreak>() {
doc = doc.append(self.convert_parbreak(pb));
continue;
}
if has_text {
doc = doc.append(self.format_disabled(node));
} else if let Some(expr) = node.cast::<Expr>() {
let expr_doc = self.convert_expr(expr);
doc = doc.append(expr_doc);
} else {
doc = doc.append(trivia(node));
}
}
}
doc
}

fn check_disabled<'a>(&'a self, node: &'a SyntaxNode) -> Option<BoxDoc<'a, ()>> {
if self.disabled_nodes.contains(node) {
Some(self.format_disabled(node))
Expand Down Expand Up @@ -418,7 +343,11 @@ impl PrettyPrinter {
}

fn convert_content_block<'a>(&'a self, content_block: ContentBlock<'a>) -> BoxDoc<'a, ()> {
let content = self.convert_markup(content_block.body()).group().nest(2);
let content = BoxDoc::line_()
.append(self.convert_markup(content_block.body()).group())
.group()
.nest(2)
.append(BoxDoc::line_());
let doc = BoxDoc::text("[").append(content).append(BoxDoc::text("]"));
doc
}
Expand Down Expand Up @@ -1113,7 +1042,7 @@ pub fn to_doc(s: Cow<'_, str>, strip_prefix: bool) -> BoxDoc<'_, ()> {
}
};
// String::lines() doesn't include the trailing newline
let has_trailing_newline = s.ends_with('\n');
let has_trailing_newline = s.ends_with('\n') || s.ends_with('\r');
let res = BoxDoc::intersperse(
s.lines().map(|s| BoxDoc::text(get_line(s))),
BoxDoc::hardline(),
Expand Down
5 changes: 5 additions & 0 deletions tests/assets/unit/markup/content-space.typ
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#{
show heading.where(level: 1): it => box(width: 100%)[
#v(0.5em)
]
}
10 changes: 10 additions & 0 deletions tests/assets/unit/windows.typ
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#align(center, table(
columns: 2,
column-gutter: 1em,
[
$ f_n = cases(
a &"if" n = 0,
r dot f_(n - 1) &"else"
) $
],
))
3 changes: 2 additions & 1 deletion tests/snapshots/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ input_file: tests/assets/book.typ
repository-edit: "https://github.com/Myriad-Dreamin/typst-book/edit/main/github-pages/docs/{path}",
authors: ("Myriad-Dreamin", "7mile"),
language: "en",
summary: [ // begin of summary
summary: [
// begin of summary
#prefix-chapter("introduction.typ")[Introduction]
= User Guide
- #chapter("guide/installation.typ", section: "1")[Installation]
Expand Down
51 changes: 23 additions & 28 deletions tests/snapshots/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ input_file: tests/assets/book.typ
repository-edit: "https://github.com/Myriad-Dreamin/typst-book/edit/main/github-pages/docs/{path}",
authors: ("Myriad-Dreamin", "7mile"),
language: "en",
summary: [ // begin of summary
#prefix-chapter(
"introduction.typ",
)[Introduction]
summary: [
// begin of summary
#prefix-chapter("introduction.typ")[
Introduction
]
= User Guide
- #chapter(
"guide/installation.typ",
Expand All @@ -31,10 +32,9 @@ input_file: tests/assets/book.typ
"guide/faq.typ",
section: "3",
)[Frequently Asked Questions]
- #chapter(
none,
section: "4",
)[Further reading]
- #chapter(none, section: "4")[
Further reading
]
= Reference Guide
- #chapter(
"cli/main.typ",
Expand Down Expand Up @@ -87,26 +87,21 @@ input_file: tests/assets/book.typ
"format/theme.typ",
section: "6.2",
)[Theme]
- #chapter(
none,
section: "6.3",
)[Typst Support]
- #chapter(
none,
section: "7",
)[For developers]
- #chapter(
none,
section: "7.1",
)[Typst-side APIs]
- #chapter(
none,
section: "7.2",
)[typst-book CLI Internals]
- #chapter(
none,
section: "7.3",
)[Alternative Backends]
- #chapter(none, section: "6.3")[
Typst Support
]
- #chapter(none, section: "7")[
For developers
]
- #chapter(none, section: "7.1")[
Typst-side APIs
]
- #chapter(none, section: "7.2")[
typst-book CLI Internals
]
- #chapter(none, section: "7.3")[
Alternative Backends
]
// end of summary
],
)
Expand Down
3 changes: 2 additions & 1 deletion tests/snapshots/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ input_file: tests/assets/book.typ
repository-edit: "https://github.com/Myriad-Dreamin/typst-book/edit/main/github-pages/docs/{path}",
authors: ("Myriad-Dreamin", "7mile"),
language: "en",
summary: [ // begin of summary
summary: [
// begin of summary
#prefix-chapter("introduction.typ")[Introduction]
= User Guide
- #chapter("guide/installation.typ", section: "1")[Installation]
Expand Down
Loading

0 comments on commit 2a7d9d4

Please sign in to comment.