mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 13:02:07 +03:00
Add a shortcut to toggle the visibility of private components in the component browser (#5582)
Closes #4962 This PR adds the `cmd+alt+p` shortcut to toggle the visibility of components with a "PRIVATE" tag in the component browser. The default is to have these private components hidden. https://user-images.githubusercontent.com/117099775/219106357-0b14a5b5-404f-44dd-b30c-5389054683a7.mp4
This commit is contained in:
parent
97bcd87dc6
commit
4f11ad10fa
@ -92,6 +92,8 @@
|
||||
- [Added restoring of last project snapshot on shortcut.][4050]
|
||||
- [Added contextual suggestions to argument dropdowns][4072]. Dropdowns will now
|
||||
contain suggestions which are based on evaluated data.
|
||||
- [Added a shortcut to show internal components (private API) in the component
|
||||
browser.][5582]
|
||||
- [Improved component browser entry filtering and sorting][5645]. The component
|
||||
browser will now provide suggestions matching either the component's label or
|
||||
the corresponding code.
|
||||
@ -482,6 +484,7 @@
|
||||
[4120]: https://github.com/enso-org/enso/pull/4120
|
||||
[4050]: https://github.com/enso-org/enso/pull/4050
|
||||
[4072]: https://github.com/enso-org/enso/pull/4072
|
||||
[5582]: https://github.com/enso-org/enso/pull/5582
|
||||
[5645]: https://github.com/enso-org/enso/pull/5645
|
||||
[5646]: https://github.com/enso-org/enso/pull/5646
|
||||
[5656]: https://github.com/enso-org/enso/pull/5656
|
||||
|
@ -129,6 +129,7 @@ broken and require further investigation.
|
||||
| <kbd>ctrl</kbd> + <kbd>alt</kbd> + <kbd>shift</kbd> + <kbd>r</kbd> | Reload the visual interface. |
|
||||
| <kbd>ctrl</kbd> + <kbd>alt</kbd> + <kbd>0 - 10</kbd> | Switch between debug rendering modes (0 is the normal mode). |
|
||||
| <kbd>ctrl</kbd> + <kbd>alt</kbd> + <kbd>`</kbd> | Toggle profiling monitor (performance, memory usage, etc). |
|
||||
| <kbd>ctrl</kbd> + <kbd>alt</kbd> + <kbd>p</kbd> | Toggle the visibility of internal components (private API) in the component browser. |
|
||||
| <kbd>ctrl</kbd> + <kbd>d</kbd> | Send test data to the selected node. |
|
||||
| <kbd>ctrl</kbd> + <kbd>shift</kbd> + <kbd>enter</kbd> | Push a hardcoded breadcrumb without navigating. |
|
||||
| <kbd>ctrl</kbd> + <kbd>shift</kbd> + <kbd>arrow up</kbd> | Pop a breadcrumb without navigating. |
|
||||
|
@ -192,6 +192,12 @@ pub trait API: Debug {
|
||||
// Automock macro does not work without explicit lifetimes here.
|
||||
#[allow(clippy::needless_lifetimes)]
|
||||
fn manage_projects<'a>(&'a self) -> FallibleResult<&'a dyn ManagingProjectAPI>;
|
||||
|
||||
/// Return whether private entries should be visible in the component browser.
|
||||
fn are_component_browser_private_entries_visible(&self) -> bool;
|
||||
|
||||
/// Sets whether private entries should be visible in the component browser.
|
||||
fn set_component_browser_private_entries_visibility(&self, visibility: bool);
|
||||
}
|
||||
|
||||
/// A polymorphic handle of IDE controller.
|
||||
|
@ -38,12 +38,13 @@ const UNNAMED_PROJECT_NAME: &str = "Unnamed";
|
||||
#[derive(Clone, CloneRef, Derivative)]
|
||||
#[derivative(Debug)]
|
||||
pub struct Handle {
|
||||
current_project: Rc<CloneCell<Option<model::Project>>>,
|
||||
current_project: Rc<CloneCell<Option<model::Project>>>,
|
||||
#[derivative(Debug = "ignore")]
|
||||
project_manager: Rc<dyn project_manager::API>,
|
||||
project_manager: Rc<dyn project_manager::API>,
|
||||
status_notifications: StatusNotificationPublisher,
|
||||
parser: Parser,
|
||||
notifications: notification::Publisher<Notification>,
|
||||
parser: Parser,
|
||||
notifications: notification::Publisher<Notification>,
|
||||
component_browser_private_entries_visibility_flag: Rc<Cell<bool>>,
|
||||
}
|
||||
|
||||
impl Handle {
|
||||
@ -71,7 +72,15 @@ impl Handle {
|
||||
let status_notifications = default();
|
||||
let parser = Parser::new();
|
||||
let notifications = default();
|
||||
Self { current_project, project_manager, status_notifications, parser, notifications }
|
||||
let component_browser_private_entries_visibility_flag = default();
|
||||
Self {
|
||||
current_project,
|
||||
project_manager,
|
||||
status_notifications,
|
||||
parser,
|
||||
notifications,
|
||||
component_browser_private_entries_visibility_flag,
|
||||
}
|
||||
}
|
||||
|
||||
/// Open project with provided name.
|
||||
@ -107,6 +116,17 @@ impl API for Handle {
|
||||
fn manage_projects(&self) -> FallibleResult<&dyn ManagingProjectAPI> {
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn are_component_browser_private_entries_visible(&self) -> bool {
|
||||
self.component_browser_private_entries_visibility_flag.get()
|
||||
}
|
||||
|
||||
fn set_component_browser_private_entries_visibility(&self, visibility: bool) {
|
||||
debug!(
|
||||
"Setting the visibility of private entries in the component browser to {visibility}."
|
||||
);
|
||||
self.component_browser_private_entries_visibility_flag.set(visibility);
|
||||
}
|
||||
}
|
||||
|
||||
impl ManagingProjectAPI for Handle {
|
||||
|
@ -38,8 +38,9 @@ pub struct ProjectOperationsNotSupported;
|
||||
#[derive(Clone, CloneRef, Debug)]
|
||||
pub struct Handle {
|
||||
pub status_notifications: StatusNotificationPublisher,
|
||||
pub parser: Parser,
|
||||
pub project: model::Project,
|
||||
pub parser: Parser,
|
||||
pub project: model::Project,
|
||||
component_browser_private_entries_visibility_flag: Rc<Cell<bool>>,
|
||||
}
|
||||
|
||||
impl Handle {
|
||||
@ -47,7 +48,13 @@ impl Handle {
|
||||
pub fn new(project: model::Project) -> Self {
|
||||
let status_notifications = default();
|
||||
let parser = Parser::new();
|
||||
Self { status_notifications, parser, project }
|
||||
let component_browser_private_entries_visibility_flag = default();
|
||||
Self {
|
||||
status_notifications,
|
||||
parser,
|
||||
project,
|
||||
component_browser_private_entries_visibility_flag,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create IDE Controller from Language Server endpoints, describing the opened project.
|
||||
@ -74,7 +81,13 @@ impl Handle {
|
||||
.await?;
|
||||
let status_notifications = default();
|
||||
let parser = Parser::new();
|
||||
Ok(Self { status_notifications, parser, project })
|
||||
let component_browser_private_entries_visibility_flag = default();
|
||||
Ok(Self {
|
||||
status_notifications,
|
||||
parser,
|
||||
project,
|
||||
component_browser_private_entries_visibility_flag,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,4 +109,15 @@ impl controller::ide::API for Handle {
|
||||
fn manage_projects(&self) -> FallibleResult<&dyn ManagingProjectAPI> {
|
||||
Err(ProjectOperationsNotSupported.into())
|
||||
}
|
||||
|
||||
fn are_component_browser_private_entries_visible(&self) -> bool {
|
||||
self.component_browser_private_entries_visibility_flag.get()
|
||||
}
|
||||
|
||||
fn set_component_browser_private_entries_visibility(&self, visibility: bool) {
|
||||
debug!(
|
||||
"Setting the visibility of private entries in the component browser to {visibility}."
|
||||
);
|
||||
self.component_browser_private_entries_visibility_flag.set(visibility);
|
||||
}
|
||||
}
|
||||
|
@ -1140,7 +1140,7 @@ impl Searcher {
|
||||
/// The current list will be set as "Loading" and Language Server will be requested for a new
|
||||
/// list - once it be retrieved, the new list will be set and notification will be emitted.
|
||||
#[profile(Debug)]
|
||||
fn reload_list(&self) {
|
||||
pub fn reload_list(&self) {
|
||||
let this_type = self.this_arg_type_for_next_completion();
|
||||
let return_types = match self.data.borrow().input.next_completion_id() {
|
||||
CompletedFragmentId::Function => vec![],
|
||||
@ -1222,10 +1222,12 @@ impl Searcher {
|
||||
info!("Received suggestions from Language Server.");
|
||||
let list = this.make_action_list(responses.iter());
|
||||
let mut data = this.data.borrow_mut();
|
||||
list.update_filtering(&data.input.pattern);
|
||||
data.actions = Actions::Loaded { list: Rc::new(list) };
|
||||
let completions = responses.iter().flat_map(|r| r.results.iter().cloned());
|
||||
data.components =
|
||||
this.make_component_list(completions, &this_type, &return_types);
|
||||
data.components.update_filtering(&data.input.pattern);
|
||||
}
|
||||
Err(err) => {
|
||||
let msg = "Request for completions to the Language Server returned error";
|
||||
@ -1234,6 +1236,7 @@ impl Searcher {
|
||||
data.actions = Actions::Error(Rc::new(err.into()));
|
||||
data.components =
|
||||
this.make_component_list(this.database.keys(), &this_type, &return_types);
|
||||
data.components.update_filtering(&data.input.pattern);
|
||||
}
|
||||
}
|
||||
this.notifier.publish(Notification::NewActionList).await;
|
||||
@ -1300,6 +1303,7 @@ impl Searcher {
|
||||
&self.database,
|
||||
module_name.as_ref(),
|
||||
&*favorites,
|
||||
self.ide.are_component_browser_private_entries_visible(),
|
||||
);
|
||||
add_virtual_entries_to_builder(&mut builder, this_type, return_types);
|
||||
builder.extend_list_and_allow_favorites_with_ids(&self.database, entry_ids);
|
||||
@ -1446,8 +1450,13 @@ fn component_list_builder_with_favorites<'a>(
|
||||
suggestion_db: &model::SuggestionDatabase,
|
||||
local_scope_module: QualifiedNameRef,
|
||||
groups: impl IntoIterator<Item = &'a model::execution_context::ComponentGroup>,
|
||||
private_entries_visibile: bool,
|
||||
) -> component::builder::List {
|
||||
let mut builder = component::builder::List::new();
|
||||
let mut builder = if private_entries_visibile {
|
||||
component::builder::List::new_with_private_components()
|
||||
} else {
|
||||
component::builder::List::new()
|
||||
};
|
||||
if let Some((id, _)) = suggestion_db.lookup_by_qualified_name(local_scope_module) {
|
||||
builder = builder.with_local_scope_module_id(id);
|
||||
}
|
||||
@ -1783,6 +1792,7 @@ pub mod test {
|
||||
ide.expect_current_project().returning_st(move || Some(current_project.clone_ref()));
|
||||
ide.expect_manage_projects()
|
||||
.returning_st(move || Err(ProjectOperationsNotSupported.into()));
|
||||
ide.expect_are_component_browser_private_entries_visible().returning_st(|| false);
|
||||
let node_metadata_guard = default();
|
||||
let breadcrumbs = Breadcrumbs::new();
|
||||
let searcher = Searcher {
|
||||
|
@ -159,6 +159,7 @@ pub struct List {
|
||||
/// IDs of [`Component`]s allowed in [`component::List::favorites`] if they are also present in
|
||||
/// [`grouping_and_order_of_favorites`].
|
||||
allowed_favorites: HashSet<component::Id>,
|
||||
keep_private_components: bool,
|
||||
}
|
||||
|
||||
impl List {
|
||||
@ -167,6 +168,12 @@ impl List {
|
||||
default()
|
||||
}
|
||||
|
||||
/// Construct List builder without content, do not remove private components when extending
|
||||
/// list.
|
||||
pub fn new_with_private_components() -> Self {
|
||||
List { keep_private_components: true, ..default() }
|
||||
}
|
||||
|
||||
/// Return [`List`] with a new [`local_scope`] with its [`Group::component_id`] field set to
|
||||
/// `module_id`. When the [`extend_list_and_allow_favorites_with_ids`] method is called on the
|
||||
/// returned object, components passed to the method which have their parent module ID equal
|
||||
@ -191,6 +198,7 @@ impl List {
|
||||
let local_scope_id = self.local_scope.component_id;
|
||||
let id_and_looked_up_entry = |id| Some((id, db.lookup(id).ok()?));
|
||||
let ids_and_entries = entry_ids.into_iter().filter_map(id_and_looked_up_entry);
|
||||
let keep_private_components = self.keep_private_components;
|
||||
for (id, entry) in ids_and_entries {
|
||||
self.allowed_favorites.insert(id);
|
||||
let component = Component::new_from_database_entry(id, entry.clone_ref());
|
||||
@ -202,7 +210,9 @@ impl List {
|
||||
let in_local_scope = parent_id == local_scope_id && local_scope_id.is_some();
|
||||
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 {
|
||||
let keep_private_component =
|
||||
in_local_scope || in_local_namespace || keep_private_components;
|
||||
if !component.is_private() || keep_private_component {
|
||||
parent_group.content.entries.borrow_mut().push(component.clone_ref());
|
||||
component_inserted_somewhere = true;
|
||||
let not_module = entry.kind != Kind::Module;
|
||||
@ -216,7 +226,8 @@ impl List {
|
||||
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 {
|
||||
let keep_private_component = in_local_namespace || keep_private_components;
|
||||
if !component.is_private() || keep_private_component {
|
||||
flatten_group.entries.borrow_mut().push(component.clone_ref());
|
||||
component_inserted_somewhere = true;
|
||||
}
|
||||
|
@ -194,6 +194,11 @@ impl Model {
|
||||
})
|
||||
}
|
||||
|
||||
fn toggle_component_browser_private_entries_visibility(&self) {
|
||||
let visibility = self.ide_controller.are_component_browser_private_entries_visible();
|
||||
self.ide_controller.set_component_browser_private_entries_visibility(!visibility);
|
||||
}
|
||||
|
||||
fn restore_project_snapshot(&self) {
|
||||
let controller = self.controller.clone_ref();
|
||||
let breadcrumbs = self.view.graph().model.breadcrumbs.clone_ref();
|
||||
@ -362,6 +367,10 @@ impl Project {
|
||||
eval_ view.save_project_snapshot(model.save_project_snapshot());
|
||||
eval_ view.restore_project_snapshot(model.restore_project_snapshot());
|
||||
|
||||
eval_ view.toggle_component_browser_private_entries_visibility(
|
||||
model.toggle_component_browser_private_entries_visibility()
|
||||
);
|
||||
|
||||
eval_ view.execution_context_interrupt(model.execution_context_interrupt());
|
||||
|
||||
eval_ view.execution_context_restart(model.execution_context_restart());
|
||||
|
@ -346,6 +346,9 @@ impl Searcher {
|
||||
|
||||
action_list_changed <- source::<()>();
|
||||
select_entry <- action_list_changed.filter(f_!(model.should_auto_select_first_action()));
|
||||
|
||||
eval_ model.view.toggle_component_browser_private_entries_visibility (
|
||||
model.controller.reload_list());
|
||||
}
|
||||
|
||||
match model.view.searcher() {
|
||||
@ -368,7 +371,10 @@ impl Searcher {
|
||||
|
||||
entry_selected <- grid.active.filter_map(|&s| s?.as_entry_id());
|
||||
selected_entry_changed <- entry_selected.on_change().constant(());
|
||||
grid.unhover_element <+ selected_entry_changed;
|
||||
grid.unhover_element <+ any2(
|
||||
&selected_entry_changed,
|
||||
&model.view.toggle_component_browser_private_entries_visibility,
|
||||
);
|
||||
hovered_not_selected <- all_with(&grid.hovered, &grid.active, |h, s| {
|
||||
match (h, s) {
|
||||
(Some(h), Some(s)) => h != s,
|
||||
|
@ -228,6 +228,7 @@ impl Navigator {
|
||||
section_count <- set_namespace_section_count.map(
|
||||
|&n: &usize| n + MIN_BOTTOM_BUTTONS_COUNT
|
||||
);
|
||||
section_count <- section_count.on_change();
|
||||
bottom_buttons_shape <- section_count.map(|n| (*n, 1));
|
||||
bottom_buttons_params <- all2(§ion_count, &style);
|
||||
bottom_buttons_viewport <- bottom_buttons_params.map(get_bottom_buttons_viewport);
|
||||
|
@ -81,6 +81,8 @@ ensogl::define_endpoints! {
|
||||
hide_graph_editor(),
|
||||
/// Simulates a style toggle press event.
|
||||
toggle_style(),
|
||||
/// Toggles the visibility of private components in the component browser.
|
||||
toggle_component_browser_private_entries_visibility(),
|
||||
/// Saves a snapshot of the current state of the project to the VCS.
|
||||
save_project_snapshot(),
|
||||
/// Restores the state of the project to the last snapshot saved to the VCS.
|
||||
@ -767,6 +769,7 @@ impl application::View for View {
|
||||
(Press, "is_searcher_opened", "escape", "close_searcher"),
|
||||
(Press, "project_list_shown", "escape", "hide_project_list"),
|
||||
(Press, "", "cmd alt shift t", "toggle_style"),
|
||||
(Press, "", "cmd alt p", "toggle_component_browser_private_entries_visibility"),
|
||||
(Press, "", "cmd s", "save_project_snapshot"),
|
||||
(Press, "", "cmd r", "restore_project_snapshot"),
|
||||
(Press, "", "cmd z", "undo"),
|
||||
|
Loading…
Reference in New Issue
Block a user