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 {
|
||||
crate::core::{
|
||||
type_term::{TypeDict, TypeTerm},
|
||||
crate::{
|
||||
core::{
|
||||
type_term::{TypeDict, TypeTerm, TypeID},
|
||||
AnyOuterViewPort, OuterViewPort, View,
|
||||
},
|
||||
tree_nav::{
|
||||
TerminalTreeEditor
|
||||
}
|
||||
},
|
||||
std::{
|
||||
collections::HashMap,
|
||||
sync::{Arc, RwLock},
|
||||
|
@ -232,10 +237,20 @@ pub struct MorphismType {
|
|||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||
|
||||
pub struct Context {
|
||||
/// assigns a name to every type
|
||||
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>>,
|
||||
morphism_constructors: HashMap<MorphismType, Box<dyn Fn(Object) -> Object + Send + Sync>>,
|
||||
objects: HashMap<String, Object>,
|
||||
|
||||
/// recursion
|
||||
parent: Option<Arc<RwLock<Context>>>,
|
||||
}
|
||||
|
||||
|
@ -243,6 +258,7 @@ impl Context {
|
|||
pub fn with_parent(parent: Option<Arc<RwLock<Context>>>) -> Self {
|
||||
Context {
|
||||
type_dict: TypeDict::new(),
|
||||
editor_ctors: HashMap::new(),
|
||||
default_constructors: HashMap::new(),
|
||||
morphism_constructors: HashMap::new(),
|
||||
objects: HashMap::new(),
|
||||
|
@ -261,6 +277,26 @@ impl Context {
|
|||
pub fn type_term_from_str(&self, tn: &str) -> Option<TypeTerm> {
|
||||
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(
|
||||
&mut self,
|
||||
|
|
|
@ -12,6 +12,6 @@ pub use {
|
|||
port::{
|
||||
AnyInnerViewPort, AnyOuterViewPort, AnyViewPort, InnerViewPort, OuterViewPort, ViewPort,
|
||||
},
|
||||
type_term::{TypeDict, TypeID, TypeTerm},
|
||||
type_term::{TypeDict, TypeID, TypeTerm, TypeLadder},
|
||||
view::View,
|
||||
};
|
||||
|
|
|
@ -3,6 +3,7 @@ use {crate::bimap::Bimap, std::collections::HashMap};
|
|||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||
|
||||
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 {
|
||||
match self {
|
||||
TypeTerm::Type { id, args } => format!(
|
||||
"( {} {})",
|
||||
"« {} {}»",
|
||||
names[id],
|
||||
if args.len() > 0 {
|
||||
args.iter().fold(String::new(), |str, term| {
|
||||
|
@ -141,6 +142,14 @@ impl TypeDict {
|
|||
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> {
|
||||
TypeTerm::from_str(typename, &self.typenames.mλ)
|
||||
}
|
||||
|
|
|
@ -198,11 +198,11 @@ where
|
|||
let old_limit = self.limit;
|
||||
self.limit = Point2::new(
|
||||
(0..=top_range.end().x as usize)
|
||||
.map(|x| col_widths[x])
|
||||
.map(|x| col_widths.get(x).unwrap_or(&0))
|
||||
.sum::<i16>()
|
||||
- 1,
|
||||
(0..=top_range.end().y as usize)
|
||||
.map(|y| row_heights[y])
|
||||
.map(|y| row_heights.get(y).unwrap_or(&0))
|
||||
.sum::<i16>()
|
||||
- 1,
|
||||
);
|
||||
|
|
|
@ -77,6 +77,8 @@ impl TerminalEditor for DigitEditor {
|
|||
}
|
||||
}
|
||||
|
||||
impl TerminalTreeEditor for DigitEditor {}
|
||||
|
||||
pub struct PosIntEditor {
|
||||
radix: u32,
|
||||
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 index;
|
||||
pub mod integer;
|
||||
pub mod product;
|
||||
pub mod list;
|
||||
pub mod sequence;
|
||||
pub mod singleton;
|
||||
pub mod terminal;
|
||||
pub mod vec;
|
||||
pub mod make_editor;
|
||||
|
||||
pub mod tree_nav;
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ use {
|
|||
pub enum ListEditorStyle {
|
||||
HorizontalSexpr,
|
||||
VerticalSexpr,
|
||||
Tuple(usize),
|
||||
Path,
|
||||
String,
|
||||
Clist,
|
||||
|
@ -189,6 +190,7 @@ where
|
|||
return TreeNavResult::Continue;
|
||||
}
|
||||
|
||||
self.cursor.set(ListCursor::default());
|
||||
TreeNavResult::Exit
|
||||
}
|
||||
}
|
||||
|
@ -201,7 +203,7 @@ where
|
|||
}
|
||||
|
||||
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() {
|
||||
self.cursor.set(ListCursor {
|
||||
mode: ListCursorMode::Insert,
|
||||
|
@ -228,7 +230,7 @@ where
|
|||
}
|
||||
}
|
||||
ListCursorMode::Modify => {
|
||||
let ce = self.get_item().unwrap();
|
||||
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();
|
||||
|
@ -238,8 +240,6 @@ where
|
|||
drop(cur_edit);
|
||||
|
||||
if let Some(i) = cur.idx {
|
||||
self.up();
|
||||
|
||||
if i > 0 {
|
||||
self.set_mode(ListCursorMode::Select);
|
||||
self.pxev();
|
||||
|
@ -249,18 +249,20 @@ where
|
|||
self.goto_end();
|
||||
}
|
||||
|
||||
self.set_leaf_mode(cur_mode);
|
||||
self.dn();
|
||||
self.goto_home();
|
||||
self.set_leaf_mode(cur_mode);
|
||||
//self.goto_home();
|
||||
return TreeNavResult::Continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
TreeNavResult::Continue => { return TreeNavResult::Continue; }
|
||||
};
|
||||
}
|
||||
|
||||
self.cursor.set(ListCursor::default());
|
||||
TreeNavResult::Exit
|
||||
}
|
||||
TreeNavResult::Continue => TreeNavResult::Continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -279,19 +281,25 @@ where
|
|||
TreeNavResult::Continue => {}
|
||||
}
|
||||
|
||||
return 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 cur = self.cursor.get();
|
||||
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 {
|
||||
|
@ -301,6 +309,7 @@ where
|
|||
leaf_mode: cur.mode,
|
||||
tree_addr: vec![],
|
||||
});
|
||||
self.data.get_mut(i).write().unwrap().dn();
|
||||
*self.cur_dist.write().unwrap() += 1;
|
||||
}
|
||||
}
|
||||
|
@ -309,6 +318,7 @@ where
|
|||
ListCursorMode::Modify => self.get_item().unwrap().write().unwrap().dn(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn pxev(&mut self) -> TreeNavResult {
|
||||
let mut cur = self.cursor.get();
|
||||
|
@ -397,7 +407,7 @@ where
|
|||
TreeNavResult::Exit => {
|
||||
drop(cur_edit);
|
||||
drop(ce);
|
||||
self.up();
|
||||
//self.up();
|
||||
|
||||
if i + 1 < self.data.len() {
|
||||
self.set_mode(ListCursorMode::Select);
|
||||
|
@ -405,14 +415,14 @@ where
|
|||
|
||||
for _x in 1..depth {
|
||||
self.dn();
|
||||
self.goto_home();
|
||||
}
|
||||
|
||||
self.set_leaf_mode(cur_mode);
|
||||
self.dn();
|
||||
self.goto_home();
|
||||
|
||||
TreeNavResult::Continue
|
||||
} else {
|
||||
self.cursor.set(ListCursor::default());
|
||||
TreeNavResult::Exit
|
||||
}
|
||||
}
|
||||
|
@ -435,6 +445,7 @@ where
|
|||
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(),
|
||||
|
@ -474,10 +485,10 @@ where
|
|||
_ => {
|
||||
let new_edit = (self.make_item_editor)();
|
||||
self.data.insert(idx, new_edit.clone());
|
||||
self.dn();
|
||||
self.goto_home();
|
||||
self.set_mode(ListCursorMode::Modify);
|
||||
let mut ne = new_edit.write().unwrap();
|
||||
|
||||
match new_edit.write().unwrap().handle_terminal_event(event) {
|
||||
match ne.handle_terminal_event(event) {
|
||||
TerminalEditorResult::Exit => {
|
||||
self.cursor.set(ListCursor {
|
||||
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>
|
||||
where
|
||||
ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||
|
@ -633,6 +650,13 @@ where
|
|||
.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)
|
||||
|
@ -738,3 +762,4 @@ where
|
|||
self.goto(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -224,6 +224,7 @@ impl VerticalSexprDecorator {
|
|||
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 {
|
||||
|
|
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>>) {
|
||||
self.src_view = view;
|
||||
self.cast.notify(&IndexArea::Full);
|
||||
self.cast.notify(&IndexArea::Set(vec![ () ]));
|
||||
}
|
||||
|
||||
fn notify(&mut self, _: &()) {
|
||||
self.cast.notify(&IndexArea::Full);
|
||||
self.cast.notify(&IndexArea::Set(vec![ () ]));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,12 @@ use {
|
|||
crate::{
|
||||
core::{OuterViewPort, ViewPort},
|
||||
list::{sexpr::ListDecoration, ListEditor},
|
||||
sequence::SequenceView,
|
||||
sequence::{SequenceView, SequenceViewExt},
|
||||
singleton::{SingletonBuffer, SingletonView},
|
||||
terminal::{
|
||||
TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle, TerminalView,
|
||||
},
|
||||
tree_nav::{TreeCursor, TreeNav, TreeNavResult},
|
||||
tree_nav::{TreeCursor, TreeNav, TreeNavResult, TerminalTreeEditor},
|
||||
},
|
||||
std::sync::Arc,
|
||||
std::sync::RwLock,
|
||||
|
@ -62,6 +62,8 @@ impl TerminalEditor for CharEditor {
|
|||
}
|
||||
}
|
||||
|
||||
impl TerminalTreeEditor for CharEditor {}
|
||||
|
||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||
|
||||
pub struct StringEditor {
|
||||
|
@ -82,7 +84,18 @@ impl StringEditor {
|
|||
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())
|
||||
.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()
|
||||
}
|
||||
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,
|
||||
Exit,
|
||||
}
|
||||
|
||||
/*
|
||||
impl From<TreeNavResult> for TerminalEditorResult {
|
||||
fn from(v: TreeNavResult) -> TerminalEditorResult {
|
||||
|
@ -15,12 +16,22 @@ impl From<TreeNavResult> for TerminalEditorResult {
|
|||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
pub struct TreeCursor {
|
||||
pub leaf_mode: ListCursorMode,
|
||||
pub tree_addr: Vec<usize>,
|
||||
}
|
||||
|
||||
impl TreeCursor {
|
||||
pub fn home() -> Self {
|
||||
TreeCursor {
|
||||
leaf_mode: ListCursorMode::Select,
|
||||
tree_addr: vec![0]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TreeCursor {
|
||||
fn default() -> Self {
|
||||
TreeCursor {
|
||||
|
@ -66,4 +77,5 @@ pub trait TreeNav {
|
|||
|
||||
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 vec2seq;
|
||||
|
||||
pub use buffer::VecBuffer;
|
||||
pub use buffer::{VecBuffer, MutableVecAccess};
|
||||
|
||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||
|
||||
|
|
Loading…
Reference in a new issue