use std::collections::HashMap;
use crate::mm::{BufferId, Position};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Mark {
pub position: Position,
pub buffer_id: BufferId,
}
impl Mark {
#[must_use]
pub const fn new(position: Position, buffer_id: BufferId) -> Self {
Self {
position,
buffer_id,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum SpecialMark {
LastJump,
LastEdit,
LastInsert,
VisualStart,
VisualEnd,
LastExitInsert,
}
#[derive(Debug, Clone, Default)]
pub struct MarkBank {
local: HashMap<char, Position>,
global: HashMap<char, Mark>,
special: HashMap<SpecialMark, Mark>,
}
impl MarkBank {
#[must_use]
pub fn new() -> Self {
Self {
local: HashMap::new(),
global: HashMap::new(),
special: HashMap::new(),
}
}
pub fn set_local(&mut self, name: char, position: Position) -> bool {
if name.is_ascii_lowercase() {
self.local.insert(name, position);
true
} else {
false
}
}
#[must_use]
pub fn get_local(&self, name: char) -> Option<Position> {
if name.is_ascii_lowercase() {
self.local.get(&name).copied()
} else {
None
}
}
pub fn delete_local(&mut self, name: char) -> bool {
if name.is_ascii_lowercase() {
self.local.remove(&name).is_some()
} else {
false
}
}
#[must_use]
pub fn list_local(&self) -> Vec<(char, Position)> {
let mut marks: Vec<_> = self.local.iter().map(|(&c, &p)| (c, p)).collect();
marks.sort_by_key(|(c, _)| *c);
marks
}
pub fn set_global(&mut self, name: char, mark: Mark) -> bool {
if name.is_ascii_uppercase() {
self.global.insert(name, mark);
true
} else {
false
}
}
#[must_use]
pub fn get_global(&self, name: char) -> Option<&Mark> {
if name.is_ascii_uppercase() {
self.global.get(&name)
} else {
None
}
}
pub fn delete_global(&mut self, name: char) -> bool {
if name.is_ascii_uppercase() {
self.global.remove(&name).is_some()
} else {
false
}
}
#[must_use]
pub fn list_global(&self) -> Vec<(char, &Mark)> {
let mut marks: Vec<_> = self.global.iter().map(|(&c, m)| (c, m)).collect();
marks.sort_by_key(|(c, _)| *c);
marks
}
pub fn set_special(&mut self, mark: SpecialMark, value: Mark) {
self.special.insert(mark, value);
}
#[must_use]
pub fn get_special(&self, mark: SpecialMark) -> Option<&Mark> {
self.special.get(&mark)
}
pub fn clear_special(&mut self, mark: SpecialMark) {
self.special.remove(&mark);
}
#[must_use]
pub fn get_by_char(&self, c: char) -> Option<MarkResult<'_>> {
match c {
'a'..='z' => self.local.get(&c).map(|&p| MarkResult::Local(p)),
'A'..='Z' => self.global.get(&c).map(MarkResult::Global),
'\'' | '`' => self
.special
.get(&SpecialMark::LastJump)
.map(MarkResult::Global),
'.' => self
.special
.get(&SpecialMark::LastEdit)
.map(MarkResult::Global),
'^' => self
.special
.get(&SpecialMark::LastInsert)
.map(MarkResult::Global),
'<' => self
.special
.get(&SpecialMark::VisualStart)
.map(MarkResult::Global),
'>' => self
.special
.get(&SpecialMark::VisualEnd)
.map(MarkResult::Global),
_ => None,
}
}
pub fn clear_local(&mut self) {
self.local.clear();
}
pub fn clear_all(&mut self) {
self.local.clear();
self.global.clear();
self.special.clear();
}
}
#[derive(Debug, Clone, Copy)]
pub enum MarkResult<'a> {
Local(Position),
Global(&'a Mark),
}
impl MarkResult<'_> {
#[must_use]
pub const fn position(&self) -> Position {
match self {
Self::Local(pos) => *pos,
Self::Global(mark) => mark.position,
}
}
#[must_use]
pub const fn buffer_id(&self) -> Option<BufferId> {
match self {
Self::Local(_) => None,
Self::Global(mark) => Some(mark.buffer_id),
}
}
}