diff --git a/editor/src/editor/ed_error.rs b/editor/src/editor/ed_error.rs index a32ee0abb4..73b3b2451c 100644 --- a/editor/src/editor/ed_error.rs +++ b/editor/src/editor/ed_error.rs @@ -67,6 +67,12 @@ pub enum EdError { ))] EmptyCodeString { backtrace: Backtrace }, + #[snafu(display( + "FailedToUpdateIdentIdName: {}", + err_str + ))] + FailedToUpdateIdentIdName { err_str: String, backtrace: Backtrace }, + #[snafu(display("GetContentOnNestedNode: tried to get string content from Nested MarkupNode. Can only get content from Text or Blank nodes."))] GetContentOnNestedNode { backtrace: Backtrace }, @@ -123,6 +129,12 @@ pub enum EdError { backtrace: Backtrace, }, + #[snafu(display("NoDefMarkNodeBeforeLineNr: I could not find a MarkupNode whose root parent points to a DefId located before the given line number: {}.", line_nr))] + NoDefMarkNodeBeforeLineNr { + line_nr: usize, + backtrace: Backtrace, + }, + #[snafu(display("NodeWithoutAttributes: expected to have a node with attributes. This is a Nested MarkupNode, only Text and Blank nodes have attributes."))] NodeWithoutAttributes { backtrace: Backtrace }, diff --git a/editor/src/editor/grid_node_map.rs b/editor/src/editor/grid_node_map.rs index b9400db2c5..96ef1b1b26 100644 --- a/editor/src/editor/grid_node_map.rs +++ b/editor/src/editor/grid_node_map.rs @@ -1,6 +1,6 @@ use crate::editor::ed_error::EdResult; use crate::editor::ed_error::NestedNodeWithoutChildren; -use crate::editor::ed_error::NodeIdNotInGridNodeMap; +use crate::editor::ed_error::{NodeIdNotInGridNodeMap, NoDefMarkNodeBeforeLineNr}; use crate::editor::mvc::ed_model::EdModel; use crate::editor::slow_pool::MarkNodeId; use crate::editor::slow_pool::SlowPool; @@ -14,6 +14,8 @@ use crate::ui::util::{slice_get, slice_get_mut}; use snafu::OptionExt; use std::fmt; +use super::markup::nodes::get_root_mark_node_id; + #[derive(Debug)] pub struct GridNodeMap { pub lines: Vec>, @@ -79,16 +81,13 @@ impl GridNodeMap { line_ref.drain(selection.start_pos.column..selection.end_pos.column); } else { - // TODO support multiline + unimplemented!("TODO support deleting multiline selection") + } Ok(()) } - /*pub fn new_line(&mut self) { - self.lines.push(vec![]) - }*/ - pub fn get_id_at_row_col(&self, caret_pos: TextPos) -> UIResult { let line = slice_get(caret_pos.line, &self.lines)?; let node_id = slice_get(caret_pos.column, line)?; @@ -327,6 +326,38 @@ impl GridNodeMap { Ok(last_child_id) } + + // get id of root mark_node whose ast_node_id points to a DefId + pub fn get_def_mark_node_id_before_line( + &self, + line_nr: usize, + mark_node_pool: &SlowPool, + ) -> EdResult { + + for curr_line_nr in (0..line_nr).rev() { + let first_col_pos = + TextPos { + line: curr_line_nr, + column: 0 + }; + + if self.node_exists_at_pos(first_col_pos) { + let mark_node_id = self.get_id_at_row_col(first_col_pos)?; + let root_mark_node_id = get_root_mark_node_id(mark_node_id, mark_node_pool); + + let ast_node_id = mark_node_pool.get(root_mark_node_id).get_ast_node_id(); + + match ast_node_id { + ASTNodeId::ADefId(_) => return Ok(root_mark_node_id), + _ => (), + } + } + } + + NoDefMarkNodeBeforeLineNr { + line_nr + }.fail() + } } impl fmt::Display for GridNodeMap { diff --git a/editor/src/editor/markup/nodes.rs b/editor/src/editor/markup/nodes.rs index f8cb54735d..06e480b3c0 100644 --- a/editor/src/editor/markup/nodes.rs +++ b/editor/src/editor/markup/nodes.rs @@ -829,3 +829,20 @@ fn tree_as_string_helper( tree_as_string_helper(child, level + 1, tree_string, mark_node_pool); } } + +// return to the the root parent_id of the current node +pub fn get_root_mark_node_id( + mark_node_id: MarkNodeId, + mark_node_pool: &SlowPool, +) -> MarkNodeId { + + let mut curr_mark_node_id = mark_node_id; + let mut curr_parent_id_opt = mark_node_pool.get(curr_mark_node_id).get_parent_id_opt(); + + while let Some(curr_parent_id) = curr_parent_id_opt { + curr_mark_node_id = curr_parent_id; + curr_parent_id_opt = mark_node_pool.get(curr_mark_node_id).get_parent_id_opt(); + } + + curr_mark_node_id +} diff --git a/editor/src/editor/mvc/ed_update.rs b/editor/src/editor/mvc/ed_update.rs index 6d17be3bd3..1b9580410c 100644 --- a/editor/src/editor/mvc/ed_update.rs +++ b/editor/src/editor/mvc/ed_update.rs @@ -28,6 +28,7 @@ use crate::editor::mvc::tld_value_update::{start_new_tld_value, update_tld_val_n use crate::editor::slow_pool::MarkNodeId; use crate::editor::slow_pool::SlowPool; use crate::editor::syntax_highlight::HighlightStyle; +use crate::editor::util::index_of; use crate::lang::ast::Def2; use crate::lang::ast::DefId; use crate::lang::ast::{Expr2, ExprId}; @@ -755,7 +756,7 @@ pub fn handle_new_char_expr( start_new_list(ed_model)? } '\r' => { - // For convenience and consistency there is only one way to format Roc, you can't add extra blank lines. + println!("For convenience and consistency there is only one way to format Roc, you can't add extra blank lines."); InputOutcome::Ignored } _ => InputOutcome::Ignored, @@ -1032,7 +1033,7 @@ pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult } else { //no MarkupNode at the current position if *received_char == '\r' { - // TODO move to separate file + // TODO move to separate function let carets = ed_model.get_carets(); for caret_pos in carets.iter() { @@ -1055,14 +1056,14 @@ pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult let new_line_blank = Def2::Blank; let new_line_blank_id = ed_model.module.env.pool.add(new_line_blank); - // TODO this should insert at caret line_nr, not push at end - ed_model.module.ast.def_ids.push(new_line_blank_id); + let prev_def_mn_id = ed_model.grid_node_map.get_def_mark_node_id_before_line(caret_pos.line + 1, &ed_model.mark_node_pool)?; + let prev_def_mn_id_indx = index_of(prev_def_mn_id, &ed_model.markup_ids)?; + ed_model.module.ast.def_ids.insert(prev_def_mn_id_indx, new_line_blank_id); let blank_mn_id = ed_model .add_mark_node(new_blank_mn(ASTNodeId::ADefId(new_line_blank_id), None)); - // TODO this should insert at caret line_nr, not push at end - ed_model.markup_ids.push(blank_mn_id); + ed_model.markup_ids.insert(prev_def_mn_id_indx + 1,blank_mn_id); // + 1 because first markup node is header ed_model.insert_all_between_line( caret_pos.line + 2, // one blank line between top level definitions @@ -1103,14 +1104,14 @@ pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult let new_blank = Def2::Blank; let new_blank_id = ed_model.module.env.pool.add(new_blank); - // TODO this should insert at caret line_nr, not push at end - ed_model.module.ast.def_ids.push(new_blank_id); + let prev_def_mn_id = ed_model.grid_node_map.get_def_mark_node_id_before_line(caret_pos.line, &ed_model.mark_node_pool)?; + let prev_def_mn_id_indx = index_of(prev_def_mn_id, &ed_model.markup_ids)?; + ed_model.module.ast.def_ids.insert(prev_def_mn_id_indx, new_blank_id); let blank_mn_id = ed_model .add_mark_node(new_blank_mn(ASTNodeId::ADefId(new_blank_id), None)); - // TODO this should insert at caret line_nr, not push at end - ed_model.markup_ids.push(blank_mn_id); + ed_model.markup_ids.insert(prev_def_mn_id_indx + 1,blank_mn_id); // + 1 because first mark_node is header if ed_model.code_lines.line_is_only_newline(caret_pos.line - 1)? { @@ -1124,7 +1125,7 @@ pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult ed_model.simple_move_caret_down(caret_pos, 1); ed_model.insert_all_between_line( - caret_pos.line + 1, + caret_pos.line, 0, &[blank_mn_id], )?; diff --git a/editor/src/editor/mvc/tld_value_update.rs b/editor/src/editor/mvc/tld_value_update.rs index 7c2a0bf565..2fd7429cd9 100644 --- a/editor/src/editor/mvc/tld_value_update.rs +++ b/editor/src/editor/mvc/tld_value_update.rs @@ -1,25 +1,12 @@ use roc_module::symbol::{Interns, Symbol}; -use crate::{ - editor::{ - ed_error::{EdResult, KeyNotFound}, - markup::{ - attribute::Attributes, - common_nodes::{new_blank_mn_w_nl, new_equals_mn}, - nodes::MarkupNode, - }, - slow_pool::{MarkNodeId, SlowPool}, - syntax_highlight::HighlightStyle, - }, - lang::{ +use crate::{editor::{ed_error::{EdResult, KeyNotFound, FailedToUpdateIdentIdName}, markup::{attribute::Attributes, common_nodes::{new_blank_mn_w_nl, new_equals_mn}, nodes::{MarkupNode, set_parent_for_all}}, slow_pool::{MarkNodeId, SlowPool}, syntax_highlight::HighlightStyle}, lang::{ ast::{Def2, Expr2}, expr::Env, parse::ASTNodeId, pattern::{get_identifier_string, Pattern2}, pool::NodeId, - }, - ui::text::text_pos::TextPos, -}; + }, ui::text::text_pos::TextPos}; use super::{ app_update::InputOutcome, @@ -134,6 +121,8 @@ pub fn start_new_tld_value(ed_model: &mut EdModel, new_char: &char) -> EdResult< .mark_node_pool .replace_node(curr_mark_node_id, tld_mark_node); + set_parent_for_all(curr_mark_node_id, &mut ed_model.mark_node_pool); + // remove data corresponding to old Blank node ed_model.del_at_line(old_caret_pos.line, old_caret_pos.column)?; @@ -172,13 +161,21 @@ pub fn update_tld_val_name( if node_caret_offset <= content_str_mut.len() { content_str_mut.insert(node_caret_offset, *new_char); - // TODO no unwrap - ed_model + let update_val_name_res = ed_model .module .env .ident_ids - .update_key(&old_val_name, content_str_mut) - .unwrap(); + .update_key(&old_val_name, content_str_mut); + + match update_val_name_res { + Err(err_str) => { + FailedToUpdateIdentIdName { + err_str + }.fail()?; + } + _ => (), + } + ed_model.insert_between_line( old_caret_pos.line,