2021-01-16 13:57:06 +01:00
|
|
|
|
2020-12-14 19:36:21 +01:00
|
|
|
use {
|
2021-01-06 21:35:46 +01:00
|
|
|
std::{
|
|
|
|
sync::{Arc, RwLock},
|
|
|
|
},
|
|
|
|
cgmath::Point2,
|
2020-12-14 19:36:21 +01:00
|
|
|
crate::{
|
2021-01-06 21:35:46 +01:00
|
|
|
core::{
|
|
|
|
ObserverExt,
|
|
|
|
ObserverBroadcast,
|
2021-01-16 16:09:16 +01:00
|
|
|
InnerViewPort
|
2021-01-06 21:35:46 +01:00
|
|
|
},
|
|
|
|
index::{ImplIndexView},
|
2021-01-16 16:09:16 +01:00
|
|
|
grid::{GridWindowIterator},
|
2021-01-06 21:35:46 +01:00
|
|
|
terminal::{TerminalAtom, TerminalStyle, TerminalView},
|
|
|
|
//vec_buffer::VecBuffer
|
2020-12-14 19:36:21 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-01-06 21:35:46 +01:00
|
|
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
|
|
|
|
2020-12-14 19:36:21 +01:00
|
|
|
pub struct StringEditorState {
|
|
|
|
cursor: usize,
|
|
|
|
data: Arc<RwLock<Vec<char>>>
|
|
|
|
}
|
|
|
|
|
2021-01-06 21:35:46 +01:00
|
|
|
impl ImplIndexView for StringEditorState {
|
|
|
|
type Key = Point2<i16>;
|
|
|
|
type Value = Option<TerminalAtom>;
|
2020-12-14 19:36:21 +01:00
|
|
|
|
2021-01-06 21:35:46 +01:00
|
|
|
fn get(&self, pos: &Point2<i16>) -> Option<TerminalAtom> {
|
|
|
|
let data = self.data.read().unwrap();
|
2020-12-14 19:36:21 +01:00
|
|
|
|
2021-01-06 21:35:46 +01:00
|
|
|
if pos.y == 0 {
|
2021-01-16 13:57:06 +01:00
|
|
|
let i = pos.x as usize;
|
|
|
|
if i < data.len() + 3 {
|
2020-12-14 19:36:21 +01:00
|
|
|
return Some(
|
|
|
|
if i == 0 {
|
|
|
|
TerminalAtom::new('"', TerminalStyle::fg_color((180,200,130)))
|
2021-01-06 21:35:46 +01:00
|
|
|
} else if i-1 == self.cursor {
|
2021-01-16 13:57:06 +01:00
|
|
|
TerminalAtom::new('|', TerminalStyle::fg_color((180,200,130)).add(TerminalStyle::bold(false)))
|
2020-12-14 19:36:21 +01:00
|
|
|
} else if i-1 == data.len()+1 {
|
|
|
|
TerminalAtom::new('"', TerminalStyle::fg_color((180,200,130)))
|
|
|
|
} else {
|
|
|
|
TerminalAtom::new(
|
2021-01-06 21:35:46 +01:00
|
|
|
data.get(i as usize - if i <= self.cursor { 1 } else { 2 }).unwrap().clone(),
|
2021-01-16 13:57:06 +01:00
|
|
|
TerminalStyle::fg_color((80,150,80)).add(TerminalStyle::bold(true))
|
2020-12-14 19:36:21 +01:00
|
|
|
)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
None
|
2021-01-06 21:35:46 +01:00
|
|
|
}
|
|
|
|
|
2021-01-16 13:57:06 +01:00
|
|
|
fn area(&self) -> Option<Vec<Point2<i16>>> {
|
|
|
|
Some(GridWindowIterator::from(
|
2021-01-06 21:35:46 +01:00
|
|
|
Point2::new(0, 0)
|
2021-01-16 13:57:06 +01:00
|
|
|
.. Point2::new(self.data.read().unwrap().len() as i16 + 3, 1)).collect())
|
2020-12-14 19:36:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct StringEditor {
|
|
|
|
state: Arc<RwLock<StringEditorState>>,
|
2021-01-06 21:35:46 +01:00
|
|
|
cast: Arc<RwLock<ObserverBroadcast<dyn TerminalView>>>
|
2020-12-14 19:36:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl StringEditor {
|
|
|
|
pub fn new(
|
2021-01-06 21:35:46 +01:00
|
|
|
port: InnerViewPort<dyn TerminalView>
|
2020-12-14 19:36:21 +01:00
|
|
|
) -> Self {
|
|
|
|
let state = Arc::new(RwLock::new(StringEditorState{
|
2021-01-06 21:35:46 +01:00
|
|
|
cursor: 7,
|
|
|
|
data: Arc::new(RwLock::new("edit me".chars().collect()))
|
2020-12-14 19:36:21 +01:00
|
|
|
}));
|
2021-01-06 21:35:46 +01:00
|
|
|
|
|
|
|
let cast = port.set_view(Some(state.clone()));
|
|
|
|
|
2020-12-14 19:36:21 +01:00
|
|
|
StringEditor {
|
|
|
|
state,
|
2021-01-06 21:35:46 +01:00
|
|
|
cast
|
2020-12-14 19:36:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn next(&mut self) {
|
|
|
|
let cur = self.state.read().unwrap().cursor;
|
|
|
|
self.goto(cur + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn prev(&mut self) {
|
|
|
|
let cur = self.state.read().unwrap().cursor;
|
|
|
|
if cur > 0 {
|
|
|
|
self.goto(cur - 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn goto_end(&mut self) {
|
|
|
|
let l = self.state.read().unwrap().data.read().unwrap().len();
|
|
|
|
self.goto(l);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn goto(&mut self, mut new_idx: usize) {
|
|
|
|
let old_idx = {
|
|
|
|
let mut state = self.state.write().unwrap();
|
|
|
|
let old_idx = state.cursor.clone();
|
|
|
|
let len = state.data.read().unwrap().len();
|
|
|
|
new_idx = std::cmp::min(new_idx, len);
|
|
|
|
state.cursor = new_idx;
|
|
|
|
old_idx
|
|
|
|
};
|
|
|
|
|
2021-01-06 21:35:46 +01:00
|
|
|
self.cast.notify_each(
|
2020-12-14 19:36:21 +01:00
|
|
|
(std::cmp::min(old_idx, new_idx) ..= std::cmp::max(old_idx, new_idx))
|
2021-01-06 21:35:46 +01:00
|
|
|
.map(|idx| Point2::new(1+idx as i16, 0))
|
2020-12-14 19:36:21 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn insert(&mut self, c: char) {
|
2021-01-06 21:35:46 +01:00
|
|
|
self.cast.notify_each({
|
2021-01-16 16:09:16 +01:00
|
|
|
let state = self.state.write().unwrap();
|
2020-12-14 19:36:21 +01:00
|
|
|
let mut data = state.data.write().unwrap();
|
|
|
|
|
|
|
|
data.insert(state.cursor, c);
|
2021-01-16 16:09:16 +01:00
|
|
|
|
|
|
|
state.cursor .. data.len()+2
|
2021-01-06 21:35:46 +01:00
|
|
|
}.map(|idx| Point2::new(1+idx as i16, 0)));
|
2020-12-14 19:36:21 +01:00
|
|
|
|
|
|
|
self.next();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn delete(&mut self) {
|
2021-01-06 21:35:46 +01:00
|
|
|
self.cast.notify_each({
|
2021-01-16 16:09:16 +01:00
|
|
|
let state = self.state.write().unwrap();
|
2020-12-14 19:36:21 +01:00
|
|
|
let mut data = state.data.write().unwrap();
|
|
|
|
|
|
|
|
if state.cursor < data.len() {
|
|
|
|
data.remove(state.cursor);
|
|
|
|
}
|
2021-01-16 16:09:16 +01:00
|
|
|
|
|
|
|
state.cursor .. data.len()+3
|
2021-01-06 21:35:46 +01:00
|
|
|
}.map(|idx| Point2::new(1+idx as i16, 0)));
|
2020-12-14 19:36:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|