cleanup refactor

This commit is contained in:
Anton-4 2021-04-27 17:26:29 +02:00
parent ca23881199
commit 19353a7951
5 changed files with 237 additions and 240 deletions

View File

@ -130,6 +130,9 @@ pub enum EdError {
#[snafu(display("RecordWithoutFields: expected record to have at least one field because it is not an EmpyRecord."))]
RecordWithoutFields { backtrace: Backtrace },
#[snafu(display("StringParseError: {}", msg))]
StringParseError { msg: String, backtrace: Backtrace },
#[snafu(display("UIError: {}", msg))]
UIErrorBacktrace { msg: String, backtrace: Backtrace },
}

View File

@ -126,6 +126,10 @@ impl<'a> EdModel<'a> {
Ok(prev_id_opt)
}
pub fn node_exists_at_caret(&self) -> bool {
self.grid_node_map.node_exists_at_pos(self.get_caret())
}
}
#[derive(Debug)]

View File

@ -551,7 +551,7 @@ pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult
}
ch => {
let outcome =
if ed_model.grid_node_map.node_exists_at_pos(ed_model.get_caret()){
if ed_model.node_exists_at_caret() {
let curr_mark_node_id = ed_model.get_curr_mark_node_id()?;
let curr_mark_node = ed_model.markup_node_pool.get(curr_mark_node_id);
let prev_mark_node_id_opt = ed_model.get_prev_mark_node_id()?;
@ -612,11 +612,7 @@ pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult
}
}
Expr2::SmallInt{ .. } => {
if ch.is_ascii_digit() {
update_int(ed_model, curr_mark_node_id, ch)?
} else {
InputOutcome::Ignored
}
update_int(ed_model, curr_mark_node_id, ch)?
}
_ => InputOutcome::Ignored
}
@ -624,18 +620,14 @@ pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult
match ast_node_ref {
Expr2::SmallInt{ .. } => {
if ch.is_ascii_digit() {
update_int(ed_model, curr_mark_node_id, ch)?
} else {
InputOutcome::Ignored
}
update_int(ed_model, curr_mark_node_id, ch)?
}
_ => {
let prev_ast_node_id =
ed_model
.markup_node_pool
.get(prev_mark_node_id)
.get_ast_node_id();
ed_model
.markup_node_pool
.get(prev_mark_node_id)
.get_ast_node_id();
let prev_node_ref = ed_model.module.env.pool.get(prev_ast_node_id);
@ -674,27 +666,19 @@ pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult
}
}
Expr2::SmallInt{ .. } => {
if ch.is_ascii_digit() {
update_int(ed_model, prev_mark_node_id, ch)?
} else {
InputOutcome::Ignored
}
update_int(ed_model, prev_mark_node_id, ch)?
}
_ => {
match ast_node_ref {
Expr2::EmptyRecord => {
let sibling_ids = curr_mark_node.get_sibling_ids(&ed_model.markup_node_pool);
if ch.is_ascii_alphabetic() && ch.is_ascii_lowercase() {
update_empty_record(
&ch.to_string(),
prev_mark_node_id,
sibling_ids,
ed_model
)?
} else {
InputOutcome::Ignored
}
update_empty_record(
&ch.to_string(),
prev_mark_node_id,
sibling_ids,
ed_model
)?
}
_ => InputOutcome::Ignored
}
@ -719,11 +703,7 @@ pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult
} else {
match ast_node_ref {
Expr2::SmallInt{ .. } => {
if ch.is_ascii_digit() {
update_int(ed_model, curr_mark_node_id, ch)?
} else {
InputOutcome::Ignored
}
update_int(ed_model, curr_mark_node_id, ch)?
},
// only SmallInt currently allows prepending at the start
_ => InputOutcome::Ignored
@ -739,11 +719,7 @@ pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult
match prev_ast_node {
Expr2::SmallInt{ .. } => {
if ch.is_ascii_digit() {
update_int(ed_model, prev_mark_node_id, ch)?
} else {
InputOutcome::Ignored
}
update_int(ed_model, prev_mark_node_id, ch)?
},
_ => {
InputOutcome::Ignored
@ -811,6 +787,10 @@ pub mod test_ed_update {
assert_insert_seq(pre_lines, expected_post_lines, &new_char.to_string())
}
pub fn assert_insert_ignore(lines: &[&str], new_char: char) -> Result<(), String> {
assert_insert_seq(lines, lines, &new_char.to_string())
}
// Create ed_model from pre_lines DSL, do handle_new_char() for every char in new_char_seq, check if modified ed_model has expected
// string representation of code, caret position and active selection.
pub fn assert_insert_seq(
@ -866,13 +846,8 @@ pub mod test_ed_update {
assert_insert(&["1┃"], &["19┃"], '9')?;
assert_insert(&["9876┃"], &["98769┃"], '9')?;
assert_insert(&["0┃"], &["0┃"], '0')?;
assert_insert(&["0┃"], &["0┃"], '9')?;
assert_insert(&["10┃"], &["103┃"], '3')?;
assert_insert(&["┃0"], &["┃0"], '0')?;
assert_insert(&["┃0"], &["1┃0"], '1')?;
assert_insert(&["┃1"], &["┃1"], '0')?;
assert_insert(&["10000┃"], &["100000┃"], '0')?;
assert_insert(&["┃1234"], &["5┃1234"], '5')?;
@ -883,13 +858,6 @@ pub mod test_ed_update {
Ok(())
}
#[test]
fn test_int_time() -> Result<(), String> {
assert_insert_seq(&[""], &["555555┃"], "555555")?;
Ok(())
}
#[test]
fn test_ignore_int() -> Result<(), String> {
assert_insert_seq_ignore(&["┃0"], "{}()[]-><-_\"azAZ:@")?;
@ -909,6 +877,12 @@ pub mod test_ed_update {
assert_insert_seq_ignore(&["129┃96"], ",{}()[]-><-_\"azAZ:@")?;
assert_insert_seq_ignore(&["97┃684"], ",{}()[]-><-_\"azAZ:@")?;
assert_insert_ignore(&["0┃"], '0')?;
assert_insert_ignore(&["0┃"], '9')?;
assert_insert_ignore(&["┃0"], '0')?;
assert_insert_ignore(&["┃1234"], '0')?;
assert_insert_ignore(&["┃100"], '0')?;
Ok(())
}

View File

@ -1,4 +1,5 @@
use crate::editor::ed_error::EdResult;
use crate::editor::ed_error::StringParseError;
use crate::editor::markup::attribute::Attributes;
use crate::editor::markup::nodes::MarkupNode;
use crate::editor::mvc::app_update::InputOutcome;
@ -71,67 +72,85 @@ pub fn start_new_int(ed_model: &mut EdModel, digit_char: &char) -> EdResult<Inpu
}
}
// digit_char should be verified to be a digit before calling this function
// todo verify if new int needs more than e.g. 64 bits
// TODO check if new int needs more than e.g. 64 bits
pub fn update_int(
ed_model: &mut EdModel,
int_mark_node_id: MarkNodeId,
digit_char: &char,
ch: &char,
) -> EdResult<InputOutcome> {
let old_caret_pos = ed_model.get_caret();
if ch.is_ascii_digit() {
let old_caret_pos = ed_model.get_caret();
let node_caret_offset = ed_model
.grid_node_map
.get_offset_to_node_id(old_caret_pos, int_mark_node_id)?;
let node_caret_offset = ed_model
.grid_node_map
.get_offset_to_node_id(old_caret_pos, int_mark_node_id)?;
let int_mark_node = ed_model.markup_node_pool.get_mut(int_mark_node_id);
let int_ast_node_id = int_mark_node.get_ast_node_id();
let int_mark_node = ed_model.markup_node_pool.get_mut(int_mark_node_id);
let int_ast_node_id = int_mark_node.get_ast_node_id();
let content_str_mut = int_mark_node.get_content_mut()?;
let content_str_mut = int_mark_node.get_content_mut()?;
// 00, 01 are not valid ints
if (content_str_mut == "0" && (node_caret_offset == 1 || *digit_char == '0'))
|| (*digit_char == '0' && node_caret_offset == 0)
{
Ok(InputOutcome::Ignored)
} else {
content_str_mut.insert(node_caret_offset, *digit_char);
// 00, 01 are not valid ints
if (content_str_mut == "0" && (node_caret_offset == 1 || *ch == '0'))
|| (*ch == '0' && node_caret_offset == 0)
{
Ok(InputOutcome::Ignored)
} else {
content_str_mut.insert(node_caret_offset, *ch);
let content_str = int_mark_node.get_content()?;
let content_str = int_mark_node.get_content()?;
// update GridNodeMap and CodeLines
ed_model.insert_between_line(
old_caret_pos.line,
old_caret_pos.column,
&digit_char.to_string(),
int_mark_node_id,
)?;
// update GridNodeMap and CodeLines
ed_model.insert_between_line(
old_caret_pos.line,
old_caret_pos.column,
&ch.to_string(),
int_mark_node_id,
)?;
// update ast
let new_pool_str = PoolStr::new(&content_str, ed_model.module.env.pool);
let int_ast_node = ed_model.module.env.pool.get_mut(int_ast_node_id);
match int_ast_node {
SmallInt { number, text, .. } => {
*number = match number {
// TODO remove unwrap
I64(_) => I64(content_str.parse::<i64>().unwrap()),
U64(_) => U64(content_str.parse::<u64>().unwrap()),
I32(_) => I32(content_str.parse::<i32>().unwrap()),
U32(_) => U32(content_str.parse::<u32>().unwrap()),
I16(_) => I16(content_str.parse::<i16>().unwrap()),
U16(_) => U16(content_str.parse::<u16>().unwrap()),
I8(_) => I8(content_str.parse::<i8>().unwrap()),
U8(_) => U8(content_str.parse::<u8>().unwrap()),
};
// update ast
let new_pool_str = PoolStr::new(&content_str, ed_model.module.env.pool);
let int_ast_node = ed_model.module.env.pool.get_mut(int_ast_node_id);
match int_ast_node {
SmallInt { number, text, .. } => {
update_small_int_num(number, &content_str)?;
*text = new_pool_str;
*text = new_pool_str;
}
_ => unimplemented!("TODO implement updating this type of Number"),
}
_ => unimplemented!("TODO implement updating this type of Number"),
// update caret
ed_model.simple_move_carets_right(1);
Ok(InputOutcome::Accepted)
}
// update caret
ed_model.simple_move_carets_right(1);
Ok(InputOutcome::Accepted)
} else {
Ok(InputOutcome::Ignored)
}
}
fn update_small_int_num(number: &mut IntVal, updated_str: &str) -> EdResult<()> {
*number = match number {
I64(_) => I64(check_parse_res(updated_str.parse::<i64>())?),
U64(_) => U64(updated_str.parse::<u64>().unwrap()),
I32(_) => I32(updated_str.parse::<i32>().unwrap()),
U32(_) => U32(updated_str.parse::<u32>().unwrap()),
I16(_) => I16(updated_str.parse::<i16>().unwrap()),
U16(_) => U16(updated_str.parse::<u16>().unwrap()),
I8(_) => I8(updated_str.parse::<i8>().unwrap()),
U8(_) => U8(updated_str.parse::<u8>().unwrap()),
};
Ok(())
}
fn check_parse_res<T, E: std::fmt::Debug>(parse_res: Result<T, E>) -> EdResult<T> {
match parse_res {
Ok(updated_num) => Ok(updated_num),
Err(parse_err) => StringParseError {
msg: format!("{:?}", parse_err),
}
.fail(),
}
}

View File

@ -96,69 +96,77 @@ pub fn update_empty_record(
sibling_ids: Vec<MarkNodeId>,
ed_model: &mut EdModel,
) -> EdResult<InputOutcome> {
let prev_mark_node = ed_model.markup_node_pool.get(prev_mark_node_id);
let mut input_chars = new_input.chars();
let NodeContext {
old_caret_pos,
curr_mark_node_id,
curr_mark_node,
parent_id_opt,
ast_node_id,
} = get_node_context(&ed_model)?;
if prev_mark_node.get_content()? == nodes::LEFT_ACCOLADE
&& curr_mark_node.get_content()? == nodes::RIGHT_ACCOLADE
if input_chars.all(|ch| ch.is_ascii_alphabetic())
&& input_chars.all(|ch| ch.is_ascii_lowercase())
{
// update AST
let record_var = ed_model.module.env.var_store.fresh();
let field_name = PoolStr::new(new_input, &mut ed_model.module.env.pool);
let field_var = ed_model.module.env.var_store.fresh();
//TODO actually check if field_str belongs to a previously defined variable
let first_field = RecordField::InvalidLabelOnly(field_name, field_var);
let prev_mark_node = ed_model.markup_node_pool.get(prev_mark_node_id);
let fields = PoolVec::new(vec![first_field].into_iter(), &mut ed_model.module.env.pool);
let new_ast_node = Expr2::Record { record_var, fields };
ed_model.module.env.pool.set(ast_node_id, new_ast_node);
// update Markup
let record_field_node = MarkupNode::Text {
content: new_input.to_owned(),
ast_node_id,
syn_high_style: HighlightStyle::RecordField,
attributes: Attributes::new(),
let NodeContext {
old_caret_pos,
curr_mark_node_id,
curr_mark_node,
parent_id_opt,
};
ast_node_id,
} = get_node_context(&ed_model)?;
let record_field_node_id = ed_model.markup_node_pool.add(record_field_node);
if prev_mark_node.get_content()? == nodes::LEFT_ACCOLADE
&& curr_mark_node.get_content()? == nodes::RIGHT_ACCOLADE
{
// update AST
let record_var = ed_model.module.env.var_store.fresh();
let field_name = PoolStr::new(new_input, &mut ed_model.module.env.pool);
let field_var = ed_model.module.env.var_store.fresh();
//TODO actually check if field_str belongs to a previously defined variable
let first_field = RecordField::InvalidLabelOnly(field_name, field_var);
if let Some(parent_id) = parent_id_opt {
let parent = ed_model.markup_node_pool.get_mut(parent_id);
let fields = PoolVec::new(vec![first_field].into_iter(), &mut ed_model.module.env.pool);
let new_child_index = index_of(curr_mark_node_id, &sibling_ids)?;
let new_ast_node = Expr2::Record { record_var, fields };
parent.add_child_at_index(new_child_index, record_field_node_id)?;
} else {
MissingParent {
node_id: curr_mark_node_id,
ed_model.module.env.pool.set(ast_node_id, new_ast_node);
// update Markup
let record_field_node = MarkupNode::Text {
content: new_input.to_owned(),
ast_node_id,
syn_high_style: HighlightStyle::RecordField,
attributes: Attributes::new(),
parent_id_opt,
};
let record_field_node_id = ed_model.markup_node_pool.add(record_field_node);
if let Some(parent_id) = parent_id_opt {
let parent = ed_model.markup_node_pool.get_mut(parent_id);
let new_child_index = index_of(curr_mark_node_id, &sibling_ids)?;
parent.add_child_at_index(new_child_index, record_field_node_id)?;
} else {
MissingParent {
node_id: curr_mark_node_id,
}
.fail()?
}
.fail()?
// update caret
ed_model.simple_move_carets_right(1);
// update GridNodeMap and CodeLines
ed_model.insert_between_line(
old_caret_pos.line,
old_caret_pos.column,
new_input,
record_field_node_id,
)?;
Ok(InputOutcome::Accepted)
} else {
Ok(InputOutcome::Ignored)
}
// update caret
ed_model.simple_move_carets_right(1);
// update GridNodeMap and CodeLines
ed_model.insert_between_line(
old_caret_pos.line,
old_caret_pos.column,
new_input,
record_field_node_id,
)?;
Ok(InputOutcome::Accepted)
} else {
Ok(InputOutcome::Ignored)
}
@ -175,7 +183,6 @@ pub fn update_record_colon(
parent_id_opt,
ast_node_id,
} = get_node_context(&ed_model)?;
// TODO clean up if-else waterfall
if let Some(parent_id) = parent_id_opt {
let curr_ast_node = ed_model.module.env.pool.get(ast_node_id);
@ -190,110 +197,100 @@ pub fn update_record_colon(
.get(prev_mark_node.get_ast_node_id());
// current and prev node should always point to record when in valid position to add ':'
if let Expr2::Record { .. } = prev_ast_node {
if let Expr2::Record { .. } = curr_ast_node {
let sibling_ids = curr_mark_node.get_sibling_ids(&ed_model.markup_node_pool);
if matches!(prev_ast_node, Expr2::Record { .. }) && matches!(curr_ast_node, Expr2::Record { .. }) {
let sibling_ids = curr_mark_node.get_sibling_ids(&ed_model.markup_node_pool);
let new_child_index = index_of(curr_mark_node_id, &sibling_ids)?;
let new_child_index = index_of(curr_mark_node_id, &sibling_ids)?;
let ast_node_ref = ed_model.module.env.pool.get(record_ast_node_id);
let ast_node_ref = ed_model.module.env.pool.get(record_ast_node_id);
match ast_node_ref {
Expr2::Record {
record_var: _,
fields,
} => {
let next_mark_node_id_res =
ed_model.grid_node_map.get_id_at_row_col(old_caret_pos);
match ast_node_ref {
Expr2::Record {
record_var: _,
fields,
} => {
if ed_model.node_exists_at_caret() {
let next_mark_node_id =
ed_model.grid_node_map.get_id_at_row_col(old_caret_pos)?;
let next_mark_node = ed_model.markup_node_pool.get(next_mark_node_id);
if next_mark_node.get_content()? == nodes::RIGHT_ACCOLADE {
// update AST node
let new_field_val = Expr2::Blank;
let new_field_val_id = ed_model.module.env.pool.add(new_field_val);
if let Ok(next_mark_node_id) = next_mark_node_id_res {
let next_mark_node =
ed_model.markup_node_pool.get(next_mark_node_id);
if next_mark_node.get_content()? == nodes::RIGHT_ACCOLADE {
// update AST node
let new_field_val = Expr2::Blank;
let new_field_val_id =
ed_model.module.env.pool.add(new_field_val);
let first_field_mut = fields
.iter_mut(ed_model.module.env.pool)
.next()
.with_context(|| RecordWithoutFields {})?;
let first_field_mut = fields
.iter_mut(ed_model.module.env.pool)
.next()
.with_context(|| RecordWithoutFields {})?;
*first_field_mut = RecordField::LabeledValue(
*first_field_mut.get_record_field_pool_str(),
*first_field_mut.get_record_field_var(),
new_field_val_id,
);
*first_field_mut = RecordField::LabeledValue(
*first_field_mut.get_record_field_pool_str(),
*first_field_mut.get_record_field_var(),
new_field_val_id,
);
// update Markup
let record_colon = nodes::COLON;
// update Markup
let record_colon = nodes::COLON;
let record_colon_node = MarkupNode::Text {
content: record_colon.to_owned(),
ast_node_id: record_ast_node_id,
syn_high_style: HighlightStyle::Operator,
attributes: Attributes::new(),
parent_id_opt: Some(parent_id),
};
let record_colon_node = MarkupNode::Text {
content: record_colon.to_owned(),
ast_node_id: record_ast_node_id,
syn_high_style: HighlightStyle::Operator,
attributes: Attributes::new(),
parent_id_opt: Some(parent_id),
};
let record_colon_node_id =
ed_model.markup_node_pool.add(record_colon_node);
ed_model
.markup_node_pool
.get_mut(parent_id)
.add_child_at_index(new_child_index, record_colon_node_id)?;
let record_colon_node_id =
ed_model.markup_node_pool.add(record_colon_node);
ed_model
.markup_node_pool
.get_mut(parent_id)
.add_child_at_index(
new_child_index,
record_colon_node_id,
)?;
let record_blank_node = MarkupNode::Blank {
ast_node_id: new_field_val_id,
syn_high_style: HighlightStyle::Blank,
attributes: Attributes::new(),
parent_id_opt: Some(parent_id),
};
let record_blank_node = MarkupNode::Blank {
ast_node_id: new_field_val_id,
syn_high_style: HighlightStyle::Blank,
attributes: Attributes::new(),
parent_id_opt: Some(parent_id),
};
let record_blank_node_id =
ed_model.markup_node_pool.add(record_blank_node);
ed_model
.markup_node_pool
.get_mut(parent_id)
.add_child_at_index(
new_child_index + 1,
record_blank_node_id,
)?;
// update caret
ed_model.simple_move_carets_right(record_colon.len());
// update GridNodeMap and CodeLines
ed_model.insert_between_line(
old_caret_pos.line,
old_caret_pos.column,
nodes::COLON,
record_colon_node_id,
)?;
ed_model.insert_between_line(
old_caret_pos.line,
old_caret_pos.column + nodes::COLON.len(),
nodes::BLANK_PLACEHOLDER,
let record_blank_node_id =
ed_model.markup_node_pool.add(record_blank_node);
ed_model
.markup_node_pool
.get_mut(parent_id)
.add_child_at_index(
new_child_index + 1,
record_blank_node_id,
)?;
Ok(InputOutcome::Accepted)
} else {
Ok(InputOutcome::Ignored)
}
// update caret
ed_model.simple_move_carets_right(record_colon.len());
// update GridNodeMap and CodeLines
ed_model.insert_between_line(
old_caret_pos.line,
old_caret_pos.column,
nodes::COLON,
record_colon_node_id,
)?;
ed_model.insert_between_line(
old_caret_pos.line,
old_caret_pos.column + nodes::COLON.len(),
nodes::BLANK_PLACEHOLDER,
record_blank_node_id,
)?;
Ok(InputOutcome::Accepted)
} else {
Ok(InputOutcome::Ignored)
}
} else {
Ok(InputOutcome::Ignored)
}
_ => Ok(InputOutcome::Ignored),
}
} else {
Ok(InputOutcome::Ignored)
_ => Ok(InputOutcome::Ignored),
}
} else {
Ok(InputOutcome::Ignored)