Add api for updating searcher with selected component (#3659)

Implements [#182593882](https://www.pivotaltracker.com/story/show/182633582).

Adds API for updating Searcher with the selected suggestion. To-dos are left in the places where this will be implemented in a subsequent PR for the next task.

**Example of the debug output generated by typing into the searcher.**

![ShowSearcherInputLog](https://user-images.githubusercontent.com/1428930/186120851-7292824c-7c6e-444e-8453-5f2d234f3244.png)

**Example of the debug output generated by selecting something in the searcher.**

![ShowSearcherSelectionLog](https://user-images.githubusercontent.com/1428930/186120857-d9610eba-04fd-4e65-bb9e-71ec7bfe361d.png)

# Important Notes
For testing/QA set the `app/gui/src/lib.rs:145` logging initialization to `DEBUG` to see the console output.

[ci no changelog needed]
This commit is contained in:
Michael Mauderer 2022-08-26 09:33:19 +01:00 committed by GitHub
parent 020d0807ec
commit 14c516aff3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 3 deletions

View File

@ -607,7 +607,7 @@ impl Searcher {
/// in a new action list (the appropriate notification will be emitted).
#[profile(Debug)]
pub fn set_input(&self, new_input: String) -> FallibleResult {
debug!(self.logger, "Manually setting input to {new_input}.");
tracing::debug!("Manually setting input to {}.", new_input);
let parsed_input = ParsedInput::new(new_input, self.ide.parser())?;
let old_expr = self.data.borrow().input.expression.repr();
let new_expr = parsed_input.expression.repr();
@ -696,6 +696,18 @@ impl Searcher {
}
}
/// Preview the suggestion in the searcher.
pub fn preview_entry_as_suggestion(&self, index: usize) {
tracing::debug!("Previewing entry: {:?}", index);
//TODO[MM] the actual functionality here will be implemented as part of task #182634050.
}
/// Use action at given index as a suggestion. The exact outcome depends on the action's type.
pub fn preview_suggestion(&self, selected_suggestion: action::Suggestion) {
//TODO[MM] the actual functionality here will be implemented as part of task #182634050.
tracing::debug!("Previewing suggestion: {:?}", selected_suggestion);
}
/// Execute given action.
///
/// If the action results in adding new node to the graph, or changing an exiting node, its id
@ -754,6 +766,20 @@ impl Searcher {
self.execute_action(action.clone_ref())
}
/// Preview the action in the searcher.
#[profile(Task)]
pub fn preview_action_by_index(&self, index: usize) -> FallibleResult<()> {
//TODO[MM] the actual functionality here will be implemented as part of task #182634050.
let error = || NoSuchAction { index };
let action = {
let data = self.data.borrow();
let list = data.actions.list().ok_or_else(error)?;
list.get_cloned(index).ok_or_else(error)?.action
};
tracing::debug!("Previewing action: {:?}", action);
Ok(())
}
/// Check if the first fragment in the input (i.e. the one representing the called function)
/// is still unmodified.
///

View File

@ -117,6 +117,12 @@ impl Model {
}
}
/// Should be called if an entry is selected but not used yet. Only used for the old searcher
/// API.
fn entry_selected_as_suggestion(&self, entry_id: view::searcher::entry::Id) {
self.controller.preview_entry_as_suggestion(entry_id);
}
fn commit_editing(&self, entry_id: Option<view::searcher::entry::Id>) -> Option<AstNodeId> {
let result = match entry_id {
Some(id) => self.controller.execute_action_by_index(id),
@ -132,9 +138,25 @@ impl Model {
provider::create_providers_from_controller(&self.logger, &self.controller)
}
fn suggestion_for_entry_id(&self, id: list_panel::EntryId) -> FallibleResult<Suggestion> {
let component: FallibleResult<_> =
self.component_by_view_id(id).ok_or_else(|| NoSuchComponent(id).into());
Ok(match component?.data {
component::Data::FromDatabase { entry, .. } =>
Suggestion::FromDatabase(entry.clone_ref()),
component::Data::Virtual { snippet } => Suggestion::Hardcoded(snippet.clone_ref()),
})
}
/// Should be called if a suggestion is selected but not used yet.
fn suggestion_selected(&self, entry_id: list_panel::EntryId) {
let suggestion = self.suggestion_for_entry_id(entry_id).unwrap();
self.controller.preview_suggestion(suggestion);
}
fn suggestion_accepted(
&self,
id: view::component_browser::list_panel::EntryId,
id: list_panel::EntryId,
) -> Option<(ViewNodeId, node_view::Expression)> {
let component: FallibleResult<_> =
self.component_by_view_id(id).ok_or_else(|| NoSuchComponent(id).into());
@ -321,6 +343,7 @@ impl Searcher {
trace documentation.frp.display_documentation;
eval_ list_view.suggestion_accepted([]analytics::remote_log_event("component_browser::suggestion_accepted"));
eval list_view.suggestion_selected((entry) model.suggestion_selected(*entry));
}
}
SearcherVariant::OldNodeSearcher(searcher) => {
@ -333,6 +356,8 @@ impl Searcher {
used_as_suggestion <- searcher.used_as_suggestion.filter_map(|entry| *entry);
new_input <- used_as_suggestion.filter_map(f!((e) model.entry_used_as_suggestion(*e)));
graph.set_node_expression <+ new_input;
eval searcher.selected_entry([model](entry)
if let Some(id) = entry { model.entry_selected_as_suggestion(*id)});
eval_ searcher.used_as_suggestion([]analytics::remote_log_event("searcher::used_as_suggestion"));
}

View File

@ -916,6 +916,8 @@ define_endpoints_2! {
selected(Option<Selected>),
suggestion_accepted(EntryId),
expression_accepted(EntryId),
/// The last selected suggestion.
suggestion_selected(EntryId),
header_accepted(GroupId),
size(Vector2),
}
@ -968,7 +970,9 @@ impl component::Frp<Model> for Frp {
eval_ on_hover ( model.on_hover() );
eval_ on_hover_end ( model.on_hover_end() );
output.selected <+ groups.selected.map(|op| op.as_ref().map(Selected::from_wrapper_event));
selected <- groups.selected.map(|op| op.as_ref().map(Selected::from_wrapper_event));
output.selected <+ selected;
output.suggestion_selected <+ selected.map(|selected| selected.and_then(|selected| selected.as_entry_id())).unwrap();
output.suggestion_accepted <+ groups.suggestion_accepted.map(EntryId::from_wrapper_event);
output.expression_accepted <+ groups.expression_accepted.map(EntryId::from_wrapper_event);
output.header_accepted <+ groups.header_accepted;