fix: correct hover docs generated by typlite (#1761)

* fix: annotate fn

* fix(typlite): duplicate docs description (#1799)

* fix: avoid duplicate docs description

* fix: clippy error

* test: flat repr of hover snapshots

* g

* test: update snapshots

---------

Co-authored-by: Myriad-Dreamin <camiyoru@gmail.com>

* test: update snapshot

---------

Co-authored-by: Hong Jiarong <me@jrhim.com>
This commit is contained in:
Myriad-Dreamin 2025-06-07 09:14:20 +08:00 committed by GitHub
parent ae99016cd9
commit 3d24320674
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
42 changed files with 1386 additions and 217 deletions

View file

@ -122,6 +122,7 @@ pub fn identify_pat_docs(converted: &str) -> StrResult<TidyPatDocs> {
default: None,
docs: buf.into_iter().join("\n").into(),
});
break_line = Some(line_width);
break;
}
@ -306,16 +307,14 @@ See show-module() for outputting the results of this function.
#[test]
fn test_identify_tidy_docs4() {
insta::assert_snapshot!(var(r###"
- <!-- typlite:begin:list-item 0 -->name (string): The name for the module.<!-- typlite:end:list-item 0 -->
-> string"###), @r"
insta::assert_snapshot!(func(r###"
- <!-- typlite:begin:list-item 0 -->fn (function, fn): The `fn`.<!-- typlite:end:list-item 0 -->"###), @r"
>> docs:
- <!-- typlite:begin:list-item 0 -->name (string): The name for the module.<!-- typlite:end:list-item 0 -->
<< docs
>>return
string
<<return
>>arg fn: function, fn
The `fn`.
<< arg
");
}
}

View file

@ -125,7 +125,7 @@ fn malform(e: io::Error) -> PackageError {
}
fn other_io(e: impl Display) -> io::Error {
io::Error::new(io::ErrorKind::Other, e.to_string())
io::Error::other(e.to_string())
}
fn other(e: impl Display) -> PackageError {

View file

@ -50,10 +50,7 @@ fn clone(url: &str, dst: &Path) -> io::Result<()> {
cmd.arg("clone").arg(url).arg(dst);
let status = cmd.status()?;
if !status.success() {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("git clone failed: {status}"),
));
return Err(io::Error::other(format!("git clone failed: {status}")));
}
Ok(())
}

View file

@ -479,7 +479,7 @@ impl<'a> CodeActionWorker<'a> {
static IS_PUNCTUATION: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"\p{Punctuation}").unwrap());
(ch.is_ascii_punctuation()
&& ch_next.map_or(true, |ch_next| !ch_next.is_ascii_punctuation()))
&& ch_next.is_none_or(|ch_next| !ch_next.is_ascii_punctuation()))
|| (!ch.is_ascii_punctuation() && IS_PUNCTUATION.is_match(&ch.to_string()))
});
let punc_modify = if let Some((nx, _)) = mark_after_equation {

View file

@ -119,7 +119,7 @@ impl SemanticRequest for InteractCodeContextRequest {
.collect::<Vec<_>>();
cursor_styles.sort_by_key(|x| x.as_slice().len());
log::info!("style at styles {cursor_styles:?} . {style:?}");
let cursor_style = cursor_styles.into_iter().last().unwrap_or_default();
let cursor_style = cursor_styles.into_iter().next_back().unwrap_or_default();
let cursor_style = StyleChain::new(&cursor_style);
log::info!("style at style {cursor_style:?} . {style:?}");

View file

@ -1,9 +1,39 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/annotate_dict_param.typ
---
{
"contents": "```typc\nlet show-example(\n ..options: arguments,\n inherited-scope: dictionary = (:),\n) = none;\n```\n\n---\n\n- <!-- typlite:begin:list-item 0 -->inherited-scope (dictionary): Definitions that are made available to the entire parsed module. This parameter is only used internally.<!-- typlite:end:list-item 0 -->\n\n# Rest Parameters\n\n## options\n\n```typc\ntype: arguments\n```\n\n\n\n# Named Parameters\n\n## inherited-scope\n\n```typc\ntype: dictionary\n```\n\nDefinitions that are made available to the entire parsed module. This parameter is only used internally.",
"range": "7:20:7:32"
}
Range: 7:20:7:32
```typc
let show-example(
..options: arguments,
inherited-scope: dictionary = (:),
) = none;
```
======
# Rest Parameters
## options
```typc
type: arguments
```
# Named Parameters
## inherited-scope
```typc
type: dictionary
```
Definitions that are made available to the entire parsed module. This parameter is only used internally.

View file

@ -1,9 +1,16 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/annotate_dict_param2.typ
---
{
"contents": "```typc\nlet inherited-scope = dictionary;\n```\n\n---\n\nDefinitions that are made available to the entire parsed module. This parameter is only used internally.",
"range": "6:21:6:36"
}
Range: 6:21:6:36
```typc
let inherited-scope = dictionary;
```
======
Definitions that are made available to the entire parsed module. This parameter is only used internally.

View file

@ -1,9 +1,50 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/annotate_docs_error.typ
---
{
"contents": "```typc\nlet speaker-note(\n note: any,\n mode: str = \"typ\",\n setting: (any) => any = Closure(..),\n) = none;\n```\n\n---\n\nSpeaker notes are a way to add additional information to your slides that is not visible to the audience. This can be useful for providing additional context or reminders to yourself.\n\n### Example\n\nThis is a speaker note\n\n# Positional Parameters\n\n## note\n\n```typc\ntype: \n```\n\n\n\n# Named Parameters\n\n## mode\n\n```typc\ntype: \"typ\"\n```\n\n\n\n## setting (named)\n\n```typc\ntype: (any) => any\n```\n\n",
"range": "12:20:12:32"
}
Range: 12:20:12:32
```typc
let speaker-note(
note: any,
mode: str = "typ",
setting: (any) => any = Closure(..),
) = none;
```
======
Speaker notes are a way to add additional information to your slides that is not visible to the audience. This can be useful for providing additional context or reminders to yourself.
### Example
This is a speaker note
# Positional Parameters
## note
```typc
type:
```
# Named Parameters
## mode
```typc
type: "typ"
```
## setting (named)
```typc
type: (any) => any
```

View file

@ -1,9 +1,59 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/annotate_fn.typ
---
{
"contents": "```typc\nlet touying-fn-wrapper(\n fn: (..: any) => any | function,\n ..args: arguments,\n max-repetitions: int | none = none,\n repetitions: int | none = none,\n) = none;\n```\n\n---\n\n- <!-- typlite:begin:list-item 0 -->fn (function, fn): The `fn`.<!-- typlite:end:list-item 0 -->\n- <!-- typlite:begin:list-item 0 -->max-repetitions (int): The `max-repetitions`.<!-- typlite:end:list-item 0 -->\n- <!-- typlite:begin:list-item 0 -->repetitions (int): The `repetitions`.<!-- typlite:end:list-item 0 -->\n- <!-- typlite:begin:list-item 0 -->args (any, fn-args): The `args`.<!-- typlite:end:list-item 0 -->\n\n# Positional Parameters\n\n## fn\n\n```typc\ntype: (..: any) => any | function\n```\n\nThe `fn`.\n\n# Rest Parameters\n\n## args\n\n```typc\ntype: arguments\n```\n\nThe `args`.\n\n# Named Parameters\n\n## max-repetitions\n\n```typc\ntype: int | none\n```\n\nThe `max-repetitions`.\n\n## repetitions (named)\n\n```typc\ntype: int | none\n```\n\nThe `repetitions`.",
"range": "8:20:8:38"
}
Range: 8:20:8:38
```typc
let touying-fn-wrapper(
fn: (..: any) => any | function,
..args: arguments,
max-repetitions: int | none = none,
repetitions: int | none = none,
) = none;
```
======
# Positional Parameters
## fn
```typc
type: (..: any) => any | function
```
The `fn`.
# Rest Parameters
## args
```typc
type: arguments
```
The `args`.
# Named Parameters
## max-repetitions
```typc
type: int | none
```
The `max-repetitions`.
## repetitions (named)
```typc
type: int | none
```
The `repetitions`.

View file

@ -1,10 +1,26 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/annotate_ret.typ
snapshot_kind: text
---
{
"contents": "```typc\nlet _delayed-wrapper(\n body: any,\n) = content;\n```\n\n---\n\n\n\n# Positional Parameters\n\n## body\n\n```typc\ntype: \n```\n\n",
"range": "6:20:6:36"
}
Range: 6:20:6:36
```typc
let _delayed-wrapper(
body: any,
) = content;
```
======
# Positional Parameters
## body
```typc
type:
```

File diff suppressed because one or more lines are too long

View file

@ -1,10 +1,19 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/builtin_module.typ
snapshot_kind: text
---
{
"contents": "```typc\nlet sys;\n```\n\n---\n\n### Sampled Values\n```typc\n<module sys>\n```",
"range": "0:20:0:23"
}
Range: 0:20:0:23
```typc
let sys;
```
======
### Sampled Values
```typc
<module sys>
```

View file

@ -1,10 +1,11 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/builtin_var.typ
snapshot_kind: text
---
{
"contents": "### Sampled Values\n```typc\nrgb(\"#ff4136\")\n```",
"range": "0:20:0:23"
}
Range: 0:20:0:23
### Sampled Values
```typc
rgb("#ff4136")
```

View file

@ -1,10 +1,19 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/builtin_var2.typ
snapshot_kind: text
---
{
"contents": "```typc\nlet sys;\n```\n\n---\n\n### Sampled Values\n```typc\n<module sys>\n```",
"range": "0:20:0:23"
}
Range: 0:20:0:23
```typc
let sys;
```
======
### Sampled Values
```typc
<module sys>
```

View file

@ -1,10 +1,19 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/builtin_var3.typ
snapshot_kind: text
---
{
"contents": "```typc\nlet sys;\n```\n\n---\n\n### Sampled Values\n```typc\n<module sys>\n```",
"range": "0:2:0:5"
}
Range: 0:2:0:5
```typc
let sys;
```
======
### Sampled Values
```typc
<module sys>
```

View file

@ -1,9 +1,112 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/cases_doc.typ
---
{
"contents": "```typc\nlet cases(\n ..children: content,\n delim: array | none | str | symbol = (\"{\", \"}\"),\n gap: relative = 0% + 0.2em,\n reverse: bool = false,\n);\n```\n\n---\n\nA case distinction.\n\nContent across different branches can be aligned with the `&` symbol.\n\n# Example\n```typ\n$ f(x, y) := cases(\n 1 \"if\" (x dot y)/2 <= 0,\n 2 \"if\" x \"is even\",\n 3 \"if\" x in NN,\n 4 \"else\",\n) $\n```\n\n---\n\nA case distinction.\n\nContent across different branches can be aligned with the `&` symbol.\n\n# Example\n```typ\n$ f(x, y) := cases(\n 1 \"if\" (x dot y)/2 <= 0,\n 2 \"if\" x \"is even\",\n 3 \"if\" x in NN,\n 4 \"else\",\n) $\n```\n\n# Rest Parameters\n\n## children\n\n```typc\ntype: content\n```\n\nThe branches of the case distinction.\n\n# Named Parameters\n\n## delim\n\n```typc\ntype: array | none | str | symbol\n```\n\nThe delimiter to use.\n\nCan be a single character specifying the left delimiter, in which case\nthe right delimiter is inferred. Otherwise, can be an array containing a\nleft and a right delimiter.\n\n```typ\n#set math.cases(delim: \"[\")\n$ x = cases(1, 2) $\n```\n\n## gap (named)\n\n```typc\ntype: relative\n```\n\nThe gap between branches.\n\n```typ\n#set math.cases(gap: 1em)\n$ x = cases(1, 2) $\n```\n\n## reverse (named)\n\n```typc\ntype: bool\n```\n\nWhether the direction of cases should be reversed.\n\n```typ\n#set math.cases(reverse: true)\n$ cases(1, 2) = x $\n```\n\n---\n\n[Open docs](https://typst.app/docs/reference/math/cases/)",
"range": "0:20:0:25"
}
Range: 0:20:0:25
```typc
let cases(
..children: content,
delim: array | none | str | symbol = ("{", "}"),
gap: relative = 0% + 0.2em,
reverse: bool = false,
);
```
======
A case distinction.
Content across different branches can be aligned with the `&` symbol.
# Example
```typ
$ f(x, y) := cases(
1 "if" (x dot y)/2 <= 0,
2 "if" x "is even",
3 "if" x in NN,
4 "else",
) $
```
======
A case distinction.
Content across different branches can be aligned with the `&` symbol.
# Example
```typ
$ f(x, y) := cases(
1 "if" (x dot y)/2 <= 0,
2 "if" x "is even",
3 "if" x in NN,
4 "else",
) $
```
# Rest Parameters
## children
```typc
type: content
```
The branches of the case distinction.
# Named Parameters
## delim
```typc
type: array | none | str | symbol
```
The delimiter to use.
Can be a single character specifying the left delimiter, in which case
the right delimiter is inferred. Otherwise, can be an array containing a
left and a right delimiter.
```typ
#set math.cases(delim: "[")
$ x = cases(1, 2) $
```
## gap (named)
```typc
type: relative
```
The gap between branches.
```typ
#set math.cases(gap: 1em)
$ x = cases(1, 2) $
```
## reverse (named)
```typc
type: bool
```
Whether the direction of cases should be reversed.
```typ
#set math.cases(reverse: true)
$ cases(1, 2) = x $
```
======
[Open docs](https://typst.app/docs/reference/math/cases/)

View file

@ -1,9 +1,11 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/content_field.typ
---
{
"contents": "### Sampled Values\n```typc\n\"A\"\n```",
"range": "2:23:2:27"
}
Range: 2:23:2:27
### Sampled Values
```typc
"A"
```

View file

@ -1,9 +1,14 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/label_bib.typ
---
{
"contents": "Bibliography: `Russell:1908` [1]\n\n---\n\nB. Russell, Mathematical logic based on the theory of types, <span style=\"font-style: italic;\">American Journal of Mathematics</span>, 30, 222262, 1908.",
"range": "2:26:2:40"
}
Range: 2:26:2:40
Bibliography: `Russell:1908` [1]
======
B. Russell, Mathematical logic based on the theory of types, <span style="font-style: italic;">American Journal of Mathematics</span>, 30, 222262, 1908.

View file

@ -1,9 +1,14 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/label_bib_no_html.typ
---
{
"contents": "Bibliography: `Russell:1908` [1]\n\n---\n\nB. Russell, Mathematical logic based on the theory of types, American Journal of Mathematics, 30, 222262, 1908.",
"range": "3:26:3:40"
}
Range: 3:26:3:40
Bibliography: `Russell:1908` [1]
======
B. Russell, Mathematical logic based on the theory of types, American Journal of Mathematics, 30, 222262, 1908.

View file

@ -1,9 +1,8 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/label_figure.typ
---
{
"contents": "Label: `fig:test1`\n",
"range": "3:37:3:48"
}
Range: 3:37:3:48
Label: `fig:test1`

View file

@ -1,9 +1,8 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/label_heading.typ
---
{
"contents": "Label: `head`\n",
"range": "3:25:3:31"
}
Range: 3:25:3:31
Label: `head`

View file

@ -1,9 +1,34 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/literal_method.typ
---
{
"contents": "```typc\nlet clusters(\n self: str,\n) = array;\n```\n\n---\n\nReturns the grapheme clusters of the string as an array of substrings.\n\n# Positional Parameters\n\n## self\n\n```typc\ntype: str\n```\n\n\n\n---\n\n[Open docs](https://typst.app/docs/reference/foundations/str/#definitions-clusters)",
"range": "0:23:0:31"
}
Range: 0:23:0:31
```typc
let clusters(
self: str,
) = array;
```
======
Returns the grapheme clusters of the string as an array of substrings.
# Positional Parameters
## self
```typc
type: str
```
======
[Open docs](https://typst.app/docs/reference/foundations/str/#definitions-clusters)

View file

@ -1,9 +1,34 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/literal_method2.typ
---
{
"contents": "```typc\nlet len(\n self: array,\n) = int;\n```\n\n---\n\nThe number of values in the array.\n\n# Positional Parameters\n\n## self\n\n```typc\ntype: array\n```\n\n\n\n---\n\n[Open docs](https://typst.app/docs/reference/foundations/array/#definitions-len)",
"range": "0:22:0:25"
}
Range: 0:22:0:25
```typc
let len(
self: array,
) = int;
```
======
The number of values in the array.
# Positional Parameters
## self
```typc
type: array
```
======
[Open docs](https://typst.app/docs/reference/foundations/array/#definitions-len)

View file

@ -1,9 +1,17 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/module_alias.typ
---
{
"contents": "### Sampled Values\n```typc\n<module themod>\n```\n\n---\n\n## The Module (Alias)\n",
"range": "2:24:2:31"
}
Range: 2:24:2:31
### Sampled Values
```typc
<module themod>
```
======
## The Module (Alias)

View file

@ -1,9 +1,8 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/module_path.typ
---
{
"contents": "## Some Module\n",
"range": "0:29:0:46"
}
Range: 0:29:0:46
## Some Module

View file

@ -1,10 +1,17 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/module_star.typ
snapshot_kind: text
---
{
"contents": "This star imports line\n\n---\n\n### Sampled Values\n```typc\nnone\n```",
"range": "0:41:0:42"
}
Range: 0:41:0:42
This star imports line
======
### Sampled Values
```typc
none
```

View file

@ -1,10 +1,16 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/module_star_const_eval.typ
snapshot_kind: text
---
{
"contents": "```typc\nlet line() = int;\n```\n\n---\n\nThe draw line.",
"range": "2:23:2:27"
}
Range: 2:23:2:27
```typc
let line() = int;
```
======
The draw line.

View file

@ -1,10 +1,16 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/module_star_rename.typ
snapshot_kind: text
---
{
"contents": "```typc\nlet line() = int;\n```\n\n---\n\nThe draw line.",
"range": "3:23:3:27"
}
Range: 3:23:3:27
```typc
let line() = int;
```
======
The draw line.

View file

@ -1,10 +1,16 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/module_star_shadow.typ
snapshot_kind: text
---
{
"contents": "```typc\nlet line() = int;\n```\n\n---\n\nThe draw line.",
"range": "2:23:2:27"
}
Range: 2:23:2:27
```typc
let line() = int;
```
======
The draw line.

View file

@ -1,9 +1,17 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/module_var.typ
---
{
"contents": "### Sampled Values\n```typc\n<module themod>\n```\n\n---\n\n## The Module\n",
"range": "2:24:2:30"
}
Range: 2:24:2:30
### Sampled Values
```typc
<module themod>
```
======
## The Module

View file

@ -1,10 +1,83 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/pagebreak.typ
snapshot_kind: text
---
{
"contents": "```typc\nlet pagebreak(\n to: none | str = none,\n weak: bool = false,\n);\n```\n\n---\n\nA manual page break.\n\nMust not be used inside any containers.\n\n# Example\n```typ\nThe next page contains\nmore details on compound theory.\n#pagebreak()\n\n== Compound Theory\nIn 1984, the first ...\n```\n\n---\n\nA manual page break.\n\nMust not be used inside any containers.\n\n# Example\n```typ\nThe next page contains\nmore details on compound theory.\n#pagebreak()\n\n== Compound Theory\nIn 1984, the first ...\n```\n\n# Named Parameters\n\n## to\n\n```typc\ntype: \"even\" | \"odd\" | none\n```\n\nIf given, ensures that the next page will be an even/odd page, with an\nempty page in between if necessary.\n\n```typ\n#set page(height: 30pt)\n\nFirst.\n#pagebreak(to: \"odd\")\nThird.\n```\n\n## weak (named)\n\n```typc\ntype: bool\n```\n\nIf `true`, the page break is skipped if the current page is already\nempty.\n\n---\n\n[Open docs](https://typst.app/docs/reference/layout/pagebreak/)",
"range": "0:20:0:29"
}
Range: 0:20:0:29
```typc
let pagebreak(
to: none | str = none,
weak: bool = false,
);
```
======
A manual page break.
Must not be used inside any containers.
# Example
```typ
The next page contains
more details on compound theory.
#pagebreak()
== Compound Theory
In 1984, the first ...
```
======
A manual page break.
Must not be used inside any containers.
# Example
```typ
The next page contains
more details on compound theory.
#pagebreak()
== Compound Theory
In 1984, the first ...
```
# Named Parameters
## to
```typc
type: "even" | "odd" | none
```
If given, ensures that the next page will be an even/odd page, with an
empty page in between if necessary.
```typ
#set page(height: 30pt)
First.
#pagebreak(to: "odd")
Third.
```
## weak (named)
```typc
type: bool
```
If `true`, the page break is skipped if the current page is already
empty.
======
[Open docs](https://typst.app/docs/reference/layout/pagebreak/)

View file

@ -1,10 +1,16 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/param.typ
snapshot_kind: text
---
{
"contents": "```typc\nlet param = int;\n```\n\n---\n\nThe `parameter`.",
"range": "3:25:3:30"
}
Range: 3:25:3:30
```typc
let param = int;
```
======
The `parameter`.

View file

@ -1,9 +1,14 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/ref_bib.typ
---
{
"contents": "Bibliography: `Russell:1908` [1]\n\n---\n\nB. Russell, Mathematical logic based on the theory of types, <span style=\"font-style: italic;\">American Journal of Mathematics</span>, 30, 222262, 1908.",
"range": "2:21:2:34"
}
Range: 2:21:2:34
Bibliography: `Russell:1908` [1]
======
B. Russell, Mathematical logic based on the theory of types, <span style="font-style: italic;">American Journal of Mathematics</span>, 30, 222262, 1908.

View file

@ -1,9 +1,14 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/ref_bib_no_html.typ
---
{
"contents": "Bibliography: `Russell:1908` [1]\n\n---\n\nB. Russell, Mathematical logic based on the theory of types, American Journal of Mathematics, 30, 222262, 1908.",
"range": "3:21:3:34"
}
Range: 3:21:3:34
Bibliography: `Russell:1908` [1]
======
B. Russell, Mathematical logic based on the theory of types, American Journal of Mathematics, 30, 222262, 1908.

View file

@ -1,9 +1,28 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/ref_figure.typ
---
{
"contents": "Ref: `fig:test1`\n\n\n---\n\n```typc\nfigure(\n body: [Test1],\n placement: none,\n scope: \"column\",\n caption: none,\n kind: image,\n supplement: [Figure],\n numbering: \"1\",\n gap: 0.65em,\n outlined: true,\n counter: counter(figure.where(kind: image)),\n)\n```",
"range": "4:21:4:31"
}
Range: 4:21:4:31
Ref: `fig:test1`
======
```typc
figure(
body: [Test1],
placement: none,
scope: "column",
caption: none,
kind: image,
supplement: [Figure],
numbering: "1",
gap: 0.65em,
outlined: true,
counter: counter(figure.where(kind: image)),
)
```

View file

@ -1,9 +1,8 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/ref_heading.typ
---
{
"contents": "Label: `head`\n",
"range": "3:25:3:31"
}
Range: 3:25:3:31
Label: `head`

View file

@ -1,9 +1,43 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/render_equation.typ
---
{
"contents": "```typc\nlet lam(\n A: type,\n B: type,\n) = dictionary;\n```\n\n---\n\nLambda constructor.\n\nTyping Rule:\n\n<p align=\"center\"><img alt=\"typst-block\" src=\"data:image-hash/svg+xml;base64,redacted\" /></p>\n\n# Positional Parameters\n\n## A\n\n```typc\ntype: type\n```\n\nThe type of the argument.\n - <!-- typlite:begin:list-item 1 -->It can be also regarded as the condition of the proposition.<!-- typlite:end:list-item 1 -->\n\n## B (positional)\n\n```typc\ntype: type\n```\n\nThe type of the body.\n - <!-- typlite:begin:list-item 1 -->It can be also regarded as the conclusion of the proposition.<!-- typlite:end:list-item 1 -->",
"range": "12:20:12:23"
}
Range: 12:20:12:23
```typc
let lam(
A: type,
B: type,
) = dictionary;
```
======
Lambda constructor.
Typing Rule:
<p align="center"><img alt="typst-block" src="data:image-hash/svg+xml;base64,redacted" /></p>
# Positional Parameters
## A
```typc
type: type
```
The type of the argument.
- <!-- typlite:begin:list-item 1 -->It can be also regarded as the condition of the proposition.<!-- typlite:end:list-item 1 -->
## B (positional)
```typc
type: type
```
The type of the body.
- <!-- typlite:begin:list-item 1 -->It can be also regarded as the conclusion of the proposition.<!-- typlite:end:list-item 1 -->

View file

@ -1,10 +1,43 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/render_equation_no_html.typ
snapshot_kind: text
---
{
"contents": "```typc\nlet lam(\n A: type,\n B: type,\n) = dictionary;\n```\n\n---\n\nLambda constructor.\n\nTyping Rule:\n\nΓ,x:A⊢M:BΓ⊢a:BΓ⊢λ(x:A)→M:π(x:A)→B\n\n# Positional Parameters\n\n## A\n\n```typc\ntype: type\n```\n\nThe type of the argument.\n - It can be also regarded as the condition of the proposition.\n\n## B (positional)\n\n```typc\ntype: type\n```\n\nThe type of the body.\n - It can be also regarded as the conclusion of the proposition.",
"range": "14:20:14:23"
}
Range: 14:20:14:23
```typc
let lam(
A: type,
B: type,
) = dictionary;
```
======
Lambda constructor.
Typing Rule:
Γ,x:A⊢M:BΓ⊢a:BΓ⊢λ(x:A)→M:π(x:A)→B
# Positional Parameters
## A
```typc
type: type
```
The type of the argument.
- It can be also regarded as the condition of the proposition.
## B (positional)
```typc
type: type
```
The type of the body.
- It can be also regarded as the conclusion of the proposition.

View file

@ -1,10 +1,16 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/user.typ
snapshot_kind: text
---
{
"contents": "```typc\nlet f() = int;\n```\n\n---\n\nTest",
"range": "3:20:3:21"
}
Range: 3:20:3:21
```typc
let f() = int;
```
======
Test

View file

@ -1,9 +1,184 @@
---
source: crates/tinymist-query/src/hover.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
expression: content
input_file: crates/tinymist-query/src/fixtures/hover/value_repr.typ
---
{
"contents": "```typc\nlet f(\n x: any,\n y: any,\n z: any,\n w01: int = 1,\n w02: str = \"test\",\n w03: any = 1 + 2,\n w04: any = Label(test),\n w05: (content | none, baseline: relative, clip: bool, fill: color, height: auto | relative, inset: inset, outset: outset, radius: radius, stroke: stroke, width: auto | fraction | relative) => box = (content | none, baseline: relative, clip: bool, fill: color, height: auto | relative, inset: inset, outset: outset, radius: radius, stroke: stroke, width: auto | fraction | relative) => box,\n w06: (content) => item | any = (body-indent: length, indent: length, marker: array | content | function, spacing: auto | length, tight: bool, ..: content) => list.item,\n w07: text = Expr(..),\n w08: any = Expr(..),\n w09: any = 1 + 2,\n w10: array = (\n 1,\n 2,\n ),\n w11: array = (),\n w12: dictionary = (:),\n w13: dictionary = (a: 1),\n w14: dictionary = (a: (content | none, baseline: relative, clip: bool, fill: color, height: auto | relative, inset: inset, outset: outset, radius: radius, stroke: stroke, width: auto | fraction | relative) => box),\n w15: dictionary = (a: (body-indent: length, indent: length, marker: array | content | function, spacing: auto | length, tight: bool, ..: content) => list.item),\n) = int;\n```\n\n---\n\n\n\n# Positional Parameters\n\n## x\n\n```typc\ntype: \n```\n\n\n\n## y (positional)\n\n```typc\ntype: \n```\n\n\n\n## z (positional)\n\n```typc\ntype: \n```\n\n\n\n# Named Parameters\n\n## w01\n\n```typc\ntype: 1\n```\n\n\n\n## w02 (named)\n\n```typc\ntype: \"test\"\n```\n\n\n\n## w03 (named)\n\n```typc\ntype: any\n```\n\n\n\n## w04 (named)\n\n```typc\ntype: \n```\n\n\n\n## w05 (named)\n\n```typc\ntype: (content | none, baseline: relative, clip: bool, fill: color, height: auto | relative, inset: inset, outset: outset, radius: radius, stroke: stroke, width: auto | fraction | relative) => box\n```\n\n\n\n## w06 (named)\n\n```typc\ntype: (content) => item | any\n```\n\n\n\n## w07 (named)\n\n```typc\ntype: text\n```\n\n\n\n## w08 (named)\n\n```typc\ntype: any\n```\n\n\n\n## w09 (named)\n\n```typc\ntype: any\n```\n\n\n\n## w10 (named)\n\n```typc\ntype: array\n```\n\n\n\n## w11 (named)\n\n```typc\ntype: array\n```\n\n\n\n## w12 (named)\n\n```typc\ntype: dictionary\n```\n\n\n\n## w13 (named)\n\n```typc\ntype: dictionary\n```\n\n\n\n## w14 (named)\n\n```typc\ntype: dictionary\n```\n\n\n\n## w15 (named)\n\n```typc\ntype: dictionary\n```\n\n",
"range": "23:20:23:21"
}
Range: 23:20:23:21
```typc
let f(
x: any,
y: any,
z: any,
w01: int = 1,
w02: str = "test",
w03: any = 1 + 2,
w04: any = Label(test),
w05: (content | none, baseline: relative, clip: bool, fill: color, height: auto | relative, inset: inset, outset: outset, radius: radius, stroke: stroke, width: auto | fraction | relative) => box = (content | none, baseline: relative, clip: bool, fill: color, height: auto | relative, inset: inset, outset: outset, radius: radius, stroke: stroke, width: auto | fraction | relative) => box,
w06: (content) => item | any = (body-indent: length, indent: length, marker: array | content | function, spacing: auto | length, tight: bool, ..: content) => list.item,
w07: text = Expr(..),
w08: any = Expr(..),
w09: any = 1 + 2,
w10: array = (
1,
2,
),
w11: array = (),
w12: dictionary = (:),
w13: dictionary = (a: 1),
w14: dictionary = (a: (content | none, baseline: relative, clip: bool, fill: color, height: auto | relative, inset: inset, outset: outset, radius: radius, stroke: stroke, width: auto | fraction | relative) => box),
w15: dictionary = (a: (body-indent: length, indent: length, marker: array | content | function, spacing: auto | length, tight: bool, ..: content) => list.item),
) = int;
```
======
# Positional Parameters
## x
```typc
type:
```
## y (positional)
```typc
type:
```
## z (positional)
```typc
type:
```
# Named Parameters
## w01
```typc
type: 1
```
## w02 (named)
```typc
type: "test"
```
## w03 (named)
```typc
type: any
```
## w04 (named)
```typc
type:
```
## w05 (named)
```typc
type: (content | none, baseline: relative, clip: bool, fill: color, height: auto | relative, inset: inset, outset: outset, radius: radius, stroke: stroke, width: auto | fraction | relative) => box
```
## w06 (named)
```typc
type: (content) => item | any
```
## w07 (named)
```typc
type: text
```
## w08 (named)
```typc
type: any
```
## w09 (named)
```typc
type: any
```
## w10 (named)
```typc
type: array
```
## w11 (named)
```typc
type: array
```
## w12 (named)
```typc
type: dictionary
```
## w13 (named)
```typc
type: dictionary
```
## w14 (named)
```typc
type: dictionary
```
## w15 (named)
```typc
type: dictionary
```

View file

@ -430,7 +430,57 @@ mod tests {
};
let result = request.request(ctx, graph);
assert_snapshot!(JsonRepr::new_redacted(result, &REDACT_LOC));
let content = HoverDisplay(result.as_ref())
.to_string()
.replace("\n---\n", "\n\n======\n\n");
let content = JsonRepr::md_content(&content);
assert_snapshot!(content);
});
}
struct HoverDisplay<'a>(Option<&'a Hover>);
impl fmt::Display for HoverDisplay<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Some(Hover { range, contents }) = self.0 else {
return write!(f, "No hover information");
};
// write range
if let Some(range) = range {
writeln!(f, "Range: {}\n", JsonRepr::range(range))?;
} else {
writeln!(f, "No range")?;
};
// write contents
match contents {
HoverContents::Markup(content) => {
writeln!(f, "{}", content.value)?;
}
HoverContents::Scalar(MarkedString::String(content)) => {
writeln!(f, "{content}")?;
}
HoverContents::Scalar(MarkedString::LanguageString(lang_str)) => {
writeln!(f, "=== {} ===\n{}", lang_str.language, lang_str.value)?
}
HoverContents::Array(contents) => {
// interperse the contents with a divider
let content = contents
.iter()
.map(|content| match content {
MarkedString::String(text) => text.to_string(),
MarkedString::LanguageString(lang_str) => {
format!("=== {} ===\n{}", lang_str.language, lang_str.value)
}
})
.collect::<Vec<_>>()
.join("\n\n=====\n\n");
writeln!(f, "{content}")?;
}
}
Ok(())
}
}
}

View file

@ -242,7 +242,7 @@ fn match_by_pos(mut n: LinkedNode, prev: bool, ident: bool) -> usize {
.find(|n| matches!(n.kind(), SyntaxKind::Ident))
.unwrap();
} else {
n = n.children().last().unwrap();
n = n.children().next_back().unwrap();
}
continue;
}
@ -331,6 +331,25 @@ impl JsonRepr {
let s = serde_json::to_value(v).unwrap();
Self(rm.redact(s))
}
pub fn md_content(v: &str) -> Cow<'_, str> {
static REG: LazyLock<regex::Regex> =
LazyLock::new(|| regex::Regex::new(r#"data:image/svg\+xml;base64,([^"]+)"#).unwrap());
let v = REG.replace_all(v, |_captures: &regex::Captures| {
"data:image-hash/svg+xml;base64,redacted"
});
v
}
pub fn range(v: impl serde::Serialize) -> String {
let t = serde_json::to_value(v).unwrap();
Self::range_(&t)
}
pub fn range_(t: &Value) -> String {
format!("{}:{}", pos(&t["start"]), pos(&t["end"]))
}
}
impl fmt::Display for JsonRepr {
@ -370,8 +389,6 @@ fn pos(v: &Value) -> String {
impl Redact for RedactFields {
fn redact(&self, json_val: Value) -> Value {
static REG: LazyLock<regex::Regex> =
LazyLock::new(|| regex::Regex::new(r#"data:image/svg\+xml;base64,([^"]+)"#).unwrap());
match json_val {
Value::Object(mut map) => {
for (_, val) in map.iter_mut() {
@ -400,18 +417,11 @@ impl Redact for RedactFields {
| "originSelectionRange"
| "targetRange"
| "targetSelectionRange" => {
map.insert(
key.to_owned(),
format!("{}:{}", pos(&t["start"]), pos(&t["end"])).into(),
);
map.insert(key.to_owned(), JsonRepr::range_(&t).into());
}
"contents" => {
let res = t.as_str().unwrap();
let res = REG.replace_all(res, |_captures: &regex::Captures| {
"data:image-hash/svg+xml;base64,redacted"
});
map.insert(key.to_owned(), res.into());
map.insert(key.to_owned(), JsonRepr::md_content(res).into());
}
_ => {}
}
@ -442,8 +452,8 @@ pub(crate) fn file_path_(uri: &lsp_types::Url) -> String {
};
let uri = uri.to_file_path().unwrap();
let abs_path = Path::new(&uri).strip_prefix(root).map(|p| p.to_owned());
let rel_path =
abs_path.unwrap_or_else(|_| Path::new("-").join(Path::new(&uri).iter().last().unwrap()));
let rel_path = abs_path
.unwrap_or_else(|_| Path::new("-").join(Path::new(&uri).iter().next_back().unwrap()));
unix_slash(&rel_path)
}