From 6e8b1ac9f4b71046a07759173de817daf33aedee Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Thu, 20 Jul 2023 13:55:41 +0200 Subject: [PATCH] Implementation --- .../double-representation/src/name.rs | 10 +- .../double-representation/src/name/project.rs | 2 +- app/gui/src/controller/searcher.rs | 12 ++- app/gui/src/controller/searcher/component.rs | 9 +- .../controller/searcher/component/builder.rs | 98 +++++++++++++------ .../searcher/component/hardcoded.rs | 5 +- app/gui/src/model/execution_context.rs | 50 ++++++++-- .../model/execution_context/synchronized.rs | 9 +- app/gui/suggestion-database/src/entry.rs | 7 ++ .../lib/Standard/Base/0.0.0-dev/package.yaml | 33 ++++++- .../lib/Standard/Base/0.0.0-dev/src/Data.enso | 6 +- .../Base/0.0.0-dev/src/Network/HTTP.enso | 1 + .../Base/0.0.0-dev/src/System/File.enso | 1 + .../lib/Standard/Table/0.0.0-dev/package.yaml | 6 -- .../Table/0.0.0-dev/src/Data/Column.enso | 3 +- .../Table/0.0.0-dev/src/Data/Table.enso | 6 +- lib/rust/prelude/src/string.rs | 13 +++ 17 files changed, 196 insertions(+), 75 deletions(-) diff --git a/app/gui/controller/double-representation/src/name.rs b/app/gui/controller/double-representation/src/name.rs index 1936e12b543c6..e3059f147161e 100644 --- a/app/gui/controller/double-representation/src/name.rs +++ b/app/gui/controller/double-representation/src/name.rs @@ -28,11 +28,9 @@ pub mod project; pub enum InvalidQualifiedName { #[fail(display = "The qualified name is empty.")] EmptyName, - #[fail(display = "No namespace in project qualified name.")] - NoNamespace, - #[fail(display = "Invalid namespace in project qualified name.")] - InvalidNamespace, - #[fail(display = "Too many segments in project qualified name.")] + #[fail(display = "Too few segments in qualified name.")] + TooFewSegments, + #[fail(display = "Too many segments in qualified name.")] TooManySegments, } @@ -156,7 +154,7 @@ impl QualifiedName { let mut iter = segments.into_iter().map(|name| name.into()); let project_name = match (iter.next(), iter.next()) { (Some(ns), Some(name)) => project::QualifiedName::new(ns, name), - _ => return Err(InvalidQualifiedName::NoNamespace.into()), + _ => return Err(InvalidQualifiedName::TooFewSegments.into()), }; let without_main = iter.skip_while(|s| *s == PROJECTS_MAIN_MODULE); Ok(Self::new(project_name, without_main.collect())) diff --git a/app/gui/controller/double-representation/src/name/project.rs b/app/gui/controller/double-representation/src/name/project.rs index c19e598285e19..6646d145caad9 100644 --- a/app/gui/controller/double-representation/src/name/project.rs +++ b/app/gui/controller/double-representation/src/name/project.rs @@ -165,7 +165,7 @@ impl QualifiedName { match all_segments.as_slice() { [namespace, project] => Ok(Self::new(namespace, project)), [] => Err(InvalidQualifiedName::EmptyName.into()), - [_] => Err(InvalidQualifiedName::NoNamespace.into()), + [_] => Err(InvalidQualifiedName::TooFewSegments.into()), _ => Err(InvalidQualifiedName::TooManySegments.into()), } } diff --git a/app/gui/src/controller/searcher.rs b/app/gui/src/controller/searcher.rs index 7b071474476ca..86e1d24880b9f 100644 --- a/app/gui/src/controller/searcher.rs +++ b/app/gui/src/controller/searcher.rs @@ -9,6 +9,7 @@ use crate::model::module::NodeEditStatus; use crate::model::suggestion_database; use crate::presenter::searcher; +use crate::model::execution_context::GroupQualifiedName; use breadcrumbs::Breadcrumbs; use double_representation::name::project; use double_representation::name::QualifiedName; @@ -39,6 +40,8 @@ pub mod input; /// needed. Currently enabled to trigger engine's caching of user-added nodes. /// See: https://github.com/enso-org/ide/issues/1067 pub const ASSIGN_NAMES_FOR_NODES: bool = true; +/// A name of component group containin entries representing literals. +pub const LITERALS_GROUP_NAME: &str = "Literals"; // ============== @@ -717,9 +720,9 @@ impl Searcher { fn add_virtual_entries_to_builder(builder: &mut component::Builder) { let snippets = component::hardcoded::INPUT_SNIPPETS.with(|s| s.clone()); - let group_name = component::hardcoded::INPUT_GROUP_NAME; - let project = project::QualifiedName::standard_base_library(); - builder.add_virtual_entries_to_group(group_name, project, snippets); + // Unwrap is safe because conversion from INPUt_GROUP_NAME is tested. + let group_name = GroupQualifiedName::try_from(component::hardcoded::INPUT_GROUP_NAME).unwrap(); + builder.add_virtual_entries_to_group(group_name, snippets); } @@ -865,8 +868,9 @@ fn component_list_for_literal( ) -> component::List { let mut builder = component::builder::Builder::new_empty(db); let project = project::QualifiedName::standard_base_library(); + let group_name = GroupQualifiedName::new(project, LITERALS_GROUP_NAME); let snippet = component::hardcoded::Snippet::from_literal(literal, db).into(); - builder.add_virtual_entries_to_group("Literals", project, vec![snippet]); + builder.add_virtual_entries_to_group(group_name, vec![snippet]); builder.build() } diff --git a/app/gui/src/controller/searcher/component.rs b/app/gui/src/controller/searcher/component.rs index a732efbe2793e..0592792d76039 100644 --- a/app/gui/src/controller/searcher/component.rs +++ b/app/gui/src/controller/searcher/component.rs @@ -8,7 +8,6 @@ use crate::controller::graph::RequiredImport; use crate::controller::searcher::Filter; use crate::model::suggestion_database; -use double_representation::name::project; use enso_doc_parser::DocSection; use enso_doc_parser::Tag; use enso_suggestion_database::entry; @@ -25,10 +24,10 @@ use superslice::Ext; pub mod builder; pub mod hardcoded; +use crate::model::execution_context::GroupQualifiedName; pub use builder::Builder; - // ================= // === Constants === // ================= @@ -47,11 +46,9 @@ const ALIAS_MATCH_ATTENUATION_FACTOR: f32 = 0.75; #[allow(missing_docs)] #[derive(Clone, Debug, Default)] pub struct Group { - /// The project where the group is defined. - pub project: project::QualifiedName, - pub name: ImString, + pub name: GroupQualifiedName, /// Color as defined in project's `package.yaml` file. - pub color: Option, + pub color: Option, } diff --git a/app/gui/src/controller/searcher/component/builder.rs b/app/gui/src/controller/searcher/component/builder.rs index e578e9cec46c9..9d86651a60637 100644 --- a/app/gui/src/controller/searcher/component/builder.rs +++ b/app/gui/src/controller/searcher/component/builder.rs @@ -9,14 +9,13 @@ use crate::controller::searcher::component::Component; use crate::model::execution_context; use crate::model::suggestion_database; -use double_representation::name::project; +use crate::model::execution_context::GroupQualifiedName; use double_representation::name::project::STANDARD_NAMESPACE; use double_representation::name::QualifiedName; use double_representation::name::QualifiedNameRef; use enso_suggestion_database::SuggestionDatabase; - // =============================== // === Component Ordering Keys === // =============================== @@ -113,6 +112,7 @@ pub struct Builder<'a> { built_list: component::List, /// A mapping from entry id to group index and the cached suggestion database entry. entry_to_group_map: HashMap, + group_name_to_id: HashMap, } impl<'a> Builder<'a> { @@ -124,26 +124,29 @@ impl<'a> Builder<'a> { inside_module: default(), built_list: default(), entry_to_group_map: default(), + group_name_to_id: default(), } } /// Create builder for base view (without self type and not inside any module). pub fn new(db: &'a SuggestionDatabase, groups: &[execution_context::ComponentGroup]) -> Self { - let entry_to_group_entries = groups - .iter() - .enumerate() - .flat_map(|(index, data)| Self::group_data_to_map_entries(db, index, data)); + let group_name_to_id = + groups.iter().enumerate().map(|(index, data)| (data.name.clone_ref(), index)).collect(); + let entry_to_group_entries = groups.iter().enumerate().flat_map(|(index, data)| { + Self::group_data_to_map_entries(db, index, data, &group_name_to_id) + }); let groups = groups.iter().map(|group_data| component::Group { - project: group_data.project.clone_ref(), - name: group_data.name.clone_ref(), - color: group_data.color, + name: group_data.name.clone_ref(), + color: group_data.color, }); + Self { db, this_type: None, inside_module: None, built_list: component::List { groups: groups.collect(), ..default() }, entry_to_group_map: entry_to_group_entries.collect(), + group_name_to_id, } } @@ -151,12 +154,15 @@ impl<'a> Builder<'a> { db: &'b SuggestionDatabase, group_index: usize, group_data: &'b execution_context::ComponentGroup, + group_name_to_id: &'b HashMap, ) -> impl Iterator + 'b { group_data.components.iter().filter_map(move |component_qn| { let (id, entry) = db.lookup_by_qualified_name(component_qn).handle_err(|err| { warn!("Cannot put entry {component_qn} to component groups. {err}") })?; - Some((id, EntryInGroup { entry, group_index })) + // The group name from documentation tags has precedence. + let group_from_tag = group_index_from_entry_tag(&entry, group_name_to_id); + Some((id, EntryInGroup { entry, group_index: group_from_tag.unwrap_or(group_index) })) }) } @@ -252,17 +258,20 @@ impl<'a> Builder<'a> { /// It may not be actually added, depending on the mode. See [structure's docs](Builder) for /// details. pub fn add_component_from_db(&mut self, id: suggestion_database::entry::Id) -> FallibleResult { - let in_group = self.entry_to_group_map.get(&id); - // If the entry is in group, we already retrieved it from suggestion database. - let entry = - in_group.map_or_else(|| self.db.lookup(id), |group| Ok(group.entry.clone_ref()))?; + // If the entry was specified as in some group, we already retrieved it from suggestion + // database. + let cached_in_group = self.entry_to_group_map.get(&id); + let entry = cached_in_group + .map_or_else(|| self.db.lookup(id), |entry| Ok(entry.entry.clone_ref()))?; + let group_id = cached_in_group + .map(|entry| entry.group_index) + .or_else(|| self.group_index_from_entry_tag(&entry)); let when_displayed = match &self.inside_module { Some(module) => WhenDisplayed::inside_module(&entry, module.as_ref()), None if self.this_type.is_some() => WhenDisplayed::with_self_type(), - None => WhenDisplayed::in_base_mode(&entry, in_group.is_some()), + None => WhenDisplayed::in_base_mode(&entry, group_id.is_some()), }; - let component = - Component::new_from_database_entry(id, entry, in_group.map(|e| e.group_index)); + let component = Component::new_from_database_entry(id, entry, group_id); if matches!(when_displayed, WhenDisplayed::Always) { self.built_list.displayed_by_default.push(component.clone()); } @@ -272,19 +281,22 @@ impl<'a> Builder<'a> { Ok(()) } + fn group_index_from_entry_tag(&self, entry: &suggestion_database::Entry) -> Option { + group_index_from_entry_tag(entry, &self.group_name_to_id) + } + /// Add virtual entries to a specific group. /// /// If the groups was not specified in constructor, it will be added. pub fn add_virtual_entries_to_group( &mut self, - group_name: &str, - project: project::QualifiedName, + group_name: GroupQualifiedName, snippets: impl IntoIterator>, ) { let groups = &mut self.built_list.groups; let existing_group_index = groups.iter().position(|grp| grp.name == group_name); let group_index = existing_group_index.unwrap_or_else(|| { - groups.push(component::Group { project, name: group_name.into(), color: None }); + groups.push(component::Group { name: group_name, color: None }); groups.len() - 1 }); for snippet in snippets { @@ -299,6 +311,22 @@ impl<'a> Builder<'a> { } } +fn group_index_from_entry_tag( + entry: &suggestion_database::Entry, + group_name_to_id: &HashMap, +) -> Option { + entry.group_name.as_ref().and_then(|name| { + // If the group name in tag is not fully qualified, we assume a group defined in the + // same project where entry is defined. + let qn_name = + GroupQualifiedName::try_from(name.as_str()).unwrap_or_else(|_| GroupQualifiedName { + project: entry.defined_in.project().clone_ref(), + name: name.into(), + }); + group_name_to_id.get(&qn_name).copied() + }) +} + // ============= @@ -308,8 +336,11 @@ impl<'a> Builder<'a> { #[cfg(test)] mod tests { use super::*; + use crate::controller::searcher::component::tests::check_displayed_components; use crate::controller::searcher::component::tests::check_groups; + + use double_representation::name::project; use enso_suggestion_database::mock_suggestion_database; use ide_view::component_browser::component_list_panel::icon; @@ -317,18 +348,21 @@ mod tests { mock_suggestion_database! { test.Test { mod TopModule1 { + #[in_group("First Group")] fn fun2() -> Standard.Base.Any; mod SubModule1 { fn fun4() -> Standard.Base.Any; } mod SubModule2 { + #[in_group("Second Group")] fn fun5 -> Standard.Base.Any; mod SubModule3 { fn fun6 -> Standard.Base.Any; } } + #[in_group("First Group")] fn fun1() -> Standard.Base.Any; } mod TopModule2 { @@ -342,20 +376,18 @@ mod tests { let project = project::QualifiedName::from_text("test.Test").unwrap(); vec![ execution_context::ComponentGroup { - project: project.clone(), - name: "First Group".into(), + name: GroupQualifiedName::new(project.clone_ref(), "First Group"), color: None, components: vec![ "test.Test.TopModule2.fun0".try_into().unwrap(), - "test.Test.TopModule1.fun1".try_into().unwrap(), - "test.Test.TopModule1.fun2".try_into().unwrap(), + // Should be overwritten by tag. + "test.Test.TopModule1.SubModule2.fun5".try_into().unwrap(), ], }, execution_context::ComponentGroup { - project, - name: "Second Group".into(), - color: None, - components: vec!["test.Test.TopModule1.SubModule2.fun5".try_into().unwrap()], + name: GroupQualifiedName::new(project, "Second Group"), + color: None, + components: vec![], }, ] } @@ -444,7 +476,10 @@ mod tests { // Adding to an empty builder. let mut builder = Builder::new_empty(&database); - builder.add_virtual_entries_to_group("First Group", project.clone_ref(), snippets.clone()); + builder.add_virtual_entries_to_group( + GroupQualifiedName::new(project.clone_ref(), "First Group"), + snippets.clone(), + ); let list = builder.build(); check_displayed_components(&list, vec!["test1", "test2"]); check_filterable_components(&list, vec!["test1", "test2"]); @@ -453,7 +488,8 @@ mod tests { expected_components: Vec<&str>, expected_group: Vec>| { let mut builder = Builder::new(&database, &groups); - builder.add_virtual_entries_to_group(group_name, project.clone_ref(), snippets.clone()); + let group_name = GroupQualifiedName::new(project.clone_ref(), group_name); + builder.add_virtual_entries_to_group(group_name.clone_ref(), snippets.clone()); builder.add_components_from_db(database.keys()); let list = builder.build(); check_displayed_components(&list, expected_components.clone()); @@ -461,7 +497,7 @@ mod tests { let mut builder = Builder::new(&database, &groups); builder.add_components_from_db(database.keys()); - builder.add_virtual_entries_to_group(group_name, project.clone_ref(), snippets.clone()); + builder.add_virtual_entries_to_group(group_name, snippets.clone()); let list = builder.build(); check_displayed_components(&list, expected_components); check_groups(&list, expected_group); diff --git a/app/gui/src/controller/searcher/component/hardcoded.rs b/app/gui/src/controller/searcher/component/hardcoded.rs index af436780c7a32..03370486f7249 100644 --- a/app/gui/src/controller/searcher/component/hardcoded.rs +++ b/app/gui/src/controller/searcher/component/hardcoded.rs @@ -22,7 +22,7 @@ use ide_view::component_browser::component_list_panel::grid::entry::icon::Id as /// Name of the favorites component group in the `Standard.Base` library where virtual components /// created from the [`INPUT_SNIPPETS`] should be added. -pub const INPUT_GROUP_NAME: &str = "Input"; +pub const INPUT_GROUP_NAME: &str = "Standard.Base.Input"; /// Qualified name of the `Text` type. const TEXT_ENTRY: &str = "Standard.Base.Main.Data.Text.Text"; /// Qualified name of the `Number` type. @@ -139,11 +139,14 @@ impl Snippet { mod tests { use super::*; + use crate::model::execution_context::GroupQualifiedName; + /// Test that the qualified names used for hardcoded snippets can be constructed. We don't check /// if the entries are actually available in the suggestion database. #[test] fn test_qualified_names_construction() { QualifiedName::from_text(TEXT_ENTRY).unwrap(); QualifiedName::from_text(NUMBER_ENTRY).unwrap(); + GroupQualifiedName::try_from(INPUT_GROUP_NAME).unwrap(); } } diff --git a/app/gui/src/model/execution_context.rs b/app/gui/src/model/execution_context.rs index b10b5b3abe0c7..0f78afb2905ed 100644 --- a/app/gui/src/model/execution_context.rs +++ b/app/gui/src/model/execution_context.rs @@ -2,7 +2,9 @@ use crate::prelude::*; +use ast::opr::predefined::ACCESS; use double_representation::identifier::Identifier; +use double_representation::name; use double_representation::name::project; use double_representation::name::QualifiedName; use engine_protocol::language_server; @@ -380,6 +382,42 @@ pub struct AttachedVisualization { // === ComponentGroup === // ====================== +// === GroupQualifiedName === + +/// A Component Group name containing project name part. +#[derive(Clone, CloneRef, Debug, Default, Eq, Hash, PartialEq)] +pub struct GroupQualifiedName { + /// The fully qualified name of the library project. + pub project: project::QualifiedName, + /// The group name without the library project name prefix. E.g. given the `Standard.Base.Group + /// 1` group reference, the `name` field contains `Group 1`. + pub name: ImString, +} + +impl GroupQualifiedName { + /// Contructor. + pub fn new(project: project::QualifiedName, name: impl Into) -> Self { + Self { project, name: name.into() } + } +} + +impl TryFrom<&str> for GroupQualifiedName { + type Error = failure::Error; + fn try_from(value: &str) -> Result { + if let Some((namespace, project, group)) = value.splitn(3, ACCESS).collect_tuple() { + Ok(Self { + project: project::QualifiedName::new(namespace, project), + name: group.into(), + }) + } else { + Err(name::InvalidQualifiedName::TooFewSegments.into()) + } + } +} + + +// === ComponentGroup === + /// A named group of components which is defined in a library imported into an execution context. /// /// Components are language elements displayed by the Component Browser. The Component Browser @@ -389,11 +427,7 @@ pub struct AttachedVisualization { #[allow(missing_docs)] #[derive(Clone, Debug, PartialEq)] pub struct ComponentGroup { - /// The fully qualified name of the library project. - pub project: project::QualifiedName, - /// The group name without the library project name prefix. E.g. given the `Standard.Base.Group - /// 1` group reference, the `name` field contains `Group 1`. - pub name: ImString, + pub name: GroupQualifiedName, /// An optional color to use when displaying the component group. pub color: Option, pub components: Vec, @@ -404,12 +438,12 @@ impl ComponentGroup { pub fn from_language_server_protocol_struct( group: language_server::LibraryComponentGroup, ) -> FallibleResult { - let project = group.library.try_into()?; - let name = group.name.into(); + let name = + GroupQualifiedName { project: group.library.try_into()?, name: group.name.into() }; let color = group.color.as_ref().and_then(|c| color::Rgb::from_css_hex(c)); let components: FallibleResult> = group.exports.into_iter().map(|e| e.name.try_into()).collect(); - Ok(ComponentGroup { project, name, color, components: components? }) + Ok(ComponentGroup { name, color, components: components? }) } } diff --git a/app/gui/src/model/execution_context/synchronized.rs b/app/gui/src/model/execution_context/synchronized.rs index 12e55c73cda30..76631a11abff1 100644 --- a/app/gui/src/model/execution_context/synchronized.rs +++ b/app/gui/src/model/execution_context/synchronized.rs @@ -395,6 +395,7 @@ pub mod test { use crate::executor::test_utils::TestWithLocalPoolExecutor; use crate::model::execution_context::plain::test::MockData; use crate::model::execution_context::ComponentGroup; + use crate::model::execution_context::GroupQualifiedName; use crate::model::traits::*; use double_representation::name::project; @@ -704,7 +705,7 @@ pub mod test { // Verify that the first component group was parsed and has expected contents. let first_group = &groups[0]; - assert_eq!(first_group.name, "Test Group 1".to_string()); + assert_eq!(first_group.name.name, "Test Group 1".to_string()); let color = first_group.color.unwrap(); assert_eq!((color.red * 255.0) as u8, 0xC0); assert_eq!((color.green * 255.0) as u8, 0x47); @@ -717,8 +718,10 @@ pub mod test { // Verify that the second component group was parsed and has expected contents. assert_eq!(groups[1], ComponentGroup { - project: project::QualifiedName::standard_base_library(), - name: "Input".into(), + name: GroupQualifiedName::new( + project::QualifiedName::standard_base_library(), + "Input" + ), color: None, components: vec!["Standard.Base.System.File.new".try_into().unwrap(),], }); diff --git a/app/gui/suggestion-database/src/entry.rs b/app/gui/suggestion-database/src/entry.rs index 82258adf16033..d81f6cd63751b 100644 --- a/app/gui/suggestion-database/src/entry.rs +++ b/app/gui/suggestion-database/src/entry.rs @@ -238,6 +238,7 @@ pub struct Entry { pub scope: Scope, /// A name of a custom icon to use when displaying the entry. pub icon_name: Option, + /// A name of a group this entry belongs to. pub group_name: Option, } @@ -398,6 +399,12 @@ impl Entry { self.icon_name = Some(icon_name); self } + + /// Takes self and returns it with new `group_name` value. + pub fn in_group(mut self, group_name: impl Into) -> Self { + self.group_name = Some(group_name.into()); + self + } } diff --git a/distribution/lib/Standard/Base/0.0.0-dev/package.yaml b/distribution/lib/Standard/Base/0.0.0-dev/package.yaml index 4d01a9813a971..dce42a430f2bb 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/package.yaml +++ b/distribution/lib/Standard/Base/0.0.0-dev/package.yaml @@ -12,8 +12,31 @@ component-groups: new: - Input: {} - Web: {} - - Parse: {} - - Select: {} - - Join: {} - - Transform: {} - - Output: {} + - Parse: + exports: + - Standard.Base.Data.Json.Json.parse + - Standard.Base.Data.Text.Regex.compile + - Standard.Base.Data.Text.Regex.escape + - Select: + exports: + - Standard.Base.Data.Vector.Vector.at + - Standard.Base.Data.Vector.Vector.get + - Standard.Base.Data.Vector.Vector.filter + - Standard.Base.Data.Vector.Vector.find + - Standard.Base.Data.Vector.Vector.take + - Standard.Base.Data.Vector.Vector.drop + - Standard.Base.Data.Vector.Vector.partition + - Standard.Base.Data.Vector.Vector.distinct + - Join: + exports: + - Standard.Base.Data.Vector.Vector.zip + - Transform: + exports: + - Standard.Base.Data.Vector.Vector.insert + - Standard.Base.Data.Vector.Vector.remove + - Standard.Base.Data.Vector.Vector.map + - Standard.Base.Data.Vector.Vector.sort + - Standard.Base.Data.Vector.Vector.distinct + - Output: + exports: + - Standard.Base.Data.Text.Text.write diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data.enso index cef7002fb7e56..4a417e84e7ccd 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data.enso @@ -20,6 +20,7 @@ from project.Data.Boolean import Boolean, False, True from project.System.File_Format import Auto_Detect, File_Format ## ALIAS Load, Open + GROUP Input Reads a file into Enso. Uses the specified file format to parse the file into an Enso type. If not specified will use the file's extension to determine the file format. @@ -60,6 +61,7 @@ read path format=Auto_Detect (on_problems=Problem_Behavior.Report_Warning) = File.new path . read format on_problems ## ALIAS Load Text, Open Text + GROUP Input Open and read the file at the provided `path`. Arguments: @@ -85,7 +87,8 @@ read_text : (Text | File) -> Encoding -> Problem_Behavior -> Text read_text path (encoding=Encoding.utf_8) (on_problems=Problem_Behavior.Report_Warning) = File.new path . read_text encoding on_problems -## Lists files contained in the provided directory. +## GROUP Input + Lists files contained in the provided directory. Arguments: - name_filter: A glob pattern that can be used to filter the returned files. @@ -140,6 +143,7 @@ list_directory directory name_filter=Nothing recursive=False = File.new directory . list name_filter=name_filter recursive=recursive ## ALIAS Download, HTTP Get + GROUP Web Fetches from the provided URI and returns the response, parsing the body if the content-type is recognised. Returns an error if the status code does not represent a successful response. diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP.enso index f3f8ae100f77a..d18ccfd53c5c4 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Network/HTTP.enso @@ -28,6 +28,7 @@ polyglot java import org.enso.base.Http_Utils type HTTP ## ADVANCED + GROUP Web Create a new instance of the HTTP client. Arguments: diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/System/File.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/System/File.enso index c16e34e7983ec..2821aab33d381 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/System/File.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/System/File.enso @@ -46,6 +46,7 @@ polyglot java import org.enso.base.Encoding_Utils @Builtin_Type type File ## ALIAS New File + GROUP Input Creates a new file object, pointing to the given path. diff --git a/distribution/lib/Standard/Table/0.0.0-dev/package.yaml b/distribution/lib/Standard/Table/0.0.0-dev/package.yaml index 3f96ef6f2ae90..855746cfe1255 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/package.yaml +++ b/distribution/lib/Standard/Table/0.0.0-dev/package.yaml @@ -10,12 +10,6 @@ maintainers: email: contact@enso.org component-groups: extends: - - Standard.Base.Input: - exports: - - Standard.Table.Data.Table.Table.new - - Standard.Table.Data.Table.Table.from_rows - - Standard.Table.Data.Table.Table.from_objects - - Standard.Table.Data.Column.Column.from_vector - Standard.Base.Select: exports: - Standard.Table.Data.Table.Table.at diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso index 5253c1ad20466..926497ed90d1c 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso @@ -32,7 +32,8 @@ polyglot java import org.enso.table.data.table.Column as Java_Column polyglot java import org.enso.table.operations.OrderBuilder type Column - ## Creates a new column given a name and a vector of elements. + ## GROUP Standard.Base.Input + Creates a new column given a name and a vector of elements. Arguments: - name: The name of the column to create. diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Table.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Table.enso index 2fc2de1ea2749..16f9f812e1a32 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Table.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Table.enso @@ -61,7 +61,8 @@ polyglot java import org.enso.table.operations.OrderBuilder ## Represents a column-oriented table data structure. type Table - ## Creates a new table from a vector of `[name, items]` pairs. + ## GROUP Standard.Base.Input + Creates a new table from a vector of `[name, items]` pairs. Arguments: - columns: The `[name, items]` pairs to construct a new table from. @@ -91,7 +92,8 @@ type Table if cols.distinct .getName . length != cols.length then Error.throw (Illegal_Argument.Error "Column names must be distinct.") else Table.Value (Java_Table.new cols) - ## Creates a new table from a vector of column names and a vector of vectors + ## GROUP Standard.Base.Input + Creates a new table from a vector of column names and a vector of vectors specifying row contents. Arguments: diff --git a/lib/rust/prelude/src/string.rs b/lib/rust/prelude/src/string.rs index fac5ed4adeb4c..544e9b1908032 100644 --- a/lib/rust/prelude/src/string.rs +++ b/lib/rust/prelude/src/string.rs @@ -9,6 +9,7 @@ use crate::impls; use serde::Deserialize; use serde::Serialize; +use std::borrow::Borrow; use std::borrow::Cow; use std::ops::Deref; use std::rc::Rc; @@ -215,6 +216,18 @@ impl AsRef for ImString { } } +impl Borrow for ImString { + fn borrow(&self) -> &str { + &self.content + } +} + +impl Borrow for ImString { + fn borrow(&self) -> &String { + &self.content + } +} + impl From for ImString { fn from(t: String) -> Self { Self::new(t)