Skip to content

Commit

Permalink
[move-ide] Refactored auto-completions implementation to multiple fil…
Browse files Browse the repository at this point in the history
…es (#19236)

## Description 

The auto-completions implementation was becoming unwieldy and this PR
splits it up to multiple files in a separate directory. This a pure
refactoring - other than some name changes, added comments, and moving
code around, no modifications have been made

## Test plan 

All existing tests must pass
  • Loading branch information
awelc authored Sep 10, 2024
1 parent a911368 commit 5b7f117
Show file tree
Hide file tree
Showing 8 changed files with 1,157 additions and 1,065 deletions.
2 changes: 1 addition & 1 deletion external-crates/move/crates/move-analyzer/src/analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use std::{
};

use crate::{
completion::on_completion_request, context::Context, inlay_hints, symbols,
completions::on_completion_request, context::Context, inlay_hints, symbols,
vfs::on_text_document_sync_notification,
};
use url::Url;
Expand Down
115 changes: 115 additions & 0 deletions external-crates/move/crates/move-analyzer/src/completions/dot.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// Copyright (c) The Move Contributors
// SPDX-License-Identifier: Apache-2.0

// Auto-completion for the dot operator, e.g., `struct.` or `value.foo()`.`

use crate::{
completions::utils::{call_completion_item, mod_defs},
symbols::{type_to_ide_string, DefInfo, FunType, Symbols},
utils::lsp_position_to_loc,
};
use lsp_types::{
CompletionItem, CompletionItemKind, CompletionItemLabelDetails, InsertTextFormat, Position,
};
use move_compiler::{
expansion::ast::ModuleIdent_,
shared::{ide::AutocompleteMethod, Identifier},
};
use move_symbol_pool::Symbol;

use std::path::Path;

/// Handle "dot" auto-completion at a given position.
pub fn dot_completions(
symbols: &Symbols,
use_fpath: &Path,
position: &Position,
) -> (Vec<CompletionItem>, bool) {
let mut completions = vec![];
let mut completion_finalized = false;
let Some(fhash) = symbols.file_hash(use_fpath) else {
eprintln!("no dot completions due to missing file");
return (completions, completion_finalized);
};
let Some(loc) = lsp_position_to_loc(&symbols.files, fhash, position) else {
eprintln!("no dot completions due to missing loc");
return (completions, completion_finalized);
};
let Some(info) = symbols.compiler_info.get_autocomplete_info(fhash, &loc) else {
return (completions, completion_finalized);
};
// we found auto-completion info, so don't look for any more completions
// even if if it does not contain any
completion_finalized = true;
for AutocompleteMethod {
method_name,
target_function: (mod_ident, function_name),
} in &info.methods
{
let call_completion = if let Some(DefInfo::Function(
..,
fun_type,
_,
type_args,
arg_names,
arg_types,
ret_type,
_,
)) = fun_def_info(symbols, mod_ident.value, function_name.value())
{
call_completion_item(
&mod_ident.value,
matches!(fun_type, FunType::Macro),
Some(method_name),
&function_name.value(),
type_args,
arg_names,
arg_types,
ret_type,
/* inside_use */ false,
)
} else {
// this shouldn't really happen as we should be able to get
// `DefInfo` for a function but if for some reason we cannot,
// let's generate simpler autotompletion value
eprintln!("incomplete dot item");
CompletionItem {
label: format!("{method_name}()"),
kind: Some(CompletionItemKind::METHOD),
insert_text: Some(method_name.to_string()),
insert_text_format: Some(InsertTextFormat::PLAIN_TEXT),
..Default::default()
}
};
completions.push(call_completion);
}
for (n, t) in &info.fields {
let label_details = Some(CompletionItemLabelDetails {
detail: None,
description: Some(type_to_ide_string(t, /* verbose */ false)),
});
let init_completion = CompletionItem {
label: n.to_string(),
label_details,
kind: Some(CompletionItemKind::FIELD),
insert_text: Some(n.to_string()),
insert_text_format: Some(InsertTextFormat::PLAIN_TEXT),
..Default::default()
};
completions.push(init_completion);
}

(completions, completion_finalized)
}

/// Get the `DefInfo` for a function definition.
fn fun_def_info(symbols: &Symbols, mod_ident: ModuleIdent_, name: Symbol) -> Option<&DefInfo> {
let Some(mod_defs) = mod_defs(symbols, &mod_ident) else {
return None;
};

let Some(fdef) = mod_defs.functions.get(&name) else {
return None;
};
symbols.def_info(&fdef.name_loc)
}
Loading

0 comments on commit 5b7f117

Please sign in to comment.