Groups in DocTags (#7337)

Fixes #7336 in a quick way.

Next to the old way of defining groups, the library can just add `GROUP` tag to some entities, and it will be added to the group specified in tag's description.

The group name may be qualified (with project name, like `Standard.Base.Input/Output`) or just name - in the latter case, IDE will assume a group defined in the same library as the entity.

Also moved some entities from "export" list in package.yaml to GROUP tag to give an example. I didn't move all of those, as I assume the library team will reorganize those groups anyway.

### Important Notes

@jdunkerley @radeusgd @GregoryTravis When you will start specifying groups in tags, remember that:
* The groups still belongs to a concrete project; if some entity outside a project wants to be added to its group, the "qualified" name should be specified. See `Table.new` example in this PR.
* If the group name does not reflect any group in package.yaml **the tag is ignored**.
* A single entity may be only in a single group. If it's specified in both package.yaml and in tag, the tag takes precedence.

---------

Co-authored-by: Ilya Bogdanov <fumlead@gmail.com>
This commit is contained in:
Adam Obuchowicz 2023-07-24 15:54:16 +02:00 committed by GitHub
parent 04ed4c1868
commit 1d2371f986
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 195 additions and 80 deletions

View File

@ -205,6 +205,9 @@
- [Help chat][7151]. The link to the Discord server is replaced with a chat
bridge to the Discord server. This is intended to have the chat visible at the
same time as the IDE, so that help can be much more interactive.
- [The libraries' authors may put entities to groups by adding GROUP tag in the
docstring]. It was requested as more convenient way than specifying full names
in package.yaml.
[5910]: https://github.com/enso-org/enso/pull/5910
[6279]: https://github.com/enso-org/enso/pull/6279
@ -226,6 +229,7 @@
[7151]: https://github.com/enso-org/enso/pull/7151
[7164]: https://github.com/enso-org/enso/pull/7164
[7372]: https://github.com/enso-org/enso/pull/7372
[7337]: https://github.com/enso-org/enso/pull/7337
#### EnsoGL (rendering engine)

View File

@ -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()))

View File

@ -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()),
}
}

View File

@ -1177,6 +1177,7 @@ pub struct LibraryComponentGroup {
pub color: Option<String>,
pub icon: Option<String>,
/// The list of components provided by this component group.
#[serde(default)]
pub exports: Vec<LibraryComponent>,
}

View File

@ -5,6 +5,7 @@ use crate::prelude::*;
use crate::controller::graph::ImportType;
use crate::controller::graph::RequiredImport;
use crate::model::execution_context::GroupQualifiedName;
use crate::model::module::NodeEditStatus;
use crate::model::suggestion_database;
use crate::presenter::searcher;
@ -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 a component group containing 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()
}

View File

@ -6,9 +6,9 @@ use crate::prelude::*;
use crate::controller::graph::RequiredImport;
use crate::controller::searcher::Filter;
use crate::model::execution_context::GroupQualifiedName;
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;
@ -47,11 +47,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<color::Rgb>,
pub color: Option<color::Rgb>,
}

View File

@ -7,9 +7,9 @@ use crate::controller::searcher::component;
use crate::controller::searcher::component::hardcoded;
use crate::controller::searcher::component::Component;
use crate::model::execution_context;
use crate::model::execution_context::GroupQualifiedName;
use crate::model::suggestion_database;
use double_representation::name::project;
use double_representation::name::project::STANDARD_NAMESPACE;
use double_representation::name::QualifiedName;
use double_representation::name::QualifiedNameRef;
@ -113,6 +113,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<suggestion_database::entry::Id, EntryInGroup>,
group_name_to_id: HashMap<GroupQualifiedName, usize>,
}
impl<'a> Builder<'a> {
@ -124,26 +125,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 groups = groups.iter().map(|group_data| component::Group {
project: group_data.project.clone_ref(),
name: group_data.name.clone_ref(),
color: group_data.color,
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 {
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 +155,15 @@ impl<'a> Builder<'a> {
db: &'b SuggestionDatabase,
group_index: usize,
group_data: &'b execution_context::ComponentGroup,
group_name_to_id: &'b HashMap<GroupQualifiedName, usize>,
) -> impl Iterator<Item = (suggestion_database::entry::Id, EntryInGroup)> + '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 +259,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 +282,22 @@ impl<'a> Builder<'a> {
Ok(())
}
fn group_index_from_entry_tag(&self, entry: &suggestion_database::Entry) -> Option<usize> {
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<Item = Rc<hardcoded::Snippet>>,
) {
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 +312,22 @@ impl<'a> Builder<'a> {
}
}
fn group_index_from_entry_tag(
entry: &suggestion_database::Entry,
group_name_to_id: &HashMap<GroupQualifiedName, usize>,
) -> Option<usize> {
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 +337,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 +349,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 +377,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 +477,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 +489,8 @@ mod tests {
expected_components: Vec<&str>,
expected_group: Vec<Option<usize>>| {
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 +498,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);

View File

@ -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();
}
}

View File

@ -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<ImString>) -> Self {
Self { project, name: name.into() }
}
}
impl TryFrom<&str> for GroupQualifiedName {
type Error = failure::Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
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<color::Rgb>,
pub components: Vec<QualifiedName>,
@ -404,12 +438,12 @@ impl ComponentGroup {
pub fn from_language_server_protocol_struct(
group: language_server::LibraryComponentGroup,
) -> FallibleResult<Self> {
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<Vec<_>> =
group.exports.into_iter().map(|e| e.name.try_into()).collect();
Ok(ComponentGroup { project, name, color, components: components? })
Ok(ComponentGroup { name, color, components: components? })
}
}

View File

@ -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(),],
});

View File

@ -15,6 +15,7 @@ use double_representation::name::QualifiedNameRef;
use engine_protocol::language_server;
use engine_protocol::language_server::FieldUpdate;
use engine_protocol::language_server::SuggestionsDatabaseModification;
use enso_doc_parser::doc_sections::HtmlString;
use enso_doc_parser::DocSection;
use enso_doc_parser::Tag;
use enso_text::Location;
@ -237,6 +238,8 @@ pub struct Entry {
pub scope: Scope,
/// A name of a custom icon to use when displaying the entry.
pub icon_name: Option<IconName>,
/// A name of a group this entry belongs to.
pub group_name: Option<String>,
}
@ -265,6 +268,7 @@ impl Entry {
self_type: None,
scope: Scope::Everywhere,
icon_name: None,
group_name: None,
}
}
@ -395,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<String>) -> Self {
self.group_name = Some(group_name.into());
self
}
}
@ -633,6 +643,7 @@ impl Entry {
};
let doc_sections = enso_doc_parser::parse(documentation);
let icon_name = find_icon_name_in_doc_sections(&doc_sections);
let group_name = find_group_name_in_doc_sections(&doc_sections);
let reexported_in: Option<QualifiedName> = match &mut entry {
Type { reexport: Some(reexport), .. }
| Constructor { reexport: Some(reexport), .. }
@ -672,6 +683,7 @@ impl Entry {
};
this.documentation = doc_sections;
this.icon_name = icon_name;
this.group_name = group_name;
this.reexported_in = reexported_in;
this
}
@ -964,9 +976,19 @@ where
// === Entry helpers ===
fn find_icon_name_in_doc_sections<'a, I>(doc_sections: I) -> Option<IconName>
where I: IntoIterator<Item = &'a DocSection> {
find_tag_in_doc_sections(Tag::Icon, doc_sections).map(|body| IconName::from_tag_body(body))
}
fn find_group_name_in_doc_sections<'a, I>(doc_sections: I) -> Option<String>
where I: IntoIterator<Item = &'a DocSection> {
find_tag_in_doc_sections(Tag::Group, doc_sections).cloned()
}
fn find_tag_in_doc_sections<'a, I>(tag: Tag, doc_sections: I) -> Option<&'a HtmlString>
where I: IntoIterator<Item = &'a DocSection> {
doc_sections.into_iter().find_map(|section| match section {
DocSection::Tag { tag: Tag::Icon, body } => Some(IconName::from_tag_body(body)),
DocSection::Tag { tag: current_tag, body } if *current_tag == tag => Some(body),
_ => None,
})
}

View File

@ -10,16 +10,8 @@ maintainers:
email: contact@enso.org
component-groups:
new:
- Input:
exports:
- Standard.Base.System.File.File.new
- Standard.Base.Data.read
- Standard.Base.Data.read_text
- Standard.Base.Data.list_directory
- Web:
exports:
- Standard.Base.Network.HTTP.HTTP.new
- Standard.Base.Data.fetch
- Input: {}
- Web: {}
- Parse:
exports:
- Standard.Base.Data.Json.Json.parse

View File

@ -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.

View File

@ -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:

View File

@ -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.

View File

@ -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

View File

@ -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.

View File

@ -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:

View File

@ -63,6 +63,7 @@ pub enum Tag {
Alias,
Deprecated,
Icon,
Group,
Modified,
Private,
Removed,
@ -92,6 +93,7 @@ impl Tag {
"ALIAS" => Some(Alias),
"DEPRECATED" => Some(Deprecated),
"ICON" => Some(Icon),
"GROUP" => Some(Group),
"MODIFIED" => Some(Modified),
"PRIVATE" => Some(Private),
"REMOVED" => Some(Removed),
@ -110,6 +112,7 @@ impl Tag {
Tag::Alias => "ALIAS",
Tag::Deprecated => "DEPRECATED",
Tag::Icon => "ICON",
Tag::Group => "GROUP",
Tag::Modified => "MODIFIED",
Tag::Private => "PRIVATE",
Tag::Removed => "REMOVED",

View File

@ -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<str> for ImString {
}
}
impl Borrow<str> for ImString {
fn borrow(&self) -> &str {
&self.content
}
}
impl Borrow<String> for ImString {
fn borrow(&self) -> &String {
&self.content
}
}
impl From<String> for ImString {
fn from(t: String) -> Self {
Self::new(t)