mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-08-03 17:58:17 +00:00
feat: use field access classifier for completion (#1035)
* feat: use field access classifier for completion * dev: more cases about dot access
This commit is contained in:
parent
39243ba626
commit
980571ad61
4 changed files with 20 additions and 58 deletions
|
@ -17,7 +17,7 @@ snapshot_kind: text
|
|||
"kind": 3,
|
||||
"label": "table-prefix",
|
||||
"textEdit": {
|
||||
"newText": "table-prefix",
|
||||
"newText": "table-prefix(${1:})",
|
||||
"range": {
|
||||
"end": {
|
||||
"character": 24,
|
||||
|
|
|
@ -441,14 +441,15 @@ pub fn classify_syntax(node: LinkedNode, cursor: usize) -> Option<SyntaxClass<'_
|
|||
node = node.prev_sibling()?;
|
||||
}
|
||||
|
||||
let is_dot = matches!(node.kind(), SyntaxKind::Dot)
|
||||
|| (matches!(node.kind(), SyntaxKind::Text | SyntaxKind::Error) && node.text() == ".");
|
||||
let starts_with_dot = matches!(node.kind(), SyntaxKind::Dot)
|
||||
|| (matches!(node.kind(), SyntaxKind::Text | SyntaxKind::Error)
|
||||
&& node.text().starts_with("."));
|
||||
|
||||
if is_dot && node.offset() + 1 == cursor {
|
||||
if starts_with_dot && node.offset() + 1 == cursor {
|
||||
let dot_target = node.clone().prev_leaf().and_then(first_ancestor_expr);
|
||||
|
||||
if let Some(dots_target) = dot_target {
|
||||
return Some(SyntaxClass::VarAccess(VarClass::DotAccess(dots_target)));
|
||||
if let Some(dot_target) = dot_target {
|
||||
return Some(SyntaxClass::VarAccess(VarClass::DotAccess(dot_target)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,6 @@ pub fn autocomplete(
|
|||
|| complete_type_and_syntax(&mut ctx).is_none() && {
|
||||
crate::log_debug_ct!("continue after completing type and syntax");
|
||||
complete_imports(&mut ctx)
|
||||
|| complete_field_accesses(&mut ctx)
|
||||
|| complete_markup(&mut ctx)
|
||||
|| complete_math(&mut ctx)
|
||||
|| complete_code(&mut ctx, false)
|
||||
|
@ -244,53 +243,6 @@ fn complete_math(ctx: &mut CompletionContext) -> bool {
|
|||
false
|
||||
}
|
||||
|
||||
/// Complete field accesses.
|
||||
fn complete_field_accesses(ctx: &mut CompletionContext) -> bool {
|
||||
// Used to determine whether trivia nodes are allowed before '.'.
|
||||
// During an inline expression in markup mode trivia nodes exit the inline
|
||||
// expression.
|
||||
let in_markup: bool = matches!(
|
||||
ctx.leaf.parent_kind(),
|
||||
None | Some(SyntaxKind::Markup) | Some(SyntaxKind::Ref)
|
||||
);
|
||||
|
||||
// Behind an expression plus dot: "emoji.|".
|
||||
if_chain! {
|
||||
if ctx.leaf.kind() == SyntaxKind::Dot
|
||||
|| (ctx.leaf.kind() == SyntaxKind::Text
|
||||
&& ctx.leaf.text() == ".");
|
||||
if ctx.leaf.range().end == ctx.cursor;
|
||||
if let Some(prev) = ctx.leaf.prev_sibling();
|
||||
if !in_markup || prev.range().end == ctx.leaf.range().start;
|
||||
if prev.is::<ast::Expr>();
|
||||
if prev.parent_kind() != Some(SyntaxKind::Markup) ||
|
||||
prev.prev_sibling_kind() == Some(SyntaxKind::Hash);
|
||||
if let Some((value, styles)) = ctx.ctx.analyze_expr(&prev).into_iter().next();
|
||||
then {
|
||||
ctx.from = ctx.cursor;
|
||||
field_access_completions(ctx, &prev, &value, &styles);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Behind a started field access: "emoji.fa|".
|
||||
if_chain! {
|
||||
if ctx.leaf.kind() == SyntaxKind::Ident;
|
||||
if let Some(prev) = ctx.leaf.prev_sibling();
|
||||
if prev.kind() == SyntaxKind::Dot;
|
||||
if let Some(prev_prev) = prev.prev_sibling();
|
||||
if prev_prev.is::<ast::Expr>();
|
||||
if let Some((value, styles)) = ctx.ctx.analyze_expr(&prev_prev).into_iter().next();
|
||||
then {
|
||||
ctx.from = ctx.leaf.offset();
|
||||
field_access_completions(ctx,&prev_prev, &value, &styles);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// Add completions for all fields on a value.
|
||||
fn field_access_completions(
|
||||
ctx: &mut CompletionContext,
|
||||
|
|
|
@ -25,7 +25,7 @@ use crate::syntax::{
|
|||
VarClass,
|
||||
};
|
||||
use crate::ty::{DynTypeBounds, Iface, IfaceChecker, InsTy, SigTy, TyCtx, TypeInfo, TypeVar};
|
||||
use crate::upstream::complete::complete_code;
|
||||
use crate::upstream::complete::{complete_code, field_access_completions};
|
||||
|
||||
use crate::{completion_kind, prelude::*, LspCompletion};
|
||||
|
||||
|
@ -1398,9 +1398,18 @@ pub(crate) fn complete_type_and_syntax(ctx: &mut CompletionContext) -> Option<()
|
|||
args_node = Some(args.to_untyped().clone());
|
||||
}
|
||||
// todo: complete field by types
|
||||
Some(CursorClass::VarAccess(VarClass::FieldAccess { .. }))
|
||||
| Some(CursorClass::VarAccess(VarClass::DotAccess { .. })) => {
|
||||
return None;
|
||||
Some(CursorClass::VarAccess(
|
||||
var @ (VarClass::FieldAccess { .. } | VarClass::DotAccess { .. }),
|
||||
)) => {
|
||||
let target = var.accessed_node()?;
|
||||
let field = var.accessing_field()?;
|
||||
|
||||
let offset = field.offset(&ctx.ctx.source_by_id(target.span().id()?).ok()?)?;
|
||||
ctx.from = offset;
|
||||
|
||||
let (value, styles) = ctx.ctx.analyze_expr(&target).into_iter().next()?;
|
||||
field_access_completions(ctx, &target, &value, &styles);
|
||||
return Some(());
|
||||
}
|
||||
Some(CursorClass::ImportPath(path) | CursorClass::IncludePath(path)) => {
|
||||
let Some(ast::Expr::Str(str)) = path.cast() else {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue