mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-08-04 02:08:17 +00:00
feat: evaluate table and grid (#1300)
* feat: add table and grid functions evaluating * fix: clippy * refactor: simplify table and grid functions by extracting common logic * fix: handle invalid columns argument and set default value; handle no header situation
This commit is contained in:
parent
cddb193b18
commit
b24a7fd497
1 changed files with 99 additions and 0 deletions
|
@ -2,6 +2,7 @@
|
|||
|
||||
use super::*;
|
||||
use ecow::eco_format;
|
||||
use typst_syntax::{ast, SyntaxKind, SyntaxNode};
|
||||
use value::*;
|
||||
|
||||
mod docstring;
|
||||
|
@ -21,6 +22,8 @@ pub fn library() -> Scopes<Value> {
|
|||
scopes.define("important-box", important_box as RawFunc);
|
||||
scopes.define("warning-box", warning_box as RawFunc);
|
||||
scopes.define("caution-box", caution_box as RawFunc);
|
||||
scopes.define("table", table as RawFunc);
|
||||
scopes.define("grid", grid as RawFunc);
|
||||
scopes
|
||||
}
|
||||
|
||||
|
@ -133,3 +136,99 @@ fn note_box(title: &str, body: Content) -> Value {
|
|||
|
||||
Value::Content(res)
|
||||
}
|
||||
|
||||
/// Evaluate a table.
|
||||
pub fn table(args: Args) -> Result<Value> {
|
||||
table_eval(args, &EcoString::from("table"))
|
||||
}
|
||||
|
||||
/// Evaluate a grid.
|
||||
pub fn grid(args: Args) -> Result<Value> {
|
||||
table_eval(args, &EcoString::from("grid"))
|
||||
}
|
||||
|
||||
fn table_eval(mut args: Args, kind: &EcoString) -> Result<Value> {
|
||||
let columns = if let Some(columns) = args.get_named_("columns") {
|
||||
match columns.kind() {
|
||||
SyntaxKind::Array => {
|
||||
let array: ast::Array = args.get_named_("columns").unwrap().cast().unwrap();
|
||||
array.items().count()
|
||||
}
|
||||
SyntaxKind::Int => {
|
||||
let int_val: ast::Int = args.get_named_("columns").unwrap().cast().unwrap();
|
||||
int_val.get().try_into().unwrap()
|
||||
}
|
||||
other => return Err(format!("invalid columns argument of type {:?}", other).into()),
|
||||
}
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
let header_field = SyntaxNode::inner(
|
||||
SyntaxKind::FieldAccess,
|
||||
vec![
|
||||
SyntaxNode::leaf(SyntaxKind::Ident, kind),
|
||||
SyntaxNode::leaf(SyntaxKind::Dot, "."),
|
||||
SyntaxNode::leaf(SyntaxKind::Ident, "header"),
|
||||
],
|
||||
);
|
||||
let footer_field = SyntaxNode::inner(
|
||||
SyntaxKind::FieldAccess,
|
||||
vec![
|
||||
SyntaxNode::leaf(SyntaxKind::Ident, kind),
|
||||
SyntaxNode::leaf(SyntaxKind::Dot, "."),
|
||||
SyntaxNode::leaf(SyntaxKind::Ident, "footer"),
|
||||
],
|
||||
);
|
||||
|
||||
let mut header: Vec<EcoString> = Vec::new();
|
||||
let mut cells: Vec<EcoString> = Vec::new();
|
||||
|
||||
while let Some(pos_arg) = args.pos.pop() {
|
||||
if pos_arg.kind() != SyntaxKind::FuncCall {
|
||||
let evaluated = args.vm.eval(pos_arg)?;
|
||||
cells.push(TypliteWorker::value(evaluated));
|
||||
} else {
|
||||
let func_call: ast::FuncCall = pos_arg.cast().unwrap();
|
||||
let first_child = pos_arg.children().next().unwrap();
|
||||
|
||||
if header_field.spanless_eq(first_child) {
|
||||
let mut header_args = Args::new(args.vm, func_call.args());
|
||||
while let Some(arg) = header_args.pos.pop() {
|
||||
let evaluated = header_args.vm.eval(arg)?;
|
||||
header.push(TypliteWorker::value(evaluated));
|
||||
}
|
||||
} else {
|
||||
let evaluated = args.vm.eval(pos_arg)?;
|
||||
cells.push(TypliteWorker::value(evaluated));
|
||||
}
|
||||
if footer_field.spanless_eq(first_child) {
|
||||
let mut footer_args = Args::new(args.vm, func_call.args());
|
||||
while let Some(arg) = footer_args.pos.pop() {
|
||||
let evaluated = footer_args.vm.eval(arg)?;
|
||||
cells.push(TypliteWorker::value(evaluated));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut res = EcoString::from("<table>\n");
|
||||
if !header.is_empty() {
|
||||
res.push_str(" <thead>\n <tr>\n");
|
||||
for cell in &header {
|
||||
res.push_str(&eco_format!(" <th>{}</th>\n", cell));
|
||||
}
|
||||
res.push_str(" </tr>\n </thead>\n");
|
||||
}
|
||||
res.push_str(" <tbody>\n");
|
||||
for row in cells.chunks(columns) {
|
||||
res.push_str(" <tr>\n");
|
||||
for cell in row {
|
||||
res.push_str(&eco_format!(" <td>{}</td>\n", cell));
|
||||
}
|
||||
res.push_str(" </tr>\n");
|
||||
}
|
||||
res.push_str(" </tbody>\n</table>");
|
||||
|
||||
Ok(Value::Content(res))
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue