Skip to content

Commit

Permalink
Merge branch 'develop' into wip/procrat/fix-project-manager-unavailab…
Browse files Browse the repository at this point in the history
…le-6756-6804

* develop: (22 commits)
  Coalesce graph editor view invalidations (#6786)
  Append warnings extracted before tail call execution (#6849)
  Detect and override hooks of the same kind (#6842)
  Dynamic app resampling and better performance measurements. (#6595)
  Show spinner when opening/creating a project, take #2 (#6827)
  Infrastructure for testing inter project imports and exports (#6840)
  Only initialise visualisation chooser if it is used. (#6758)
  Allow casting a Mixed column into a concrete type (#6777)
  Stop graph editing when in full-screen visualization mode (#6844)
  Handle `show-dashboard` event (#6837)
  Fix some dashboard issues (#6668)
  Fix JWT leak (#6815)
  Fix "set username" screen (#6824)
  Fallback to opened date when ordering projects (#6814)
  Various test improvements to increase coverage and speed things up (#6820)
  do not activate nested dropdowns together (#6830)
  Clearly select single specialization with enum dispatch pattern (#6819)
  Prevent incorrect application of list widget on incompatible expressions (#6771)
  Update GraalVM to 22.3.1 JDK17 (#6750)
  Import/export syntax error have more specific messages (#6808)
  ...
  • Loading branch information
Procrat committed May 30, 2023
2 parents d4df6d8 + 7e6a919 commit 4486d00
Show file tree
Hide file tree
Showing 190 changed files with 4,714 additions and 2,734 deletions.
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,13 @@
it is now referenced via the `Main` namespace instead of the project
namespace,][6719] e.g. `Main.func1` instead of `MyProject.func1`. This makes
it robust against project name changes.
- [Added a button to return from an opened project back to the project
dashboard.][6474]
- [Keyboard shortcuts for graph editing are now disabled when the full-screen
visualization is active.][6844]
- [A loading animation is now shown when opening and creating projects][6827],
as the previous behaviour of showing a blank screen while the project was
being loaded was potentially confusing to users.

[6279]: https://github.com/enso-org/enso/pull/6279
[6421]: https://github.com/enso-org/enso/pull/6421
Expand All @@ -181,6 +188,9 @@
[6663]: https://github.com/enso-org/enso/pull/6663
[6752]: https://github.com/enso-org/enso/pull/6752
[6719]: https://github.com/enso-org/enso/pull/6719
[6474]: https://github.com/enso-org/enso/pull/6474
[6844]: https://github.com/enso-org/enso/pull/6844
[6827]: https://github.com/enso-org/enso/pull/6827

#### EnsoGL (rendering engine)

Expand Down Expand Up @@ -234,6 +244,8 @@
- [ToggleButtons can now have tooltips][6035].
- [Rendering of tooltips was improved.][6097] Their text is now more vertically
centered and the delay before showing them was extended.
- [Accurate GPU performance measurements have been implemented][6595]. It is
possible now to track both the time spent on both the CPU and the GPU sides.

[3857]: https://github.com/enso-org/enso/pull/3857
[3985]: https://github.com/enso-org/enso/pull/3985
Expand All @@ -246,6 +258,7 @@
[6366]: https://github.com/enso-org/enso/pull/6366
[6341]: https://github.com/enso-org/enso/pull/6341
[6470]: https://github.com/enso-org/enso/pull/6470
[6595]: https://github.com/enso-org/enso/pull/6595
[6487]: https://github.com/enso-org/enso/pull/6487
[6512]: https://github.com/enso-org/enso/pull/6512

Expand Down Expand Up @@ -781,6 +794,7 @@
- [Limit number of reported warnings per value][6577]
- [Suggestions are updated only when the type of the expression changes][6755]
- [Add project creation time to project metadata][6780]
- [Upgrade GraalVM to 22.3.1 JDK17][6750]

[3227]: https://github.com/enso-org/enso/pull/3227
[3248]: https://github.com/enso-org/enso/pull/3248
Expand Down Expand Up @@ -891,6 +905,7 @@
[6372]: https://github.com/enso-org/enso/pull/6372
[6352]: https://github.com/enso-org/enso/pull/6352
[6577]: https://github.com/enso-org/enso/pull/6577
[6750]: https://github.com/enso-org/enso/pull/6750
[6755]: https://github.com/enso-org/enso/pull/6755
[6780]: https://github.com/enso-org/enso/pull/6780

Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions app/gui/language/span-tree/src/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -811,7 +811,6 @@ fn tree_generate_node<T: Payload>(
context: &impl Context,
ast_id: Option<Id>,
) -> FallibleResult<Node<T>> {
let parenthesized = matches!(tree.type_info, ast::TreeType::Group);
let mut children = vec![];
let size;
if let Some(leaf_info) = &tree.leaf_info {
Expand Down Expand Up @@ -873,7 +872,9 @@ fn tree_generate_node<T: Payload>(
}
size = parent_offset;
}
Ok(Node { kind, parenthesized, size, children, ast_id, ..default() })

let tree_type = Some(tree.type_info.clone());
Ok(Node { kind, tree_type, size, children, ast_id, ..default() })
}


Expand Down
4 changes: 4 additions & 0 deletions app/gui/language/span-tree/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,10 @@ impl<T> SpanTree<T> {
write!(buffer, " ext_id={ext_id:?}").unwrap();
}

if let Some(tt) = node.tree_type.as_ref() {
write!(buffer, " tt={tt:?}").unwrap();
}

buffer.push('\n');

let num_children = node.children.len();
Expand Down
11 changes: 5 additions & 6 deletions app/gui/language/span-tree/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ pub struct Node<T> {
/// span-tree, but not in AST), this field will contain the AST ID of the expression it extends
/// (e.g. the AST of a function call with missing arguments, extended with expected arguments).
pub extended_ast_id: Option<ast::Id>,
pub parenthesized: bool,
/// A tree type of the associated AST node. Only present when the AST node was a
/// [`ast::Shape::Tree`].
pub tree_type: Option<ast::TreeType>,
pub payload: T,
}

Expand Down Expand Up @@ -74,23 +76,20 @@ impl<T> Node<T> {
/// Payload mapping utility.
pub fn map<S>(self, f: impl Copy + Fn(T) -> S) -> Node<S> {
let kind = self.kind;
let parenthesized = self.parenthesized;
let tree_type = self.tree_type;
let size = self.size;
let children = self.children.into_iter().map(|t| t.map(f)).collect_vec();
let ast_id = self.ast_id;
let extended_ast_id = self.extended_ast_id;
let payload = f(self.payload);
Node { kind, parenthesized, size, children, ast_id, extended_ast_id, payload }
Node { kind, tree_type, size, children, ast_id, extended_ast_id, payload }
}
}

// === Kind utils ===

#[allow(missing_docs)]
impl<T> Node<T> {
pub fn parenthesized(&self) -> bool {
self.parenthesized
}
pub fn is_root(&self) -> bool {
self.kind.is_root()
}
Expand Down
70 changes: 54 additions & 16 deletions app/gui/src/controller/ide.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use crate::prelude::*;

use crate::config::ProjectToOpen;

use double_representation::name::project;
use mockall::automock;
use parser::Parser;
Expand Down Expand Up @@ -102,9 +104,7 @@ impl StatusNotificationPublisher {
/// used internally in code.
#[derive(Copy, Clone, Debug)]
pub enum Notification {
/// User created a new project. The new project is opened in IDE.
NewProjectCreated,
/// User opened an existing project.
/// User opened a new or existing project.
ProjectOpened,
/// User closed the project.
ProjectClosed,
Expand All @@ -118,10 +118,12 @@ pub enum Notification {

// === Errors ===

#[allow(missing_docs)]
/// Error raised when a project with given name or ID was not found.
#[derive(Clone, Debug, Fail)]
#[fail(display = "Project with name \"{}\" not found.", 0)]
struct ProjectNotFound(String);
#[fail(display = "Project '{}' was not found.", project)]
pub struct ProjectNotFound {
project: ProjectToOpen,
}


// === Managing API ===
Expand All @@ -131,11 +133,16 @@ struct ProjectNotFound(String);
/// It is a separate trait, because those methods are not supported in some environments (see also
/// [`API::manage_projects`]).
pub trait ManagingProjectAPI {
/// Create a new unnamed project and open it in the IDE.
/// Create a new project and open it in the IDE.
///
/// `name` is an optional project name. It overrides the name of the template if given.
/// `template` is an optional project template name. Available template names are defined in
/// `lib/scala/pkg/src/main/scala/org/enso/pkg/Template.scala`.
fn create_new_project(&self, template: Option<project::Template>) -> BoxFuture<FallibleResult>;
fn create_new_project(
&self,
name: Option<String>,
template: Option<project::Template>,
) -> BoxFuture<FallibleResult>;

/// Return a list of existing projects.
fn list_projects(&self) -> BoxFuture<FallibleResult<Vec<ProjectMetadata>>>;
Expand All @@ -150,18 +157,44 @@ pub trait ManagingProjectAPI {
/// and then for the project opening.
fn open_project_by_name(&self, name: String) -> BoxFuture<FallibleResult> {
async move {
let projects = self.list_projects().await?;
let mut projects = projects.into_iter();
let project = projects.find(|project| project.name.as_ref() == name);
let uuid = project.map(|project| project.id);
if let Some(uuid) = uuid {
self.open_project(uuid).await
} else {
Err(ProjectNotFound(name).into())
let project_id = self.find_project(&ProjectToOpen::Name(name.into())).await?;
self.open_project(project_id).await
}
.boxed_local()
}

/// Open a project by name or ID. If no project with the given name exists, it will be created.
fn open_or_create_project(&self, project_to_open: ProjectToOpen) -> BoxFuture<FallibleResult> {
async move {
match self.find_project(&project_to_open).await {
Ok(project_id) => self.open_project(project_id).await,
Err(error) =>
if let ProjectToOpen::Name(name) = project_to_open {
info!("Attempting to create project with name '{name}'.");
self.create_new_project(Some(name.to_string()), None).await
} else {
Err(error)
},
}
}
.boxed_local()
}

/// Find a project by name or ID.
fn find_project<'a: 'c, 'b: 'c, 'c>(
&'a self,
project_to_open: &'b ProjectToOpen,
) -> BoxFuture<'c, FallibleResult<Uuid>> {
async move {
self.list_projects()
.await?
.into_iter()
.find(|project_metadata| project_to_open.matches(project_metadata))
.map(|metadata| metadata.id)
.ok_or_else(|| ProjectNotFound { project: project_to_open.clone() }.into())
}
.boxed_local()
}
}


Expand Down Expand Up @@ -193,6 +226,11 @@ pub trait API: Debug {
#[allow(clippy::needless_lifetimes)]
fn manage_projects<'a>(&'a self) -> FallibleResult<&'a dyn ManagingProjectAPI>;

/// Returns whether the Managing Project API is available.
fn can_manage_projects(&self) -> bool {
self.manage_projects().is_ok()
}

/// Return whether private entries should be visible in the component browser.
fn are_component_browser_private_entries_visible(&self) -> bool;

Expand Down
74 changes: 16 additions & 58 deletions app/gui/src/controller/ide/desktop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@
use crate::prelude::*;

use crate::config::ProjectToOpen;
use crate::controller::ide::ManagingProjectAPI;
use crate::controller::ide::Notification;
use crate::controller::ide::StatusNotificationPublisher;
use crate::controller::ide::API;
use crate::ide::initializer;

use double_representation::name::project;
use engine_protocol::project_manager;
Expand Down Expand Up @@ -49,53 +47,16 @@ pub struct Handle {
}

impl Handle {
/// Create IDE controller. If `maybe_project_name` is `Some`, a project with provided name will
/// be opened. Otherwise controller will be used for project manager operations by Welcome
/// Screen.
pub async fn new(
project_manager: Rc<dyn project_manager::API>,
project_to_open: Option<ProjectToOpen>,
) -> FallibleResult<Self> {
let project = match project_to_open {
Some(project_to_open) =>
Some(Self::init_project_model(project_manager.clone_ref(), project_to_open).await?),
None => None,
};
Ok(Self::new_with_project_model(project_manager, project))
}

/// Create IDE controller with prepared project model. If `project` is `None`,
/// `API::current_project` returns `None` as well.
pub fn new_with_project_model(
project_manager: Rc<dyn project_manager::API>,
project: Option<model::Project>,
) -> Self {
let current_project = Rc::new(CloneCell::new(project));
let status_notifications = default();
let parser = Parser::new();
let notifications = default();
let component_browser_private_entries_visibility_flag = default();
Self {
current_project,
/// Create IDE controller.
pub fn new(project_manager: Rc<dyn project_manager::API>) -> FallibleResult<Self> {
Ok(Self {
current_project: default(),
project_manager,
status_notifications,
parser,
notifications,
component_browser_private_entries_visibility_flag,
}
}

/// Open project with provided name.
async fn init_project_model(
project_manager: Rc<dyn project_manager::API>,
project_to_open: ProjectToOpen,
) -> FallibleResult<model::Project> {
// TODO[ao]: Reuse of initializer used in previous code design. It should be soon replaced
// anyway, because we will soon resign from the "open or create" approach when opening
// IDE. See https://github.com/enso-org/ide/issues/1492 for details.
let initializer = initializer::WithProjectManager::new(project_manager, project_to_open);
let model = initializer.initialize_project_model().await?;
Ok(model)
status_notifications: default(),
parser: default(),
notifications: default(),
component_browser_private_entries_visibility_flag: default(),
})
}
}

Expand Down Expand Up @@ -133,14 +94,16 @@ impl API for Handle {

impl ManagingProjectAPI for Handle {
#[profile(Objective)]
fn create_new_project(&self, template: Option<project::Template>) -> BoxFuture<FallibleResult> {
fn create_new_project(
&self,
name: Option<String>,
template: Option<project::Template>,
) -> BoxFuture<FallibleResult> {
async move {
use model::project::Synchronized as Project;

let list = self.project_manager.list_projects(&None).await?;
let existing_names: HashSet<_> =
list.projects.into_iter().map(|p| p.name.into()).collect();
let name = make_project_name(&template);
let name = name.unwrap_or_else(|| make_project_name(&template));
let name = choose_unique_project_name(&existing_names, &name);
let name = ProjectName::new_unchecked(name);
let version = &enso_config::ARGS.groups.engine.options.preferred_version.value;
Expand All @@ -151,12 +114,7 @@ impl ManagingProjectAPI for Handle {
.project_manager
.create_project(&name, &template.map(|t| t.into()), &version, &action)
.await?;
let new_project_id = create_result.project_id;
let project_mgr = self.project_manager.clone_ref();
let new_project = Project::new_opened(project_mgr, new_project_id);
self.current_project.set(Some(new_project.await?));
self.notifications.notify(Notification::NewProjectCreated);
Ok(())
self.open_project(create_result.project_id).await
}
.boxed_local()
}
Expand Down
Loading

0 comments on commit 4486d00

Please sign in to comment.