listeditor cleanup

This commit is contained in:
Michael Sippel 2022-06-19 23:13:21 +02:00
parent d6fe977183
commit 5fef75e24f
Signed by: senvas
GPG key ID: F96CF119C34B64A6
25 changed files with 1342 additions and 1581 deletions

68
nested/src/char_editor.rs Normal file
View file

@ -0,0 +1,68 @@
use {
crate::{
core::{OuterViewPort, ViewPort},
list::{ListEditor},
sequence::{SequenceView, SequenceViewExt},
singleton::{SingletonBuffer, SingletonView},
terminal::{
TerminalAtom, TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle,
TerminalView,
},
tree_nav::{TerminalTreeEditor, TreeCursor, TreeNav, TreeNavResult},
},
std::sync::Arc,
std::sync::RwLock,
termion::event::{Event, Key},
cgmath::Vector2
};
pub struct CharEditor {
data: SingletonBuffer<Option<char>>
}
impl CharEditor {
pub fn new() -> Self {
CharEditor {
data: SingletonBuffer::new(None)
}
}
pub fn get_port(&self) -> OuterViewPort<dyn SingletonView<Item = Option<char>>> {
self.data.get_port()
}
}
impl TreeNav for CharEditor {}
impl TerminalEditor for CharEditor {
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
self.data
.get_port()
.map(move |c| {
TerminalAtom::new(
c.unwrap_or('?'),
TerminalStyle::fg_color((100, 140, 100)),
)
})
.to_grid()
}
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
match event {
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => TerminalEditorResult::Exit,
TerminalEvent::Input(Event::Key(Key::Char(c))) => {
self.data.set(Some(*c));
TerminalEditorResult::Exit
}
TerminalEvent::Input(Event::Key(Key::Backspace))
| TerminalEvent::Input(Event::Key(Key::Delete)) => {
self.data.set(None);
TerminalEditorResult::Exit
}
_ => TerminalEditorResult::Exit,
}
}
}
impl TerminalTreeEditor for CharEditor {}

25
nested/src/color.rs Normal file
View file

@ -0,0 +1,25 @@
use {
crate::terminal::TerminalStyle,
};
pub fn bg_style_from_depth(depth: usize) -> TerminalStyle {
if depth == 0 {
TerminalStyle::default()
} else {
TerminalStyle::bg_color((
(30.0 / ( 0.90*depth as f64 )) as u8,
(30.0 / ( 0.93*depth as f64 )) as u8,
(50.0 / ( 0.95*depth as f64 )) as u8
))
}
}
pub fn fg_style_from_depth(depth: usize) -> TerminalStyle {
match depth % 3 {
0 => TerminalStyle::fg_color((200, 200, 80)),
1 => TerminalStyle::fg_color((80, 200, 200)),
2 => TerminalStyle::fg_color((150, 150, 200)),
_ => TerminalStyle::default()
}
}

View file

@ -1,6 +1,6 @@
use {
crate::{
core::{InnerViewPort, ViewPort, Observer, ObserverBroadcast, View},
core::{InnerViewPort, OuterViewPort, ViewPort, Observer, ObserverBroadcast, View},
index::{IndexArea, IndexView},
},
std::sync::RwLock,
@ -64,6 +64,10 @@ where
IndexBuffer::with_port(ViewPort::new().into_inner())
}
pub fn get_port(&self) -> OuterViewPort<dyn IndexView<Key, Item = Item>> {
self.port.0.outer()
}
pub fn insert(&mut self, key: Key, item: Item) {
self.data.write().unwrap().insert(key.clone(), item);
self.port.notify(&IndexArea::Set(vec![key]));

View file

@ -127,6 +127,9 @@ impl TreeNav for PosIntEditor {
fn get_cursor(&self) -> TreeCursor {
self.digits_editor.get_cursor()
}
fn get_cursor_warp(&self) -> TreeCursor {
self.digits_editor.get_cursor_warp()
}
fn goto(&mut self, cur: TreeCursor) -> TreeNavResult {
self.digits_editor.goto(cur)
}

View file

@ -1,24 +1,34 @@
#![feature(trait_alias)]
// general
pub mod core;
pub mod projection;
pub mod bimap;
pub mod modulo;
pub use modulo::modulo;
pub mod grid;
// semantics
pub mod singleton;
pub mod sequence;
pub mod index;
pub mod integer;
pub mod grid;
// implementation
pub mod vec;
// editors
pub mod tree_nav;
pub mod product;
pub mod list;
pub mod sequence;
pub mod singleton;
pub mod terminal;
pub mod vec;
// high-level types
pub mod char_editor;
pub mod integer;
pub mod make_editor;
pub mod tree_nav;
pub mod string_editor;
pub mod bimap;
// display
pub mod color;
pub mod terminal;
pub fn magic_header() {
eprintln!("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>");

View file

@ -1,33 +1,34 @@
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum ListCursorMode {
Insert,
Select,
Modify,
Select
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct ListCursor {
pub mode: ListCursorMode,
pub idx: Option<usize>,
pub idx: Option<isize>,
}
impl ListCursor {
pub fn home() -> Self {
ListCursor {
mode: ListCursorMode::Insert,
idx: Some(0)
}
}
pub fn none() -> Self {
ListCursor {
mode: ListCursorMode::Insert,
idx: None,
}
}
}
impl Default for ListCursor {
fn default() -> Self {
ListCursor {
mode: ListCursorMode::Select,
idx: None,
}
ListCursor::none()
}
}
/*
pub trait ListNav {
fn pxev(&mut self) -> ListNavResult;
fn nexd(&mut self) -> ListNavResult;
fn pua(&mut self) -> ListNavResult;
fn end(&mut self) -> ListNavResult;
fn set_cursor(&mut self, new_cursor: Option<ListCursor>) -> ListNavResult;
fn get_cursor(&self) -> Option<ListCursor>;
}
*/

View file

@ -2,10 +2,11 @@ use {
crate::{
core::{OuterViewPort, ViewPort},
list::{
editor_view::{ListEditorView, ListEditorViewSegment},
ListCursor, ListCursorMode, ListDecoration, SExprView,
ListCursor, ListCursorMode,
ListSegment, ListSegmentSequence,
segment::PTYSegment
},
sequence::SequenceView,
sequence::{SequenceView},
singleton::{SingletonBuffer, SingletonView},
terminal::{
make_label, TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle,
@ -13,696 +14,62 @@ use {
},
tree_nav::{TerminalTreeEditor, TreeCursor, TreeNav, TreeNavResult},
vec::VecBuffer,
color::{bg_style_from_depth, fg_style_from_depth}
},
std::sync::{Arc, RwLock},
termion::event::{Event, Key},
};
#[derive(Clone, Copy)]
pub enum ListEditorStyle {
HorizontalSexpr,
VerticalSexpr,
Tuple(usize),
Path,
String,
Clist,
Hex,
Plain,
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct ListEditor<ItemEditor>
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static
{
pub(super) cursor: SingletonBuffer<ListCursor>,
pub(super) data: VecBuffer<Arc<RwLock<ItemEditor>>>,
pub(super) make_item_editor: Box<dyn Fn() -> Arc<RwLock<ItemEditor>> + Send + Sync>,
pub(super) depth: usize,
pub(super) cur_dist: Arc<RwLock<usize>>,
}
pub struct ListEditor<ItemEditor, FnMakeItemEditor>
where
ItemEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
FnMakeItemEditor: Fn() -> Arc<RwLock<ItemEditor>>,
impl<ItemEditor> ListEditor<ItemEditor>
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static
{
cursor: SingletonBuffer<ListCursor>,
data: VecBuffer<Arc<RwLock<ItemEditor>>>,
cursor_port: ViewPort<dyn SingletonView<Item = ListCursor>>,
data_port: ViewPort<RwLock<Vec<Arc<RwLock<ItemEditor>>>>>,
make_item_editor: FnMakeItemEditor,
style: ListEditorStyle,
_level: usize,
cur_dist: Arc<RwLock<usize>>,
}
impl<ItemEditor, FnMakeItemEditor> TreeNav for ListEditor<ItemEditor, FnMakeItemEditor>
where
ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
FnMakeItemEditor: Fn() -> Arc<RwLock<ItemEditor>>,
{
fn get_cursor(&self) -> TreeCursor {
let cur = self.cursor.get();
match cur.mode {
ListCursorMode::Insert | ListCursorMode::Select => TreeCursor {
leaf_mode: cur.mode,
tree_addr: if let Some(i) = cur.idx {
vec![i]
} else {
vec![]
},
},
ListCursorMode::Modify => {
if let Some(i) = cur.idx {
if i < self.data.len() {
let mut sub_cur = self.data.get(i).read().unwrap().get_cursor();
sub_cur.tree_addr.insert(0, i);
return sub_cur;
}
}
TreeCursor {
leaf_mode: cur.mode,
tree_addr: vec![],
}
}
pub fn new(make_item_editor: impl Into<Box<dyn Fn() -> Arc<RwLock<ItemEditor>> + Send + Sync>>, depth: usize) -> Self {
ListEditor {
cursor: SingletonBuffer::new(ListCursor::default()),
data: VecBuffer::<Arc<RwLock<ItemEditor>>>::new(),
make_item_editor: make_item_editor.into(),
depth,
cur_dist: Arc::new(RwLock::new(0)),
}
}
fn goto(&mut self, new_cur: TreeCursor) -> TreeNavResult {
let old_cur = self.cursor.get();
if old_cur.mode == ListCursorMode::Modify {
if let Some(i) = old_cur.idx {
let ce = self.data.get_mut(i);
let mut cur_edit = ce.write().unwrap();
cur_edit.goto(TreeCursor::default());
}
}
if new_cur.tree_addr.len() == 1 {
self.cursor.set(ListCursor {
mode: new_cur.leaf_mode,
idx: Some(new_cur.tree_addr[0]),
});
TreeNavResult::Continue
} else if new_cur.tree_addr.len() > 1 && new_cur.tree_addr[0] < self.data.len() {
self.cursor.set(ListCursor {
mode: ListCursorMode::Modify,
idx: Some(new_cur.tree_addr[0]),
});
let ne = self.data.get_mut(new_cur.tree_addr[0]);
let mut nxt_edit = ne.write().unwrap();
nxt_edit.goto(TreeCursor {
leaf_mode: new_cur.leaf_mode,
tree_addr: new_cur.tree_addr[1..].iter().cloned().collect(),
});
TreeNavResult::Continue
} else {
self.cursor.set(ListCursor {
mode: new_cur.leaf_mode,
idx: None,
});
TreeNavResult::Continue
}
}
fn goto_end(&mut self) -> TreeNavResult {
let mut cur = self.cursor.get();
let i = cur.idx.unwrap_or(0);
if self.data.len() == 0 && cur.idx.is_none() {
self.cursor.set(ListCursor {
mode: ListCursorMode::Insert,
idx: Some(0),
});
return TreeNavResult::Continue;
}
if i < self.data.len() {
match cur.mode {
ListCursorMode::Insert => {
if i < self.data.len() || cur.idx.is_none() {
cur.idx = Some(self.data.len());
self.cursor.set(cur);
TreeNavResult::Continue
} else {
self.cursor.set(ListCursor::default());
TreeNavResult::Exit
}
}
ListCursorMode::Select => {
if self.data.len() == 0 && cur.idx.is_none() {
self.cursor.set(ListCursor {
mode: ListCursorMode::Insert,
idx: Some(0),
});
return TreeNavResult::Continue;
}
if i + 1 < self.data.len() || cur.idx.is_none() {
cur.idx = Some(self.data.len() - 1);
self.cursor.set(cur);
TreeNavResult::Continue
} else {
self.cursor.set(ListCursor::default());
TreeNavResult::Exit
}
}
ListCursorMode::Modify => {
let ce = self.data.get_mut(i);
let mut cur_edit = ce.write().unwrap();
let cur_mode = cur_edit.get_cursor().leaf_mode;
let depth = cur_edit.get_cursor().tree_addr.len();
match cur_edit.goto_end() {
TreeNavResult::Continue => TreeNavResult::Continue,
TreeNavResult::Exit => {
drop(cur_edit);
self.up();
if i + 1 < self.data.len() {
self.set_mode(ListCursorMode::Select);
self.nexd();
for _x in 1..depth {
self.dn();
self.goto_home();
}
self.set_leaf_mode(cur_mode);
self.dn();
self.goto_end();
return TreeNavResult::Continue;
}
self.cursor.set(ListCursor::default());
TreeNavResult::Exit
}
}
}
}
} else {
self.cursor.set(ListCursor::default());
TreeNavResult::Exit
}
}
fn goto_home(&mut self) -> TreeNavResult {
let mut cur = self.cursor.get();
if self.data.len() == 0 && cur.idx.is_none() {
self.cursor.set(ListCursor {
mode: ListCursorMode::Insert,
idx: Some(0),
});
return TreeNavResult::Continue;
}
match cur.mode {
ListCursorMode::Insert | ListCursorMode::Select => {
if cur.idx != Some(0) {
self.cursor.set(ListCursor {
mode: if self.data.len() == 0 {
ListCursorMode::Insert
} else {
cur.mode
},
idx: Some(0),
});
TreeNavResult::Continue
} else {
self.cursor.set(ListCursor::default());
TreeNavResult::Exit
}
}
ListCursorMode::Modify => {
if let Some(ce) = self.get_item() {
let mut cur_edit = ce.write().unwrap();
let cur_mode = cur_edit.get_cursor().leaf_mode;
let depth = cur_edit.get_cursor().tree_addr.len();
match cur_edit.goto_home() {
TreeNavResult::Exit => {
drop(cur_edit);
if let Some(i) = cur.idx {
if i > 0 {
self.set_mode(ListCursorMode::Select);
self.pxev();
for _x in 1..depth {
self.dn();
self.goto_end();
}
self.dn();
self.set_leaf_mode(cur_mode);
//self.goto_home();
return TreeNavResult::Continue;
}
}
}
TreeNavResult::Continue => { return TreeNavResult::Continue; }
};
}
self.cursor.set(ListCursor::default());
TreeNavResult::Exit
}
}
}
fn up(&mut self) -> TreeNavResult {
let cur = self.cursor.get();
if cur.mode == ListCursorMode::Modify {
if let Some(i) = cur.idx {
let ce = self.data.get_mut(i);
let mut cur_edit = ce.write().unwrap();
let mode = cur_edit.get_cursor().leaf_mode;
match cur_edit.up() {
TreeNavResult::Exit => {
self.set_mode(mode);
}
TreeNavResult::Continue => {}
}
TreeNavResult::Continue
} else {
TreeNavResult::Exit
}
} else {
self.cursor.set(ListCursor {
mode: cur.mode,
idx: None,
});
TreeNavResult::Exit
}
}
fn dn(&mut self) -> TreeNavResult {
let mut cur = self.cursor.get();
if cur.idx.is_none() {
self.goto_home()
} else {
match cur.mode {
ListCursorMode::Insert | ListCursorMode::Select => {
if let Some(i) = cur.idx {
if i < self.data.len() {
self.set_mode(ListCursorMode::Modify);
self.data.get_mut(i).write().unwrap().goto(TreeCursor {
leaf_mode: cur.mode,
tree_addr: vec![],
});
self.data.get_mut(i).write().unwrap().dn();
*self.cur_dist.write().unwrap() += 1;
}
}
TreeNavResult::Continue
}
ListCursorMode::Modify => self.get_item().unwrap().write().unwrap().dn(),
}
}
}
fn pxev(&mut self) -> TreeNavResult {
let mut cur = self.cursor.get();
if let Some(i) = cur.idx {
match cur.mode {
ListCursorMode::Insert | ListCursorMode::Select => {
if i > 0 {
cur.idx = Some(i - 1);
self.cursor.set(cur);
TreeNavResult::Continue
} else {
self.cursor.set(ListCursor::default());
TreeNavResult::Exit
}
}
ListCursorMode::Modify => {
let ce = self.get_item().unwrap();
let mut cur_edit = ce.write().unwrap();
let cur_mode = cur_edit.get_cursor().leaf_mode;
let depth = cur_edit.get_cursor().tree_addr.len();
match cur_edit.pxev() {
TreeNavResult::Exit => {
drop(cur_edit);
self.up();
if i > 0 {
self.set_mode(ListCursorMode::Select);
self.pxev();
for _x in 1..depth {
self.dn();
self.goto_end();
}
self.set_leaf_mode(cur_mode);
self.dn();
self.goto_end();
TreeNavResult::Continue
} else {
TreeNavResult::Exit
}
}
TreeNavResult::Continue => TreeNavResult::Continue,
}
}
}
} else {
TreeNavResult::Exit
}
}
fn nexd(&mut self) -> TreeNavResult {
let mut cur = self.cursor.get();
if let Some(i) = cur.idx {
match cur.mode {
ListCursorMode::Insert => {
if i < self.data.len() {
cur.idx = Some(i + 1);
self.cursor.set(cur);
TreeNavResult::Continue
} else {
self.cursor.set(ListCursor::default());
TreeNavResult::Exit
}
}
ListCursorMode::Select => {
if i + 1 < self.data.len() {
cur.idx = Some(i + 1);
self.cursor.set(cur);
TreeNavResult::Continue
} else {
self.cursor.set(ListCursor::default());
TreeNavResult::Exit
}
}
ListCursorMode::Modify => {
let ce = self.data.get(i);
let mut cur_edit = ce.write().unwrap();
let depth = cur_edit.get_cursor().tree_addr.len();
let cur_mode = cur_edit.get_cursor().leaf_mode;
match cur_edit.nexd() {
TreeNavResult::Exit => {
drop(cur_edit);
drop(ce);
//self.up();
if i + 1 < self.data.len() {
self.set_mode(ListCursorMode::Select);
self.nexd();
for _x in 1..depth {
self.dn();
}
self.set_leaf_mode(cur_mode);
self.dn();
TreeNavResult::Continue
} else {
self.cursor.set(ListCursor::default());
TreeNavResult::Exit
}
}
TreeNavResult::Continue => TreeNavResult::Continue,
}
}
}
} else {
TreeNavResult::Exit
}
}
}
impl<ItemEditor, FnMakeItemEditor> TerminalEditor for ListEditor<ItemEditor, FnMakeItemEditor>
where
ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
FnMakeItemEditor: Fn() -> Arc<RwLock<ItemEditor>>,
{
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
match self.style {
ListEditorStyle::HorizontalSexpr => self.horizontal_sexpr_view(),
ListEditorStyle::VerticalSexpr => self.vertical_sexpr_view(),
ListEditorStyle::Tuple(depth) => self.tuple_view(depth),
ListEditorStyle::Path => self.path_view(),
ListEditorStyle::String => self.string_view(),
ListEditorStyle::Clist => self.clist_view(),
ListEditorStyle::Hex => self.hex_view(),
ListEditorStyle::Plain => self.plain_view(),
}
}
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
let mut cur = self.cursor.get();
if let Some(idx) = cur.idx {
match cur.mode {
ListCursorMode::Insert => match event {
TerminalEvent::Input(Event::Key(Key::Backspace)) => {
if idx > 0 && idx <= self.data.len() {
cur.idx = Some(idx - 1);
self.cursor.set(cur);
self.data.remove(idx - 1);
TerminalEditorResult::Continue
} else {
TerminalEditorResult::Exit
}
}
TerminalEvent::Input(Event::Key(Key::Delete)) => {
if idx < self.data.len() {
self.data.remove(idx);
TerminalEditorResult::Continue
} else {
TerminalEditorResult::Exit
}
}
TerminalEvent::Input(Event::Key(Key::Char('\t')))
| TerminalEvent::Input(Event::Key(Key::Insert)) => {
self.set_mode(ListCursorMode::Select);
TerminalEditorResult::Continue
}
_ => {
let new_edit = (self.make_item_editor)();
self.data.insert(idx, new_edit.clone());
self.set_mode(ListCursorMode::Modify);
let mut ne = new_edit.write().unwrap();
match ne.handle_terminal_event(event) {
TerminalEditorResult::Exit => {
self.cursor.set(ListCursor {
mode: ListCursorMode::Insert,
idx: Some(idx + 1),
});
}
_ => {}
}
TerminalEditorResult::Continue
}
},
ListCursorMode::Select => match event {
TerminalEvent::Input(Event::Key(Key::Char('\t')))
| TerminalEvent::Input(Event::Key(Key::Insert)) => {
self.set_mode(ListCursorMode::Insert);
TerminalEditorResult::Continue
}
TerminalEvent::Input(Event::Key(Key::Delete)) => {
self.data.remove(idx);
if self.data.len() == 0 {
self.cursor.set(ListCursor::default());
} else if idx == self.data.len() {
self.cursor.set(ListCursor {
mode: ListCursorMode::Select,
idx: Some(idx - 1),
});
}
TerminalEditorResult::Continue
}
_ => TerminalEditorResult::Continue,
},
ListCursorMode::Modify => {
let ce = self.data.get_mut(idx);
let mut cur_edit = ce.write().unwrap();
match cur_edit.handle_terminal_event(event) {
TerminalEditorResult::Exit => {
cur_edit.up();
drop(cur_edit);
drop(ce);
match event {
TerminalEvent::Input(Event::Key(Key::Backspace)) => {
// todo: join instead of remove
self.cursor.set(ListCursor {
mode: ListCursorMode::Insert,
idx: Some(idx),
});
self.data.remove(idx);
}
_ => {
// todo: split
self.cursor.set(ListCursor {
mode: ListCursorMode::Insert,
idx: Some(idx + 1),
});
}
}
}
TerminalEditorResult::Continue => {}
}
TerminalEditorResult::Continue
}
}
} else {
TerminalEditorResult::Continue
}
}
}
impl<ItemEditor, FnMakeItemEditor> TerminalTreeEditor for ListEditor<ItemEditor, FnMakeItemEditor>
where
ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
FnMakeItemEditor: Fn() -> Arc<RwLock<ItemEditor>> + Send + Sync,
{}
impl<ItemEditor, FnMakeItemEditor> ListEditor<ItemEditor, FnMakeItemEditor>
where
ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
FnMakeItemEditor: Fn() -> Arc<RwLock<ItemEditor>>,
{
pub fn get_seg_seq_view(
&self,
) -> OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>> {
let segment_view_port = ViewPort::<dyn SequenceView<Item = ListEditorViewSegment>>::new();
ListEditorView::new(
self.cursor_port.outer(),
self.data_port
.outer()
.to_sequence()
.map(|ed| ed.read().unwrap().get_term_view()),
let segment_view_port = ViewPort::<dyn SequenceView<Item = ListSegment<ItemEditor>>>::new();
ListSegmentSequence::new(
self.get_cursor_port(),
self.get_data_port(),
segment_view_port.inner(),
self.depth
);
segment_view_port.into_outer().map(move |segment| {
let cursor_col = (90, 60, 200);
match segment {
ListEditorViewSegment::InsertCursor => {
make_label("|").map_item(move |_pt, atom| {
atom.add_style_back(TerminalStyle::fg_color(cursor_col))
.add_style_back(TerminalStyle::bold(true))
})
}
ListEditorViewSegment::Select(sub_view) => sub_view.map_item(move |_pt, atom| {
let old_col = atom.style.bg_color.unwrap_or(cursor_col);
atom.add_style_front(TerminalStyle::bg_color((
(old_col.0 as f32 * 0.4) as u8,
(old_col.1 as f32 * 0.4) as u8,
(old_col.2 as f32 * 0.4) as u8,
)))
}),
ListEditorViewSegment::Modify(sub_view) => {
sub_view.clone().map_item(
move |_pt, atom| {
let old_col = atom.style.bg_color.unwrap_or(cursor_col);
atom.add_style_front(TerminalStyle::bg_color((
(old_col.0 as f32 * 0.4) as u8,
(old_col.1 as f32 * 0.4) as u8,
(old_col.2 as f32 * 0.4) as u8,
)))
}, //.add_style_back(TerminalStyle::bold(true))
)
}
ListEditorViewSegment::View(sub_view) => sub_view.clone(),
}
})
}
pub fn horizontal_sexpr_view(&self) -> OuterViewPort<dyn TerminalView> {
self.get_seg_seq_view().horizontal_sexpr_view(1)
}
pub fn vertical_sexpr_view(&self) -> OuterViewPort<dyn TerminalView> {
self.get_seg_seq_view().vertical_sexpr_view(0)
}
pub fn path_view(&self) -> OuterViewPort<dyn TerminalView> {
self.get_seg_seq_view()
.decorate("<", ">", "/", 0)
.to_grid_horizontal()
.flatten()
}
pub fn string_view(&self) -> OuterViewPort<dyn TerminalView> {
self.get_seg_seq_view()
.decorate("\"", "\"", "", 1)
.to_grid_horizontal()
.flatten()
}
pub fn clist_view(&self) -> OuterViewPort<dyn TerminalView> {
self.get_seg_seq_view()
.decorate("{", "}", ", ", 1)
.to_grid_horizontal()
.flatten()
}
pub fn tuple_view(&self, depth: usize) -> OuterViewPort<dyn TerminalView> {
self.get_seg_seq_view()
.decorate("(", ")", ", ", depth)
.to_grid_horizontal()
.flatten()
}
pub fn hex_view(&self) -> OuterViewPort<dyn TerminalView> {
self.get_seg_seq_view()
.decorate("0x", "", "", 0)
.to_grid_horizontal()
.flatten()
}
pub fn plain_view(&self) -> OuterViewPort<dyn TerminalView> {
self.get_seg_seq_view().to_grid_horizontal().flatten()
}
pub fn new(make_item_editor: FnMakeItemEditor, style: ListEditorStyle) -> Self {
let cursor_port = ViewPort::new();
let data_port = ViewPort::new();
let cursor = SingletonBuffer::new(ListCursor::default(), cursor_port.inner());
let data = VecBuffer::<Arc<RwLock<ItemEditor>>>::new(data_port.inner());
let mut le = ListEditor {
data,
data_port,
cursor,
cursor_port,
style,
make_item_editor,
_level: 0,
cur_dist: Arc::new(RwLock::new(0)),
};
le.set_style(style);
le
}
pub fn set_style(&mut self, style: ListEditorStyle) {
self.style = style;
segment_view_port.into_outer().map(move |segment| segment.pty_view())
}
pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = Arc<RwLock<ItemEditor>>>> {
self.data_port.outer().to_sequence()
self.data.get_port().to_sequence()
}
pub fn get_list_cursor_port(&self) -> OuterViewPort<dyn SingletonView<Item = ListCursor>> {
self.cursor_port.outer()
pub fn get_cursor_port(&self) -> OuterViewPort<dyn SingletonView<Item = ListCursor>> {
self.cursor.get_port()
}
pub fn get_item(&self) -> Option<Arc<RwLock<ItemEditor>>> {
if let Some(idx) = self.cursor.get().idx {
let idx = crate::modulo(idx as isize, self.data.len() as isize) as usize;
if idx < self.data.len() {
Some(self.data.get(idx))
} else {
@ -716,50 +83,5 @@ where
pub fn clear(&mut self) {
self.data.clear();
}
fn set_idx(&mut self, idx: isize) {
let cur = self.cursor.get();
let mode = cur.mode;
if idx < 0 {
self.cursor.set(ListCursor {
mode,
idx: Some((self.data.len() as isize + idx) as usize),
});
} else {
self.cursor.set(ListCursor {
mode,
idx: Some(idx as usize),
});
}
}
fn set_mode(&mut self, mode: ListCursorMode) {
let mut cur = self.cursor.get();
if cur.mode == ListCursorMode::Insert && mode != ListCursorMode::Insert {
if let Some(idx) = cur.idx {
if idx == self.data.len() && idx > 0 {
cur.idx = Some(idx - 1);
}
}
}
cur.mode = mode;
self.cursor.set(cur);
}
}
impl<ItemEditor, FnMakeItemEditor> ListEditor<ItemEditor, FnMakeItemEditor>
where
ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
FnMakeItemEditor: Fn() -> Arc<RwLock<ItemEditor>>,
{
fn set_leaf_mode(&mut self, mode: ListCursorMode) {
let mut c = self.get_cursor();
c.leaf_mode = mode;
self.goto(c);
}
}

View file

@ -1,122 +0,0 @@
use {
crate::{
core::{InnerViewPort, Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View},
list::{ListCursor, ListCursorMode},
projection::ProjectionHelper,
sequence::SequenceView,
singleton::SingletonView,
terminal::TerminalView,
},
std::sync::Arc,
std::sync::RwLock,
};
pub enum ListEditorViewSegment {
InsertCursor,
View(OuterViewPort<dyn TerminalView>),
Select(OuterViewPort<dyn TerminalView>),
Modify(OuterViewPort<dyn TerminalView>),
}
pub struct ListEditorView {
cursor: Arc<dyn SingletonView<Item = ListCursor>>,
data: Arc<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>,
cur_cursor: ListCursor,
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = ListEditorViewSegment>>>>,
proj_helper: ProjectionHelper<usize, Self>,
}
impl View for ListEditorView {
type Msg = usize;
}
impl SequenceView for ListEditorView {
type Item = ListEditorViewSegment;
fn len(&self) -> Option<usize> {
match self.cursor.get().mode {
ListCursorMode::Insert => {
Some(self.data.len()? + if self.cur_cursor.idx.is_some() { 1 } else { 0 })
}
_ => self.data.len(),
}
}
fn get(&self, idx: &usize) -> Option<Self::Item> {
Some(if let Some(cur) = self.cur_cursor.idx {
match self.cur_cursor.mode {
ListCursorMode::Select => {
if *idx == cur {
ListEditorViewSegment::Select(self.data.get(&idx)?)
} else {
ListEditorViewSegment::View(self.data.get(&idx)?)
}
}
ListCursorMode::Insert => {
if *idx < cur {
ListEditorViewSegment::View(self.data.get(&idx)?)
} else if *idx == cur {
ListEditorViewSegment::InsertCursor
} else {
ListEditorViewSegment::View(self.data.get(&(idx - 1))?)
}
}
ListCursorMode::Modify => {
if *idx == cur {
ListEditorViewSegment::Modify(self.data.get(&idx)?)
} else {
ListEditorViewSegment::View(self.data.get(&idx)?)
}
}
}
} else {
ListEditorViewSegment::View(self.data.get(&idx)?)
})
}
}
impl ListEditorView {
pub fn new(
cursor_port: OuterViewPort<dyn SingletonView<Item = ListCursor>>,
data_port: OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>,
out_port: InnerViewPort<dyn SequenceView<Item = ListEditorViewSegment>>,
) -> Arc<RwLock<Self>> {
let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone());
let proj = Arc::new(RwLock::new(ListEditorView {
cur_cursor: ListCursor::default(),
cursor: proj_helper.new_singleton_arg(0, cursor_port, |s: &mut Self, _msg| {
let _old_cursor = s.cur_cursor;
let new_cursor = s.cursor.get();
s.cur_cursor = new_cursor;
s.cast.notify_each(0..=s.data.len().unwrap_or(0) + 1);
}),
data: proj_helper.new_sequence_arg(1, data_port, |s: &mut Self, idx| {
if let Some(cur_idx) = s.cur_cursor.idx {
match s.cur_cursor.mode {
ListCursorMode::Insert => {
if *idx < cur_idx {
s.cast.notify(idx);
} else {
s.cast.notify(&(*idx + 1));
}
}
_ => {
s.cast.notify(idx);
}
}
} else {
s.cast.notify(idx);
}
}),
cast: out_port.get_broadcast(),
proj_helper,
}));
proj.write().unwrap().proj_helper.set_proj(&proj);
out_port.set_view(Some(proj.clone()));
proj
}
}

View file

@ -1,8 +1,12 @@
pub mod cursor;
pub mod segment;
pub mod editor;
pub mod editor_view;
pub mod sexpr;
pub mod nav;
pub mod pty_editor;
pub use cursor::{ListCursor, ListCursorMode};
pub use editor::{ListEditor, ListEditorStyle};
pub use sexpr::{ListDecoration, SExprView};
pub use segment::{ListSegment, ListSegmentSequence};
pub use editor::ListEditor;
pub use pty_editor::PTYListEditor;

240
nested/src/list/nav.rs Normal file
View file

@ -0,0 +1,240 @@
use {
crate::{
core::{OuterViewPort, ViewPort},
list::{
ListCursor, ListCursorMode,
ListSegment, ListSegmentSequence,
ListEditor
},
sequence::SequenceView,
singleton::{SingletonBuffer, SingletonView},
terminal::{
make_label, TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle,
TerminalView,
},
tree_nav::{TerminalTreeEditor, TreeCursor, TreeNav, TreeNavResult},
vec::VecBuffer,
color::{bg_style_from_depth, fg_style_from_depth}
},
std::sync::{Arc, RwLock},
termion::event::{Event, Key},
cgmath::Vector2
};
impl<ItemEditor> TreeNav for ListEditor<ItemEditor>
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static
{
fn get_cursor_warp(&self) -> TreeCursor {
let cur = self.cursor.get();
match cur.mode {
ListCursorMode::Insert => TreeCursor {
leaf_mode: cur.mode,
tree_addr: if let Some(i) = cur.idx {
vec![
i - self.data.len() as isize - 1
]
} else {
vec![]
},
},
ListCursorMode::Select => {
if let Some(i) = cur.idx {
if i < self.data.len() as isize {
let mut sub_cur = self.data.get(i as usize).read().unwrap().get_cursor_warp();
sub_cur.tree_addr.insert(0, i as isize - self.data.len() as isize);
return sub_cur;
}
}
TreeCursor {
leaf_mode: cur.mode,
tree_addr: vec![],
}
}
}
}
fn get_cursor(&self) -> TreeCursor {
let cur = self.cursor.get();
match cur.mode {
ListCursorMode::Insert => TreeCursor {
leaf_mode: cur.mode,
tree_addr: if let Some(i) = cur.idx {
vec![i]
} else {
vec![]
},
},
ListCursorMode::Select => {
if let Some(i) = cur.idx {
if i < self.data.len() as isize {
let mut sub_cur = self.data.get(i as usize).read().unwrap().get_cursor();
sub_cur.tree_addr.insert(0, i as isize);
return sub_cur;
}
}
TreeCursor {
leaf_mode: cur.mode,
tree_addr: vec![],
}
}
}
}
fn goto(&mut self, new_cur: TreeCursor) -> TreeNavResult {
let old_cur = self.cursor.get();
if let Some(i) = old_cur.idx {
if i < self.data.len() as isize {
let ce = self.data.get_mut(i as usize);
let mut cur_edit = ce.write().unwrap();
cur_edit.goto(TreeCursor::none());
}
}
match new_cur.tree_addr.len() {
0 => {
self.cursor.set(ListCursor {
mode: new_cur.leaf_mode,
idx: None,
});
TreeNavResult::Continue
}
1 => {
self.cursor.set(ListCursor {
mode: new_cur.leaf_mode,
idx: Some(crate::modulo(new_cur.tree_addr[0], if new_cur.leaf_mode == ListCursorMode::Insert { 1 } else { 0 } + self.data.len() as isize)),
});
TreeNavResult::Continue
}
_ => {
let idx = crate::modulo(new_cur.tree_addr[0], self.data.len() as isize);
self.cursor.set(ListCursor {
mode: ListCursorMode::Select,
idx: Some(idx),
});
let item = self.data.get_mut(idx as usize);
let mut item_edit = item.write().unwrap();
item_edit.goto(TreeCursor {
leaf_mode: new_cur.leaf_mode,
tree_addr: new_cur.tree_addr[1..].iter().cloned().collect(),
});
TreeNavResult::Continue
}
}
}
fn goby(&mut self, direction: Vector2<isize>) -> TreeNavResult {
let mut cur = self.get_cursor();
match cur.tree_addr.len() {
0 => {
if direction.y < 0 {
// up
TreeNavResult::Exit
} else if direction.y > 0 {
// dn
self.cursor.set(ListCursor::home());
self.goby(Vector2::new(direction.x, direction.y-1));
TreeNavResult::Continue
} else {
TreeNavResult::Continue
}
},
1 => {
if direction.y > 0 {
// dn
if cur.tree_addr[0] < self.data.len() as isize {
let item = self.data.get_mut(cur.tree_addr[0] as usize);
let mut item_edit = item.write().unwrap();
if item_edit.goby(Vector2::new(direction.x, direction.y)) == TreeNavResult::Continue {
self.cursor.set(ListCursor {
mode: ListCursorMode::Select,
idx: Some(cur.tree_addr[0])
})
}
}
TreeNavResult::Continue
} else if direction.y < 0 {
// up
self.cursor.set(ListCursor::none());
TreeNavResult::Exit
} else {
// horizontal
if (cur.tree_addr[0]+direction.x >= 0) &&
(cur.tree_addr[0]+direction.x <
self.data.len() as isize
+ if cur.leaf_mode == ListCursorMode::Insert { 1 } else { 0 })
{
self.cursor.set(ListCursor {
mode: cur.leaf_mode,
idx: Some(cur.tree_addr[0] + direction.x)
});
TreeNavResult::Continue
} else {
self.cursor.set(ListCursor::none());
TreeNavResult::Exit
}
}
},
depth => {
// nested
let item = self.data.get_mut(cur.tree_addr[0] as usize);
let mut item_edit = item.write().unwrap();
match item_edit.goby(direction) {
TreeNavResult::Exit => {
if direction.y < 0 {
// up
self.cursor.set(ListCursor {
mode: cur.leaf_mode,
idx: Some(cur.tree_addr[0])
});
TreeNavResult::Continue
} else if direction.y > 0 {
// dn
TreeNavResult::Continue
} else {
// horizontal
drop(item_edit);
if (cur.tree_addr[0]+direction.x >= 0) &&
(cur.tree_addr[0]+direction.x < self.data.len() as isize)
{
if direction.x < 0 {
cur.tree_addr[0] -= 1;
for i in 1..depth {
cur.tree_addr[i] = -1;
}
} else {
cur.tree_addr[0] += 1;
for i in 1..depth {
cur.tree_addr[i] = 0;
}
}
self.goto(cur)
} else {
self.cursor.set(ListCursor::none());
TreeNavResult::Exit
}
}
}
TreeNavResult::Continue => TreeNavResult::Continue
}
}
}
}
}

View file

@ -0,0 +1,208 @@
use {
crate::{
core::{OuterViewPort, ViewPort},
list::{
ListCursor, ListCursorMode,
ListSegment, ListSegmentSequence,
ListEditor
},
sequence::{SequenceView, decorator::{SeqDecorStyle, PTYSeqDecorate}},
singleton::{SingletonBuffer, SingletonView},
terminal::{
make_label, TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle,
TerminalView,
},
tree_nav::{TerminalTreeEditor, TreeCursor, TreeNav, TreeNavResult},
vec::VecBuffer,
color::{bg_style_from_depth, fg_style_from_depth}
},
std::sync::{Arc, RwLock},
termion::event::{Event, Key},
cgmath::Vector2
};
pub struct PTYListEditor<ItemEditor>
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static
{
pub editor: ListEditor<ItemEditor>,
style: SeqDecorStyle,
depth: usize,
port: ViewPort<dyn TerminalView>
}
impl<ItemEditor> PTYListEditor<ItemEditor>
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static
{
pub fn new(
make_item_editor: Box<dyn Fn() -> Arc<RwLock<ItemEditor>> + Send + Sync>,
style: SeqDecorStyle,
depth: usize
) -> Self {
let port = ViewPort::new();
PTYListEditor {
editor: ListEditor::new(make_item_editor, depth),
style,
depth,
port
}
}
pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = Arc<RwLock<ItemEditor>>>> {
self.editor.get_data_port()
}
pub fn clear(&mut self) {
self.editor.clear();
}
pub fn get_item(&self) -> Option<Arc<RwLock<ItemEditor>>> {
self.editor.get_item()
}
pub fn set_depth(&mut self, depth: usize) {
self.depth = depth;
}
pub fn set_style(&mut self, style: SeqDecorStyle) {
self.style = style;
}
}
impl<ItemEditor> TerminalEditor for PTYListEditor<ItemEditor>
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static
{
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
self.editor
.get_seg_seq_view()
.pty_decorate(self.style, self.depth)
}
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
let mut cur = self.editor.cursor.get();
if let Some(idx) = cur.idx {
match cur.mode {
ListCursorMode::Insert => match event {
TerminalEvent::Input(Event::Key(Key::Backspace)) => {
if idx > 0 && idx <= self.editor.data.len() as isize {
cur.idx = Some(idx as isize - 1);
self.editor.cursor.set(cur);
self.editor.data.remove(idx as usize - 1);
if self.editor.data.len() > 0 {
TerminalEditorResult::Continue
} else {
TerminalEditorResult::Exit
}
} else {
TerminalEditorResult::Exit
}
}
TerminalEvent::Input(Event::Key(Key::Delete)) => {
if idx < self.editor.data.len() as isize {
self.editor.data.remove(idx as usize);
TerminalEditorResult::Continue
} else {
TerminalEditorResult::Exit
}
}
TerminalEvent::Input(Event::Key(Key::Char('\t')))
| TerminalEvent::Input(Event::Key(Key::Insert)) => {
self.editor.set_leaf_mode(ListCursorMode::Select);
TerminalEditorResult::Continue
}
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
self.editor.goto(TreeCursor::none());
TerminalEditorResult::Exit
}
_ => {
let new_edit = (self.editor.make_item_editor)();
self.editor.data.insert(idx as usize, new_edit.clone());
self.editor.set_leaf_mode(ListCursorMode::Select);
let mut ne = new_edit.write().unwrap();
ne.goto(TreeCursor::home());
match ne.handle_terminal_event(event) {
TerminalEditorResult::Exit => {
self.editor.cursor.set(ListCursor {
mode: ListCursorMode::Insert,
idx: Some(idx as isize + 1),
});
}
_ => {}
}
TerminalEditorResult::Continue
}
},
ListCursorMode::Select => {
match event {
TerminalEvent::Input(Event::Key(Key::Char('\t')))
| TerminalEvent::Input(Event::Key(Key::Insert)) => {
self.editor.set_leaf_mode(ListCursorMode::Insert);
TerminalEditorResult::Continue
}
ev => {
if let Some(e) = self.editor.get_item() {
match e.write().unwrap().handle_terminal_event(ev) {
TerminalEditorResult::Exit => {
match ev {
TerminalEvent::Input(Event::Key(Key::Backspace)) => {
self.editor.data.remove(idx as usize);
self.editor.cursor.set(ListCursor {
mode: ListCursorMode::Insert,
idx: Some(idx as isize),
});
}
_ => {
self.editor.cursor.set(ListCursor {
mode: ListCursorMode::Insert,
idx: Some(idx as isize + 1),
});
}
}
}
TerminalEditorResult::Continue => {
}
}
}
TerminalEditorResult::Continue
}
}
}
}
} else {
TerminalEditorResult::Continue
}
}
}
impl<ItemEditor> TreeNav for PTYListEditor<ItemEditor>
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static
{
fn get_cursor_warp(&self) -> TreeCursor {
self.editor.get_cursor_warp()
}
fn get_cursor(&self) -> TreeCursor {
self.editor.get_cursor()
}
fn goby(&mut self, direction: Vector2<isize>) -> TreeNavResult {
self.editor.goby(direction)
}
fn goto(&mut self, cursor: TreeCursor) -> TreeNavResult {
self.editor.goto(cursor)
}
}
impl<ItemEditor> TerminalTreeEditor for PTYListEditor<ItemEditor>
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static
{}

176
nested/src/list/segment.rs Normal file
View file

@ -0,0 +1,176 @@
use {
crate::{
core::{InnerViewPort, Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View},
list::{ListCursor, ListCursorMode},
projection::ProjectionHelper,
sequence::SequenceView,
singleton::SingletonView,
terminal::{TerminalView, TerminalStyle, make_label},
tree_nav::TerminalTreeEditor,
color::{bg_style_from_depth, fg_style_from_depth}
},
std::sync::Arc,
std::sync::RwLock,
};
pub enum ListSegment<ItemEditor>
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static
{
InsertCursor,
Item {
editor: Arc<RwLock<ItemEditor>>,
depth: usize,
cur_dist: isize,
}
}
pub trait PTYSegment {
fn pty_view(&self) -> OuterViewPort<dyn TerminalView>;
}
impl<ItemEditor> PTYSegment for ListSegment<ItemEditor>
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static
{
fn pty_view(&self) -> OuterViewPort<dyn TerminalView> {
match self {
ListSegment::InsertCursor => {
make_label("|")
.map_item(move |_pt, atom| {
atom.add_style_back(bg_style_from_depth(0))
.add_style_back(TerminalStyle::bold(true))
})
}
ListSegment::Item{ editor, depth, cur_dist } => {
let e = editor.clone();
let d = *depth;
editor.read().unwrap().get_term_view().map_item(move |_pt, atom| {
let cur_depth = e.read().unwrap().get_cursor().tree_addr.len();
atom.add_style_back(bg_style_from_depth(cur_depth))
.add_style_back(fg_style_from_depth(d+cur_depth))
})
}
}
}
}
pub struct ListSegmentSequence<ItemEditor>
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static
{
data: Arc<dyn SequenceView<Item = Arc<RwLock<ItemEditor>>>>,
cursor: Arc<dyn SingletonView<Item = ListCursor>>,
depth: usize,
cur_cursor: ListCursor,
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = ListSegment<ItemEditor>>>>>,
proj_helper: ProjectionHelper<usize, Self>,
}
impl<ItemEditor> View for ListSegmentSequence<ItemEditor>
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static
{
type Msg = usize;
}
impl<ItemEditor> SequenceView for ListSegmentSequence<ItemEditor>
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static
{
type Item = ListSegment<ItemEditor>;
fn len(&self) -> Option<usize> {
match self.cur_cursor.mode {
ListCursorMode::Insert => {
Some(self.data.len()? + if self.cur_cursor.idx.is_some() { 1 } else { 0 })
}
_ => self.data.len(),
}
}
fn get(&self, idx: &usize) -> Option<Self::Item> {
let c = self.cursor.get();
Some(if let Some(mut cur) = c.idx {
match c.mode {
ListCursorMode::Select => {
ListSegment::Item {
editor: self.data.get(idx)?,
depth: self.depth,
cur_dist: cur - *idx as isize
}
}
ListCursorMode::Insert => {
if *idx < cur as usize {
ListSegment::Item {
editor: self.data.get(idx)?,
depth: self.depth,
cur_dist: cur - *idx as isize
}
} else if *idx == cur as usize {
ListSegment::InsertCursor
} else {
ListSegment::Item {
editor: self.data.get(&(*idx - 1))?,
depth: self.depth,
cur_dist: cur - (*idx as isize - 1)
}
}
}
}
} else {
ListSegment::Item {
editor: self.data.get(&idx)?,
depth: self.depth,
cur_dist: *idx as isize + 1
}
})
}
}
impl<ItemEditor> ListSegmentSequence<ItemEditor>
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static
{
pub fn new(
cursor_port: OuterViewPort<dyn SingletonView<Item = ListCursor>>,
data_port: OuterViewPort<dyn SequenceView<Item = Arc<RwLock<ItemEditor>>>>,
out_port: InnerViewPort<dyn SequenceView<Item = ListSegment<ItemEditor>>>,
depth: usize
) -> Arc<RwLock<Self>> {
let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone());
let proj = Arc::new(RwLock::new(ListSegmentSequence {
cur_cursor: cursor_port.get_view().get(),
depth,
cursor: proj_helper.new_singleton_arg(0, cursor_port, |s: &mut Self, _msg| {
let _old_cursor = s.cur_cursor;
s.cur_cursor = s.cursor.get();
// todo: optimize
s.cast.notify_each(0..=s.data.len().unwrap_or(0) + 1);
}),
data: proj_helper.new_sequence_arg(1, data_port, |s: &mut Self, idx| {
if let Some(mut cur_idx) = s.cur_cursor.idx {
match s.cur_cursor.mode {
ListCursorMode::Insert => {
if *idx < cur_idx as usize {
s.cast.notify(idx);
} else {
s.cast.notify(&(*idx + 1));
}
}
_ => {
s.cast.notify(idx);
}
}
} else {
s.cast.notify(idx);
}
}),
cast: out_port.get_broadcast(),
proj_helper,
}));
proj.write().unwrap().proj_helper.set_proj(&proj);
out_port.set_view(Some(proj.clone()));
proj
}
}

View file

@ -1,270 +0,0 @@
use {
crate::{
core::{InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View, ViewPort},
index::IndexArea,
projection::ProjectionHelper,
sequence::SequenceView,
terminal::{make_label, TerminalStyle, TerminalView},
},
cgmath::Point2,
std::sync::Arc,
std::sync::RwLock,
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct ListDecorator {
opening_port: OuterViewPort<dyn TerminalView>,
closing_port: OuterViewPort<dyn TerminalView>,
delim_port: OuterViewPort<dyn TerminalView>,
items: Arc<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>,
list_style: TerminalStyle,
item_style: TerminalStyle,
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>>>,
proj_helper: ProjectionHelper<(), Self>,
}
impl View for ListDecorator {
type Msg = usize;
}
impl SequenceView for ListDecorator {
type Item = OuterViewPort<dyn TerminalView>;
fn len(&self) -> Option<usize> {
let l = self.items.len()?;
Some(if l == 0 { 2 } else { 2 * l + 1 })
}
fn get(&self, idx: &usize) -> Option<Self::Item> {
let item_idx = idx / 2;
let list_style = self.list_style.clone();
let item_style = self.item_style.clone();
let l = self.items.len().unwrap_or(0);
Some(if *idx == 0 {
self.opening_port
.clone()
.map_item(move |_, atom| atom.add_style_back(list_style))
} else if (l == 0 && *idx == 1) || *idx == 2 * l {
self.closing_port
.clone()
.map_item(move |_, atom| atom.add_style_back(list_style))
} else if idx % 2 == 0 {
self.delim_port
.clone()
.map_item(move |_, atom| atom.add_style_back(list_style))
} else {
self.items
.get(&item_idx)?
.map_item(move |_, atom| atom.add_style_back(item_style))
})
}
}
impl ListDecorator {
pub fn new(
opening: &str,
closing: &str,
delim: &str,
level: usize,
items_port: OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>,
out_port: InnerViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>,
) -> Arc<RwLock<Self>> {
let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone());
let li = Arc::new(RwLock::new(ListDecorator {
opening_port: make_label(opening),
closing_port: make_label(closing),
delim_port: make_label(delim),
items: proj_helper.new_sequence_arg((), items_port, |s: &mut Self, item_idx| {
s.cast.notify(&(*item_idx * 2 + 1));
s.cast.notify(&(*item_idx * 2 + 2));
}),
list_style: TerminalStyle::fg_color(match level {
0 => (200, 120, 10),
1 => (120, 200, 10),
_ => (255, 255, 255),
}),
item_style: TerminalStyle::fg_color(match level {
_ => (255, 255, 255),
}),
cast: out_port.get_broadcast(),
proj_helper,
}));
li.write().unwrap().proj_helper.set_proj(&li);
out_port.set_view(Some(li.clone()));
li
}
}
pub trait ListDecoration {
fn decorate(
&self,
opening: &str,
closing: &str,
delim: &str,
level: usize,
) -> OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>;
}
impl ListDecoration for OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>> {
fn decorate(
&self,
opening: &str,
closing: &str,
delim: &str,
level: usize,
) -> OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>> {
let port = ViewPort::new();
ListDecorator::new(opening, closing, delim, level, self.clone(), port.inner());
port.into_outer()
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
use crate::{grid::GridView, index::IndexView};
pub struct VerticalSexprDecorator {
opening_port: OuterViewPort<dyn TerminalView>,
closing_port: OuterViewPort<dyn TerminalView>,
items: Arc<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>,
list_style: TerminalStyle,
item_style: TerminalStyle,
cast: Arc<RwLock<ObserverBroadcast<dyn GridView<Item = OuterViewPort<dyn TerminalView>>>>>,
proj_helper: ProjectionHelper<(), Self>,
}
impl View for VerticalSexprDecorator {
type Msg = IndexArea<Point2<i16>>;
}
impl IndexView<Point2<i16>> for VerticalSexprDecorator {
type Item = OuterViewPort<dyn TerminalView>;
fn area(&self) -> IndexArea<Point2<i16>> {
IndexArea::Range(
Point2::new(0, 0)
..=Point2::new(2, std::cmp::max(self.items.len().unwrap() as i16 - 1, 0)),
)
}
fn get(&self, pt: &Point2<i16>) -> Option<Self::Item> {
if pt.y < 0 {
return None;
}
let item_idx = pt.y as usize;
let list_style = self.list_style.clone();
let item_style = self.item_style.clone();
let l = self.items.len().unwrap_or(0);
match pt.x {
0 => {
if pt.y == 0 {
Some(
self.opening_port
.clone()
.map_item(move |_, atom| atom.add_style_back(list_style)),
)
} else {
None
}
}
1 => {
if item_idx < l {
Some(
self.items
.get(&item_idx)?
.map_item(move |_, atom| atom.add_style_back(item_style)),
)
} else {
None
}
}
2 => {
if (l == 0 && pt.y == 0) || (item_idx + 1 == l) {
Some(
self.closing_port
.clone()
.map_item(move |_, atom| atom.add_style_back(list_style)),
)
} else {
None
}
}
_ => None,
}
}
}
impl VerticalSexprDecorator {
pub fn new(
opening: &str,
closing: &str,
level: usize,
items_port: OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>,
out_port: InnerViewPort<dyn GridView<Item = OuterViewPort<dyn TerminalView>>>,
) -> Arc<RwLock<Self>> {
let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone());
let li = Arc::new(RwLock::new(VerticalSexprDecorator {
opening_port: make_label(opening),
closing_port: make_label(closing),
items: proj_helper.new_sequence_arg((), items_port, |s: &mut Self, item_idx| {
s.cast.notify(&IndexArea::Range(
Point2::new(0, *item_idx as i16)..=Point2::new(2, *item_idx as i16),
));
}),
list_style: TerminalStyle::fg_color(match level {
0 => (200, 120, 10),
1 => (120, 200, 10),
2 => (200, 10, 120),
_ => (255, 255, 255),
}),
item_style: TerminalStyle::fg_color(match level {
_ => (255, 255, 255),
}),
cast: out_port.get_broadcast(),
proj_helper,
}));
li.write().unwrap().proj_helper.set_proj(&li);
out_port.set_view(Some(li.clone()));
li
}
}
pub trait SExprView {
fn horizontal_sexpr_view(&self, level: usize) -> OuterViewPort<dyn TerminalView>;
fn vertical_bar_view(&self, level: usize) -> OuterViewPort<dyn TerminalView>;
fn vertical_sexpr_view(&self, level: usize) -> OuterViewPort<dyn TerminalView>;
}
impl SExprView for OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>> {
fn horizontal_sexpr_view(&self, level: usize) -> OuterViewPort<dyn TerminalView> {
let port = ViewPort::new();
ListDecorator::new("(", ")", " ", level, self.clone(), port.inner());
port.into_outer().to_grid_horizontal().flatten()
}
fn vertical_bar_view(&self, level: usize) -> OuterViewPort<dyn TerminalView> {
let port = ViewPort::new();
ListDecorator::new("Λ", "V", "|", level, self.clone(), port.inner());
port.into_outer().to_grid_vertical().flatten()
}
fn vertical_sexpr_view(&self, level: usize) -> OuterViewPort<dyn TerminalView> {
let port = ViewPort::new();
VerticalSexprDecorator::new("(", ")", level, self.clone(), port.inner());
port.into_outer().flatten()
}
}

View file

@ -1,24 +1,17 @@
use {
crate::{
core::{ViewPort, OuterViewPort, Observer, port::UpdateTask, TypeTerm, TypeLadder, Context},
terminal::{
Terminal, TerminalAtom, TerminalCompositor, TerminalEditor,
TerminalEditorResult, TerminalEvent, TerminalStyle, TerminalView,
make_label
},
sequence::{SequenceView},
tree_nav::{TreeNav, TerminalTreeEditor, TreeCursor, TreeNavResult},
vec::{VecBuffer, MutableVecAccess},
index::buffer::IndexBuffer,
core::{TypeLadder, Context},
terminal::{TerminalView},
tree_nav::{TerminalTreeEditor},
integer::PosIntEditor,
string_editor::{StringEditor, CharEditor},
list::{ListEditor, ListCursorMode, ListEditorStyle},
product::editor::ProductEditor
list::{ListEditor, PTYListEditor},
sequence::{decorator::{SeqDecorStyle}},
product::editor::ProductEditor,
char_editor::CharEditor
},
cgmath::{Point2, Vector2},
std::{sync::{Arc, RwLock}, ops::{Deref, DerefMut}},
termion::event::{Event, Key},
cgmath::Vector2,
std::sync::{Arc, RwLock},
};
pub fn make_editor(ctx: Arc<RwLock<Context>>, t: &TypeLadder, depth: usize) -> Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>> {
@ -30,44 +23,70 @@ pub fn make_editor(ctx: Arc<RwLock<Context>>, t: &TypeLadder, depth: usize) -> A
Arc::new(RwLock::new(PosIntEditor::new(10))) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
} else if t[0] == c.type_term_from_str("( String )").unwrap() {
Arc::new(RwLock::new(StringEditor::new())) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
Arc::new(RwLock::new(
PTYListEditor::new(
Box::new(|| {
Arc::new(RwLock::new(CharEditor::new()))
}),
SeqDecorStyle::DoubleQuote,
depth
)
))
} else if t[0] == c.type_term_from_str("( List Char )").unwrap() {
Arc::new(RwLock::new(ListEditor::new(
|| { Arc::new(RwLock::new(CharEditor::new())) },
ListEditorStyle::Plain
))) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
Arc::new(RwLock::new(
PTYListEditor::new(
Box::new(
|| { Arc::new(RwLock::new(CharEditor::new())) }
),
SeqDecorStyle::Plain,
depth
)
)) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
} else if t[0] == c.type_term_from_str("( List )").unwrap() {
Arc::new(RwLock::new(ListEditor::new(
|| {
Arc::new(RwLock::new(PosIntEditor::new(16)))
},
ListEditorStyle::HorizontalSexpr
))) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
Arc::new(RwLock::new(
PTYListEditor::new(
Box::new(|| {
Arc::new(RwLock::new(PosIntEditor::new(16)))
}),
SeqDecorStyle::EnumSet,
depth
)
)) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
} else if t[0] == c.type_term_from_str("( Path )").unwrap() {
Arc::new(RwLock::new(ListEditor::new(
|| {
Arc::new(RwLock::new(ListEditor::new(
|| {
Arc::new(RwLock::new(CharEditor::new()))
},
ListEditorStyle::Plain
)))
},
ListEditorStyle::Path
let d = depth + 1;
Arc::new(RwLock::new(PTYListEditor::new(
Box::new({
let d= depth +1;
move || {
Arc::new(RwLock::new(PTYListEditor::new(
Box::new(|| {
Arc::new(RwLock::new(CharEditor::new()))
}),
SeqDecorStyle::Plain,
d
)))
}}),
SeqDecorStyle::Path,
depth
))) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
} else if t[0] == c.type_term_from_str("( List RGB )").unwrap() {
Arc::new(RwLock::new(ListEditor::new({
let ctx = ctx.clone();
move || {
make_editor(ctx.clone(), &vec![ ctx.read().unwrap().type_term_from_str("( RGB )").unwrap() ], depth+1)
}
},
ListEditorStyle::VerticalSexpr
))) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
Arc::new(RwLock::new(
PTYListEditor::<dyn TerminalTreeEditor + Send +Sync>::new(
Box::new({
let d = depth+1;
let ctx = ctx.clone();
move || {
make_editor(ctx.clone(), &vec![ ctx.read().unwrap().type_term_from_str("( RGB )").unwrap() ], d)
}
}),
SeqDecorStyle::VerticalSexpr,
depth
)
)) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
} else if t[0] == c.type_term_from_str("( RGB )").unwrap() {
Arc::new(RwLock::new(ProductEditor::new(depth, ctx.clone())
@ -92,14 +111,18 @@ pub fn make_editor(ctx: Arc<RwLock<Context>>, t: &TypeLadder, depth: usize) -> A
)) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
} else if t[0] == c.type_term_from_str("( List Term )").unwrap() {
Arc::new(RwLock::new(ListEditor::new({
let ctx = ctx.clone();
move || {
make_editor(ctx.clone(), &vec![ ctx.read().unwrap().type_term_from_str("( Term )").unwrap() ], depth+1)
}
},
ListEditorStyle::Tuple(depth)
))) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
Arc::new(RwLock::new(
PTYListEditor::<dyn TerminalTreeEditor + Send + Sync>::new(
Box::new({
let ctx = ctx.clone();
move || {
make_editor(ctx.clone(), &vec![ ctx.read().unwrap().type_term_from_str("( Term )").unwrap() ], depth+1)
}
}),
SeqDecorStyle::Tuple,
depth
)
)) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
} else { // else: term
Arc::new(RwLock::new(

10
nested/src/modulo.rs Normal file
View file

@ -0,0 +1,10 @@
pub fn modulo(a: isize, b: isize) -> isize {
if b > 0 {
((a % b) + b) % b
} else {
0
}
}

View file

@ -1,24 +1,19 @@
use {
crate::{
core::{ViewPort, OuterViewPort, Observer, port::UpdateTask, TypeTerm, TypeLadder, Context},
core::{ViewPort, OuterViewPort, TypeLadder, Context},
terminal::{
Terminal, TerminalAtom, TerminalCompositor, TerminalEditor,
TerminalEditorResult, TerminalEvent, TerminalStyle, TerminalView,
make_label
TerminalEditor, TerminalEditorResult,
TerminalEvent, TerminalView
},
sequence::{SequenceView},
tree_nav::{TreeNav, TerminalTreeEditor, TreeCursor, TreeNavResult},
tree_nav::{TreeNav, TerminalTreeEditor, TreeNavResult},
vec::{VecBuffer, MutableVecAccess},
index::buffer::IndexBuffer,
integer::PosIntEditor,
string_editor::{StringEditor, CharEditor},
list::{ListEditor, ListCursorMode, ListEditorStyle},
list::ListCursorMode,
product::{element::ProductEditorElement},
make_editor::make_editor
},
cgmath::{Point2, Vector2},
std::{sync::{Arc, RwLock}, ops::{Deref, DerefMut}},
cgmath::Vector2,
std::sync::{Arc, RwLock},
termion::event::{Event, Key},
};
@ -31,8 +26,8 @@ pub struct ProductEditor {
pub(super) ctx: Arc<RwLock<Context>>,
pub(super) cursor: Option<usize>,
pub(super) depth: usize
pub(super) cursor: Option<isize>,
pub(super) depth: usize,
}
impl ProductEditor {
@ -46,7 +41,7 @@ impl ProductEditor {
});
ProductEditor {
elements: VecBuffer::new(port.inner()),
elements: VecBuffer::with_port(port.inner()),
el_port,
el_view_port,
n_indices: Vec::new(),
@ -57,9 +52,9 @@ impl ProductEditor {
depth
}
}
pub fn with_t(mut self, t: &str) -> Self {
self.elements.push(ProductEditorElement::T(t.to_string()));
self.elements.push(ProductEditorElement::T(t.to_string(), self.depth));
self
}
@ -68,22 +63,24 @@ impl ProductEditor {
self.elements.push(ProductEditorElement::N{
t: n,
editor: None,
select: false
cur_depth: 0
});
self.n_indices.push(elem_idx);
self
}
pub fn get_editor_element(&self, idx: usize) -> Option<ProductEditorElement> {
if let Some(i) = self.n_indices.get(idx) {
pub fn get_editor_element(&self, mut idx: isize) -> Option<ProductEditorElement> {
idx = crate::modulo(idx, self.n_indices.len() as isize);
if let Some(i) = self.n_indices.get(idx as usize) {
Some(self.elements.get(*i))
} else {
None
}
}
pub fn get_editor_element_mut(&mut self, idx: usize) -> Option<MutableVecAccess<ProductEditorElement>> {
if let Some(i) = self.n_indices.get(idx) {
pub fn get_editor_element_mut(&mut self, mut idx: isize) -> Option<MutableVecAccess<ProductEditorElement>> {
idx = crate::modulo(idx, self.n_indices.len() as isize);
if let Some(i) = self.n_indices.get(idx as usize) {
Some(self.elements.get_mut(*i))
} else {
None
@ -98,14 +95,14 @@ impl ProductEditor {
self.get_editor_element_mut(self.cursor?)
}
pub fn get_editor(&self, idx: usize) -> Option<Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>> {
if let Some(ProductEditorElement::N{ t: _, editor, select: _ }) = self.get_editor_element(idx) {
pub fn get_editor(&self, idx: isize) -> Option<Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>> {
if let Some(ProductEditorElement::N{ t: _, editor, cur_depth: _ }) = self.get_editor_element(idx) {
editor
} else {
None
}
}
pub fn get_cur_editor(&self) -> Option<Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>> {
self.get_editor(self.cursor?)
}
@ -123,14 +120,15 @@ impl TerminalEditor for ProductEditor {
}
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
if let Some(ProductEditorElement::N{ t, editor, select }) = self.get_cur_element_mut().as_deref_mut() {
*select = true;
if let Some(ProductEditorElement::N{ t, editor, cur_depth }) = self.get_cur_element_mut().as_deref_mut() {
*cur_depth = self.get_cursor().tree_addr.len();
if let Some(e) = editor.clone() {
match e.clone().write().unwrap().handle_terminal_event(event) {
TerminalEditorResult::Exit =>
match event {
TerminalEvent::Input(Event::Key(Key::Backspace)) => {
*editor = None;
*cur_depth -= 1;
TerminalEditorResult::Continue
}
_ => {
@ -149,6 +147,7 @@ impl TerminalEditor for ProductEditor {
*editor = Some(e.clone());
e.write().unwrap().dn();
let x = e.write().unwrap().handle_terminal_event(event);
*cur_depth = self.get_cursor().tree_addr.len();
x
}
} else {

View file

@ -1,72 +1,55 @@
use {
crate::{
core::{ViewPort, OuterViewPort, Observer, port::UpdateTask, TypeTerm, TypeLadder, Context},
core::{OuterViewPort, TypeLadder, Context},
terminal::{
Terminal, TerminalAtom, TerminalCompositor, TerminalEditor,
TerminalEditorResult, TerminalEvent, TerminalStyle, TerminalView,
TerminalEditor, TerminalStyle, TerminalView,
make_label
},
sequence::{SequenceView},
tree_nav::{TreeNav, TerminalTreeEditor, TreeCursor, TreeNavResult},
vec::{VecBuffer, MutableVecAccess},
index::buffer::IndexBuffer,
integer::PosIntEditor,
string_editor::{StringEditor, CharEditor},
list::{ListEditor, ListCursorMode, ListEditorStyle}
tree_nav::{TerminalTreeEditor},
color::{bg_style_from_depth, fg_style_from_depth}
},
cgmath::{Point2, Vector2},
std::{sync::{Arc, RwLock}, ops::{Deref, DerefMut}},
termion::event::{Event, Key},
};
#[derive(Clone)]
pub enum ProductEditorElement {
T( String ),
T( String, usize ),
N {
t: TypeLadder,
editor: Option<Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>>,
select: bool
cur_depth: usize
}
}
impl ProductEditorElement {
pub fn get_view(&self, ctx: Arc<RwLock<Context>>) -> OuterViewPort<dyn TerminalView> {
match self {
ProductEditorElement::T(t) =>
ProductEditorElement::T(t, depth) =>
make_label(t.as_str())
.map_item(
|i, x|
x.add_style_back(TerminalStyle::fg_color((0,120,200)))
),
.map_item({
let depth = *depth;
move |i, x|
x.add_style_back(fg_style_from_depth(depth))
}
),
ProductEditorElement::N {t: _, editor: Some(e), select} =>
ProductEditorElement::N { t: _, editor: Some(e), cur_depth } =>
e.read().unwrap()
.get_term_view()
.map_item({ let select = *select;
.map_item({ let cur_depth = *cur_depth;//e.read().unwrap().get_cursor().tree_addr.len()+1;
move |i, x| x
.add_style_back(TerminalStyle::fg_color((250,210,0)))
.add_style_back(
if select {
TerminalStyle::bg_color((40,40,40))
} else {
TerminalStyle::default()
}
)
.add_style_back(fg_style_from_depth(cur_depth))//fg_color((250,210,0)))
.add_style_back(bg_style_from_depth(cur_depth))
}),
ProductEditorElement::N{t, editor: None, select} =>
ProductEditorElement::N{ t, editor: None, cur_depth } =>
make_label(&ctx.read().unwrap().type_term_to_str(&t[0]))
.map_item({ let select = *select;
move |i, x| x
.map_item({
let cur_depth = *cur_depth;
move |i, x| x
.add_style_back(TerminalStyle::fg_color((130,90,40)))
.add_style_back(
if select {
TerminalStyle::bg_color((40,40,40))
} else {
TerminalStyle::default()
}
)
.add_style_back(bg_style_from_depth(cur_depth))
})
}
}

View file

@ -1,20 +1,8 @@
use {
crate::{
core::{ViewPort, OuterViewPort, Observer, port::UpdateTask, TypeTerm, TypeLadder, Context},
terminal::{
Terminal, TerminalAtom, TerminalCompositor, TerminalEditor,
TerminalEditorResult, TerminalEvent, TerminalStyle, TerminalView,
make_label
},
sequence::{SequenceView},
tree_nav::{TreeNav, TerminalTreeEditor, TreeCursor, TreeNavResult},
vec::{VecBuffer, MutableVecAccess},
index::buffer::IndexBuffer,
integer::PosIntEditor,
string_editor::{StringEditor, CharEditor},
list::{ListEditor, ListCursorMode, ListEditorStyle},
product::{element::ProductEditorElement, ProductEditor},
make_editor::make_editor
list::ListCursorMode,
tree_nav::{TreeNav, TreeNavResult, TreeCursor, TerminalTreeEditor},
product::{element::ProductEditorElement, ProductEditor}
},
cgmath::{Point2, Vector2},
std::{sync::{Arc, RwLock}, ops::{Deref, DerefMut}},
@ -44,23 +32,23 @@ impl TreeNav for ProductEditor {
fn goto(&mut self, mut c: TreeCursor) -> TreeNavResult {
if let Some(mut element) = self.get_cur_element_mut() {
if let ProductEditorElement::N{ t, editor, select } = element.deref_mut() {
if let ProductEditorElement::N{ t, editor, cur_depth } = element.deref_mut() {
if let Some(e) = editor {
e.write().unwrap().goto(TreeCursor::default());
}
*select = false;
*cur_depth = self.get_cursor().tree_addr.len();
}
}
if c.tree_addr.len() > 0 {
self.cursor = Some(c.tree_addr.remove(0));
self.cursor = Some(c.clone().tree_addr.remove(0));
if let Some(mut element) = self.get_cur_element_mut() {
if let ProductEditorElement::N{ t, editor, select } = element.deref_mut() {
if let ProductEditorElement::N{ t, editor, cur_depth } = element.deref_mut() {
if let Some(e) = editor {
e.write().unwrap().goto(c);
e.write().unwrap().goto(c.clone());
}
*select = true;
*cur_depth = c.tree_addr.len() + 1;
}
}
@ -71,9 +59,13 @@ impl TreeNav for ProductEditor {
}
}
fn goby(&mut self, direction: Vector2<isize>) -> TreeNavResult {
TreeNavResult::Exit
}
/*
fn goto_home(&mut self) -> TreeNavResult {
if let Some(c) = self.cursor {
if let Some(ProductEditorElement::N{ t, editor, select }) = self.get_cur_element_mut().as_deref_mut() {
if let Some(ProductEditorElement::N{ t, editor, cur_depth }) = self.get_cur_element_mut().as_deref_mut() {
if let Some(e) = editor {
let mut ce = e.write().unwrap();
@ -84,7 +76,7 @@ impl TreeNav for ProductEditor {
return match ce.goto_home() {
TreeNavResult::Exit => {
drop(ce);
*select = false;
*cur_depth = 0;
match self.pxev() {
TreeNavResult::Exit => TreeNavResult::Exit,
@ -105,11 +97,11 @@ impl TreeNav for ProductEditor {
}
}
*select = false;
*cur_depth = 0;
if c != 0 {
self.cursor = Some(0);
if let Some(ProductEditorElement::N{ t, editor, select }) = self.get_cur_element_mut().as_deref_mut() {
*select = true;
if let Some(ProductEditorElement::N{ t, editor, cur_depth }) = self.get_cur_element_mut().as_deref_mut() {
*cur_depth = self.get_cursor().tree_addr.len() + 1;
}
return TreeNavResult::Continue;
}
@ -121,7 +113,7 @@ impl TreeNav for ProductEditor {
fn goto_end(&mut self) -> TreeNavResult {
if let Some(c) = self.cursor {
if let Some(ProductEditorElement::N{ t, editor, select }) = self.get_cur_element_mut().as_deref_mut() {
if let Some(ProductEditorElement::N{ t, editor, cur_depth }) = self.get_cur_element_mut().as_deref_mut() {
if let Some(e) = editor {
let mut ce = e.write().unwrap();
@ -132,7 +124,7 @@ impl TreeNav for ProductEditor {
match ce.goto_end() {
TreeNavResult::Exit => {
drop(ce);
*select = false;
*cur_depth = 0;
if c+1 < self.n_indices.len() {
match self.nexd() {
@ -158,11 +150,11 @@ impl TreeNav for ProductEditor {
}
}
*select = false;
*cur_depth = 0;
if c < self.n_indices.len()-1 {
self.cursor = Some(self.n_indices.len()-1);
if let Some(ProductEditorElement::N{ t, editor, select }) = self.get_cur_element_mut().as_deref_mut() {
*select = true;
if let Some(ProductEditorElement::N{ t, editor, cur_depth }) = self.get_cur_element_mut().as_deref_mut() {
*cur_depth = self.get_cursor().tree_addr.len();
}
return TreeNavResult::Continue;
}
@ -174,7 +166,7 @@ impl TreeNav for ProductEditor {
fn pxev(&mut self) -> TreeNavResult {
if let Some(c) = self.cursor {
if let Some(ProductEditorElement::N{ t, editor, select }) = self.get_editor_element_mut(c).as_deref_mut() {
if let Some(ProductEditorElement::N{ t, editor, cur_depth }) = self.get_editor_element_mut(c).as_deref_mut() {
if let Some(e) = editor {
let mut ce = e.write().unwrap();
@ -185,12 +177,12 @@ impl TreeNav for ProductEditor {
return match ce.pxev() {
TreeNavResult::Exit => {
drop(ce);
*select = false;
*cur_depth = 0;
if c > 0 {
self.cursor = Some(c-1);
if let Some(ProductEditorElement::N{ t, editor, select }) = self.get_cur_element_mut().as_deref_mut() {
*select = true;
if let Some(ProductEditorElement::N{ t, editor, cur_depth }) = self.get_cur_element_mut().as_deref_mut() {
*cur_depth = self.get_cursor().tree_addr.len();
}
for _x in 1..depth {
@ -212,11 +204,11 @@ impl TreeNav for ProductEditor {
}
}
*select = false;
*cur_depth = 0;
if c > 0 {
self.cursor = Some(c-1);
if let Some(ProductEditorElement::N{ t, editor, select }) = self.get_cur_element_mut().as_deref_mut() {
*select = true;
if let Some(ProductEditorElement::N{ t, editor, cur_depth }) = self.get_cur_element_mut().as_deref_mut() {
*cur_depth = self.get_cursor().tree_addr.len();
}
return TreeNavResult::Continue;
}
@ -229,7 +221,7 @@ impl TreeNav for ProductEditor {
fn nexd(&mut self) -> TreeNavResult {
if let Some(c) = self.cursor.clone() {
if let Some(ProductEditorElement::N{ t, editor, select }) = self.get_editor_element_mut(c).as_deref_mut() {
if let Some(ProductEditorElement::N{ t, editor, cur_depth }) = self.get_editor_element_mut(c).as_deref_mut() {
if let Some(e) = editor {
let mut ce = e.write().unwrap();
@ -240,16 +232,17 @@ impl TreeNav for ProductEditor {
return match ce.nexd() {
TreeNavResult::Exit => {
drop(ce);
*select = false;
*cur_depth = 0;
if c+1 < self.n_indices.len() {
self.cursor = Some(c+1);
if let Some(ProductEditorElement::N{ t, editor, select }) = self.get_cur_element_mut().as_deref_mut() {
*select = true;
if let Some(ProductEditorElement::N{ t, editor, cur_depth }) = self.get_cur_element_mut().as_deref_mut() {
*cur_depth = self.get_cursor().tree_addr.len();
}
for _x in 1..depth {
self.dn();
self.goto_home();
}
self.dn();
@ -266,11 +259,11 @@ impl TreeNav for ProductEditor {
}
}
*select = false;
*cur_depth = 0;
if c+1 < self.n_indices.len() {
self.cursor = Some(c+1);
if let Some(ProductEditorElement::N{ t, editor, select }) = self.get_cur_element_mut().as_deref_mut() {
*select = true;
if let Some(ProductEditorElement::N{ t, editor, cur_depth }) = self.get_cur_element_mut().as_deref_mut() {
*cur_depth = self.get_cursor().tree_addr.len();
}
return TreeNavResult::Continue;
@ -283,15 +276,16 @@ impl TreeNav for ProductEditor {
}
fn up(&mut self) -> TreeNavResult {
if let Some(ProductEditorElement::N{ t, editor, select }) = self.get_cur_element_mut().as_deref_mut() {
if let Some(ProductEditorElement::N{ t, editor, cur_depth }) = self.get_cur_element_mut().as_deref_mut() {
if let Some(e) = editor {
let mut ce = e.write().unwrap();
*cur_depth = ce.get_cursor().tree_addr.len();
if ce.get_cursor().tree_addr.len() > 0 {
ce.up();
return TreeNavResult::Continue;
}
}
*select = false;
*cur_depth = 0;
}
self.cursor = None;
@ -300,24 +294,26 @@ impl TreeNav for ProductEditor {
fn dn(&mut self) -> TreeNavResult {
if let Some(c) = self.cursor {
if let Some(ProductEditorElement::N{ t, editor, select }) = self.get_editor_element_mut(c).as_deref_mut() {
if let Some(ProductEditorElement::N{ t, editor, cur_depth }) = self.get_editor_element_mut(c).as_deref_mut() {
if let Some(e) = editor {
e.write().unwrap().dn();
} else {
let e = make_editor(self.ctx.clone(), t, self.depth+1);
e.write().unwrap().goto_home();
e.write().unwrap().dn();
*editor = Some(e);
}
*cur_depth = self.get_cursor().tree_addr.len();
}
} else {
self.cursor = Some(0);
if let Some(ProductEditorElement::N{ t, editor, select }) = self.get_cur_element_mut().as_deref_mut() {
*select = true;
if let Some(ProductEditorElement::N{ t, editor, cur_depth }) = self.get_cur_element_mut().as_deref_mut() {
*cur_depth = self.get_cursor().tree_addr.len();
}
}
TreeNavResult::Continue
}
}
*/
}
impl TerminalTreeEditor for ProductEditor {}

View file

@ -228,13 +228,13 @@ impl PTYSeqDecorate for OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn
*/
SeqDecorStyle::Tuple => self
.separate(make_label(","))
.separate(make_label(", "))
.wrap(make_label("("), make_label(")"))
.to_grid_horizontal()
.flatten(),
SeqDecorStyle::EnumSet => self
.separate(make_label(","))
.separate(make_label(", "))
.wrap(make_label("{"), make_label("}"))
.to_grid_horizontal()
.flatten(),
@ -246,7 +246,7 @@ impl PTYSeqDecorate for OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn
.flatten(),
SeqDecorStyle::Hex => self
.wrap(make_label("0"), make_label(""))
.wrap(make_label("0x"), make_label(""))
.to_grid_horizontal()
.flatten(),
}

View file

@ -1,151 +0,0 @@
use {
crate::{
core::{OuterViewPort, ViewPort},
list::{sexpr::ListDecoration, ListEditor},
sequence::{SequenceView, SequenceViewExt},
singleton::{SingletonBuffer, SingletonView},
terminal::{
TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle, TerminalView,
},
tree_nav::{TreeCursor, TreeNav, TreeNavResult, TerminalTreeEditor},
},
std::sync::Arc,
std::sync::RwLock,
termion::event::{Event, Key},
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct CharEditor {
data: SingletonBuffer<Option<char>>,
data_port: ViewPort<dyn SingletonView<Item = Option<char>>>,
}
impl CharEditor {
pub fn new() -> Self {
let data_port = ViewPort::new();
CharEditor {
data: SingletonBuffer::new(None, data_port.inner()),
data_port,
}
}
pub fn get_data_port(&self) -> OuterViewPort<dyn SingletonView<Item = Option<char>>> {
self.data_port.outer()
}
}
impl TreeNav for CharEditor {}
impl TerminalEditor for CharEditor {
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
crate::terminal::make_label(&if let Some(c) = self.data.get() {
c.to_string()
} else {
"".to_string()
})
}
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
match event {
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => TerminalEditorResult::Continue,
TerminalEvent::Input(Event::Key(Key::Char(c))) => {
self.data.set(Some(*c));
TerminalEditorResult::Exit
}
TerminalEvent::Input(Event::Key(Key::Backspace))
| TerminalEvent::Input(Event::Key(Key::Delete)) => {
self.data.set(None);
TerminalEditorResult::Exit
}
_ => TerminalEditorResult::Continue,
}
}
}
impl TerminalTreeEditor for CharEditor {}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct StringEditor {
chars_editor:
ListEditor<CharEditor, Box<dyn Fn() -> Arc<RwLock<CharEditor>> + Send + Sync + 'static>>,
}
impl StringEditor {
pub fn new() -> Self {
StringEditor {
chars_editor: ListEditor::new(
Box::new(move || Arc::new(RwLock::new(CharEditor::new()))),
crate::list::ListEditorStyle::String,
),
}
}
pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = char>> {
self.chars_editor
.get_data_port()
.map(|char_editor| char_editor.read().unwrap().data.get().unwrap_or('?'))
}
pub fn get_plain_editor_view(&self) -> OuterViewPort<dyn TerminalView> {
self.chars_editor
.get_seg_seq_view()
.to_grid_horizontal()
.flatten()
}
pub fn get_string(&self) -> String {
self.get_data_port().get_view().unwrap().iter().collect()
}
}
impl TreeNav for StringEditor {
fn get_cursor(&self) -> TreeCursor {
self.chars_editor.get_cursor()
}
fn goto(&mut self, cur: TreeCursor) -> TreeNavResult {
self.chars_editor.goto(cur)
}
fn goto_home(&mut self) -> TreeNavResult {
self.chars_editor.goto_home()
}
fn goto_end(&mut self) -> TreeNavResult {
self.chars_editor.goto_end()
}
fn pxev(&mut self) -> TreeNavResult {
self.chars_editor.pxev()
}
fn nexd(&mut self) -> TreeNavResult {
self.chars_editor.nexd()
}
fn up(&mut self) -> TreeNavResult {
self.chars_editor.up()
}
fn dn(&mut self) -> TreeNavResult {
self.chars_editor.dn()
}
}
impl TerminalEditor for StringEditor {
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
self.chars_editor
.get_seg_seq_view()
.decorate("\"", "\"", "", 1)
.to_grid_horizontal()
.flatten()
.map_item(|_idx, atom| atom.add_style_back(TerminalStyle::fg_color((120, 200, 10))))
}
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
match event {
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
self.chars_editor.up();
TerminalEditorResult::Exit
}
event => self.chars_editor.handle_terminal_event(event),
}
}
}
impl TerminalTreeEditor for StringEditor {}

View file

@ -1,4 +1,7 @@
use crate::list::ListCursorMode;
use {
crate::list::ListCursorMode,
cgmath::Vector2
};
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum TreeNavResult {
@ -20,49 +23,43 @@ impl From<TreeNavResult> for TerminalEditorResult {
#[derive(Clone, Eq, PartialEq)]
pub struct TreeCursor {
pub leaf_mode: ListCursorMode,
pub tree_addr: Vec<usize>,
pub tree_addr: Vec<isize>,
}
impl TreeCursor {
pub fn home() -> Self {
TreeCursor {
leaf_mode: ListCursorMode::Select,
leaf_mode: ListCursorMode::Insert,
tree_addr: vec![0]
}
}
pub fn none() -> Self {
TreeCursor {
leaf_mode: ListCursorMode::Insert,
tree_addr: vec![],
}
}
}
impl Default for TreeCursor {
fn default() -> Self {
TreeCursor {
leaf_mode: ListCursorMode::Select,
tree_addr: vec![],
}
TreeCursor::none()
}
}
pub trait TreeNav {
fn up(&mut self) -> TreeNavResult {
TreeNavResult::Exit
/* CORE
*/
fn get_cursor(&self) -> TreeCursor {
TreeCursor::default()
}
fn dn(&mut self) -> TreeNavResult {
TreeNavResult::Exit
fn get_cursor_warp(&self) -> TreeCursor {
TreeCursor::default()
}
fn pxev(&mut self) -> TreeNavResult {
TreeNavResult::Exit
}
fn nexd(&mut self) -> TreeNavResult {
TreeNavResult::Exit
}
fn goto_home(&mut self) -> TreeNavResult {
TreeNavResult::Exit
}
fn goto_end(&mut self) -> TreeNavResult {
fn goby(&mut self, direction: Vector2<isize>) -> TreeNavResult {
TreeNavResult::Exit
}
@ -70,8 +67,85 @@ pub trait TreeNav {
TreeNavResult::Exit
}
fn get_cursor(&self) -> TreeCursor {
TreeCursor::default()
/* HULL
*/
fn set_addr(&mut self, addr: isize) -> TreeNavResult {
let mut c = self.get_cursor();
c.tree_addr[0] = addr;
self.goto(c)
}
fn set_leaf_mode(&mut self, new_leaf_mode: ListCursorMode) -> TreeNavResult {
let mut c = self.get_cursor();
c.leaf_mode = new_leaf_mode;
self.goto(c)
}
fn up(&mut self) -> TreeNavResult {
self.goby(Vector2::new(0, -1))
}
fn dn(&mut self) -> TreeNavResult {
self.goby(Vector2::new(0, 1))
}
fn pxev(&mut self) -> TreeNavResult {
self.goby(Vector2::new(-1, 0))
}
fn nexd(&mut self) -> TreeNavResult {
self.goby(Vector2::new(1, 0))
}
// TODO
fn qpxev(&mut self) -> TreeNavResult {
let mut c = self.get_cursor();
match c.tree_addr.len() {
0 => {
self.goto(TreeCursor::home())
},
depth => {
if c.tree_addr[depth-1] != 0 {
c.tree_addr[depth-1] = 0;
} else {
for i in (0..depth-1).rev() {
if c.tree_addr[i] == 0 {
c.tree_addr[i] = -1;
} else {
c.tree_addr[i] -=1;
break;
}
}
}
self.goto(c)
}
}
}
fn qnexd(&mut self) -> TreeNavResult {
let mut c = self.get_cursor_warp();
match c.tree_addr.len() {
0 => {
TreeNavResult::Exit
},
depth => {
if c.tree_addr[depth-1] != -1 {
c.tree_addr[depth-1] = -1;
} else {
for i in (0..depth-1).rev() {
if c.tree_addr[i] == -1 {
c.tree_addr[i] = 0;
} else {
c.tree_addr[i] += 1;
break;
}
}
}
self.goto(c)
}
}
}
}

194
shell/src/command.rs Normal file
View file

@ -0,0 +1,194 @@
use {
std::{
sync::{Arc, RwLock},
collections::HashMap
},
cgmath::{Point2},
termion::event::{Event, Key},
nested::{
list::{sexpr::ListDecoration, ListEditor, ListEditorStyle},
core::TypeTerm,
core::{OuterViewPort, ViewPort},
index::{IndexArea, IndexView},
string_editor::StringEditor,
vec::VecBuffer,
terminal::{
TerminalAtom, TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle, TerminalView, make_label
},
tree_nav::{TreeCursor, TreeNav, TreeNavResult},
}
};
trait Action {
fn make_editor(&self) ->
(Arc<RwLock<dyn TerminalEditor + Send + Sync>>,
Arc<RwLock<dyn TreeNav + Send + Sync>>);
}
pub struct ActCd {}
impl Action for ActCd {
fn make_editor(&self) ->
(Arc<RwLock<dyn TerminalEditor + Send + Sync>>,
Arc<RwLock<dyn TreeNav + Send + Sync>>)
{
let ed =
Arc::new(RwLock::new(ListEditor::new(
Box::new(|| {
Arc::new(RwLock::new(StringEditor::new()))
}) as Box<dyn Fn() -> Arc<RwLock<StringEditor>> + Send + Sync>,
ListEditorStyle::HorizontalSexpr,
)));
//Arc::new(RwLock::new(StringEditor::new()));
(ed.clone() as Arc<RwLock<dyn TerminalEditor + Send + Sync>>, ed as Arc<RwLock<dyn TreeNav + Send + Sync>>)
}
}
pub struct Commander {
cmds: HashMap<String, Arc<dyn Action + Send + Sync>>,
symbol_editor: StringEditor,
cmd_editor: Option<(
Arc<RwLock<dyn TerminalEditor + Send + Sync>>,
Arc<RwLock<dyn TreeNav + Send + Sync>>
)>,
view_elements: VecBuffer<OuterViewPort<dyn TerminalView>>,
out_port: OuterViewPort<dyn TerminalView>,
}
impl Commander {
pub fn new() -> Self {
let port = ViewPort::new();
let mut view_elements = VecBuffer::new(port.inner());
let symbol_editor = StringEditor::new();
view_elements.push(symbol_editor.get_plain_editor_view());
let mut cmds = HashMap::new();
cmds.insert("cd".into(), Arc::new(ActCd{}) as Arc<dyn Action + Send + Sync>);
cmds.insert("echo".into(), Arc::new(ActCd{}) as Arc<dyn Action + Send + Sync>);
cmds.insert("ls".into(), Arc::new(ActCd{}) as Arc<dyn Action + Send + Sync>);
let mut c = Commander {
cmds,
symbol_editor,
cmd_editor: None,
view_elements,
out_port: port.outer()
.to_sequence()
.to_grid_horizontal()
.flatten()
};
c
}
}
impl TerminalEditor for Commander {
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
self.out_port.clone()
}
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
if let Some(cmd_editor) = self.cmd_editor.as_ref() {
match event {
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
// run
cmd_editor.1.write().unwrap().up();
TerminalEditorResult::Exit
}
event => {
cmd_editor.0.write().unwrap().handle_terminal_event(event)
}
}
} else {
match event {
TerminalEvent::Input(Event::Key(Key::Char(' '))) |
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
let symbol = self.symbol_editor.get_string();
if let Some(action) = self.cmds.get(&symbol) {
let editor = action.make_editor();
self.symbol_editor.up();
self.view_elements.push(make_label(" "));
self.view_elements.push(editor.0.read().unwrap().get_term_view());
editor.1.write().unwrap().goto_home();
self.cmd_editor = Some(editor);
}
TerminalEditorResult::Continue
}
event => {
self.symbol_editor.handle_terminal_event(event)
}
}
}
}
}
impl TreeNav for Commander {
fn get_cursor(&self) -> TreeCursor {
if let Some(cmd_editor) = self.cmd_editor.as_ref() {
cmd_editor.1.write().unwrap().get_cursor()
} else {
self.symbol_editor.get_cursor()
}
}
fn goto(&mut self, cur: TreeCursor) -> TreeNavResult {
if let Some(cmd_editor) = self.cmd_editor.as_ref() {
cmd_editor.1.write().unwrap().goto(cur)
} else {
self.symbol_editor.goto(cur)
}
}
fn goto_home(&mut self) -> TreeNavResult {
if let Some(cmd_editor) = self.cmd_editor.as_ref() {
cmd_editor.1.write().unwrap().goto_home()
} else {
self.symbol_editor.goto_home()
}
}
fn goto_end(&mut self) -> TreeNavResult {
if let Some(cmd_editor) = self.cmd_editor.as_ref() {
cmd_editor.1.write().unwrap().goto_end()
} else {
self.symbol_editor.goto_end()
}
}
fn pxev(&mut self) -> TreeNavResult {
if let Some(cmd_editor) = self.cmd_editor.as_ref() {
cmd_editor.1.write().unwrap().pxev()
} else {
self.symbol_editor.pxev()
}
}
fn nexd(&mut self) -> TreeNavResult {
if let Some(cmd_editor) = self.cmd_editor.as_ref() {
cmd_editor.1.write().unwrap().nexd()
} else {
self.symbol_editor.nexd()
}
}
fn up(&mut self) -> TreeNavResult {
if let Some(cmd_editor) = self.cmd_editor.as_ref() {
cmd_editor.1.write().unwrap().up()
} else {
self.symbol_editor.up()
}
}
fn dn(&mut self) -> TreeNavResult {
if let Some(cmd_editor) = self.cmd_editor.as_ref() {
cmd_editor.1.write().unwrap().dn()
} else {
self.symbol_editor.dn()
}
}
}

View file

@ -13,12 +13,13 @@ use {
nested::{
core::{port::UpdateTask, Observer, OuterViewPort, ViewPort},
index::IndexArea,
list::{ListCursorMode, ListEditor, ListEditorStyle},
list::{ListCursorMode, PTYListEditor},
sequence::{decorator::{SeqDecorStyle}},
terminal::{
make_label, Terminal, TerminalAtom, TerminalCompositor, TerminalEditor,
TerminalEditorResult, TerminalEvent, TerminalStyle, TerminalView,
},
tree_nav::{TerminalTreeEditor, TreeCursor, TreeNavResult},
tree_nav::{TreeNav, TerminalTreeEditor, TreeCursor, TreeNavResult},
vec::VecBuffer,
},
std::sync::{Arc, RwLock},
@ -34,9 +35,7 @@ async fn main() {
let term_writer = term.get_writer();
async_std::task::spawn(async move {
let table_port =
ViewPort::<dyn nested::grid::GridView<Item = OuterViewPort<dyn TerminalView>>>::new();
let mut table_buf = nested::index::buffer::IndexBuffer::new(table_port.inner());
let mut table = nested::index::buffer::IndexBuffer::new();
let magic =
make_label("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>").map_item(|pos, atom| {
@ -47,21 +46,17 @@ async fn main() {
)))
});
let cur_size_port = ViewPort::new();
let mut cur_size =
nested::singleton::SingletonBuffer::new(Vector2::new(10, 10), cur_size_port.inner());
let mut cur_size = nested::singleton::SingletonBuffer::new(Vector2::new(10, 10));
let mut status_chars = VecBuffer::new();
let status_chars_port = ViewPort::new();
let mut status_chars = VecBuffer::new(status_chars_port.inner());
let mut process_list_editor = ListEditor::new(
let mut process_list_editor = PTYListEditor::new(
Box::new(|| Arc::new(RwLock::new(ProcessLauncher::new()))),
ListEditorStyle::VerticalSexpr,
SeqDecorStyle::VerticalSexpr,
0
);
let plist_vec_port = ViewPort::new();
let mut plist = VecBuffer::new(plist_vec_port.inner());
let mut plist = VecBuffer::new();
let mut plist_port = plist.get_port();
async_std::task::spawn(async move {
let (w, _h) = termion::terminal_size().unwrap();
let mut x: usize = 0;
@ -89,13 +84,13 @@ async fn main() {
});
let plot_port = ViewPort::new();
let _plot = crate::plot::Plot::new(plist_vec_port.outer().to_sequence(), plot_port.inner());
let _plot = crate::plot::Plot::new(plist_port.to_sequence(), plot_port.inner());
table_buf.insert_iter(vec![
table.insert_iter(vec![
(Point2::new(0, 0), magic.clone()),
(
Point2::new(0, 1),
status_chars_port.outer().to_sequence().to_grid_horizontal(),
status_chars.get_port().to_sequence().to_grid_horizontal(),
),
(Point2::new(0, 2), magic.clone()),
(Point2::new(0, 3), process_list_editor.get_term_view()),
@ -104,8 +99,7 @@ async fn main() {
let (w, h) = termion::terminal_size().unwrap();
compositor.write().unwrap().push(
plot_port
.outer()
plot_port.outer()
.map_item(|pt, a| {
a.add_style_back(TerminalStyle::fg_color((
255 - pt.y as u8 * 8,
@ -124,7 +118,7 @@ async fn main() {
compositor
.write()
.unwrap()
.push(table_port.outer().flatten().offset(Vector2::new(3, 0)));
.push(table.get_port().flatten().offset(Vector2::new(3, 0)));
process_list_editor.goto(TreeCursor {
leaf_mode: ListCursorMode::Insert,
@ -165,8 +159,7 @@ async fn main() {
));
for c in match cur.leaf_mode {
ListCursorMode::Insert => "INSERT",
ListCursorMode::Select => "SELECT",
ListCursorMode::Modify => "MODIFY",
ListCursorMode::Select => "SELECT"
}
.chars()
{
@ -226,19 +219,19 @@ async fn main() {
TerminalEvent::Input(Event::Key(Key::Up)) => {
if process_list_editor.up() == TreeNavResult::Exit {
process_list_editor.dn();
process_list_editor.goto_home();
}
}
TerminalEvent::Input(Event::Key(Key::Down)) => {
if process_list_editor.dn() == TreeNavResult::Continue {
process_list_editor.goto_home();
}
process_list_editor.dn();
// == TreeNavResult::Continue {
//process_list_editor.goto_home();
//}
}
TerminalEvent::Input(Event::Key(Key::Home)) => {
process_list_editor.goto_home();
process_list_editor.qpxev();
}
TerminalEvent::Input(Event::Key(Key::End)) => {
process_list_editor.goto_end();
process_list_editor.qnexd();
}
ev => {
if process_list_editor.get_cursor().leaf_mode == ListCursorMode::Select {
@ -256,10 +249,10 @@ async fn main() {
process_list_editor.nexd();
}
TerminalEvent::Input(Event::Key(Key::Char('u'))) => {
process_list_editor.goto_home();
process_list_editor.qpxev();
}
TerminalEvent::Input(Event::Key(Key::Char('o'))) => {
process_list_editor.goto_end();
process_list_editor.qnexd();
}
_ => {
process_list_editor.handle_terminal_event(&ev);

View file

@ -2,10 +2,10 @@ use {
crate::pty::{PTYStatus, PTY},
nested::{
core::{OuterViewPort, ViewPort},
list::{sexpr::ListDecoration, ListCursorMode, ListEditor, ListEditorStyle},
sequence::{SequenceView, SequenceViewExt},
list::{ListCursorMode, PTYListEditor},
sequence::{SequenceView, SequenceViewExt, decorator::{SeqDecorStyle, Separate, Wrap}},
singleton::SingletonView,
string_editor::CharEditor,
char_editor::CharEditor,
terminal::{
TerminalAtom, TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle,
TerminalView,
@ -15,13 +15,14 @@ use {
std::sync::Arc,
std::sync::RwLock,
termion::event::{Event, Key},
cgmath::Vector2
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct ProcessArg {
editor:
ListEditor<CharEditor, Box<dyn Fn() -> Arc<RwLock<CharEditor>> + Send + Sync + 'static>>,
PTYListEditor<CharEditor>,
}
impl ProcessArg {
@ -30,7 +31,7 @@ impl ProcessArg {
char_editor
.read()
.unwrap()
.get_data_port()
.get_port()
.get_view()
.unwrap()
.get()
@ -41,10 +42,7 @@ impl ProcessArg {
impl TerminalEditor for ProcessArg {
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
self.editor
.get_seg_seq_view()
.to_grid_horizontal()
.flatten()
self.editor.get_term_view()
}
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
@ -64,32 +62,21 @@ impl TreeNav for ProcessArg {
fn get_cursor(&self) -> TreeCursor {
self.editor.get_cursor()
}
fn get_cursor_warp(&self) -> TreeCursor {
self.editor.get_cursor_warp()
}
fn goto(&mut self, cur: TreeCursor) -> TreeNavResult {
self.editor.goto(cur)
}
fn goto_home(&mut self) -> TreeNavResult {
self.editor.goto_home()
}
fn goto_end(&mut self) -> TreeNavResult {
self.editor.goto_end()
}
fn pxev(&mut self) -> TreeNavResult {
self.editor.pxev()
}
fn nexd(&mut self) -> TreeNavResult {
self.editor.nexd()
}
fn up(&mut self) -> TreeNavResult {
self.editor.up()
}
fn dn(&mut self) -> TreeNavResult {
self.editor.dn()
fn goby(&mut self, dir: Vector2<isize>) -> TreeNavResult {
self.editor.goby(dir)
}
}
impl TerminalTreeEditor for ProcessArg {}
pub struct ProcessLauncher {
cmd_editor:
ListEditor<ProcessArg, Box<dyn Fn() -> Arc<RwLock<ProcessArg>> + Send + Sync + 'static>>,
cmd_editor: PTYListEditor<ProcessArg>,
pty: Option<crate::pty::PTY>,
_ptybox: Arc<RwLock<crate::ascii_box::AsciiBox>>,
suspended: bool,
@ -109,16 +96,18 @@ impl ProcessLauncher {
let box_port = ViewPort::<dyn TerminalView>::new();
let compositor = nested::terminal::TerminalCompositor::new(comp_port.inner());
let cmd_editor = ListEditor::new(
let cmd_editor = PTYListEditor::new(
Box::new(|| {
Arc::new(RwLock::new(ProcessArg {
editor: ListEditor::new(
editor: PTYListEditor::new(
Box::new(|| Arc::new(RwLock::new(CharEditor::new()))),
ListEditorStyle::Plain,
SeqDecorStyle::Plain,
1
),
}))
}) as Box<dyn Fn() -> Arc<RwLock<ProcessArg>> + Send + Sync>,
ListEditorStyle::Plain,
SeqDecorStyle::HorizontalSexpr,
0
);
compositor.write().unwrap().push(
@ -127,11 +116,7 @@ impl ProcessLauncher {
.map_item(|_idx, x| x.add_style_back(TerminalStyle::fg_color((90, 120, 100)))),
);
compositor.write().unwrap().push(
cmd_editor
.get_seg_seq_view()
.decorate("$(", ")", " ", 0)
.to_grid_horizontal()
.flatten(),
cmd_editor.get_term_view()
);
ProcessLauncher {
@ -251,6 +236,9 @@ impl TreeNav for ProcessLauncher {
fn get_cursor(&self) -> TreeCursor {
self.cmd_editor.get_cursor()
}
fn get_cursor_warp(&self) -> TreeCursor {
self.cmd_editor.get_cursor_warp()
}
fn goto(&mut self, cur: TreeCursor) -> TreeNavResult {
self.suspended = false;
@ -269,27 +257,10 @@ impl TreeNav for ProcessLauncher {
}
}
fn goto_home(&mut self) -> TreeNavResult {
self.cmd_editor.goto_home()
fn goby(&mut self, dir: Vector2<isize>) -> TreeNavResult {
self.cmd_editor.goby(dir)
}
fn goto_end(&mut self) -> TreeNavResult {
self.cmd_editor.goto_end()
}
fn pxev(&mut self) -> TreeNavResult {
self.cmd_editor.pxev()
}
fn nexd(&mut self) -> TreeNavResult {
self.cmd_editor.nexd()
}
fn up(&mut self) -> TreeNavResult {
self.cmd_editor.up()
}
fn dn(&mut self) -> TreeNavResult {
self.cmd_editor.dn()
}
}
impl TerminalTreeEditor for ProcessLauncher {}

View file

@ -57,7 +57,7 @@ impl PTY {
if let Ok(child) = pair.slave.spawn_command(cmd) {
let mut reader = pair.master.try_clone_reader().unwrap();
let mut status_buf = SingletonBuffer::new(
let mut status_buf = SingletonBuffer::with_port(
PTYStatus::Running {
pid: child.process_id().expect(""),
},