finished hadnle_new_char tests, bugfixes

This commit is contained in:
Anton-4 2021-04-12 17:33:22 +02:00
parent 81f44b936b
commit 33184b60f8
9 changed files with 557 additions and 167 deletions

View File

@ -15,7 +15,10 @@ pub struct CodeLines {
impl CodeLines {
pub fn from_str(code_str: &str) -> CodeLines {
CodeLines {
lines: code_str.split_inclusive('\n').map(|s| s.to_owned()).collect(),
lines: code_str
.split_inclusive('\n')
.map(|s| s.to_owned())
.collect(),
nr_of_chars: code_str.len(),
}
}

View File

@ -1,4 +1,3 @@
use crate::lang::ast::{RecordField};
use super::attribute::Attributes;
use crate::editor::ed_error::EdResult;
use crate::editor::ed_error::ExpectedTextNode;
@ -7,6 +6,7 @@ use crate::editor::ed_error::NestedNodeRequired;
use crate::editor::slow_pool::MarkNodeId;
use crate::editor::slow_pool::SlowPool;
use crate::editor::syntax_highlight::HighlightStyle;
use crate::lang::ast::RecordField;
use crate::lang::{
ast::Expr2,
expr::Env,
@ -200,7 +200,12 @@ pub fn expr2_to_markup<'a, 'b>(
Expr2::Var(symbol) => {
//TODO make bump_format with arena
let text = format!("{:?}", symbol);
new_markup_node(text, expr2_node_id, HighlightStyle::Variable, markup_node_pool)
new_markup_node(
text,
expr2_node_id,
HighlightStyle::Variable,
markup_node_pool,
)
}
Expr2::List { elems, .. } => {
let mut children_ids = vec![new_markup_node(
@ -213,7 +218,13 @@ pub fn expr2_to_markup<'a, 'b>(
for (idx, node_id) in elems.iter_node_ids().enumerate() {
let sub_expr2 = env.pool.get(node_id);
children_ids.push(expr2_to_markup(arena, env, sub_expr2, node_id, markup_node_pool));
children_ids.push(expr2_to_markup(
arena,
env,
sub_expr2,
node_id,
markup_node_pool,
));
if idx + 1 < elems.len() {
children_ids.push(new_markup_node(
@ -275,7 +286,7 @@ pub fn expr2_to_markup<'a, 'b>(
// let (pool_field_name, _, sub_expr2_node_id) = env.pool.get(field_node_id);
let record_field = env.pool.get(field_node_id);
let field_name = record_field.get_record_field_pool_str();
let field_name = record_field.get_record_field_pool_str();
children_ids.push(new_markup_node(
field_name.as_str(env.pool).to_owned(),
@ -284,20 +295,26 @@ pub fn expr2_to_markup<'a, 'b>(
markup_node_pool,
));
children_ids.push(new_markup_node(
COLON.to_string(),
expr2_node_id,
HighlightStyle::Operator,
markup_node_pool,
));
match record_field {
RecordField::InvalidLabelOnly(_, _) => (),
RecordField::LabelOnly(_, _, _) => (),
RecordField::LabeledValue(_, _, sub_expr2_node_id) => {
children_ids.push(new_markup_node(
COLON.to_string(),
expr2_node_id,
HighlightStyle::Operator,
markup_node_pool,
));
let sub_expr2 = env.pool.get(*sub_expr2_node_id);
children_ids.push(expr2_to_markup(arena, env, sub_expr2, *sub_expr2_node_id, markup_node_pool));
},
children_ids.push(expr2_to_markup(
arena,
env,
sub_expr2,
*sub_expr2_node_id,
markup_node_pool,
));
}
}
if idx + 1 < fields.len() {

View File

@ -23,7 +23,6 @@ use nonempty::NonEmpty;
use roc_region::all::Region;
use std::path::Path;
#[derive(Debug)]
pub struct EdModel<'a> {
pub module: EdModule<'a>,
@ -68,8 +67,13 @@ pub fn init_model<'a>(
} else {
let ast_root = &module.env.pool.get(ast_root_id);
let temp_markup_root_id =
expr2_to_markup(code_arena, &mut module.env, ast_root, ast_root_id, &mut markup_node_pool);
let temp_markup_root_id = expr2_to_markup(
code_arena,
&mut module.env,
ast_root,
ast_root_id,
&mut markup_node_pool,
);
set_parent_for_all(temp_markup_root_id, &mut markup_node_pool);
temp_markup_root_id
@ -159,23 +163,25 @@ impl<'a> EdModule<'a> {
#[cfg(test)]
pub mod test_ed_model {
use crate::ui::text::caret_w_select::test_caret_w_select::convert_selection_to_dsl;
use crate::ui::ui_error::UIResult;
use crate::ui::text::caret_w_select::test_caret_w_select::convert_dsl_to_selection;
use std::{path::Path};
use crate::editor::ed_error::EdResult;
use crate::editor::mvc::ed_model;
use crate::lang::expr::Env;
use crate::lang::pool::Pool;
use crate::editor::mvc::ed_model;
use ed_model::EdModel;
use crate::ui::text::caret_w_select::test_caret_w_select::convert_dsl_to_selection;
use crate::ui::text::caret_w_select::test_caret_w_select::convert_selection_to_dsl;
use crate::ui::text::lines::SelectableLines;
use crate::ui::ui_error::UIResult;
use bumpalo::collections::String as BumpString;
use bumpalo::Bump;
use ed_model::EdModel;
use roc_module::symbol::{IdentIds, ModuleIds};
use roc_types::subs::VarStore;
use bumpalo::collections::String as BumpString;
use crate::editor::ed_error::EdResult;
use crate::ui::text::lines::SelectableLines;
use std::path::Path;
pub fn init_dummy_model<'a>(code_str: &'a BumpString, ed_model_refs: &'a mut EdModelRefs) -> EdResult<EdModel<'a>> {
pub fn init_dummy_model<'a>(
code_str: &'a BumpString,
ed_model_refs: &'a mut EdModelRefs,
) -> EdResult<EdModel<'a>> {
let file_path = Path::new("");
let dep_idents = IdentIds::exposed_builtins(8);
@ -189,14 +195,14 @@ use std::{path::Path};
&mut ed_model_refs.env_pool,
&mut ed_model_refs.var_store,
dep_idents,
& ed_model_refs.module_ids,
&ed_model_refs.module_ids,
exposed_ident_ids,
);
ed_model::init_model(&code_str, file_path, env, &ed_model_refs.code_arena)
}
pub struct EdModelRefs{
pub struct EdModelRefs {
code_arena: Bump,
env_arena: Bump,
env_pool: Pool,
@ -214,11 +220,13 @@ use std::{path::Path};
}
}
pub fn ed_model_from_dsl<'a>(clean_code_str: &'a BumpString, code_lines: &[&str], ed_model_refs: &'a mut EdModelRefs) -> Result<EdModel<'a>, String> {
pub fn ed_model_from_dsl<'a>(
clean_code_str: &'a BumpString,
code_lines: &[&str],
ed_model_refs: &'a mut EdModelRefs,
) -> Result<EdModel<'a>, String> {
let code_lines_vec: Vec<String> = (*code_lines).iter().map(|s| s.to_string()).collect();
let caret_w_select = convert_dsl_to_selection(
&code_lines_vec
)?;
let caret_w_select = convert_dsl_to_selection(&code_lines_vec)?;
let mut ed_model = init_dummy_model(clean_code_str, ed_model_refs)?;

View File

@ -443,12 +443,16 @@ pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult
Expr2::EmptyRecord => {
let sibling_ids = curr_mark_node.get_sibling_ids(&ed_model.markup_node_pool);
update_empty_record(
&ch.to_string(),
prev_mark_node_id,
sibling_ids,
ed_model
)?
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
}
}
_ => InputOutcome::Ignored
}
@ -488,26 +492,26 @@ pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult
#[cfg(test)]
pub mod test_ed_update {
use crate::ui::ui_error::UIResult;
use crate::editor::mvc::ed_model::test_ed_model::ed_model_to_dsl;
use crate::editor::mvc::ed_update::EdResult;
use crate::editor::mvc::ed_update::handle_new_char;
use crate::editor::mvc::ed_model::test_ed_model::ed_model_from_dsl;
use bumpalo::Bump;
use bumpalo::collections::String as BumpString;
use crate::editor::mvc::ed_model::test_ed_model::ed_model_to_dsl;
use crate::editor::mvc::ed_model::test_ed_model::init_model_refs;
use crate::editor::mvc::ed_update::handle_new_char;
use crate::editor::mvc::ed_update::EdResult;
use crate::ui::ui_error::UIResult;
use bumpalo::collections::String as BumpString;
use bumpalo::Bump;
fn ed_res_to_res<T>(ed_res: EdResult<T>) -> Result<T, String> {
match ed_res {
Ok(t) => Ok(t),
Err(e) => Err(e.to_string())
Err(e) => Err(e.to_string()),
}
}
fn ui_res_to_res<T>(ed_res: UIResult<T>) -> Result<T, String> {
match ed_res {
Ok(t) => Ok(t),
Err(e) => Err(e.to_string())
Err(e) => Err(e.to_string()),
}
}
@ -516,25 +520,16 @@ pub mod test_ed_update {
expected_post_lines: &[&str],
new_char: char,
) -> Result<(), String> {
assert_insert_char_seq(
pre_lines,
expected_post_lines,
&new_char.to_string()
)
assert_insert_seq(pre_lines, expected_post_lines, &new_char.to_string())
}
pub fn assert_insert_char_seq(
pub fn assert_insert_seq(
pre_lines: &[&str],
expected_post_lines: &[&str],
new_char_seq: &str,
) -> Result<(), String> {
let test_arena = Bump::new();
let code_str = BumpString::from_str_in(
&pre_lines.join("").replace("", ""),
&test_arena
);
let code_str = BumpString::from_str_in(&pre_lines.join("").replace("", ""), &test_arena);
let mut model_refs = init_model_refs();
@ -551,6 +546,10 @@ pub mod test_ed_update {
Ok(())
}
pub fn assert_insert_seq_ignore(lines: &[&str], new_char_seq: &str) -> Result<(), String> {
assert_insert_seq(lines, lines, new_char_seq)
}
#[test]
fn test_ignore_basic() -> Result<(), String> {
// space is added because Blank is inserted
@ -585,9 +584,21 @@ pub mod test_ed_update {
assert_insert(&["\"ab ┃\""], &["\"ab {┃\""], '{')?;
assert_insert(&["\"ab ┃\""], &["\"ab }┃\""], '}')?;
assert_insert(&["\"{ str: 4┃}\""], &["\"{ str: 44┃}\""], '4')?;
assert_insert(&["\"┃ello, hello, hello\""], &["\"h┃ello, hello, hello\""], 'h')?;
assert_insert(&["\"hello┃ hello, hello\""], &["\"hello,┃ hello, hello\""], ',')?;
assert_insert(&["\"hello, hello, hello┃\""], &["\"hello, hello, hello.┃\""], '.')?;
assert_insert(
&["\"┃ello, hello, hello\""],
&["\"h┃ello, hello, hello\""],
'h',
)?;
assert_insert(
&["\"hello┃ hello, hello\""],
&["\"hello,┃ hello, hello\""],
',',
)?;
assert_insert(
&["\"hello, hello, hello┃\""],
&["\"hello, hello, hello.┃\""],
'.',
)?;
Ok(())
}
@ -650,31 +661,41 @@ pub mod test_ed_update {
assert_insert(&["\"[ 1, 2, 3 ]\""], &["\"[ 1, 2, 3 ]\""], '{')?;
assert_insert(&["\"[ 1, 2, 3 ]\""], &["\"[ 1, 2, 3 ]\""], '{')?;
assert_insert(&["\"hello, hello, hello\""], &["\"hello, hello, hello\""], '.')?;
assert_insert(&["\"hello, hello, hello\""], &["\"hello, hello, hello\""], '.')?;
assert_insert(
&["\"hello, hello, hello\""],
&["\"hello, hello, hello\""],
'.',
)?;
assert_insert(
&["\"hello, hello, hello\""],
&["\"hello, hello, hello\""],
'.',
)?;
// TODO char_seq
Ok(())
}
#[test]
fn test_record() -> Result<(), String> {
// assert_insert(&["┃"], &["{ ┃ }"], '{')?;
// assert_insert(&["{ ┃ }"], &["{ a┃ }"], 'a')?;
// assert_insert(&["{ a┃ }"], &["{ ab┃ }"], 'b')?;
// assert_insert(&["{ ab┃ }"], &["{ abc┃ }"], 'c')?;
// assert_insert(&["{ ┃ab }"], &["{ z┃abc }"], 'z')?;
// assert_insert(&["{ a┃b }"], &["{ az┃b }"], 'z')?;
assert_insert(&[""], &["{ ┃ }"], '{')?;
assert_insert(&["{ ┃ }"], &["{ a┃ }"], 'a')?;
assert_insert(&["{ a┃ }"], &["{ ab┃ }"], 'b')?;
assert_insert(&["{ a┃ }"], &["{ a1┃ }"], '1')?;
assert_insert(&["{ a1┃ }"], &["{ a1z┃ }"], 'z')?;
assert_insert(&["{ a1┃ }"], &["{ a15┃ }"], '5')?;
assert_insert(&["{ ab┃ }"], &["{ abc┃ }"], 'c')?;
assert_insert(&["{ ┃abc }"], &["{ z┃abc }"], 'z')?;
assert_insert(&["{ a┃b }"], &["{ az┃b }"], 'z')?;
assert_insert(&["{ a┃b }"], &["{ a9┃b }"], '9')?;
// assert_insert(&["{ a┃ }"], &["{ a: ┃ }"], ':')?;
// assert_insert(&["{ abc┃ }"], &["{ abc: ┃ }"], ':')?;
// assert_insert(&["{ aBc┃ }"], &["{ aBc: ┃ }"], ':')?;
// extra space for Blank node
assert_insert(&["{ a┃ }"], &["{ a: ┃ }"], ':')?;
assert_insert(&["{ abc┃ }"], &["{ abc: ┃ }"], ':')?;
assert_insert(&["{ aBc┃ }"], &["{ aBc: ┃ }"], ':')?;
// TODO use assert_insert_char_seq here
// assert_insert(&["{ a: ┃ }"], &["{ a: \"┃\" }"], '"')?;
// assert_insert(&["{ abc: ┃ }"], &["{ abc: \"┃\" }"], '"')?;
// assert_insert(&["{ a: ┃ }"], &["{ a: { ┃ }"], '{')?;
// assert_insert(&["{ abc: ┃ }"], &["{ abc: { ┃ }"], '{')?;
assert_insert_seq(&["{ a┃ }"], &["{ a: \"\" }"], ":\"")?;
assert_insert_seq(&["{ abc┃ }"], &["{ abc: \"\" }"], ":\"")?;
assert_insert(&["{ a: \"\" }"], &["{ a: \"a┃\" }"], 'a')?;
assert_insert(&["{ a: \"a┃\" }"], &["{ a: \"ab┃\" }"], 'b')?;
@ -688,50 +709,328 @@ pub mod test_ed_update {
assert_insert(&["{ ┃a: \"\" }"], &["{ z┃a: \"\" }"], 'z')?;
assert_insert(&["{ ab┃: \"\" }"], &["{ abc┃: \"\" }"], 'c')?;
assert_insert(&["{ ┃ab: \"\" }"], &["{ z┃ab: \"\" }"], 'z')?;
assert_insert(&["{ camelCase┃: \"hello\" }"], &["{ camelCaseB┃: \"hello\" }"], 'B')?;
assert_insert(&["{ camel┃Case: \"hello\" }"], &["{ camelZ┃Case: \"hello\" }"], 'Z')?;
assert_insert(&["{ ┃camelCase: \"hello\" }"], &["{ z┃camelCase: \"hello\" }"], 'z')?;
assert_insert(
&["{ camelCase┃: \"hello\" }"],
&["{ camelCaseB┃: \"hello\" }"],
'B',
)?;
assert_insert(
&["{ camel┃Case: \"hello\" }"],
&["{ camelZ┃Case: \"hello\" }"],
'Z',
)?;
assert_insert(
&["{ ┃camelCase: \"hello\" }"],
&["{ z┃camelCase: \"hello\" }"],
'z',
)?;
assert_insert_seq(&[""], &["{ camelCase: \"hello┃\" }"], "{camelCase:\"hello")?;
Ok(())
}
#[test]
fn test_nested_record() -> Result<(), String> {
// TODO construct nested record
assert_insert_seq(&["{ a┃ }"], &["{ a: { ┃ } }"], ":{")?;
assert_insert_seq(&["{ abc┃ }"], &["{ abc: { ┃ } }"], ":{")?;
assert_insert_seq(&["{ camelCase┃ }"], &["{ camelCase: { ┃ } }"], ":{")?;
assert_insert_char_seq(&["{ ┃ }"], &["{ a: { ┃ } }"], "a:{")?;
assert_insert_char_seq(&["{ ┃ }"], &["{ abc: { ┃ } }"], "abc:{")?;
assert_insert_char_seq(&["{ ┃ }"], &["{ camelCase: { ┃ } }"], "camelCase:{")?;
assert_insert_seq(&["{ a: { ┃ } }"], &["{ a: { zulu┃ } }"], "zulu")?;
assert_insert_seq(
&["{ abc: { ┃ } }"],
&["{ abc: { camelCase┃ } }"],
"camelCase",
)?;
assert_insert_seq(&["{ camelCase: { ┃ } }"], &["{ camelCase: { z┃ } }"], "z")?;
assert_insert_seq(&["{ a: { zulu┃ } }"], &["{ a: { zulu: ┃ } }"], ":")?;
assert_insert_seq(
&["{ abc: { camelCase┃ } }"],
&["{ abc: { camelCase: ┃ } }"],
":",
)?;
assert_insert_seq(
&["{ camelCase: { z┃ } }"],
&["{ camelCase: { z: ┃ } }"],
":",
)?;
assert_insert_seq(&["{ a┃: { zulu } }"], &["{ a0┃: { zulu } }"], "0")?;
assert_insert_seq(
&["{ ab┃c: { camelCase } }"],
&["{ abz┃c: { camelCase } }"],
"z",
)?;
assert_insert_seq(&["{ ┃camelCase: { z } }"], &["{ x┃camelCase: { z } }"], "x")?;
assert_insert_seq(&["{ a: { zulu┃ } }"], &["{ a: { zulu: \"\" } }"], ":\"")?;
assert_insert_seq(
&["{ abc: { camelCase┃ } }"],
&["{ abc: { camelCase: \"\" } }"],
":\"",
)?;
assert_insert_seq(
&["{ camelCase: { z┃ } }"],
&["{ camelCase: { z: \"\" } }"],
":\"",
)?;
assert_insert_seq(
&["{ a: { zulu: \"\" } }"],
&["{ a: { zulu: \"azula┃\" } }"],
"azula",
)?;
assert_insert_seq(
&["{ a: { zulu: \"az┃a\" } }"],
&["{ a: { zulu: \"azul┃a\" } }"],
"ul",
)?;
assert_insert_seq(&["{ a: { zulu┃ } }"], &["{ a: { zulu: { ┃ } } }"], ":{")?;
assert_insert_seq(
&["{ abc: { camelCase┃ } }"],
&["{ abc: { camelCase: { ┃ } } }"],
":{",
)?;
assert_insert_seq(
&["{ camelCase: { z┃ } }"],
&["{ camelCase: { z: { ┃ } } }"],
":{",
)?;
assert_insert_seq(
&["{ a: { zulu: { ┃ } } }"],
&["{ a: { zulu: { he┃ } } }"],
"he",
)?;
assert_insert_seq(
&["{ a: { ┃zulu: { } } }"],
&["{ a: { x┃zulu: { } } }"],
"x",
)?;
assert_insert_seq(
&["{ a: { z┃ulu: { } } }"],
&["{ a: { z9┃ulu: { } } }"],
"9",
)?;
assert_insert_seq(
&["{ a: { zulu┃: { } } }"],
&["{ a: { zulu7┃: { } } }"],
"7",
)?;
assert_insert_seq(
&["{ a┃: { bcD: { eFgHij: { k15 } } } }"],
&["{ a4┃: { bcD: { eFgHij: { k15 } } } }"],
"4",
)?;
assert_insert_seq(
&["{ ┃a: { bcD: { eFgHij: { k15 } } } }"],
&["{ y┃a: { bcD: { eFgHij: { k15 } } } }"],
"y",
)?;
assert_insert_seq(
&["{ a: { bcD: { eF┃gHij: { k15 } } } }"],
&["{ a: { bcD: { eFxyz┃gHij: { k15 } } } }"],
"xyz",
)?;
assert_insert_seq(
&[""],
&["{ g: { oi: { ng: { d: { e: { e: { p: { camelCase┃ } } } } } } } }"],
"{g:{oi:{ng:{d:{e:{e:{p:{camelCase",
)?;
Ok(())
}
#[test]
fn test_ignore_record() -> Result<(), String> {
assert_insert(&["┃{ }"], &["┃{ }"], 'a')?;
assert_insert(&["┃{ }"], &["┃{ }"], '{')?;
assert_insert(&["┃{ }"], &["┃{ }"], '"')?;
assert_insert(&["┃{ }"], &["┃{ }"], '5')?;
assert_insert_seq_ignore(&["┃{ }"], "a{\"5")?;
assert_insert_seq_ignore(&["{ }┃"], "a{\"5")?;
assert_insert_seq_ignore(&["{┃ }"], "a{\"5")?;
assert_insert_seq_ignore(&["{ ┃}"], "a{\"5")?;
assert_insert(&["{ }┃"], &["{ }┃"], 'a')?;
assert_insert(&["{ }┃"], &["{ }┃"], '{')?;
assert_insert(&["{ }┃"], &["{ }┃"], '"')?;
assert_insert(&["{ }┃"], &["{ }┃"], '5')?;
assert_insert_seq_ignore(&["{ ┃ }"], "{\"5")?;
assert_insert_seq_ignore(&["{ ┃a }"], "{\"5")?;
assert_insert_seq_ignore(&["{ ┃abc }"], "{\"5")?;
assert_insert(&["{┃ }"], &["{┃ }"], 'a')?;
assert_insert(&["{┃ }"], &["{┃ }"], '{')?;
assert_insert(&["{┃ }"], &["{┃ }"], '"')?;
assert_insert(&["{┃ }"], &["{┃ }"], '5')?;
assert_insert_seq_ignore(&["┃{ a }"], "a{\"5")?;
assert_insert_seq_ignore(&["{ a }┃"], "a{\"5")?;
assert_insert_seq_ignore(&["{┃ a }"], "a{\"5")?;
assert_insert_seq_ignore(&["{ a ┃}"], "a{\"5")?;
assert_insert(&["{ ┃}"], &["{ ┃}"], 'a')?;
assert_insert(&["{ ┃}"], &["{ ┃}"], '{')?;
assert_insert(&["{ ┃}"], &["{ ┃}"], '"')?;
assert_insert(&["{ ┃}"], &["{ ┃}"], '5')?;
assert_insert_seq_ignore(&["┃{ a15 }"], "a{\"5")?;
assert_insert_seq_ignore(&["{ a15 }┃"], "a{\"5")?;
assert_insert_seq_ignore(&["{┃ a15 }"], "a{\"5")?;
assert_insert_seq_ignore(&["{ a15 ┃}"], "a{\"5")?;
// TODO non-empty records
assert_insert_seq_ignore(&["┃{ camelCase }"], "a{\"5")?;
assert_insert_seq_ignore(&["{ camelCase }┃"], "a{\"5")?;
assert_insert_seq_ignore(&["{┃ camelCase }"], "a{\"5")?;
assert_insert_seq_ignore(&["{ camelCase ┃}"], "a{\"5")?;
assert_insert_seq_ignore(&["┃{ a: \"\" }"], "a{\"5")?;
assert_insert_seq_ignore(&["{┃ a: \"\" }"], "a{\"5")?;
assert_insert_seq_ignore(&["{ a: ┃\"\" }"], "a{\"5")?;
assert_insert_seq_ignore(&["{ a: \"\"┃ }"], "a{\"5")?;
assert_insert_seq_ignore(&["{ a: \"\" }┃"], "a{\"5")?;
assert_insert_seq_ignore(&["┃{ camelCase: \"\" }"], "a{\"5")?;
assert_insert_seq_ignore(&["{┃ camelCase: \"\" }"], "a{\"5")?;
assert_insert_seq_ignore(&["{ camelCase: ┃\"\" }"], "a{\"5")?;
assert_insert_seq_ignore(&["{ camelCase: \"\"┃ }"], "a{\"5")?;
assert_insert_seq_ignore(&["{ camelCase: \"\" }┃"], "a{\"5")?;
assert_insert_seq_ignore(&["┃{ a: \"z\" }"], "a{\"5")?;
assert_insert_seq_ignore(&["{┃ a: \"z\" }"], "a{\"5")?;
assert_insert_seq_ignore(&["{ a: ┃\"z\" }"], "a{\"5")?;
assert_insert_seq_ignore(&["{ a: \"z\"┃ }"], "a{\"5")?;
assert_insert_seq_ignore(&["{ a: \"z\" }┃"], "a{\"5")?;
assert_insert_seq_ignore(&["┃{ a: \"hello, hello.12345ZXY{}[]-><-\" }"], "a{\"5")?;
assert_insert_seq_ignore(&["{┃ a: \"hello, hello.12345ZXY{}[]-><-\" }"], "a{\"5")?;
assert_insert_seq_ignore(&["{ a: ┃\"hello, hello.12345ZXY{}[]-><-\" }"], "a{\"5")?;
assert_insert_seq_ignore(&["{ a: \"hello, hello.12345ZXY{}[]-><-\"┃ }"], "a{\"5")?;
assert_insert_seq_ignore(&["{ a: \"hello, hello.12345ZXY{}[]-><-\" }┃"], "a{\"5")?;
Ok(())
}
#[test]
fn test_ignore_nested_record() -> Result<(), String> {
assert_insert_seq_ignore(&["{ a: { ┃ } }"], "{\"5")?;
assert_insert_seq_ignore(&["{ a: ┃{ } }"], "{\"5")?;
assert_insert_seq_ignore(&["{ a: {┃ } }"], "{\"5")?;
assert_insert_seq_ignore(&["{ a: { }┃ }"], "{\"5")?;
assert_insert_seq_ignore(&["{ a: { } ┃}"], "{\"5")?;
assert_insert_seq_ignore(&["{ a: { } }┃"], "{\"5")?;
assert_insert_seq_ignore(&["{ a:┃ { } }"], "{\"5")?;
assert_insert_seq_ignore(&["{┃ a: { } }"], "{\"5")?;
assert_insert_seq_ignore(&["┃{ a: { } }"], "{\"5")?;
assert_insert_seq_ignore(&["{ ┃a: { } }"], "1")?;
assert_insert_seq_ignore(&["{ camelCaseB1: { z15a ┃} }"], "{\"5")?;
assert_insert_seq_ignore(&["{ camelCaseB1: {┃ z15a } }"], "{\"5")?;
assert_insert_seq_ignore(&["{ camelCaseB1: ┃{ z15a } }"], "{\"5")?;
assert_insert_seq_ignore(&["{ camelCaseB1: { z15a }┃ }"], "{\"5")?;
assert_insert_seq_ignore(&["{ camelCaseB1: { z15a } ┃}"], "{\"5")?;
assert_insert_seq_ignore(&["{ camelCaseB1: { z15a } }┃"], "{\"5")?;
assert_insert_seq_ignore(&["{ camelCaseB1:┃ { z15a } }"], "{\"5")?;
assert_insert_seq_ignore(&["{┃ camelCaseB1: { z15a } }"], "{\"5")?;
assert_insert_seq_ignore(&["┃{ camelCaseB1: { z15a } }"], "{\"5")?;
assert_insert_seq_ignore(&["{ ┃camelCaseB1: { z15a } }"], "1")?;
assert_insert_seq_ignore(&["{ camelCaseB1: { ┃z15a } }"], "1")?;
assert_insert_seq_ignore(&["{ camelCaseB1: { z15a: \"\"┃ } }"], "{\"5")?;
assert_insert_seq_ignore(&["{ camelCaseB1: { z15a: ┃\"\" } }"], "{\"5")?;
assert_insert_seq_ignore(&["{ camelCaseB1: { z15a:┃ \"\" } }"], "{\"5")?;
assert_insert_seq_ignore(&["{ camelCaseB1: { z15a: \"\" ┃} }"], "{\"5")?;
assert_insert_seq_ignore(&["{ camelCaseB1: {┃ z15a: \"\" } }"], "{\"5")?;
assert_insert_seq_ignore(&["{ camelCaseB1: ┃{ z15a: \"\" } }"], "{\"5")?;
assert_insert_seq_ignore(&["{ camelCaseB1: { z15a: \"\" }┃ }"], "{\"5")?;
assert_insert_seq_ignore(&["{ camelCaseB1: { z15a: \"\" } ┃}"], "{\"5")?;
assert_insert_seq_ignore(&["{ camelCaseB1: { z15a: \"\" } }┃"], "{\"5")?;
assert_insert_seq_ignore(&["{ camelCaseB1:┃ { z15a: \"\" } }"], "{\"5")?;
assert_insert_seq_ignore(&["{┃ camelCaseB1: { z15a: \"\" } }"], "{\"5")?;
assert_insert_seq_ignore(&["┃{ camelCaseB1: { z15a: \"\" } }"], "{\"5")?;
assert_insert_seq_ignore(&["{ ┃camelCaseB1: { z15a: \"\" } }"], "1")?;
assert_insert_seq_ignore(&["{ camelCaseB1: { ┃z15a: \"\" } }"], "1")?;
assert_insert_seq_ignore(
&["{ camelCaseB1: { z15a: \"hello, hello.12345ZXY{}[]-><-\"┃ } }"],
"{\"5",
)?;
assert_insert_seq_ignore(
&["{ camelCaseB1: { z15a: ┃\"hello, hello.12345ZXY{}[]-><-\" } }"],
"{\"5",
)?;
assert_insert_seq_ignore(
&["{ camelCaseB1: { z15a:┃ \"hello, hello.12345ZXY{}[]-><-\" } }"],
"{\"5",
)?;
assert_insert_seq_ignore(
&["{ camelCaseB1: { z15a: \"hello, hello.12345ZXY{}[]-><-\" ┃} }"],
"{\"5",
)?;
assert_insert_seq_ignore(
&["{ camelCaseB1: {┃ z15a: \"hello, hello.12345ZXY{}[]-><-\" } }"],
"{\"5",
)?;
assert_insert_seq_ignore(
&["{ camelCaseB1: ┃{ z15a: \"hello, hello.12345ZXY{}[]-><-\" } }"],
"{\"5",
)?;
assert_insert_seq_ignore(
&["{ camelCaseB1: { z15a: \"hello, hello.12345ZXY{}[]-><-\" }┃ }"],
"{\"5",
)?;
assert_insert_seq_ignore(
&["{ camelCaseB1: { z15a: \"hello, hello.12345ZXY{}[]-><-\" } ┃}"],
"{\"5",
)?;
assert_insert_seq_ignore(
&["{ camelCaseB1: { z15a: \"hello, hello.12345ZXY{}[]-><-\" } }┃"],
"{\"5",
)?;
assert_insert_seq_ignore(
&["{ camelCaseB1:┃ { z15a: \"hello, hello.12345ZXY{}[]-><-\" } }"],
"{\"5",
)?;
assert_insert_seq_ignore(
&["{┃ camelCaseB1: { z15a: \"hello, hello.12345ZXY{}[]-><-\" } }"],
"{\"5",
)?;
assert_insert_seq_ignore(
&["┃{ camelCaseB1: { z15a: \"hello, hello.12345ZXY{}[]-><-\" } }"],
"{\"5",
)?;
assert_insert_seq_ignore(
&["{ ┃camelCaseB1: { z15a: \"hello, hello.12345ZXY{}[]-><-\" } }"],
"1",
)?;
assert_insert_seq_ignore(
&["{ camelCaseB1: { ┃z15a: \"hello, hello.12345ZXY{}[]-><-\" } }"],
"1",
)?;
assert_insert_seq_ignore(
&["{ g: { oi: { ng: { d: { e: { e: { p: { camelCase ┃} } } } } } } }"],
"{\"5",
)?;
assert_insert_seq_ignore(
&["{ g: { oi: { ng: { d: { e: { e: { p: { camelCase } ┃} } } } } } }"],
"{\"5",
)?;
assert_insert_seq_ignore(
&["{ g: { oi: { ng: { d: { e: { e: { p: { camelCase } } } } } } } }┃"],
"{\"5",
)?;
assert_insert_seq_ignore(
&["{ g: { oi: { ng: { d: { e: { e: { p: { camelCase } } } } } ┃} } }"],
"{\"5",
)?;
assert_insert_seq_ignore(
&["{ g: { oi: { ng: { d: { e: {┃ e: { p: { camelCase } } } } } } } }"],
"{\"5",
)?;
assert_insert_seq_ignore(
&["{ g: { oi: { ng: { d: { e: { e:┃ { p: { camelCase } } } } } } } }"],
"{\"5",
)?;
assert_insert_seq_ignore(
&["{┃ g: { oi: { ng: { d: { e: { e: { p: { camelCase } } } } } } } }"],
"{\"5",
)?;
assert_insert_seq_ignore(
&["┃{ g: { oi: { ng: { d: { e: { e: { p: { camelCase } } } } } } } }"],
"{\"5",
)?;
assert_insert_seq_ignore(
&["{ ┃g: { oi: { ng: { d: { e: { e: { p: { camelCase } } } } } } } }"],
"2",
)?;
Ok(())
}
}

View File

@ -1,4 +1,3 @@
use crate::lang::ast::RecordField;
use crate::editor::ed_error::EdResult;
use crate::editor::ed_error::MissingParent;
use crate::editor::ed_error::RecordWithoutFields;
@ -13,6 +12,7 @@ use crate::editor::slow_pool::MarkNodeId;
use crate::editor::syntax_highlight::HighlightStyle;
use crate::editor::util::index_of;
use crate::lang::ast::Expr2;
use crate::lang::ast::RecordField;
use crate::lang::pool::{NodeId, PoolStr, PoolVec};
use crate::ui::text::text_pos::TextPos;
use snafu::OptionExt;
@ -197,12 +197,11 @@ pub fn update_record_colon(
.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;
@ -277,6 +276,17 @@ pub fn update_record_field(
let node_caret_offset = ed_model
.grid_node_map
.get_offset_to_node_id(old_caret_pos, curr_mark_node_id)?;
if node_caret_offset == 0 {
let first_char_opt = new_input.chars().next();
let first_char_is_num = first_char_opt.unwrap_or('0').is_ascii_digit();
// variable name can't start with number
if first_char_is_num {
return Ok(InputOutcome::Ignored);
}
}
content_str_mut.insert_str(node_caret_offset, new_input);
// update caret
@ -296,7 +306,9 @@ pub fn update_record_field(
.next()
.with_context(|| RecordWithoutFields {})?;
let field_pool_str = first_field.get_record_field_pool_str().as_str(ed_model.module.env.pool);
let field_pool_str = first_field
.get_record_field_pool_str()
.as_str(ed_model.module.env.pool);
let mut new_field_name = String::new();
@ -321,23 +333,22 @@ pub fn update_record_field(
match first_field_b {
RecordField::InvalidLabelOnly(_, _) => {
// TODO check if label is now valid
},
// TODO check if label is now valid. If it is, return LabelOnly
}
RecordField::LabelOnly(_, _, _symbol) => {
// TODO check if symbol is still valid
},
// TODO check if symbol is still valid. If not, return InvalidLabelOnly
}
RecordField::LabeledValue(_, _, field_val_id_ref) => {
let field_val_id = *field_val_id_ref;
let sub_expr2 = ed_model.module.env.pool.get(field_val_id);
if let Expr2::InvalidLookup(_) = sub_expr2 {
ed_model
.module
.env
.pool
.set(field_val_id, Expr2::InvalidLookup(new_field_pool_str));
.module
.env
.pool
.set(field_val_id, Expr2::InvalidLookup(new_field_pool_str));
}
}
}

View File

@ -58,7 +58,7 @@ pub enum FloatVal {
pub enum RecordField {
InvalidLabelOnly(PoolStr, Variable),
LabelOnly(PoolStr, Variable, Symbol),
LabeledValue(PoolStr, Variable, NodeId<Expr2>)
LabeledValue(PoolStr, Variable, NodeId<Expr2>),
}
#[test]
@ -166,7 +166,7 @@ pub enum Expr2 {
},
// Product Types
Record {
record_var: Variable, // 4B
record_var: Variable, // 4B
fields: PoolVec<RecordField>, // TODO ??B
},
/// Empty record constant
@ -190,10 +190,10 @@ pub enum Expr2 {
field_var: Variable, // 4B
},
Update {
symbol: Symbol, // 8B
symbol: Symbol, // 8B
updates: PoolVec<RecordField>, // 8B
record_var: Variable, // 4B
ext_var: Variable, // 4B
record_var: Variable, // 4B
ext_var: Variable, // 4B
},
// Sum Types
@ -311,7 +311,6 @@ pub type ExprId = NodeId<Expr2>;
use RecordField::*;
impl RecordField {
pub fn get_record_field_var(&self) -> &Variable {
match self {
InvalidLabelOnly(_, var) => var,
@ -319,7 +318,7 @@ impl RecordField {
LabeledValue(_, var, _) => var,
}
}
pub fn get_record_field_pool_str(&self) -> &PoolStr {
match self {
InvalidLabelOnly(pool_str, _) => pool_str,
@ -327,7 +326,7 @@ impl RecordField {
LabeledValue(pool_str, _, _) => pool_str,
}
}
pub fn get_record_field_pool_str_mut(&mut self) -> &mut PoolStr {
match self {
InvalidLabelOnly(pool_str, _) => pool_str,
@ -335,7 +334,7 @@ impl RecordField {
LabeledValue(pool_str, _, _) => pool_str,
}
}
pub fn get_record_field_val_node_id(&self) -> Option<NodeId<Expr2>> {
match self {
InvalidLabelOnly(_, _) => None,
@ -409,7 +408,7 @@ fn expr2_to_string_helper(
pool_str.as_str(pool),
var,
));
},
}
RecordField::LabelOnly(pool_str, var, symbol) => {
out_string.push_str(&format!(
"{}({}, Var({:?}), Symbol({:?})",
@ -418,7 +417,7 @@ fn expr2_to_string_helper(
var,
symbol
));
},
}
RecordField::LabeledValue(pool_str, var, val_node_id) => {
out_string.push_str(&format!(
"{}({}, Var({:?}), Expr2(\n",

View File

@ -1,6 +1,7 @@
#![allow(clippy::all)]
#![allow(dead_code)]
#![allow(unused_imports)]
use crate::lang::ast::expr2_to_string;
use crate::lang::ast::RecordField;
use crate::lang::ast::{ClosureExtra, Expr2, ExprId, FloatVal, IntStyle, IntVal, WhenBranch};
use crate::lang::def::References;
@ -1014,32 +1015,57 @@ enum CanonicalizeRecordProblem {
record_region: Region,
},
}
enum FieldVar {
VarAndExprId(Variable, ExprId),
OnlyVar(Variable),
}
fn canonicalize_fields<'a>(
env: &mut Env<'a>,
scope: &mut Scope,
fields: &'a [Located<roc_parse::ast::AssignedField<'a, roc_parse::ast::Expr<'a>>>],
) -> Result<(PoolVec<RecordField>, Output), CanonicalizeRecordProblem> {
let mut can_fields: MutMap<&'a str, (Variable, ExprId)> = MutMap::default();
let mut can_fields: MutMap<&'a str, FieldVar> = MutMap::default();
let mut output = Output::default();
for loc_field in fields.iter() {
match canonicalize_field(env, scope, &loc_field.value) {
Ok((label, field_expr, field_out, field_var)) => {
let expr_id = env.pool.add(field_expr);
let replaced = can_fields.insert(label, (field_var, expr_id));
Ok(can_field) => {
match can_field {
CanonicalField::LabelAndValue {
label,
value_expr,
value_output,
var,
} => {
let expr_id = env.pool.add(value_expr);
if let Some(_old) = replaced {
// env.problems.push(Problem::DuplicateRecordFieldValue {
// field_name: label,
// field_region: loc_field.region,
// record_region: region,
// replaced_region: old.region,
// });
todo!()
let replaced =
can_fields.insert(label, FieldVar::VarAndExprId(var, expr_id));
if let Some(_old) = replaced {
// env.problems.push(Problem::DuplicateRecordFieldValue {
// field_name: label,
// field_region: loc_field.region,
// record_region: region,
// replaced_region: old.region,
// });
todo!()
}
output.references.union_mut(value_output.references);
}
CanonicalField::InvalidLabelOnly { label, var } => {
let replaced = can_fields.insert(label, FieldVar::OnlyVar(var));
if let Some(_old) = replaced {
todo!()
}
}
}
output.references.union_mut(field_out.references);
}
Err(CanonicalizeFieldProblem::InvalidOptionalValue {
field_name: _,
field_region: _,
@ -1061,10 +1087,17 @@ fn canonicalize_fields<'a>(
let pool_vec = PoolVec::with_capacity(can_fields.len() as u32, env.pool);
for (node_id, (string, (var, expr_id))) in pool_vec.iter_node_ids().zip(can_fields.into_iter())
{
for (node_id, (string, field_var)) in pool_vec.iter_node_ids().zip(can_fields.into_iter()) {
let name = PoolStr::new(string, env.pool);
env.pool[node_id] = RecordField::LabeledValue(name, var, expr_id);
match field_var {
FieldVar::VarAndExprId(var, expr_id) => {
env.pool[node_id] = RecordField::LabeledValue(name, var, expr_id);
}
FieldVar::OnlyVar(var) => {
env.pool[node_id] = RecordField::InvalidLabelOnly(name, var);
} // TODO RecordField::LabelOnly
}
}
Ok((pool_vec, output))
@ -1076,11 +1109,23 @@ enum CanonicalizeFieldProblem {
field_region: Region,
},
}
enum CanonicalField<'a> {
LabelAndValue {
label: &'a str,
value_expr: Expr2,
value_output: Output,
var: Variable,
},
InvalidLabelOnly {
label: &'a str,
var: Variable,
}, // TODO make ValidLabelOnly
}
fn canonicalize_field<'a>(
env: &mut Env<'a>,
scope: &mut Scope,
field: &'a roc_parse::ast::AssignedField<'a, roc_parse::ast::Expr<'a>>,
) -> Result<(&'a str, Expr2, Output, Variable), CanonicalizeFieldProblem> {
) -> Result<CanonicalField<'a>, CanonicalizeFieldProblem> {
use roc_parse::ast::AssignedField::*;
match field {
@ -1089,7 +1134,12 @@ fn canonicalize_field<'a>(
let field_var = env.var_store.fresh();
let (loc_can_expr, output) = to_expr2(env, scope, &loc_expr.value, loc_expr.region);
Ok((label.value, loc_can_expr, output, field_var))
Ok(CanonicalField::LabelAndValue {
label: label.value,
value_expr: loc_can_expr,
value_output: output,
var: field_var,
})
}
OptionalValue(label, _, loc_expr) => Err(CanonicalizeFieldProblem::InvalidOptionalValue {
@ -1098,8 +1148,13 @@ fn canonicalize_field<'a>(
}),
// A label with no value, e.g. `{ name }` (this is sugar for { name: name })
LabelOnly(_) => {
panic!("Somehow a LabelOnly record field was not desugared!");
LabelOnly(label) => {
let field_var = env.var_store.fresh();
// TODO return ValidLabel if label points to in scope variable
Ok(CanonicalField::InvalidLabelOnly {
label: label.value,
var: field_var,
})
}
SpaceBefore(sub_field, _) | SpaceAfter(sub_field, _) => {

View File

@ -423,8 +423,8 @@ impl fmt::Debug for BigTextArea {
#[cfg(test)]
pub mod test_big_sel_text {
use crate::ui::text::caret_w_select::test_caret_w_select::convert_selection_to_dsl;
use crate::ui::text::caret_w_select::test_caret_w_select::convert_dsl_to_selection;
use crate::ui::text::caret_w_select::test_caret_w_select::convert_selection_to_dsl;
use crate::ui::text::{
big_text_area::from_str,
big_text_area::BigTextArea,
@ -434,7 +434,7 @@ pub mod test_big_sel_text {
use crate::ui::ui_error::{OutOfBounds, UIResult};
use crate::window::keyboard_input::{no_mods, Modifiers};
use snafu::OptionExt;
use std::{slice::SliceIndex};
use std::slice::SliceIndex;
fn shift_pressed() -> Modifiers {
Modifiers {
@ -508,8 +508,7 @@ pub mod test_big_sel_text {
}
let actual_lines = all_lines_vec(&big_text);
let dsl_slice =
convert_selection_to_dsl(big_text.caret_w_select, actual_lines).unwrap();
let dsl_slice = convert_selection_to_dsl(big_text.caret_w_select, actual_lines).unwrap();
assert_eq!(dsl_slice, expected_post_lines_str);
Ok(())
@ -632,8 +631,7 @@ pub mod test_big_sel_text {
big_text.select_all().unwrap();
let big_text_lines = all_lines_vec(&big_text);
let post_lines_str =
convert_selection_to_dsl(big_text.caret_w_select, big_text_lines)?;
let post_lines_str = convert_selection_to_dsl(big_text.caret_w_select, big_text_lines)?;
assert_eq!(post_lines_str, expected_post_lines_str);

View File

@ -114,16 +114,16 @@ pub fn make_caret_rect(
#[cfg(test)]
pub mod test_caret_w_select {
use crate::ui::ui_error::OutOfBounds;
use crate::ui::util::slice_get;
use crate::ui::ui_error::UIResult;
use crate::ui::text::caret_w_select::CaretWSelect;
use crate::ui::text::selection::validate_selection;
use crate::ui::text::text_pos::TextPos;
use crate::ui::text::caret_w_select::CaretWSelect;
use crate::ui::ui_error::OutOfBounds;
use crate::ui::ui_error::UIResult;
use crate::ui::util::slice_get;
use core::cmp::Ordering;
use pest::Parser;
use std::{collections::HashMap, slice::SliceIndex};
use snafu::OptionExt;
use std::{collections::HashMap, slice::SliceIndex};
#[derive(Parser)]
#[grammar = "../tests/selection.pest"]
@ -277,7 +277,7 @@ pub mod test_caret_w_select {
fn insert_at_pos(lines: &mut [String], pos: TextPos, insert_char: char) -> UIResult<()> {
let line = get_mut_res(pos.line, lines)?;
let mut chars: Vec<char> = line.chars().collect();
chars.insert(pos.column, insert_char);