use std::collections::HashMap;
use crossterm::style::Stylize;
use get_size::GetSize;
use r3bl_rs_utils_core::*;
use serde::{Deserialize, Serialize};
#[derive(Clone, PartialEq, Serialize, Deserialize, GetSize, Default)]
pub struct SelectionMap {
pub map: HashMap<RowIndex, SelectionRange>,
pub maybe_previous_direction: Option<CaretMovementDirection>,
}
pub type RowIndex = ChUnit;
#[test]
fn test_selection_map_direction_change() {
use crate::selection_map_impl::DirectionChangeResult;
{
let map = SelectionMap {
maybe_previous_direction: None,
..Default::default()
};
let current_direction = CaretMovementDirection::Down;
let actual = map.has_caret_movement_direction_changed(current_direction);
let expected = DirectionChangeResult::DirectionIsTheSame;
assert_eq2!(actual, expected);
}
{
let map = SelectionMap {
maybe_previous_direction: Some(CaretMovementDirection::Up),
..Default::default()
};
let current_direction = CaretMovementDirection::Down;
let actual = map.has_caret_movement_direction_changed(current_direction);
let expected = DirectionChangeResult::DirectionHasChanged;
assert_eq2!(actual, expected);
}
{
let map = SelectionMap {
maybe_previous_direction: Some(CaretMovementDirection::Down),
..Default::default()
};
let current_direction = CaretMovementDirection::Down;
let actual = map.has_caret_movement_direction_changed(current_direction);
let expected = DirectionChangeResult::DirectionIsTheSame;
assert_eq2!(actual, expected);
}
}
pub mod selection_map_impl {
use std::fmt::{Debug, Display};
use crossterm::style::StyledContent;
use super::*;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DirectionChangeResult {
DirectionHasChanged,
DirectionIsTheSame,
}
impl SelectionMap {
pub fn is_empty(&self) -> bool { self.map.is_empty() }
pub fn clear(&mut self) {
self.map.clear();
self.maybe_previous_direction = None;
}
pub fn iter(&self) -> impl Iterator<Item = (&RowIndex, &SelectionRange)> {
self.map.iter()
}
pub fn get(&self, row_index: RowIndex) -> Option<&SelectionRange> {
self.map.get(&row_index)
}
pub fn has_caret_movement_direction_changed(
&self,
current_direction: CaretMovementDirection,
) -> DirectionChangeResult {
if let Some(previous_direction) = self.maybe_previous_direction {
if previous_direction != current_direction {
return DirectionChangeResult::DirectionHasChanged;
}
}
DirectionChangeResult::DirectionIsTheSame
}
pub fn insert(
&mut self,
row_index: RowIndex,
selection_range: SelectionRange,
direction: CaretMovementDirection,
) {
self.map.insert(row_index, selection_range);
self.update_previous_direction(direction);
}
pub fn remove(&mut self, row_index: RowIndex, direction: CaretMovementDirection) {
self.map.remove(&row_index);
self.update_previous_direction(direction);
}
pub fn update_previous_direction(&mut self, direction: CaretMovementDirection) {
self.maybe_previous_direction = Some(direction);
}
pub fn remove_previous_direction(&mut self) {
self.maybe_previous_direction = None;
}
pub fn locate_row(&self, row_index_arg: ChUnit) -> RowLocationInSelectionMap {
for (row_index, _range) in self.map.iter() {
if &row_index_arg == row_index {
return RowLocationInSelectionMap::Contained;
}
}
RowLocationInSelectionMap::Overflow
}
}
#[derive(Clone, PartialEq, Serialize, Deserialize, GetSize, Copy, Debug)]
pub enum RowLocationInSelectionMap {
Overflow,
Contained,
}
mod debug_display {
use super::*;
impl SelectionMap {
pub fn to_formatted_string(&self) -> StyledContent<String> {
let selection_map_str = self.to_unformatted_string();
if selection_map_str.contains("None") {
selection_map_str.white().on_dark_grey()
} else {
selection_map_str.green().on_dark_grey()
}
}
pub fn to_unformatted_string(&self) -> String {
let mut vec_output = self
.map
.iter()
.map(|(row_index, selected_range)| {
format!(
"✂️ ┆row: {0} => start: {1}, end: {2}┆",
row_index,
selected_range.start_display_col_index,
selected_range.end_display_col_index
)
})
.collect::<Vec<String>>();
if vec_output.is_empty() {
vec_output.push("✂️ ┆--empty--┆".to_string());
}
vec_output
.push(format!("🧭 prev_dir: {:?}", self.maybe_previous_direction,));
vec_output.join("\n ")
}
}
impl Display for SelectionMap {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.to_formatted_string())
}
}
impl Debug for SelectionMap {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.to_formatted_string())
}
}
}
}