mirror of
https://github.com/roc-lang/roc.git
synced 2024-10-05 06:37:26 +03:00
cleanup nitpicks and reorganising
This commit is contained in:
parent
72e60ec01b
commit
391b695824
@ -40,6 +40,38 @@ pub(super) struct ModulesInfo {
|
|||||||
exposed: HashMap<ModuleId, Arc<Vec<(Symbol, Variable)>>>,
|
exposed: HashMap<ModuleId, Arc<Vec<(Symbol, Variable)>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ModulesInfo {
|
||||||
|
fn with_subs<F, A>(&self, mod_id: &ModuleId, f: F) -> Option<A>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut Subs) -> A,
|
||||||
|
{
|
||||||
|
self.subs.lock().get_mut(mod_id).map(f)
|
||||||
|
}
|
||||||
|
///Transforms some of the raw data from the analysis into a state that is more useful during processes like completion
|
||||||
|
fn from_analysis(
|
||||||
|
exposes: MutMap<ModuleId, Vec<(Symbol, Variable)>>,
|
||||||
|
typechecked: &MutMap<ModuleId, CheckedModule>,
|
||||||
|
) -> ModulesInfo {
|
||||||
|
//We wrap this in arc because later we will go through each module's imports and store the full list of symbols that each imported module exposes.
|
||||||
|
//eg: A imports B. B exposes [add, multiply, divide] and A will store a reference to that list.
|
||||||
|
let exposed = exposes
|
||||||
|
.into_iter()
|
||||||
|
.map(|(id, symbols)| (id, Arc::new(symbols)))
|
||||||
|
.collect::<HashMap<_, _>>();
|
||||||
|
//Combine the subs from all modules
|
||||||
|
let all_subs = Mutex::new(
|
||||||
|
typechecked
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| (*k, v.solved_subs.0.clone()))
|
||||||
|
.collect::<HashMap<_, _>>(),
|
||||||
|
);
|
||||||
|
ModulesInfo {
|
||||||
|
subs: all_subs,
|
||||||
|
exposed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(super) struct AnalyzedModule {
|
pub(super) struct AnalyzedModule {
|
||||||
exposed_imports: Vec<(Symbol, Variable)>,
|
exposed_imports: Vec<(Symbol, Variable)>,
|
||||||
@ -122,7 +154,7 @@ pub(crate) fn global_analysis(doc_info: DocInfo) -> Vec<AnalyzedDocument> {
|
|||||||
|
|
||||||
let exposed_imports = resolve_exposed_imports(exposed_imports, &exposes);
|
let exposed_imports = resolve_exposed_imports(exposed_imports, &exposes);
|
||||||
|
|
||||||
let modules_info = Arc::new(make_modules_info(exposes, &typechecked));
|
let modules_info = Arc::new(ModulesInfo::from_analysis(exposes, &typechecked));
|
||||||
let mut builder = AnalyzedDocumentBuilder {
|
let mut builder = AnalyzedDocumentBuilder {
|
||||||
interns: &interns,
|
interns: &interns,
|
||||||
module_id_to_url: module_id_to_url_from_sources(&sources),
|
module_id_to_url: module_id_to_url_from_sources(&sources),
|
||||||
@ -150,6 +182,13 @@ fn resolve_exposed_imports(
|
|||||||
exposed_imports: MutMap<ModuleId, MutMap<Symbol, roc_region::all::Region>>,
|
exposed_imports: MutMap<ModuleId, MutMap<Symbol, roc_region::all::Region>>,
|
||||||
exposes: &MutMap<ModuleId, Vec<(Symbol, Variable)>>,
|
exposes: &MutMap<ModuleId, Vec<(Symbol, Variable)>>,
|
||||||
) -> HashMap<ModuleId, Vec<(Symbol, Variable)>> {
|
) -> HashMap<ModuleId, Vec<(Symbol, Variable)>> {
|
||||||
|
let get_exposed_symbol_info = |symbol: &Symbol, module_id: &ModuleId| {
|
||||||
|
exposes
|
||||||
|
.get(module_id)?
|
||||||
|
.iter()
|
||||||
|
.find(|(symb, _)| symb == symbol)
|
||||||
|
};
|
||||||
|
|
||||||
exposed_imports
|
exposed_imports
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(module_id, symbols)| {
|
.map(|(module_id, symbols)| {
|
||||||
@ -157,41 +196,13 @@ fn resolve_exposed_imports(
|
|||||||
module_id,
|
module_id,
|
||||||
symbols
|
symbols
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|(symbol, _)| {
|
.filter_map(|(symbol, _)| get_exposed_symbol_info(&symbol, &module_id))
|
||||||
exposes.get(&module_id)?.iter().find(|(symb, _)| {
|
|
||||||
//TODO this seems to not be comparing properly so we aren't getting any exposed imports
|
|
||||||
symb == &symbol
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
///Transforms some of the raw data from the analysis into a state that is more useful during processes like completion
|
|
||||||
fn make_modules_info(
|
|
||||||
exposes: MutMap<ModuleId, Vec<(Symbol, Variable)>>,
|
|
||||||
typechecked: &MutMap<ModuleId, CheckedModule>,
|
|
||||||
) -> ModulesInfo {
|
|
||||||
//We wrap this in arc because later we will go through each module's imports and store the full list of symbols that each imported module exposes.
|
|
||||||
//eg: A imports B. B exposes [add, multiply, divide] and A will store a reference to that list.
|
|
||||||
let exposed = exposes
|
|
||||||
.into_iter()
|
|
||||||
.map(|(id, symbols)| (id, Arc::new(symbols)))
|
|
||||||
.collect::<HashMap<_, _>>();
|
|
||||||
//Combine the subs from all modules
|
|
||||||
let all_subs = Mutex::new(
|
|
||||||
typechecked
|
|
||||||
.iter()
|
|
||||||
.map(|(k, v)| (*k, v.solved_subs.0.clone()))
|
|
||||||
.collect::<HashMap<_, _>>(),
|
|
||||||
);
|
|
||||||
ModulesInfo {
|
|
||||||
subs: all_subs,
|
|
||||||
exposed,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_src_dir(path: &Path) -> &Path {
|
fn find_src_dir(path: &Path) -> &Path {
|
||||||
path.parent().unwrap_or(path)
|
path.parent().unwrap_or(path)
|
||||||
@ -275,6 +286,7 @@ impl<'a> AnalyzedDocumentBuilder<'a> {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<HashMap<_, _>>();
|
.collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
let exposed_imports = self.exposed_imports.remove(&module_id).unwrap_or_default();
|
let exposed_imports = self.exposed_imports.remove(&module_id).unwrap_or_default();
|
||||||
|
|
||||||
if let Some(m) = self.typechecked.remove(&module_id) {
|
if let Some(m) = self.typechecked.remove(&module_id) {
|
||||||
|
@ -13,9 +13,7 @@ use tower_lsp::lsp_types::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
analysis::completion::{
|
analysis::completion::{field_completion, get_completion_items, get_module_completion_items},
|
||||||
field_completion, get_completion_items, get_upper_case_completion_items,
|
|
||||||
},
|
|
||||||
convert::{ToRange, ToRocPosition},
|
convert::{ToRange, ToRocPosition},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -242,7 +240,7 @@ impl AnalyzedDocument {
|
|||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
if is_module_completion {
|
if is_module_completion {
|
||||||
info!("Getting module dot completion");
|
info!("Getting module dot completion");
|
||||||
Some(get_upper_case_completion_items(
|
Some(get_module_completion_items(
|
||||||
symbol_prefix,
|
symbol_prefix,
|
||||||
interns,
|
interns,
|
||||||
imports,
|
imports,
|
||||||
@ -267,7 +265,7 @@ impl AnalyzedDocument {
|
|||||||
.map_or(false, |c| c.is_uppercase());
|
.map_or(false, |c| c.is_uppercase());
|
||||||
if is_module_or_type_completion {
|
if is_module_or_type_completion {
|
||||||
info!("Getting module completion");
|
info!("Getting module completion");
|
||||||
let completions = get_upper_case_completion_items(
|
let completions = get_module_completion_items(
|
||||||
symbol_prefix,
|
symbol_prefix,
|
||||||
interns,
|
interns,
|
||||||
imports,
|
imports,
|
||||||
|
@ -321,62 +321,70 @@ pub fn get_completion_items(
|
|||||||
.collect(),
|
.collect(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
pub(super) fn get_upper_case_completion_items(
|
pub(super) fn get_module_completion_items(
|
||||||
prefix: String,
|
prefix: String,
|
||||||
interns: &Interns,
|
interns: &Interns,
|
||||||
imported_modules: &HashMap<ModuleId, Arc<Vec<(Symbol, Variable)>>>,
|
imported_modules: &HashMap<ModuleId, Arc<Vec<(Symbol, Variable)>>>,
|
||||||
modules_info: &ModulesInfo,
|
modules_info: &ModulesInfo,
|
||||||
just_modules: bool,
|
just_modules: bool,
|
||||||
) -> Vec<CompletionItem> {
|
) -> Vec<CompletionItem> {
|
||||||
let module_completions = imported_modules.iter().flat_map(|(mod_id, vars)| {
|
let module_completions = imported_modules
|
||||||
let mod_name = mod_id.to_ident_str(interns).to_string();
|
.iter()
|
||||||
|
.flat_map(|(mod_id, exposed_symbols)| {
|
||||||
|
let mod_name = mod_id.to_ident_str(interns).to_string();
|
||||||
|
|
||||||
if mod_name.starts_with(&prefix) {
|
if mod_name.starts_with(&prefix) {
|
||||||
let item = CompletionItem {
|
let item = CompletionItem {
|
||||||
label: mod_name.clone(),
|
label: mod_name.clone(),
|
||||||
kind: Some(CompletionItemKind::MODULE),
|
kind: Some(CompletionItemKind::MODULE),
|
||||||
documentation: Some(formatting::module_documentation(
|
documentation: Some(formatting::module_documentation(
|
||||||
formatting::DescriptionsType::Exposes,
|
formatting::DescriptionsType::Exposes,
|
||||||
mod_id,
|
mod_id,
|
||||||
interns,
|
interns,
|
||||||
modules_info,
|
exposed_symbols,
|
||||||
)),
|
modules_info,
|
||||||
..Default::default()
|
)),
|
||||||
};
|
..Default::default()
|
||||||
vec![item]
|
};
|
||||||
//Complete dot completions
|
vec![item]
|
||||||
} else if prefix.starts_with(&(mod_name + ".")) {
|
//Complete dot completions
|
||||||
vars.clone()
|
} else if prefix.starts_with(&(mod_name + ".")) {
|
||||||
.iter()
|
get_module_exposed_completion(exposed_symbols, modules_info, mod_id, interns)
|
||||||
.map(|(sym, var)| {
|
} else {
|
||||||
//We need to fetch the subs for the module that is exposing what we are trying to complete because that will have the type info we need
|
vec![]
|
||||||
modules_info
|
}
|
||||||
.subs
|
});
|
||||||
.lock()
|
|
||||||
.get_mut(mod_id)
|
|
||||||
.map(|subs| {
|
|
||||||
make_completion_item(
|
|
||||||
subs,
|
|
||||||
mod_id,
|
|
||||||
interns,
|
|
||||||
sym.as_str(interns).to_string(),
|
|
||||||
*var,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.expect("Couldn't find subs for module during completion.")
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
} else {
|
|
||||||
vec![]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if just_modules {
|
if just_modules {
|
||||||
return module_completions.collect();
|
return module_completions.collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
module_completions.collect()
|
module_completions.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_module_exposed_completion(
|
||||||
|
exposed_symbols: &Vec<(Symbol, Variable)>,
|
||||||
|
modules_info: &ModulesInfo,
|
||||||
|
mod_id: &ModuleId,
|
||||||
|
interns: &Interns,
|
||||||
|
) -> Vec<CompletionItem> {
|
||||||
|
exposed_symbols
|
||||||
|
.iter()
|
||||||
|
.map(|(sym, var)| {
|
||||||
|
//We need to fetch the subs for the module that is exposing what we are trying to complete because that will have the type info we need
|
||||||
|
modules_info
|
||||||
|
.with_subs(mod_id, |subs| {
|
||||||
|
make_completion_item(
|
||||||
|
subs,
|
||||||
|
mod_id,
|
||||||
|
interns,
|
||||||
|
sym.as_str(interns).to_string(),
|
||||||
|
*var,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.expect("Couldn't find subs for module during completion.")
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
|
||||||
///Provides a list of completions for Type aliases within the scope.
|
///Provides a list of completions for Type aliases within the scope.
|
||||||
///TODO: Use this when we know we are within a type definition
|
///TODO: Use this when we know we are within a type definition
|
||||||
fn _alias_completions(
|
fn _alias_completions(
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use roc_module::symbol::{Interns, ModuleId};
|
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||||
|
|
||||||
|
use roc_types::subs::Variable;
|
||||||
use tower_lsp::lsp_types::{Documentation, MarkupContent, MarkupKind};
|
use tower_lsp::lsp_types::{Documentation, MarkupContent, MarkupKind};
|
||||||
|
|
||||||
use crate::analysis::{utils::format_var_type, ModulesInfo};
|
use crate::analysis::{utils::format_var_type, ModulesInfo};
|
||||||
@ -7,20 +8,19 @@ use crate::analysis::{utils::format_var_type, ModulesInfo};
|
|||||||
fn module_exposed_list(
|
fn module_exposed_list(
|
||||||
module_id: &ModuleId,
|
module_id: &ModuleId,
|
||||||
interns: &Interns,
|
interns: &Interns,
|
||||||
ModulesInfo { subs, exposed }: &ModulesInfo,
|
modules_info: &ModulesInfo,
|
||||||
|
exposed: &Vec<(Symbol, Variable)>,
|
||||||
) -> Option<std::string::String> {
|
) -> Option<std::string::String> {
|
||||||
exposed.get(module_id).and_then(|exposed| {
|
modules_info.with_subs(module_id, |subs| {
|
||||||
subs.lock().get_mut(module_id).map(|subs| {
|
let items = exposed
|
||||||
let items = exposed
|
.iter()
|
||||||
.iter()
|
.map(|(symb, var)| {
|
||||||
.map(|(symb, var)| {
|
let var_str = format_var_type(*var, subs, module_id, interns);
|
||||||
let var_str = format_var_type(*var, subs, module_id, interns);
|
format!("{0}: {1}", symb.as_str(interns), var_str)
|
||||||
format!("{0}: {1}", symb.as_str(interns), var_str)
|
})
|
||||||
})
|
.collect::<Vec<_>>();
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
items.join("\n").to_string()
|
items.join("\n").to_string()
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub(super) enum DescriptionsType {
|
pub(super) enum DescriptionsType {
|
||||||
@ -38,11 +38,13 @@ pub(super) fn module_documentation(
|
|||||||
description_type: DescriptionsType,
|
description_type: DescriptionsType,
|
||||||
module_id: &ModuleId,
|
module_id: &ModuleId,
|
||||||
interns: &Interns,
|
interns: &Interns,
|
||||||
|
exposed: &Vec<(Symbol, Variable)>,
|
||||||
modules_info: &ModulesInfo,
|
modules_info: &ModulesInfo,
|
||||||
) -> Documentation {
|
) -> Documentation {
|
||||||
let exposed = || module_exposed_list(module_id, interns, modules_info).unwrap_or_default();
|
let exposed_string =
|
||||||
|
module_exposed_list(module_id, interns, modules_info, exposed).unwrap_or_default();
|
||||||
|
|
||||||
match description_type {
|
match description_type {
|
||||||
DescriptionsType::Exposes => md_doc(format!("```roc\n{0}\n```", exposed())),
|
DescriptionsType::Exposes => md_doc(format!("```roc\n{0}\n```", exposed_string)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user