mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Merge branch 'master' into code-blocks
This commit is contained in:
commit
5e1fd35926
@ -63,6 +63,10 @@ impl<'a> TreeLayouter<'a> {
|
|||||||
match &node.v {
|
match &node.v {
|
||||||
SyntaxNode::Spacing => self.layout_space(),
|
SyntaxNode::Spacing => self.layout_space(),
|
||||||
SyntaxNode::Linebreak => self.layouter.finish_line(),
|
SyntaxNode::Linebreak => self.layouter.finish_line(),
|
||||||
|
SyntaxNode::Parbreak => self.layouter.add_secondary_spacing(
|
||||||
|
self.style.text.paragraph_spacing(),
|
||||||
|
SpacingKind::PARAGRAPH,
|
||||||
|
),
|
||||||
|
|
||||||
SyntaxNode::ToggleItalic => {
|
SyntaxNode::ToggleItalic => {
|
||||||
self.style.text.italic = !self.style.text.italic;
|
self.style.text.italic = !self.style.text.italic;
|
||||||
@ -81,7 +85,7 @@ impl<'a> TreeLayouter<'a> {
|
|||||||
|
|
||||||
SyntaxNode::Raw(lines) => self.layout_raw(lines).await,
|
SyntaxNode::Raw(lines) => self.layout_raw(lines).await,
|
||||||
SyntaxNode::CodeBlock(block) => self.layout_code(block).await,
|
SyntaxNode::CodeBlock(block) => self.layout_code(block).await,
|
||||||
SyntaxNode::Par(par) => self.layout_par(par).await,
|
|
||||||
SyntaxNode::Call(call) => {
|
SyntaxNode::Call(call) => {
|
||||||
self.layout_call(Spanned::new(call, node.span)).await;
|
self.layout_call(Spanned::new(call, node.span)).await;
|
||||||
}
|
}
|
||||||
@ -144,14 +148,6 @@ impl<'a> TreeLayouter<'a> {
|
|||||||
self.style.text.fallback = fallback;
|
self.style.text.fallback = fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn layout_par(&mut self, par: &SyntaxTree) {
|
|
||||||
self.layout_tree(par).await;
|
|
||||||
self.layouter.add_secondary_spacing(
|
|
||||||
self.style.text.paragraph_spacing(),
|
|
||||||
SpacingKind::PARAGRAPH,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn layout_call(&mut self, call: Spanned<&CallExpr>) {
|
async fn layout_call(&mut self, call: Spanned<&CallExpr>) {
|
||||||
let ctx = LayoutContext {
|
let ctx = LayoutContext {
|
||||||
style: &self.style,
|
style: &self.style,
|
||||||
|
@ -5,16 +5,19 @@ use super::*;
|
|||||||
/// # Positional arguments
|
/// # Positional arguments
|
||||||
/// - At most two of `left`, `right`, `top`, `bottom`, `center`.
|
/// - At most two of `left`, `right`, `top`, `bottom`, `center`.
|
||||||
///
|
///
|
||||||
|
/// When `center` is used as a positional argument, it is automatically inferred
|
||||||
|
/// which axis it should apply to depending on further arguments, defaulting
|
||||||
|
/// to the axis, text is set along.
|
||||||
|
///
|
||||||
/// # Keyword arguments
|
/// # Keyword arguments
|
||||||
/// - `horizontal`: Any of `left`, `right` or `center`.
|
/// - `horizontal`: Any of `left`, `right` or `center`.
|
||||||
/// - `vertical`: Any of `top`, `bottom` or `center`.
|
/// - `vertical`: Any of `top`, `bottom` or `center`.
|
||||||
///
|
///
|
||||||
/// There may not be two alignment specifications for the same axis.
|
/// There may not be two alignment specifications for the same axis.
|
||||||
pub async fn align(_: Span, mut args: TableValue, mut ctx: LayoutContext<'_>) -> Pass<Value> {
|
pub async fn align(_: Span, mut args: TableValue, ctx: LayoutContext<'_>) -> Pass<Value> {
|
||||||
let mut f = Feedback::new();
|
let mut f = Feedback::new();
|
||||||
|
|
||||||
let content = args.take::<SyntaxTree>();
|
let content = args.take::<SyntaxTree>();
|
||||||
|
|
||||||
let h = args.take_key::<Spanned<SpecAlign>>("horizontal", &mut f);
|
let h = args.take_key::<Spanned<SpecAlign>>("horizontal", &mut f);
|
||||||
let v = args.take_key::<Spanned<SpecAlign>>("vertical", &mut f);
|
let v = args.take_key::<Spanned<SpecAlign>>("vertical", &mut f);
|
||||||
let all = args
|
let all = args
|
||||||
@ -23,17 +26,15 @@ pub async fn align(_: Span, mut args: TableValue, mut ctx: LayoutContext<'_>) ->
|
|||||||
.chain(h.into_iter().map(|align| (Some(Horizontal), align)))
|
.chain(h.into_iter().map(|align| (Some(Horizontal), align)))
|
||||||
.chain(v.into_iter().map(|align| (Some(Vertical), align)));
|
.chain(v.into_iter().map(|align| (Some(Vertical), align)));
|
||||||
|
|
||||||
|
let mut aligns = ctx.align;
|
||||||
let mut had = [false; 2];
|
let mut had = [false; 2];
|
||||||
for (axis, align) in all {
|
let mut deferred_center = false;
|
||||||
let axis = axis.unwrap_or_else(|| align.v.axis().unwrap_or_else(|| {
|
|
||||||
let primary = ctx.axes.primary.axis();
|
|
||||||
if !had[primary as usize] {
|
|
||||||
primary
|
|
||||||
} else {
|
|
||||||
ctx.axes.secondary.axis()
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
for (axis, align) in all {
|
||||||
|
// Check whether we know which axis this alignment belongs to. We don't
|
||||||
|
// if the alignment is `center` for a positional argument. Then we set
|
||||||
|
// `deferred_center` to true and handle the situation once we know more.
|
||||||
|
if let Some(axis) = axis {
|
||||||
if align.v.axis().map(|a| a != axis).unwrap_or(false) {
|
if align.v.axis().map(|a| a != axis).unwrap_or(false) {
|
||||||
error!(
|
error!(
|
||||||
@f, align.span,
|
@f, align.span,
|
||||||
@ -42,21 +43,52 @@ pub async fn align(_: Span, mut args: TableValue, mut ctx: LayoutContext<'_>) ->
|
|||||||
} else if had[axis as usize] {
|
} else if had[axis as usize] {
|
||||||
error!(@f, align.span, "duplicate alignment for {} axis", axis);
|
error!(@f, align.span, "duplicate alignment for {} axis", axis);
|
||||||
} else {
|
} else {
|
||||||
had[axis as usize] = true;
|
|
||||||
let gen_axis = axis.to_generic(ctx.axes);
|
|
||||||
let gen_align = align.v.to_generic(ctx.axes);
|
let gen_align = align.v.to_generic(ctx.axes);
|
||||||
*ctx.align.get_mut(gen_axis) = gen_align;
|
*aligns.get_mut(axis.to_generic(ctx.axes)) = gen_align;
|
||||||
|
had[axis as usize] = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if had == [true, true] {
|
||||||
|
error!(@f, align.span, "duplicate alignment");
|
||||||
|
} else if deferred_center {
|
||||||
|
// We have two unflushed centers, meaning we know that both axes
|
||||||
|
// are to be centered.
|
||||||
|
had = [true, true];
|
||||||
|
aligns = LayoutAlign::new(Center, Center);
|
||||||
|
} else {
|
||||||
|
deferred_center = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let commands = match content {
|
// Flush a deferred center alignment if we know have had at least one
|
||||||
Some(tree) => {
|
// known alignment.
|
||||||
ctx.base = ctx.spaces[0].size;
|
if deferred_center && had != [false, false] {
|
||||||
let layouted = layout(&tree, ctx).await;
|
let axis = if !had[Horizontal as usize] {
|
||||||
f.extend(layouted.feedback);
|
Horizontal
|
||||||
vec![AddMultiple(layouted.output)]
|
} else {
|
||||||
|
Vertical
|
||||||
|
};
|
||||||
|
|
||||||
|
*aligns.get_mut(axis.to_generic(ctx.axes)) = Center;
|
||||||
|
|
||||||
|
had[axis as usize] = true;
|
||||||
|
deferred_center = false;
|
||||||
}
|
}
|
||||||
None => vec![SetAlignment(ctx.align)],
|
}
|
||||||
|
|
||||||
|
// If center has not been flushed by known, it is the only argument and then
|
||||||
|
// we default to applying it to the primary axis.
|
||||||
|
if deferred_center {
|
||||||
|
aligns.primary = Center;
|
||||||
|
}
|
||||||
|
|
||||||
|
let commands = match content {
|
||||||
|
Some(tree) => vec![
|
||||||
|
SetAlignment(aligns),
|
||||||
|
LayoutSyntaxTree(tree),
|
||||||
|
SetAlignment(ctx.align),
|
||||||
|
],
|
||||||
|
None => vec![SetAlignment(aligns)],
|
||||||
};
|
};
|
||||||
|
|
||||||
args.unexpected(&mut f);
|
args.unexpected(&mut f);
|
||||||
|
@ -50,27 +50,20 @@ impl<'s> Parser<'s> {
|
|||||||
impl Parser<'_> {
|
impl Parser<'_> {
|
||||||
fn parse_body_contents(&mut self) -> SyntaxTree {
|
fn parse_body_contents(&mut self) -> SyntaxTree {
|
||||||
let mut tree = SyntaxTree::new();
|
let mut tree = SyntaxTree::new();
|
||||||
let mut par = SyntaxTree::new();
|
|
||||||
|
|
||||||
while let Some(token) = self.peek() {
|
while let Some(token) = self.peek() {
|
||||||
par.push(match token.v {
|
tree.push(match token.v {
|
||||||
// Starting from two newlines counts as a paragraph break, a single
|
// Starting from two newlines counts as a paragraph break, a single
|
||||||
// newline does not.
|
// newline does not.
|
||||||
Token::Space(newlines) => if newlines < 2 {
|
Token::Space(newlines) => self.with_span(if newlines < 2 {
|
||||||
self.with_span(SyntaxNode::Spacing)
|
SyntaxNode::Spacing
|
||||||
} else {
|
} else {
|
||||||
// End the current paragraph if it is not empty.
|
SyntaxNode::Parbreak
|
||||||
if let (Some(first), Some(last)) = (par.first(), par.last()) {
|
}),
|
||||||
let span = Span::merge(first.span, last.span);
|
|
||||||
let node = SyntaxNode::Par(std::mem::take(&mut par));
|
|
||||||
tree.push(Spanned::new(node, span));
|
|
||||||
}
|
|
||||||
self.eat();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Token::LineComment(_) | Token::BlockComment(_) => {
|
Token::LineComment(_) | Token::BlockComment(_) => {
|
||||||
self.eat();
|
self.eat();
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Token::LeftBracket => {
|
Token::LeftBracket => {
|
||||||
@ -134,12 +127,6 @@ impl Parser<'_> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let (Some(first), Some(last)) = (par.first(), par.last()) {
|
|
||||||
let span = Span::merge(first.span, last.span);
|
|
||||||
let node = SyntaxNode::Par(par);
|
|
||||||
tree.push(Spanned::new(node, span));
|
|
||||||
}
|
|
||||||
|
|
||||||
tree
|
tree
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -753,6 +740,7 @@ mod tests {
|
|||||||
use SyntaxNode::{
|
use SyntaxNode::{
|
||||||
Spacing as S,
|
Spacing as S,
|
||||||
Linebreak as L,
|
Linebreak as L,
|
||||||
|
Parbreak as P,
|
||||||
ToggleItalic as I,
|
ToggleItalic as I,
|
||||||
ToggleBolder as B,
|
ToggleBolder as B,
|
||||||
};
|
};
|
||||||
@ -765,6 +753,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn Lang(text: &str) -> Option<Spanned<Ident>> { Some(Spanned::zero(Ident(text.to_string()))) }
|
fn Lang(text: &str) -> Option<Spanned<Ident>> { Some(Spanned::zero(Ident(text.to_string()))) }
|
||||||
|
|
||||||
macro_rules! C {
|
macro_rules! C {
|
||||||
@ -773,10 +762,6 @@ mod tests {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! P {
|
|
||||||
($($tts:tt)*) => { SyntaxNode::Par(Tree![@$($tts)*]) };
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! F {
|
macro_rules! F {
|
||||||
($($tts:tt)*) => { SyntaxNode::Call(Call!(@$($tts)*)) }
|
($($tts:tt)*) => { SyntaxNode::Call(Call!(@$($tts)*)) }
|
||||||
}
|
}
|
||||||
@ -860,7 +845,7 @@ mod tests {
|
|||||||
// Test expressions.
|
// Test expressions.
|
||||||
macro_rules! v {
|
macro_rules! v {
|
||||||
($src:expr => $($tts:tt)*) => {
|
($src:expr => $($tts:tt)*) => {
|
||||||
t!(concat!("[val: ", $src, "]") => P![F!("val"; $($tts)*)]);
|
t!(concat!("[val: ", $src, "]") => F!("val"; $($tts)*));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -945,16 +930,17 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_parse_simple_nodes() {
|
fn test_parse_simple_nodes() {
|
||||||
t!("" => );
|
t!("" => );
|
||||||
t!("hi" => P![T("hi")]);
|
t!("hi" => T("hi"));
|
||||||
t!("*hi" => P![B, T("hi")]);
|
t!("*hi" => B, T("hi"));
|
||||||
t!("hi_" => P![T("hi"), I]);
|
t!("hi_" => T("hi"), I);
|
||||||
t!("hi you" => P![T("hi"), S, T("you")]);
|
t!("hi you" => T("hi"), S, T("you"));
|
||||||
t!("\n\n\nhello" => P![T("hello")]);
|
t!("\n\n\nhello" => P, T("hello"));
|
||||||
t!(r"a\ b" => P![T("a"), L, S, T("b")]);
|
t!(r"a\ b" => T("a"), L, S, T("b"));
|
||||||
t!("`py`" => P![R!["py"]]);
|
t!("`py`" => R!["py"]);
|
||||||
t!("`hi\nyou" => P![R!["hi", "you"]]);
|
t!("`hi\nyou" => R!["hi", "you"]);
|
||||||
e!("`hi\nyou" => s(1,3, 1,3, "expected backtick"));
|
e!("`hi\nyou" => s(1,3, 1,3, "expected backtick"));
|
||||||
t!("`hi\\`du`" => P![R!["hi`du"]]);
|
t!("`hi\\`du`" => R!["hi`du"]);
|
||||||
|
|
||||||
t!("```java System.out.print```" => P![
|
t!("```java System.out.print```" => P![
|
||||||
C![Lang("java"), "System.out.print"]
|
C![Lang("java"), "System.out.print"]
|
||||||
]);
|
]);
|
||||||
@ -968,28 +954,23 @@ mod tests {
|
|||||||
e!("```🌍 hi\nyou```" => s(0,3, 0,4, "expected language to be a valid identifier"));
|
e!("```🌍 hi\nyou```" => s(0,3, 0,4, "expected language to be a valid identifier"));
|
||||||
t!("💜\n\n 🌍" => P![T("💜")], P![T("🌍")]);
|
t!("💜\n\n 🌍" => P![T("💜")], P![T("🌍")]);
|
||||||
|
|
||||||
ts!("hi" => s(0,0, 0,2, P![s(0,0, 0,2, T("hi"))]));
|
ts!("hi" => s(0,0, 0,2, T("hi")));
|
||||||
ts!("*Hi*" => s(0,0, 0,4, P![
|
ts!("*Hi*" => s(0,0, 0,1, B), s(0,1, 0,3, T("Hi")), s(0,3, 0,4, B));
|
||||||
s(0,0, 0,1, B), s(0,1, 0,3, T("Hi")), s(0,3, 0,4, B),
|
ts!("💜\n\n 🌍" => s(0,0, 0,1, T("💜")), s(0,1, 2,1, P), s(2,1, 2,2, T("🌍")));
|
||||||
]));
|
|
||||||
ts!("💜\n\n 🌍" =>
|
|
||||||
s(0,0, 0,1, P![s(0,0, 0,1, T("💜"))]),
|
|
||||||
s(2,1, 2,2, P![s(2,1, 2,2, T("🌍"))]),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_comments() {
|
fn test_parse_comments() {
|
||||||
// In body.
|
// In body.
|
||||||
t!("hi// you\nw" => P![T("hi"), S, T("w")]);
|
t!("hi// you\nw" => T("hi"), S, T("w"));
|
||||||
t!("first//\n//\nsecond" => P![T("first"), S, S, T("second")]);
|
t!("first//\n//\nsecond" => T("first"), S, S, T("second"));
|
||||||
t!("first//\n \nsecond" => P![T("first")], P![T("second")]);
|
t!("first//\n \nsecond" => T("first"), P, T("second"));
|
||||||
t!("first/*\n \n*/second" => P![T("first"), T("second")]);
|
t!("first/*\n \n*/second" => T("first"), T("second"));
|
||||||
e!("🌎\n*/n" => s(1,0, 1,2, "unexpected end of block comment"));
|
e!("🌎\n*/n" => s(1,0, 1,2, "unexpected end of block comment"));
|
||||||
|
|
||||||
// In header.
|
// In header.
|
||||||
t!("[val:/*12pt*/]" => P![F!("val")]);
|
t!("[val:/*12pt*/]" => F!("val"));
|
||||||
t!("[val \n /* \n */:]" => P![F!("val")]);
|
t!("[val \n /* \n */:]" => F!("val"));
|
||||||
e!("[val \n /* \n */:]" => );
|
e!("[val \n /* \n */:]" => );
|
||||||
e!("[val : 12, /* \n */ 14]" => );
|
e!("[val : 12, /* \n */ 14]" => );
|
||||||
}
|
}
|
||||||
@ -1006,7 +987,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_parse_function_names() {
|
fn test_parse_function_names() {
|
||||||
// No closing bracket.
|
// No closing bracket.
|
||||||
t!("[" => P![F!("")]);
|
t!("[" => F!(""));
|
||||||
e!("[" => s(0,1, 0,1, "expected function name"),
|
e!("[" => s(0,1, 0,1, "expected function name"),
|
||||||
s(0,1, 0,1, "expected closing bracket"));
|
s(0,1, 0,1, "expected closing bracket"));
|
||||||
|
|
||||||
@ -1016,8 +997,8 @@ mod tests {
|
|||||||
s(0,3, 0,3, "expected closing bracket"));
|
s(0,3, 0,3, "expected closing bracket"));
|
||||||
|
|
||||||
// A valid name.
|
// A valid name.
|
||||||
t!("[hi]" => P![F!("hi")]);
|
t!("[hi]" => F!("hi"));
|
||||||
t!("[ f]" => P![F!("f")]);
|
t!("[ f]" => F!("f"));
|
||||||
|
|
||||||
// An invalid name.
|
// An invalid name.
|
||||||
e!("[12]" => s(0,1, 0,3, "expected function name, found number"));
|
e!("[12]" => s(0,1, 0,3, "expected function name, found number"));
|
||||||
@ -1025,12 +1006,16 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_subgroups() {
|
fn test_parse_chaining() {
|
||||||
// Things the parser has to make sense of
|
// Things the parser has to make sense of
|
||||||
t!("[hi: (5.0, 2.1 >> you]" => P![F!("hi"; Table![Num(5.0), Num(2.1)], Tree![F!("you")])]);
|
t!("[hi: (5.0, 2.1 >> you]" => F!("hi"; Table![Num(5.0), Num(2.1)], Tree![F!("you")]));
|
||||||
t!("[bold: 400, >> emph >> sub: 1cm]" => P![F!("bold"; Num(400.0), Tree![F!("emph"; Tree!(F!("sub"; Len(Length::cm(1.0)))))])]);
|
t!("[box >>][Hi]" => F!("box"; Tree![T("Hi")]));
|
||||||
t!("[box >> pad: 1pt][Hi]" => P![F!("box"; Tree![F!("pad"; Len(Length::pt(1.0)), Tree!(P![T("Hi")]))])]);
|
t!("[box >> pad: 1pt][Hi]" => F!("box"; Tree![
|
||||||
t!("[box >>][Hi]" => P![F!("box"; Tree![P![T("Hi")]])]);
|
F!("pad"; Len(Length::pt(1.0)), Tree!(T("Hi")))
|
||||||
|
]));
|
||||||
|
t!("[bold: 400, >> emph >> sub: 1cm]" => F!("bold"; Num(400.0), Tree![
|
||||||
|
F!("emph"; Tree!(F!("sub"; Len(Length::cm(1.0)))))
|
||||||
|
]));
|
||||||
|
|
||||||
// Errors for unclosed / empty predecessor groups
|
// Errors for unclosed / empty predecessor groups
|
||||||
e!("[hi: (5.0, 2.1 >> you]" => s(0, 15, 0, 15, "expected closing paren"));
|
e!("[hi: (5.0, 2.1 >> you]" => s(0, 15, 0, 15, "expected closing paren"));
|
||||||
@ -1043,7 +1028,7 @@ mod tests {
|
|||||||
e!("[val:]" => );
|
e!("[val:]" => );
|
||||||
|
|
||||||
// Wrong token.
|
// Wrong token.
|
||||||
t!("[val=]" => P![F!("val")]);
|
t!("[val=]" => F!("val"));
|
||||||
e!("[val=]" => s(0,4, 0,4, "expected colon"));
|
e!("[val=]" => s(0,4, 0,4, "expected colon"));
|
||||||
e!("[val/🌎:$]" => s(0,4, 0,4, "expected colon"));
|
e!("[val/🌎:$]" => s(0,4, 0,4, "expected colon"));
|
||||||
|
|
||||||
@ -1056,27 +1041,25 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_function_bodies() {
|
fn test_parse_function_bodies() {
|
||||||
t!("[val: 1][*Hi*]" => P![F!("val"; Num(1.0), Tree![P![B, T("Hi"), B]])]);
|
t!("[val: 1][*Hi*]" => F!("val"; Num(1.0), Tree![B, T("Hi"), B]));
|
||||||
e!(" [val][ */ ]" => s(0,8, 0,10, "unexpected end of block comment"));
|
e!(" [val][ */ ]" => s(0,8, 0,10, "unexpected end of block comment"));
|
||||||
|
|
||||||
// Raw in body.
|
// Raw in body.
|
||||||
t!("[val][`Hi]`" => P![F!("val"; Tree![P![R!["Hi]"]]])]);
|
t!("[val][`Hi]`" => F!("val"; Tree![R!["Hi]"]]));
|
||||||
e!("[val][`Hi]`" => s(0,11, 0,11, "expected closing bracket"));
|
e!("[val][`Hi]`" => s(0,11, 0,11, "expected closing bracket"));
|
||||||
|
|
||||||
// Crazy.
|
// Crazy.
|
||||||
t!("[v][[v][v][v]]" => P![F!("v"; Tree![P![
|
t!("[v][[v][v][v]]" => F!("v"; Tree![F!("v"; Tree![T("v")]), F!("v")]));
|
||||||
F!("v"; Tree![P![T("v")]]), F!("v")
|
|
||||||
]])]);
|
|
||||||
|
|
||||||
// Spanned.
|
// Spanned.
|
||||||
ts!(" [box][Oh my]" => s(0,0, 0,13, P![
|
ts!(" [box][Oh my]" =>
|
||||||
s(0,0, 0,1, S),
|
s(0,0, 0,1, S),
|
||||||
s(0,1, 0,13, F!(s(0,2, 0,5, "box");
|
s(0,1, 0,13, F!(s(0,2, 0,5, "box");
|
||||||
s(0,6, 0,13, Tree![s(0,7, 0,12, P![
|
s(0,6, 0,13, Tree![
|
||||||
s(0,7, 0,9, T("Oh")), s(0,9, 0,10, S), s(0,10, 0,12, T("my"))
|
s(0,7, 0,9, T("Oh")), s(0,9, 0,10, S), s(0,10, 0,12, T("my"))
|
||||||
])])
|
])
|
||||||
))
|
))
|
||||||
]));
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1097,7 +1080,7 @@ mod tests {
|
|||||||
v!("\"a\n[]\\\"string\"" => Str("a\n[]\"string"));
|
v!("\"a\n[]\\\"string\"" => Str("a\n[]\"string"));
|
||||||
|
|
||||||
// Content.
|
// Content.
|
||||||
v!("{_hi_}" => Tree![P![I, T("hi"), I]]);
|
v!("{_hi_}" => Tree![I, T("hi"), I]);
|
||||||
e!("[val: {_hi_}]" => );
|
e!("[val: {_hi_}]" => );
|
||||||
v!("[hi]" => Tree![F!["hi"]]);
|
v!("[hi]" => Tree![F!["hi"]]);
|
||||||
e!("[val: [hi]]" => );
|
e!("[val: [hi]]" => );
|
||||||
@ -1115,9 +1098,7 @@ mod tests {
|
|||||||
s(0,13, 0,13, "expected closing bracket"));
|
s(0,13, 0,13, "expected closing bracket"));
|
||||||
|
|
||||||
// Spanned.
|
// Spanned.
|
||||||
ts!("[val: 1.4]" => s(0,0, 0,10, P![
|
ts!("[val: 1.4]" => s(0,0, 0,10, F!(s(0,1, 0,4, "val"); s(0,6, 0,9, Num(1.4)))));
|
||||||
s(0,0, 0,10, F!(s(0,1, 0,4, "val"); s(0,6, 0,9, Num(1.4))))
|
|
||||||
]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1147,17 +1128,15 @@ mod tests {
|
|||||||
v!("3/4*5" => Mul(Div(Num(3.0), Num(4.0)), Num(5.0)));
|
v!("3/4*5" => Mul(Div(Num(3.0), Num(4.0)), Num(5.0)));
|
||||||
|
|
||||||
// Spanned.
|
// Spanned.
|
||||||
ts!("[val: 1 + 3]" => s(0,0, 0,12, P![s(0,0, 0,12, F!(
|
ts!("[val: 1 + 3]" => s(0,0, 0,12, F!(
|
||||||
s(0,1, 0,4, "val"); s(0,6, 0,11, Add(
|
s(0,1, 0,4, "val"); s(0,6, 0,11, Add(
|
||||||
s(0,6, 0,7, Num(1.0)),
|
s(0,6, 0,7, Num(1.0)),
|
||||||
s(0,10, 0,11, Num(3.0)),
|
s(0,10, 0,11, Num(3.0)),
|
||||||
))
|
))
|
||||||
))]));
|
)));
|
||||||
|
|
||||||
// Span of parenthesized expression contains parens.
|
// Span of parenthesized expression contains parens.
|
||||||
ts!("[val: (1)]" => s(0,0, 0,10, P![
|
ts!("[val: (1)]" => s(0,0, 0,10, F!(s(0,1, 0,4, "val"); s(0,6, 0,9, Num(1.0)))));
|
||||||
s(0,0, 0,10, F!(s(0,1, 0,4, "val"); s(0,6, 0,9, Num(1.0))))
|
|
||||||
]));
|
|
||||||
|
|
||||||
// Invalid expressions.
|
// Invalid expressions.
|
||||||
v!("4pt--" => Len(Length::pt(4.0)));
|
v!("4pt--" => Len(Length::pt(4.0)));
|
||||||
@ -1184,12 +1163,10 @@ mod tests {
|
|||||||
d!("[val: f(key=hi)]" => s(0,8, 0,11, TableKey));
|
d!("[val: f(key=hi)]" => s(0,8, 0,11, TableKey));
|
||||||
|
|
||||||
// Spanned with spacing around keyword arguments.
|
// Spanned with spacing around keyword arguments.
|
||||||
ts!("[val: \n hi \n = /* //\n */ \"s\n\"]" => s(0,0, 4,2, P![
|
ts!("[val: \n hi \n = /* //\n */ \"s\n\"]" => s(0,0, 4,2, F!(
|
||||||
s(0,0, 4,2, F!(
|
|
||||||
s(0,1, 0,4, "val");
|
s(0,1, 0,4, "val");
|
||||||
s(1,1, 1,3, "hi") => s(3,4, 4,1, Str("s\n"))
|
s(1,1, 1,3, "hi") => s(3,4, 4,1, Str("s\n"))
|
||||||
))
|
)));
|
||||||
]));
|
|
||||||
e!("[val: \n hi \n = /* //\n */ \"s\n\"]" => );
|
e!("[val: \n hi \n = /* //\n */ \"s\n\"]" => );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@ pub enum SyntaxNode {
|
|||||||
Spacing,
|
Spacing,
|
||||||
/// A forced line break.
|
/// A forced line break.
|
||||||
Linebreak,
|
Linebreak,
|
||||||
|
/// A paragraph break.
|
||||||
|
Parbreak,
|
||||||
/// Italics were enabled / disabled.
|
/// Italics were enabled / disabled.
|
||||||
ToggleItalic,
|
ToggleItalic,
|
||||||
/// Bolder was enabled / disabled.
|
/// Bolder was enabled / disabled.
|
||||||
@ -33,8 +35,6 @@ pub enum SyntaxNode {
|
|||||||
Raw(Vec<String>),
|
Raw(Vec<String>),
|
||||||
/// An optionally highlighted multi-line code block.
|
/// An optionally highlighted multi-line code block.
|
||||||
CodeBlock(CodeBlockExpr),
|
CodeBlock(CodeBlockExpr),
|
||||||
/// A paragraph of child nodes.
|
|
||||||
Par(SyntaxTree),
|
|
||||||
/// A function call.
|
/// A function call.
|
||||||
Call(CallExpr),
|
Call(CallExpr),
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
Dr. Max Mustermann \
|
Dr. Max Mustermann \
|
||||||
Ola Nordmann, John Doe
|
Ola Nordmann, John Doe
|
||||||
]
|
]
|
||||||
[align: right][
|
[align: right >> box][
|
||||||
*WiSe 2019/2020* \
|
*WiSe 2019/2020* \
|
||||||
Woche 3
|
Woche 3
|
||||||
]
|
]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user