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