From ca5e2d0285c507af04fe2f128a40799a3f46de24 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Wed, 10 Feb 2021 18:58:56 +0100 Subject: [PATCH 1/2] Ctrl+A to select all --- editor/src/keyboard_input.rs | 9 ++++- editor/src/mvc/app_update.rs | 66 ++++++++++++++++++++++++++++++++++-- editor/src/mvc/ed_update.rs | 3 +- editor/src/text_buffer.rs | 18 ++++++++++ 4 files changed, 92 insertions(+), 4 deletions(-) diff --git a/editor/src/keyboard_input.rs b/editor/src/keyboard_input.rs index 3478840a56..4254d9ac52 100644 --- a/editor/src/keyboard_input.rs +++ b/editor/src/keyboard_input.rs @@ -1,6 +1,8 @@ use crate::error::EdResult; use crate::mvc::app_model::AppModel; -use crate::mvc::app_update::{handle_copy, handle_paste, pass_keydown_to_focused}; +use crate::mvc::app_update::{ + handle_copy, handle_paste, handle_select_all, pass_keydown_to_focused, +}; use winit::event::VirtualKeyCode::*; use winit::event::{ElementState, ModifiersState, VirtualKeyCode}; @@ -27,6 +29,11 @@ pub fn handle_keydown( todo!("cut"); } + A => { + if modifiers.ctrl() { + handle_select_all(app_model) + } + } C => { if modifiers.ctrl() { handle_copy(app_model)? diff --git a/editor/src/mvc/app_update.rs b/editor/src/mvc/app_update.rs index 46a9c84647..36edf17e9c 100644 --- a/editor/src/mvc/app_update.rs +++ b/editor/src/mvc/app_update.rs @@ -1,6 +1,6 @@ use super::app_model; use super::app_model::AppModel; -use super::ed_model::Position; +use super::ed_model::{Position, RawSelection}; use super::ed_update; use crate::error::EdResult; use winit::event::{ModifiersState, VirtualKeyCode}; @@ -76,6 +76,21 @@ pub fn handle_paste(app_model: &mut AppModel) -> EdResult<()> { Ok(()) } +pub fn handle_select_all(app_model: &mut AppModel) { + if let Some(ref mut ed_model) = app_model.ed_model_opt { + if ed_model.has_focus && ed_model.text_buf.nr_of_chars() > 0 { + let last_pos = ed_model.text_buf.last_position(); + + ed_model.selection_opt = Some(RawSelection { + start_pos: Position { line: 0, column: 0 }, + end_pos: last_pos, + }); + + ed_model.caret_pos = last_pos; + } + } +} + pub fn pass_keydown_to_focused( modifiers: &ModifiersState, virtual_keycode: VirtualKeyCode, @@ -102,7 +117,7 @@ pub fn handle_new_char(received_char: &char, app_model: &mut AppModel) -> EdResu pub mod test_app_update { use crate::mvc::app_model; use crate::mvc::app_model::{AppModel, Clipboard}; - use crate::mvc::app_update::{handle_copy, handle_paste}; + use crate::mvc::app_update::{handle_copy, handle_paste, handle_select_all}; use crate::mvc::ed_model::{EdModel, Position, RawSelection}; use crate::mvc::ed_update::test_ed_update::gen_caret_text_buf; use crate::selection::test_selection::{all_lines_vec, convert_selection_to_dsl}; @@ -205,4 +220,51 @@ pub mod test_app_update { Ok(()) } + + fn assert_select_all( + pre_lines_str: &[&str], + expected_post_lines_str: &[&str], + ) -> Result<(), String> { + let (caret_pos, selection_opt, pre_text_buf) = gen_caret_text_buf(pre_lines_str)?; + + let mut app_model = mock_app_model(pre_text_buf, caret_pos, selection_opt, None); + + handle_select_all(&mut app_model); + + let ed_model = app_model.ed_model_opt.unwrap(); + let mut text_buf_lines = all_lines_vec(&ed_model.text_buf); + let post_lines_str = convert_selection_to_dsl( + ed_model.selection_opt, + ed_model.caret_pos, + &mut text_buf_lines, + )?; + + assert_eq!(post_lines_str, expected_post_lines_str); + + Ok(()) + } + + #[test] + fn select_all() -> Result<(), String> { + assert_select_all(&["|"], &["|"])?; + assert_select_all(&["|a"], &["[a]|"])?; + assert_select_all(&["a|"], &["[a]|"])?; + assert_select_all(&["abc d|ef ghi"], &["[abc def ghi]|"])?; + assert_select_all(&["[a]|"], &["[a]|"])?; + assert_select_all(&["|[a]"], &["[a]|"])?; + assert_select_all(&["|[abc def ghi]"], &["[abc def ghi]|"])?; + assert_select_all(&["a\n", "[b\n", "]|"], &["[a\n", "b\n", "]|"])?; + assert_select_all(&["a\n", "[b]|\n", ""], &["[a\n", "b\n", "]|"])?; + assert_select_all(&["a\n", "|[b\n", "]"], &["[a\n", "b\n", "]|"])?; + assert_select_all( + &["abc\n", "def\n", "gh|i\n", "jkl"], + &["[abc\n", "def\n", "ghi\n", "jkl]|"], + )?; + assert_select_all( + &["|[abc\n", "def\n", "ghi\n", "jkl]"], + &["[abc\n", "def\n", "ghi\n", "jkl]|"], + )?; + + Ok(()) + } } diff --git a/editor/src/mvc/ed_update.rs b/editor/src/mvc/ed_update.rs index 86fe4652e7..631a4bf6dc 100644 --- a/editor/src/mvc/ed_update.rs +++ b/editor/src/mvc/ed_update.rs @@ -351,7 +351,8 @@ pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult ed_model.selection_opt = None; } - '\u{3}' // Ctrl + C + '\u{1}' // Ctrl + A + | '\u{3}' // Ctrl + C | '\u{16}' // Ctrl + V | '\u{30}' // Ctrl + X | '\u{e000}'..='\u{f8ff}' // http://www.unicode.org/faq/private_use.html diff --git a/editor/src/text_buffer.rs b/editor/src/text_buffer.rs index f43d0260ff..a0a512883c 100644 --- a/editor/src/text_buffer.rs +++ b/editor/src/text_buffer.rs @@ -116,6 +116,10 @@ impl TextBuffer { self.text_rope.len_lines() } + pub fn nr_of_chars(&self) -> usize { + self.text_rope.len_chars() + } + // expensive function, don't use it if it can be done with a specialized, more efficient function // TODO use pool allocation here pub fn all_lines<'a>(&self, arena: &'a Bump) -> BumpString<'a> { @@ -132,6 +136,16 @@ impl TextBuffer { self.text_rope.line_to_char(pos.line) + pos.column } + fn char_indx_to_pos(&self, char_indx: usize) -> Position { + let line = self.text_rope.char_to_line(char_indx); + + let char_idx_line_start = self.pos_to_char_indx(Position { line, column: 0 }); + + let column = char_indx - char_idx_line_start; + + Position { line, column } + } + fn sel_to_tup(&self, raw_sel: RawSelection) -> EdResult<(usize, usize)> { let valid_sel = validate_selection(raw_sel)?; let start_char_indx = self.pos_to_char_indx(valid_sel.selection.start_pos); @@ -139,6 +153,10 @@ impl TextBuffer { Ok((start_char_indx, end_char_indx)) } + + pub fn last_position(&self) -> Position { + self.char_indx_to_pos(self.nr_of_chars()) + } } pub fn from_path(path: &Path) -> EdResult { From 4f7269d87dcf11d483e85f97873ee9fc27541577 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Wed, 10 Feb 2021 19:53:42 +0100 Subject: [PATCH 2/2] moved handle_select_all to ed_update --- editor/src/keyboard_input.rs | 12 +++---- editor/src/mvc/app_update.rs | 66 ++-------------------------------- editor/src/mvc/ed_update.rs | 69 +++++++++++++++++++++++++++++++++++- 3 files changed, 74 insertions(+), 73 deletions(-) diff --git a/editor/src/keyboard_input.rs b/editor/src/keyboard_input.rs index 4254d9ac52..c7ef5ff799 100644 --- a/editor/src/keyboard_input.rs +++ b/editor/src/keyboard_input.rs @@ -1,8 +1,6 @@ use crate::error::EdResult; use crate::mvc::app_model::AppModel; -use crate::mvc::app_update::{ - handle_copy, handle_paste, handle_select_all, pass_keydown_to_focused, -}; +use crate::mvc::app_update::{handle_copy, handle_paste, pass_keydown_to_focused}; use winit::event::VirtualKeyCode::*; use winit::event::{ElementState, ModifiersState, VirtualKeyCode}; @@ -29,11 +27,6 @@ pub fn handle_keydown( todo!("cut"); } - A => { - if modifiers.ctrl() { - handle_select_all(app_model) - } - } C => { if modifiers.ctrl() { handle_copy(app_model)? @@ -50,6 +43,9 @@ pub fn handle_keydown( todo!("cut"); } } + + A => pass_keydown_to_focused(&modifiers, virtual_keycode, app_model), + _ => (), } diff --git a/editor/src/mvc/app_update.rs b/editor/src/mvc/app_update.rs index 36edf17e9c..46a9c84647 100644 --- a/editor/src/mvc/app_update.rs +++ b/editor/src/mvc/app_update.rs @@ -1,6 +1,6 @@ use super::app_model; use super::app_model::AppModel; -use super::ed_model::{Position, RawSelection}; +use super::ed_model::Position; use super::ed_update; use crate::error::EdResult; use winit::event::{ModifiersState, VirtualKeyCode}; @@ -76,21 +76,6 @@ pub fn handle_paste(app_model: &mut AppModel) -> EdResult<()> { Ok(()) } -pub fn handle_select_all(app_model: &mut AppModel) { - if let Some(ref mut ed_model) = app_model.ed_model_opt { - if ed_model.has_focus && ed_model.text_buf.nr_of_chars() > 0 { - let last_pos = ed_model.text_buf.last_position(); - - ed_model.selection_opt = Some(RawSelection { - start_pos: Position { line: 0, column: 0 }, - end_pos: last_pos, - }); - - ed_model.caret_pos = last_pos; - } - } -} - pub fn pass_keydown_to_focused( modifiers: &ModifiersState, virtual_keycode: VirtualKeyCode, @@ -117,7 +102,7 @@ pub fn handle_new_char(received_char: &char, app_model: &mut AppModel) -> EdResu pub mod test_app_update { use crate::mvc::app_model; use crate::mvc::app_model::{AppModel, Clipboard}; - use crate::mvc::app_update::{handle_copy, handle_paste, handle_select_all}; + use crate::mvc::app_update::{handle_copy, handle_paste}; use crate::mvc::ed_model::{EdModel, Position, RawSelection}; use crate::mvc::ed_update::test_ed_update::gen_caret_text_buf; use crate::selection::test_selection::{all_lines_vec, convert_selection_to_dsl}; @@ -220,51 +205,4 @@ pub mod test_app_update { Ok(()) } - - fn assert_select_all( - pre_lines_str: &[&str], - expected_post_lines_str: &[&str], - ) -> Result<(), String> { - let (caret_pos, selection_opt, pre_text_buf) = gen_caret_text_buf(pre_lines_str)?; - - let mut app_model = mock_app_model(pre_text_buf, caret_pos, selection_opt, None); - - handle_select_all(&mut app_model); - - let ed_model = app_model.ed_model_opt.unwrap(); - let mut text_buf_lines = all_lines_vec(&ed_model.text_buf); - let post_lines_str = convert_selection_to_dsl( - ed_model.selection_opt, - ed_model.caret_pos, - &mut text_buf_lines, - )?; - - assert_eq!(post_lines_str, expected_post_lines_str); - - Ok(()) - } - - #[test] - fn select_all() -> Result<(), String> { - assert_select_all(&["|"], &["|"])?; - assert_select_all(&["|a"], &["[a]|"])?; - assert_select_all(&["a|"], &["[a]|"])?; - assert_select_all(&["abc d|ef ghi"], &["[abc def ghi]|"])?; - assert_select_all(&["[a]|"], &["[a]|"])?; - assert_select_all(&["|[a]"], &["[a]|"])?; - assert_select_all(&["|[abc def ghi]"], &["[abc def ghi]|"])?; - assert_select_all(&["a\n", "[b\n", "]|"], &["[a\n", "b\n", "]|"])?; - assert_select_all(&["a\n", "[b]|\n", ""], &["[a\n", "b\n", "]|"])?; - assert_select_all(&["a\n", "|[b\n", "]"], &["[a\n", "b\n", "]|"])?; - assert_select_all( - &["abc\n", "def\n", "gh|i\n", "jkl"], - &["[abc\n", "def\n", "ghi\n", "jkl]|"], - )?; - assert_select_all( - &["|[abc\n", "def\n", "ghi\n", "jkl]"], - &["[abc\n", "def\n", "ghi\n", "jkl]|"], - )?; - - Ok(()) - } } diff --git a/editor/src/mvc/ed_update.rs b/editor/src/mvc/ed_update.rs index 631a4bf6dc..33f18b250a 100644 --- a/editor/src/mvc/ed_update.rs +++ b/editor/src/mvc/ed_update.rs @@ -318,6 +318,20 @@ fn del_selection(selection: RawSelection, ed_model: &mut EdModel) -> EdResult<() Ok(()) } +// TODO move this to impl EdModel +pub fn handle_select_all(ed_model: &mut EdModel) { + if ed_model.text_buf.nr_of_chars() > 0 { + let last_pos = ed_model.text_buf.last_position(); + + ed_model.selection_opt = Some(RawSelection { + start_pos: Position { line: 0, column: 0 }, + end_pos: last_pos, + }); + + ed_model.caret_pos = last_pos; + } +} + pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult<()> { let old_caret_pos = ed_model.caret_pos; @@ -398,6 +412,12 @@ pub fn handle_key_down( Up => handle_arrow(move_caret_up, modifiers, ed_model), Right => handle_arrow(move_caret_right, modifiers, ed_model), Down => handle_arrow(move_caret_down, modifiers, ed_model), + + A => { + if modifiers.ctrl() { + handle_select_all(ed_model) + } + } _ => {} } } @@ -406,7 +426,7 @@ pub fn handle_key_down( pub mod test_ed_update { use crate::mvc::app_update::test_app_update::mock_app_model; use crate::mvc::ed_model::{Position, RawSelection}; - use crate::mvc::ed_update::handle_new_char; + use crate::mvc::ed_update::{handle_new_char, handle_select_all}; use crate::selection::test_selection::{ all_lines_vec, convert_dsl_to_selection, convert_selection_to_dsl, text_buffer_from_dsl_str, }; @@ -555,4 +575,51 @@ pub mod test_ed_update { Ok(()) } + + fn assert_select_all( + pre_lines_str: &[&str], + expected_post_lines_str: &[&str], + ) -> Result<(), String> { + let (caret_pos, selection_opt, pre_text_buf) = gen_caret_text_buf(pre_lines_str)?; + + let app_model = mock_app_model(pre_text_buf, caret_pos, selection_opt, None); + let mut ed_model = app_model.ed_model_opt.unwrap(); + + handle_select_all(&mut ed_model); + + let mut text_buf_lines = all_lines_vec(&ed_model.text_buf); + let post_lines_str = convert_selection_to_dsl( + ed_model.selection_opt, + ed_model.caret_pos, + &mut text_buf_lines, + )?; + + assert_eq!(post_lines_str, expected_post_lines_str); + + Ok(()) + } + + #[test] + fn select_all() -> Result<(), String> { + assert_select_all(&["|"], &["|"])?; + assert_select_all(&["|a"], &["[a]|"])?; + assert_select_all(&["a|"], &["[a]|"])?; + assert_select_all(&["abc d|ef ghi"], &["[abc def ghi]|"])?; + assert_select_all(&["[a]|"], &["[a]|"])?; + assert_select_all(&["|[a]"], &["[a]|"])?; + assert_select_all(&["|[abc def ghi]"], &["[abc def ghi]|"])?; + assert_select_all(&["a\n", "[b\n", "]|"], &["[a\n", "b\n", "]|"])?; + assert_select_all(&["a\n", "[b]|\n", ""], &["[a\n", "b\n", "]|"])?; + assert_select_all(&["a\n", "|[b\n", "]"], &["[a\n", "b\n", "]|"])?; + assert_select_all( + &["abc\n", "def\n", "gh|i\n", "jkl"], + &["[abc\n", "def\n", "ghi\n", "jkl]|"], + )?; + assert_select_all( + &["|[abc\n", "def\n", "ghi\n", "jkl]"], + &["[abc\n", "def\n", "ghi\n", "jkl]|"], + )?; + + Ok(()) + } }