fix(selection): add proper multi-click dragging options (#4052)
* properly extend/reduce word-bound selection on drag * properly extend/reduce line bound selection on drag * fix scrolling * style(fmt): rustfmt --------- Co-authored-by: aram <aram@green.green>
This commit is contained in:
parent
4fd0bac675
commit
ff595fccb6
3 changed files with 420 additions and 3 deletions
|
|
@ -1835,9 +1835,31 @@ impl Grid {
|
||||||
pub fn update_selection(&mut self, to: &Position) {
|
pub fn update_selection(&mut self, to: &Position) {
|
||||||
let old_selection = self.selection;
|
let old_selection = self.selection;
|
||||||
if &old_selection.end != to {
|
if &old_selection.end != to {
|
||||||
self.selection.to(*to);
|
if self.click.is_double_click() {
|
||||||
self.update_selected_lines(&old_selection, &self.selection.clone());
|
let Some((word_start_position, word_end_position)) = self.word_around_position(&to)
|
||||||
self.mark_for_rerender();
|
else {
|
||||||
|
// no-op
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
self.selection
|
||||||
|
.add_word_to_position(word_start_position, word_end_position);
|
||||||
|
let current_selection = self.selection;
|
||||||
|
self.update_selected_lines(&old_selection, ¤t_selection);
|
||||||
|
self.mark_for_rerender();
|
||||||
|
} else if self.click.is_triple_click() {
|
||||||
|
let Some(last_index_in_line) = self.last_index_in_line(&to) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
self.selection
|
||||||
|
.add_line_to_position(to.line.0, last_index_in_line);
|
||||||
|
let current_selection = self.selection;
|
||||||
|
self.update_selected_lines(&old_selection, ¤t_selection);
|
||||||
|
self.mark_for_rerender();
|
||||||
|
} else {
|
||||||
|
self.selection.to(*to);
|
||||||
|
self.update_selected_lines(&old_selection, &self.selection.clone());
|
||||||
|
self.mark_for_rerender();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1940,6 +1962,10 @@ impl Grid {
|
||||||
pub fn absolute_position_in_scrollback(&self) -> usize {
|
pub fn absolute_position_in_scrollback(&self) -> usize {
|
||||||
self.lines_above.len() + self.cursor.y
|
self.lines_above.len() + self.cursor.y
|
||||||
}
|
}
|
||||||
|
pub fn last_index_in_line(&self, position: &Position) -> Option<usize> {
|
||||||
|
let position_row = self.viewport.get(position.line.0 as usize)?;
|
||||||
|
Some(position_row.last_index_in_line())
|
||||||
|
}
|
||||||
pub fn word_around_position(&self, position: &Position) -> Option<(Position, Position)> {
|
pub fn word_around_position(&self, position: &Position) -> Option<(Position, Position)> {
|
||||||
let position_row = self.viewport.get(position.line.0 as usize)?;
|
let position_row = self.viewport.get(position.line.0 as usize)?;
|
||||||
let (index_start, index_end) =
|
let (index_start, index_end) =
|
||||||
|
|
@ -3811,6 +3837,9 @@ impl Row {
|
||||||
self.width = None;
|
self.width = None;
|
||||||
parts
|
parts
|
||||||
}
|
}
|
||||||
|
pub fn last_index_in_line(&self) -> usize {
|
||||||
|
self.columns.len()
|
||||||
|
}
|
||||||
pub fn word_indices_around_character_index(&self, index: usize) -> Option<(usize, usize)> {
|
pub fn word_indices_around_character_index(&self, index: usize) -> Option<(usize, usize)> {
|
||||||
let character_at_index = self.columns.get(index)?;
|
let character_at_index = self.columns.get(index)?;
|
||||||
if is_selection_boundary_character(character_at_index.character) {
|
if is_selection_boundary_character(character_at_index.character) {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ pub struct Selection {
|
||||||
pub start: Position,
|
pub start: Position,
|
||||||
pub end: Position,
|
pub end: Position,
|
||||||
active: bool, // used to handle moving the selection up and down
|
active: bool, // used to handle moving the selection up and down
|
||||||
|
last_added_word_position: Option<(Position, Position)>, // (start / end)
|
||||||
|
last_added_line_index: Option<isize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Selection {
|
impl Default for Selection {
|
||||||
|
|
@ -17,6 +19,8 @@ impl Default for Selection {
|
||||||
start: Position::new(0, 0),
|
start: Position::new(0, 0),
|
||||||
end: Position::new(0, 0),
|
end: Position::new(0, 0),
|
||||||
active: false,
|
active: false,
|
||||||
|
last_added_word_position: None,
|
||||||
|
last_added_line_index: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -38,8 +42,120 @@ impl Selection {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_start_and_end_positions(&mut self, start: Position, end: Position) {
|
pub fn set_start_and_end_positions(&mut self, start: Position, end: Position) {
|
||||||
|
self.active = true;
|
||||||
self.start = start;
|
self.start = start;
|
||||||
self.end = end;
|
self.end = end;
|
||||||
|
self.last_added_word_position = Some((start, end));
|
||||||
|
self.last_added_line_index = Some(start.line.0);
|
||||||
|
}
|
||||||
|
pub fn add_word_to_position(&mut self, word_start: Position, word_end: Position) {
|
||||||
|
// here we assume word_start is smaller or equal to word_end
|
||||||
|
let already_added = self
|
||||||
|
.last_added_word_position
|
||||||
|
.map(|(last_word_start, last_word_end)| {
|
||||||
|
last_word_start == word_start && last_word_end == word_end
|
||||||
|
})
|
||||||
|
.unwrap_or(false);
|
||||||
|
if already_added {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let word_is_above_last_added_word = self
|
||||||
|
.last_added_word_position
|
||||||
|
.map(|(l_start, _l_end)| word_start.line < l_start.line)
|
||||||
|
.unwrap_or(false);
|
||||||
|
let word_is_below_last_added_word = self
|
||||||
|
.last_added_word_position
|
||||||
|
.map(|(_l_start, l_end)| word_end.line > l_end.line)
|
||||||
|
.unwrap_or(false);
|
||||||
|
if word_is_above_last_added_word && word_start.line < self.start.line {
|
||||||
|
// extend line above
|
||||||
|
self.start = word_start;
|
||||||
|
} else if word_is_below_last_added_word && word_end.line > self.end.line {
|
||||||
|
// extend line below
|
||||||
|
self.end = word_end;
|
||||||
|
} else if word_is_below_last_added_word && word_start.line > self.start.line {
|
||||||
|
// reduce from above
|
||||||
|
self.start = word_start;
|
||||||
|
} else if word_is_above_last_added_word && word_end.line < self.end.line {
|
||||||
|
// reduce from below
|
||||||
|
self.end = word_end;
|
||||||
|
} else {
|
||||||
|
let word_end_is_to_the_left_of_last_word_start = self
|
||||||
|
.last_added_word_position
|
||||||
|
.map(|(l_start, _l_end)| word_end.column <= l_start.column)
|
||||||
|
.unwrap_or(false);
|
||||||
|
let word_start_is_to_the_right_of_last_word_end = self
|
||||||
|
.last_added_word_position
|
||||||
|
.map(|(_l_start, l_end)| word_start.column >= l_end.column)
|
||||||
|
.unwrap_or(false);
|
||||||
|
let last_word_start_equals_word_end = self
|
||||||
|
.last_added_word_position
|
||||||
|
.map(|(l_start, _l_end)| l_start.column == word_end.column)
|
||||||
|
.unwrap_or(false);
|
||||||
|
let last_word_end_equals_word_start = self
|
||||||
|
.last_added_word_position
|
||||||
|
.map(|(_l_start, l_end)| l_end.column == word_start.column)
|
||||||
|
.unwrap_or(false);
|
||||||
|
let selection_start_column_is_to_the_right_of_word_start =
|
||||||
|
self.start.column > word_start.column;
|
||||||
|
let selection_start_is_on_same_line_as_word_start = self.start.line == word_start.line;
|
||||||
|
let selection_end_is_to_the_left_of_word_end = self.end.column < word_end.column;
|
||||||
|
let selection_end_is_on_same_line_as_word_end = self.end.line == word_end.line;
|
||||||
|
if word_end_is_to_the_left_of_last_word_start
|
||||||
|
&& selection_start_column_is_to_the_right_of_word_start
|
||||||
|
&& selection_start_is_on_same_line_as_word_start
|
||||||
|
{
|
||||||
|
// extend selection left
|
||||||
|
self.start.column = word_start.column;
|
||||||
|
} else if word_start_is_to_the_right_of_last_word_end
|
||||||
|
&& selection_end_is_to_the_left_of_word_end
|
||||||
|
&& selection_end_is_on_same_line_as_word_end
|
||||||
|
{
|
||||||
|
// extend selection right
|
||||||
|
self.end.column = word_end.column;
|
||||||
|
} else if last_word_start_equals_word_end {
|
||||||
|
// reduce selection from the right
|
||||||
|
self.end.column = word_end.column;
|
||||||
|
} else if last_word_end_equals_word_start {
|
||||||
|
// reduce selection from the left
|
||||||
|
self.start.column = word_start.column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.last_added_word_position = Some((word_start, word_end));
|
||||||
|
}
|
||||||
|
pub fn add_line_to_position(&mut self, line_index: isize, last_index_in_line: usize) {
|
||||||
|
let already_added = self
|
||||||
|
.last_added_line_index
|
||||||
|
.map(|last_added_line_index| last_added_line_index == line_index)
|
||||||
|
.unwrap_or(false);
|
||||||
|
if already_added {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let line_index_is_smaller_than_last_added_line_index = self
|
||||||
|
.last_added_line_index
|
||||||
|
.map(|last| line_index < last)
|
||||||
|
.unwrap_or(false);
|
||||||
|
let line_index_is_larger_than_last_added_line_index = self
|
||||||
|
.last_added_line_index
|
||||||
|
.map(|last| line_index > last)
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
if line_index_is_smaller_than_last_added_line_index && self.start.line.0 > line_index {
|
||||||
|
// extend selection one line upwards
|
||||||
|
self.start = Position::new(line_index as i32, 0);
|
||||||
|
} else if line_index_is_larger_than_last_added_line_index && self.end.line.0 < line_index {
|
||||||
|
// extend selection one line downwards
|
||||||
|
self.end = Position::new(line_index as i32, last_index_in_line as u16);
|
||||||
|
} else if line_index_is_smaller_than_last_added_line_index && self.end.line.0 > line_index {
|
||||||
|
// reduce selection one line from below
|
||||||
|
self.end = Position::new(line_index as i32, last_index_in_line as u16);
|
||||||
|
} else if line_index_is_larger_than_last_added_line_index && self.start.line.0 < line_index
|
||||||
|
{
|
||||||
|
// reduce selection one line from above
|
||||||
|
self.start = Position::new(line_index as i32, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.last_added_line_index = Some(line_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn contains(&self, row: usize, col: usize) -> bool {
|
pub fn contains(&self, row: usize, col: usize) -> bool {
|
||||||
|
|
@ -91,6 +207,8 @@ impl Selection {
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
active: self.active,
|
active: self.active,
|
||||||
|
last_added_word_position: self.last_added_word_position,
|
||||||
|
last_added_line_index: self.last_added_line_index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,8 @@ fn contains() {
|
||||||
start: Position::new(10, 5),
|
start: Position::new(10, 5),
|
||||||
end: Position::new(40, 20),
|
end: Position::new(40, 20),
|
||||||
active: false,
|
active: false,
|
||||||
|
last_added_word_position: None,
|
||||||
|
last_added_line_index: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let test_cases = vec![
|
let test_cases = vec![
|
||||||
|
|
@ -93,6 +95,8 @@ fn sorted() {
|
||||||
start: Position::new(1, 1),
|
start: Position::new(1, 1),
|
||||||
end: Position::new(10, 2),
|
end: Position::new(10, 2),
|
||||||
active: false,
|
active: false,
|
||||||
|
last_added_word_position: None,
|
||||||
|
last_added_line_index: None,
|
||||||
};
|
};
|
||||||
let sorted_selection = selection.sorted();
|
let sorted_selection = selection.sorted();
|
||||||
assert_eq!(selection.start, sorted_selection.start);
|
assert_eq!(selection.start, sorted_selection.start);
|
||||||
|
|
@ -102,6 +106,8 @@ fn sorted() {
|
||||||
start: Position::new(10, 2),
|
start: Position::new(10, 2),
|
||||||
end: Position::new(1, 1),
|
end: Position::new(1, 1),
|
||||||
active: false,
|
active: false,
|
||||||
|
last_added_word_position: None,
|
||||||
|
last_added_line_index: None,
|
||||||
};
|
};
|
||||||
let sorted_selection = selection.sorted();
|
let sorted_selection = selection.sorted();
|
||||||
assert_eq!(selection.end, sorted_selection.start);
|
assert_eq!(selection.end, sorted_selection.start);
|
||||||
|
|
@ -114,6 +120,8 @@ fn line_indices() {
|
||||||
start: Position::new(1, 1),
|
start: Position::new(1, 1),
|
||||||
end: Position::new(10, 2),
|
end: Position::new(10, 2),
|
||||||
active: false,
|
active: false,
|
||||||
|
last_added_word_position: None,
|
||||||
|
last_added_line_index: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(selection.line_indices(), (1..=10))
|
assert_eq!(selection.line_indices(), (1..=10))
|
||||||
|
|
@ -127,6 +135,8 @@ fn move_up_inactive() {
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
active: false,
|
active: false,
|
||||||
|
last_added_word_position: None,
|
||||||
|
last_added_line_index: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
inactive_selection.move_up(2);
|
inactive_selection.move_up(2);
|
||||||
|
|
@ -145,6 +155,8 @@ fn move_up_active() {
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
active: true,
|
active: true,
|
||||||
|
last_added_word_position: None,
|
||||||
|
last_added_line_index: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
inactive_selection.move_up(2);
|
inactive_selection.move_up(2);
|
||||||
|
|
@ -160,6 +172,8 @@ fn move_down_inactive() {
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
active: false,
|
active: false,
|
||||||
|
last_added_word_position: None,
|
||||||
|
last_added_line_index: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
inactive_selection.move_down(2);
|
inactive_selection.move_down(2);
|
||||||
|
|
@ -178,9 +192,265 @@ fn move_down_active() {
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
active: true,
|
active: true,
|
||||||
|
last_added_word_position: None,
|
||||||
|
last_added_line_index: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
inactive_selection.move_down(2);
|
inactive_selection.move_down(2);
|
||||||
assert_eq!(inactive_selection.start, Position::new(12, 1));
|
assert_eq!(inactive_selection.start, Position::new(12, 1));
|
||||||
assert_eq!(inactive_selection.end, end);
|
assert_eq!(inactive_selection.end, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_word_to_position_extend_line_above() {
|
||||||
|
let selection_start = Position::new(10, 10);
|
||||||
|
let selection_end = Position::new(20, 20);
|
||||||
|
let last_word_start = Position::new(10, 10);
|
||||||
|
let last_word_end = Position::new(10, 15);
|
||||||
|
let mut selection = Selection {
|
||||||
|
start: selection_start,
|
||||||
|
end: selection_end,
|
||||||
|
active: true,
|
||||||
|
last_added_word_position: Some((last_word_start, last_word_end)),
|
||||||
|
last_added_line_index: None,
|
||||||
|
};
|
||||||
|
let word_start = Position::new(9, 5);
|
||||||
|
let word_end = Position::new(9, 6);
|
||||||
|
selection.add_word_to_position(word_start, word_end);
|
||||||
|
|
||||||
|
assert_eq!(selection.start, word_start);
|
||||||
|
assert_eq!(selection.end, selection_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_word_to_position_extend_line_below() {
|
||||||
|
let selection_start = Position::new(10, 10);
|
||||||
|
let selection_end = Position::new(20, 20);
|
||||||
|
let last_word_start = Position::new(20, 15);
|
||||||
|
let last_word_end = Position::new(20, 20);
|
||||||
|
let mut selection = Selection {
|
||||||
|
start: selection_start,
|
||||||
|
end: selection_end,
|
||||||
|
active: true,
|
||||||
|
last_added_word_position: Some((last_word_start, last_word_end)),
|
||||||
|
last_added_line_index: None,
|
||||||
|
};
|
||||||
|
let word_start = Position::new(21, 5);
|
||||||
|
let word_end = Position::new(21, 6);
|
||||||
|
selection.add_word_to_position(word_start, word_end);
|
||||||
|
|
||||||
|
assert_eq!(selection.start, selection_start);
|
||||||
|
assert_eq!(selection.end, word_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_word_to_position_reduce_from_above() {
|
||||||
|
let selection_start = Position::new(10, 10);
|
||||||
|
let selection_end = Position::new(20, 20);
|
||||||
|
let last_word_start = Position::new(10, 10);
|
||||||
|
let last_word_end = Position::new(10, 20);
|
||||||
|
let mut selection = Selection {
|
||||||
|
start: selection_start,
|
||||||
|
end: selection_end,
|
||||||
|
active: true,
|
||||||
|
last_added_word_position: Some((last_word_start, last_word_end)),
|
||||||
|
last_added_line_index: None,
|
||||||
|
};
|
||||||
|
let word_start = Position::new(11, 5);
|
||||||
|
let word_end = Position::new(11, 6);
|
||||||
|
selection.add_word_to_position(word_start, word_end);
|
||||||
|
|
||||||
|
assert_eq!(selection.start, word_start);
|
||||||
|
assert_eq!(selection.end, selection_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_word_to_position_reduce_from_below() {
|
||||||
|
let selection_start = Position::new(10, 10);
|
||||||
|
let selection_end = Position::new(20, 20);
|
||||||
|
let last_word_start = Position::new(20, 10);
|
||||||
|
let last_word_end = Position::new(20, 20);
|
||||||
|
let mut selection = Selection {
|
||||||
|
start: selection_start,
|
||||||
|
end: selection_end,
|
||||||
|
active: true,
|
||||||
|
last_added_word_position: Some((last_word_start, last_word_end)),
|
||||||
|
last_added_line_index: None,
|
||||||
|
};
|
||||||
|
let word_start = Position::new(19, 5);
|
||||||
|
let word_end = Position::new(19, 6);
|
||||||
|
selection.add_word_to_position(word_start, word_end);
|
||||||
|
|
||||||
|
assert_eq!(selection.start, selection_start);
|
||||||
|
assert_eq!(selection.end, word_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_word_to_position_extend_right() {
|
||||||
|
let selection_start = Position::new(10, 10);
|
||||||
|
let selection_end = Position::new(20, 20);
|
||||||
|
let last_word_start = Position::new(20, 10);
|
||||||
|
let last_word_end = Position::new(20, 20);
|
||||||
|
let mut selection = Selection {
|
||||||
|
start: selection_start,
|
||||||
|
end: selection_end,
|
||||||
|
active: true,
|
||||||
|
last_added_word_position: Some((last_word_start, last_word_end)),
|
||||||
|
last_added_line_index: None,
|
||||||
|
};
|
||||||
|
let word_start = Position::new(20, 21);
|
||||||
|
let word_end = Position::new(20, 23);
|
||||||
|
selection.add_word_to_position(word_start, word_end);
|
||||||
|
|
||||||
|
assert_eq!(selection.start, selection_start);
|
||||||
|
assert_eq!(selection.end, word_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_word_to_position_extend_left() {
|
||||||
|
let selection_start = Position::new(10, 10);
|
||||||
|
let selection_end = Position::new(20, 20);
|
||||||
|
let last_word_start = Position::new(10, 10);
|
||||||
|
let last_word_end = Position::new(10, 20);
|
||||||
|
let mut selection = Selection {
|
||||||
|
start: selection_start,
|
||||||
|
end: selection_end,
|
||||||
|
active: true,
|
||||||
|
last_added_word_position: Some((last_word_start, last_word_end)),
|
||||||
|
last_added_line_index: None,
|
||||||
|
};
|
||||||
|
let word_start = Position::new(10, 5);
|
||||||
|
let word_end = Position::new(10, 9);
|
||||||
|
selection.add_word_to_position(word_start, word_end);
|
||||||
|
|
||||||
|
assert_eq!(selection.start, word_start);
|
||||||
|
assert_eq!(selection.end, selection_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_word_to_position_reduce_from_left() {
|
||||||
|
let selection_start = Position::new(10, 10);
|
||||||
|
let selection_end = Position::new(20, 20);
|
||||||
|
let last_word_start = Position::new(10, 10);
|
||||||
|
let last_word_end = Position::new(10, 20);
|
||||||
|
let mut selection = Selection {
|
||||||
|
start: selection_start,
|
||||||
|
end: selection_end,
|
||||||
|
active: true,
|
||||||
|
last_added_word_position: Some((last_word_start, last_word_end)),
|
||||||
|
last_added_line_index: None,
|
||||||
|
};
|
||||||
|
let word_start = Position::new(10, 20);
|
||||||
|
let word_end = Position::new(10, 30);
|
||||||
|
selection.add_word_to_position(word_start, word_end);
|
||||||
|
|
||||||
|
assert_eq!(selection.start, word_start);
|
||||||
|
assert_eq!(selection.end, selection_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_word_to_position_reduce_from_right() {
|
||||||
|
let selection_start = Position::new(10, 10);
|
||||||
|
let selection_end = Position::new(20, 20);
|
||||||
|
let last_word_start = Position::new(20, 10);
|
||||||
|
let last_word_end = Position::new(20, 20);
|
||||||
|
let mut selection = Selection {
|
||||||
|
start: selection_start,
|
||||||
|
end: selection_end,
|
||||||
|
active: true,
|
||||||
|
last_added_word_position: Some((last_word_start, last_word_end)),
|
||||||
|
last_added_line_index: None,
|
||||||
|
};
|
||||||
|
let word_start = Position::new(20, 5);
|
||||||
|
let word_end = Position::new(20, 10);
|
||||||
|
selection.add_word_to_position(word_start, word_end);
|
||||||
|
|
||||||
|
assert_eq!(selection.start, selection_start);
|
||||||
|
assert_eq!(selection.end, word_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_line_to_position_extend_upwards() {
|
||||||
|
let selection_start = Position::new(10, 10);
|
||||||
|
let selection_end = Position::new(20, 20);
|
||||||
|
let last_added_line_index = 10;
|
||||||
|
let mut selection = Selection {
|
||||||
|
start: selection_start,
|
||||||
|
end: selection_end,
|
||||||
|
active: true,
|
||||||
|
last_added_word_position: None,
|
||||||
|
last_added_line_index: Some(last_added_line_index),
|
||||||
|
};
|
||||||
|
let line_index_to_add = 9;
|
||||||
|
let last_index_in_line = 21;
|
||||||
|
selection.add_line_to_position(line_index_to_add, last_index_in_line);
|
||||||
|
|
||||||
|
assert_eq!(selection.start, Position::new(line_index_to_add as i32, 0));
|
||||||
|
assert_eq!(selection.end, selection_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_line_to_position_extend_downwards() {
|
||||||
|
let selection_start = Position::new(10, 10);
|
||||||
|
let selection_end = Position::new(20, 20);
|
||||||
|
let last_added_line_index = 20;
|
||||||
|
let mut selection = Selection {
|
||||||
|
start: selection_start,
|
||||||
|
end: selection_end,
|
||||||
|
active: true,
|
||||||
|
last_added_word_position: None,
|
||||||
|
last_added_line_index: Some(last_added_line_index),
|
||||||
|
};
|
||||||
|
let line_index_to_add = 21;
|
||||||
|
let last_index_in_line = 21;
|
||||||
|
selection.add_line_to_position(line_index_to_add, last_index_in_line);
|
||||||
|
|
||||||
|
assert_eq!(selection.start, selection_start);
|
||||||
|
assert_eq!(
|
||||||
|
selection.end,
|
||||||
|
Position::new(line_index_to_add as i32, last_index_in_line as u16)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_line_to_position_reduce_from_below() {
|
||||||
|
let selection_start = Position::new(10, 10);
|
||||||
|
let selection_end = Position::new(20, 20);
|
||||||
|
let last_added_line_index = 20;
|
||||||
|
let mut selection = Selection {
|
||||||
|
start: selection_start,
|
||||||
|
end: selection_end,
|
||||||
|
active: true,
|
||||||
|
last_added_word_position: None,
|
||||||
|
last_added_line_index: Some(last_added_line_index),
|
||||||
|
};
|
||||||
|
let line_index_to_add = 19;
|
||||||
|
let last_index_in_line = 21;
|
||||||
|
selection.add_line_to_position(line_index_to_add, last_index_in_line);
|
||||||
|
|
||||||
|
assert_eq!(selection.start, selection_start);
|
||||||
|
assert_eq!(
|
||||||
|
selection.end,
|
||||||
|
Position::new(line_index_to_add as i32, last_index_in_line as u16)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_line_to_position_reduce_from_above() {
|
||||||
|
let selection_start = Position::new(10, 10);
|
||||||
|
let selection_end = Position::new(20, 20);
|
||||||
|
let last_added_line_index = 10;
|
||||||
|
let mut selection = Selection {
|
||||||
|
start: selection_start,
|
||||||
|
end: selection_end,
|
||||||
|
active: true,
|
||||||
|
last_added_word_position: None,
|
||||||
|
last_added_line_index: Some(last_added_line_index),
|
||||||
|
};
|
||||||
|
let line_index_to_add = 9;
|
||||||
|
let last_index_in_line = 21;
|
||||||
|
selection.add_line_to_position(line_index_to_add, last_index_in_line);
|
||||||
|
|
||||||
|
assert_eq!(selection.start, Position::new(line_index_to_add as i32, 0));
|
||||||
|
assert_eq!(selection.end, selection_end);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue