use { r3vi::{ view::{ OuterViewPort, singleton::*, }, buffer::{ singleton::*, vec::*, index_hashmap::* } }, laddertypes::{TypeTerm}, crate::{ editors::{list::{ListCmd}, ObjCommander}, repr_tree::{Context, ReprTree}, edit_tree::{EditTree, TreeNav, TreeNavResult, TreeCursor, diagnostics::{Message}}, }, std::sync::Arc, std::sync::RwLock, std::iter::FromIterator, cgmath::{Point2} }; pub fn init_ctx( ctx: Arc> ) { // todo: proper scoping of Radix variable ctx.write().unwrap().add_varname("Radix"); let morphtype = crate::repr_tree::MorphismType { src_type: Context::parse(&ctx, ""), dst_type: Context::parse(&ctx, "~EditTree") }; ctx.write().unwrap() .morphisms .add_morphism( morphtype, { let ctx = ctx.clone(); move |rt, σ| { let radix = match σ.get( &laddertypes::TypeID::Var(ctx.read().unwrap().get_var_typeid("Radix").unwrap()) ) { Some(TypeTerm::Num(n)) => *n as u32, _ => 0 }; /* Create EditTree object */ let mut edittree_digit = DigitEditor::new( ctx.clone(), radix ).into_node( r3vi::buffer::singleton::SingletonBuffer::::new(0).get_port() ); /* Insert EditTree into ReprTree */ let mut rt = rt.write().unwrap(); rt.insert_leaf( vec![ Context::parse(&ctx, "EditTree") ].into_iter(), SingletonBuffer::new( Arc::new(RwLock::new(edittree_digit)) ).get_port().into() ); } } ); } //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> pub struct DigitEditor { ctx: Arc>, radix: u32, data: SingletonBuffer>, msg: VecBuffer, } impl ObjCommander for DigitEditor { fn send_cmd_obj(&mut self, cmd_obj: Arc>) -> TreeNavResult { let cmd_obj = cmd_obj.read().unwrap(); let cmd_type = cmd_obj.get_type().clone(); if cmd_type == Context::parse(&self.ctx, "Char") { if let Some(cmd_view) = cmd_obj.get_view::>() { let c = cmd_view.get(); self.msg.clear(); if self.ctx.read().unwrap().meta_chars.contains(&c) { return TreeNavResult::Exit; } else if c.to_digit(self.radix).is_none() { /* in case the character c is not in the range of digit-chars, add a message to the diagnostics view */ /* let message = IndexBuffer::from_iter(vec![ (Point2::new(1, 0), make_label("invalid digit '")), (Point2::new(2, 0), make_label(&format!("{}", c)) .map_item(|_p,a| a.add_style_back(TerminalStyle::fg_color((140,140,250))))), (Point2::new(3, 0), make_label("'")) ]); self.msg.push(crate::diagnostics::make_error(message.get_port().flatten())); */ self.data.set(Some(c)); } else { self.data.set(Some(c)); } } } TreeNavResult::Continue } } impl DigitEditor { pub fn new(ctx: Arc>, radix: u32) -> Self { DigitEditor { ctx, radix, data: SingletonBuffer::new(None), msg: VecBuffer::new(), } } pub fn into_node(self, depth: OuterViewPort>) -> EditTree { let data = self.get_data(); let editor = Arc::new(RwLock::new(self)); let ed = editor.write().unwrap(); let r = ed.radix; EditTree::new(ed.ctx.clone(), depth) .set_editor(editor.clone()) .set_cmd(editor.clone()) .set_diag( ed.msg.get_port().to_sequence() ) } pub fn attach_to(&mut self, source: OuterViewPort>) { /* source.add_observer( Arc::new(NotifyFnObserver::new(|_msg| { self.data.set( source.get() ) })) ); */ } pub fn get_data_port(&self) -> OuterViewPort>> { let radix = self.radix; self.data.get_port().map(move |c| if let Some(d) = c.unwrap_or('?').to_digit(radix) { Ok(d) } else { Err(c.unwrap_or('?')) } ) } pub fn get_type(&self) -> TypeTerm { TypeTerm::TypeID(self.ctx.read().unwrap().get_typeid("Digit").unwrap()) } pub fn get_data(&self) -> Arc> { ReprTree::ascend( &ReprTree::new_leaf( self.ctx.read().unwrap().type_term_from_str("").unwrap(), self.get_data_port().into() ), self.get_type() ) } } pub struct PosIntEditor { radix: u32, digits: EditTree, // todo: endianness } impl PosIntEditor { pub fn new(ctx: Arc>, radix: u32) -> Self { PosIntEditor { radix, digits: EditTree::new( ctx, r3vi::buffer::singleton::SingletonBuffer::new(0).get_port() ) } } pub fn from_u64(ctx: Arc>, radix: u32, value: u64) -> Self { let mut edit = PosIntEditor::new(ctx, radix); edit.set_value_u64( value ); edit } pub fn set_value_u64(&mut self, mut value: u64) { self.digits.send_cmd_obj(ListCmd::Clear.into_repr_tree(&self.digits.ctx)); while value > 0 { let digit_val = (value % self.radix as u64) as u32; value /= self.radix as u64; // if BigEndian self.digits.goto(TreeCursor::home()); self.digits.send_cmd_obj(ReprTree::from_char(&self.digits.ctx, char::from_digit(digit_val, self.radix).expect("invalid digit"))); } self.digits.goto(TreeCursor::none()); } pub fn into_node(self) -> EditTree { self.digits } /* pub fn get_data_port(&self) -> OuterViewPort> { let radix = self.radix; self.digits .get_data_port() .filter_map(move |digit_editor| { digit_editor.read().unwrap().data.get()?.to_digit(radix) }) } pub fn get_value(&self) -> u32 { let mut value = 0; let mut weight = 1; for digit_value in self .get_data_port() .get_view() .unwrap() .iter() .collect::>() .into_iter() .rev() { value += digit_value * weight; weight *= self.radix; } value } */ }