product editor
This commit is contained in:
parent
61c2d55441
commit
f118eada34
17 changed files with 821 additions and 68 deletions
|
@ -1,8 +1,13 @@
|
||||||
use {
|
use {
|
||||||
crate::core::{
|
crate::{
|
||||||
type_term::{TypeDict, TypeTerm},
|
core::{
|
||||||
|
type_term::{TypeDict, TypeTerm, TypeID},
|
||||||
AnyOuterViewPort, OuterViewPort, View,
|
AnyOuterViewPort, OuterViewPort, View,
|
||||||
},
|
},
|
||||||
|
tree_nav::{
|
||||||
|
TerminalTreeEditor
|
||||||
|
}
|
||||||
|
},
|
||||||
std::{
|
std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
|
@ -232,10 +237,20 @@ pub struct MorphismType {
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
|
/// assigns a name to every type
|
||||||
type_dict: TypeDict,
|
type_dict: TypeDict,
|
||||||
|
|
||||||
|
/// objects
|
||||||
|
objects: HashMap<String, Object>,
|
||||||
|
|
||||||
|
/// editors
|
||||||
|
editor_ctors: HashMap<TypeID, Box<dyn Fn(&Self, TypeTerm) -> Option<Arc<RwLock<dyn TerminalTreeEditor>>> + Send + Sync>>,
|
||||||
|
|
||||||
|
/// morphisms
|
||||||
default_constructors: HashMap<TypeTerm, Box<dyn Fn() -> Object + Send + Sync>>,
|
default_constructors: HashMap<TypeTerm, Box<dyn Fn() -> Object + Send + Sync>>,
|
||||||
morphism_constructors: HashMap<MorphismType, Box<dyn Fn(Object) -> Object + Send + Sync>>,
|
morphism_constructors: HashMap<MorphismType, Box<dyn Fn(Object) -> Object + Send + Sync>>,
|
||||||
objects: HashMap<String, Object>,
|
|
||||||
|
/// recursion
|
||||||
parent: Option<Arc<RwLock<Context>>>,
|
parent: Option<Arc<RwLock<Context>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,6 +258,7 @@ impl Context {
|
||||||
pub fn with_parent(parent: Option<Arc<RwLock<Context>>>) -> Self {
|
pub fn with_parent(parent: Option<Arc<RwLock<Context>>>) -> Self {
|
||||||
Context {
|
Context {
|
||||||
type_dict: TypeDict::new(),
|
type_dict: TypeDict::new(),
|
||||||
|
editor_ctors: HashMap::new(),
|
||||||
default_constructors: HashMap::new(),
|
default_constructors: HashMap::new(),
|
||||||
morphism_constructors: HashMap::new(),
|
morphism_constructors: HashMap::new(),
|
||||||
objects: HashMap::new(),
|
objects: HashMap::new(),
|
||||||
|
@ -261,6 +277,26 @@ impl Context {
|
||||||
pub fn type_term_from_str(&self, tn: &str) -> Option<TypeTerm> {
|
pub fn type_term_from_str(&self, tn: &str) -> Option<TypeTerm> {
|
||||||
self.type_dict.type_term_from_str(&tn)
|
self.type_dict.type_term_from_str(&tn)
|
||||||
}
|
}
|
||||||
|
pub fn type_term_to_str(&self, t: &TypeTerm) -> String {
|
||||||
|
self.type_dict.type_term_to_str(&t)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_editor_ctor(&mut self, tn: &str, mk_editor: Box<dyn Fn(&Self, TypeTerm) -> Option<Arc<RwLock<dyn TerminalTreeEditor>>> + Send + Sync>) {
|
||||||
|
if let Some(tid) = self.type_dict.get_typeid(&tn.into()) {
|
||||||
|
self.editor_ctors.insert(tid, mk_editor);
|
||||||
|
} else {
|
||||||
|
println!("invalid type name");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_editor(&self, type_term: TypeTerm) -> Option<Arc<RwLock<dyn TerminalTreeEditor>>> {
|
||||||
|
if let TypeTerm::Type{ id, args } = type_term.clone() {
|
||||||
|
let mk_editor = self.editor_ctors.get(&id)?;
|
||||||
|
mk_editor(self, type_term)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_morphism(
|
pub fn add_morphism(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
|
@ -12,6 +12,6 @@ pub use {
|
||||||
port::{
|
port::{
|
||||||
AnyInnerViewPort, AnyOuterViewPort, AnyViewPort, InnerViewPort, OuterViewPort, ViewPort,
|
AnyInnerViewPort, AnyOuterViewPort, AnyViewPort, InnerViewPort, OuterViewPort, ViewPort,
|
||||||
},
|
},
|
||||||
type_term::{TypeDict, TypeID, TypeTerm},
|
type_term::{TypeDict, TypeID, TypeTerm, TypeLadder},
|
||||||
view::View,
|
view::View,
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,6 +3,7 @@ use {crate::bimap::Bimap, std::collections::HashMap};
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub type TypeID = u64;
|
pub type TypeID = u64;
|
||||||
|
pub type TypeLadder = Vec<TypeTerm>;
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
|
@ -105,7 +106,7 @@ impl TypeTerm {
|
||||||
pub fn to_str(&self, names: &HashMap<u64, String>) -> String {
|
pub fn to_str(&self, names: &HashMap<u64, String>) -> String {
|
||||||
match self {
|
match self {
|
||||||
TypeTerm::Type { id, args } => format!(
|
TypeTerm::Type { id, args } => format!(
|
||||||
"( {} {})",
|
"« {} {}»",
|
||||||
names[id],
|
names[id],
|
||||||
if args.len() > 0 {
|
if args.len() > 0 {
|
||||||
args.iter().fold(String::new(), |str, term| {
|
args.iter().fold(String::new(), |str, term| {
|
||||||
|
@ -141,6 +142,14 @@ impl TypeDict {
|
||||||
self.type_id_counter += 1;
|
self.type_id_counter += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_typeid(&self, tn: &String) -> Option<TypeID> {
|
||||||
|
if let Some(id) = self.typenames.mλ.get(tn) {
|
||||||
|
Some(*id)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn type_term_from_str(&self, typename: &str) -> Option<TypeTerm> {
|
pub fn type_term_from_str(&self, typename: &str) -> Option<TypeTerm> {
|
||||||
TypeTerm::from_str(typename, &self.typenames.mλ)
|
TypeTerm::from_str(typename, &self.typenames.mλ)
|
||||||
}
|
}
|
||||||
|
|
|
@ -198,11 +198,11 @@ where
|
||||||
let old_limit = self.limit;
|
let old_limit = self.limit;
|
||||||
self.limit = Point2::new(
|
self.limit = Point2::new(
|
||||||
(0..=top_range.end().x as usize)
|
(0..=top_range.end().x as usize)
|
||||||
.map(|x| col_widths[x])
|
.map(|x| col_widths.get(x).unwrap_or(&0))
|
||||||
.sum::<i16>()
|
.sum::<i16>()
|
||||||
- 1,
|
- 1,
|
||||||
(0..=top_range.end().y as usize)
|
(0..=top_range.end().y as usize)
|
||||||
.map(|y| row_heights[y])
|
.map(|y| row_heights.get(y).unwrap_or(&0))
|
||||||
.sum::<i16>()
|
.sum::<i16>()
|
||||||
- 1,
|
- 1,
|
||||||
);
|
);
|
||||||
|
|
|
@ -77,6 +77,8 @@ impl TerminalEditor for DigitEditor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TerminalTreeEditor for DigitEditor {}
|
||||||
|
|
||||||
pub struct PosIntEditor {
|
pub struct PosIntEditor {
|
||||||
radix: u32,
|
radix: u32,
|
||||||
digits_editor:
|
digits_editor:
|
||||||
|
@ -182,3 +184,6 @@ impl TerminalEditor for PosIntEditor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TerminalTreeEditor for PosIntEditor {}
|
||||||
|
|
||||||
|
|
|
@ -6,11 +6,13 @@ pub mod projection;
|
||||||
pub mod grid;
|
pub mod grid;
|
||||||
pub mod index;
|
pub mod index;
|
||||||
pub mod integer;
|
pub mod integer;
|
||||||
|
pub mod product;
|
||||||
pub mod list;
|
pub mod list;
|
||||||
pub mod sequence;
|
pub mod sequence;
|
||||||
pub mod singleton;
|
pub mod singleton;
|
||||||
pub mod terminal;
|
pub mod terminal;
|
||||||
pub mod vec;
|
pub mod vec;
|
||||||
|
pub mod make_editor;
|
||||||
|
|
||||||
pub mod tree_nav;
|
pub mod tree_nav;
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ use {
|
||||||
pub enum ListEditorStyle {
|
pub enum ListEditorStyle {
|
||||||
HorizontalSexpr,
|
HorizontalSexpr,
|
||||||
VerticalSexpr,
|
VerticalSexpr,
|
||||||
|
Tuple(usize),
|
||||||
Path,
|
Path,
|
||||||
String,
|
String,
|
||||||
Clist,
|
Clist,
|
||||||
|
@ -189,6 +190,7 @@ where
|
||||||
return TreeNavResult::Continue;
|
return TreeNavResult::Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.cursor.set(ListCursor::default());
|
||||||
TreeNavResult::Exit
|
TreeNavResult::Exit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -201,7 +203,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn goto_home(&mut self) -> TreeNavResult {
|
fn goto_home(&mut self) -> TreeNavResult {
|
||||||
let cur = self.cursor.get();
|
let mut cur = self.cursor.get();
|
||||||
if self.data.len() == 0 && cur.idx.is_none() {
|
if self.data.len() == 0 && cur.idx.is_none() {
|
||||||
self.cursor.set(ListCursor {
|
self.cursor.set(ListCursor {
|
||||||
mode: ListCursorMode::Insert,
|
mode: ListCursorMode::Insert,
|
||||||
|
@ -228,7 +230,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ListCursorMode::Modify => {
|
ListCursorMode::Modify => {
|
||||||
let ce = self.get_item().unwrap();
|
if let Some(ce) = self.get_item() {
|
||||||
let mut cur_edit = ce.write().unwrap();
|
let mut cur_edit = ce.write().unwrap();
|
||||||
let cur_mode = cur_edit.get_cursor().leaf_mode;
|
let cur_mode = cur_edit.get_cursor().leaf_mode;
|
||||||
let depth = cur_edit.get_cursor().tree_addr.len();
|
let depth = cur_edit.get_cursor().tree_addr.len();
|
||||||
|
@ -238,8 +240,6 @@ where
|
||||||
drop(cur_edit);
|
drop(cur_edit);
|
||||||
|
|
||||||
if let Some(i) = cur.idx {
|
if let Some(i) = cur.idx {
|
||||||
self.up();
|
|
||||||
|
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
self.set_mode(ListCursorMode::Select);
|
self.set_mode(ListCursorMode::Select);
|
||||||
self.pxev();
|
self.pxev();
|
||||||
|
@ -249,18 +249,20 @@ where
|
||||||
self.goto_end();
|
self.goto_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.set_leaf_mode(cur_mode);
|
|
||||||
self.dn();
|
self.dn();
|
||||||
self.goto_home();
|
self.set_leaf_mode(cur_mode);
|
||||||
|
//self.goto_home();
|
||||||
return TreeNavResult::Continue;
|
return TreeNavResult::Continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
TreeNavResult::Continue => { return TreeNavResult::Continue; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
self.cursor.set(ListCursor::default());
|
||||||
TreeNavResult::Exit
|
TreeNavResult::Exit
|
||||||
}
|
}
|
||||||
TreeNavResult::Continue => TreeNavResult::Continue,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,19 +281,25 @@ where
|
||||||
TreeNavResult::Continue => {}
|
TreeNavResult::Continue => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
return TreeNavResult::Continue;
|
TreeNavResult::Continue
|
||||||
|
} else {
|
||||||
|
TreeNavResult::Exit
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
|
||||||
self.cursor.set(ListCursor {
|
self.cursor.set(ListCursor {
|
||||||
mode: cur.mode,
|
mode: cur.mode,
|
||||||
idx: None,
|
idx: None,
|
||||||
});
|
});
|
||||||
TreeNavResult::Exit
|
TreeNavResult::Exit
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn dn(&mut self) -> TreeNavResult {
|
fn dn(&mut self) -> TreeNavResult {
|
||||||
let cur = self.cursor.get();
|
let mut cur = self.cursor.get();
|
||||||
|
|
||||||
|
if cur.idx.is_none() {
|
||||||
|
self.goto_home()
|
||||||
|
} else {
|
||||||
match cur.mode {
|
match cur.mode {
|
||||||
ListCursorMode::Insert | ListCursorMode::Select => {
|
ListCursorMode::Insert | ListCursorMode::Select => {
|
||||||
if let Some(i) = cur.idx {
|
if let Some(i) = cur.idx {
|
||||||
|
@ -301,6 +309,7 @@ where
|
||||||
leaf_mode: cur.mode,
|
leaf_mode: cur.mode,
|
||||||
tree_addr: vec![],
|
tree_addr: vec![],
|
||||||
});
|
});
|
||||||
|
self.data.get_mut(i).write().unwrap().dn();
|
||||||
*self.cur_dist.write().unwrap() += 1;
|
*self.cur_dist.write().unwrap() += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -309,6 +318,7 @@ where
|
||||||
ListCursorMode::Modify => self.get_item().unwrap().write().unwrap().dn(),
|
ListCursorMode::Modify => self.get_item().unwrap().write().unwrap().dn(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn pxev(&mut self) -> TreeNavResult {
|
fn pxev(&mut self) -> TreeNavResult {
|
||||||
let mut cur = self.cursor.get();
|
let mut cur = self.cursor.get();
|
||||||
|
@ -397,7 +407,7 @@ where
|
||||||
TreeNavResult::Exit => {
|
TreeNavResult::Exit => {
|
||||||
drop(cur_edit);
|
drop(cur_edit);
|
||||||
drop(ce);
|
drop(ce);
|
||||||
self.up();
|
//self.up();
|
||||||
|
|
||||||
if i + 1 < self.data.len() {
|
if i + 1 < self.data.len() {
|
||||||
self.set_mode(ListCursorMode::Select);
|
self.set_mode(ListCursorMode::Select);
|
||||||
|
@ -405,14 +415,14 @@ where
|
||||||
|
|
||||||
for _x in 1..depth {
|
for _x in 1..depth {
|
||||||
self.dn();
|
self.dn();
|
||||||
self.goto_home();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.set_leaf_mode(cur_mode);
|
self.set_leaf_mode(cur_mode);
|
||||||
self.dn();
|
self.dn();
|
||||||
self.goto_home();
|
|
||||||
TreeNavResult::Continue
|
TreeNavResult::Continue
|
||||||
} else {
|
} else {
|
||||||
|
self.cursor.set(ListCursor::default());
|
||||||
TreeNavResult::Exit
|
TreeNavResult::Exit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -435,6 +445,7 @@ where
|
||||||
match self.style {
|
match self.style {
|
||||||
ListEditorStyle::HorizontalSexpr => self.horizontal_sexpr_view(),
|
ListEditorStyle::HorizontalSexpr => self.horizontal_sexpr_view(),
|
||||||
ListEditorStyle::VerticalSexpr => self.vertical_sexpr_view(),
|
ListEditorStyle::VerticalSexpr => self.vertical_sexpr_view(),
|
||||||
|
ListEditorStyle::Tuple(depth) => self.tuple_view(depth),
|
||||||
ListEditorStyle::Path => self.path_view(),
|
ListEditorStyle::Path => self.path_view(),
|
||||||
ListEditorStyle::String => self.string_view(),
|
ListEditorStyle::String => self.string_view(),
|
||||||
ListEditorStyle::Clist => self.clist_view(),
|
ListEditorStyle::Clist => self.clist_view(),
|
||||||
|
@ -474,10 +485,10 @@ where
|
||||||
_ => {
|
_ => {
|
||||||
let new_edit = (self.make_item_editor)();
|
let new_edit = (self.make_item_editor)();
|
||||||
self.data.insert(idx, new_edit.clone());
|
self.data.insert(idx, new_edit.clone());
|
||||||
self.dn();
|
self.set_mode(ListCursorMode::Modify);
|
||||||
self.goto_home();
|
let mut ne = new_edit.write().unwrap();
|
||||||
|
|
||||||
match new_edit.write().unwrap().handle_terminal_event(event) {
|
match ne.handle_terminal_event(event) {
|
||||||
TerminalEditorResult::Exit => {
|
TerminalEditorResult::Exit => {
|
||||||
self.cursor.set(ListCursor {
|
self.cursor.set(ListCursor {
|
||||||
mode: ListCursorMode::Insert,
|
mode: ListCursorMode::Insert,
|
||||||
|
@ -552,6 +563,12 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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>
|
impl<ItemEditor, FnMakeItemEditor> ListEditor<ItemEditor, FnMakeItemEditor>
|
||||||
where
|
where
|
||||||
ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
|
@ -633,6 +650,13 @@ where
|
||||||
.flatten()
|
.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> {
|
pub fn hex_view(&self) -> OuterViewPort<dyn TerminalView> {
|
||||||
self.get_seg_seq_view()
|
self.get_seg_seq_view()
|
||||||
.decorate("0x", "", "", 0)
|
.decorate("0x", "", "", 0)
|
||||||
|
@ -738,3 +762,4 @@ where
|
||||||
self.goto(c);
|
self.goto(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -224,6 +224,7 @@ impl VerticalSexprDecorator {
|
||||||
list_style: TerminalStyle::fg_color(match level {
|
list_style: TerminalStyle::fg_color(match level {
|
||||||
0 => (200, 120, 10),
|
0 => (200, 120, 10),
|
||||||
1 => (120, 200, 10),
|
1 => (120, 200, 10),
|
||||||
|
2 => (200, 10, 120),
|
||||||
_ => (255, 255, 255),
|
_ => (255, 255, 255),
|
||||||
}),
|
}),
|
||||||
item_style: TerminalStyle::fg_color(match level {
|
item_style: TerminalStyle::fg_color(match level {
|
||||||
|
|
113
nested/src/make_editor.rs
Normal file
113
nested/src/make_editor.rs
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
|
||||||
|
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::editor::ProductEditor
|
||||||
|
},
|
||||||
|
cgmath::{Point2, Vector2},
|
||||||
|
std::{sync::{Arc, RwLock}, ops::{Deref, DerefMut}},
|
||||||
|
termion::event::{Event, Key},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn make_editor(ctx: Arc<RwLock<Context>>, t: &TypeLadder, depth: usize) -> Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>> {
|
||||||
|
let c = ctx.read().unwrap();
|
||||||
|
if t[0] == c.type_term_from_str("( PosInt 16 BigEndian )").unwrap() {
|
||||||
|
Arc::new(RwLock::new(PosIntEditor::new(16))) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
|
||||||
|
|
||||||
|
} else if t[0] == c.type_term_from_str("( PosInt 10 BigEndian )").unwrap() {
|
||||||
|
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>>
|
||||||
|
|
||||||
|
} 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>>
|
||||||
|
|
||||||
|
} 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>>
|
||||||
|
|
||||||
|
} 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
|
||||||
|
))) 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>>
|
||||||
|
|
||||||
|
} else if t[0] == c.type_term_from_str("( RGB )").unwrap() {
|
||||||
|
Arc::new(RwLock::new(ProductEditor::new(depth, ctx.clone())
|
||||||
|
.with_t("{ r: ")
|
||||||
|
.with_n( vec![ ctx.read().unwrap().type_term_from_str("( PosInt 16 BigEndian )").unwrap() ] )
|
||||||
|
.with_t(", g: ")
|
||||||
|
.with_n( vec![ ctx.read().unwrap().type_term_from_str("( PosInt 16 BigEndian )").unwrap() ] )
|
||||||
|
.with_t(", b: ")
|
||||||
|
.with_n( vec![ ctx.read().unwrap().type_term_from_str("( PosInt 16 BigEndian )").unwrap() ] )
|
||||||
|
.with_t(" }")
|
||||||
|
)) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
|
||||||
|
|
||||||
|
} else if t[0] == c.type_term_from_str("( Vec3i )").unwrap() {
|
||||||
|
Arc::new(RwLock::new(ProductEditor::new(depth, ctx.clone())
|
||||||
|
.with_t("{ x: ")
|
||||||
|
.with_n( vec![ ctx.read().unwrap().type_term_from_str("( PosInt 10 BigEndian )").unwrap() ] )
|
||||||
|
.with_t(", y: ")
|
||||||
|
.with_n( vec![ ctx.read().unwrap().type_term_from_str("( PosInt 10 BigEndian )").unwrap() ] )
|
||||||
|
.with_t(", z: ")
|
||||||
|
.with_n( vec![ ctx.read().unwrap().type_term_from_str("( PosInt 10 BigEndian )").unwrap() ] )
|
||||||
|
.with_t(" }")
|
||||||
|
)) 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>>
|
||||||
|
|
||||||
|
} else { // else: term
|
||||||
|
Arc::new(RwLock::new(
|
||||||
|
ProductEditor::new(depth, ctx.clone())
|
||||||
|
.with_n( vec![ c.type_term_from_str("( List Char )").unwrap() ] )
|
||||||
|
.with_n( vec![ c.type_term_from_str("( List Term )").unwrap() ] )
|
||||||
|
)) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
456
nested/src/product/editor.rs
Normal file
456
nested/src/product/editor.rs
Normal file
|
@ -0,0 +1,456 @@
|
||||||
|
|
||||||
|
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},
|
||||||
|
make_editor::make_editor
|
||||||
|
},
|
||||||
|
cgmath::{Point2, Vector2},
|
||||||
|
std::{sync::{Arc, RwLock}, ops::{Deref, DerefMut}},
|
||||||
|
termion::event::{Event, Key},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct ProductEditor {
|
||||||
|
elements: VecBuffer<ProductEditorElement>,
|
||||||
|
n_indices: Vec<usize>,
|
||||||
|
|
||||||
|
el_port: OuterViewPort<dyn SequenceView<Item = ProductEditorElement>>,
|
||||||
|
el_view_port: OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>,
|
||||||
|
|
||||||
|
ctx: Arc<RwLock<Context>>,
|
||||||
|
|
||||||
|
cursor: Option<usize>,
|
||||||
|
depth: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProductEditor {
|
||||||
|
pub fn new(depth: usize, ctx: Arc<RwLock<Context>>) -> Self {
|
||||||
|
let mut port = ViewPort::new();
|
||||||
|
|
||||||
|
let el_port = port.outer().to_sequence();
|
||||||
|
let el_view_port = el_port.map({
|
||||||
|
let ctx = ctx.clone();
|
||||||
|
move |e: &ProductEditorElement| { e.get_view(ctx.clone()) }
|
||||||
|
});
|
||||||
|
|
||||||
|
ProductEditor {
|
||||||
|
elements: VecBuffer::new(port.inner()),
|
||||||
|
el_port,
|
||||||
|
el_view_port,
|
||||||
|
n_indices: Vec::new(),
|
||||||
|
|
||||||
|
ctx,
|
||||||
|
|
||||||
|
cursor: None,
|
||||||
|
depth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_t(mut self, t: &str) -> Self {
|
||||||
|
self.elements.push(ProductEditorElement::T(t.to_string()));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_n(mut self, n: TypeLadder) -> Self {
|
||||||
|
let elem_idx = self.elements.len();
|
||||||
|
self.elements.push(ProductEditorElement::N{
|
||||||
|
t: n,
|
||||||
|
editor: None,
|
||||||
|
select: false
|
||||||
|
});
|
||||||
|
self.n_indices.push(elem_idx);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_editor_element(&self, idx: usize) -> Option<ProductEditorElement> {
|
||||||
|
if let Some(i) = self.n_indices.get(idx) {
|
||||||
|
Some(self.elements.get(*i))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_editor_element_mut(&mut self, idx: usize) -> Option<MutableVecAccess<ProductEditorElement>> {
|
||||||
|
if let Some(i) = self.n_indices.get(idx) {
|
||||||
|
Some(self.elements.get_mut(*i))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_cur_element(&self) -> Option<ProductEditorElement> {
|
||||||
|
self.get_editor_element(self.cursor?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_cur_element_mut(&mut self) -> Option<MutableVecAccess<ProductEditorElement>> {
|
||||||
|
self.get_editor_element_mut(self.cursor?)
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
editor
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_cur_editor(&self) -> Option<Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>> {
|
||||||
|
self.get_editor(self.cursor?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_leaf_mode(&mut self, mode: ListCursorMode) {
|
||||||
|
let mut c = self.get_cursor();
|
||||||
|
c.leaf_mode = mode;
|
||||||
|
self.goto(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TreeNav for ProductEditor {
|
||||||
|
fn get_cursor(&self) -> TreeCursor {
|
||||||
|
if let Some(i) = self.cursor {
|
||||||
|
if let Some(e) = self.get_editor(i) {
|
||||||
|
let mut c = e.read().unwrap().get_cursor();
|
||||||
|
if c.tree_addr.len() == 0 {
|
||||||
|
c.leaf_mode = ListCursorMode::Select;
|
||||||
|
}
|
||||||
|
c.tree_addr.insert(0, i);
|
||||||
|
c
|
||||||
|
} else {
|
||||||
|
TreeCursor {
|
||||||
|
leaf_mode: ListCursorMode::Select,
|
||||||
|
tree_addr: vec![ i ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TreeCursor::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 Some(e) = editor {
|
||||||
|
e.write().unwrap().goto(TreeCursor::default());
|
||||||
|
}
|
||||||
|
*select = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.tree_addr.len() > 0 {
|
||||||
|
self.cursor = Some(c.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 Some(e) = editor {
|
||||||
|
e.write().unwrap().goto(c);
|
||||||
|
}
|
||||||
|
*select = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeNavResult::Continue
|
||||||
|
} else {
|
||||||
|
self.cursor = None;
|
||||||
|
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(e) = editor {
|
||||||
|
let mut ce = e.write().unwrap();
|
||||||
|
|
||||||
|
let cur_mode = ce.get_cursor().leaf_mode;
|
||||||
|
let depth = ce.get_cursor().tree_addr.len();
|
||||||
|
|
||||||
|
if depth > 0 {
|
||||||
|
return match ce.goto_home() {
|
||||||
|
TreeNavResult::Exit => {
|
||||||
|
drop(ce);
|
||||||
|
*select = false;
|
||||||
|
|
||||||
|
match self.pxev() {
|
||||||
|
TreeNavResult::Exit => TreeNavResult::Exit,
|
||||||
|
TreeNavResult::Continue => {
|
||||||
|
for _x in 1..depth {
|
||||||
|
self.dn();
|
||||||
|
self.goto_end();
|
||||||
|
}
|
||||||
|
self.dn();
|
||||||
|
self.set_leaf_mode(cur_mode);
|
||||||
|
|
||||||
|
TreeNavResult::Continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TreeNavResult::Continue => TreeNavResult::Continue
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*select = false;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
return TreeNavResult::Continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.cursor = None;
|
||||||
|
TreeNavResult::Exit
|
||||||
|
}
|
||||||
|
|
||||||
|
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(e) = editor {
|
||||||
|
let mut ce = e.write().unwrap();
|
||||||
|
|
||||||
|
let cur_mode = ce.get_cursor().leaf_mode;
|
||||||
|
let depth = ce.get_cursor().tree_addr.len();
|
||||||
|
|
||||||
|
if depth > 0 {
|
||||||
|
return match ce.goto_end() {
|
||||||
|
TreeNavResult::Exit => {
|
||||||
|
drop(ce);
|
||||||
|
*select = false;
|
||||||
|
|
||||||
|
match self.nexd() {
|
||||||
|
TreeNavResult::Exit => TreeNavResult::Exit,
|
||||||
|
TreeNavResult::Continue => {
|
||||||
|
for _x in 1..depth {
|
||||||
|
self.dn();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.dn();
|
||||||
|
self.set_leaf_mode(cur_mode);
|
||||||
|
self.goto_end();
|
||||||
|
|
||||||
|
TreeNavResult::Continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TreeNavResult::Continue => TreeNavResult::Continue
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*select = false;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
return TreeNavResult::Continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.cursor = None;
|
||||||
|
TreeNavResult::Exit
|
||||||
|
}
|
||||||
|
|
||||||
|
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(e) = editor {
|
||||||
|
let mut ce = e.write().unwrap();
|
||||||
|
|
||||||
|
let depth = ce.get_cursor().tree_addr.len();
|
||||||
|
let cur_mode = ce.get_cursor().leaf_mode;
|
||||||
|
|
||||||
|
if depth > 0 {
|
||||||
|
return match ce.pxev() {
|
||||||
|
TreeNavResult::Exit => {
|
||||||
|
drop(ce);
|
||||||
|
*select = false;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
for _x in 1..depth {
|
||||||
|
self.dn();
|
||||||
|
self.goto_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.dn();
|
||||||
|
self.set_leaf_mode(cur_mode);
|
||||||
|
self.goto_end();
|
||||||
|
|
||||||
|
TreeNavResult::Continue
|
||||||
|
} else {
|
||||||
|
TreeNavResult::Exit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TreeNavResult::Continue => TreeNavResult::Continue
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*select = false;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
return TreeNavResult::Continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.cursor = None;
|
||||||
|
TreeNavResult::Exit
|
||||||
|
}
|
||||||
|
|
||||||
|
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(e) = editor {
|
||||||
|
let mut ce = e.write().unwrap();
|
||||||
|
|
||||||
|
let depth = ce.get_cursor().tree_addr.len();
|
||||||
|
let cur_mode = ce.get_cursor().leaf_mode;
|
||||||
|
|
||||||
|
if depth > 0 {
|
||||||
|
return match ce.nexd() {
|
||||||
|
TreeNavResult::Exit => {
|
||||||
|
drop(ce);
|
||||||
|
*select = false;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
for _x in 1..depth {
|
||||||
|
self.dn();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.dn();
|
||||||
|
self.set_leaf_mode(cur_mode);
|
||||||
|
|
||||||
|
TreeNavResult::Continue
|
||||||
|
} else {
|
||||||
|
self.cursor = None;
|
||||||
|
TreeNavResult::Exit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TreeNavResult::Continue => TreeNavResult::Continue
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*select = false;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TreeNavResult::Continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.cursor = None;
|
||||||
|
TreeNavResult::Exit
|
||||||
|
}
|
||||||
|
|
||||||
|
fn up(&mut self) -> TreeNavResult {
|
||||||
|
if let Some(ProductEditorElement::N{ t, editor, select }) = self.get_cur_element_mut().as_deref_mut() {
|
||||||
|
if let Some(e) = editor {
|
||||||
|
let mut ce = e.write().unwrap();
|
||||||
|
if ce.get_cursor().tree_addr.len() > 0 {
|
||||||
|
ce.up();
|
||||||
|
return TreeNavResult::Continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*select = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.cursor = None;
|
||||||
|
TreeNavResult::Exit
|
||||||
|
}
|
||||||
|
|
||||||
|
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(e) = editor {
|
||||||
|
e.write().unwrap().dn();
|
||||||
|
} else {
|
||||||
|
let e = make_editor(self.ctx.clone(), t, self.depth+1);
|
||||||
|
e.write().unwrap().goto_home();
|
||||||
|
*editor = Some(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.cursor = Some(0);
|
||||||
|
if let Some(ProductEditorElement::N{ t, editor, select }) = self.get_cur_element_mut().as_deref_mut() {
|
||||||
|
*select = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeNavResult::Continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TerminalEditor for ProductEditor {
|
||||||
|
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
|
||||||
|
self.el_view_port.to_grid_horizontal().flatten()
|
||||||
|
}
|
||||||
|
|
||||||
|
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(e) = editor.clone() {
|
||||||
|
match e.clone().write().unwrap().handle_terminal_event(event) {
|
||||||
|
TerminalEditorResult::Exit =>
|
||||||
|
match event {
|
||||||
|
TerminalEvent::Input(Event::Key(Key::Backspace)) => {
|
||||||
|
*editor = None;
|
||||||
|
TerminalEditorResult::Continue
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
drop(e);
|
||||||
|
match self.nexd() {
|
||||||
|
TreeNavResult::Continue => TerminalEditorResult::Continue,
|
||||||
|
TreeNavResult::Exit => TerminalEditorResult::Exit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TerminalEditorResult::Continue =>
|
||||||
|
TerminalEditorResult::Continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let e = make_editor(self.ctx.clone(), t, self.depth+1);
|
||||||
|
*editor = Some(e.clone());
|
||||||
|
e.write().unwrap().dn();
|
||||||
|
let x = e.write().unwrap().handle_terminal_event(event);
|
||||||
|
x
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TerminalEditorResult::Exit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TerminalTreeEditor for ProductEditor {}
|
||||||
|
|
74
nested/src/product/element.rs
Normal file
74
nested/src/product/element.rs
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
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}
|
||||||
|
},
|
||||||
|
cgmath::{Point2, Vector2},
|
||||||
|
std::{sync::{Arc, RwLock}, ops::{Deref, DerefMut}},
|
||||||
|
termion::event::{Event, Key},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum ProductEditorElement {
|
||||||
|
T( String ),
|
||||||
|
N {
|
||||||
|
t: TypeLadder,
|
||||||
|
editor: Option<Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>>,
|
||||||
|
select: bool
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProductEditorElement {
|
||||||
|
pub fn get_view(&self, ctx: Arc<RwLock<Context>>) -> OuterViewPort<dyn TerminalView> {
|
||||||
|
match self {
|
||||||
|
ProductEditorElement::T(t) =>
|
||||||
|
make_label(t.as_str())
|
||||||
|
.map_item(
|
||||||
|
|i, x|
|
||||||
|
x.add_style_back(TerminalStyle::fg_color((0,120,200)))
|
||||||
|
),
|
||||||
|
|
||||||
|
ProductEditorElement::N {t: _, editor: Some(e), select} =>
|
||||||
|
e.read().unwrap()
|
||||||
|
.get_term_view()
|
||||||
|
.map_item({ let select = *select;
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
|
||||||
|
ProductEditorElement::N{t, editor: None, select} =>
|
||||||
|
make_label(&ctx.read().unwrap().type_term_to_str(&t[0]))
|
||||||
|
.map_item({ let select = *select;
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
4
nested/src/product/mod.rs
Normal file
4
nested/src/product/mod.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
pub mod editor;
|
||||||
|
pub mod element;
|
||||||
|
|
|
@ -82,10 +82,10 @@ where
|
||||||
{
|
{
|
||||||
fn reset(&mut self, view: Option<Arc<SrcView>>) {
|
fn reset(&mut self, view: Option<Arc<SrcView>>) {
|
||||||
self.src_view = view;
|
self.src_view = view;
|
||||||
self.cast.notify(&IndexArea::Full);
|
self.cast.notify(&IndexArea::Set(vec![ () ]));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn notify(&mut self, _: &()) {
|
fn notify(&mut self, _: &()) {
|
||||||
self.cast.notify(&IndexArea::Full);
|
self.cast.notify(&IndexArea::Set(vec![ () ]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,12 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
core::{OuterViewPort, ViewPort},
|
core::{OuterViewPort, ViewPort},
|
||||||
list::{sexpr::ListDecoration, ListEditor},
|
list::{sexpr::ListDecoration, ListEditor},
|
||||||
sequence::SequenceView,
|
sequence::{SequenceView, SequenceViewExt},
|
||||||
singleton::{SingletonBuffer, SingletonView},
|
singleton::{SingletonBuffer, SingletonView},
|
||||||
terminal::{
|
terminal::{
|
||||||
TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle, TerminalView,
|
TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle, TerminalView,
|
||||||
},
|
},
|
||||||
tree_nav::{TreeCursor, TreeNav, TreeNavResult},
|
tree_nav::{TreeCursor, TreeNav, TreeNavResult, TerminalTreeEditor},
|
||||||
},
|
},
|
||||||
std::sync::Arc,
|
std::sync::Arc,
|
||||||
std::sync::RwLock,
|
std::sync::RwLock,
|
||||||
|
@ -62,6 +62,8 @@ impl TerminalEditor for CharEditor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TerminalTreeEditor for CharEditor {}
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub struct StringEditor {
|
pub struct StringEditor {
|
||||||
|
@ -82,7 +84,18 @@ impl StringEditor {
|
||||||
pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = char>> {
|
pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = char>> {
|
||||||
self.chars_editor
|
self.chars_editor
|
||||||
.get_data_port()
|
.get_data_port()
|
||||||
.map(|char_editor| char_editor.read().unwrap().data.get().unwrap())
|
.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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +122,7 @@ impl TreeNav for StringEditor {
|
||||||
self.chars_editor.up()
|
self.chars_editor.up()
|
||||||
}
|
}
|
||||||
fn dn(&mut self) -> TreeNavResult {
|
fn dn(&mut self) -> TreeNavResult {
|
||||||
TreeNavResult::Exit
|
self.chars_editor.dn()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,3 +146,6 @@ impl TerminalEditor for StringEditor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TerminalTreeEditor for StringEditor {}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ pub enum TreeNavResult {
|
||||||
Continue,
|
Continue,
|
||||||
Exit,
|
Exit,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
impl From<TreeNavResult> for TerminalEditorResult {
|
impl From<TreeNavResult> for TerminalEditorResult {
|
||||||
fn from(v: TreeNavResult) -> TerminalEditorResult {
|
fn from(v: TreeNavResult) -> TerminalEditorResult {
|
||||||
|
@ -15,12 +16,22 @@ impl From<TreeNavResult> for TerminalEditorResult {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
pub struct TreeCursor {
|
pub struct TreeCursor {
|
||||||
pub leaf_mode: ListCursorMode,
|
pub leaf_mode: ListCursorMode,
|
||||||
pub tree_addr: Vec<usize>,
|
pub tree_addr: Vec<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TreeCursor {
|
||||||
|
pub fn home() -> Self {
|
||||||
|
TreeCursor {
|
||||||
|
leaf_mode: ListCursorMode::Select,
|
||||||
|
tree_addr: vec![0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for TreeCursor {
|
impl Default for TreeCursor {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
TreeCursor {
|
TreeCursor {
|
||||||
|
@ -66,4 +77,5 @@ pub trait TreeNav {
|
||||||
|
|
||||||
use crate::terminal::{TerminalEditor};
|
use crate::terminal::{TerminalEditor};
|
||||||
|
|
||||||
pub trait TerminalTreeEditor = TerminalEditor + TreeNav;
|
pub trait TerminalTreeEditor : TerminalEditor + TreeNav + Send {}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ pub mod vec2bin;
|
||||||
pub mod vec2json;
|
pub mod vec2json;
|
||||||
pub mod vec2seq;
|
pub mod vec2seq;
|
||||||
|
|
||||||
pub use buffer::VecBuffer;
|
pub use buffer::{VecBuffer, MutableVecAccess};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue