diff --git a/editor/src/keyboard_input.rs b/editor/src/keyboard_input.rs index 99410d28c7..df01638c0d 100644 --- a/editor/src/keyboard_input.rs +++ b/editor/src/keyboard_input.rs @@ -1,6 +1,6 @@ use winit::event::{ElementState, ModifiersState, VirtualKeyCode}; use crate::tea::model::{Model}; -use crate::tea::update::{move_caret_left, move_caret_right}; +use crate::tea::update::{move_caret_left, move_caret_right, move_caret_down, move_caret_up}; pub fn handle_keydown( elem_state: ElementState, @@ -21,7 +21,9 @@ pub fn handle_keydown( model.selection_opt = new_selection_opt; }, Up => { - todo!("arrow up"); + let (new_caret_pos, new_selection_opt) = move_caret_up(model.caret_pos, model.selection_opt, modifiers.shift(), &model.lines); + model.caret_pos = new_caret_pos; + model.selection_opt = new_selection_opt; }, Right => { let (new_caret_pos, new_selection_opt) = move_caret_right(model.caret_pos, model.selection_opt, modifiers.shift(), &model.lines); @@ -29,7 +31,9 @@ pub fn handle_keydown( model.selection_opt = new_selection_opt; }, Down => { - todo!("arrow down"); + let (new_caret_pos, new_selection_opt) = move_caret_down(model.caret_pos, model.selection_opt, modifiers.shift(), &model.lines); + model.caret_pos = new_caret_pos; + model.selection_opt = new_selection_opt; }, Copy => { todo!("copy"); diff --git a/editor/src/tea/model.rs b/editor/src/tea/model.rs index e4488f4c3a..9670588ceb 100644 --- a/editor/src/tea/model.rs +++ b/editor/src/tea/model.rs @@ -1,3 +1,6 @@ + +use std::cmp::{Ordering}; + #[derive(Debug)] pub struct Model { pub lines: Vec, @@ -25,6 +28,26 @@ pub struct Position { pub column: usize } +impl Ord for Position { + fn cmp(&self, other: &Self) -> Ordering { + (self.line, self.column).cmp(&(other.line, other.column)) + } +} + +impl PartialOrd for Position { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl PartialEq for Position { + fn eq(&self, other: &Self) -> bool { + (self.line, self.column) == (other.line, other.column) + } +} + +impl Eq for Position { } + #[derive(Debug, Copy, Clone)] pub struct RawSelection { pub start_pos: Position, diff --git a/editor/src/tea/update.rs b/editor/src/tea/update.rs index 84283135d2..8e5fa92be2 100644 --- a/editor/src/tea/update.rs +++ b/editor/src/tea/update.rs @@ -1,6 +1,7 @@ use crate::tea::model::{Position, RawSelection}; use crate::text::{is_newline}; +use std::cmp::{min, max}; pub fn move_caret_left(old_caret_pos: Position, old_selection_opt: Option, shift_pressed: bool, lines: &[String]) -> (Position, Option) { let old_line_nr = old_caret_pos.line; @@ -19,6 +20,11 @@ pub fn move_caret_left(old_caret_pos: Position, old_selection_opt: Option, shift_pressed: bool, lines: &[String]) -> (Position, Option) { + let old_line_nr = old_caret_pos.line; + let old_col_nr = old_caret_pos.column; + + let (line_nr, col_nr) = + if old_line_nr == 0 { + (old_line_nr, old_col_nr) + } else if let Some(prev_line) = lines.get(old_line_nr - 1) { + if prev_line.len() < old_col_nr { + (old_line_nr - 1, prev_line.len() - 1) + } else { + (old_line_nr - 1, old_col_nr) + } + } else { + (0, 0) // this should never happen, should this method return Result? + }; + + let new_caret_pos = Position { line: line_nr, column: col_nr - }, + }; + + let new_selection_opt = + if shift_pressed { + if let Some(old_selection) = old_selection_opt { + Some( + RawSelection { + start_pos: + new_caret_pos + , + end_pos: + old_selection.end_pos + , + } + ) + } else if !(old_line_nr == line_nr && old_col_nr == col_nr){ + Some( + RawSelection { + start_pos: + min(old_caret_pos, new_caret_pos) + , + end_pos: + max(old_caret_pos, new_caret_pos) + , + } + ) + } else { + None + } + + } else { + None + }; + + ( + new_caret_pos, + new_selection_opt + ) +} + +pub fn move_caret_down(old_caret_pos: Position, old_selection_opt: Option, shift_pressed: bool, lines: &[String]) -> (Position, Option) { + let old_line_nr = old_caret_pos.line; + let old_col_nr = old_caret_pos.column; + + let (line_nr, col_nr) = + if old_line_nr + 1 >= lines.len() { + (old_line_nr, old_col_nr) + } else if let Some(next_line) = lines.get(old_line_nr + 1) { + if next_line.len() < old_col_nr { + if let Some(last_char) = next_line.chars().last() { + if is_newline(&last_char) { + (old_line_nr + 1, next_line.len() - 1) + } else { + (old_line_nr + 1, next_line.len()) + } + } else { + (old_line_nr + 1, 0) + } + + } else { + (old_line_nr + 1, old_col_nr) + } + } else { + (0, 0) // this should never happen, should this method return Result? + }; + + let new_caret_pos = Position { + line: line_nr, + column: col_nr + }; + + let new_selection_opt = + if shift_pressed { + if let Some(old_selection) = old_selection_opt { + Some( + RawSelection { + start_pos: + old_selection.start_pos + , + end_pos: + new_caret_pos + , + } + ) + } else if !(old_line_nr == line_nr && old_col_nr == col_nr){ + Some( + RawSelection { + start_pos: + min(old_caret_pos, new_caret_pos) + , + end_pos: + max(old_caret_pos, new_caret_pos) + , + } + ) + } else { + None + } + + } else { + None + }; + + ( + new_caret_pos, new_selection_opt ) } \ No newline at end of file