lib-nested/nested/src/product/editor.rs
2022-12-18 01:39:01 +01:00

248 lines
8.8 KiB
Rust

use {
crate::{
core::{OuterViewPort, TypeLadder, Context},
terminal::{
TerminalEditor, TerminalEditorResult,
TerminalEvent, TerminalView
},
vec::{VecBuffer},
index::{buffer::{IndexBuffer, MutableIndexAccess}},
list::ListCursorMode,
product::{segment::ProductEditorSegment},
sequence::{SequenceView},
tree::{TreeNav, TreeNavResult},
diagnostics::{Diagnostics},
terminal::{TerminalStyle},
Nested
},
cgmath::{Point2},
std::sync::{Arc, RwLock},
termion::event::{Event, Key},
std::ops::{DerefMut}
};
pub struct ProductEditor {
msg_buf: VecBuffer<Option<OuterViewPort<dyn SequenceView<Item = crate::diagnostics::Message>>>>,
msg_port: OuterViewPort<dyn SequenceView<Item = crate::diagnostics::Message>>,
segments: IndexBuffer<Point2<i16>, ProductEditorSegment>,
pub(super) n_indices: Vec<Point2<i16>>,
pub(super) ctx: Arc<RwLock<Context>>,
pub(super) cursor: Option<isize>,
pub(super) depth: usize,
}
impl ProductEditor {
pub fn new(depth: usize, ctx: Arc<RwLock<Context>>) -> Self {
let msg_buf = VecBuffer::new();
ProductEditor {
segments: IndexBuffer::new(),
msg_port: msg_buf.get_port()
.to_sequence()
.enumerate()
.filter_map(|(idx, msgs): &(usize, Option<OuterViewPort<dyn SequenceView<Item = crate::diagnostics::Message>>>)| {
let idx = *idx;
if let Some(msgs) = msgs {
Some(msgs.map(
move |msg| {
let mut msg = msg.clone();
msg.addr.insert(0, idx);
msg
}))
} else {
None
}
})
.flatten(),
msg_buf,
n_indices: Vec::new(),
ctx,
cursor: None,
depth
}
}
pub fn with_t(mut self, pos: Point2<i16>, t: &str) -> Self {
self.segments.insert(pos, ProductEditorSegment::T(t.to_string(), self.depth));
self
}
pub fn with_n(mut self, pos: Point2<i16>, n: TypeLadder) -> Self {
self.segments.insert(pos, ProductEditorSegment::N{
t: n.clone(),
editor: None,
ed_depth: self.depth + 1,
cur_depth: 0,
cur_dist: isize::MAX
});
self.n_indices.push(pos);
let mut b = VecBuffer::new();
b.push(crate::diagnostics::make_todo(crate::terminal::make_label(&format!("complete {}", self.ctx.read().unwrap().type_term_to_str(&n[0])))));
self.msg_buf.push(Some(b.get_port().to_sequence()));
self
}
pub fn get_editor_segment(&self, mut idx: isize) -> ProductEditorSegment {
idx = crate::modulo(idx, self.n_indices.len() as isize);
if let Some(pos) = self.n_indices.get(idx as usize) {
self.segments.get(pos).unwrap()
} else {
unreachable!()
}
}
pub fn get_editor_segment_mut(&mut self, mut idx: isize) -> MutableIndexAccess<Point2<i16>, ProductEditorSegment> {
idx = crate::modulo(idx, self.n_indices.len() as isize);
if let Some(pos) = self.n_indices.get(idx as usize) {
self.segments.get_mut(pos)
} else {
unreachable!()
}
}
pub fn get_cur_segment(&self) -> Option<ProductEditorSegment> {
Some(self.get_editor_segment(self.cursor?))
}
pub fn get_cur_segment_mut(&mut self) -> Option<MutableIndexAccess<Point2<i16>, ProductEditorSegment>> {
Some(self.get_editor_segment_mut(self.cursor?))
}
pub fn get_editor(&self, idx: isize) -> Option<Arc<RwLock<dyn Nested + Send + Sync>>> {
if let ProductEditorSegment::N{ t: _, editor, ed_depth: _, cur_depth: _, cur_dist: _ } = self.get_editor_segment(idx) {
editor
} else {
unreachable!()
}
}
pub fn get_cur_editor(&self) -> Option<Arc<RwLock<dyn Nested + Send + Sync>>> {
self.get_editor(self.cursor?)
}
pub fn set_leaf_mode(&mut self, mode: ListCursorMode) {
let mut c = self.get_cursor();
c.leaf_mode = mode;
self.goto(c);
}
pub fn update_segment(&mut self, idx: isize) {
if let Some(ProductEditorSegment::N{ t, editor, ed_depth: _, cur_depth, cur_dist }) = self.get_editor_segment_mut(idx).deref_mut() {
let cur = self.get_cursor();
if cur.tree_addr.len() > 0 {
if cur.tree_addr[0] == idx {
*cur_depth = cur.tree_addr.len();
}
*cur_dist = cur.tree_addr[0] - idx
} else {
*cur_dist = isize::MAX;
};
if let Some(e) = editor {
self.msg_buf.update(idx as usize, Some(e.read().unwrap().get_msg_port()));
} else {
let mut b = VecBuffer::new();
b.push(crate::diagnostics::make_todo(crate::terminal::make_label(&format!("complete {}", self.ctx.read().unwrap().type_term_to_str(&t[0])))));
self.msg_buf.update(idx as usize, Some(b.get_port().to_sequence()));
if cur.tree_addr.len() > 0 {
if cur.tree_addr[0] == idx {
self.msg_buf.update(idx as usize, Some(b.get_port().to_sequence().map(
|msg| {
let mut msg = msg.clone();
msg.port = msg.port.map_item(|_p,a| a.add_style_back(TerminalStyle::bg_color((40,40,40))));
msg
}
)));
}
}
}
} else {
unreachable!()
}
}
pub fn update_cur_segment(&mut self) {
if let Some(c) = self.cursor {
self.update_segment(c);
}
}
}
impl TerminalEditor for ProductEditor {
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
let ctx = self.ctx.clone();
self.segments
.get_port()
.map_item(move |_pos, e: &ProductEditorSegment| { e.get_view(ctx.clone()) })
.flatten()
}
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
let mut update_segment = false;
let result = if let Some(mut segment) = self.get_cur_segment_mut().as_deref_mut() {
if let Some(ProductEditorSegment::N{ t, editor, ed_depth, cur_depth, cur_dist: _ }) = segment.deref_mut() {
*cur_depth = self.get_cursor().tree_addr.len();
if let Some(e) = editor.clone() {
let mut ce = e.write().unwrap();
match ce.handle_terminal_event(event) {
TerminalEditorResult::Exit =>
match event {
TerminalEvent::Input(Event::Key(Key::Backspace)) => {
*editor = None;
update_segment = true;
TerminalEditorResult::Continue
}
_ => {
*cur_depth = ce.get_cursor().tree_addr.len();
drop(ce);
match self.nexd() {
TreeNavResult::Continue => TerminalEditorResult::Continue,
TreeNavResult::Exit => TerminalEditorResult::Exit
}
}
},
TerminalEditorResult::Continue => {
*cur_depth = ce.get_cursor().tree_addr.len();
TerminalEditorResult::Continue
}
}
} else {
let e = Context::make_editor(self.ctx.clone(), t[0].clone(), *ed_depth+1).unwrap();
*editor = Some(e.clone());
update_segment = true;
e.write().unwrap().dn();
let x = e.write().unwrap().handle_terminal_event(event);
x
}
} else {
unreachable!();
}
} else {
TerminalEditorResult::Exit
};
if update_segment {
self.update_cur_segment();
}
result
}
}
impl Diagnostics for ProductEditor {
fn get_msg_port(&self) -> OuterViewPort<dyn SequenceView<Item = crate::diagnostics::Message>> {
self.msg_port.clone()
}
}