diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f9ea5988f22..b5fb5fd00c80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -86,6 +86,8 @@ present only when the argument is of type that has a predefined set of values. - [Separate component browser navigator sections for modules imported from different namespaces][4044] +- [Internal components (private API) are not displayed in the component + browser.][4085] - [The correct default visualisation for tables is shown on new nodes.][4120] - [Added contextual suggestions to argument dropdowns][4072]. Dropdowns will now contain suggestions which are based on evaluated data. @@ -464,6 +466,7 @@ [4052]: https://github.com/enso-org/enso/pull/4052 [4063]: https://github.com/enso-org/enso/pull/4063 [4078]: https://github.com/enso-org/enso/pull/4078 +[4085]: https://github.com/enso-org/enso/pull/4085 [4097]: https://github.com/enso-org/enso/pull/4097 [4120]: https://github.com/enso-org/enso/pull/4120 [4072]: https://github.com/enso-org/enso/pull/4072 diff --git a/app/gui/language/ast/impl/src/lib.rs b/app/gui/language/ast/impl/src/lib.rs index 9066b9f66a02..4e51a9604dd7 100644 --- a/app/gui/language/ast/impl/src/lib.rs +++ b/app/gui/language/ast/impl/src/lib.rs @@ -80,6 +80,9 @@ pub mod constants { /// The "void" atom returned by function meant to not return any argument. pub const NOTHING: &str = "Nothing"; } + + /// The tag name of documentation sections marked as "PRIVATE" + pub const PRIVATE_DOC_SECTION_TAG_NAME: &str = "PRIVATE"; } pub use crumbs::Crumb; diff --git a/app/gui/src/controller/searcher/component.rs b/app/gui/src/controller/searcher/component.rs index 48ba84467bb2..b85b66cb1d02 100644 --- a/app/gui/src/controller/searcher/component.rs +++ b/app/gui/src/controller/searcher/component.rs @@ -9,6 +9,7 @@ use crate::model::suggestion_database; use convert_case::Case; use convert_case::Casing; use double_representation::name::QualifiedName; +use engine_protocol::language_server::DocSection; // ============== @@ -162,6 +163,18 @@ impl Component { None => MatchInfo::DoesNotMatch, }; } + + /// Check whether the component contains the "PRIVATE" tag. + pub fn is_private(&self) -> bool { + match &self.data { + Data::FromDatabase { entry, .. } => entry.documentation.iter().any(|doc| match doc { + DocSection::Tag { name, .. } => + name == ast::constants::PRIVATE_DOC_SECTION_TAG_NAME, + _ => false, + }), + _ => false, + } + } } impl From> for Component { diff --git a/app/gui/src/controller/searcher/component/builder.rs b/app/gui/src/controller/searcher/component/builder.rs index 518972ce4dbb..dc01cef24dc1 100644 --- a/app/gui/src/controller/searcher/component/builder.rs +++ b/app/gui/src/controller/searcher/component/builder.rs @@ -32,6 +32,15 @@ use double_representation::name::QualifiedNameTemplate; +// ================= +// === Constants === +// ================= + +/// The `local` namespace, within which modules local to the project are located. +const LOCAL_NAMESPACE: &str = "local"; + + + // ==================== // === ModuleGroups === // ==================== @@ -189,19 +198,28 @@ impl List { if let Some(parent_module) = entry.parent_module() { if let Some(parent_group) = self.lookup_module_group(db, parent_module.clone_ref()) { - parent_group.content.entries.borrow_mut().push(component.clone_ref()); - component_inserted_somewhere = true; let parent_id = parent_group.content.component_id; let in_local_scope = parent_id == local_scope_id && local_scope_id.is_some(); - let not_module = entry.kind != Kind::Module; - if in_local_scope && not_module { - self.local_scope.entries.borrow_mut().push(component.clone_ref()); + let namespace = &parent_group.qualified_name.project().namespace; + let in_local_namespace = namespace == LOCAL_NAMESPACE; + if !component.is_private() || in_local_scope || in_local_namespace { + parent_group.content.entries.borrow_mut().push(component.clone_ref()); + component_inserted_somewhere = true; + let not_module = entry.kind != Kind::Module; + if in_local_scope && not_module { + self.local_scope.entries.borrow_mut().push(component.clone_ref()); + } } } if let Some(top_group) = self.lookup_module_group(db, top_module(&parent_module)) { if let Some(flatten_group) = &mut top_group.flattened_content { - flatten_group.entries.borrow_mut().push(component.clone_ref()); - component_inserted_somewhere = true; + let project = flatten_group.project.as_ref(); + let in_local_namespace = + project.map(|name| name.namespace == LOCAL_NAMESPACE).unwrap_or(false); + if !component.is_private() || in_local_namespace { + flatten_group.entries.borrow_mut().push(component.clone_ref()); + component_inserted_somewhere = true; + } } } } @@ -593,4 +611,41 @@ mod tests { assert_eq!(group_at_1.name, "Group 1"); check_names_and_order_of_group_entries(group_at_1, &[qn_of_db_entry_1.name()]); } + + /// Test building a component list with a private component. The private component will be + /// excluded from the list. + #[test] + fn building_component_list_with_private_component() { + use ast::constants::PRIVATE_DOC_SECTION_TAG_NAME as PRIVATE_TAG; + let private_doc_section = enso_suggestion_database::doc_section!(@ PRIVATE_TAG, ""); + let suggestion_db = enso_suggestion_database::mock_suggestion_database! { + test.Test { + mod LocalModule { + fn local_fun1() -> Standard.Base.Any; + #[with_doc_section(private_doc_section.clone())] + fn local_private_fun2() -> Standard.Base.Any; + } + mod TopModule { + fn fun3() -> Standard.Base.Any; + #[with_doc_section(private_doc_section.clone())] + fn private_fun4() -> Standard.Base.Any; + } + } + }; + let mut builder = List::new().with_local_scope_module_id(1); + // ID's for `test.Test`, `TopModule` and 3 function ID's in `suggestion_db`. + let entry_ids = 0..9; + builder.extend_list_and_allow_favorites_with_ids(&suggestion_db, entry_ids); + let list = builder.build(); + let component_names: Vec<_> = list + .all_components + .iter() + .filter_map(|component| match &component.data { + component::Data::FromDatabase { entry, .. } => Some(&entry.name), + _ => None, + }) + .collect(); + let expected = vec!["LocalModule", "local_fun1", "local_private_fun2", "TopModule", "fun3"]; + assert_eq!(component_names, expected); + } }