Skip to content

Commit d65dcd2

Browse files
authored
Feat: Add available architectures when completing an entity (#263)
* Add architectures to entity completion * Happy Clippy
1 parent 780ffce commit d65dcd2

File tree

2 files changed

+102
-10
lines changed

2 files changed

+102
-10
lines changed

vhdl_lang/src/completion.rs

Lines changed: 90 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::named_entity::{self, AsUnique, DesignEnt, HasEntityId, NamedEntities,
1414
use crate::syntax::Kind::*;
1515
use crate::syntax::{Kind, Symbols, Token, TokenAccess, Tokenizer, Value};
1616
use crate::{AnyEntKind, Design, EntRef, EntityId, HasTokenSpan, Overloaded, Position, Source};
17+
use itertools::Itertools;
1718
use std::collections::HashSet;
1819
use std::default::Default;
1920
use std::iter::once;
@@ -42,7 +43,10 @@ pub enum CompletionItem<'a> {
4243
/// -- ...
4344
/// );
4445
/// ```
45-
EntityInstantiation(EntRef<'a>),
46+
///
47+
/// The second argument is a vector of architectures that are associated
48+
/// to this entity
49+
EntityInstantiation(EntRef<'a>, Vec<EntRef<'a>>),
4650
}
4751

4852
macro_rules! kind {
@@ -371,7 +375,14 @@ impl<'a> Searcher for CompletionSearcher<'a> {
371375
self.completions = self
372376
.root
373377
.get_visible_entities_from_entity(ent)
374-
.map(|eid| CompletionItem::EntityInstantiation(self.root.get_ent(eid)))
378+
.map(|eid| {
379+
let ent = self.root.get_ent(eid);
380+
let architectures = get_architectures_for_entity(ent, self.root);
381+
CompletionItem::EntityInstantiation(
382+
self.root.get_ent(eid),
383+
architectures,
384+
)
385+
})
375386
.collect()
376387
}
377388
Finished(Found)
@@ -381,6 +392,23 @@ impl<'a> Searcher for CompletionSearcher<'a> {
381392
}
382393
}
383394

395+
/// Returns a vec populated with all architectures that belong to the given entity
396+
fn get_architectures_for_entity<'a>(ent: EntRef<'a>, root: &'a DesignRoot) -> Vec<EntRef<'a>> {
397+
if let Some(design) = DesignEnt::from_any(ent) {
398+
root.public_symbols()
399+
.filter(|sym| match sym.kind() {
400+
AnyEntKind::Design(Design::Architecture(arch_design)) => {
401+
arch_design.id() == design.id()
402+
}
403+
_ => false,
404+
})
405+
.sorted_by_key(|a| a.decl_pos())
406+
.collect_vec()
407+
} else {
408+
vec![]
409+
}
410+
}
411+
384412
impl DesignRoot {
385413
/// List all entities (entities in this context is a VHDL entity, not a `DesignEnt` or similar)
386414
/// that are visible from another VHDL entity.
@@ -712,8 +740,8 @@ end arch;
712740
assert_eq_unordered(
713741
&options[..],
714742
&[
715-
CompletionItem::EntityInstantiation(my_ent),
716-
CompletionItem::EntityInstantiation(my_other_ent),
743+
CompletionItem::EntityInstantiation(my_ent, vec![]),
744+
CompletionItem::EntityInstantiation(my_other_ent, vec![]),
717745
],
718746
);
719747
}
@@ -775,11 +803,11 @@ end arch;
775803

776804
assert_eq_unordered(
777805
&options[..],
778-
&[CompletionItem::EntityInstantiation(my_ent2)],
806+
&[CompletionItem::EntityInstantiation(my_ent2, vec![])],
779807
);
780808

781809
let ent1 = root
782-
.search_reference(code1.source(), code2.s1("my_ent").start())
810+
.search_reference(code1.source(), code1.s1("my_ent").start())
783811
.unwrap();
784812

785813
let cursor = code3.s1("begin").end();
@@ -792,9 +820,63 @@ end arch;
792820
assert_eq_unordered(
793821
&options[..],
794822
&[
795-
CompletionItem::EntityInstantiation(my_ent2),
796-
CompletionItem::EntityInstantiation(ent1),
823+
CompletionItem::EntityInstantiation(my_ent2, vec![]),
824+
CompletionItem::EntityInstantiation(ent1, vec![]),
797825
],
798826
);
799827
}
828+
829+
#[test]
830+
pub fn entity_with_two_architecture() {
831+
let mut builder = LibraryBuilder::new();
832+
let code1 = builder.code(
833+
"libA",
834+
"\
835+
entity my_ent is
836+
end my_ent;
837+
838+
architecture arch1 of my_ent is
839+
begin
840+
end arch1;
841+
842+
architecture arch2 of my_ent is
843+
begin
844+
end arch2;
845+
",
846+
);
847+
let code2 = builder.code(
848+
"libA",
849+
"\
850+
entity my_ent2 is
851+
end my_ent2;
852+
853+
architecture arch of my_ent2 is
854+
begin
855+
856+
end arch;
857+
",
858+
);
859+
860+
let (root, diag) = builder.get_analyzed_root();
861+
check_no_diagnostics(&diag[..]);
862+
let cursor = code2.s("begin", 1).end();
863+
let options = list_completion_options(&root, code2.source(), cursor);
864+
865+
let ent = root
866+
.search_reference(code1.source(), code1.s1("my_ent").start())
867+
.unwrap();
868+
869+
let arch1 = root
870+
.search_reference(code1.source(), code1.s1("arch1").start())
871+
.unwrap();
872+
873+
let arch2 = root
874+
.search_reference(code1.source(), code1.s1("arch2").start())
875+
.unwrap();
876+
877+
assert_eq!(
878+
options,
879+
vec![CompletionItem::EntityInstantiation(ent, vec![arch1, arch2])]
880+
)
881+
}
800882
}

vhdl_ls/src/vhdl_server.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ impl VHDLServer {
300300
kind: Some(CompletionItemKind::KEYWORD),
301301
..Default::default()
302302
},
303-
vhdl_lang::CompletionItem::EntityInstantiation(ent) => {
303+
vhdl_lang::CompletionItem::EntityInstantiation(ent, architectures) => {
304304
let work_name = "work";
305305

306306
let library_names = if let Some(lib_name) = ent.library_name() {
@@ -325,8 +325,18 @@ impl VHDLServer {
325325
ent.designator
326326
)
327327
};
328+
if architectures.len() > 1 {
329+
line.push_str("(${3|");
330+
for (i, architecture) in architectures.iter().enumerate() {
331+
line.push_str(&architecture.designator().to_string());
332+
if i != architectures.len() - 1 {
333+
line.push(',')
334+
}
335+
}
336+
line.push_str("|})");
337+
}
328338
let (ports, generics) = region.ports_and_generics();
329-
let mut idx = 3;
339+
let mut idx = 4;
330340
let mut interface_ent = |elements: Vec<InterfaceEnt>, purpose: &str| {
331341
line += &*format!("\n {} map(\n", purpose);
332342
for (i, generic) in elements.iter().enumerate() {

0 commit comments

Comments
 (0)