block: split parse_block function
This commit is contained in:
parent
a03d46dfaf
commit
a60e40e1f3
1 changed files with 236 additions and 243 deletions
293
src/block.rs
293
src/block.rs
|
@ -238,7 +238,17 @@ impl<'s> TreeParser<'s> {
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
Block::Atom(a) => self.tree.atom(a, span),
|
Block::Atom(a) => self.tree.atom(a, span),
|
||||||
Block::Leaf(l) => {
|
Block::Leaf(l) => self.parse_leaf(l, lines, span),
|
||||||
|
Block::Container(Table) => self.parse_table(lines, span),
|
||||||
|
Block::Container(c) => self.parse_container(c, lines, span, indent),
|
||||||
|
}
|
||||||
|
|
||||||
|
line_count
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_leaf(&mut self, l: Leaf, lines: &mut [Span], span: Span) {
|
||||||
self.tree.enter(Node::Leaf(l), span);
|
self.tree.enter(Node::Leaf(l), span);
|
||||||
|
|
||||||
if matches!(l, Leaf::CodeBlock) {
|
if matches!(l, Leaf::CodeBlock) {
|
||||||
|
@ -267,153 +277,8 @@ impl<'s> TreeParser<'s> {
|
||||||
lines.iter().for_each(|line| self.tree.inline(*line));
|
lines.iter().for_each(|line| self.tree.inline(*line));
|
||||||
self.tree.exit();
|
self.tree.exit();
|
||||||
}
|
}
|
||||||
Block::Container(Table) => {
|
|
||||||
self.alignments.clear();
|
fn parse_container(&mut self, c: Container, lines: &mut [Span], span: Span, indent: usize) {
|
||||||
self.tree.enter(Node::Container(Table), span);
|
|
||||||
let mut last_row_node = None;
|
|
||||||
let caption_line = lines
|
|
||||||
.iter()
|
|
||||||
.position(|sp| sp.of(self.src).trim_start().starts_with('^'))
|
|
||||||
.map_or(lines.len(), |caption_line| {
|
|
||||||
self.tree.enter(Node::Leaf(Caption), span);
|
|
||||||
lines[caption_line] =
|
|
||||||
lines[caption_line].trim_start(self.src).skip("^ ".len());
|
|
||||||
lines[lines.len() - 1] = lines[lines.len() - 1].trim_end(self.src);
|
|
||||||
for line in &lines[caption_line..] {
|
|
||||||
self.tree.inline(*line);
|
|
||||||
}
|
|
||||||
self.tree.exit(); // caption, will insert inlines later if any
|
|
||||||
caption_line
|
|
||||||
});
|
|
||||||
for row in &lines[..caption_line] {
|
|
||||||
let row = row.trim(self.src);
|
|
||||||
if row.is_empty() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let row_node = self
|
|
||||||
.tree
|
|
||||||
.enter(Node::Container(TableRow { head: false }), row.with_len(1));
|
|
||||||
let rem = row.skip(1);
|
|
||||||
let lex = lex::Lexer::new(row.skip(1).of(self.src).chars());
|
|
||||||
let mut pos = rem.start();
|
|
||||||
let mut cell_start = pos;
|
|
||||||
let mut separator_row = true;
|
|
||||||
let mut verbatim = None;
|
|
||||||
let mut column_index = 0;
|
|
||||||
for lex::Token { kind, len } in lex {
|
|
||||||
if let Some(l) = verbatim {
|
|
||||||
if matches!(kind, lex::Kind::Seq(lex::Sequence::Backtick))
|
|
||||||
&& len == l
|
|
||||||
{
|
|
||||||
verbatim = None;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match kind {
|
|
||||||
lex::Kind::Sym(lex::Symbol::Pipe) => {
|
|
||||||
{
|
|
||||||
let span =
|
|
||||||
Span::new(cell_start, pos).trim(self.src);
|
|
||||||
let cell = span.of(self.src);
|
|
||||||
let separator_cell = match cell.len() {
|
|
||||||
0 => false,
|
|
||||||
1 => cell == "-",
|
|
||||||
2 => matches!(cell, ":-" | "--" | "-:"),
|
|
||||||
l => {
|
|
||||||
matches!(cell.as_bytes()[0], b'-' | b':')
|
|
||||||
&& matches!(
|
|
||||||
cell.as_bytes()[l - 1],
|
|
||||||
b'-' | b':'
|
|
||||||
)
|
|
||||||
&& cell
|
|
||||||
.chars()
|
|
||||||
.skip(1)
|
|
||||||
.take(l - 2)
|
|
||||||
.all(|c| c == '-')
|
|
||||||
}
|
|
||||||
};
|
|
||||||
separator_row &= separator_cell;
|
|
||||||
self.tree.enter(
|
|
||||||
Node::Leaf(TableCell(
|
|
||||||
self.alignments
|
|
||||||
.get(column_index)
|
|
||||||
.copied()
|
|
||||||
.unwrap_or(Alignment::Unspecified),
|
|
||||||
)),
|
|
||||||
Span::by_len(cell_start - 1, 1),
|
|
||||||
);
|
|
||||||
self.tree.inline(span);
|
|
||||||
self.tree.exit(); // cell
|
|
||||||
cell_start = pos + len;
|
|
||||||
column_index += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lex::Kind::Seq(lex::Sequence::Backtick) => {
|
|
||||||
verbatim = Some(len);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pos += len;
|
|
||||||
}
|
|
||||||
if separator_row {
|
|
||||||
self.alignments.clear();
|
|
||||||
self.alignments.extend(
|
|
||||||
self.tree
|
|
||||||
.children(row_node)
|
|
||||||
.filter(|(kind, _)| matches!(kind, tree::Element::Inline))
|
|
||||||
.map(|(_, sp)| {
|
|
||||||
let cell = sp.of(self.src);
|
|
||||||
let l = cell.as_bytes()[0] == b':';
|
|
||||||
let r = cell.as_bytes()[cell.len() - 1] == b':';
|
|
||||||
match (l, r) {
|
|
||||||
(false, false) => Alignment::Unspecified,
|
|
||||||
(false, true) => Alignment::Right,
|
|
||||||
(true, false) => Alignment::Left,
|
|
||||||
(true, true) => Alignment::Center,
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
self.tree.exit_discard(); // table row
|
|
||||||
if let Some(head_row) = last_row_node {
|
|
||||||
self.tree
|
|
||||||
.children(head_row)
|
|
||||||
.filter(|(e, _sp)| {
|
|
||||||
matches!(
|
|
||||||
e,
|
|
||||||
tree::Element::Container(Node::Leaf(TableCell(..)))
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.zip(
|
|
||||||
self.alignments
|
|
||||||
.iter()
|
|
||||||
.copied()
|
|
||||||
.chain(std::iter::repeat(Alignment::Unspecified)),
|
|
||||||
)
|
|
||||||
.for_each(|((e, _), new_align)| {
|
|
||||||
if let tree::Element::Container(Node::Leaf(
|
|
||||||
TableCell(alignment),
|
|
||||||
)) = e
|
|
||||||
{
|
|
||||||
*alignment = new_align;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if let tree::Element::Container(Node::Container(TableRow {
|
|
||||||
head,
|
|
||||||
})) = self.tree.elem(head_row)
|
|
||||||
{
|
|
||||||
*head = true;
|
|
||||||
} else {
|
|
||||||
panic!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.tree.exit(); // table row
|
|
||||||
}
|
|
||||||
last_row_node = Some(row_node);
|
|
||||||
}
|
|
||||||
self.tree.exit(); // table
|
|
||||||
}
|
|
||||||
Block::Container(c) => {
|
|
||||||
let line_count_inner = lines.len() - usize::from(matches!(c, Div));
|
let line_count_inner = lines.len() - usize::from(matches!(c, Div));
|
||||||
|
|
||||||
// update spans, remove indentation / container prefix
|
// update spans, remove indentation / container prefix
|
||||||
|
@ -481,11 +346,139 @@ impl<'s> TreeParser<'s> {
|
||||||
|
|
||||||
self.tree.exit();
|
self.tree.exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_table(&mut self, lines: &mut [Span], span: Span) {
|
||||||
|
self.alignments.clear();
|
||||||
|
self.tree.enter(Node::Container(Table), span);
|
||||||
|
|
||||||
|
let caption_line = lines
|
||||||
|
.iter()
|
||||||
|
.position(|sp| sp.of(self.src).trim_start().starts_with('^'))
|
||||||
|
.map_or(lines.len(), |caption_line| {
|
||||||
|
self.tree.enter(Node::Leaf(Caption), span);
|
||||||
|
lines[caption_line] = lines[caption_line].trim_start(self.src).skip("^ ".len());
|
||||||
|
lines[lines.len() - 1] = lines[lines.len() - 1].trim_end(self.src);
|
||||||
|
for line in &lines[caption_line..] {
|
||||||
|
self.tree.inline(*line);
|
||||||
|
}
|
||||||
|
self.tree.exit();
|
||||||
|
caption_line
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut last_row_node = None;
|
||||||
|
for row in &lines[..caption_line] {
|
||||||
|
let row = row.trim(self.src);
|
||||||
|
if row.is_empty() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let row_node = self
|
||||||
|
.tree
|
||||||
|
.enter(Node::Container(TableRow { head: false }), row.with_len(1));
|
||||||
|
let rem = row.skip(1);
|
||||||
|
let lex = lex::Lexer::new(row.skip(1).of(self.src).chars());
|
||||||
|
let mut pos = rem.start();
|
||||||
|
let mut cell_start = pos;
|
||||||
|
let mut separator_row = true;
|
||||||
|
let mut verbatim = None;
|
||||||
|
let mut column_index = 0;
|
||||||
|
for lex::Token { kind, len } in lex {
|
||||||
|
if let Some(l) = verbatim {
|
||||||
|
if matches!(kind, lex::Kind::Seq(lex::Sequence::Backtick)) && len == l {
|
||||||
|
verbatim = None;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match kind {
|
||||||
|
lex::Kind::Sym(lex::Symbol::Pipe) => {
|
||||||
|
{
|
||||||
|
let span = Span::new(cell_start, pos).trim(self.src);
|
||||||
|
let cell = span.of(self.src);
|
||||||
|
let separator_cell = match cell.len() {
|
||||||
|
0 => false,
|
||||||
|
1 => cell == "-",
|
||||||
|
2 => matches!(cell, ":-" | "--" | "-:"),
|
||||||
|
l => {
|
||||||
|
matches!(cell.as_bytes()[0], b'-' | b':')
|
||||||
|
&& matches!(cell.as_bytes()[l - 1], b'-' | b':')
|
||||||
|
&& cell.chars().skip(1).take(l - 2).all(|c| c == '-')
|
||||||
|
}
|
||||||
|
};
|
||||||
|
separator_row &= separator_cell;
|
||||||
|
self.tree.enter(
|
||||||
|
Node::Leaf(TableCell(
|
||||||
|
self.alignments
|
||||||
|
.get(column_index)
|
||||||
|
.copied()
|
||||||
|
.unwrap_or(Alignment::Unspecified),
|
||||||
|
)),
|
||||||
|
Span::by_len(cell_start - 1, 1),
|
||||||
|
);
|
||||||
|
self.tree.inline(span);
|
||||||
|
self.tree.exit(); // cell
|
||||||
|
cell_start = pos + len;
|
||||||
|
column_index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lex::Kind::Seq(lex::Sequence::Backtick) => {
|
||||||
|
verbatim = Some(len);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
line_count
|
if separator_row {
|
||||||
},
|
self.alignments.clear();
|
||||||
|
self.alignments.extend(
|
||||||
|
self.tree
|
||||||
|
.children(row_node)
|
||||||
|
.filter(|(kind, _)| matches!(kind, tree::Element::Inline))
|
||||||
|
.map(|(_, sp)| {
|
||||||
|
let cell = sp.of(self.src);
|
||||||
|
let l = cell.as_bytes()[0] == b':';
|
||||||
|
let r = cell.as_bytes()[cell.len() - 1] == b':';
|
||||||
|
match (l, r) {
|
||||||
|
(false, false) => Alignment::Unspecified,
|
||||||
|
(false, true) => Alignment::Right,
|
||||||
|
(true, false) => Alignment::Left,
|
||||||
|
(true, true) => Alignment::Center,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
self.tree.exit_discard(); // table row
|
||||||
|
if let Some(head_row) = last_row_node {
|
||||||
|
self.tree
|
||||||
|
.children(head_row)
|
||||||
|
.filter(|(e, _sp)| {
|
||||||
|
matches!(e, tree::Element::Container(Node::Leaf(TableCell(..))))
|
||||||
|
})
|
||||||
|
.zip(
|
||||||
|
self.alignments
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.chain(std::iter::repeat(Alignment::Unspecified)),
|
||||||
)
|
)
|
||||||
|
.for_each(|((e, _), new_align)| {
|
||||||
|
if let tree::Element::Container(Node::Leaf(TableCell(alignment))) = e {
|
||||||
|
*alignment = new_align;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if let tree::Element::Container(Node::Container(TableRow { head })) =
|
||||||
|
self.tree.elem(head_row)
|
||||||
|
{
|
||||||
|
*head = true;
|
||||||
|
} else {
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.tree.exit(); // table row
|
||||||
|
}
|
||||||
|
|
||||||
|
last_row_node = Some(row_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tree.exit(); // table
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue