feat: make enter feature in list or enum work (#2022)

Continue work on Myriad-Dreamin/tinymist#1446
This commit is contained in:
Myriad-Dreamin 2025-08-13 11:15:31 +08:00 committed by GitHub
parent a561059a4e
commit 2c552ce985
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 113 additions and 13 deletions

View file

@ -0,0 +1,2 @@
/* range after 2..10 */
+ #let f = 1;

View file

@ -0,0 +1,2 @@
/* range after 2..10 */
+ #let f() = 1;

View file

@ -0,0 +1,2 @@
/* range after 2..7 */
+ test

View file

@ -0,0 +1,2 @@
/* range after 4..7 */
+ test

View file

@ -0,0 +1,2 @@
/* range after 4..4 */
+ test

View file

@ -0,0 +1,3 @@
#let a = 1;
/* range after 2..10 */
+ #a test

View file

@ -4,4 +4,9 @@ description: "On Enter on 3..3 */\n+ ||\n)"
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/on_enter/enum2.typ input_file: crates/tinymist-query/src/fixtures/on_enter/enum2.typ
--- ---
null [
{
"newText": "\n+ $0",
"range": "1:2:1:2"
}
]

View file

@ -0,0 +1,7 @@
---
source: crates/tinymist-query/src/on_enter.rs
description: "On Enter on 2..10 */\n+| #let f |= 1;\n)"
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/on_enter/enum_let.typ
---
null

View file

@ -0,0 +1,7 @@
---
source: crates/tinymist-query/src/on_enter.rs
description: "On Enter on 2..10 */\n+| #let f(|) = 1;\n)"
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/on_enter/enum_let2.typ
---
null

View file

@ -0,0 +1,12 @@
---
source: crates/tinymist-query/src/on_enter.rs
description: "On Enter on 2..7 */\n+| test|\n)"
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/on_enter/enum_plain.typ
---
[
{
"newText": "\n+ $0",
"range": "1:1:1:6"
}
]

View file

@ -0,0 +1,12 @@
---
source: crates/tinymist-query/src/on_enter.rs
description: "On Enter on ..7 */\n+ t|est|\n)"
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/on_enter/enum_plain2.typ
---
[
{
"newText": "\n+ $0",
"range": "1:3:1:6"
}
]

View file

@ -0,0 +1,7 @@
---
source: crates/tinymist-query/src/on_enter.rs
description: "On Enter on ..4 */\n+ t||est\n)"
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/on_enter/enum_plain3.typ
---
null

View file

@ -0,0 +1,12 @@
---
source: crates/tinymist-query/src/on_enter.rs
description: "On Enter on 2..10 */\n+| #a test|\n)"
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/on_enter/enum_var.typ
---
[
{
"newText": "\n+ $0",
"range": "2:1:2:9"
}
]

View file

@ -4,4 +4,9 @@ description: "On Enter on 3..3 */\n- ||\n)"
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)" expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/on_enter/list2.typ input_file: crates/tinymist-query/src/fixtures/on_enter/list2.typ
--- ---
null [
{
"newText": "\n- $0",
"range": "1:2:1:2"
}
]

View file

@ -25,6 +25,8 @@ pub struct OnEnterRequest {
pub path: PathBuf, pub path: PathBuf,
/// The source code range to request for. /// The source code range to request for.
pub range: LspRange, pub range: LspRange,
/// Whether to handle list and enum items.
pub handle_list: bool,
} }
impl SyntaxRequest for OnEnterRequest { impl SyntaxRequest for OnEnterRequest {
@ -54,8 +56,10 @@ impl SyntaxRequest for OnEnterRequest {
let case = node_ancestors(&leaf).find_map(|node| match node.kind() { let case = node_ancestors(&leaf).find_map(|node| match node.kind() {
SyntaxKind::LineComment => Some(Cases::LineComment(node.clone())), SyntaxKind::LineComment => Some(Cases::LineComment(node.clone())),
SyntaxKind::Equation => Some(Cases::Equation(node.clone())), SyntaxKind::Equation => Some(Cases::Equation(node.clone())),
SyntaxKind::ListItem | SyntaxKind::EnumItem => Some(Cases::ListOrEnum(node.clone())), SyntaxKind::ListItem | SyntaxKind::EnumItem if self.handle_list => {
SyntaxKind::Space | SyntaxKind::Parbreak => { Some(Cases::ListOrEnum(node.clone()))
}
SyntaxKind::Space | SyntaxKind::Parbreak if self.handle_list => {
let prev_leaf = node.prev_sibling()?; let prev_leaf = node.prev_sibling()?;
let inter_space = node.offset()..rng.start; let inter_space = node.offset()..rng.start;
@ -78,13 +82,7 @@ impl SyntaxRequest for OnEnterRequest {
match case { match case {
Some(Cases::LineComment(node)) => worker.enter_line_doc_comment(node, rng), Some(Cases::LineComment(node)) => worker.enter_line_doc_comment(node, rng),
Some(Cases::Equation(node)) => worker.enter_block_math(node, rng), Some(Cases::Equation(node)) => worker.enter_block_math(node, rng),
Some(Cases::ListOrEnum(node)) => { Some(Cases::ListOrEnum(node)) => worker.enter_list_or_enum(node, rng),
let _ = node;
let _ = OnEnterWorker::enter_list_or_enum;
// worker.enter_list_or_enum(node, rng)
None
}
_ => None, _ => None,
} }
} }
@ -175,6 +173,15 @@ impl OnEnterWorker<'_> {
} }
fn enter_list_or_enum(&self, node: LinkedNode<'_>, rng: Range<usize>) -> Option<Vec<TextEdit>> { fn enter_list_or_enum(&self, node: LinkedNode<'_>, rng: Range<usize>) -> Option<Vec<TextEdit>> {
let rng_end = rng.end;
let node_end = node.range().end;
let in_middle_of_node = rng_end < node_end
&& self.source.text()[rng_end..node_end].contains(|c: char| !c.is_whitespace());
if in_middle_of_node {
return None;
}
let indent = self.indent_of(node.range().start); let indent = self.indent_of(node.range().start);
let is_list = matches!(node.kind(), SyntaxKind::ListItem); let is_list = matches!(node.kind(), SyntaxKind::ListItem);
@ -202,6 +209,7 @@ mod tests {
let request = OnEnterRequest { let request = OnEnterRequest {
path: path.clone(), path: path.clone(),
range: find_test_range(&source), range: find_test_range(&source),
handle_list: true,
}; };
let result = request.request(&source, PositionEncoding::Utf16); let result = request.request(&source, PositionEncoding::Utf16);

View file

@ -53,6 +53,7 @@ const CONFIG_ITEMS: &[&str] = &[
"formatterIndentSize", "formatterIndentSize",
"formatterProseWrap", "formatterProseWrap",
"hoverPeriscope", "hoverPeriscope",
"onEnter",
"outputPath", "outputPath",
"preview", "preview",
"projectResolution", "projectResolution",
@ -108,8 +109,10 @@ pub struct Config {
pub completion: CompletionFeat, pub completion: CompletionFeat,
/// Tinymist's preview features. /// Tinymist's preview features.
pub preview: PreviewFeat, pub preview: PreviewFeat,
/// When to trigger the lint checks. /// Tinymist's lint features.
pub lint: LintFeat, pub lint: LintFeat,
/// Tinymist's on-enter features.
pub on_enter: OnEnterFeat,
/// Specifies the cli font options /// Specifies the cli font options
pub font_opts: CompileFontArgs, pub font_opts: CompileFontArgs,
@ -329,6 +332,7 @@ impl Config {
assign_config!(color_theme := "colorTheme"?: Option<String>); assign_config!(color_theme := "colorTheme"?: Option<String>);
assign_config!(lint := "lint"?: LintFeat); assign_config!(lint := "lint"?: LintFeat);
assign_config!(completion := "completion"?: CompletionFeat); assign_config!(completion := "completion"?: CompletionFeat);
assign_config!(on_enter := "onEnter"?: OnEnterFeat);
assign_config!(completion.trigger_suggest := "triggerSuggest"?: bool); assign_config!(completion.trigger_suggest := "triggerSuggest"?: bool);
assign_config!(completion.trigger_parameter_hints := "triggerParameterHints"?: bool); assign_config!(completion.trigger_parameter_hints := "triggerParameterHints"?: bool);
assign_config!(completion.trigger_suggest_and_parameter_hints := "triggerSuggestAndParameterHints"?: bool); assign_config!(completion.trigger_suggest_and_parameter_hints := "triggerSuggestAndParameterHints"?: bool);
@ -906,6 +910,13 @@ impl LintFeat {
self.when.as_ref().unwrap_or(&TaskWhen::OnSave) self.when.as_ref().unwrap_or(&TaskWhen::OnSave)
} }
} }
/// The lint features.
#[derive(Debug, Default, Clone, Deserialize)]
pub struct OnEnterFeat {
/// Whether to handle list.
#[serde(default, deserialize_with = "deserialize_null_default")]
pub handle_list: bool,
}
/// Options for browsing preview. /// Options for browsing preview.
#[derive(Debug, Default, Clone, Deserialize)] #[derive(Debug, Default, Clone, Deserialize)]

View file

@ -173,7 +173,8 @@ impl ServerState {
pub(crate) fn on_enter(&mut self, params: OnEnterParams) -> ScheduleResult { pub(crate) fn on_enter(&mut self, params: OnEnterParams) -> ScheduleResult {
let path = as_path(params.text_document); let path = as_path(params.text_document);
let range = params.range; let range = params.range;
run_query!(self.OnEnter(path, range)) let handle_list = self.config.on_enter.handle_list;
run_query!(self.OnEnter(path, range, handle_list))
} }
pub(crate) fn will_rename_files(&mut self, params: RenameFilesParams) -> ScheduleResult { pub(crate) fn will_rename_files(&mut self, params: RenameFilesParams) -> ScheduleResult {