implement tree cursor widget as projection pipeline

This commit is contained in:
Michael Sippel 2023-01-07 04:37:44 +01:00
parent a9550600f4
commit 47b8900adc
Signed by: senvas
GPG key ID: F96CF119C34B64A6
9 changed files with 191 additions and 89 deletions

View file

@ -4,6 +4,12 @@ pub enum ListCursorMode {
Select Select
} }
impl Default for ListCursorMode {
fn default() -> Self {
ListCursorMode::Select
}
}
#[derive(Clone, Copy, Eq, PartialEq)] #[derive(Clone, Copy, Eq, PartialEq)]
pub struct ListCursor { pub struct ListCursor {
pub mode: ListCursorMode, pub mode: ListCursorMode,

View file

@ -6,11 +6,12 @@ use {
ListCursor, ListCursor,
ListSegment, ListSegment,
ListSegmentSequence, ListSegmentSequence,
ListCursorMode
}, },
sequence::{SequenceView}, sequence::{SequenceView},
singleton::{SingletonBuffer, SingletonView}, singleton::{SingletonBuffer, SingletonView},
terminal::{TerminalView}, terminal::{TerminalView},
tree::NestedNode, tree::{NestedNode, TreeNav},
vec::{VecBuffer, MutableVecAccess}, vec::{VecBuffer, MutableVecAccess},
PtySegment PtySegment
}, },
@ -23,6 +24,9 @@ pub struct ListEditor {
pub(super) cursor: SingletonBuffer<ListCursor>, pub(super) cursor: SingletonBuffer<ListCursor>,
pub(crate) data: VecBuffer<NestedNode>, pub(crate) data: VecBuffer<NestedNode>,
pub(super) addr_port: OuterViewPort<dyn SequenceView<Item = isize>>,
pub(super) mode_port: OuterViewPort<dyn SingletonView<Item = ListCursorMode>>,
pub(crate) ctx: Arc<RwLock<Context>>, pub(crate) ctx: Arc<RwLock<Context>>,
pub(super) typ: TypeTerm, pub(super) typ: TypeTerm,
pub(super) depth: usize, pub(super) depth: usize,
@ -35,9 +39,67 @@ impl ListEditor {
typ: TypeTerm, typ: TypeTerm,
depth: usize depth: usize
) -> Self { ) -> Self {
let mut cursor = SingletonBuffer::new(ListCursor::default());
let mut data = VecBuffer::<NestedNode>::new();
ListEditor { ListEditor {
cursor: SingletonBuffer::new(ListCursor::default()), mode_port: cursor
data: VecBuffer::<NestedNode>::new(), .get_port()
.map({
let data = data.clone();
move |c| {
let ip = SingletonBuffer::new(c.mode).get_port();
match c.mode {
ListCursorMode::Insert => ip,
ListCursorMode::Select => {
if let Some(idx) = c.idx {
data.get(idx as usize).get_mode_view()
} else {
ip
}
}
}
}
})
.flatten(),
addr_port: VecBuffer::<OuterViewPort<dyn SequenceView<Item = isize>>>::with_data(
vec![
cursor.get_port()
.map(
|x| {
// todo implement this with filter_map
let mut b = VecBuffer::new();
if let Some(i) = x.idx {
b.push(i);
}
b.get_port().to_sequence()
}
)
.to_sequence()
.flatten(),
cursor.get_port()
.map({
let data = data.clone();
move |cur| {
if cur.mode == ListCursorMode::Select {
if let Some(idx) = cur.idx {
if idx >= 0 && idx < data.len() as isize {
return data.get(idx as usize).get_addr_view();
}
}
}
OuterViewPort::default()
}
})
.to_sequence()
.flatten()
])
.get_port()
.to_sequence()
.flatten(),
cursor,
data,
ctx, ctx,
typ, typ,
depth, depth,
@ -77,6 +139,7 @@ impl ListEditor {
None None
} }
} }
pub fn get_item_mut(&mut self) -> Option<MutableVecAccess<NestedNode>> { pub fn get_item_mut(&mut self) -> Option<MutableVecAccess<NestedNode>> {
if let Some(idx) = self.cursor.get().idx { if let Some(idx) = self.cursor.get().idx {
let idx = crate::utils::modulo(idx as isize, self.data.len() as isize) as usize; let idx = crate::utils::modulo(idx as isize, self.data.len() as isize) as usize;

View file

@ -1,10 +1,13 @@
use { use {
crate::{ crate::{
core::{OuterViewPort},
sequence::{SequenceView},
list::{ list::{
ListCursor, ListCursorMode, ListCursor, ListCursorMode,
ListEditor ListEditor
}, },
tree::{TreeCursor, TreeNav, TreeNavResult}, tree::{TreeCursor, TreeNav, TreeNavResult},
singleton::SingletonView,
Nested Nested
}, },
cgmath::Vector2 cgmath::Vector2
@ -13,6 +16,14 @@ use {
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl TreeNav for ListEditor { impl TreeNav for ListEditor {
fn get_addr_view(&self) -> OuterViewPort<dyn SequenceView<Item = isize>> {
self.addr_port.clone()
}
fn get_mode_view(&self) -> OuterViewPort<dyn SingletonView<Item = ListCursorMode>> {
self.mode_port.clone()
}
fn get_cursor_warp(&self) -> TreeCursor { fn get_cursor_warp(&self) -> TreeCursor {
let cur = self.cursor.get(); let cur = self.cursor.get();
match cur.mode { match cur.mode {

View file

@ -52,11 +52,11 @@ where
type Item = SrcView::Item; type Item = SrcView::Item;
fn get(&self, _idx: &usize) -> Option<Self::Item> { fn get(&self, _idx: &usize) -> Option<Self::Item> {
Some(self.src_view.as_ref().unwrap().get()) Some(self.src_view.as_ref()?.get())
} }
fn len(&self) -> Option<usize> { fn len(&self) -> Option<usize> {
Some(1) Some(if self.src_view.is_some() { 1 } else { 0 })
} }
} }

View file

@ -40,11 +40,9 @@ use {
}; };
pub fn make_label(s: &str) -> OuterViewPort<dyn TerminalView> { pub fn make_label(s: &str) -> OuterViewPort<dyn TerminalView> {
let label_port = ViewPort::new(); let label = VecBuffer::with_data(s.chars().collect());
let _label = VecBuffer::with_data(s.chars().collect(), label_port.inner());
let v = label_port let v = label.get_port()
.outer()
.to_sequence() .to_sequence()
.map(|c| TerminalAtom::from(c)) .map(|c| TerminalAtom::from(c))
.to_index() .to_index()
@ -55,3 +53,21 @@ pub fn make_label(s: &str) -> OuterViewPort<dyn TerminalView> {
v v
} }
impl OuterViewPort<dyn TerminalView> {
pub fn with_style(&self, style: TerminalStyle) -> OuterViewPort<dyn TerminalView> {
self.map_item(
move |_idx, a|
a.add_style_front(style)
)
}
pub fn with_fg_color(&self, col: (u8, u8, u8)) -> OuterViewPort<dyn TerminalView> {
self.with_style(TerminalStyle::fg_color(col))
}
pub fn with_bg_color(&self, col: (u8, u8, u8)) -> OuterViewPort<dyn TerminalView> {
self.with_style(TerminalStyle::bg_color(col))
}
}

View file

@ -1,7 +1,15 @@
use { use {
crate::list::ListCursorMode, crate::list::ListCursorMode,
crate::tree::TreeCursor, crate::tree::TreeCursor,
cgmath::Vector2 crate::vec::VecBuffer,
crate::core::{OuterViewPort},
crate::sequence::{SequenceView, decorator::Separate},
crate::singleton::{SingletonBuffer, SingletonView},
cgmath::Vector2,
crate::{
terminal::{TerminalView, TerminalStyle, make_label}
}
}; };
#[derive(Clone, Copy, Eq, PartialEq)] #[derive(Clone, Copy, Eq, PartialEq)]
@ -21,6 +29,8 @@ impl From<TreeNavResult> for TerminalEditorResult {
} }
*/ */
pub trait TreeNav { pub trait TreeNav {
/* CORE /* CORE
*/ */
@ -28,6 +38,14 @@ pub trait TreeNav {
TreeCursor::default() TreeCursor::default()
} }
fn get_addr_view(&self) -> OuterViewPort<dyn SequenceView<Item = isize>> {
VecBuffer::<isize>::new().get_port().to_sequence()
}
fn get_mode_view(&self) -> OuterViewPort<dyn SingletonView<Item = ListCursorMode>> {
SingletonBuffer::new(ListCursorMode::Select).get_port()
}
fn get_cursor_warp(&self) -> TreeCursor { fn get_cursor_warp(&self) -> TreeCursor {
TreeCursor::default() TreeCursor::default()
} }
@ -124,5 +142,35 @@ pub trait TreeNav {
} }
} }
} }
fn get_cursor_widget(&self) -> OuterViewPort<dyn TerminalView> {
VecBuffer::with_data(
vec![
make_label("@").with_fg_color((150, 80,230)),
self.get_addr_view()
.map(|i|
make_label(&format!("{}", i)).with_fg_color((0, 100, 20)))
.separate(make_label(".").with_fg_color((150, 80,230)))
.to_grid_horizontal()
.flatten(),
make_label(":").with_fg_color((150, 80,230)),
self.get_mode_view()
.map(|mode| {
make_label(
match mode {
ListCursorMode::Insert => "INSERT",
ListCursorMode::Select => "SELECT"
})
.with_fg_color((200, 200, 20))
})
.to_grid()
.flatten(),
make_label(":").with_fg_color((150, 80,230))
]
).get_port()
.to_sequence()
.to_grid_horizontal()
.flatten()
}
} }

View file

@ -4,12 +4,14 @@ use {
crate::{ crate::{
core::{ViewPort, OuterViewPort, AnyOuterViewPort}, core::{ViewPort, OuterViewPort, AnyOuterViewPort},
type_system::{ReprTree, Context}, type_system::{ReprTree, Context},
singleton::{SingletonBuffer}, singleton::{SingletonBuffer, SingletonView},
sequence::SequenceView, sequence::SequenceView,
terminal::{TerminalView, TerminalEvent, TerminalEditor, TerminalEditorResult}, terminal::{TerminalView, TerminalEvent, TerminalEditor, TerminalEditorResult},
diagnostics::{Diagnostics, Message}, diagnostics::{Diagnostics, Message},
tree::{TreeNav, TreeCursor, TreeNavResult}, tree::{TreeNav, TreeCursor, TreeNavResult},
list::{ListCursorMode},
commander::ObjCommander, commander::ObjCommander,
vec::VecBuffer,
Nested Nested
} }
}; };
@ -62,6 +64,22 @@ impl TreeNav for NestedNode {
} }
} }
fn get_addr_view(&self) -> OuterViewPort<dyn SequenceView<Item = isize>> {
if let Some(tn) = self.tree_nav.as_ref() {
tn.read().unwrap().get_addr_view()
} else {
OuterViewPort::default()
}
}
fn get_mode_view(&self) -> OuterViewPort<dyn SingletonView<Item = ListCursorMode>> {
if let Some(tn) = self.tree_nav.as_ref() {
tn.read().unwrap().get_mode_view()
} else {
OuterViewPort::default()
}
}
fn get_cursor_warp(&self) -> TreeCursor { fn get_cursor_warp(&self) -> TreeCursor {
if let Some(tn) = self.tree_nav.as_ref() { if let Some(tn) = self.tree_nav.as_ref() {
tn.read().unwrap().get_cursor_warp() tn.read().unwrap().get_cursor_warp()

View file

@ -34,7 +34,7 @@ impl<T> VecBuffer<T>
where where
T: Clone + Send + Sync + 'static, T: Clone + Send + Sync + 'static,
{ {
pub fn with_data(data: Vec<T>, port: InnerViewPort<RwLock<Vec<T>>>) -> Self { pub fn with_data_port(data: Vec<T>, port: InnerViewPort<RwLock<Vec<T>>>) -> Self {
let data = Arc::new(RwLock::new(data)); let data = Arc::new(RwLock::new(data));
port.set_view(Some(data.clone())); port.set_view(Some(data.clone()));
@ -48,8 +48,12 @@ where
} }
} }
pub fn with_data(data: Vec<T>) -> Self {
VecBuffer::with_data_port(data, ViewPort::new().into_inner())
}
pub fn with_port(port: InnerViewPort<RwLock<Vec<T>>>) -> Self { pub fn with_port(port: InnerViewPort<RwLock<Vec<T>>>) -> Self {
VecBuffer::with_data(vec![], port) VecBuffer::with_data_port(vec![], port)
} }
pub fn new() -> Self { pub fn new() -> Self {

View file

@ -13,6 +13,7 @@ use {
core::{port::UpdateTask, Observer, AnyOuterViewPort, ViewPort}, core::{port::UpdateTask, Observer, AnyOuterViewPort, ViewPort},
type_system::{Context, ReprTree}, type_system::{Context, ReprTree},
index::IndexArea, index::IndexArea,
singleton::{SingletonView, SingletonBuffer},
list::{ListCursorMode, PTYListEditor}, list::{ListCursorMode, PTYListEditor},
sequence::{decorator::{SeqDecorStyle, Separate}}, sequence::{decorator::{SeqDecorStyle, Separate}},
terminal::{ terminal::{
@ -121,14 +122,10 @@ async fn main() {
}); });
let mut cur_size = nested::singleton::SingletonBuffer::new(Vector2::new(10, 10)); let mut cur_size = nested::singleton::SingletonBuffer::new(Vector2::new(10, 10));
let mut status_chars = VecBuffer::new();
table.insert_iter(vec![ table.insert_iter(vec![
(Point2::new(0, 0), magic.clone()), (Point2::new(0, 0), magic.clone()),
( (Point2::new(0, 1), process_list_editor.editor.read().unwrap().get_cursor_widget()),
Point2::new(0, 1),
status_chars.get_port().to_sequence().to_grid_horizontal(),
),
(Point2::new(0, 2), magic.clone()), (Point2::new(0, 2), magic.clone()),
(Point2::new(0, 3), make_label(" ")), (Point2::new(0, 3), make_label(" ")),
(Point2::new(0, 4), (Point2::new(0, 4),
@ -162,12 +159,7 @@ async fn main() {
) )
.separate({ .separate({
let mut buf = IndexBuffer::new(); let mut buf = IndexBuffer::new();
buf.insert(Point2::new(1,0), buf.insert(Point2::new(1,0), make_label(" ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~").with_fg_color((40,40,40))
make_label(" ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~")
.map_item(
|p,a|
a.add_style_front(TerminalStyle::fg_color((40,40,40)))
)
); );
buf.get_port() buf.get_port()
}) })
@ -183,17 +175,14 @@ async fn main() {
|entry| { |entry| {
let mut b = VecBuffer::new(); let mut b = VecBuffer::new();
b.push( b.push(
make_label("@") make_label("@").with_style(
.map_item(|_p,a| a TerminalStyle::bold(true)
.add_style_back(TerminalStyle::bold(true)) .add(TerminalStyle::fg_color((120,120,0))))
.add_style_back(TerminalStyle::fg_color((120,120,0))))
); );
for x in entry.addr.iter() { for x in entry.addr.iter() {
b.push( b.push(
make_label(&format!("{}", x)) make_label(&format!("{}", x)).with_fg_color((0, 100, 20))
.map_item(|_p,a| a
.add_style_back(TerminalStyle::fg_color((0, 100, 20))))
); );
b.push( b.push(
make_label(".") make_label(".")
@ -222,12 +211,7 @@ async fn main() {
]); ]);
let (_w, _h) = termion::terminal_size().unwrap(); let (_w, _h) = termion::terminal_size().unwrap();
/*
compositor
.write()
.unwrap()
.push(monstera::make_monstera().offset(Vector2::new(w as i16 - 38, 0)));
*/
compositor compositor
.write() .write()
.unwrap() .unwrap()
@ -307,54 +291,6 @@ async fn main() {
process_list_editor.send_cmd(&ev); process_list_editor.send_cmd(&ev);
} }
} }
status_chars.clear();
let cur = process_list_editor.editor.read().unwrap().get_cursor();
if cur.tree_addr.len() > 0 {
status_chars.push(TerminalAtom::new(
'@',
TerminalStyle::fg_color((150, 80,230)).add(TerminalStyle::bold(true)),
));
for x in cur.tree_addr {
for c in format!("{}", x).chars() {
status_chars
.push(TerminalAtom::new(c, TerminalStyle::fg_color((0, 100, 20))));
}
status_chars.push(TerminalAtom::new(
'.',
TerminalStyle::fg_color((150, 80,230))
));
}
status_chars.push(TerminalAtom::new(
':',
TerminalStyle::fg_color((150, 80,230)).add(TerminalStyle::bold(true)),
));
for c in match cur.leaf_mode {
ListCursorMode::Insert => "INSERT",
ListCursorMode::Select => "SELECT"
}
.chars()
{
status_chars.push(TerminalAtom::new(
c,
TerminalStyle::fg_color((200, 200, 20)),
));
}
status_chars.push(TerminalAtom::new(
':',
TerminalStyle::fg_color((150, 80,230)).add(TerminalStyle::bold(true)),
));
} else {
for c in "Press <DN> to enter".chars() {
status_chars.push(TerminalAtom::new(
c,
TerminalStyle::fg_color((200, 200, 20)),
));
}
}
} }
drop(term); drop(term);