Skip to content

Commit

Permalink
Always suggest instantiation completions in the architecture statemen…
Browse files Browse the repository at this point in the history
…ts part
  • Loading branch information
Schottkyc137 committed Jul 28, 2024
1 parent 86eb38e commit 2426c49
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 15 deletions.
14 changes: 14 additions & 0 deletions vhdl_lang/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use crate::ast::token_range::*;
use crate::data::*;
use crate::named_entity::{EntityId, Reference};
use crate::syntax::{Token, TokenAccess, TokenId};
use crate::TokenSpan;
pub(crate) use any_design_unit::*;
use vhdl_lang::HasTokenSpan;

Expand Down Expand Up @@ -1560,6 +1561,19 @@ impl ArchitectureBody {
pub fn is_token(&self) -> TokenId {
self.span.start_token + 4
}

/// Returns the span that encompasses the statements of this architecture, i.e.
/// ```vhdl
/// architecture arch of ent is
/// begin /* start */
/// foo <= bar;
/// /* end*/ end arch;
/// ```
/// Note that the `begin` and `end` tokens are **included** in the span
/// to avoid the ambiguity of an empty statement part.
pub fn statement_span(&self) -> TokenSpan {
TokenSpan::new(self.begin_token, self.end_token)
}
}

/// LRM 4.7 Package declarations
Expand Down
78 changes: 78 additions & 0 deletions vhdl_lang/src/completion/entity_instantiation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,44 @@ end arch;
assert!(options.contains(&CompletionItem::Instantiation(my_other_ent, vec![])));
}

#[test]
fn does_not_complete_in_architecture_declarative_part() {
let mut builder = LibraryBuilder::new();
let code = builder.code(
"libname",
"\
entity my_ent is
end my_ent;
entity my_other_ent is
end my_other_ent;
entity my_third_ent is
end my_third_ent;
architecture arch of my_third_ent is
begin
end arch;
",
);

let (root, _) = builder.get_analyzed_root();
let cursor = code.s("is", 4).end();
let options = list_completion_options(&root, code.source(), cursor);

let my_ent = root
.search_reference(code.source(), code.s1("my_ent").start())
.unwrap();

let my_other_ent = root
.search_reference(code.source(), code.s1("my_other_ent").start())
.unwrap();

assert!(!options.contains(&CompletionItem::Instantiation(my_ent, vec![])));
assert!(!options.contains(&CompletionItem::Instantiation(my_other_ent, vec![])));
}

#[test]
fn complete_entities_from_different_libraries() {
let mut builder = LibraryBuilder::new();
Expand Down Expand Up @@ -288,4 +326,44 @@ end arch1;
assert!(options.contains(&CompletionItem::Instantiation(entity, vec![])))
}
}

#[test]
fn complete_entities_in_block() {
let mut builder = LibraryBuilder::new();
let code = builder.code(
"libname",
"\
entity my_ent is
end my_ent;
entity my_other_ent is
end my_other_ent;
entity my_third_ent is
end my_third_ent;
architecture arch of my_third_ent is
begin
foo: block is
begin
end block foo;
end arch;
",
);

let (root, _) = builder.get_analyzed_root();
let cursor = code.s("begin", 2).end();
let options = list_completion_options(&root, code.source(), cursor);

let my_ent = root
.search_reference(code.source(), code.s1("my_ent").start())
.unwrap();

let my_other_ent = root
.search_reference(code.source(), code.s1("my_other_ent").start())
.unwrap();

assert!(options.contains(&CompletionItem::Instantiation(my_ent, vec![])));
assert!(options.contains(&CompletionItem::Instantiation(my_other_ent, vec![])));
}
}
19 changes: 4 additions & 15 deletions vhdl_lang/src/completion/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,26 +47,13 @@ impl<'a> CompletionSearcher<'a> {

impl<'a> CompletionSearcher<'a> {
/// Add entity instantiation completions that are visible from within an architecture body
fn add_entity_instantiations(&mut self, ctx: &dyn TokenAccess, body: &ArchitectureBody) {
fn add_entity_instantiations(&mut self, body: &ArchitectureBody) {
let Some(ent_id) = body.ident.decl.get() else {
return;
};
let Some(ent) = DesignEnt::from_any(self.root.get_ent(ent_id)) else {
return;
};
// Early-exit for when we are inside a statement.
for statement in &body.statements {
let pos = &statement.statement.pos(ctx);

// Early exit. The cursor is below the current statement.
if pos.start() > self.cursor {
break;
}

if pos.contains(self.cursor) {
return;
}
}
self.completions
.extend(get_visible_entities_from_architecture(self.root, &ent));
}
Expand All @@ -85,7 +72,9 @@ impl<'a> Searcher for CompletionSearcher<'a> {
if !body.get_pos(ctx).contains(self.cursor) {
return NotFinished;
}
self.add_entity_instantiations(ctx, body);
if body.statement_span().get_pos(ctx).contains(self.cursor) {
self.add_entity_instantiations(body);
}
body.ident.decl.get()
}
DeclarationItem::Package(package) => {
Expand Down

0 comments on commit 2426c49

Please sign in to comment.