mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-01 10:52:18 +00:00
first working version of docs hover
This commit is contained in:
parent
87af8bd610
commit
cdf218fe7a
8 changed files with 58748 additions and 31 deletions
58647
crates/compiler/load_internal/log.log
Normal file
58647
crates/compiler/load_internal/log.log
Normal file
File diff suppressed because one or more lines are too long
|
@ -177,6 +177,8 @@ fn generate_entry_docs(
|
|||
let mut acc = Vec::with_capacity(defs.tags.len() + 1);
|
||||
|
||||
if let Some(docs) = comments_or_new_lines_to_docs(header_comments) {
|
||||
println!("<<docs:\n {:#?}\n docs>>", docs);
|
||||
|
||||
acc.push(DetachedDoc(docs));
|
||||
}
|
||||
|
||||
|
@ -197,6 +199,7 @@ fn generate_entry_docs(
|
|||
|
||||
let docs = comments_or_new_lines_to_docs(&scratchpad);
|
||||
|
||||
println!("<<docs:\n {:#?}\n docs>>", docs);
|
||||
match either_index.split() {
|
||||
Err(value_index) => match &defs.value_defs[value_index.index()] {
|
||||
ValueDef::Annotation(loc_pattern, loc_ann) => {
|
||||
|
@ -379,12 +382,14 @@ fn contains_unexposed_type(
|
|||
Apply(module_name, _ident, loc_args) => {
|
||||
// If the *ident* was unexposed, we would have gotten a naming error
|
||||
// during canonicalization, so all we need to check is the module.
|
||||
let module_id = module_ids.get_id(&(*module_name).into()).unwrap();
|
||||
|
||||
!exposed_module_ids.contains(&module_id)
|
||||
|| loc_args.iter().any(|loc_arg| {
|
||||
contains_unexposed_type(&loc_arg.value, exposed_module_ids, module_ids)
|
||||
})
|
||||
if let Some(module_id) = module_ids.get_id(&(*module_name).into()) {
|
||||
!exposed_module_ids.contains(&module_id)
|
||||
|| loc_args.iter().any(|loc_arg| {
|
||||
contains_unexposed_type(&loc_arg.value, exposed_module_ids, module_ids)
|
||||
})
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Malformed(_) | Inferred | Wildcard | BoundVariable(_) => false,
|
||||
Function(loc_args, loc_ret) => {
|
||||
|
|
|
@ -3378,17 +3378,13 @@ fn finish(
|
|||
|
||||
roc_checkmate::dump_checkmate!(checkmate);
|
||||
|
||||
let mut docs_by_module = Vec::with_capacity(state.exposed_modules.len());
|
||||
// let mut docs_by_module = Vec::with_capacity(state.exposed_modules.len());
|
||||
|
||||
for module_id in state.exposed_modules.iter() {
|
||||
let docs = documentation.remove(module_id).unwrap_or_else(|| {
|
||||
panic!("A module was exposed but didn't have an entry in `documentation` somehow: {module_id:?}");
|
||||
});
|
||||
|
||||
docs_by_module.push(docs);
|
||||
}
|
||||
|
||||
debug_assert_eq!(documentation.len(), 0);
|
||||
// for (module_id, _) in state.module_cache.module_names {
|
||||
// if let Some(docs) = documentation.remove(&module_id) {
|
||||
// docs_by_module.push(docs);
|
||||
// }
|
||||
// }
|
||||
|
||||
LoadedModule {
|
||||
module_id: state.root_id,
|
||||
|
@ -3406,7 +3402,7 @@ fn finish(
|
|||
resolved_implementations,
|
||||
sources,
|
||||
timings: state.timings,
|
||||
docs_by_module,
|
||||
docs_by_module: documentation,
|
||||
abilities_store,
|
||||
exposed_imports: state.module_cache.exposed_imports,
|
||||
imports: state.module_cache.imports,
|
||||
|
@ -5411,9 +5407,7 @@ fn canonicalize_and_constrain<'a>(
|
|||
}
|
||||
HeaderType::Interface { name, .. }
|
||||
| HeaderType::Builtin { name, .. }
|
||||
| HeaderType::Hosted { name, .. }
|
||||
if exposed_module_ids.contains(&parsed.module_id) =>
|
||||
{
|
||||
| HeaderType::Hosted { name, .. } => {
|
||||
let mut scope = module_output.scope.clone();
|
||||
scope.add_docs_imports();
|
||||
let docs = crate::docs::generate_module_docs(
|
||||
|
@ -5427,12 +5421,11 @@ fn canonicalize_and_constrain<'a>(
|
|||
parsed.header_comments,
|
||||
);
|
||||
|
||||
println!("adding docs for {:?},", module_path);
|
||||
println!("docs {:#?},", &docs);
|
||||
|
||||
Some(docs)
|
||||
}
|
||||
HeaderType::Interface { .. } | HeaderType::Builtin { .. } | HeaderType::Hosted { .. } => {
|
||||
// This module isn't exposed by the platform, so don't generate docs for it!
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
// _before has an underscore because it's unused in --release builds
|
||||
|
|
|
@ -43,7 +43,7 @@ pub struct LoadedModule {
|
|||
pub resolved_implementations: ResolvedImplementations,
|
||||
pub sources: MutMap<ModuleId, (PathBuf, Box<str>)>,
|
||||
pub timings: MutMap<ModuleId, ModuleTiming>,
|
||||
pub docs_by_module: Vec<(ModuleId, ModuleDocumentation)>,
|
||||
pub docs_by_module: VecMap<ModuleId, ModuleDocumentation>,
|
||||
pub abilities_store: AbilitiesStore,
|
||||
pub typechecked: MutMap<ModuleId, CheckedModule>,
|
||||
|
||||
|
|
17
crates/compiler/load_internal/tests/fixtures/build/no_deps/Docs.roc
vendored
Normal file
17
crates/compiler/load_internal/tests/fixtures/build/no_deps/Docs.roc
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
## An interface for docs tests
|
||||
interface Docs
|
||||
exposes [makeUser, getName]
|
||||
imports []
|
||||
|
||||
## This is a user
|
||||
User : { name : Str }
|
||||
|
||||
## Makes a user
|
||||
makeUser : Str -> User
|
||||
makeUser = \name ->
|
||||
{ name }
|
||||
|
||||
## gets the user's name
|
||||
getName : User -> Str
|
||||
getName = \a -> a.name
|
||||
|
|
@ -422,6 +422,24 @@ fn load_unit() {
|
|||
},
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn load_docs() {
|
||||
let subs_by_module = Default::default();
|
||||
let loaded_module = load_fixture("no_deps", "Docs", subs_by_module);
|
||||
|
||||
let prob = format!("{:#?}", loaded_module.can_problems);
|
||||
let prob_type = format!("{:#?}", loaded_module.type_problems);
|
||||
// assert_str_eq!("", prob, "can problems");
|
||||
// assert_str_eq!("", prob_type, "type problems");
|
||||
let docs = format!(
|
||||
"{:#?}",
|
||||
loaded_module
|
||||
.docs_by_module
|
||||
.get(&loaded_module.module_id)
|
||||
.unwrap()
|
||||
);
|
||||
assert_str_eq!("", docs);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn import_alias() {
|
||||
|
|
|
@ -8,8 +8,11 @@ use bumpalo::Bump;
|
|||
|
||||
use parking_lot::Mutex;
|
||||
use roc_can::{abilities::AbilitiesStore, expr::Declarations};
|
||||
use roc_collections::{MutMap, MutSet};
|
||||
use roc_load::{CheckedModule, LoadedModule};
|
||||
use roc_collections::{MutMap, MutSet, VecMap};
|
||||
use roc_load::{
|
||||
docs::{DocDef, ModuleDocumentation},
|
||||
CheckedModule, LoadedModule,
|
||||
};
|
||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||
use roc_packaging::cache::{self, RocCacheDir};
|
||||
use roc_region::all::LineInfo;
|
||||
|
@ -86,6 +89,7 @@ pub(super) struct AnalyzedModule {
|
|||
// We need this because ModuleIds are not stable between compilations, so a ModuleId visible to
|
||||
// one module may not be true global to the language server.
|
||||
module_id_to_url: ModuleIdToUrl,
|
||||
docs_by_module: Arc<VecMap<ModuleId, ModuleDocumentation>>,
|
||||
}
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AnalysisResult {
|
||||
|
@ -144,6 +148,7 @@ pub(crate) fn global_analysis(doc_info: DocInfo) -> Vec<AnalyzedDocument> {
|
|||
exposed_imports,
|
||||
mut imports,
|
||||
exposes,
|
||||
docs_by_module,
|
||||
..
|
||||
} = module;
|
||||
|
||||
|
@ -153,6 +158,7 @@ pub(crate) fn global_analysis(doc_info: DocInfo) -> Vec<AnalyzedDocument> {
|
|||
});
|
||||
|
||||
let exposed_imports = resolve_exposed_imports(exposed_imports, &exposes);
|
||||
let docs_by_module = Arc::new(docs_by_module);
|
||||
|
||||
let modules_info = Arc::new(ModulesInfo::from_analysis(exposes, &typechecked));
|
||||
let mut builder = AnalyzedDocumentBuilder {
|
||||
|
@ -166,6 +172,7 @@ pub(crate) fn global_analysis(doc_info: DocInfo) -> Vec<AnalyzedDocument> {
|
|||
exposed_imports,
|
||||
imports: &mut imports,
|
||||
modules_info,
|
||||
docs_by_module,
|
||||
};
|
||||
|
||||
for (module_id, (path, source)) in sources {
|
||||
|
@ -255,6 +262,7 @@ struct AnalyzedDocumentBuilder<'a> {
|
|||
imports: &'a mut MutMap<ModuleId, MutSet<ModuleId>>,
|
||||
exposed_imports: HashMap<ModuleId, Vec<(Symbol, Variable)>>,
|
||||
modules_info: Arc<ModulesInfo>,
|
||||
docs_by_module: Arc<VecMap<ModuleId, ModuleDocumentation>>,
|
||||
}
|
||||
|
||||
impl<'a> AnalyzedDocumentBuilder<'a> {
|
||||
|
@ -296,6 +304,7 @@ impl<'a> AnalyzedDocumentBuilder<'a> {
|
|||
modules_info: self.modules_info.clone(),
|
||||
interns: self.interns.clone(),
|
||||
module_id_to_url: self.module_id_to_url.clone(),
|
||||
docs_by_module: self.docs_by_module.clone(),
|
||||
};
|
||||
|
||||
let line_info = LineInfo::new(&source);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use log::{debug, info};
|
||||
use roc_load::docs::DocDef;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use bumpalo::Bump;
|
||||
|
@ -169,19 +170,46 @@ impl AnalyzedDocument {
|
|||
declarations,
|
||||
module_id,
|
||||
interns,
|
||||
abilities,
|
||||
docs_by_module,
|
||||
..
|
||||
} = self.module()?;
|
||||
|
||||
let (region, var) = roc_can::traverse::find_closest_type_at(pos, declarations)?;
|
||||
|
||||
let docs = roc_can::traverse::find_closest_symbol_at(pos, declarations, abilities)
|
||||
.and_then(|symb| {
|
||||
let symb = symb.implementation_symbol();
|
||||
docs_by_module
|
||||
.get(module_id)?
|
||||
.entries
|
||||
.iter()
|
||||
.find_map(|doc| match doc {
|
||||
roc_load::docs::DocEntry::DocDef(DocDef { symbol, docs, .. })
|
||||
if symbol == &symb =>
|
||||
{
|
||||
docs.clone()
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
});
|
||||
|
||||
let type_str = format_var_type(var, &mut subs.clone(), module_id, interns);
|
||||
|
||||
let range = region.to_range(self.line_info());
|
||||
|
||||
let type_content = MarkedString::LanguageString(LanguageString {
|
||||
language: "roc".to_string(),
|
||||
value: type_str,
|
||||
});
|
||||
|
||||
let content = vec![Some(type_content), docs.map(|a| MarkedString::String(a))]
|
||||
.into_iter()
|
||||
.filter_map(|a| a)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Some(Hover {
|
||||
contents: HoverContents::Scalar(MarkedString::LanguageString(LanguageString {
|
||||
language: "roc".to_string(),
|
||||
value: type_str,
|
||||
})),
|
||||
contents: HoverContents::Array(content),
|
||||
range: Some(range),
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue