Skip to content

Commit

Permalink
Merge branch 'develop' into wip/procrat/rename-project-with-space-5065
Browse files Browse the repository at this point in the history
* develop:
  Turn null into UnexpectedExpression when Union type is incomplete (#6415)
  Ensure that IO.println does not fail if `to_text` returned a non-Text value. (#6223)
  Improve inlining of `<|` on (GraalVM EE) (#6384)
  Feat: update templates styles and feature (#6071)
  5127 Add Table.parse_to_columns to parse a single column to a set of columns. (#6383)
  URL handling (#6243)
  Exclude comparison operators from modifier logic (#6370)
  Better cleanup of project management test suite (#6392)
  Fix all eslint errors (#6267)
  Infer SQLite types locally (#6381)
  Vector Editor with List Editor and adding elements. (#6363)
  Add typechecks to Aggregate and Cross Tab (#6380)
  Forbid edits in read-only mode (#6342)
  Add Table.parse_text_to_table to convert Text to a Table. (#6294)
  Adding typechecks to Column Operations (#6298)
  Rollback cloud options groups (#6331)
  Project folder not renamed after project name change (#6369)
  Add `replace`, `trim` to Column. Better number parsing. (#6253)
  Read-only mode for controllers (#6259)
  Prevent default for all events, fixing multiple IDE bugs (#6364)
  • Loading branch information
Procrat committed Apr 25, 2023
2 parents 5b6ffe8 + 63de18e commit 04b228f
Show file tree
Hide file tree
Showing 162 changed files with 5,112 additions and 1,808 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,10 @@
- [Implemented `Table.union` for the Database backend.][6204]
- [Array & Vector have the same methods & behavior][6218]
- [Implemented `Table.split` and `Table.tokenize` for in-memory tables.][6233]
- [Added `trim` and `replace` to `Column`. Enhanced number parsing with support
for thousands and decimal point automatic detection.][6253]
- [Implemented `Table.parse_text_to_table`.][6294]
- [Added `Table.parse_to_columns`.][6383]

[debug-shortcuts]:
https://github.com/enso-org/enso/blob/develop/app/gui/docs/product/shortcuts.md#debug
Expand Down Expand Up @@ -588,6 +592,9 @@
[6077]: https://github.com/enso-org/enso/pull/6077
[6218]: https://github.com/enso-org/enso/pull/6218
[6233]: https://github.com/enso-org/enso/pull/6233
[6253]: https://github.com/enso-org/enso/pull/6253
[6294]: https://github.com/enso-org/enso/pull/6294
[6383]: https://github.com/enso-org/enso/pull/6383

#### Enso Compiler

Expand Down
2 changes: 1 addition & 1 deletion app/gui/controller/engine-protocol/src/language_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ trait API {
/// have permission to edit the resources for which edits are sent. This failure may be partial,
/// in that some edits are applied and others are not.
#[MethodInput=ApplyTextFileEditInput, rpc_name="text/applyEdit"]
fn apply_text_file_edit(&self, edit: FileEdit) -> ();
fn apply_text_file_edit(&self, edit: FileEdit, execute: bool) -> ();

/// Create a new execution context. Return capabilities executionContext/canModify and
/// executionContext/receivesUpdates containing freshly created ContextId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,7 @@ fn test_execution_context() {
let path = main.clone();
let edit = FileEdit { path, edits, old_version, new_version };
test_request(
|client| client.apply_text_file_edit(&edit),
|client| client.apply_text_file_edit(&edit, &true),
"text/applyEdit",
json!({
"edit" : {
Expand All @@ -572,7 +572,8 @@ fn test_execution_context() {
],
"oldVersion" : "d3ee9b1ba1990fecfd794d2f30e0207aaa7be5d37d463073096d86f8",
"newVersion" : "6a33e22f20f16642697e8bd549ff7b759252ad56c05a1b0acc31dc69"
}
},
"execute": true
}),
unit_json.clone(),
(),
Expand Down
3 changes: 2 additions & 1 deletion app/gui/docs/product/shortcuts.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ broken and require further investigation.
#### Debug

| Shortcut | Action |
| ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
| ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ | ---------------------- |
| <kbd>ctrl</kbd> + <kbd>shift</kbd> + <kbd>d</kbd> | Toggle Debug Mode. All actions below are only possible when it is activated. |
| <kbd>ctrl</kbd> + <kbd>alt</kbd> + <kbd>shift</kbd> + <kbd>i</kbd> | Open the developer console. |
| <kbd>ctrl</kbd> + <kbd>alt</kbd> + <kbd>shift</kbd> + <kbd>r</kbd> | Reload the visual interface. |
Expand All @@ -134,3 +134,4 @@ broken and require further investigation.
| <kbd>ctrl</kbd> + <kbd>shift</kbd> + <kbd>enter</kbd> | Push a hardcoded breadcrumb without navigating. |
| <kbd>ctrl</kbd> + <kbd>shift</kbd> + <kbd>arrow up</kbd> | Pop a breadcrumb without navigating. |
| <kbd>cmd</kbd> + <kbd>i</kbd> | Reload visualizations. To see the effect in the currently shown visualizations, you need to switch to another and switch back. |
| <kbd>ctrl</kbd> + <kbd>shift</kbd> + <kbd>b</kbd> | | Toggle read-only mode. |
9 changes: 9 additions & 0 deletions app/gui/language/ast/impl/src/opr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,15 @@ mod tests {
test_enumerating(&chain, &a_plus_b_plus_c, &[&a, &b, &c]);
}

#[test]
fn infix_section() {
let a = Ast::var("a");
let a_plus = Ast::section_left(a.clone(), "+");
let chain = Chain::try_new(&a_plus).unwrap();
expect_at(&chain.target, &a);
test_enumerating(&chain, &a_plus, &[&a]);
}

#[test]
fn infix_chain_tests_right() {
let a = Ast::var("a");
Expand Down
22 changes: 9 additions & 13 deletions app/gui/language/parser/src/translation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -436,21 +436,17 @@ impl Translate {
infix(lhs, opr, rhs).map(|opr_app| self.finish_ast(opr_app, builder))
}

/// Translate an operator or multiple-operator erorr into the [`Ast`] representation.
/// Translate an operator or multiple-operator error into the [`Ast`] representation.
fn translate_operators(&mut self, opr: &tree::OperatorOrError) -> WithInitialSpace<Ast> {
match opr {
Ok(name) => match name.code.repr.strip_suffix('=') {
Some(mod_name) if mod_name.contains(|c| c != '=') => {
let opr_builder = self.start_ast();
let token = self.visit_token(name);
token.map(|_| {
let name = mod_name.to_string();
let opr = ast::Mod { name };
self.finish_ast(opr, opr_builder)
})
}
_ => self.translate_operator(name),
},
Ok(name) if name.properties.is_modifier() => {
let opr_builder = self.start_ast();
self.visit_token(name).map(|name| {
let name = name.strip_suffix('=').map(|s| s.to_owned()).unwrap_or(name);
self.finish_ast(ast::Mod { name }, opr_builder)
})
}
Ok(name) => self.translate_operator(name),
Err(names) => {
let opr_builder = self.start_ast();
let mut span_info = SpanSeedBuilder::new();
Expand Down
39 changes: 39 additions & 0 deletions app/gui/language/span-tree/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//! Command-line debug tool for `SpanTree`. Accepts a single line of Enso source code as an
//! argument, and prints a debug representation of the resulting `SpanTree`.
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
#![allow(clippy::bool_to_int_with_if)]
#![allow(clippy::let_and_return)]
// === Non-Standard Linter Configuration ===
#![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]

use span_tree::generate;
use span_tree::generate::SpanTreeGenerator;
use span_tree::SpanTree;



// ===================
// === Entry point ===
// ===================

#[allow(missing_docs)]
pub fn main() {
let mut args = std::env::args();
let _ = args.next().unwrap();
let code = args.next().unwrap();

let parser = parser::Parser::new();
let ast = parser.parse_line_ast(&code).unwrap();
let tree: SpanTree = ast.generate_tree(&generate::context::Empty).unwrap();
let tree = tree.debug_print(&code);
println!("{tree}");
}
176 changes: 153 additions & 23 deletions app/gui/src/controller/graph/executed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ pub struct NotEvaluatedYet(double_representation::node::Id);
#[fail(display = "The node {} does not resolve to a method call.", _0)]
pub struct NoResolvedMethod(double_representation::node::Id);

#[allow(missing_docs)]
#[derive(Debug, Fail, Clone, Copy)]
#[fail(display = "Operation is not permitted in read only mode")]
pub struct ReadOnly;


// ====================
Expand Down Expand Up @@ -216,19 +220,25 @@ impl Handle {
/// This will cause pushing a new stack frame to the execution context and changing the graph
/// controller to point to a new definition.
///
/// Fails if method graph cannot be created (see `graph_for_method` documentation).
/// ### Errors
/// - Fails if method graph cannot be created (see `graph_for_method` documentation).
/// - Fails if the project is in read-only mode.
pub async fn enter_method_pointer(&self, local_call: &LocalCall) -> FallibleResult {
debug!("Entering node {}.", local_call.call);
let method_ptr = &local_call.definition;
let graph = controller::Graph::new_method(&self.project, method_ptr);
let graph = graph.await?;
self.execution_ctx.push(local_call.clone()).await?;
debug!("Replacing graph with {graph:?}.");
self.graph.replace(graph);
debug!("Sending graph invalidation signal.");
self.notifier.publish(Notification::EnteredNode(local_call.clone())).await;

Ok(())
if self.project.read_only() {
Err(ReadOnly.into())
} else {
debug!("Entering node {}.", local_call.call);
let method_ptr = &local_call.definition;
let graph = controller::Graph::new_method(&self.project, method_ptr);
let graph = graph.await?;
self.execution_ctx.push(local_call.clone()).await?;
debug!("Replacing graph with {graph:?}.");
self.graph.replace(graph);
debug!("Sending graph invalidation signal.");
self.notifier.publish(Notification::EnteredNode(local_call.clone())).await;

Ok(())
}
}

/// Attempts to get the computed value of the specified node.
Expand All @@ -246,15 +256,21 @@ impl Handle {

/// Leave the current node. Reverse of `enter_node`.
///
/// Fails if this execution context is already at the stack's root or if the parent graph
/// ### Errors
/// - Fails if this execution context is already at the stack's root or if the parent graph
/// cannot be retrieved.
/// - Fails if the project is in read-only mode.
pub async fn exit_node(&self) -> FallibleResult {
let frame = self.execution_ctx.pop().await?;
let method = self.execution_ctx.current_method();
let graph = controller::Graph::new_method(&self.project, &method).await?;
self.graph.replace(graph);
self.notifier.publish(Notification::SteppedOutOfNode(frame.call)).await;
Ok(())
if self.project.read_only() {
Err(ReadOnly.into())
} else {
let frame = self.execution_ctx.pop().await?;
let method = self.execution_ctx.current_method();
let graph = controller::Graph::new_method(&self.project, &method).await?;
self.graph.replace(graph);
self.notifier.publish(Notification::SteppedOutOfNode(frame.call)).await;
Ok(())
}
}

/// Interrupt the program execution.
Expand All @@ -264,9 +280,16 @@ impl Handle {
}

/// Restart the program execution.
///
/// ### Errors
/// - Fails if the project is in read-only mode.
pub async fn restart(&self) -> FallibleResult {
self.execution_ctx.restart().await?;
Ok(())
if self.project.read_only() {
Err(ReadOnly.into())
} else {
self.execution_ctx.restart().await?;
Ok(())
}
}

/// Get the current call stack frames.
Expand Down Expand Up @@ -308,15 +331,29 @@ impl Handle {
}

/// Create connection in graph.
///
/// ### Errors
/// - Fails if the project is in read-only mode.
pub fn connect(&self, connection: &Connection) -> FallibleResult {
self.graph.borrow().connect(connection, self)
if self.project.read_only() {
Err(ReadOnly.into())
} else {
self.graph.borrow().connect(connection, self)
}
}

/// Remove the connections from the graph. Returns an updated edge destination endpoint for
/// disconnected edge, in case it is still used as destination-only edge. When `None` is
/// returned, no update is necessary.
///
/// ### Errors
/// - Fails if the project is in read-only mode.
pub fn disconnect(&self, connection: &Connection) -> FallibleResult<Option<span_tree::Crumbs>> {
self.graph.borrow().disconnect(connection, self)
if self.project.read_only() {
Err(ReadOnly.into())
} else {
self.graph.borrow().disconnect(connection, self)
}
}
}

Expand Down Expand Up @@ -368,6 +405,8 @@ pub mod tests {
use crate::model::execution_context::ExpressionId;
use crate::test;

use crate::test::mock::Fixture;
use controller::graph::SpanTree;
use engine_protocol::language_server::types::test::value_update_with_type;
use wasm_bindgen_test::wasm_bindgen_test;
use wasm_bindgen_test::wasm_bindgen_test_configure;
Expand Down Expand Up @@ -454,4 +493,95 @@ pub mod tests {

notifications.expect_pending();
}

// Test that moving nodes is possible in read-only mode.
#[wasm_bindgen_test]
fn read_only_mode_does_not_restrict_moving_nodes() {
use model::module::Position;

let fixture = crate::test::mock::Unified::new().fixture();
let Fixture { executed_graph, graph, .. } = fixture;

let nodes = executed_graph.graph().nodes().unwrap();
let node = &nodes[0];

let pos1 = Position::new(500.0, 250.0);
let pos2 = Position::new(300.0, 150.0);

graph.set_node_position(node.id(), pos1).unwrap();
assert_eq!(graph.node(node.id()).unwrap().position(), Some(pos1));
graph.set_node_position(node.id(), pos2).unwrap();
assert_eq!(graph.node(node.id()).unwrap().position(), Some(pos2));
}

// Test that certain actions are forbidden in read-only mode.
#[wasm_bindgen_test]
fn read_only_mode() {
fn run(code: &str, f: impl FnOnce(&Handle)) {
let mut data = crate::test::mock::Unified::new();
data.set_code(code);
let fixture = data.fixture();
fixture.read_only.set(true);
let Fixture { executed_graph, .. } = fixture;
f(&executed_graph);
}


// === Editing the node. ===

let default_code = r#"
main =
foo = 2 * 2
"#;
run(default_code, |executed| {
let nodes = executed.graph().nodes().unwrap();
let node = &nodes[0];
assert!(executed.graph().set_expression(node.info.id(), "5 * 20").is_err());
});


// === Collapsing nodes. ===

let code = r#"
main =
foo = 2
bar = foo + 6
baz = 2 + foo + bar
caz = baz / 2 * baz
"#;
run(code, |executed| {
let nodes = executed.graph().nodes().unwrap();
// Collapse two middle nodes.
let nodes_range = vec![nodes[1].id(), nodes[2].id()];
assert!(executed.graph().collapse(nodes_range, "extracted").is_err());
});


// === Connecting nodes. ===

let code = r#"
main =
2 + 2
5 * 5
"#;
run(code, |executed| {
let nodes = executed.graph().nodes().unwrap();
let sum_node = &nodes[0];
let product_node = &nodes[1];

assert_eq!(sum_node.expression().to_string(), "2 + 2");
assert_eq!(product_node.expression().to_string(), "5 * 5");

let context = &span_tree::generate::context::Empty;
let sum_tree = SpanTree::<()>::new(&sum_node.expression(), context).unwrap();
let sum_input =
sum_tree.root_ref().leaf_iter().find(|n| n.is_argument()).unwrap().crumbs;
let connection = Connection {
source: controller::graph::Endpoint::new(product_node.id(), []),
destination: controller::graph::Endpoint::new(sum_node.id(), sum_input),
};

assert!(executed.connect(&connection).is_err());
});
}
}
2 changes: 1 addition & 1 deletion app/gui/src/controller/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ impl Handle {
) -> FallibleResult<Self> {
let ast = parser.parse(code.to_string(), id_map).try_into()?;
let metadata = default();
let model = Rc::new(model::module::Plain::new(path, ast, metadata, repository));
let model = Rc::new(model::module::Plain::new(path, ast, metadata, repository, default()));
Ok(Handle { model, language_server, parser })
}

Expand Down
Loading

0 comments on commit 04b228f

Please sign in to comment.