mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-08-03 17:58:17 +00:00
dev: insert commas in arg context for completing before identifiers (#251)
This commit is contained in:
parent
c640d53396
commit
bbded48a1b
4 changed files with 116 additions and 13 deletions
|
@ -99,6 +99,7 @@ impl StatefulRequest for CompletionRequest {
|
|||
|
||||
let mut match_ident = None;
|
||||
let mut completion_result = None;
|
||||
let is_callee = matches!(deref_target, Some(DerefTarget::Callee(..)));
|
||||
match deref_target {
|
||||
Some(DerefTarget::Callee(v) | DerefTarget::VarAccess(v)) => {
|
||||
if v.is::<ast::Ident>() {
|
||||
|
@ -152,10 +153,9 @@ impl StatefulRequest for CompletionRequest {
|
|||
let replace_range;
|
||||
if match_ident.as_ref().is_some_and(|i| i.offset() == offset) {
|
||||
let match_ident = match_ident.unwrap();
|
||||
let rng = match_ident.range();
|
||||
replace_range = ctx.to_lsp_range(match_ident.range(), &source);
|
||||
|
||||
let mut rng = match_ident.range();
|
||||
let ident_prefix = source.text()[rng.start..cursor].to_string();
|
||||
|
||||
completions.retain(|c| {
|
||||
// c.label
|
||||
let mut prefix_matcher = c.label.chars();
|
||||
|
@ -171,6 +171,29 @@ impl StatefulRequest for CompletionRequest {
|
|||
|
||||
true
|
||||
});
|
||||
|
||||
// if modifying some arguments, we need to truncate and add a comma
|
||||
if !is_callee && cursor != rng.end && is_arg_like_context(&match_ident) {
|
||||
// extend comma
|
||||
for c in completions.iter_mut() {
|
||||
let apply = match &mut c.apply {
|
||||
Some(w) => w,
|
||||
None => {
|
||||
c.apply = Some(c.label.clone());
|
||||
c.apply.as_mut().unwrap()
|
||||
}
|
||||
};
|
||||
if apply.trim_end().ends_with(',') {
|
||||
continue;
|
||||
}
|
||||
apply.push_str(", ");
|
||||
}
|
||||
|
||||
// Truncate
|
||||
rng.end = cursor;
|
||||
}
|
||||
|
||||
replace_range = ctx.to_lsp_range(rng, &source);
|
||||
} else {
|
||||
let lsp_start_position = ctx.to_lsp_pos(offset, &source);
|
||||
replace_range = LspRange::new(lsp_start_position, self.position);
|
||||
|
@ -198,6 +221,28 @@ impl StatefulRequest for CompletionRequest {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_arg_like_context(mut matching: &LinkedNode) -> bool {
|
||||
while let Some(parent) = matching.parent() {
|
||||
use SyntaxKind::*;
|
||||
// if parent.kind() == SyntaxKind::Markup | SyntaxKind::Markup |
|
||||
// SyntaxKind::Markup { return true;
|
||||
// }
|
||||
// if parent.kind() == SyntaxKind::Args {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// todo: contextual
|
||||
match parent.kind() {
|
||||
ContentBlock | Equation | CodeBlock | Markup | Math | Code => return false,
|
||||
Args | Params | Destructuring | Array | Dict => return true,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
matching = parent;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::HashSet;
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
// contains: content,authors,font,class
|
||||
|
||||
#let tmpl(content, authors: (), font: none, class: "article") = {
|
||||
if class != "article" and class != "letter" {
|
||||
panic("")
|
||||
}
|
||||
|
||||
set document(author: authors)
|
||||
set text(font: font)
|
||||
|
||||
set page(paper: "a4") if class == "article"
|
||||
set page(paper: "us-letter") if class == "letter"
|
||||
|
||||
content
|
||||
}
|
||||
|
||||
#tmpl(/* range after 1..2 */authors: (),)
|
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
source: crates/tinymist-query/src/completion.rs
|
||||
description: Completion on u (371..372)
|
||||
expression: "JsonRepr::new_pure(results)"
|
||||
input_file: crates/tinymist-query/src/fixtures/completion/func_args_after.typ
|
||||
---
|
||||
[
|
||||
{
|
||||
"isIncomplete": false,
|
||||
"items": [
|
||||
{
|
||||
"kind": 6,
|
||||
"label": "class",
|
||||
"sortText": "000",
|
||||
"textEdit": {
|
||||
"newText": "class: ${1:}, ",
|
||||
"range": {
|
||||
"end": {
|
||||
"character": 29,
|
||||
"line": 16
|
||||
},
|
||||
"start": {
|
||||
"character": 28,
|
||||
"line": 16
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -158,18 +158,28 @@ pub fn run_with_sources<T>(source: &str, f: impl FnOnce(&mut TypstSystemWorld, P
|
|||
|
||||
pub fn find_test_range(s: &Source) -> Range<usize> {
|
||||
// /* range -3..-1 */
|
||||
let re = s.text().find("/* range ").unwrap();
|
||||
let re_base = re;
|
||||
let re = re + "/* range ".len();
|
||||
let re = re..s.text().find(" */").unwrap();
|
||||
let re = &s.text()[re];
|
||||
fn find_prefix(s: &str, sub: &str, left: bool) -> Option<(usize, usize, bool)> {
|
||||
Some((s.find(sub)?, sub.len(), left))
|
||||
}
|
||||
let (re_base, re_len, is_after) = find_prefix(s.text(), "/* range after ", true)
|
||||
.or_else(|| find_prefix(s.text(), "/* range ", false))
|
||||
.unwrap();
|
||||
let re_end = re_base + re_len;
|
||||
let range_rng = re_end..(s.text()[re_end..].find(" */").unwrap() + re_end);
|
||||
let range_base = if is_after {
|
||||
range_rng.end + " */".len()
|
||||
} else {
|
||||
re_base
|
||||
};
|
||||
let range = &s.text()[range_rng];
|
||||
// split by ".."
|
||||
let mut re = re.split("..");
|
||||
let mut bounds = range.split("..");
|
||||
// parse the range
|
||||
let start: isize = re.next().unwrap().parse().unwrap();
|
||||
let end: isize = re.next().unwrap().parse().unwrap();
|
||||
let start = start + re_base as isize;
|
||||
let end = end + re_base as isize;
|
||||
let start: isize = bounds.next().unwrap().parse().unwrap();
|
||||
let end: isize = bounds.next().unwrap().parse().unwrap();
|
||||
|
||||
let start = start + range_base as isize;
|
||||
let end = end + range_base as isize;
|
||||
start as usize..end as usize
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue