From 1f8675a03184409741e1dfbd3f907838a2e44169 Mon Sep 17 00:00:00 2001 From: Ilya Bogdanov Date: Tue, 5 Sep 2023 18:51:33 +0400 Subject: [PATCH] Fix atom types in dropdowns. (#7670) Fixes #7468 The fix is pretty simple: we reuse the existing functionality for importing stuff and generating expressions. It fixes issues with `Nothing` or `Report_Unmatched` types. https://github.com/enso-org/enso/assets/6566674/4e7addf9-2175-4f2a-a571-4ef823de5cb0 While debugging, I found it easier to work with a suggestion database when exported to some external format. Hence, I implemented serde serialization support for database entries and also a new debug shortcut ctrl+shift+u to dump all entries to the console. --- CHANGELOG.md | 3 +++ Cargo.lock | 3 +++ app/gui/docs/product/shortcuts.md | 1 + app/gui/src/controller/searcher.rs | 5 ++++ app/gui/src/presenter/project.rs | 11 -------- .../presenter/searcher/component_browser.rs | 1 + app/gui/suggestion-database/Cargo.toml | 2 ++ app/gui/suggestion-database/src/entry.rs | 26 +++++++++---------- app/gui/suggestion-database/src/lib.rs | 7 +++++ app/gui/view/src/project.rs | 7 ++++- lib/rust/font/src/lib.rs | 1 - lib/rust/parser/doc-parser/Cargo.toml | 1 + .../parser/doc-parser/src/doc_sections.rs | 4 +-- lib/rust/parser/doc-parser/src/lib.rs | 4 +-- lib/rust/text/Cargo.toml | 2 +- lib/rust/text/src/index.rs | 1 + lib/rust/text/src/unit.rs | 2 ++ lib/rust/types/src/unit.rs | 7 +++-- 18 files changed, 52 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e19c173be3ec..65a682cc3655 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -219,6 +219,8 @@ enter][7527] - [Connections to lamdas are displayed correctly][7550]. It is possible to drag a connection to any expression inside the lambda body. +- [Atom types in dropdowns do not produce redundant imports][#7670]. The + possibility of imports conflicts is reduced. - [Copying and pasting a single node][7618]. Using the common cmd+C and cmd+V shortcuts, it is now possible to copy a single selected node and paste its code to the graph or @@ -249,6 +251,7 @@ [7311]: https://github.com/enso-org/enso/pull/7311 [7527]: https://github.com/enso-org/enso/pull/7527 [7550]: https://github.com/enso-org/enso/pull/7550 +[7670]: https://github.com/enso-org/enso/pull/7670 [7618]: https://github.com/enso-org/enso/pull/7618 #### EnsoGL (rendering engine) diff --git a/Cargo.lock b/Cargo.lock index d11987e83483..0a098b59d914 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2116,6 +2116,7 @@ dependencies = [ "enso-reflect", "lexpr", "pretty_assertions", + "serde", ] [[package]] @@ -2588,6 +2589,8 @@ dependencies = [ "flo_stream", "futures", "parser", + "serde", + "serde_json", "span-tree", "wasm-bindgen-test", ] diff --git a/app/gui/docs/product/shortcuts.md b/app/gui/docs/product/shortcuts.md index 95bc3e8e5a9d..3b4e2d26d096 100644 --- a/app/gui/docs/product/shortcuts.md +++ b/app/gui/docs/product/shortcuts.md @@ -141,3 +141,4 @@ broken and require further investigation. | ctrl + shift + arrow up | Pop a breadcrumb without navigating. | | cmd + i | Reload visualizations. To see the effect in the currently shown visualizations, you need to switch to another and switch back. | | ctrl + shift + b | Toggle read-only mode. | +| ctrl + shift + u | Dump the suggestion database as JSON to the console. Available only in debug mode, and only if the component browser is open. | diff --git a/app/gui/src/controller/searcher.rs b/app/gui/src/controller/searcher.rs index 6f8cc3c36b8b..f340bee3ab33 100644 --- a/app/gui/src/controller/searcher.rs +++ b/app/gui/src/controller/searcher.rs @@ -313,6 +313,11 @@ impl Searcher { self } + /// Dump the suggestion database to the console in JSON format. + pub fn dump_database_as_json(&self) { + console_log!("{}", self.database.dump_as_json()); + } + /// Abort editing and perform cleanup. pub fn abort_editing(&self) { self.clear_temporary_imports(); diff --git a/app/gui/src/presenter/project.rs b/app/gui/src/presenter/project.rs index bfc9d54995ee..5db85e3f86e0 100644 --- a/app/gui/src/presenter/project.rs +++ b/app/gui/src/presenter/project.rs @@ -336,16 +336,6 @@ impl Model { } }); } - - fn show_dashboard(&self) { - match enso_web::Event::new("show-dashboard") { - Ok(event) => - if let Err(error) = enso_web::document.dispatch_event(&event) { - error!("Failed to dispatch event to show the dashboard. {error:?}"); - }, - Err(error) => error!("Failed to create event to show the dashboard. {error:?}"), - } - } } @@ -441,7 +431,6 @@ impl Project { eval graph_view.execution_environment((env) model.execution_environment_changed(*env)); eval_ graph_view.execution_environment_play_button_pressed( model.trigger_clean_live_execution()); - eval_ view.go_to_dashboard_button_pressed (model.show_dashboard()); eval view.current_shortcut ((shortcut) model.handled_shortcut_changed(shortcut)); } diff --git a/app/gui/src/presenter/searcher/component_browser.rs b/app/gui/src/presenter/searcher/component_browser.rs index da1ff878c501..b9c2648d2d9b 100644 --- a/app/gui/src/presenter/searcher/component_browser.rs +++ b/app/gui/src/presenter/searcher/component_browser.rs @@ -255,6 +255,7 @@ impl ComponentBrowserSearcher { // must be up-to-date. action_list_changed <+ model.project.searcher_input_changed.constant(()); + eval_ model.project.request_dump_suggestion_database(model.controller.dump_database_as_json()); eval_ model.project.toggle_component_browser_private_entries_visibility ( model.controller.reload_list()); } diff --git a/app/gui/suggestion-database/Cargo.toml b/app/gui/suggestion-database/Cargo.toml index f6c75b8b9ee3..620e44ecb90d 100644 --- a/app/gui/suggestion-database/Cargo.toml +++ b/app/gui/suggestion-database/Cargo.toml @@ -23,6 +23,8 @@ ensogl-icons = { path = "../../../lib/rust/ensogl/component/icons" } flo_stream = { version = "0.4.0" } failure = { workspace = true } enso-notification = { path = "../../../lib/rust/notification" } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" [dev-dependencies] futures = { workspace = true } diff --git a/app/gui/suggestion-database/src/entry.rs b/app/gui/suggestion-database/src/entry.rs index 5358bc3daa88..71cd66c13b0b 100644 --- a/app/gui/suggestion-database/src/entry.rs +++ b/app/gui/suggestion-database/src/entry.rs @@ -88,7 +88,7 @@ pub struct ModuleSpan { /// In order to make icon definitions more readable for non-programmer users, the builtin icon name /// is allowed to be formatted in arbitrary casing. Either `SNAKE_case`,`camelCase`, `Pascal_Case` /// etc. is allowed. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)] pub struct IconName { /// The name is kept in `PascalCase` to allow easy conversion into builtin icon ID. pascal_cased: ImString, @@ -176,7 +176,7 @@ impl From for import::Info { // === Kind === /// A type of suggestion entry. -#[derive(Copy, Clone, Debug, Eq, PartialEq, ForEachVariant)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, ForEachVariant, serde::Serialize)] #[allow(missing_docs)] pub enum Kind { Type, @@ -195,7 +195,7 @@ pub enum Kind { /// Methods are visible "Everywhere", as they are imported on a module level, so they are not /// specific to any particular span in the module file. /// However local variables and local function have limited visibility. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)] pub enum Scope { /// The entry is visible in the whole module where it was defined. It can be also brought to /// other modules by import declarations. @@ -214,7 +214,7 @@ pub enum Scope { // === Entry === /// The Suggestion Database Entry. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)] pub struct Entry { /// A type of suggestion. pub kind: Kind, @@ -972,18 +972,16 @@ where TagValueResolution::Resolved(entry, chain) => { let label = chain_to_label(&chain); let qualified_name = entry.qualified_name(); - let parent_module = qualified_name.parent(); - let required_import = parent_module.as_ref().map(|n| n.to_string()); - - let expression = if let Some(parent) = parent_module { - let in_module_name = qualified_name.name(); - let parent_name = parent.name(); - [parent_name, in_module_name].join(opr::predefined::ACCESS) + let required_import = Some(qualified_name.to_string()); + // As we don't generate `this`, we will never follow the code path where + // `in_module` is used. That's why passing `default()` is valid. + let in_module = default(); + let expression = entry.code_to_insert(false, in_module); + let expression = if entry.arguments.is_empty() { + expression.to_string() } else { - qualified_name.to_string() + format!("({expression})") }; - let expression = - if entry.arguments.is_empty() { expression } else { format!("({expression})") }; span_tree::TagValue { required_import, expression, label: Some(label) } } diff --git a/app/gui/suggestion-database/src/lib.rs b/app/gui/suggestion-database/src/lib.rs index e202b36e4085..1d2a58ab2197 100644 --- a/app/gui/suggestion-database/src/lib.rs +++ b/app/gui/suggestion-database/src/lib.rs @@ -338,6 +338,13 @@ impl SuggestionDatabase { default() } + /// Dump all entries in JSON. + pub fn dump_as_json(&self) -> String { + let all_entries: Vec = + self.entries.borrow().values().map(|e| e.deref().clone()).collect_vec(); + serde_json::to_string(&all_entries).unwrap() + } + /// Create a database filled with entries provided by the given iterator. pub fn new_from_entries<'a>( entries: impl IntoIterator, diff --git a/app/gui/view/src/project.rs b/app/gui/view/src/project.rs index 8461db6d2068..47f46bbc69a0 100644 --- a/app/gui/view/src/project.rs +++ b/app/gui/view/src/project.rs @@ -149,6 +149,8 @@ ensogl::define_endpoints! { start_node_creation_with_component_browser(), /// Accepts the currently selected input of the searcher. accept_searcher_input(), + /// Dump the suggestion database in JSON to the console. + dump_suggestion_database(), } Output { @@ -174,9 +176,10 @@ ensogl::define_endpoints! { fullscreen_visualization_shown (bool), drop_files_enabled (bool), debug_mode (bool), - go_to_dashboard_button_pressed (), /// The name of the command currently being handled due to shortcut being pressed. current_shortcut (Option), + /// Request the controller to dump the suggestion database in JSON to the console. + request_dump_suggestion_database(), } } @@ -700,6 +703,7 @@ impl View { debug_mode <- bool(&frp.disable_debug_mode, &frp.enable_debug_mode); frp.source.debug_mode <+ debug_mode; popup.is_enabled <+ debug_mode; + frp.source.request_dump_suggestion_database <+ frp.dump_suggestion_database; } self } @@ -803,6 +807,7 @@ impl application::View for View { (Press, "is_searcher_opened", "enter", "accept_searcher_input"), (Press, "debug_mode", "ctrl shift enter", "debug_push_breadcrumb"), (Press, "debug_mode", "ctrl shift b", "debug_pop_breadcrumb"), + (Press, "debug_mode", "ctrl shift u", "dump_suggestion_database"), ] .iter() .map(|(a, b, c, d)| Self::self_shortcut_when(*a, *c, *d, *b)) diff --git a/lib/rust/font/src/lib.rs b/lib/rust/font/src/lib.rs index 41267a1f1386..2f6e0db2fc6c 100644 --- a/lib/rust/font/src/lib.rs +++ b/lib/rust/font/src/lib.rs @@ -29,7 +29,6 @@ use derive_more::Deref; use derive_more::Display; - // ============== // === Export === // ============== diff --git a/lib/rust/parser/doc-parser/Cargo.toml b/lib/rust/parser/doc-parser/Cargo.toml index 2813e61cc5e8..8c5b1168fe70 100644 --- a/lib/rust/parser/doc-parser/Cargo.toml +++ b/lib/rust/parser/doc-parser/Cargo.toml @@ -14,6 +14,7 @@ enso-parser = { path = ".." } enso-prelude = { path = "../../prelude" } enso-profiler = { path = "../../profiler" } enso-reflect = { path = "../../reflect" } +serde = { version = "1.0", features = ["derive"] } [dev-dependencies] enso-metamodel = { path = "../../metamodel", features = ["rust"] } diff --git a/lib/rust/parser/doc-parser/src/doc_sections.rs b/lib/rust/parser/doc-parser/src/doc_sections.rs index 99085d4f1a01..777db8b3d000 100644 --- a/lib/rust/parser/doc-parser/src/doc_sections.rs +++ b/lib/rust/parser/doc-parser/src/doc_sections.rs @@ -64,7 +64,7 @@ pub type HtmlString = String; /// A description of a single argument in the documentation. The name is delimited from the /// description using a colon. -#[derive(Debug, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq, serde::Serialize)] pub struct Argument { /// Name of the argument. pub name: String, @@ -87,7 +87,7 @@ impl Argument { } /// A single section of the documentation. -#[derive(Hash, Debug, Clone, PartialEq, Eq)] +#[derive(Hash, Debug, Clone, PartialEq, Eq, serde::Serialize)] #[allow(missing_docs)] pub enum DocSection { /// The documentation tag. diff --git a/lib/rust/parser/doc-parser/src/lib.rs b/lib/rust/parser/doc-parser/src/lib.rs index 532ed283a4f2..44dee4476e29 100644 --- a/lib/rust/parser/doc-parser/src/lib.rs +++ b/lib/rust/parser/doc-parser/src/lib.rs @@ -56,7 +56,7 @@ pub struct TagWithDescription<'a, L> { } /// Indicator placed at the beginning of a documentation section, e.g. `PRIVATE`. -#[derive(Hash, Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Hash, Debug, Clone, Copy, PartialEq, Eq, serde::Serialize)] #[allow(missing_docs)] pub enum Tag { Added, @@ -138,7 +138,7 @@ pub struct Marked<'a, L> { } /// Documentation section mark. -#[derive(Hash, Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Hash, Debug, Copy, Clone, PartialEq, Eq, serde::Serialize)] #[allow(missing_docs)] pub enum Mark { Important, diff --git a/lib/rust/text/Cargo.toml b/lib/rust/text/Cargo.toml index 1d31041338a9..08fbdc8edc46 100644 --- a/lib/rust/text/Cargo.toml +++ b/lib/rust/text/Cargo.toml @@ -11,4 +11,4 @@ crate-type = ["rlib", "cdylib"] enso-prelude = { path = "../prelude" } enso-types = { path = "../types" } xi-rope = { version = "0.3.0" } -serde = "1" +serde = { version = "1", features = ["derive"] } diff --git a/lib/rust/text/src/index.rs b/lib/rust/text/src/index.rs index 95b81bb20976..c8572eabae65 100644 --- a/lib/rust/text/src/index.rs +++ b/lib/rust/text/src/index.rs @@ -180,6 +180,7 @@ macro_rules! define_line_unit { #[derive( Clone, Copy, Debug, Display, Default, Eq, Hash, Ord, PartialEq, PartialOrd, From, Into )] + #[derive(serde::Serialize, serde::Deserialize)] pub struct $name { #[allow(missing_docs)] pub value: usize, diff --git a/lib/rust/text/src/unit.rs b/lib/rust/text/src/unit.rs index 5114239a7922..2adeb40c6021 100644 --- a/lib/rust/text/src/unit.rs +++ b/lib/rust/text/src/unit.rs @@ -198,6 +198,7 @@ impl AddAssign for Column { unit! { /// An offset in the text measured in number of code units in text in UTF-16 representation. + #[derive(serde::Serialize, serde::Deserialize)] Utf16CodeUnit::utf16_code_unit(usize) } @@ -213,6 +214,7 @@ mod location { use super::*; #[doc = " A type representing 2d measurements."] #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] + #[derive(serde::Serialize, serde::Deserialize)] #[allow(missing_docs)] pub struct Location { pub line: LineType, diff --git a/lib/rust/types/src/unit.rs b/lib/rust/types/src/unit.rs index fcdfb128712d..cb67a3237a84 100644 --- a/lib/rust/types/src/unit.rs +++ b/lib/rust/types/src/unit.rs @@ -401,7 +401,7 @@ macro_rules! newtype_no_sub { macro_rules! newtype_struct { ($(#$meta:tt)* $name:ident { $($field:ident : $field_type:ty),* $(,)? }) => { $crate::newtype_struct_def! {$(#$meta)* $name { $($field : $field_type),*}} - $crate::newtype_struct_impls! {$(#$meta)* $name { $($field : $field_type),*}} + $crate::newtype_struct_impls! {$name { $($field : $field_type),*}} } } @@ -410,7 +410,7 @@ macro_rules! newtype_struct { macro_rules! newtype_struct_float_like { ($(#$meta:tt)* $name:ident { $($field:ident : $field_type:ty),* $(,)? }) => { $crate::newtype_struct_def_float_like! {$(#$meta)* $name { $($field : $field_type),*}} - $crate::newtype_struct_impls! {$(#$meta)* $name { $($field : $field_type),*}} + $crate::newtype_struct_impls! {$name { $($field : $field_type),*}} } } @@ -441,9 +441,8 @@ macro_rules! newtype_struct_def_float_like { /// Unit definition macro. See module docs to learn more. #[macro_export] macro_rules! newtype_struct_impls { - ($(#$meta:tt)* $name:ident { $field:ident : $field_type:ty $(,)? }) => { + ($name:ident { $field:ident : $field_type:ty $(,)? }) => { /// Smart constructor. - $(#$meta)* #[allow(non_snake_case)] pub const fn $name($field:$field_type) -> $name { $name {$field} }