mirror of
https://github.com/typst/typst
synced 2025-07-30 07:47:55 +08:00
Compare commits
6 Commits
a985817c16
...
28897e5e28
Author | SHA1 | Date | |
---|---|---|---|
|
28897e5e28 | ||
|
b790c6d59c | ||
|
b1c79b50d4 | ||
|
4629ede020 | ||
|
53d13bae36 | ||
|
7057809e23 |
@ -174,7 +174,10 @@ 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
|
||||||
|
@ -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())
|
||||||
|
@ -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)
|
||||||
|
@ -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))
|
||||||
|
@ -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.
|
||||||
|
@ -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>,
|
||||||
|
@ -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
|
||||||
|
BIN
tests/ref/math-attach-followed-by-func-call-complex.png
Normal file
BIN
tests/ref/math-attach-followed-by-func-call-complex.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 927 B |
BIN
tests/ref/math-attach-followed-by-func-call-warning.png
Normal file
BIN
tests/ref/math-attach-followed-by-func-call-warning.png
Normal file
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 |
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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())
|
||||||
|
Loading…
x
Reference in New Issue
Block a user