Compare commits

...

6 Commits

14 changed files with 92 additions and 21 deletions

View File

@ -173,8 +173,11 @@ typst help
typst help watch typst help watch
``` ```
If you prefer an integrated IDE-like experience with autocompletion and instant If you prefer an integrated IDE-like experience with autocompletion and instant
preview, you can also check out [Typst's free web app][app]. preview, you can also check out our [free web app][app]. Alternatively, there is
a community-created language server called
[Tinymist](https://myriad-dreamin.github.io/tinymist/) which is integrated into
various editor extensions.
## Community ## Community
The main places where the community gathers are our [Forum][forum] and our The main places where the community gathers are our [Forum][forum] and our

View File

@ -1,5 +1,5 @@
use ecow::eco_format; use ecow::eco_format;
use typst_library::diag::{At, SourceResult}; use typst_library::diag::{warning, At, SourceResult};
use typst_library::foundations::{Content, NativeElement, Symbol, SymbolElem, Value}; use typst_library::foundations::{Content, NativeElement, Symbol, SymbolElem, Value};
use typst_library::math::{ use typst_library::math::{
AlignPointElem, AttachElem, FracElem, LrElem, PrimesElem, RootElem, AlignPointElem, AttachElem, FracElem, LrElem, PrimesElem, RootElem,
@ -80,7 +80,14 @@ impl Eval for ast::MathAttach<'_> {
let mut elem = AttachElem::new(base); let mut elem = AttachElem::new(base);
if let Some(expr) = self.top() { if let Some(expr) = self.top() {
elem.t.set(Some(expr.eval_display(vm)?)); let top = expr.eval(vm)?;
if let Value::Func(_) = top {
vm.engine.sink.warn(warning!(
expr.span(), "function literal used as superscript";
hint: "wrap the entire function call in parentheses",
));
}
elem.t.set(Some(top.display().spanned(self.span())));
} }
// Always attach primes in scripts style (not limits style), // Always attach primes in scripts style (not limits style),
@ -90,7 +97,14 @@ impl Eval for ast::MathAttach<'_> {
} }
if let Some(expr) = self.bottom() { if let Some(expr) = self.bottom() {
elem.b.set(Some(expr.eval_display(vm)?)); let bottom = expr.eval(vm)?;
if let Value::Func(_) = bottom {
vm.engine.sink.warn(warning!(
expr.span(), "function literal used as subscript";
hint: "wrap the entire function call in parentheses",
));
}
elem.b.set(Some(bottom.display().spanned(self.span())));
} }
Ok(elem.pack()) Ok(elem.pack())

View File

@ -797,7 +797,9 @@ impl Color {
components components
} }
/// Returns the constructor function for this color's space: /// Returns the constructor function for this color's space.
///
/// Returns one of:
/// - [`luma`]($color.luma) /// - [`luma`]($color.luma)
/// - [`oklab`]($color.oklab) /// - [`oklab`]($color.oklab)
/// - [`oklch`]($color.oklch) /// - [`oklch`]($color.oklch)

View File

@ -384,10 +384,10 @@ fn math_expr_prec(p: &mut Parser, min_prec: usize, stop: SyntaxKind) {
fn math_op(kind: SyntaxKind) -> Option<(SyntaxKind, SyntaxKind, ast::Assoc, usize)> { fn math_op(kind: SyntaxKind) -> Option<(SyntaxKind, SyntaxKind, ast::Assoc, usize)> {
match kind { match kind {
SyntaxKind::Underscore => { SyntaxKind::Underscore => {
Some((SyntaxKind::MathAttach, SyntaxKind::Hat, ast::Assoc::Right, 2)) Some((SyntaxKind::MathAttach, SyntaxKind::Hat, ast::Assoc::Right, 3))
} }
SyntaxKind::Hat => { SyntaxKind::Hat => {
Some((SyntaxKind::MathAttach, SyntaxKind::Underscore, ast::Assoc::Right, 2)) Some((SyntaxKind::MathAttach, SyntaxKind::Underscore, ast::Assoc::Right, 3))
} }
SyntaxKind::Slash => { SyntaxKind::Slash => {
Some((SyntaxKind::MathFrac, SyntaxKind::End, ast::Assoc::Left, 1)) Some((SyntaxKind::MathFrac, SyntaxKind::End, ast::Assoc::Left, 1))

View File

@ -242,7 +242,7 @@ fn category_page(resolver: &dyn Resolver, category: Category) -> PageModel {
items.push(CategoryItem { items.push(CategoryItem {
name: group.name.clone(), name: group.name.clone(),
route: subpage.route.clone(), route: subpage.route.clone(),
oneliner: oneliner(docs).into(), oneliner: oneliner(docs),
code: true, code: true,
}); });
children.push(subpage); children.push(subpage);
@ -296,7 +296,7 @@ fn category_page(resolver: &dyn Resolver, category: Category) -> PageModel {
items.push(CategoryItem { items.push(CategoryItem {
name: name.into(), name: name.into(),
route: subpage.route.clone(), route: subpage.route.clone(),
oneliner: oneliner(func.docs().unwrap_or_default()).into(), oneliner: oneliner(func.docs().unwrap_or_default()),
code: true, code: true,
}); });
children.push(subpage); children.push(subpage);
@ -306,7 +306,7 @@ fn category_page(resolver: &dyn Resolver, category: Category) -> PageModel {
items.push(CategoryItem { items.push(CategoryItem {
name: ty.short_name().into(), name: ty.short_name().into(),
route: subpage.route.clone(), route: subpage.route.clone(),
oneliner: oneliner(ty.docs()).into(), oneliner: oneliner(ty.docs()),
code: true, code: true,
}); });
children.push(subpage); children.push(subpage);
@ -637,7 +637,7 @@ fn group_page(
let item = CategoryItem { let item = CategoryItem {
name: group.name.clone(), name: group.name.clone(),
route: model.route.clone(), route: model.route.clone(),
oneliner: oneliner(&group.details).into(), oneliner: oneliner(&group.details),
code: false, code: false,
}; };
@ -772,8 +772,24 @@ pub fn urlify(title: &str) -> EcoString {
} }
/// Extract the first line of documentation. /// Extract the first line of documentation.
fn oneliner(docs: &str) -> &str { fn oneliner(docs: &str) -> EcoString {
docs.lines().next().unwrap_or_default() let paragraph = docs.split("\n\n").next().unwrap_or_default();
let mut depth = 0;
let mut period = false;
let mut end = paragraph.len();
for (i, c) in paragraph.char_indices() {
match c {
'(' | '[' | '{' => depth += 1,
')' | ']' | '}' => depth -= 1,
'.' if depth == 0 => period = true,
c if period && c.is_whitespace() && !docs[..i].ends_with("e.g.") => {
end = i;
break;
}
_ => period = false,
}
}
EcoString::from(&docs[..end]).replace("\r\n", " ").replace("\n", " ")
} }
/// The order of types in the documentation. /// The order of types in the documentation.

View File

@ -86,7 +86,7 @@ pub struct FuncModel {
pub name: EcoString, pub name: EcoString,
pub title: &'static str, pub title: &'static str,
pub keywords: &'static [&'static str], pub keywords: &'static [&'static str],
pub oneliner: &'static str, pub oneliner: EcoString,
pub element: bool, pub element: bool,
pub contextual: bool, pub contextual: bool,
pub deprecation: Option<&'static str>, pub deprecation: Option<&'static str>,
@ -139,7 +139,7 @@ pub struct TypeModel {
pub name: &'static str, pub name: &'static str,
pub title: &'static str, pub title: &'static str,
pub keywords: &'static [&'static str], pub keywords: &'static [&'static str],
pub oneliner: &'static str, pub oneliner: EcoString,
pub details: Html, pub details: Html,
pub constructor: Option<FuncModel>, pub constructor: Option<FuncModel>,
pub scope: Vec<FuncModel>, pub scope: Vec<FuncModel>,

View File

@ -127,6 +127,10 @@
checks = self'.checks; checks = self'.checks;
inputsFrom = [ typst ]; inputsFrom = [ typst ];
buildInputs = with pkgs; [
rust-analyzer
];
packages = [ packages = [
# A script for quickly running tests. # A script for quickly running tests.
# See https://github.com/typst/typst/blob/main/tests/README.md#making-an-alias # See https://github.com/typst/typst/blob/main/tests/README.md#making-an-alias

Binary file not shown.

After

Width:  |  Height:  |  Size: 927 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

View File

@ -34,7 +34,7 @@ $tilde(sum), tilde(sum, size: #50%), accent(H, hat, size: #200%)$
--- math-accent-sized-script --- --- math-accent-sized-script ---
// Test accent size in script size. // Test accent size in script size.
$tilde(U, size: #1.1em), x^tilde(U, size: #1.1em), sscript(tilde(U, size: #1.1em))$ $tilde(U, size: #1.1em), x^(tilde(U, size: #1.1em)), sscript(tilde(U, size: #1.1em))$
--- math-accent-dotless --- --- math-accent-dotless ---
// Test dotless glyph variants. // Test dotless glyph variants.

View File

@ -42,9 +42,41 @@ attach(a, tl: u, t: t, tr: v, bl: x, b: b, br: y)
$ $
--- math-attach-followed-by-func-call --- --- math-attach-followed-by-func-call ---
// Test function call after subscript. // Test function call after subscripts and superscripts.
$pi_1(Y), a_f(x), a^zeta (x), a^abs(b)_sqrt(c) \ #set page(width: auto)
a^subset.eq (x), a_(zeta(x)), pi_(1(Y)), a^(abs(b))_(sqrt(c))$ $a_1(x), a^10(x), a_f(x), a^zeta(x), a_"text"(x),
// Warning: 22-25 function literal used as subscript
// Hint: 22-25 wrap the entire function call in parentheses
// Warning: 32-36 function literal used as superscript
// Hint: 32-36 wrap the entire function call in parentheses
a_∂(x), a^cos(x), a_abs(x), a^root(2, x), a_subset.eq(x) \
a_(1(x)), a^(10(x)), a_(f(x)), a^(zeta(x)), a_("text"(x)),
a_(∂(x)), a^(cos(x)), a_(abs(x)), a^(root(2, x)), a_(subset.eq(x))$
--- math-attach-followed-by-func-call-complex ---
// Test function call with named arguments after scripts.
#let cross = $c$
// Warning: 4-10 function literal used as subscript
// Hint: 4-10 wrap the entire function call in parentheses
$a_cancel(x, cross: #true)$
--- math-attach-followed-by-func-call-error ---
// Error: 14-19 unknown variable: cross
// Hint: 14-19 if you meant to display multiple letters as is, try adding spaces between each letter: `c r o s s`
// Hint: 14-19 or if you meant to display this as text, try placing it in quotes: `"cross"`
// Warning: 4-10 function literal used as subscript
// Hint: 4-10 wrap the entire function call in parentheses
$a_cancel(x, cross: #true)$
--- math-attach-followed-by-func-call-warning ---
// Test warning for function literal as subscripts and superscripts.
#let myfunc(arg) = $arg$
// Warning: 4-10 function literal used as subscript
// Hint: 4-10 wrap the entire function call in parentheses
$a_myfunc(x) a_(myfunc(x))$
// Warning: 4-10 function literal used as subscript
// Hint: 4-10 wrap the entire function call in parentheses
$a_myfunc a_(myfunc)$
--- math-attach-nested --- --- math-attach-nested ---
// Test associativity and scaling. // Test associativity and scaling.

View File

@ -215,7 +215,7 @@ box[]
hello.world hello.world
hello.world() hello.world()
hello.my.world() hello.my.world()
f_zeta(x), f_zeta(x)/1 f_(zeta(x)), f_(zeta(x))/1
emph(hello.my.world()) emph(hello.my.world())
emph(hello.my().world) emph(hello.my().world)
emph(hello.my().world()) emph(hello.my().world())