dev: complete labels with tolerating syntax error (#974)

This commit is contained in:
Myriad-Dreamin 2024-12-10 16:05:19 +08:00 committed by GitHub
parent 00195884de
commit 2f882378bc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 42 additions and 31 deletions

View file

@ -82,7 +82,7 @@ pub fn definition(
find_bib_definition(ctx, introspector, name) find_bib_definition(ctx, introspector, name)
.or_else(|| find_ref_definition(introspector, name, ref_expr)) .or_else(|| find_ref_definition(introspector, name, ref_expr))
} }
DerefTarget::Normal(..) => None, DerefTarget::LabelError(..) | DerefTarget::Normal(..) => None,
} }
} }

View file

@ -9,6 +9,7 @@ use super::{
TypeScheme, TypeVar, TypeScheme, TypeVar,
}; };
use crate::syntax::{get_check_target, get_check_target_by_context, CheckTarget, ParamTarget}; use crate::syntax::{get_check_target, get_check_target_by_context, CheckTarget, ParamTarget};
use crate::ty::BuiltinTy;
/// With given type information, check the type of a literal expression again by /// With given type information, check the type of a literal expression again by
/// touching the possible related nodes. /// touching the possible related nodes.
@ -306,11 +307,12 @@ impl<'a> PostTypeChecker<'a> {
Some(resp.finalize()) Some(resp.finalize())
} }
CheckTarget::ImportPath(..) | CheckTarget::IncludePath(..) => Some(Ty::Builtin( CheckTarget::ImportPath(..) | CheckTarget::IncludePath(..) => Some(Ty::Builtin(
crate::ty::BuiltinTy::Path(crate::ty::PathPreference::Source { BuiltinTy::Path(crate::ty::PathPreference::Source {
allow_package: true, allow_package: true,
}), }),
)), )),
CheckTarget::Normal(target) => { CheckTarget::LabelError(..) => Some(Ty::Builtin(BuiltinTy::Label)),
CheckTarget::Label(target) | CheckTarget::Normal(target) => {
let ty = self.check_context_or(&target, context_ty)?; let ty = self.check_context_or(&target, context_ty)?;
crate::log_debug_ct!("post check target normal: {ty:?}"); crate::log_debug_ct!("post check target normal: {ty:?}");
Some(ty) Some(ty)

View file

@ -1,6 +1,6 @@
--- ---
source: crates/tinymist-query/src/completion.rs source: crates/tinymist-query/src/completion.rs
description: Completion on t (43..44) description: Completion on t (44..45)
expression: "JsonRepr::new_pure(results)" expression: "JsonRepr::new_pure(results)"
input_file: crates/tinymist-query/src/fixtures/completion/complete_half_label.typ input_file: crates/tinymist-query/src/fixtures/completion/complete_half_label.typ
snapshot_kind: text snapshot_kind: text
@ -15,6 +15,7 @@ snapshot_kind: text
"labelDetails": { "labelDetails": {
"description": "H2" "description": "H2"
}, },
"sortText": "001",
"textEdit": { "textEdit": {
"newText": "test>", "newText": "test>",
"range": { "range": {

View file

@ -48,7 +48,7 @@ pub(crate) fn find_references(
) -> Option<Vec<LspLocation>> { ) -> Option<Vec<LspLocation>> {
let finding_label = match target { let finding_label = match target {
DerefTarget::VarAccess(..) | DerefTarget::Callee(..) => false, DerefTarget::VarAccess(..) | DerefTarget::Callee(..) => false,
DerefTarget::Label(..) | DerefTarget::Ref(..) => true, DerefTarget::Label(..) | DerefTarget::LabelError(..) | DerefTarget::Ref(..) => true,
DerefTarget::ImportPath(..) | DerefTarget::IncludePath(..) | DerefTarget::Normal(..) => { DerefTarget::ImportPath(..) | DerefTarget::IncludePath(..) | DerefTarget::Normal(..) => {
return None; return None;
} }

View file

@ -291,6 +291,7 @@ pub(crate) fn interpret_mode_at(mut leaf: Option<&LinkedNode>) -> InterpretMode
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum DerefTarget<'a> { pub enum DerefTarget<'a> {
Label(LinkedNode<'a>), Label(LinkedNode<'a>),
LabelError(LinkedNode<'a>),
Ref(LinkedNode<'a>), Ref(LinkedNode<'a>),
VarAccess(LinkedNode<'a>), VarAccess(LinkedNode<'a>),
Callee(LinkedNode<'a>), Callee(LinkedNode<'a>),
@ -302,18 +303,23 @@ pub enum DerefTarget<'a> {
impl<'a> DerefTarget<'a> { impl<'a> DerefTarget<'a> {
pub fn node(&self) -> &LinkedNode<'a> { pub fn node(&self) -> &LinkedNode<'a> {
match self { match self {
DerefTarget::Label(node) => node, DerefTarget::Label(node)
DerefTarget::Ref(node) => node, | DerefTarget::LabelError(node)
DerefTarget::VarAccess(node) => node, | DerefTarget::Ref(node)
DerefTarget::Callee(node) => node, | DerefTarget::VarAccess(node)
DerefTarget::ImportPath(node) => node, | DerefTarget::Callee(node)
DerefTarget::IncludePath(node) => node, | DerefTarget::ImportPath(node)
DerefTarget::Normal(_, node) => node, | DerefTarget::IncludePath(node)
| DerefTarget::Normal(_, node) => node,
} }
} }
} }
pub fn get_deref_target(node: LinkedNode, cursor: usize) -> Option<DerefTarget<'_>> { pub fn get_deref_target(node: LinkedNode, cursor: usize) -> Option<DerefTarget<'_>> {
if matches!(node.kind(), SyntaxKind::Error) && node.text().starts_with('<') {
return Some(DerefTarget::LabelError(node));
}
/// Skips trivia nodes that are on the same line as the cursor. /// Skips trivia nodes that are on the same line as the cursor.
fn can_skip_trivia(node: &LinkedNode, cursor: usize) -> bool { fn can_skip_trivia(node: &LinkedNode, cursor: usize) -> bool {
// A non-trivia node is our target so we stop at it. // A non-trivia node is our target so we stop at it.
@ -521,6 +527,8 @@ pub enum CheckTarget<'a> {
}, },
ImportPath(LinkedNode<'a>), ImportPath(LinkedNode<'a>),
IncludePath(LinkedNode<'a>), IncludePath(LinkedNode<'a>),
Label(LinkedNode<'a>),
LabelError(LinkedNode<'a>),
Normal(LinkedNode<'a>), Normal(LinkedNode<'a>),
} }
@ -533,7 +541,9 @@ impl<'a> CheckTarget<'a> {
ParamTarget::Named(node) => node.clone(), ParamTarget::Named(node) => node.clone(),
}, },
CheckTarget::Paren { container, .. } => container.clone(), CheckTarget::Paren { container, .. } => container.clone(),
CheckTarget::ImportPath(node) CheckTarget::Label(node)
| CheckTarget::LabelError(node)
| CheckTarget::ImportPath(node)
| CheckTarget::IncludePath(node) | CheckTarget::IncludePath(node)
| CheckTarget::Normal(node) => node.clone(), | CheckTarget::Normal(node) => node.clone(),
}) })
@ -607,6 +617,12 @@ pub fn get_check_target(node: LinkedNode) -> Option<CheckTarget<'_>> {
DerefTarget::Callee(callee) => { DerefTarget::Callee(callee) => {
return get_callee_target(callee, node); return get_callee_target(callee, node);
} }
DerefTarget::Label(node) => {
return Some(CheckTarget::Label(node));
}
DerefTarget::LabelError(node) => {
return Some(CheckTarget::LabelError(node));
}
DerefTarget::ImportPath(node) => { DerefTarget::ImportPath(node) => {
return Some(CheckTarget::ImportPath(node)); return Some(CheckTarget::ImportPath(node));
} }
@ -868,7 +884,7 @@ mod tests {
match kind { match kind {
Some(DerefTarget::VarAccess(..)) => 'v', Some(DerefTarget::VarAccess(..)) => 'v',
Some(DerefTarget::Normal(..)) => 'n', Some(DerefTarget::Normal(..)) => 'n',
Some(DerefTarget::Label(..)) => 'l', Some(DerefTarget::Label(..) | DerefTarget::LabelError(..)) => 'l',
Some(DerefTarget::Ref(..)) => 'r', Some(DerefTarget::Ref(..)) => 'r',
Some(DerefTarget::Callee(..)) => 'c', Some(DerefTarget::Callee(..)) => 'c',
Some(DerefTarget::ImportPath(..)) => 'i', Some(DerefTarget::ImportPath(..)) => 'i',
@ -888,6 +904,7 @@ mod tests {
Some(CheckTarget::Paren { .. }) => 'P', Some(CheckTarget::Paren { .. }) => 'P',
Some(CheckTarget::ImportPath(..)) => 'i', Some(CheckTarget::ImportPath(..)) => 'i',
Some(CheckTarget::IncludePath(..)) => 'I', Some(CheckTarget::IncludePath(..)) => 'I',
Some(CheckTarget::Label(..) | CheckTarget::LabelError(..)) => 'l',
Some(CheckTarget::Normal(..)) => 'n', Some(CheckTarget::Normal(..)) => 'n',
None => ' ', None => ' ',
} }

View file

@ -40,8 +40,7 @@ pub fn autocomplete(
let _ = complete_comments(&mut ctx) let _ = complete_comments(&mut ctx)
|| complete_type_and_syntax(&mut ctx).is_none() && { || complete_type_and_syntax(&mut ctx).is_none() && {
crate::log_debug_ct!("continue after completing type and syntax"); crate::log_debug_ct!("continue after completing type and syntax");
complete_labels(&mut ctx) complete_imports(&mut ctx)
|| complete_imports(&mut ctx)
|| complete_field_accesses(&mut ctx) || complete_field_accesses(&mut ctx)
|| complete_markup(&mut ctx) || complete_markup(&mut ctx)
|| complete_math(&mut ctx) || complete_math(&mut ctx)
@ -495,20 +494,6 @@ fn field_access_completions(
} }
} }
/// Complete labels.
fn complete_labels(ctx: &mut CompletionContext) -> bool {
// A label anywhere in code: "(<la|".
if (ctx.leaf.kind().is_error() && ctx.leaf.text().starts_with('<'))
|| ctx.leaf.kind() == SyntaxKind::Label
{
ctx.from = ctx.leaf.offset() + 1;
ctx.label_completions(false);
return true;
}
false
}
/// Complete imports. /// Complete imports.
fn complete_imports(ctx: &mut CompletionContext) -> bool { fn complete_imports(ctx: &mut CompletionContext) -> bool {
// On the colon marker of an import list: // On the colon marker of an import list:

View file

@ -1475,7 +1475,13 @@ pub(crate) fn complete_type_and_syntax(ctx: &mut CompletionContext) -> Option<()
Some(CheckTarget::Normal(e)) if matches!(e.kind(), SyntaxKind::FieldAccess) => { Some(CheckTarget::Normal(e)) if matches!(e.kind(), SyntaxKind::FieldAccess) => {
return None; return None;
} }
Some(CheckTarget::Paren { .. } | CheckTarget::Normal(..)) | None => {} Some(
CheckTarget::Paren { .. }
| CheckTarget::Label(..)
| CheckTarget::LabelError(..)
| CheckTarget::Normal(..),
)
| None => {}
} }
crate::log_debug_ct!("ctx.leaf {:?}", ctx.leaf.clone()); crate::log_debug_ct!("ctx.leaf {:?}", ctx.leaf.clone());