listeditor cleanup
This commit is contained in:
parent
d6fe977183
commit
5fef75e24f
25 changed files with 1342 additions and 1581 deletions
68
nested/src/char_editor.rs
Normal file
68
nested/src/char_editor.rs
Normal 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
25
nested/src/color.rs
Normal 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
core::{InnerViewPort, ViewPort, Observer, ObserverBroadcast, View},
|
core::{InnerViewPort, OuterViewPort, ViewPort, Observer, ObserverBroadcast, View},
|
||||||
index::{IndexArea, IndexView},
|
index::{IndexArea, IndexView},
|
||||||
},
|
},
|
||||||
std::sync::RwLock,
|
std::sync::RwLock,
|
||||||
|
@ -64,6 +64,10 @@ where
|
||||||
IndexBuffer::with_port(ViewPort::new().into_inner())
|
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) {
|
pub fn insert(&mut self, key: Key, item: Item) {
|
||||||
self.data.write().unwrap().insert(key.clone(), item);
|
self.data.write().unwrap().insert(key.clone(), item);
|
||||||
self.port.notify(&IndexArea::Set(vec![key]));
|
self.port.notify(&IndexArea::Set(vec![key]));
|
||||||
|
|
|
@ -127,6 +127,9 @@ impl TreeNav for PosIntEditor {
|
||||||
fn get_cursor(&self) -> TreeCursor {
|
fn get_cursor(&self) -> TreeCursor {
|
||||||
self.digits_editor.get_cursor()
|
self.digits_editor.get_cursor()
|
||||||
}
|
}
|
||||||
|
fn get_cursor_warp(&self) -> TreeCursor {
|
||||||
|
self.digits_editor.get_cursor_warp()
|
||||||
|
}
|
||||||
fn goto(&mut self, cur: TreeCursor) -> TreeNavResult {
|
fn goto(&mut self, cur: TreeCursor) -> TreeNavResult {
|
||||||
self.digits_editor.goto(cur)
|
self.digits_editor.goto(cur)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,34 @@
|
||||||
#![feature(trait_alias)]
|
#![feature(trait_alias)]
|
||||||
|
|
||||||
|
// general
|
||||||
pub mod core;
|
pub mod core;
|
||||||
pub mod projection;
|
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 index;
|
||||||
pub mod integer;
|
pub mod grid;
|
||||||
|
|
||||||
|
// implementation
|
||||||
|
pub mod vec;
|
||||||
|
|
||||||
|
// editors
|
||||||
|
pub mod tree_nav;
|
||||||
pub mod product;
|
pub mod product;
|
||||||
pub mod list;
|
pub mod list;
|
||||||
pub mod sequence;
|
|
||||||
pub mod singleton;
|
// high-level types
|
||||||
pub mod terminal;
|
pub mod char_editor;
|
||||||
pub mod vec;
|
pub mod integer;
|
||||||
pub mod make_editor;
|
pub mod make_editor;
|
||||||
|
|
||||||
pub mod tree_nav;
|
// display
|
||||||
|
pub mod color;
|
||||||
pub mod string_editor;
|
pub mod terminal;
|
||||||
|
|
||||||
pub mod bimap;
|
|
||||||
|
|
||||||
pub fn magic_header() {
|
pub fn magic_header() {
|
||||||
eprintln!("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>");
|
eprintln!("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>");
|
||||||
|
|
|
@ -1,33 +1,34 @@
|
||||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
pub enum ListCursorMode {
|
pub enum ListCursorMode {
|
||||||
Insert,
|
Insert,
|
||||||
Select,
|
Select
|
||||||
Modify,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
pub struct ListCursor {
|
pub struct ListCursor {
|
||||||
pub mode: ListCursorMode,
|
pub mode: ListCursorMode,
|
||||||
pub idx: Option<usize>,
|
pub idx: Option<isize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ListCursor {
|
impl ListCursor {
|
||||||
fn default() -> Self {
|
pub fn home() -> Self {
|
||||||
ListCursor {
|
ListCursor {
|
||||||
mode: ListCursorMode::Select,
|
mode: ListCursorMode::Insert,
|
||||||
|
idx: Some(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn none() -> Self {
|
||||||
|
ListCursor {
|
||||||
|
mode: ListCursorMode::Insert,
|
||||||
idx: None,
|
idx: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
impl Default for ListCursor {
|
||||||
pub trait ListNav {
|
fn default() -> Self {
|
||||||
fn pxev(&mut self) -> ListNavResult;
|
ListCursor::none()
|
||||||
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>;
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
|
@ -2,10 +2,11 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
core::{OuterViewPort, ViewPort},
|
core::{OuterViewPort, ViewPort},
|
||||||
list::{
|
list::{
|
||||||
editor_view::{ListEditorView, ListEditorViewSegment},
|
ListCursor, ListCursorMode,
|
||||||
ListCursor, ListCursorMode, ListDecoration, SExprView,
|
ListSegment, ListSegmentSequence,
|
||||||
|
segment::PTYSegment
|
||||||
},
|
},
|
||||||
sequence::SequenceView,
|
sequence::{SequenceView},
|
||||||
singleton::{SingletonBuffer, SingletonView},
|
singleton::{SingletonBuffer, SingletonView},
|
||||||
terminal::{
|
terminal::{
|
||||||
make_label, TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle,
|
make_label, TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle,
|
||||||
|
@ -13,696 +14,62 @@ use {
|
||||||
},
|
},
|
||||||
tree_nav::{TerminalTreeEditor, TreeCursor, TreeNav, TreeNavResult},
|
tree_nav::{TerminalTreeEditor, TreeCursor, TreeNav, TreeNavResult},
|
||||||
vec::VecBuffer,
|
vec::VecBuffer,
|
||||||
|
color::{bg_style_from_depth, fg_style_from_depth}
|
||||||
},
|
},
|
||||||
std::sync::{Arc, RwLock},
|
std::sync::{Arc, RwLock},
|
||||||
termion::event::{Event, Key},
|
termion::event::{Event, Key},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
pub enum ListEditorStyle {
|
|
||||||
HorizontalSexpr,
|
pub struct ListEditor<ItemEditor>
|
||||||
VerticalSexpr,
|
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static
|
||||||
Tuple(usize),
|
{
|
||||||
Path,
|
pub(super) cursor: SingletonBuffer<ListCursor>,
|
||||||
String,
|
pub(super) data: VecBuffer<Arc<RwLock<ItemEditor>>>,
|
||||||
Clist,
|
pub(super) make_item_editor: Box<dyn Fn() -> Arc<RwLock<ItemEditor>> + Send + Sync>,
|
||||||
Hex,
|
|
||||||
Plain,
|
pub(super) depth: usize,
|
||||||
|
pub(super) cur_dist: Arc<RwLock<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ListEditor<ItemEditor, FnMakeItemEditor>
|
impl<ItemEditor> ListEditor<ItemEditor>
|
||||||
where
|
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static
|
||||||
ItemEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
|
|
||||||
FnMakeItemEditor: Fn() -> Arc<RwLock<ItemEditor>>,
|
|
||||||
{
|
{
|
||||||
cursor: SingletonBuffer<ListCursor>,
|
pub fn new(make_item_editor: impl Into<Box<dyn Fn() -> Arc<RwLock<ItemEditor>> + Send + Sync>>, depth: usize) -> Self {
|
||||||
data: VecBuffer<Arc<RwLock<ItemEditor>>>,
|
ListEditor {
|
||||||
|
cursor: SingletonBuffer::new(ListCursor::default()),
|
||||||
cursor_port: ViewPort<dyn SingletonView<Item = ListCursor>>,
|
data: VecBuffer::<Arc<RwLock<ItemEditor>>>::new(),
|
||||||
data_port: ViewPort<RwLock<Vec<Arc<RwLock<ItemEditor>>>>>,
|
make_item_editor: make_item_editor.into(),
|
||||||
|
depth,
|
||||||
make_item_editor: FnMakeItemEditor,
|
cur_dist: Arc::new(RwLock::new(0)),
|
||||||
|
|
||||||
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![],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
pub fn get_seg_seq_view(
|
||||||
&self,
|
&self,
|
||||||
) -> OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>> {
|
) -> OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>> {
|
||||||
let segment_view_port = ViewPort::<dyn SequenceView<Item = ListEditorViewSegment>>::new();
|
let segment_view_port = ViewPort::<dyn SequenceView<Item = ListSegment<ItemEditor>>>::new();
|
||||||
ListEditorView::new(
|
ListSegmentSequence::new(
|
||||||
self.cursor_port.outer(),
|
self.get_cursor_port(),
|
||||||
self.data_port
|
self.get_data_port(),
|
||||||
.outer()
|
|
||||||
.to_sequence()
|
|
||||||
.map(|ed| ed.read().unwrap().get_term_view()),
|
|
||||||
segment_view_port.inner(),
|
segment_view_port.inner(),
|
||||||
|
self.depth
|
||||||
);
|
);
|
||||||
|
segment_view_port.into_outer().map(move |segment| segment.pty_view())
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = Arc<RwLock<ItemEditor>>>> {
|
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>> {
|
pub fn get_cursor_port(&self) -> OuterViewPort<dyn SingletonView<Item = ListCursor>> {
|
||||||
self.cursor_port.outer()
|
self.cursor.get_port()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_item(&self) -> Option<Arc<RwLock<ItemEditor>>> {
|
pub fn get_item(&self) -> Option<Arc<RwLock<ItemEditor>>> {
|
||||||
if let Some(idx) = self.cursor.get().idx {
|
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() {
|
if idx < self.data.len() {
|
||||||
Some(self.data.get(idx))
|
Some(self.data.get(idx))
|
||||||
} else {
|
} else {
|
||||||
|
@ -716,50 +83,5 @@ where
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.data.clear();
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +1,12 @@
|
||||||
|
|
||||||
pub mod cursor;
|
pub mod cursor;
|
||||||
|
pub mod segment;
|
||||||
pub mod editor;
|
pub mod editor;
|
||||||
pub mod editor_view;
|
pub mod nav;
|
||||||
pub mod sexpr;
|
pub mod pty_editor;
|
||||||
|
|
||||||
pub use cursor::{ListCursor, ListCursorMode};
|
pub use cursor::{ListCursor, ListCursorMode};
|
||||||
pub use editor::{ListEditor, ListEditorStyle};
|
pub use segment::{ListSegment, ListSegmentSequence};
|
||||||
pub use sexpr::{ListDecoration, SExprView};
|
pub use editor::ListEditor;
|
||||||
|
pub use pty_editor::PTYListEditor;
|
||||||
|
|
||||||
|
|
240
nested/src/list/nav.rs
Normal file
240
nested/src/list/nav.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
208
nested/src/list/pty_editor.rs
Normal file
208
nested/src/list/pty_editor.rs
Normal 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
176
nested/src/list/segment.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +1,17 @@
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
core::{ViewPort, OuterViewPort, Observer, port::UpdateTask, TypeTerm, TypeLadder, Context},
|
core::{TypeLadder, Context},
|
||||||
terminal::{
|
terminal::{TerminalView},
|
||||||
Terminal, TerminalAtom, TerminalCompositor, TerminalEditor,
|
tree_nav::{TerminalTreeEditor},
|
||||||
TerminalEditorResult, TerminalEvent, TerminalStyle, TerminalView,
|
|
||||||
make_label
|
|
||||||
},
|
|
||||||
sequence::{SequenceView},
|
|
||||||
tree_nav::{TreeNav, TerminalTreeEditor, TreeCursor, TreeNavResult},
|
|
||||||
vec::{VecBuffer, MutableVecAccess},
|
|
||||||
index::buffer::IndexBuffer,
|
|
||||||
integer::PosIntEditor,
|
integer::PosIntEditor,
|
||||||
string_editor::{StringEditor, CharEditor},
|
list::{ListEditor, PTYListEditor},
|
||||||
list::{ListEditor, ListCursorMode, ListEditorStyle},
|
sequence::{decorator::{SeqDecorStyle}},
|
||||||
product::editor::ProductEditor
|
product::editor::ProductEditor,
|
||||||
|
char_editor::CharEditor
|
||||||
},
|
},
|
||||||
cgmath::{Point2, Vector2},
|
cgmath::Vector2,
|
||||||
std::{sync::{Arc, RwLock}, ops::{Deref, DerefMut}},
|
std::sync::{Arc, RwLock},
|
||||||
termion::event::{Event, Key},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn make_editor(ctx: Arc<RwLock<Context>>, t: &TypeLadder, depth: usize) -> Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>> {
|
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>>
|
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() {
|
} 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() {
|
} else if t[0] == c.type_term_from_str("( List Char )").unwrap() {
|
||||||
Arc::new(RwLock::new(ListEditor::new(
|
Arc::new(RwLock::new(
|
||||||
|| { Arc::new(RwLock::new(CharEditor::new())) },
|
PTYListEditor::new(
|
||||||
ListEditorStyle::Plain
|
Box::new(
|
||||||
))) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
|
|| { 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() {
|
} else if t[0] == c.type_term_from_str("( List ℕ )").unwrap() {
|
||||||
Arc::new(RwLock::new(ListEditor::new(
|
Arc::new(RwLock::new(
|
||||||
|| {
|
PTYListEditor::new(
|
||||||
|
Box::new(|| {
|
||||||
Arc::new(RwLock::new(PosIntEditor::new(16)))
|
Arc::new(RwLock::new(PosIntEditor::new(16)))
|
||||||
},
|
}),
|
||||||
ListEditorStyle::HorizontalSexpr
|
SeqDecorStyle::EnumSet,
|
||||||
))) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
|
depth
|
||||||
|
)
|
||||||
|
)) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
|
||||||
|
|
||||||
} else if t[0] == c.type_term_from_str("( Path )").unwrap() {
|
} else if t[0] == c.type_term_from_str("( Path )").unwrap() {
|
||||||
Arc::new(RwLock::new(ListEditor::new(
|
let d = depth + 1;
|
||||||
|| {
|
Arc::new(RwLock::new(PTYListEditor::new(
|
||||||
Arc::new(RwLock::new(ListEditor::new(
|
Box::new({
|
||||||
|| {
|
let d= depth +1;
|
||||||
|
move || {
|
||||||
|
Arc::new(RwLock::new(PTYListEditor::new(
|
||||||
|
Box::new(|| {
|
||||||
Arc::new(RwLock::new(CharEditor::new()))
|
Arc::new(RwLock::new(CharEditor::new()))
|
||||||
},
|
}),
|
||||||
ListEditorStyle::Plain
|
SeqDecorStyle::Plain,
|
||||||
|
d
|
||||||
)))
|
)))
|
||||||
},
|
}}),
|
||||||
ListEditorStyle::Path
|
SeqDecorStyle::Path,
|
||||||
|
depth
|
||||||
))) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
|
))) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
|
||||||
|
|
||||||
} else if t[0] == c.type_term_from_str("( List RGB )").unwrap() {
|
} else if t[0] == c.type_term_from_str("( List RGB )").unwrap() {
|
||||||
Arc::new(RwLock::new(ListEditor::new({
|
Arc::new(RwLock::new(
|
||||||
|
PTYListEditor::<dyn TerminalTreeEditor + Send +Sync>::new(
|
||||||
|
Box::new({
|
||||||
|
let d = depth+1;
|
||||||
let ctx = ctx.clone();
|
let ctx = ctx.clone();
|
||||||
move || {
|
move || {
|
||||||
make_editor(ctx.clone(), &vec![ ctx.read().unwrap().type_term_from_str("( RGB )").unwrap() ], depth+1)
|
make_editor(ctx.clone(), &vec![ ctx.read().unwrap().type_term_from_str("( RGB )").unwrap() ], d)
|
||||||
}
|
}
|
||||||
},
|
}),
|
||||||
ListEditorStyle::VerticalSexpr
|
SeqDecorStyle::VerticalSexpr,
|
||||||
))) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
|
depth
|
||||||
|
)
|
||||||
|
)) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
|
||||||
|
|
||||||
} else if t[0] == c.type_term_from_str("( RGB )").unwrap() {
|
} else if t[0] == c.type_term_from_str("( RGB )").unwrap() {
|
||||||
Arc::new(RwLock::new(ProductEditor::new(depth, ctx.clone())
|
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>>
|
)) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
|
||||||
|
|
||||||
} else if t[0] == c.type_term_from_str("( List Term )").unwrap() {
|
} else if t[0] == c.type_term_from_str("( List Term )").unwrap() {
|
||||||
Arc::new(RwLock::new(ListEditor::new({
|
Arc::new(RwLock::new(
|
||||||
|
PTYListEditor::<dyn TerminalTreeEditor + Send + Sync>::new(
|
||||||
|
Box::new({
|
||||||
let ctx = ctx.clone();
|
let ctx = ctx.clone();
|
||||||
move || {
|
move || {
|
||||||
make_editor(ctx.clone(), &vec![ ctx.read().unwrap().type_term_from_str("( Term )").unwrap() ], depth+1)
|
make_editor(ctx.clone(), &vec![ ctx.read().unwrap().type_term_from_str("( Term )").unwrap() ], depth+1)
|
||||||
}
|
}
|
||||||
},
|
}),
|
||||||
ListEditorStyle::Tuple(depth)
|
SeqDecorStyle::Tuple,
|
||||||
))) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
|
depth
|
||||||
|
)
|
||||||
|
)) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
|
||||||
|
|
||||||
} else { // else: term
|
} else { // else: term
|
||||||
Arc::new(RwLock::new(
|
Arc::new(RwLock::new(
|
||||||
|
|
10
nested/src/modulo.rs
Normal file
10
nested/src/modulo.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
pub fn modulo(a: isize, b: isize) -> isize {
|
||||||
|
if b > 0 {
|
||||||
|
((a % b) + b) % b
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,19 @@
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
core::{ViewPort, OuterViewPort, Observer, port::UpdateTask, TypeTerm, TypeLadder, Context},
|
core::{ViewPort, OuterViewPort, TypeLadder, Context},
|
||||||
terminal::{
|
terminal::{
|
||||||
Terminal, TerminalAtom, TerminalCompositor, TerminalEditor,
|
TerminalEditor, TerminalEditorResult,
|
||||||
TerminalEditorResult, TerminalEvent, TerminalStyle, TerminalView,
|
TerminalEvent, TerminalView
|
||||||
make_label
|
|
||||||
},
|
},
|
||||||
sequence::{SequenceView},
|
sequence::{SequenceView},
|
||||||
tree_nav::{TreeNav, TerminalTreeEditor, TreeCursor, TreeNavResult},
|
tree_nav::{TreeNav, TerminalTreeEditor, TreeNavResult},
|
||||||
vec::{VecBuffer, MutableVecAccess},
|
vec::{VecBuffer, MutableVecAccess},
|
||||||
index::buffer::IndexBuffer,
|
list::ListCursorMode,
|
||||||
integer::PosIntEditor,
|
|
||||||
string_editor::{StringEditor, CharEditor},
|
|
||||||
list::{ListEditor, ListCursorMode, ListEditorStyle},
|
|
||||||
product::{element::ProductEditorElement},
|
product::{element::ProductEditorElement},
|
||||||
make_editor::make_editor
|
make_editor::make_editor
|
||||||
},
|
},
|
||||||
cgmath::{Point2, Vector2},
|
cgmath::Vector2,
|
||||||
std::{sync::{Arc, RwLock}, ops::{Deref, DerefMut}},
|
std::sync::{Arc, RwLock},
|
||||||
termion::event::{Event, Key},
|
termion::event::{Event, Key},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -31,8 +26,8 @@ pub struct ProductEditor {
|
||||||
|
|
||||||
pub(super) ctx: Arc<RwLock<Context>>,
|
pub(super) ctx: Arc<RwLock<Context>>,
|
||||||
|
|
||||||
pub(super) cursor: Option<usize>,
|
pub(super) cursor: Option<isize>,
|
||||||
pub(super) depth: usize
|
pub(super) depth: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProductEditor {
|
impl ProductEditor {
|
||||||
|
@ -46,7 +41,7 @@ impl ProductEditor {
|
||||||
});
|
});
|
||||||
|
|
||||||
ProductEditor {
|
ProductEditor {
|
||||||
elements: VecBuffer::new(port.inner()),
|
elements: VecBuffer::with_port(port.inner()),
|
||||||
el_port,
|
el_port,
|
||||||
el_view_port,
|
el_view_port,
|
||||||
n_indices: Vec::new(),
|
n_indices: Vec::new(),
|
||||||
|
@ -59,7 +54,7 @@ impl ProductEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_t(mut self, t: &str) -> Self {
|
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
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,22 +63,24 @@ impl ProductEditor {
|
||||||
self.elements.push(ProductEditorElement::N{
|
self.elements.push(ProductEditorElement::N{
|
||||||
t: n,
|
t: n,
|
||||||
editor: None,
|
editor: None,
|
||||||
select: false
|
cur_depth: 0
|
||||||
});
|
});
|
||||||
self.n_indices.push(elem_idx);
|
self.n_indices.push(elem_idx);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_editor_element(&self, idx: usize) -> Option<ProductEditorElement> {
|
pub fn get_editor_element(&self, mut idx: isize) -> Option<ProductEditorElement> {
|
||||||
if let Some(i) = self.n_indices.get(idx) {
|
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))
|
Some(self.elements.get(*i))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_editor_element_mut(&mut self, idx: usize) -> Option<MutableVecAccess<ProductEditorElement>> {
|
pub fn get_editor_element_mut(&mut self, mut idx: isize) -> Option<MutableVecAccess<ProductEditorElement>> {
|
||||||
if let Some(i) = self.n_indices.get(idx) {
|
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))
|
Some(self.elements.get_mut(*i))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -98,8 +95,8 @@ impl ProductEditor {
|
||||||
self.get_editor_element_mut(self.cursor?)
|
self.get_editor_element_mut(self.cursor?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_editor(&self, idx: usize) -> Option<Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>> {
|
pub fn get_editor(&self, idx: isize) -> Option<Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>> {
|
||||||
if let Some(ProductEditorElement::N{ t: _, editor, select: _ }) = self.get_editor_element(idx) {
|
if let Some(ProductEditorElement::N{ t: _, editor, cur_depth: _ }) = self.get_editor_element(idx) {
|
||||||
editor
|
editor
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -123,14 +120,15 @@ impl TerminalEditor for ProductEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
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() {
|
if let Some(ProductEditorElement::N{ t, editor, cur_depth }) = self.get_cur_element_mut().as_deref_mut() {
|
||||||
*select = true;
|
*cur_depth = self.get_cursor().tree_addr.len();
|
||||||
if let Some(e) = editor.clone() {
|
if let Some(e) = editor.clone() {
|
||||||
match e.clone().write().unwrap().handle_terminal_event(event) {
|
match e.clone().write().unwrap().handle_terminal_event(event) {
|
||||||
TerminalEditorResult::Exit =>
|
TerminalEditorResult::Exit =>
|
||||||
match event {
|
match event {
|
||||||
TerminalEvent::Input(Event::Key(Key::Backspace)) => {
|
TerminalEvent::Input(Event::Key(Key::Backspace)) => {
|
||||||
*editor = None;
|
*editor = None;
|
||||||
|
*cur_depth -= 1;
|
||||||
TerminalEditorResult::Continue
|
TerminalEditorResult::Continue
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -149,6 +147,7 @@ impl TerminalEditor for ProductEditor {
|
||||||
*editor = Some(e.clone());
|
*editor = Some(e.clone());
|
||||||
e.write().unwrap().dn();
|
e.write().unwrap().dn();
|
||||||
let x = e.write().unwrap().handle_terminal_event(event);
|
let x = e.write().unwrap().handle_terminal_event(event);
|
||||||
|
*cur_depth = self.get_cursor().tree_addr.len();
|
||||||
x
|
x
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,72 +1,55 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
core::{ViewPort, OuterViewPort, Observer, port::UpdateTask, TypeTerm, TypeLadder, Context},
|
core::{OuterViewPort, TypeLadder, Context},
|
||||||
terminal::{
|
terminal::{
|
||||||
Terminal, TerminalAtom, TerminalCompositor, TerminalEditor,
|
TerminalEditor, TerminalStyle, TerminalView,
|
||||||
TerminalEditorResult, TerminalEvent, TerminalStyle, TerminalView,
|
|
||||||
make_label
|
make_label
|
||||||
},
|
},
|
||||||
sequence::{SequenceView},
|
tree_nav::{TerminalTreeEditor},
|
||||||
tree_nav::{TreeNav, TerminalTreeEditor, TreeCursor, TreeNavResult},
|
color::{bg_style_from_depth, fg_style_from_depth}
|
||||||
vec::{VecBuffer, MutableVecAccess},
|
|
||||||
index::buffer::IndexBuffer,
|
|
||||||
integer::PosIntEditor,
|
|
||||||
string_editor::{StringEditor, CharEditor},
|
|
||||||
list::{ListEditor, ListCursorMode, ListEditorStyle}
|
|
||||||
},
|
},
|
||||||
cgmath::{Point2, Vector2},
|
|
||||||
std::{sync::{Arc, RwLock}, ops::{Deref, DerefMut}},
|
std::{sync::{Arc, RwLock}, ops::{Deref, DerefMut}},
|
||||||
termion::event::{Event, Key},
|
termion::event::{Event, Key},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum ProductEditorElement {
|
pub enum ProductEditorElement {
|
||||||
T( String ),
|
T( String, usize ),
|
||||||
N {
|
N {
|
||||||
t: TypeLadder,
|
t: TypeLadder,
|
||||||
editor: Option<Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>>,
|
editor: Option<Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>>,
|
||||||
select: bool
|
cur_depth: usize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProductEditorElement {
|
impl ProductEditorElement {
|
||||||
pub fn get_view(&self, ctx: Arc<RwLock<Context>>) -> OuterViewPort<dyn TerminalView> {
|
pub fn get_view(&self, ctx: Arc<RwLock<Context>>) -> OuterViewPort<dyn TerminalView> {
|
||||||
match self {
|
match self {
|
||||||
ProductEditorElement::T(t) =>
|
ProductEditorElement::T(t, depth) =>
|
||||||
make_label(t.as_str())
|
make_label(t.as_str())
|
||||||
.map_item(
|
.map_item({
|
||||||
|i, x|
|
let depth = *depth;
|
||||||
x.add_style_back(TerminalStyle::fg_color((0,120,200)))
|
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()
|
e.read().unwrap()
|
||||||
.get_term_view()
|
.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
|
move |i, x| x
|
||||||
.add_style_back(TerminalStyle::fg_color((250,210,0)))
|
.add_style_back(fg_style_from_depth(cur_depth))//fg_color((250,210,0)))
|
||||||
.add_style_back(
|
.add_style_back(bg_style_from_depth(cur_depth))
|
||||||
if select {
|
|
||||||
TerminalStyle::bg_color((40,40,40))
|
|
||||||
} else {
|
|
||||||
TerminalStyle::default()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
ProductEditorElement::N{t, editor: None, select} =>
|
ProductEditorElement::N{ t, editor: None, cur_depth } =>
|
||||||
make_label(&ctx.read().unwrap().type_term_to_str(&t[0]))
|
make_label(&ctx.read().unwrap().type_term_to_str(&t[0]))
|
||||||
.map_item({ let select = *select;
|
.map_item({
|
||||||
|
let cur_depth = *cur_depth;
|
||||||
move |i, x| x
|
move |i, x| x
|
||||||
.add_style_back(TerminalStyle::fg_color((130,90,40)))
|
.add_style_back(TerminalStyle::fg_color((130,90,40)))
|
||||||
.add_style_back(
|
.add_style_back(bg_style_from_depth(cur_depth))
|
||||||
if select {
|
|
||||||
TerminalStyle::bg_color((40,40,40))
|
|
||||||
} else {
|
|
||||||
TerminalStyle::default()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,8 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
core::{ViewPort, OuterViewPort, Observer, port::UpdateTask, TypeTerm, TypeLadder, Context},
|
list::ListCursorMode,
|
||||||
terminal::{
|
tree_nav::{TreeNav, TreeNavResult, TreeCursor, TerminalTreeEditor},
|
||||||
Terminal, TerminalAtom, TerminalCompositor, TerminalEditor,
|
product::{element::ProductEditorElement, ProductEditor}
|
||||||
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
|
|
||||||
},
|
},
|
||||||
cgmath::{Point2, Vector2},
|
cgmath::{Point2, Vector2},
|
||||||
std::{sync::{Arc, RwLock}, ops::{Deref, DerefMut}},
|
std::{sync::{Arc, RwLock}, ops::{Deref, DerefMut}},
|
||||||
|
@ -44,23 +32,23 @@ impl TreeNav for ProductEditor {
|
||||||
|
|
||||||
fn goto(&mut self, mut c: TreeCursor) -> TreeNavResult {
|
fn goto(&mut self, mut c: TreeCursor) -> TreeNavResult {
|
||||||
if let Some(mut element) = self.get_cur_element_mut() {
|
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 {
|
if let Some(e) = editor {
|
||||||
e.write().unwrap().goto(TreeCursor::default());
|
e.write().unwrap().goto(TreeCursor::default());
|
||||||
}
|
}
|
||||||
*select = false;
|
*cur_depth = self.get_cursor().tree_addr.len();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.tree_addr.len() > 0 {
|
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 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 {
|
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 {
|
fn goto_home(&mut self) -> TreeNavResult {
|
||||||
if let Some(c) = self.cursor {
|
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 {
|
if let Some(e) = editor {
|
||||||
let mut ce = e.write().unwrap();
|
let mut ce = e.write().unwrap();
|
||||||
|
|
||||||
|
@ -84,7 +76,7 @@ impl TreeNav for ProductEditor {
|
||||||
return match ce.goto_home() {
|
return match ce.goto_home() {
|
||||||
TreeNavResult::Exit => {
|
TreeNavResult::Exit => {
|
||||||
drop(ce);
|
drop(ce);
|
||||||
*select = false;
|
*cur_depth = 0;
|
||||||
|
|
||||||
match self.pxev() {
|
match self.pxev() {
|
||||||
TreeNavResult::Exit => TreeNavResult::Exit,
|
TreeNavResult::Exit => TreeNavResult::Exit,
|
||||||
|
@ -105,11 +97,11 @@ impl TreeNav for ProductEditor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*select = false;
|
*cur_depth = 0;
|
||||||
if c != 0 {
|
if c != 0 {
|
||||||
self.cursor = Some(0);
|
self.cursor = Some(0);
|
||||||
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() {
|
||||||
*select = true;
|
*cur_depth = self.get_cursor().tree_addr.len() + 1;
|
||||||
}
|
}
|
||||||
return TreeNavResult::Continue;
|
return TreeNavResult::Continue;
|
||||||
}
|
}
|
||||||
|
@ -121,7 +113,7 @@ impl TreeNav for ProductEditor {
|
||||||
|
|
||||||
fn goto_end(&mut self) -> TreeNavResult {
|
fn goto_end(&mut self) -> TreeNavResult {
|
||||||
if let Some(c) = self.cursor {
|
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 {
|
if let Some(e) = editor {
|
||||||
let mut ce = e.write().unwrap();
|
let mut ce = e.write().unwrap();
|
||||||
|
|
||||||
|
@ -132,7 +124,7 @@ impl TreeNav for ProductEditor {
|
||||||
match ce.goto_end() {
|
match ce.goto_end() {
|
||||||
TreeNavResult::Exit => {
|
TreeNavResult::Exit => {
|
||||||
drop(ce);
|
drop(ce);
|
||||||
*select = false;
|
*cur_depth = 0;
|
||||||
|
|
||||||
if c+1 < self.n_indices.len() {
|
if c+1 < self.n_indices.len() {
|
||||||
match self.nexd() {
|
match self.nexd() {
|
||||||
|
@ -158,11 +150,11 @@ impl TreeNav for ProductEditor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*select = false;
|
*cur_depth = 0;
|
||||||
if c < self.n_indices.len()-1 {
|
if c < self.n_indices.len()-1 {
|
||||||
self.cursor = Some(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() {
|
if let Some(ProductEditorElement::N{ t, editor, cur_depth }) = self.get_cur_element_mut().as_deref_mut() {
|
||||||
*select = true;
|
*cur_depth = self.get_cursor().tree_addr.len();
|
||||||
}
|
}
|
||||||
return TreeNavResult::Continue;
|
return TreeNavResult::Continue;
|
||||||
}
|
}
|
||||||
|
@ -174,7 +166,7 @@ impl TreeNav for ProductEditor {
|
||||||
|
|
||||||
fn pxev(&mut self) -> TreeNavResult {
|
fn pxev(&mut self) -> TreeNavResult {
|
||||||
if let Some(c) = self.cursor {
|
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 {
|
if let Some(e) = editor {
|
||||||
let mut ce = e.write().unwrap();
|
let mut ce = e.write().unwrap();
|
||||||
|
|
||||||
|
@ -185,12 +177,12 @@ impl TreeNav for ProductEditor {
|
||||||
return match ce.pxev() {
|
return match ce.pxev() {
|
||||||
TreeNavResult::Exit => {
|
TreeNavResult::Exit => {
|
||||||
drop(ce);
|
drop(ce);
|
||||||
*select = false;
|
*cur_depth = 0;
|
||||||
|
|
||||||
if c > 0 {
|
if c > 0 {
|
||||||
self.cursor = Some(c-1);
|
self.cursor = Some(c-1);
|
||||||
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() {
|
||||||
*select = true;
|
*cur_depth = self.get_cursor().tree_addr.len();
|
||||||
}
|
}
|
||||||
|
|
||||||
for _x in 1..depth {
|
for _x in 1..depth {
|
||||||
|
@ -212,11 +204,11 @@ impl TreeNav for ProductEditor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*select = false;
|
*cur_depth = 0;
|
||||||
if c > 0 {
|
if c > 0 {
|
||||||
self.cursor = Some(c-1);
|
self.cursor = Some(c-1);
|
||||||
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() {
|
||||||
*select = true;
|
*cur_depth = self.get_cursor().tree_addr.len();
|
||||||
}
|
}
|
||||||
return TreeNavResult::Continue;
|
return TreeNavResult::Continue;
|
||||||
}
|
}
|
||||||
|
@ -229,7 +221,7 @@ impl TreeNav for ProductEditor {
|
||||||
|
|
||||||
fn nexd(&mut self) -> TreeNavResult {
|
fn nexd(&mut self) -> TreeNavResult {
|
||||||
if let Some(c) = self.cursor.clone() {
|
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 {
|
if let Some(e) = editor {
|
||||||
let mut ce = e.write().unwrap();
|
let mut ce = e.write().unwrap();
|
||||||
|
|
||||||
|
@ -240,16 +232,17 @@ impl TreeNav for ProductEditor {
|
||||||
return match ce.nexd() {
|
return match ce.nexd() {
|
||||||
TreeNavResult::Exit => {
|
TreeNavResult::Exit => {
|
||||||
drop(ce);
|
drop(ce);
|
||||||
*select = false;
|
*cur_depth = 0;
|
||||||
|
|
||||||
if c+1 < self.n_indices.len() {
|
if c+1 < self.n_indices.len() {
|
||||||
self.cursor = Some(c+1);
|
self.cursor = Some(c+1);
|
||||||
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() {
|
||||||
*select = true;
|
*cur_depth = self.get_cursor().tree_addr.len();
|
||||||
}
|
}
|
||||||
|
|
||||||
for _x in 1..depth {
|
for _x in 1..depth {
|
||||||
self.dn();
|
self.dn();
|
||||||
|
self.goto_home();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.dn();
|
self.dn();
|
||||||
|
@ -266,11 +259,11 @@ impl TreeNav for ProductEditor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*select = false;
|
*cur_depth = 0;
|
||||||
if c+1 < self.n_indices.len() {
|
if c+1 < self.n_indices.len() {
|
||||||
self.cursor = Some(c+1);
|
self.cursor = Some(c+1);
|
||||||
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() {
|
||||||
*select = true;
|
*cur_depth = self.get_cursor().tree_addr.len();
|
||||||
}
|
}
|
||||||
|
|
||||||
return TreeNavResult::Continue;
|
return TreeNavResult::Continue;
|
||||||
|
@ -283,15 +276,16 @@ impl TreeNav for ProductEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn up(&mut self) -> TreeNavResult {
|
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 {
|
if let Some(e) = editor {
|
||||||
let mut ce = e.write().unwrap();
|
let mut ce = e.write().unwrap();
|
||||||
|
*cur_depth = ce.get_cursor().tree_addr.len();
|
||||||
if ce.get_cursor().tree_addr.len() > 0 {
|
if ce.get_cursor().tree_addr.len() > 0 {
|
||||||
ce.up();
|
ce.up();
|
||||||
return TreeNavResult::Continue;
|
return TreeNavResult::Continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*select = false;
|
*cur_depth = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.cursor = None;
|
self.cursor = None;
|
||||||
|
@ -300,24 +294,26 @@ impl TreeNav for ProductEditor {
|
||||||
|
|
||||||
fn dn(&mut self) -> TreeNavResult {
|
fn dn(&mut self) -> TreeNavResult {
|
||||||
if let Some(c) = self.cursor {
|
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 {
|
if let Some(e) = editor {
|
||||||
e.write().unwrap().dn();
|
e.write().unwrap().dn();
|
||||||
} else {
|
} else {
|
||||||
let e = make_editor(self.ctx.clone(), t, self.depth+1);
|
let e = make_editor(self.ctx.clone(), t, self.depth+1);
|
||||||
e.write().unwrap().goto_home();
|
e.write().unwrap().dn();
|
||||||
*editor = Some(e);
|
*editor = Some(e);
|
||||||
}
|
}
|
||||||
|
*cur_depth = self.get_cursor().tree_addr.len();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.cursor = Some(0);
|
self.cursor = Some(0);
|
||||||
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() {
|
||||||
*select = true;
|
*cur_depth = self.get_cursor().tree_addr.len();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TreeNavResult::Continue
|
TreeNavResult::Continue
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TerminalTreeEditor for ProductEditor {}
|
impl TerminalTreeEditor for ProductEditor {}
|
||||||
|
|
|
@ -228,13 +228,13 @@ impl PTYSeqDecorate for OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn
|
||||||
*/
|
*/
|
||||||
|
|
||||||
SeqDecorStyle::Tuple => self
|
SeqDecorStyle::Tuple => self
|
||||||
.separate(make_label(","))
|
.separate(make_label(", "))
|
||||||
.wrap(make_label("("), make_label(")"))
|
.wrap(make_label("("), make_label(")"))
|
||||||
.to_grid_horizontal()
|
.to_grid_horizontal()
|
||||||
.flatten(),
|
.flatten(),
|
||||||
|
|
||||||
SeqDecorStyle::EnumSet => self
|
SeqDecorStyle::EnumSet => self
|
||||||
.separate(make_label(","))
|
.separate(make_label(", "))
|
||||||
.wrap(make_label("{"), make_label("}"))
|
.wrap(make_label("{"), make_label("}"))
|
||||||
.to_grid_horizontal()
|
.to_grid_horizontal()
|
||||||
.flatten(),
|
.flatten(),
|
||||||
|
@ -246,7 +246,7 @@ impl PTYSeqDecorate for OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn
|
||||||
.flatten(),
|
.flatten(),
|
||||||
|
|
||||||
SeqDecorStyle::Hex => self
|
SeqDecorStyle::Hex => self
|
||||||
.wrap(make_label("0"), make_label(""))
|
.wrap(make_label("0x"), make_label(""))
|
||||||
.to_grid_horizontal()
|
.to_grid_horizontal()
|
||||||
.flatten(),
|
.flatten(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {}
|
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
use crate::list::ListCursorMode;
|
use {
|
||||||
|
crate::list::ListCursorMode,
|
||||||
|
cgmath::Vector2
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
pub enum TreeNavResult {
|
pub enum TreeNavResult {
|
||||||
|
@ -20,49 +23,43 @@ impl From<TreeNavResult> for TerminalEditorResult {
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
pub struct TreeCursor {
|
pub struct TreeCursor {
|
||||||
pub leaf_mode: ListCursorMode,
|
pub leaf_mode: ListCursorMode,
|
||||||
pub tree_addr: Vec<usize>,
|
pub tree_addr: Vec<isize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TreeCursor {
|
impl TreeCursor {
|
||||||
pub fn home() -> Self {
|
pub fn home() -> Self {
|
||||||
TreeCursor {
|
TreeCursor {
|
||||||
leaf_mode: ListCursorMode::Select,
|
leaf_mode: ListCursorMode::Insert,
|
||||||
tree_addr: vec![0]
|
tree_addr: vec![0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn none() -> Self {
|
||||||
|
TreeCursor {
|
||||||
|
leaf_mode: ListCursorMode::Insert,
|
||||||
|
tree_addr: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TreeCursor {
|
impl Default for TreeCursor {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
TreeCursor {
|
TreeCursor::none()
|
||||||
leaf_mode: ListCursorMode::Select,
|
|
||||||
tree_addr: vec![],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TreeNav {
|
pub trait TreeNav {
|
||||||
fn up(&mut self) -> TreeNavResult {
|
/* CORE
|
||||||
TreeNavResult::Exit
|
*/
|
||||||
|
fn get_cursor(&self) -> TreeCursor {
|
||||||
|
TreeCursor::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dn(&mut self) -> TreeNavResult {
|
fn get_cursor_warp(&self) -> TreeCursor {
|
||||||
TreeNavResult::Exit
|
TreeCursor::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pxev(&mut self) -> TreeNavResult {
|
fn goby(&mut self, direction: Vector2<isize>) -> TreeNavResult {
|
||||||
TreeNavResult::Exit
|
|
||||||
}
|
|
||||||
|
|
||||||
fn nexd(&mut self) -> TreeNavResult {
|
|
||||||
TreeNavResult::Exit
|
|
||||||
}
|
|
||||||
|
|
||||||
fn goto_home(&mut self) -> TreeNavResult {
|
|
||||||
TreeNavResult::Exit
|
|
||||||
}
|
|
||||||
|
|
||||||
fn goto_end(&mut self) -> TreeNavResult {
|
|
||||||
TreeNavResult::Exit
|
TreeNavResult::Exit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,8 +67,85 @@ pub trait TreeNav {
|
||||||
TreeNavResult::Exit
|
TreeNavResult::Exit
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_cursor(&self) -> TreeCursor {
|
/* HULL
|
||||||
TreeCursor::default()
|
*/
|
||||||
|
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
194
shell/src/command.rs
Normal 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,12 +13,13 @@ use {
|
||||||
nested::{
|
nested::{
|
||||||
core::{port::UpdateTask, Observer, OuterViewPort, ViewPort},
|
core::{port::UpdateTask, Observer, OuterViewPort, ViewPort},
|
||||||
index::IndexArea,
|
index::IndexArea,
|
||||||
list::{ListCursorMode, ListEditor, ListEditorStyle},
|
list::{ListCursorMode, PTYListEditor},
|
||||||
|
sequence::{decorator::{SeqDecorStyle}},
|
||||||
terminal::{
|
terminal::{
|
||||||
make_label, Terminal, TerminalAtom, TerminalCompositor, TerminalEditor,
|
make_label, Terminal, TerminalAtom, TerminalCompositor, TerminalEditor,
|
||||||
TerminalEditorResult, TerminalEvent, TerminalStyle, TerminalView,
|
TerminalEditorResult, TerminalEvent, TerminalStyle, TerminalView,
|
||||||
},
|
},
|
||||||
tree_nav::{TerminalTreeEditor, TreeCursor, TreeNavResult},
|
tree_nav::{TreeNav, TerminalTreeEditor, TreeCursor, TreeNavResult},
|
||||||
vec::VecBuffer,
|
vec::VecBuffer,
|
||||||
},
|
},
|
||||||
std::sync::{Arc, RwLock},
|
std::sync::{Arc, RwLock},
|
||||||
|
@ -34,9 +35,7 @@ async fn main() {
|
||||||
let term_writer = term.get_writer();
|
let term_writer = term.get_writer();
|
||||||
|
|
||||||
async_std::task::spawn(async move {
|
async_std::task::spawn(async move {
|
||||||
let table_port =
|
let mut table = nested::index::buffer::IndexBuffer::new();
|
||||||
ViewPort::<dyn nested::grid::GridView<Item = OuterViewPort<dyn TerminalView>>>::new();
|
|
||||||
let mut table_buf = nested::index::buffer::IndexBuffer::new(table_port.inner());
|
|
||||||
|
|
||||||
let magic =
|
let magic =
|
||||||
make_label("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>").map_item(|pos, atom| {
|
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));
|
||||||
let mut cur_size =
|
let mut status_chars = VecBuffer::new();
|
||||||
nested::singleton::SingletonBuffer::new(Vector2::new(10, 10), cur_size_port.inner());
|
|
||||||
|
|
||||||
let status_chars_port = ViewPort::new();
|
let mut process_list_editor = PTYListEditor::new(
|
||||||
let mut status_chars = VecBuffer::new(status_chars_port.inner());
|
|
||||||
|
|
||||||
let mut process_list_editor = ListEditor::new(
|
|
||||||
Box::new(|| Arc::new(RwLock::new(ProcessLauncher::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();
|
||||||
let mut plist = VecBuffer::new(plist_vec_port.inner());
|
let mut plist_port = plist.get_port();
|
||||||
|
|
||||||
async_std::task::spawn(async move {
|
async_std::task::spawn(async move {
|
||||||
let (w, _h) = termion::terminal_size().unwrap();
|
let (w, _h) = termion::terminal_size().unwrap();
|
||||||
let mut x: usize = 0;
|
let mut x: usize = 0;
|
||||||
|
@ -89,13 +84,13 @@ async fn main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let plot_port = ViewPort::new();
|
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, 0), magic.clone()),
|
||||||
(
|
(
|
||||||
Point2::new(0, 1),
|
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, 2), magic.clone()),
|
||||||
(Point2::new(0, 3), process_list_editor.get_term_view()),
|
(Point2::new(0, 3), process_list_editor.get_term_view()),
|
||||||
|
@ -104,8 +99,7 @@ async fn main() {
|
||||||
let (w, h) = termion::terminal_size().unwrap();
|
let (w, h) = termion::terminal_size().unwrap();
|
||||||
|
|
||||||
compositor.write().unwrap().push(
|
compositor.write().unwrap().push(
|
||||||
plot_port
|
plot_port.outer()
|
||||||
.outer()
|
|
||||||
.map_item(|pt, a| {
|
.map_item(|pt, a| {
|
||||||
a.add_style_back(TerminalStyle::fg_color((
|
a.add_style_back(TerminalStyle::fg_color((
|
||||||
255 - pt.y as u8 * 8,
|
255 - pt.y as u8 * 8,
|
||||||
|
@ -124,7 +118,7 @@ async fn main() {
|
||||||
compositor
|
compositor
|
||||||
.write()
|
.write()
|
||||||
.unwrap()
|
.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 {
|
process_list_editor.goto(TreeCursor {
|
||||||
leaf_mode: ListCursorMode::Insert,
|
leaf_mode: ListCursorMode::Insert,
|
||||||
|
@ -165,8 +159,7 @@ async fn main() {
|
||||||
));
|
));
|
||||||
for c in match cur.leaf_mode {
|
for c in match cur.leaf_mode {
|
||||||
ListCursorMode::Insert => "INSERT",
|
ListCursorMode::Insert => "INSERT",
|
||||||
ListCursorMode::Select => "SELECT",
|
ListCursorMode::Select => "SELECT"
|
||||||
ListCursorMode::Modify => "MODIFY",
|
|
||||||
}
|
}
|
||||||
.chars()
|
.chars()
|
||||||
{
|
{
|
||||||
|
@ -226,19 +219,19 @@ async fn main() {
|
||||||
TerminalEvent::Input(Event::Key(Key::Up)) => {
|
TerminalEvent::Input(Event::Key(Key::Up)) => {
|
||||||
if process_list_editor.up() == TreeNavResult::Exit {
|
if process_list_editor.up() == TreeNavResult::Exit {
|
||||||
process_list_editor.dn();
|
process_list_editor.dn();
|
||||||
process_list_editor.goto_home();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminalEvent::Input(Event::Key(Key::Down)) => {
|
TerminalEvent::Input(Event::Key(Key::Down)) => {
|
||||||
if process_list_editor.dn() == TreeNavResult::Continue {
|
process_list_editor.dn();
|
||||||
process_list_editor.goto_home();
|
// == TreeNavResult::Continue {
|
||||||
}
|
//process_list_editor.goto_home();
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
TerminalEvent::Input(Event::Key(Key::Home)) => {
|
TerminalEvent::Input(Event::Key(Key::Home)) => {
|
||||||
process_list_editor.goto_home();
|
process_list_editor.qpxev();
|
||||||
}
|
}
|
||||||
TerminalEvent::Input(Event::Key(Key::End)) => {
|
TerminalEvent::Input(Event::Key(Key::End)) => {
|
||||||
process_list_editor.goto_end();
|
process_list_editor.qnexd();
|
||||||
}
|
}
|
||||||
ev => {
|
ev => {
|
||||||
if process_list_editor.get_cursor().leaf_mode == ListCursorMode::Select {
|
if process_list_editor.get_cursor().leaf_mode == ListCursorMode::Select {
|
||||||
|
@ -256,10 +249,10 @@ async fn main() {
|
||||||
process_list_editor.nexd();
|
process_list_editor.nexd();
|
||||||
}
|
}
|
||||||
TerminalEvent::Input(Event::Key(Key::Char('u'))) => {
|
TerminalEvent::Input(Event::Key(Key::Char('u'))) => {
|
||||||
process_list_editor.goto_home();
|
process_list_editor.qpxev();
|
||||||
}
|
}
|
||||||
TerminalEvent::Input(Event::Key(Key::Char('o'))) => {
|
TerminalEvent::Input(Event::Key(Key::Char('o'))) => {
|
||||||
process_list_editor.goto_end();
|
process_list_editor.qnexd();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
process_list_editor.handle_terminal_event(&ev);
|
process_list_editor.handle_terminal_event(&ev);
|
||||||
|
|
|
@ -2,10 +2,10 @@ use {
|
||||||
crate::pty::{PTYStatus, PTY},
|
crate::pty::{PTYStatus, PTY},
|
||||||
nested::{
|
nested::{
|
||||||
core::{OuterViewPort, ViewPort},
|
core::{OuterViewPort, ViewPort},
|
||||||
list::{sexpr::ListDecoration, ListCursorMode, ListEditor, ListEditorStyle},
|
list::{ListCursorMode, PTYListEditor},
|
||||||
sequence::{SequenceView, SequenceViewExt},
|
sequence::{SequenceView, SequenceViewExt, decorator::{SeqDecorStyle, Separate, Wrap}},
|
||||||
singleton::SingletonView,
|
singleton::SingletonView,
|
||||||
string_editor::CharEditor,
|
char_editor::CharEditor,
|
||||||
terminal::{
|
terminal::{
|
||||||
TerminalAtom, TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle,
|
TerminalAtom, TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle,
|
||||||
TerminalView,
|
TerminalView,
|
||||||
|
@ -15,13 +15,14 @@ use {
|
||||||
std::sync::Arc,
|
std::sync::Arc,
|
||||||
std::sync::RwLock,
|
std::sync::RwLock,
|
||||||
termion::event::{Event, Key},
|
termion::event::{Event, Key},
|
||||||
|
cgmath::Vector2
|
||||||
};
|
};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub struct ProcessArg {
|
pub struct ProcessArg {
|
||||||
editor:
|
editor:
|
||||||
ListEditor<CharEditor, Box<dyn Fn() -> Arc<RwLock<CharEditor>> + Send + Sync + 'static>>,
|
PTYListEditor<CharEditor>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProcessArg {
|
impl ProcessArg {
|
||||||
|
@ -30,7 +31,7 @@ impl ProcessArg {
|
||||||
char_editor
|
char_editor
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get_data_port()
|
.get_port()
|
||||||
.get_view()
|
.get_view()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get()
|
.get()
|
||||||
|
@ -41,10 +42,7 @@ impl ProcessArg {
|
||||||
|
|
||||||
impl TerminalEditor for ProcessArg {
|
impl TerminalEditor for ProcessArg {
|
||||||
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
|
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
|
||||||
self.editor
|
self.editor.get_term_view()
|
||||||
.get_seg_seq_view()
|
|
||||||
.to_grid_horizontal()
|
|
||||||
.flatten()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
||||||
|
@ -64,32 +62,21 @@ impl TreeNav for ProcessArg {
|
||||||
fn get_cursor(&self) -> TreeCursor {
|
fn get_cursor(&self) -> TreeCursor {
|
||||||
self.editor.get_cursor()
|
self.editor.get_cursor()
|
||||||
}
|
}
|
||||||
|
fn get_cursor_warp(&self) -> TreeCursor {
|
||||||
|
self.editor.get_cursor_warp()
|
||||||
|
}
|
||||||
fn goto(&mut self, cur: TreeCursor) -> TreeNavResult {
|
fn goto(&mut self, cur: TreeCursor) -> TreeNavResult {
|
||||||
self.editor.goto(cur)
|
self.editor.goto(cur)
|
||||||
}
|
}
|
||||||
fn goto_home(&mut self) -> TreeNavResult {
|
fn goby(&mut self, dir: Vector2<isize>) -> TreeNavResult {
|
||||||
self.editor.goto_home()
|
self.editor.goby(dir)
|
||||||
}
|
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TerminalTreeEditor for ProcessArg {}
|
||||||
|
|
||||||
pub struct ProcessLauncher {
|
pub struct ProcessLauncher {
|
||||||
cmd_editor:
|
cmd_editor: PTYListEditor<ProcessArg>,
|
||||||
ListEditor<ProcessArg, Box<dyn Fn() -> Arc<RwLock<ProcessArg>> + Send + Sync + 'static>>,
|
|
||||||
pty: Option<crate::pty::PTY>,
|
pty: Option<crate::pty::PTY>,
|
||||||
_ptybox: Arc<RwLock<crate::ascii_box::AsciiBox>>,
|
_ptybox: Arc<RwLock<crate::ascii_box::AsciiBox>>,
|
||||||
suspended: bool,
|
suspended: bool,
|
||||||
|
@ -109,16 +96,18 @@ impl ProcessLauncher {
|
||||||
let box_port = ViewPort::<dyn TerminalView>::new();
|
let box_port = ViewPort::<dyn TerminalView>::new();
|
||||||
let compositor = nested::terminal::TerminalCompositor::new(comp_port.inner());
|
let compositor = nested::terminal::TerminalCompositor::new(comp_port.inner());
|
||||||
|
|
||||||
let cmd_editor = ListEditor::new(
|
let cmd_editor = PTYListEditor::new(
|
||||||
Box::new(|| {
|
Box::new(|| {
|
||||||
Arc::new(RwLock::new(ProcessArg {
|
Arc::new(RwLock::new(ProcessArg {
|
||||||
editor: ListEditor::new(
|
editor: PTYListEditor::new(
|
||||||
Box::new(|| Arc::new(RwLock::new(CharEditor::new()))),
|
Box::new(|| Arc::new(RwLock::new(CharEditor::new()))),
|
||||||
ListEditorStyle::Plain,
|
SeqDecorStyle::Plain,
|
||||||
|
1
|
||||||
),
|
),
|
||||||
}))
|
}))
|
||||||
}) as Box<dyn Fn() -> Arc<RwLock<ProcessArg>> + Send + Sync>,
|
}) as Box<dyn Fn() -> Arc<RwLock<ProcessArg>> + Send + Sync>,
|
||||||
ListEditorStyle::Plain,
|
SeqDecorStyle::HorizontalSexpr,
|
||||||
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
compositor.write().unwrap().push(
|
compositor.write().unwrap().push(
|
||||||
|
@ -127,11 +116,7 @@ impl ProcessLauncher {
|
||||||
.map_item(|_idx, x| x.add_style_back(TerminalStyle::fg_color((90, 120, 100)))),
|
.map_item(|_idx, x| x.add_style_back(TerminalStyle::fg_color((90, 120, 100)))),
|
||||||
);
|
);
|
||||||
compositor.write().unwrap().push(
|
compositor.write().unwrap().push(
|
||||||
cmd_editor
|
cmd_editor.get_term_view()
|
||||||
.get_seg_seq_view()
|
|
||||||
.decorate("$(", ")", " ", 0)
|
|
||||||
.to_grid_horizontal()
|
|
||||||
.flatten(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
ProcessLauncher {
|
ProcessLauncher {
|
||||||
|
@ -251,6 +236,9 @@ impl TreeNav for ProcessLauncher {
|
||||||
fn get_cursor(&self) -> TreeCursor {
|
fn get_cursor(&self) -> TreeCursor {
|
||||||
self.cmd_editor.get_cursor()
|
self.cmd_editor.get_cursor()
|
||||||
}
|
}
|
||||||
|
fn get_cursor_warp(&self) -> TreeCursor {
|
||||||
|
self.cmd_editor.get_cursor_warp()
|
||||||
|
}
|
||||||
|
|
||||||
fn goto(&mut self, cur: TreeCursor) -> TreeNavResult {
|
fn goto(&mut self, cur: TreeCursor) -> TreeNavResult {
|
||||||
self.suspended = false;
|
self.suspended = false;
|
||||||
|
@ -269,27 +257,10 @@ impl TreeNav for ProcessLauncher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn goto_home(&mut self) -> TreeNavResult {
|
fn goby(&mut self, dir: Vector2<isize>) -> TreeNavResult {
|
||||||
self.cmd_editor.goto_home()
|
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 {}
|
||||||
|
|
|
@ -57,7 +57,7 @@ impl PTY {
|
||||||
|
|
||||||
if let Ok(child) = pair.slave.spawn_command(cmd) {
|
if let Ok(child) = pair.slave.spawn_command(cmd) {
|
||||||
let mut reader = pair.master.try_clone_reader().unwrap();
|
let mut reader = pair.master.try_clone_reader().unwrap();
|
||||||
let mut status_buf = SingletonBuffer::new(
|
let mut status_buf = SingletonBuffer::with_port(
|
||||||
PTYStatus::Running {
|
PTYStatus::Running {
|
||||||
pid: child.process_id().expect(""),
|
pid: child.process_id().expect(""),
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue