diff --git a/editor/src/editor/mvc/ed_update.rs b/editor/src/editor/mvc/ed_update.rs index f1ff2d0ac9..658db45b68 100644 --- a/editor/src/editor/mvc/ed_update.rs +++ b/editor/src/editor/mvc/ed_update.rs @@ -715,8 +715,10 @@ pub mod test_ed_update { use crate::editor::mvc::ed_update::handle_new_char; use crate::editor::mvc::ed_update::EdResult; use crate::ui::ui_error::UIResult; + use crate::window::keyboard_input::test_modifiers::ctrl_shift; use bumpalo::collections::String as BumpString; use bumpalo::Bump; + use winit::event::VirtualKeyCode::*; fn ed_res_to_res(ed_res: EdResult) -> Result { match ed_res { @@ -1254,6 +1256,216 @@ pub mod test_ed_update { Ok(()) } + // Create ed_model from pre_lines DSL, do ctrl+shift+up as many times as repeat. + // check if modified ed_model has expected string representation of code, caret position and active selection. + pub fn assert_ctrl_shift_up_repeat( + pre_lines: &[&str], + expected_post_lines: &[&str], + repeats: usize, + ) -> Result<(), String> { + let test_arena = Bump::new(); + let code_str = BumpString::from_str_in(&pre_lines.join("").replace("┃", ""), &test_arena); + + let mut model_refs = init_model_refs(); + + let mut ed_model = ed_model_from_dsl(&code_str, pre_lines, &mut model_refs)?; + + for _ in 0..repeats { + ed_model.ed_handle_key_down(&ctrl_shift(), Up)?; + } + + let post_lines = ui_res_to_res(ed_model_to_dsl(&ed_model))?; + + assert_eq!(post_lines, expected_post_lines); + + Ok(()) + } + + pub fn assert_ctrl_shift_up( + pre_lines: &[&str], + expected_post_lines: &[&str], + ) -> Result<(), String> { + assert_ctrl_shift_up_repeat(pre_lines, expected_post_lines, 1) + } + + #[test] + fn test_ctrl_shift_up_blank() -> Result<(), String> { + // Blank is auto-inserted + assert_ctrl_shift_up(&["┃"], &["┃❮ ❯"])?; + assert_ctrl_shift_up_repeat(&["┃"], &["┃❮ ❯"], 4)?; + + Ok(()) + } + + #[test] + fn test_ctrl_shift_up_string() -> Result<(), String> { + assert_ctrl_shift_up(&["\"┃\""], &["┃❮\"\"❯"])?; + assert_ctrl_shift_up(&["┃\"\""], &["┃❮\"\"❯"])?; + assert_ctrl_shift_up(&["\"┃0\""], &["┃❮\"0\"❯"])?; + assert_ctrl_shift_up(&["\"0┃\""], &["┃❮\"0\"❯"])?; + assert_ctrl_shift_up(&["\"abc┃\""], &["┃❮\"abc\"❯"])?; + assert_ctrl_shift_up(&["\"ab┃c\""], &["┃❮\"abc\"❯"])?; + assert_ctrl_shift_up(&["\"┃abc\""], &["┃❮\"abc\"❯"])?; + assert_ctrl_shift_up(&["┃\"abc\""], &["┃❮\"abc\"❯"])?; + assert_ctrl_shift_up_repeat(&["\"abc┃\""], &["┃❮\"abc\"❯"], 3)?; + assert_ctrl_shift_up( + &["\"hello, hello.12345ZXY{}[]-><-┃\""], + &["┃❮\"hello, hello.12345ZXY{}[]-><-\"❯"], + )?; + + assert_ctrl_shift_up(&["\"\"┃"], &["\"\"┃"])?; + assert_ctrl_shift_up(&["\"abc\"┃"], &["\"abc\"┃"])?; + + Ok(()) + } + + #[test] + fn test_ctrl_shift_up_record() -> Result<(), String> { + assert_ctrl_shift_up(&["{ ┃ }"], &["┃❮{ }❯"])?; + assert_ctrl_shift_up(&["{┃ }"], &["┃❮{ }❯"])?; + assert_ctrl_shift_up(&["┃{ }"], &["┃❮{ }❯"])?; + assert_ctrl_shift_up(&["{ ┃}"], &["┃❮{ }❯"])?; + assert_ctrl_shift_up_repeat(&["{ ┃ }"], &["┃❮{ }❯"], 4)?; + assert_ctrl_shift_up(&["{ }┃"], &["{ }┃"])?; + + assert_ctrl_shift_up(&["{ pear┃ }"], &["┃❮{ pear }❯"])?; + assert_ctrl_shift_up(&["{ pea┃r }"], &["┃❮{ pear }❯"])?; + assert_ctrl_shift_up(&["{ p┃ear }"], &["┃❮{ pear }❯"])?; + assert_ctrl_shift_up(&["{ ┃pear }"], &["┃❮{ pear }❯"])?; + assert_ctrl_shift_up(&["{┃ pear }"], &["┃❮{ pear }❯"])?; + assert_ctrl_shift_up(&["┃{ pear }"], &["┃❮{ pear }❯"])?; + assert_ctrl_shift_up(&["{ pear ┃}"], &["┃❮{ pear }❯"])?; + assert_ctrl_shift_up_repeat(&["{ pear┃ }"], &["┃❮{ pear }❯"], 3)?; + assert_ctrl_shift_up(&["{ pear }┃"], &["{ pear }┃"])?; + + assert_ctrl_shift_up(&["{ camelCase123┃ }"], &["┃❮{ camelCase123 }❯"])?; + + assert_ctrl_shift_up(&["{ a: \"┃\" }"], &["{ a: ┃❮\"\"❯ }"])?; + assert_ctrl_shift_up(&["{ a: ┃\"\" }"], &["{ a: ┃❮\"\"❯ }"])?; + assert_ctrl_shift_up(&["{ a: \"\"┃ }"], &["┃❮{ a: \"\" }❯"])?; + assert_ctrl_shift_up(&["{ a: \"\" ┃}"], &["┃❮{ a: \"\" }❯"])?; + assert_ctrl_shift_up_repeat(&["{ a: \"\" ┃}"], &["┃❮{ a: \"\" }❯"], 3)?; + assert_ctrl_shift_up(&["{ a: \"\" }┃"], &["{ a: \"\" }┃"])?; + assert_ctrl_shift_up(&["{ a:┃ \"\" }"], &["┃❮{ a: \"\" }❯"])?; + assert_ctrl_shift_up(&["{ a┃: \"\" }"], &["┃❮{ a: \"\" }❯"])?; + assert_ctrl_shift_up(&["{ ┃a: \"\" }"], &["┃❮{ a: \"\" }❯"])?; + assert_ctrl_shift_up(&["{┃ a: \"\" }"], &["┃❮{ a: \"\" }❯"])?; + assert_ctrl_shift_up(&["┃{ a: \"\" }"], &["┃❮{ a: \"\" }❯"])?; + assert_ctrl_shift_up_repeat(&["{ a: \"┃\" }"], &["┃❮{ a: \"\" }❯"], 2)?; + assert_ctrl_shift_up_repeat(&["{ a: \"┃\" }"], &["┃❮{ a: \"\" }❯"], 4)?; + + assert_ctrl_shift_up(&["{ abc: \"de┃\" }"], &["{ abc: ┃❮\"de\"❯ }"])?; + assert_ctrl_shift_up(&["{ abc: \"d┃e\" }"], &["{ abc: ┃❮\"de\"❯ }"])?; + assert_ctrl_shift_up(&["{ abc: \"┃de\" }"], &["{ abc: ┃❮\"de\"❯ }"])?; + assert_ctrl_shift_up(&["{ abc: ┃\"de\" }"], &["{ abc: ┃❮\"de\"❯ }"])?; + assert_ctrl_shift_up(&["{ abc: \"de\"┃ }"], &["┃❮{ abc: \"de\" }❯"])?; + assert_ctrl_shift_up_repeat(&["{ abc: \"d┃e\" }"], &["┃❮{ abc: \"de\" }❯"], 2)?; + assert_ctrl_shift_up_repeat(&["{ abc: \"d┃e\" }"], &["┃❮{ abc: \"de\" }❯"], 3)?; + + assert_ctrl_shift_up( + &["{ camelCase123: \"hello, hello.12┃345ZXY{}[]-><-\" }"], + &["{ camelCase123: ┃❮\"hello, hello.12345ZXY{}[]-><-\"❯ }"], + )?; + assert_ctrl_shift_up( + &["{ camel┃Case123: \"hello, hello.12345ZXY{}[]-><-\" }"], + &["┃❮{ camelCase123: \"hello, hello.12345ZXY{}[]-><-\" }❯"], + )?; + assert_ctrl_shift_up_repeat( + &["{ camelCase123: \"hello, hello┃.12345ZXY{}[]-><-\" }"], + &["┃❮{ camelCase123: \"hello, hello.12345ZXY{}[]-><-\" }❯"], + 2, + )?; + + Ok(()) + } + + #[test] + fn test_ctrl_shift_up_nested_record() -> Result<(), String> { + assert_ctrl_shift_up(&["{ abc: { ┃ } }"], &["{ abc: ┃❮{ }❯ }"])?; + assert_ctrl_shift_up(&["{ abc: {┃ } }"], &["{ abc: ┃❮{ }❯ }"])?; + assert_ctrl_shift_up(&["{ abc: ┃{ } }"], &["{ abc: ┃❮{ }❯ }"])?; + assert_ctrl_shift_up(&["{ abc: { ┃} }"], &["{ abc: ┃❮{ }❯ }"])?; + assert_ctrl_shift_up(&["{ abc: { }┃ }"], &["┃❮{ abc: { } }❯"])?; + + assert_ctrl_shift_up(&["{ abc: { ┃d } }"], &["{ abc: ┃❮{ d }❯ }"])?; + assert_ctrl_shift_up(&["{ abc: {┃ d } }"], &["{ abc: ┃❮{ d }❯ }"])?; + assert_ctrl_shift_up(&["{ abc: ┃{ d } }"], &["{ abc: ┃❮{ d }❯ }"])?; + assert_ctrl_shift_up(&["{ abc: { d ┃} }"], &["{ abc: ┃❮{ d }❯ }"])?; + assert_ctrl_shift_up(&["{ abc: { d┃e } }"], &["{ abc: ┃❮{ de }❯ }"])?; + assert_ctrl_shift_up(&["{ abc: { d }┃ }"], &["┃❮{ abc: { d } }❯"])?; + assert_ctrl_shift_up(&["┃{ abc: { d } }"], &["┃❮{ abc: { d } }❯"])?; + + assert_ctrl_shift_up(&["{ abc: { de: { ┃ } } }"], &["{ abc: { de: ┃❮{ }❯ } }"])?; + assert_ctrl_shift_up(&["{ abc: { de: ┃{ } } }"], &["{ abc: { de: ┃❮{ }❯ } }"])?; + assert_ctrl_shift_up(&["{ abc: { de: { }┃ } }"], &["{ abc: ┃❮{ de: { } }❯ }"])?; + + assert_ctrl_shift_up(&["{ abc: { de: \"┃\" } }"], &["{ abc: { de: ┃❮\"\"❯ } }"])?; + assert_ctrl_shift_up(&["{ abc: { de: ┃\"\" } }"], &["{ abc: { de: ┃❮\"\"❯ } }"])?; + assert_ctrl_shift_up(&["{ abc: { de: \"\"┃ } }"], &["{ abc: ┃❮{ de: \"\" }❯ }"])?; + assert_ctrl_shift_up( + &["{ abc: { de: \"f g┃\" } }"], + &["{ abc: { de: ┃❮\"f g\"❯ } }"], + )?; + assert_ctrl_shift_up( + &["{ abc: { de┃: \"f g\" } }"], + &["{ abc: ┃❮{ de: \"f g\" }❯ }"], + )?; + assert_ctrl_shift_up( + &["{ abc: {┃ de: \"f g\" } }"], + &["{ abc: ┃❮{ de: \"f g\" }❯ }"], + )?; + assert_ctrl_shift_up( + &["{ abc: { de: \"f g\" ┃} }"], + &["{ abc: ┃❮{ de: \"f g\" }❯ }"], + )?; + assert_ctrl_shift_up( + &["{ abc: { de: \"f g\" }┃ }"], + &["┃❮{ abc: { de: \"f g\" } }❯"], + )?; + assert_ctrl_shift_up( + &["┃{ abc: { de: \"f g\" } }"], + &["┃❮{ abc: { de: \"f g\" } }❯"], + )?; + assert_ctrl_shift_up( + &["{ abc: { de: \"f g\" } }┃"], + &["{ abc: { de: \"f g\" } }┃"], + )?; + + assert_ctrl_shift_up_repeat( + &["{ abc: { de: \"f g┃\" } }"], + &["{ abc: ┃❮{ de: \"f g\" }❯ }"], + 2, + )?; + assert_ctrl_shift_up_repeat( + &["{ abc: { de: ┃\"f g\" } }"], + &["┃❮{ abc: { de: \"f g\" } }❯"], + 3, + )?; + assert_ctrl_shift_up_repeat( + &["{ abc: { de: ┃\"f g\" } }"], + &["┃❮{ abc: { de: \"f g\" } }❯"], + 4, + )?; + + assert_ctrl_shift_up_repeat( + &["{ g: { oi: { ng: { d: { e: { e: { p: { camelCase┃ } } } } } } } }"], + &["{ g: { oi: { ng: { d: ┃❮{ e: { e: { p: { camelCase } } } }❯ } } } }"], + 4, + )?; + assert_ctrl_shift_up_repeat( + &["{ g: { oi: { ng: { d: { e: { e: { p: { camelCase┃ } } } } } } } }"], + &["{ g: ┃❮{ oi: { ng: { d: { e: { e: { p: { camelCase } } } } } } }❯ }"], + 7, + )?; + assert_ctrl_shift_up_repeat( + &["{ g: { oi: { ng: { d: { e: { e: { p: { camelCase┃ } } } } } } } }"], + &["┃❮{ g: { oi: { ng: { d: { e: { e: { p: { camelCase } } } } } } } }❯"], + 9, + )?; + + Ok(()) + } + // Create ed_model from pre_lines DSL, do handle_new_char() with new_char_seq, select current Expr2, // check if generated tooltip matches expected_tooltip. pub fn assert_type_tooltip_seq( diff --git a/editor/src/window/keyboard_input.rs b/editor/src/window/keyboard_input.rs index 33b2ed5f28..0a7e559e86 100644 --- a/editor/src/window/keyboard_input.rs +++ b/editor/src/window/keyboard_input.rs @@ -34,3 +34,17 @@ pub fn from_winit(winit_mods: &winit::event::ModifiersState) -> Modifiers { logo: winit_mods.logo(), } } + +#[cfg(test)] +pub mod test_modifiers { + use crate::window::keyboard_input::Modifiers; + + pub fn ctrl_shift() -> Modifiers { + Modifiers { + shift: true, + ctrl: true, + alt: false, + logo: false, + } + } +}