factor out r3vi and shell crates

This commit is contained in:
Michael Sippel 2023-02-13 18:39:45 +01:00
parent d43d99c6d3
commit 6f942c8940
Signed by: senvas
GPG Key ID: F96CF119C34B64A6
83 changed files with 1294 additions and 6389 deletions

View File

@ -1,12 +1,10 @@
[workspace]
members = [
"nested",
"terminal/display_server",
"terminal/ansi_parser",
"shell",
"sdf_editor",
"math/str2int",
"math/int2str",
"math/radix_transform",
"math/fib"
# "terminal/display_server",
# "terminal/ansi_parser",
# "math/str2int",
# "math/int2str",
# "math/radix_transform",
# "math/fib"
]

View File

@ -5,6 +5,7 @@ name = "nested"
version = "0.1.0"
[dependencies]
r3vi = { git = "https://git.exobiont.de/senvas/r3vi.git" }
no_deadlocks = "*"
cgmath = { version = "0.18.0", features = ["serde"] }
termion = "1.5.5"

View File

@ -7,9 +7,9 @@ pub trait Commander {
use std::sync::{Arc, RwLock};
use crate::{
type_system::ReprTree,
singleton::SingletonView
type_system::ReprTree
};
use r3vi::view::singleton::*;
pub trait ObjCommander {
fn send_cmd_obj(&mut self, cmd_obj: Arc<RwLock<ReprTree>>);

View File

@ -1,223 +0,0 @@
use {
crate::core::Observer,
async_std::stream::Stream,
core::{
pin::Pin,
task::{Context, Poll, Waker},
},
std::{
collections::HashSet,
hash::Hash,
sync::{Arc, Mutex},
},
};
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
Traits
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
pub trait ChannelData: Default + IntoIterator + Send + Sync {
fn channel_insert(&mut self, x: Self::Item);
}
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
Queue Channel
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
impl<T> ChannelData for Vec<T>
where
T: Send + Sync,
{
fn channel_insert(&mut self, x: T) {
self.push(x);
}
}
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
Set Channel
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
impl<T> ChannelData for HashSet<T>
where
T: Eq + Hash + Send + Sync,
{
fn channel_insert(&mut self, x: T) {
self.insert(x);
}
}
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
Singleton Channel
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
impl<T> ChannelData for Option<T>
where
T: Send + Sync,
{
fn channel_insert(&mut self, x: T) {
*self = Some(x);
}
}
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
Channel
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
struct ChannelState<Data: ChannelData> {
send_buf: Option<Data>,
recv_iter: Option<Data::IntoIter>,
num_senders: usize,
waker: Option<Waker>,
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct ChannelSender<Data: ChannelData>(Arc<Mutex<ChannelState<Data>>>);
pub struct ChannelReceiver<Data: ChannelData>(Arc<Mutex<ChannelState<Data>>>);
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<Data: ChannelData> ChannelSender<Data>
where
Data::IntoIter: Send + Sync,
{
pub fn send(&self, msg: Data::Item) {
let mut state = self.0.lock().unwrap();
if state.send_buf.is_none() {
state.send_buf = Some(Data::default());
}
state.send_buf.as_mut().unwrap().channel_insert(msg);
if let Some(waker) = state.waker.take() {
waker.wake();
}
}
}
use crate::core::View;
impl<V: View + ?Sized, Data: ChannelData<Item = V::Msg>> Observer<V> for ChannelSender<Data>
where
V::Msg: Clone,
Data::IntoIter: Send + Sync,
{
fn notify(&mut self, msg: &V::Msg) {
self.send(msg.clone());
}
}
impl<Data: ChannelData> Clone for ChannelSender<Data> {
fn clone(&self) -> Self {
self.0.lock().unwrap().num_senders += 1;
ChannelSender(self.0.clone())
}
}
impl<Data: ChannelData> Drop for ChannelSender<Data> {
fn drop(&mut self) {
let mut state = self.0.lock().unwrap();
state.num_senders -= 1;
if let Some(waker) = state.waker.take() {
waker.wake();
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<Data: ChannelData> ChannelReceiver<Data> {
pub async fn recv(&self) -> Option<Data> {
ChannelRead(self.0.clone()).await
}
pub fn try_recv(&self) -> Option<Data> {
let mut state = self.0.lock().unwrap();
if let Some(buf) = state.send_buf.take() {
Some(buf)
} else {
None
}
}
}
struct ChannelRead<Data: ChannelData>(Arc<Mutex<ChannelState<Data>>>);
impl<Data: ChannelData> std::future::Future for ChannelRead<Data> {
type Output = Option<Data>;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let mut state = self.0.lock().unwrap();
if let Some(buf) = state.send_buf.take() {
Poll::Ready(Some(buf))
} else if state.num_senders == 0 {
Poll::Ready(None)
} else {
state.waker = Some(cx.waker().clone());
Poll::Pending
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<Data: ChannelData> Stream for ChannelReceiver<Data> {
type Item = Data::Item;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let mut state = self.0.lock().unwrap();
if let Some(recv_iter) = state.recv_iter.as_mut() {
if let Some(val) = recv_iter.next() {
return Poll::Ready(Some(val));
} else {
state.recv_iter = None
}
}
if let Some(send_buf) = state.send_buf.take() {
state.recv_iter = Some(send_buf.into_iter());
// recv_iter.next() is guaranteed to be Some(x)
Poll::Ready(state.recv_iter.as_mut().unwrap().next())
} else if state.num_senders == 0 {
Poll::Ready(None)
} else {
state.waker = Some(cx.waker().clone());
Poll::Pending
}
}
}
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
Factory Functions
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
pub fn channel<Data: ChannelData>() -> (ChannelSender<Data>, ChannelReceiver<Data>) {
let state = Arc::new(Mutex::new(ChannelState {
send_buf: None,
recv_iter: None,
num_senders: 1,
waker: None,
}));
(ChannelSender(state.clone()), ChannelReceiver(state))
}
pub fn set_channel<T: Eq + Hash + Send + Sync>(
) -> (ChannelSender<HashSet<T>>, ChannelReceiver<HashSet<T>>) {
channel::<HashSet<T>>()
}
pub fn queue_channel<T: Send + Sync>() -> (ChannelSender<Vec<T>>, ChannelReceiver<Vec<T>>) {
channel::<Vec<T>>()
}
pub fn singleton_channel<T: Send + Sync>() -> (ChannelSender<Option<T>>, ChannelReceiver<Option<T>>)
{
channel::<Option<T>>()
}

View File

@ -1,12 +0,0 @@
pub mod channel;
pub mod observer;
pub mod port;
pub mod view;
pub use {
channel::{queue_channel, set_channel, singleton_channel, ChannelReceiver, ChannelSender},
observer::{NotifyFnObserver, Observer, ObserverBroadcast, ObserverExt, ResetFnObserver},
port::{AnyInnerViewPort, AnyOuterViewPort, AnyViewPort, InnerViewPort, OuterViewPort, ViewPort},
view::View
};

View File

@ -1,179 +0,0 @@
use {
crate::core::{
channel::{channel, ChannelReceiver, ChannelSender},
View,
},
std::sync::RwLock,
std::sync::{Arc, Weak},
};
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
Observer
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
pub trait Observer<V: View + ?Sized>: Send + Sync {
fn reset(&mut self, _view: Option<Arc<V>>) {}
fn notify(&mut self, msg: &V::Msg);
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<V: View + ?Sized, O: Observer<V>> Observer<V> for Arc<RwLock<O>> {
fn reset(&mut self, view: Option<Arc<V>>) {
self.write().unwrap().reset(view);
}
fn notify(&mut self, msg: &V::Msg) {
self.write().unwrap().notify(msg);
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub trait ObserverExt<V: View + ?Sized>: Observer<V> {
fn notify_each(&mut self, it: impl IntoIterator<Item = V::Msg>);
}
impl<V: View + ?Sized, T: Observer<V>> ObserverExt<V> for T {
fn notify_each(&mut self, it: impl IntoIterator<Item = V::Msg>) {
for msg in it {
self.notify(&msg);
}
}
}
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
Broadcast
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
pub struct ObserverBroadcast<V: View + ?Sized>
where
V::Msg: Send + Sync,
{
rx: ChannelReceiver<Vec<V::Msg>>,
tx: ChannelSender<Vec<V::Msg>>,
observers: Vec<Weak<RwLock<dyn Observer<V>>>>,
}
impl<V: View + ?Sized> ObserverBroadcast<V>
where
V::Msg: Clone + Send + Sync,
{
pub fn new() -> Self {
let (tx, rx) = channel::<Vec<V::Msg>>();
ObserverBroadcast {
rx,
tx,
observers: Vec::new(),
}
}
pub fn add_observer(&mut self, obs: Weak<RwLock<dyn Observer<V>>>) {
self.cleanup();
self.observers.push(obs);
}
fn cleanup(&mut self) {
self.observers.retain(|o| o.strong_count() > 0);
}
fn iter(&self) -> impl Iterator<Item = Arc<RwLock<dyn Observer<V>>>> + '_ {
self.observers.iter().filter_map(|o| o.upgrade())
}
pub fn update(&self) {
if let Some(msg_vec) = self.rx.try_recv() {
for msg in msg_vec {
for o in self.iter() {
o.write().unwrap().notify(&msg);
}
}
}
}
}
impl<V: View + ?Sized> Observer<V> for ObserverBroadcast<V>
where
V::Msg: Clone,
{
fn reset(&mut self, view: Option<Arc<V>>) {
for o in self.iter() {
o.write().unwrap().reset(view.clone());
}
}
fn notify(&mut self, msg: &V::Msg) {
self.tx.send(msg.clone());
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct NotifyFnObserver<V, F>
where
V: View + ?Sized,
F: Fn(&V::Msg) + Send + Sync,
{
f: F,
_phantom: std::marker::PhantomData<V>,
}
impl<V, F> NotifyFnObserver<V, F>
where
V: View + ?Sized,
F: Fn(&V::Msg) + Send + Sync,
{
pub fn new(f: F) -> Self {
NotifyFnObserver {
f,
_phantom: std::marker::PhantomData,
}
}
}
impl<V, F> Observer<V> for NotifyFnObserver<V, F>
where
V: View + ?Sized,
F: Fn(&V::Msg) + Send + Sync,
{
fn notify(&mut self, msg: &V::Msg) {
(self.f)(msg);
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct ResetFnObserver<V, F>
where
V: View + ?Sized,
F: Fn(Option<Arc<V>>) + Send + Sync,
{
f: F,
_phantom: std::marker::PhantomData<V>,
}
impl<V, F> ResetFnObserver<V, F>
where
V: View + ?Sized,
F: Fn(Option<Arc<V>>) + Send + Sync,
{
pub fn new(f: F) -> Self {
ResetFnObserver {
f,
_phantom: std::marker::PhantomData,
}
}
}
impl<V, F> Observer<V> for ResetFnObserver<V, F>
where
V: View + ?Sized,
F: Fn(Option<Arc<V>>) + Send + Sync,
{
fn notify(&mut self, _msg: &V::Msg) {}
fn reset(&mut self, view: Option<Arc<V>>) {
(self.f)(view);
}
}

View File

@ -1,341 +0,0 @@
use {
crate::core::{NotifyFnObserver, Observer, ObserverBroadcast, ResetFnObserver, View},
std::any::Any,
std::sync::Arc,
std::sync::RwLock,
};
pub trait UpdateTask: Send + Sync {
fn update(&self);
}
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
View Port
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
pub struct ViewPort<V: View + ?Sized> {
view: Arc<RwLock<Option<Arc<V>>>>,
cast: Arc<RwLock<ObserverBroadcast<V>>>,
pub update_hooks: Arc<RwLock<Vec<Arc<dyn UpdateTask>>>>,
}
impl<V: View + ?Sized> ViewPort<V>
where
V::Msg: Clone,
{
pub fn new() -> Self {
ViewPort {
view: Arc::new(RwLock::new(None)),
cast: Arc::new(RwLock::new(ObserverBroadcast::new())),
update_hooks: Arc::new(RwLock::new(Vec::new())),
}
}
pub fn with_view(view: Arc<V>) -> Self {
let port = ViewPort::new();
port.set_view(Some(view));
port
}
pub fn set_view(&self, view: Option<Arc<V>>) {
self.update();
*self.view.write().unwrap() = view.clone();
self.cast.write().unwrap().reset(view);
}
pub fn get_cast(&self) -> Arc<RwLock<ObserverBroadcast<V>>> {
self.cast.clone()
}
pub fn add_observer(&self, observer: Arc<RwLock<dyn Observer<V>>>) {
self.update();
self.cast
.write()
.unwrap()
.add_observer(Arc::downgrade(&observer));
observer
.write()
.unwrap()
.reset(self.view.read().unwrap().clone());
}
pub fn add_update_hook(&self, hook_cast: Arc<dyn UpdateTask>) {
self.update_hooks.write().unwrap().push(hook_cast);
}
pub fn inner(&self) -> InnerViewPort<V> {
InnerViewPort(ViewPort {
view: self.view.clone(),
cast: self.cast.clone(),
update_hooks: self.update_hooks.clone(),
})
}
pub fn outer(&self) -> OuterViewPort<V> {
OuterViewPort(ViewPort {
view: self.view.clone(),
cast: self.cast.clone(),
update_hooks: self.update_hooks.clone(),
})
}
pub fn into_inner(self) -> InnerViewPort<V> {
InnerViewPort(ViewPort {
view: self.view,
cast: self.cast,
update_hooks: self.update_hooks,
})
}
pub fn into_outer(self) -> OuterViewPort<V> {
OuterViewPort(ViewPort {
view: self.view,
cast: self.cast,
update_hooks: self.update_hooks,
})
}
}
impl<V: View + ?Sized> UpdateTask for ViewPort<V>
where
V::Msg: Clone + Send + Sync,
{
fn update(&self) {
let v = {
let t = self.update_hooks.read().unwrap();
t.iter().cloned().collect::<Vec<_>>()
};
for hook in v {
hook.update();
}
self.cast.read().unwrap().update();
}
}
impl<V: View + ?Sized> Clone for ViewPort<V>
where
V::Msg: Clone,
{
fn clone(&self) -> Self {
ViewPort {
view: self.view.clone(),
cast: self.cast.clone(),
update_hooks: self.update_hooks.clone(),
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct InnerViewPort<V: View + ?Sized>(pub ViewPort<V>)
where
V::Msg: Clone;
pub struct OuterViewPort<V: View + ?Sized>(pub ViewPort<V>)
where
V::Msg: Clone;
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<V: View + ?Sized> InnerViewPort<V>
where
V::Msg: Clone,
{
pub fn get_broadcast(&self) -> Arc<RwLock<ObserverBroadcast<V>>> {
self.0.cast.clone()
}
pub fn set_view(&self, view: Option<Arc<V>>) -> Arc<RwLock<ObserverBroadcast<V>>> {
self.0.set_view(view);
self.get_broadcast()
}
pub fn get_view(&self) -> Option<Arc<V>> {
self.0.view.read().unwrap().clone()
}
pub fn notify(&self, msg: &V::Msg) {
self.0.cast.write().unwrap().notify(msg);
}
}
impl<V: View + ?Sized> Clone for InnerViewPort<V>
where
V::Msg: Clone,
{
fn clone(&self) -> Self {
InnerViewPort(self.0.clone())
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<V: View + ?Sized + 'static> OuterViewPort<V>
where
V::Msg: Clone,
{
pub fn get_view(&self) -> Option<Arc<V>> {
self.0.view.read().unwrap().clone()
}
pub fn get_view_arc(&self) -> Arc<RwLock<Option<Arc<V>>>> {
self.0.view.clone()
}
pub fn add_observer(
&self,
observer: Arc<RwLock<dyn Observer<V>>>,
) -> Arc<RwLock<Option<Arc<V>>>> {
self.0.add_observer(observer);
self.get_view_arc()
}
pub fn add_reset_fn<F: Fn(Option<Arc<V>>) + Send + Sync + 'static>(
&self,
reset: F,
) -> Arc<RwLock<ResetFnObserver<V, F>>> {
let obs = Arc::new(RwLock::new(ResetFnObserver::new(reset)));
self.add_observer(obs.clone());
obs
}
pub fn add_notify_fn<F: Fn(&V::Msg) + Send + Sync + 'static>(
&self,
notify: F,
) -> Arc<RwLock<NotifyFnObserver<V, F>>> {
let obs = Arc::new(RwLock::new(NotifyFnObserver::new(notify)));
self.add_observer(obs.clone());
obs
}
}
impl<V: View + ?Sized> Clone for OuterViewPort<V>
where
V::Msg: Clone,
{
fn clone(&self) -> Self {
OuterViewPort(self.0.clone())
}
}
impl<V: View + ?Sized> Default for OuterViewPort<V>
where V::Msg: Clone
{
fn default() -> Self {
ViewPort::new().into_outer()
}
}
/*
impl<V: View + ?Sized + 'static> OuterViewPort<V>
where V::Msg: Clone {
pub fn into_stream<Data>(
self,
reset: impl Fn(Option<Arc<V>>, ChannelSender<Data>) + Send + Sync + 'static
) -> ChannelReceiver<Data>
where Data: ChannelData<Item = V::Msg> + 'static,
Data::IntoIter: Send + Sync + 'static
{
let (s, r) = crate::core::channel::channel::<Data>();
self.add_observer(Arc::new(s.clone()));
self.add_reset_fn(
move |view| { reset(view, s.clone()); }
);
r
}
}
*/
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[derive(Clone)]
pub struct AnyViewPort {
view: Arc<dyn Any + Send + Sync + 'static>,
cast: Arc<dyn Any + Send + Sync + 'static>,
update_hooks: Arc<RwLock<Vec<Arc<dyn UpdateTask>>>>,
}
impl AnyViewPort {
pub fn downcast<V: View + ?Sized + 'static>(self) -> Result<ViewPort<V>, AnyViewPort> {
match (
self.view.clone().downcast::<RwLock<Option<Arc<V>>>>(),
self.cast.clone().downcast::<RwLock<ObserverBroadcast<V>>>(),
self.update_hooks.clone(),
) {
(Ok(view), Ok(cast), update_hooks) => Ok(ViewPort {
view,
cast,
update_hooks,
}),
_ => Err(self),
}
}
}
impl<V: View + ?Sized + 'static> From<ViewPort<V>> for AnyViewPort {
fn from(port: ViewPort<V>) -> Self {
AnyViewPort {
view: port.view as Arc<dyn Any + Send + Sync + 'static>,
cast: port.cast as Arc<dyn Any + Send + Sync + 'static>,
update_hooks: port.update_hooks,
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[derive(Clone)]
pub struct AnyOuterViewPort(AnyViewPort);
#[derive(Clone)]
pub struct AnyInnerViewPort(AnyViewPort);
impl AnyOuterViewPort {
pub fn downcast<V: View + ?Sized + 'static>(self) -> Result<OuterViewPort<V>, AnyViewPort>
where
V::Msg: Clone,
{
Ok(OuterViewPort(self.0.downcast::<V>()?))
}
}
impl<V: View + ?Sized + 'static> From<OuterViewPort<V>> for AnyOuterViewPort
where
V::Msg: Clone,
{
fn from(port: OuterViewPort<V>) -> Self {
AnyOuterViewPort(AnyViewPort {
view: port.0.view as Arc<dyn Any + Send + Sync + 'static>,
cast: port.0.cast as Arc<dyn Any + Send + Sync + 'static>,
update_hooks: port.0.update_hooks,
})
}
}
impl AnyInnerViewPort {
pub fn downcast<V: View + ?Sized + 'static>(self) -> Result<InnerViewPort<V>, AnyViewPort>
where
V::Msg: Clone,
{
Ok(InnerViewPort(self.0.downcast::<V>()?))
}
}
impl<V: View + ?Sized + 'static> From<InnerViewPort<V>> for AnyInnerViewPort
where
V::Msg: Clone,
{
fn from(port: InnerViewPort<V>) -> Self {
AnyInnerViewPort(AnyViewPort {
view: port.0.view as Arc<dyn Any + Send + Sync + 'static>,
cast: port.0.cast as Arc<dyn Any + Send + Sync + 'static>,
update_hooks: port.0.update_hooks,
})
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>

View File

@ -1,26 +0,0 @@
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
View
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
pub trait View: Send + Sync {
/// Notification message for the observers
type Msg: Send + Sync;
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
use std::sync::Arc;
use std::sync::RwLock;
impl<V: View + ?Sized> View for RwLock<V> {
type Msg = V::Msg;
}
impl<V: View + ?Sized> View for Arc<V> {
type Msg = V::Msg;
}
impl<V: View> View for Option<V> {
type Msg = V::Msg;
}

View File

@ -1,9 +1,9 @@
use {
r3vi::{
view::{OuterViewPort, sequence::*},
buffer::{vec::*, index_hashmap::*}
},
crate::{
core::{OuterViewPort},
sequence::{SequenceView},
vec::{VecBuffer},
index::{buffer::IndexBuffer},
terminal::{
TerminalView, TerminalStyle, make_label
}

View File

@ -1,8 +1,13 @@
use {
r3vi::{
view::{
OuterViewPort,
singleton::*,
},
buffer::singleton::*
},
crate::{
core::{OuterViewPort},
type_system::{Context},
singleton::{SingletonBuffer, SingletonView},
terminal::{TerminalAtom, TerminalEvent, TerminalStyle},
tree::NestedNode,
commander::Commander
@ -70,11 +75,11 @@ impl CharEditor {
)
}
}
/*
use crate::StringGen;
impl StringGen for CharEditor {
fn get_string(&self) -> String {
String::from(self.get())
}
}
*/

View File

@ -1,9 +1,13 @@
use {
crate::{
core::{InnerViewPort, OuterViewPort},
projection::ProjectionHelper,
sequence::SequenceView,
vec::VecBuffer,
r3vi::{
view::{
InnerViewPort, OuterViewPort,
sequence::*,
},
buffer::{
vec::*
},
projection::projection_helper::*,
},
std::sync::{Arc, RwLock},
};

View File

@ -1,26 +1,29 @@
use {
crate::{
core::{OuterViewPort},
type_system::{Context, TypeTerm},
list::{PTYListEditor},
sequence::{SequenceView, SequenceViewExt, decorator::{PTYSeqDecorate, SeqDecorStyle}},
singleton::{SingletonBuffer, SingletonView},
vec::{VecBuffer},
index::{buffer::IndexBuffer},
terminal::{
TerminalAtom, TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle,
TerminalView, make_label
r3vi::{
view::{
OuterViewPort,
singleton::*,
},
tree::{TreeCursor, TreeNav, TreeNavResult},
diagnostics::{Diagnostics, Message},
buffer::{
singleton::*,
vec::*,
index_hashmap::*
}
},
crate::{
type_system::{Context, TypeTerm, ReprTree},
editors::list::{PTYListEditor, ListStyle},
terminal::{
TerminalAtom, TerminalEvent, TerminalStyle, make_label
},
diagnostics::{Message},
tree::NestedNode,
Nested,
commander::Commander
},
std::sync::Arc,
std::sync::RwLock,
termion::event::{Event, Key},
cgmath::{Vector2, Point2}
cgmath::{Point2}
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
@ -74,13 +77,15 @@ impl DigitEditor {
}
pub fn into_node(self) -> NestedNode {
let data = self.get_data();
let editor = Arc::new(RwLock::new(self));
let ed = editor.read().unwrap();
let mut ed = editor.write().unwrap();
let r = ed.radix;
NestedNode::new()
.set_ctx(ed.ctx.clone())
.set_cmd(editor.clone())
.set_data(data)
.set_view(
ed.data
.get_port()
@ -106,6 +111,26 @@ impl DigitEditor {
let radix = self.radix;
self.data.get_port().map(move |c| c?.to_digit(radix))
}
pub fn get_type(&self) -> TypeTerm {
TypeTerm::Type {
id: self.ctx.read().unwrap().get_typeid("Digit").unwrap(),
args: vec![
TypeTerm::Num(self.radix as i64)
]
}
}
pub fn get_data(&self) -> Arc<RwLock<ReprTree>> {
let data_view = self.get_data_port();
ReprTree::ascend(
&ReprTree::new_leaf(
self.ctx.read().unwrap().type_term_from_str("( u32 )").unwrap(),
data_view.into()
),
self.get_type()
)
}
}
pub struct PosIntEditor {
@ -115,24 +140,40 @@ pub struct PosIntEditor {
impl PosIntEditor {
pub fn new(ctx: Arc<RwLock<Context>>, radix: u32) -> Self {
let mut node = PTYListEditor::new(
ctx.clone(),
TypeTerm::Type {
id: ctx.read().unwrap().get_typeid("Digit").unwrap(),
args: vec![
TypeTerm::Num(radix as i64)
]
},
match radix {
16 => ListStyle::Hex,
_ => ListStyle::Plain
},
0
).into_node();
// Set Type
let data = node.data.clone().unwrap();
node = node.set_data(ReprTree::ascend(
&data,
TypeTerm::Type {
id: ctx.read().unwrap().get_typeid("PosInt").unwrap(),
args: vec![
TypeTerm::Num(radix as i64),
TypeTerm::Type {
id: ctx.read().unwrap().get_typeid("BigEndian").unwrap(),
args: vec![]
}
]
}
));
PosIntEditor {
radix,
digits: PTYListEditor::new(
ctx.clone(),
TypeTerm::Type {
id: ctx.read().unwrap().get_typeid("Digit").unwrap(),
args: vec![
TypeTerm::Num(radix as i64)
]
},
None,
0
).into_node(
match radix {
16 => SeqDecorStyle::Hex,
_ => SeqDecorStyle::Plain
}
)
digits: node
}
}

View File

@ -1,8 +1,10 @@
use {
crate::{
core::{InnerViewPort, Observer, OuterViewPort},
sequence::SequenceView,
vec::VecBuffer,
r3vi::{
view::{
InnerViewPort, Observer, OuterViewPort,
sequence::*,
},
buffer::{vec::*}
},
std::sync::{Arc, RwLock},
};

View File

@ -0,0 +1,43 @@
use {
crate::{
editors::list::ListEditor
},
std::sync::{Arc, RwLock}
};
pub enum ListEditorCmd {
ItemCmd(Arc<RwLock<ReprTree>>)
Split,
Join
}
impl ObjCommander for ListEditor {
fn send_cmd_obj(&mut self, cmd_obj: Arc<RwLock<ReprTree>>) {
let cmd_repr = cmd_obj.read().unrwap();
if let Some(cmd) = cmd_repr.get_view<dyn SingletonView<ListEditorCmd>>() {
match cmd.get() {
ListEditorCmd::Split => {
}
ListEditorCmd::Join => {
}
ListEditorCmd::ItemCmd => {
if let Some(cur_item) = self.get_item_mut() {
drop(cmd);
drop(cmd_repr);
cur_item.send_cmd_obj(cmd_obj);
}
}
}
} else {
if let Some(cur_item) = self.get_item_mut() {
drop(cmd_repr);
cur_item.send_cmd_obj(cmd_obj);
}
}
}
}

View File

@ -0,0 +1,280 @@
use {
r3vi::{
view::{
OuterViewPort,
singleton::*,
sequence::*,
},
buffer::{
singleton::*,
vec::*,
}
},
crate::{
type_system::{Context, TypeTerm, ReprTree},
editors::list::{
ListCursor,
ListCursorMode
},
tree::{NestedNode, TreeNav}
},
std::sync::{Arc, RwLock},
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct ListEditor {
pub(super) cursor: SingletonBuffer<ListCursor>,
pub(crate) data: VecBuffer<NestedNode>,
pub(super) addr_port: OuterViewPort<dyn SequenceView<Item = isize>>,
pub(super) mode_port: OuterViewPort<dyn SingletonView<Item = ListCursorMode>>,
pub(crate) ctx: Arc<RwLock<Context>>,
/// item type
pub(super) typ: TypeTerm,
}
impl ListEditor {
pub fn new(
ctx: Arc<RwLock<Context>>,
typ: TypeTerm,
) -> Self {
let cursor = SingletonBuffer::new(ListCursor::default());
let data = VecBuffer::<NestedNode>::new();
ListEditor {
mode_port: cursor
.get_port()
.map({
let data = data.clone();
move |c| {
let ip = SingletonBuffer::new(c.mode).get_port();
match c.mode {
ListCursorMode::Insert => ip,
ListCursorMode::Select => {
if let Some(idx) = c.idx {
data.get(idx as usize).get_mode_view()
} else {
ip
}
}
}
}
})
.flatten(),
addr_port: VecBuffer::<OuterViewPort<dyn SequenceView<Item = isize>>>::with_data(
vec![
cursor.get_port()
.to_sequence()
.filter_map(|cur| cur.idx),
cursor.get_port()
.map({
let data = data.clone();
move |cur| {
if cur.mode == ListCursorMode::Select {
if let Some(idx) = cur.idx {
if idx >= 0 && idx < data.len() as isize {
return data.get(idx as usize).get_addr_view();
}
}
}
OuterViewPort::default()
}
})
.to_sequence()
.flatten()
])
.get_port()
.to_sequence()
.flatten(),
cursor,
data,
ctx,
typ,
}
}
pub fn get_item_type(&self) -> TypeTerm {
self.typ.clone()
}
pub fn get_seq_type(&self) -> TypeTerm {
TypeTerm::Type {
id: self.ctx.read().unwrap().get_typeid("Sequence").unwrap(),
args: vec![ self.get_item_type() ]
}
}
pub fn into_node(self) -> NestedNode {
let data = self.get_data();
let editor = Arc::new(RwLock::new(self));
NestedNode::new()
.set_data(data)
.set_editor(editor.clone())
.set_nav(editor.clone())
// .set_cmd(editor.clone())
}
pub fn get_cursor_port(&self) -> OuterViewPort<dyn SingletonView<Item = ListCursor>> {
self.cursor.get_port()
}
pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = NestedNode>> {
self.data.get_port().to_sequence()
}
pub fn get_data(&self) -> Arc<RwLock<ReprTree>> {
let data_view = self.get_data_port();
ReprTree::new_leaf(
self.get_seq_type(),
data_view.into()
)
}
pub fn get_item(&self) -> Option<NestedNode> {
if let Some(idx) = self.cursor.get().idx {
let idx = crate::utils::modulo(idx as isize, self.data.len() as isize) as usize;
if idx < self.data.len() {
Some(self.data.get(idx))
} else {
None
}
} else {
None
}
}
pub fn get_item_mut(&mut self) -> Option<MutableVecAccess<NestedNode>> {
if let Some(idx) = self.cursor.get().idx {
let idx = crate::utils::modulo(idx as isize, self.data.len() as isize) as usize;
if idx < self.data.len() {
Some(self.data.get_mut(idx))
} else {
None
}
} else {
None
}
}
pub fn is_listlist(&self) -> bool {
self.ctx.read().unwrap().is_list_type(&self.typ)
/*
match self.typ.clone() {
TypeTerm::Type { id, args } => {
id == self.ctx.read().unwrap().get_typeid("List").unwrap()
},
TypeTerm::Num(_) => false
}
*/
}
/// delete all items
pub fn clear(&mut self) {
self.data.clear();
self.cursor.set(ListCursor::home());
}
/// delete item before the cursor
pub fn delete_pxev(&mut self) {
let mut cur = self.cursor.get();
if let Some(idx) = cur.idx {
if idx > 0 && idx <= self.data.len() as isize {
cur.idx = Some(idx as isize - 1);
self.cursor.set(cur);
self.data.remove(idx as usize - 1);
}
}
}
/// delete item after the cursor
pub fn delete_nexd(&mut self) {
if let Some(idx) = self.cursor.get().idx {
if idx < self.data.len() as isize {
self.data.remove(idx as usize);
}
}
}
/// insert a new element
pub fn insert(&mut self, item: NestedNode) {
let mut cur = self.cursor.get();
if let Some(idx) = cur.idx {
match cur.mode {
ListCursorMode::Insert => {
self.data.insert(idx as usize, item.clone());
if self.is_listlist() {
cur.mode = ListCursorMode::Select;
} else {
cur.idx = Some(idx + 1);
}
}
ListCursorMode::Select => {
self.data.insert(1 + idx as usize, item.clone());
if self.is_listlist() {
cur.idx = Some(idx + 1);
}
}
}
self.cursor.set(cur);
}
}
/// split the list off at the current cursor position and return the second half
pub fn split(&mut self) -> ListEditor {
let mut le = ListEditor::new(self.ctx.clone(), self.typ.clone());
let cur = self.cursor.get();
if let Some(idx) = cur.idx {
let idx = idx as usize;
for _ in idx .. self.data.len() {
le.data.push( self.data.get(idx) );
self.data.remove(idx);
}
}
le
}
/// append data of other editor at the end and set cursor accordingly
pub fn join(&mut self, other: &ListEditor) {
let selfcur = self.cursor.get();
let othercur = other.cursor.get();
let is_bottom = self.get_cursor().tree_addr.len() == 1 ||
other.get_cursor().tree_addr.len() == 1;
let is_insert =
selfcur.mode == ListCursorMode::Insert
|| othercur.mode == ListCursorMode::Insert;
let is_primary = self.get_cursor().tree_addr.len() > 1;
self.cursor.set(ListCursor {
mode: if is_insert && is_bottom {
ListCursorMode::Insert
} else {
ListCursorMode::Select
},
idx: Some(self.data.len() as isize -
if is_primary {
1
} else {
0
}
)
});
for i in 0 .. other.data.len() {
self.data.push(other.data.get(i));
}
}
}

View File

@ -0,0 +1,15 @@
pub mod cursor;
pub mod editor;
pub mod nav;
pub mod segment;
pub mod pty_editor;
pub use {
cursor::{ListCursor, ListCursorMode},
editor::ListEditor,
segment::{ListSegment, ListSegmentSequence},
pty_editor::{ListStyle, PTYListEditor}
};

View File

@ -1,14 +1,17 @@
use {
r3vi::{
view::{
OuterViewPort,
singleton::*,
sequence::*
}
},
crate::{
core::{OuterViewPort},
sequence::{SequenceView},
list::{
editors::list::{
ListCursor, ListCursorMode,
ListEditor
editor::ListEditor
},
tree::{TreeCursor, TreeNav, TreeNavResult},
singleton::SingletonView,
Nested
tree::{TreeCursor, TreeNav, TreeNavResult}
},
cgmath::Vector2
};

View File

@ -0,0 +1,432 @@
use {
r3vi::{
view::{
OuterViewPort,
sequence::*,
},
projection::decorate_sequence::*,
},
crate::{
type_system::{Context, TypeTerm, ReprTree},
editors::list::{
ListCursor, ListCursorMode,
segment::{ListSegmentSequence},
editor::ListEditor
},
terminal::{
TerminalEditor, TerminalEvent,
TerminalView,
make_label
},
tree::{TreeCursor, TreeNav},
diagnostics::{Diagnostics, make_error},
tree::NestedNode,
commander::Commander,
PtySegment
},
std::sync::{Arc, RwLock},
termion::event::{Event, Key}
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[derive(Clone, Copy)]
pub enum ListStyle {
Plain,
HorizontalSexpr,
VerticalSexpr,
DoubleQuote,
Tuple,
EnumSet,
Path,
Hex
}
pub fn list_style_from_type(
ctx: &Arc<RwLock<Context>>,
typ: &TypeTerm
) -> Option<ListStyle> {
let ctx = ctx.read().unwrap();
match typ {
TypeTerm::Type {
id, args
} => {
if *id == ctx.get_typeid("List").unwrap() {
Some(ListStyle::HorizontalSexpr)
} else if *id == ctx.get_typeid("String").unwrap() {
Some(ListStyle::DoubleQuote)
} else if *id == ctx.get_typeid("Symbol").unwrap() {
Some(ListStyle::Plain)
} else if *id == ctx.get_typeid("PathSegment").unwrap() {
Some(ListStyle::Plain)
} else if *id == ctx.get_typeid("Path").unwrap() {
Some(ListStyle::Path)
} else if *id == ctx.get_typeid("PosInt").unwrap() {
if args.len() > 0 {
match args[0] {
TypeTerm::Num(radix) => {
match radix {
16 => Some(ListStyle::Hex),
_ => Some(ListStyle::Plain)
}
}
_ => None
}
} else {
None
}
} else {
None
}
}
_ => None
}
}
impl ListStyle {
fn get_split_char(&self) -> Option<char> {
match self {
ListStyle::Plain => None,
ListStyle::DoubleQuote => None,
ListStyle::HorizontalSexpr => Some(' '),
ListStyle::VerticalSexpr => Some('\n'),
ListStyle::Tuple => Some(','),
ListStyle::EnumSet => Some(','),
ListStyle::Path => Some('/'),
ListStyle::Hex => None
}
}
fn get_wrapper(&self) -> (&str, &str) {
match self {
ListStyle::Plain => ("", ""),
ListStyle::HorizontalSexpr => ("(", ")"),
ListStyle::VerticalSexpr => ("(", ")"),
ListStyle::DoubleQuote => ("\"", "\""),
ListStyle::Tuple => ("(", ")"),
ListStyle::EnumSet => ("{", "}"),
ListStyle::Path => ("<", ">"),
ListStyle::Hex => ("0x", "")
}
}
}
pub struct PTYListEditor {
pub editor: Arc<RwLock<ListEditor>>,
style: ListStyle,
depth: usize
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl PTYListEditor {
pub fn new(
ctx: Arc<RwLock<Context>>,
typ: TypeTerm,
style: ListStyle,
depth: usize
) -> Self {
Self::from_editor(
Arc::new(RwLock::new(ListEditor::new(ctx, typ))), style, depth)
}
pub fn from_editor(
editor: Arc<RwLock<ListEditor>>,
style: ListStyle,
depth: usize
) -> Self {
PTYListEditor {
style,
depth,
editor,
}
}
pub fn get_seg_seq_view(&self) -> OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>> {
let seg_seq = ListSegmentSequence::new(
self.editor.read().unwrap().get_cursor_port(),
self.editor.read().unwrap().get_data_port(),
self.depth
);
let se = seg_seq.read().unwrap();
se.get_view().map(move |segment| segment.pty_view())
}
pub fn pty_view(&self) -> OuterViewPort<dyn TerminalView> {
let editor = self.editor.read().unwrap();
let seg_seq = ListSegmentSequence::new(
editor.get_cursor_port(),
editor.get_data_port(),
self.depth
);
let seg_seq = seg_seq.read().unwrap();
seg_seq
.get_view()
.map(move |segment| segment.pty_view())
.separate(make_label(&if let Some(c) = self.style.get_split_char() { format!("{}", c) } else { "".to_string() } ))
.wrap(make_label(self.style.get_wrapper().0), make_label(self.style.get_wrapper().1))
.to_grid_horizontal()
.flatten()
}
pub fn into_node(self) -> NestedNode {
let view = self.pty_view();
let editor = Arc::new(RwLock::new(self));
let ed = editor.read().unwrap();
let edd = ed.editor.read().unwrap();
NestedNode::new()
.set_data(edd.get_data())
.set_cmd(editor.clone())
.set_editor(ed.editor.clone())
.set_nav(ed.editor.clone())
.set_ctx(edd.ctx.clone())
.set_view(view)
.set_diag(
edd.get_data_port()
.enumerate()
.map(
|(idx, item_editor)| {
let idx = *idx;
item_editor
.get_msg_port()
.map(
move |msg| {
let mut msg = msg.clone();
msg.addr.insert(0, idx);
msg
}
)
}
)
.flatten()
)
}
pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = NestedNode>> {
self.editor.read().unwrap().get_data_port()
}
pub fn clear(&mut self) {
self.editor.write().unwrap().clear();
}
pub fn get_item(&self) -> Option<NestedNode> {
self.editor.read().unwrap().get_item()
}
pub fn set_depth(&mut self, depth: usize) {
self.depth = depth;
}
pub fn split(e: &mut ListEditor, depth: usize) {
let cur = e.get_cursor();
if let Some(item) = e.get_item_mut() {
if let Some(head_editor) = item.editor.clone() {
let head = head_editor.downcast::<RwLock<ListEditor>>().unwrap();
let mut head = head.write().unwrap();
if cur.tree_addr.len() > 2 {
PTYListEditor::split(&mut head, depth+1);
}
let mut tail = head.split();
head.goto(TreeCursor::none());
tail.cursor.set(
ListCursor {
idx: Some(0),
mode: if cur.tree_addr.len() > 2 {
ListCursorMode::Select
} else {
ListCursorMode::Insert
}
}
);
let item_type =
if let Some(data) = item.data.clone() {
let data = data.read().unwrap();
Some(data.get_type().clone())
} else {
None
};
let style =
if let Some(item_type) = &item_type {
list_style_from_type(&tail.ctx, item_type)
.unwrap_or(
ListStyle::HorizontalSexpr
)
} else {
ListStyle::HorizontalSexpr
};
let mut tail_node = PTYListEditor::from_editor(
Arc::new(RwLock::new(tail)),
style,
depth+1
).into_node();
if let Some(item_type) = item_type {
tail_node.data = Some(ReprTree::ascend(
&tail_node.data.unwrap(),
item_type.clone()
));
}
e.insert(
tail_node
);
}
}
}
fn join_pxev(e: &mut ListEditor, idx: isize, item: &NestedNode) {
{
let prev_editor = e.data.get_mut(idx as usize-1);
let prev_editor = prev_editor.editor.clone();
let prev_editor = prev_editor.unwrap().downcast::<RwLock<ListEditor>>().unwrap();
let mut prev_editor = prev_editor.write().unwrap();
let cur_editor = item.editor.clone().unwrap();
let cur_editor = cur_editor.downcast::<RwLock<ListEditor>>().unwrap();
let cur_editor = cur_editor.write().unwrap();
prev_editor.join(&cur_editor);
}
e.cursor.set(
ListCursor {
idx: Some(idx - 1), mode: ListCursorMode::Select
}
);
e.data.remove(idx as usize);
}
fn join_nexd(e: &mut ListEditor, next_idx: usize, item: &NestedNode) {
{
let next_editor = e.data.get_mut(next_idx).editor.clone();
let next_editor = next_editor.unwrap().downcast::<RwLock<ListEditor>>().unwrap();
let next_editor = next_editor.write().unwrap();
let cur_editor = item.editor.clone().unwrap();
let cur_editor = cur_editor.downcast::<RwLock<ListEditor>>().unwrap();
let mut cur_editor = cur_editor.write().unwrap();
cur_editor.join(&next_editor);
}
e.data.remove(next_idx);
}
}
impl Commander for PTYListEditor {
type Cmd = TerminalEvent;
fn send_cmd(&mut self, event: &TerminalEvent) {
let mut e = self.editor.write().unwrap();
match event {
TerminalEvent::Input(Event::Key(Key::Char('\t')))
| TerminalEvent::Input(Event::Key(Key::Insert)) => {
e.toggle_leaf_mode();
e.set_leaf_mode(ListCursorMode::Select);
}
_ => {
let cur = e.cursor.get();
if let Some(idx) = cur.idx {
match cur.mode {
ListCursorMode::Insert => {
match event {
TerminalEvent::Input(Event::Key(Key::Backspace)) => {
e.delete_pxev();
}
TerminalEvent::Input(Event::Key(Key::Delete)) => {
e.delete_nexd();
}
_ => {
let mut new_edit = Context::make_editor(&e.ctx, e.typ.clone(), self.depth).unwrap();
new_edit.goto(TreeCursor::home());
new_edit.handle_terminal_event(event);
e.insert(new_edit);
}
}
},
ListCursorMode::Select => {
if let Some(mut item) = e.get_item().clone() {
if e.is_listlist() {
match event {
TerminalEvent::Input(Event::Key(Key::Backspace)) => {
let item_cur = item.get_cursor();
if idx > 0
&& item_cur.tree_addr.iter().fold(
true,
|is_zero, x| is_zero && (*x == 0)
)
{
PTYListEditor::join_pxev(&mut e, idx, &item);
/*
if item_cur.tree_addr.len() > 1 {
let mut item = e.get_item_mut().unwrap();
item.handle_terminal_event(event);
}
*/
} else {
item.handle_terminal_event(event);
}
}
TerminalEvent::Input(Event::Key(Key::Delete)) => {
let item_cur = item.get_cursor_warp();
let next_idx = idx as usize + 1;
if next_idx < e.data.len()
&& item_cur.tree_addr.iter().fold(
true,
|is_end, x| is_end && (*x == -1)
)
{
PTYListEditor::join_nexd(&mut e, next_idx, &item);
/*
if item_cur.tree_addr.len() > 1 {
let mut item = e.get_item_mut().unwrap();
item.handle_terminal_event(event);
}
*/
} else {
item.handle_terminal_event(event);
}
}
TerminalEvent::Input(Event::Key(Key::Char(c))) => {
if Some(*c) == self.style.get_split_char() {
PTYListEditor::split(&mut e, self.depth);
} else {
item.handle_terminal_event(event);
}
}
_ => {
item.handle_terminal_event(event);
}
}
} else {
item.handle_terminal_event(event);
}
}
}
}
}
}
}
}
}

View File

@ -1,10 +1,14 @@
use {
r3vi::{
view::{
Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View, ViewPort,
singleton::*,
sequence::*,
},
projection::projection_helper::*
},
crate::{
core::{InnerViewPort, Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View, ViewPort},
list::{ListCursor, ListCursorMode},
projection::ProjectionHelper,
sequence::SequenceView,
singleton::SingletonView,
editors::list::{ListCursor, ListCursorMode},
terminal::{TerminalView, TerminalStyle, make_label},
tree::{NestedNode, TreeNav},
utils::color::{bg_style_from_depth, fg_style_from_depth},

View File

@ -0,0 +1,7 @@
pub mod char;
pub mod integer;
pub mod list;
pub mod product;
pub mod sum;

View File

@ -1,16 +1,26 @@
use {
r3vi::{
view::{
OuterViewPort,
sequence::*
},
buffer::{
vec::*,
index_hashmap::*
}
},
crate::{
core::{OuterViewPort},
type_system::{TypeLadder, Context},
terminal::{
TerminalEditor, TerminalEditorResult,
TerminalEvent, TerminalView
},
vec::{VecBuffer},
index::{buffer::{IndexBuffer, MutableIndexAccess}},
list::ListCursorMode,
product::{segment::ProductEditorSegment},
sequence::{SequenceView},
editors::{
list::ListCursorMode,
product::{
segment::ProductEditorSegment
}
},
tree::{TreeNav, TreeNavResult},
diagnostics::{Diagnostics},
terminal::{TerminalStyle},
@ -177,6 +187,15 @@ impl ProductEditor {
}
}
use crate::commander::Commander;
impl Commander for ProductEditor {
type Cmd = TerminalEvent;
fn send_cmd(&mut self, ev: &TerminalEvent) {
self.handle_terminal_event(ev);
}
}
impl TerminalEditor for ProductEditor {
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
let ctx = self.ctx.clone();

View File

@ -1,10 +1,11 @@
use {
crate::{
type_system::Context,
list::ListCursorMode,
tree::{TreeNav, TreeNavResult, TreeCursor},
product::{segment::ProductEditorSegment, ProductEditor},
Nested
editors::{
list::ListCursorMode,
product::{segment::ProductEditorSegment, ProductEditor},
}
},
cgmath::{Vector2},
std::{ops::{DerefMut}},
@ -245,5 +246,3 @@ impl TreeNav for ProductEditor {
}
}
impl Nested for ProductEditor {}

View File

@ -1,6 +1,10 @@
use {
r3vi::{
view::{
OuterViewPort
}
},
crate::{
core::{OuterViewPort},
type_system::{TypeLadder, Context},
terminal::{
TerminalStyle, TerminalView,

View File

@ -1,11 +1,19 @@
use {
r3vi::{
view::{
ViewPort, OuterViewPort,
sequence::*,
},
buffer::{
vec::*
}
},
crate::{
core::{ViewPort, OuterViewPort},
terminal::{
TerminalEditor, TerminalEditorResult,
TerminalEvent, TerminalView
},
sequence::{SequenceView},
type_system::{Context},
tree::{TreeNav, TreeCursor, TreeNavResult},
diagnostics::{Diagnostics, Message},
tree::NestedNode,
@ -30,25 +38,26 @@ impl SumEditor {
editors: Vec< NestedNode >
) -> Self {
let port = ViewPort::new();
//let mut diag_buf = VecBuffer::new();
SumEditor {
cur: 0,
editors,
port,
diag_port: ViewPort::new()//diag_buf.get_port().to_sequence()
diag_port: ViewPort::new()
}
}
/*
pub fn into_node(self) -> NestedNode {
pub fn into_node(self, ctx: Arc<RwLock<Context>>) -> NestedNode {
let view = self.pty_view();
let editor = Arc::new(RwLock::new(self));
NestedNode::new()
.set_view()
.set_ctx(ctx)
.set_view(view)
.set_cmd(editor.clone())
.set_nav(editor.clone())
.set_diag(editor.read().unwrap().diag.clone())
// .set_diag(editor.read().unwrap().diag.clone())
}
*/
pub fn get(&self) -> NestedNode {
self.editors[ self.cur ].clone()
}

View File

@ -1,90 +0,0 @@
use {
std::{
sync::Arc,
collections::HashMap,
hash::Hash
},
std::sync::RwLock,
crate::{
core::{
Observer,
ObserverBroadcast,
View,
InnerViewPort
},
index::{IndexArea, IndexView}
}
};
struct GridBuffer<Item> {
data: HashMap<Point2<i16>, Item>,
limit: Point2<i16>
}
impl<Item> View for GridBuffer<Item>
where Item: Clone + Send + Sync + 'static
{
type Msg = IndexArea<Point2<i16>>;
}
impl<Item> IndexView<Point2<i16>> for GridBufferView<Item>
where Item: Clone + Send + Sync + 'static
{
type Item = Item;
fn get(&self, key: &Point2<i16>) -> Option<Self::Item> {
self.data.get(key).cloned()
}
fn area(&self) -> IndexArea<Point2<i16>> {
IndexArea::Range(
Point2::new(0, 0)
..= self.limit
)
}
}
pub struct GridBufferController<Item>
where Item: Clone + Send + Sync + 'static
{
data: Arc<RwLock<HashMap<Point2<i16>, Item>>>,
cast: Arc<RwLock<ObserverBroadcast<dyn IndexView<Point2<i16>, Item = Item>>>>
}
impl<Key, Item> GridBuffer<Key, Item>
where Key: Clone + Hash + Eq + Send + Sync + 'static,
Item: Clone + Send + Sync + 'static
{
pub fn new(port: InnerViewPort<dyn IndexView<Point2<i16>, Item = Item>>) -> Self {
let data = Arc::new(RwLock::new(HashMap::<Point2<i16>, Item>::new()));
port.set_view(Some(Arc::new(GridBufferView(data.clone()))));
GridBuffer {
data,
cast: port.get_broadcast()
}
}
pub fn insert(&mut self, key: Point2<i16>, item: Item) {
self.data.write().unwrap().insert(key.clone(), item);
if
self.cast.notify(&IndexArea::Set(vec![ key ]));
}
pub fn insert_iter<T>(&mut self, iter: T)
where T: IntoIterator<Item = (Point2<i16>, Item)> {
for (key, item) in iter {
self.insert(key, item);
}
}
pub fn remove(&mut self, key: Point2<i16>) {
self.data.write().unwrap().remove(&key);
self.cast.notify(&IndexArea::Set(vec![ key ]));
}
}

View File

@ -1,244 +0,0 @@
use {
crate::{
core::{InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View, ViewPort},
grid::{GridView, GridWindowIterator},
index::{IndexArea, IndexView},
projection::ProjectionHelper,
},
cgmath::{Point2, Vector2},
std::sync::RwLock,
std::{cmp::max, collections::HashMap, sync::Arc},
};
impl<Item> OuterViewPort<dyn GridView<Item = OuterViewPort<dyn GridView<Item = Item>>>>
where
Item: 'static,
{
pub fn flatten(&self) -> OuterViewPort<dyn GridView<Item = Item>> {
let port = ViewPort::new();
port.add_update_hook(Arc::new(self.0.clone()));
Flatten::new(self.clone(), port.inner());
port.into_outer()
}
}
pub struct Chunk<Item>
where
Item: 'static,
{
offset: Vector2<i16>,
limit: Point2<i16>,
view: Arc<dyn GridView<Item = Item>>,
}
pub struct Flatten<Item>
where
Item: 'static,
{
limit: Point2<i16>,
top: Arc<dyn GridView<Item = OuterViewPort<dyn GridView<Item = Item>>>>,
chunks: HashMap<Point2<i16>, Chunk<Item>>,
cast: Arc<RwLock<ObserverBroadcast<dyn GridView<Item = Item>>>>,
proj_helper: ProjectionHelper<Point2<i16>, Self>,
}
impl<Item> View for Flatten<Item>
where
Item: 'static,
{
type Msg = IndexArea<Point2<i16>>;
}
impl<Item> IndexView<Point2<i16>> for Flatten<Item>
where
Item: 'static,
{
type Item = Item;
fn get(&self, idx: &Point2<i16>) -> Option<Self::Item> {
let chunk_idx = self.get_chunk_idx(*idx)?;
let chunk = self.chunks.get(&chunk_idx)?;
chunk.view.get(&(*idx - chunk.offset))
}
fn area(&self) -> IndexArea<Point2<i16>> {
IndexArea::Range(Point2::new(0, 0)..=self.limit)
}
}
/* TODO: remove unused projection args (bot-views) if they get replaced by a new viewport */
impl<Item> Flatten<Item>
where
Item: 'static,
{
pub fn new(
top_port: OuterViewPort<dyn GridView<Item = OuterViewPort<dyn GridView<Item = Item>>>>,
out_port: InnerViewPort<dyn GridView<Item = Item>>,
) -> Arc<RwLock<Self>> {
let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone());
let flat = Arc::new(RwLock::new(Flatten {
limit: Point2::new(0, 0),
top: proj_helper.new_index_arg(
Point2::new(-1, -1),
top_port,
|s: &mut Self, chunk_area| {
for chunk_idx in chunk_area.iter() {
s.update_chunk(chunk_idx);
}
},
),
chunks: HashMap::new(),
cast: out_port.get_broadcast(),
proj_helper,
}));
flat.write().unwrap().proj_helper.set_proj(&flat);
out_port.set_view(Some(flat.clone()));
flat
}
/// the top-sequence has changed the item at chunk_idx,
/// create a new observer for the contained sub sequence
fn update_chunk(&mut self, chunk_idx: Point2<i16>) {
if let Some(chunk_port) = self.top.get(&chunk_idx) {
let view = self.proj_helper.new_index_arg(
chunk_idx,
chunk_port.clone(),
move |s: &mut Self, area| {
if let Some(chunk) = s.chunks.get(&chunk_idx) {
if chunk.limit != *chunk.view.area().range().end() {
s.update_all_offsets();
}
}
if let Some(chunk) = s.chunks.get(&chunk_idx) {
s.cast.notify(&area.map(|pt| pt + chunk.offset));
}
},
);
if let Some(chunk) = self.chunks.get_mut(&chunk_idx) {
chunk.view = view;
let old_limit = chunk.limit;
let new_limit = *chunk.view.area().range().end();
self.cast.notify(
&IndexArea::Range(
Point2::new(chunk.offset.x, chunk.offset.y) ..= Point2::new(chunk.offset.x + max(old_limit.x, new_limit.x), chunk.offset.y + max(old_limit.y, new_limit.y) )));
} else {
self.chunks.insert(
chunk_idx,
Chunk {
offset: Vector2::new(-1, -1),
limit: Point2::new(-1, -1),
view,
},
);
}
self.update_all_offsets();
} else {
self.proj_helper.remove_arg(&chunk_idx);
if let Some(_chunk) = self.chunks.remove(&chunk_idx) {
self.update_all_offsets();
}
}
}
/// recalculate all chunk offsets
/// and update size of flattened grid
fn update_all_offsets(&mut self) {
let top_range = self.top.area().range();
let mut col_widths = vec![0 as i16; (top_range.end().x + 1) as usize];
let mut row_heights = vec![0 as i16; (top_range.end().y + 1) as usize];
for chunk_idx in GridWindowIterator::from(top_range.clone()) {
if let Some(chunk) = self.chunks.get_mut(&chunk_idx) {
let chunk_range = chunk.view.area().range();
let lim = *chunk_range.end();
col_widths[chunk_idx.x as usize] = max(
col_widths[chunk_idx.x as usize],
if lim.x < 0 { 0 } else { lim.x + 1 },
);
row_heights[chunk_idx.y as usize] = max(
row_heights[chunk_idx.y as usize],
if lim.y < 0 { 0 } else { lim.y + 1 },
);
}
}
for chunk_idx in GridWindowIterator::from(top_range.clone()) {
if let Some(chunk) = self.chunks.get_mut(&chunk_idx) {
let _old_offset = chunk.offset;
let _old_limit = chunk.limit;
//chunk.limit = Point2::new( col_widths[chunk_idx.x as usize]-1, row_heights[chunk_idx.y as usize]-1 );
chunk.limit = *chunk.view.area().range().end();
chunk.offset = Vector2::new(
(0..chunk_idx.x as usize).map(|x| col_widths[x]).sum(),
(0..chunk_idx.y as usize).map(|y| row_heights[y]).sum(),
);
/*
if old_offset != chunk.offset {
self.cast.notify(
&IndexArea::Range(
Point2::new(
std::cmp::min(old_offset.x, chunk.offset.x),
std::cmp::min(old_offset.y, chunk.offset.y)
)
..= Point2::new(
std::cmp::max(old_offset.x + old_limit.x, chunk.offset.x + chunk.limit.x),
std::cmp::max(old_offset.y + old_limit.y, chunk.offset.y + chunk.limit.y)
)
)
);
}
*/
}
}
let old_limit = self.limit;
self.limit = Point2::new(
(0..=top_range.end().x)
.map(|x| col_widths.get(x as usize).unwrap_or(&0))
.sum::<i16>()
- 1,
(0..=top_range.end().y)
.map(|y| row_heights.get(y as usize).unwrap_or(&0))
.sum::<i16>()
- 1,
);
self.cast.notify(&IndexArea::Range(
Point2::new(0, 0)
..=Point2::new(
max(self.limit.x, old_limit.x),
max(self.limit.y, old_limit.y),
),
));
}
/// given an index in the flattened sequence,
/// which sub-sequence does it belong to?
fn get_chunk_idx(&self, glob_pos: Point2<i16>) -> Option<Point2<i16>> {
for chunk_idx in GridWindowIterator::from(self.top.area().range()) {
if let Some(chunk) = self.chunks.get(&chunk_idx) {
let end = chunk.limit + chunk.offset;
if glob_pos.x <= end.x && glob_pos.y <= end.y {
return Some(chunk_idx);
}
}
}
None
}
}

View File

@ -1,74 +0,0 @@
use {
crate::index::{IndexArea, IndexView},
cgmath::Point2,
std::{
cmp::{max, min},
ops::RangeInclusive,
},
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub trait GridView = IndexView<Point2<i16>>;
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub mod flatten;
pub mod offset;
pub mod window_iterator;
pub use window_iterator::GridWindowIterator;
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl IndexArea<Point2<i16>> {
// todo: this is not perfect (e.g. diagonals are inefficient)
pub fn iter(&self) -> GridWindowIterator {
GridWindowIterator::from(self.range())
}
pub fn range(&self) -> RangeInclusive<Point2<i16>> {
match self {
IndexArea::Empty => Point2::new(0, 0)..=Point2::new(-1, -1),
IndexArea::Full => panic!("range from full grid area"),
IndexArea::Set(v) => {
Point2::new(
v.iter().map(|p| p.x).min().unwrap_or(i16::MAX),
v.iter().map(|p| p.y).min().unwrap_or(i16::MAX),
)
..=Point2::new(
v.iter().map(|p| p.x).max().unwrap_or(i16::MIN),
v.iter().map(|p| p.y).max().unwrap_or(i16::MIN),
)
}
IndexArea::Range(r) => r.clone(),
}
}
pub fn union(self, other: IndexArea<Point2<i16>>) -> IndexArea<Point2<i16>> {
match (self, other) {
(IndexArea::Empty, a) | (a, IndexArea::Empty) => a,
(IndexArea::Full, _) | (_, IndexArea::Full) => IndexArea::Full,
(IndexArea::Set(mut va), IndexArea::Set(vb)) => {
va.extend(vb.into_iter());
IndexArea::Set(va)
}
(IndexArea::Range(r), IndexArea::Set(mut v))
| (IndexArea::Set(mut v), IndexArea::Range(r)) => {
v.extend(GridWindowIterator::from(r));
IndexArea::Set(v)
}
(IndexArea::Range(ra), IndexArea::Range(rb)) => IndexArea::Range(
Point2::new(
min(ra.start().x, rb.start().x),
min(ra.start().y, rb.start().y),
)
..=Point2::new(max(ra.end().x, rb.end().x), max(ra.end().y, rb.end().y)),
),
}
}
}

View File

@ -1,15 +0,0 @@
use {
crate::{core::OuterViewPort, grid::GridView},
cgmath::Vector2,
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<Item> OuterViewPort<dyn GridView<Item = Item>>
where
Item: 'static,
{
pub fn offset(&self, offset: Vector2<i16>) -> OuterViewPort<dyn GridView<Item = Item>> {
self.map_key(move |pt| pt + offset, move |pt| Some(pt - offset))
}
}

View File

@ -1,58 +0,0 @@
use {
cgmath::Point2,
std::ops::{Range, RangeInclusive},
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct GridWindowIterator {
next: Point2<i16>,
range: Range<Point2<i16>>,
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl From<Range<Point2<i16>>> for GridWindowIterator {
fn from(range: Range<Point2<i16>>) -> Self {
GridWindowIterator {
next: range.start,
range,
}
}
}
impl From<RangeInclusive<Point2<i16>>> for GridWindowIterator {
fn from(range: RangeInclusive<Point2<i16>>) -> Self {
GridWindowIterator {
next: *range.start(),
range: *range.start()..Point2::new(range.end().x + 1, range.end().y + 1),
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl Iterator for GridWindowIterator {
type Item = Point2<i16>;
fn next(&mut self) -> Option<Point2<i16>> {
if self.next.y < self.range.end.y {
if self.next.x < self.range.end.x {
let next = self.next;
if self.next.x + 1 < self.range.end.x {
self.next.x += 1;
} else {
self.next.x = self.range.start.x;
self.next.y += 1;
}
Some(next)
} else {
None
}
} else {
None
}
}
}

View File

@ -1,156 +0,0 @@
use {
crate::{
core::{InnerViewPort, OuterViewPort, ViewPort, Observer, View},
index::{IndexArea, IndexView},
},
std::sync::RwLock,
std::{collections::HashMap, hash::Hash, sync::Arc, ops::{Deref, DerefMut}},
};
pub struct IndexBufferView<Key, Item>(Arc<RwLock<HashMap<Key, Item>>>)
where
Key: Clone + Hash + Eq + Send + Sync + 'static,
Item: Clone + Send + Sync + 'static;
impl<Key, Item> View for IndexBufferView<Key, Item>
where
Key: Clone + Hash + Eq + Send + Sync + 'static,
Item: Clone + Send + Sync + 'static,
{
type Msg = IndexArea<Key>;
}
impl<Key, Item> IndexView<Key> for IndexBufferView<Key, Item>
where
Key: Clone + Hash + Eq + Send + Sync + 'static,
Item: Clone + Send + Sync + 'static,
{
type Item = Item;
fn get(&self, key: &Key) -> Option<Self::Item> {
self.0.read().unwrap().get(key).cloned()
}
fn area(&self) -> IndexArea<Key> {
IndexArea::Set(self.0.read().unwrap().keys().cloned().collect())
}
}
#[derive(Clone)]
pub struct IndexBuffer<Key, Item>
where
Key: Clone + Hash + Eq + Send + Sync + 'static,
Item: Clone + Send + Sync + 'static,
{
data: Arc<RwLock<HashMap<Key, Item>>>,
port: InnerViewPort<dyn IndexView<Key, Item = Item>>,
}
impl<Key, Item> IndexBuffer<Key, Item>
where
Key: Clone + Hash + Eq + Send + Sync + 'static,
Item: Clone + Send + Sync + 'static,
{
pub fn with_port(port: InnerViewPort<dyn IndexView<Key, Item = Item>>) -> Self {
let data = Arc::new(RwLock::new(HashMap::<Key, Item>::new()));
port.set_view(Some(Arc::new(IndexBufferView(data.clone()))));
IndexBuffer {
data,
port
}
}
pub fn new() -> Self {
IndexBuffer::with_port(ViewPort::new().into_inner())
}
pub fn get_port(&self) -> OuterViewPort<dyn IndexView<Key, Item = Item>> {
self.port.0.outer()
}
pub fn get(&self, key: &Key) -> Option<Item> {
self.data.read().unwrap().get(key).cloned()
}
pub fn get_mut(&mut self, key: &Key) -> MutableIndexAccess<Key, Item> {
MutableIndexAccess {
buf: self.clone(),
key: key.clone(),
val: self.get(key)
}
}
pub fn update(&mut self, key: Key, item: Option<Item>) {
if let Some(item) = item {
self.data.write().unwrap().insert(key.clone(), item);
} else {
self.data.write().unwrap().remove(&key);
}
self.port.notify(&IndexArea::Set(vec![key]));
}
pub fn insert(&mut self, key: Key, item: Item) {
self.data.write().unwrap().insert(key.clone(), item);
self.port.notify(&IndexArea::Set(vec![key]));
}
pub fn insert_iter<T>(&mut self, iter: T)
where
T: IntoIterator<Item = (Key, Item)>,
{
for (key, item) in iter {
self.insert(key, item);
}
}
pub fn remove(&mut self, key: Key) {
self.data.write().unwrap().remove(&key);
self.port.notify(&IndexArea::Set(vec![key]));
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct MutableIndexAccess<Key, Item>
where
Key: Clone + Hash + Eq + Send + Sync + 'static,
Item: Clone + Send + Sync + 'static,
{
buf: IndexBuffer<Key, Item>,
key: Key,
val: Option<Item>,
}
impl<Key, Item> Deref for MutableIndexAccess<Key, Item>
where
Key: Clone + Hash + Eq + Send + Sync + 'static,
Item: Clone + Send + Sync + 'static,
{
type Target = Option<Item>;
fn deref(&self) -> &Option<Item> {
&self.val
}
}
impl<Key, Item> DerefMut for MutableIndexAccess<Key, Item>
where
Key: Clone + Hash + Eq + Send + Sync + 'static,
Item: Clone + Send + Sync + 'static,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.val
}
}
impl<Key, Item> Drop for MutableIndexAccess<Key, Item>
where
Key: Clone + Hash + Eq + Send + Sync + 'static,
Item: Clone + Send + Sync + 'static,
{
fn drop(&mut self) {
self.buf.update(self.key.clone(), self.val.clone());
}
}

View File

@ -1,107 +0,0 @@
pub use {
crate::{
core::{
InnerViewPort, Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View, ViewPort,
},
index::{IndexArea, IndexView},
},
std::sync::RwLock,
std::{boxed::Box, sync::Arc},
};
impl<Key, Item> OuterViewPort<dyn IndexView<Key, Item = Item>>
where
Key: Clone + Send + Sync + 'static,
Item: Send + Sync + 'static,
{
pub fn map_item<DstItem: 'static, F: Fn(&Key, &Item) -> DstItem + Send + Sync + 'static>(
&self,
f: F,
) -> OuterViewPort<dyn IndexView<Key, Item = DstItem>> {
let port = ViewPort::new();
port.add_update_hook(Arc::new(self.0.clone()));
let map = MapIndexItem::new(port.inner(), f);
self.add_observer(map.clone());
port.into_outer()
}
}
pub struct MapIndexItem<Key, DstItem, SrcView, F>
where
Key: Clone + Send + Sync,
SrcView: IndexView<Key> + ?Sized,
F: Fn(&Key, &SrcView::Item) -> DstItem + Send + Sync,
{
src_view: Option<Arc<SrcView>>,
f: F,
cast: Arc<RwLock<ObserverBroadcast<dyn IndexView<Key, Item = DstItem>>>>,
}
impl<Key, DstItem, SrcView, F> MapIndexItem<Key, DstItem, SrcView, F>
where
Key: Clone + Send + Sync + 'static,
DstItem: 'static,
SrcView: IndexView<Key> + ?Sized + 'static,
F: Fn(&Key, &SrcView::Item) -> DstItem + Send + Sync + 'static,
{
fn new(port: InnerViewPort<dyn IndexView<Key, Item = DstItem>>, f: F) -> Arc<RwLock<Self>> {
let map = Arc::new(RwLock::new(MapIndexItem {
src_view: None,
f,
cast: port.get_broadcast(),
}));
port.set_view(Some(map.clone()));
map
}
}
impl<Key, DstItem, SrcView, F> View for MapIndexItem<Key, DstItem, SrcView, F>
where
Key: Clone + Send + Sync,
SrcView: IndexView<Key> + ?Sized,
F: Fn(&Key, &SrcView::Item) -> DstItem + Send + Sync,
{
type Msg = IndexArea<Key>;
}
impl<Key, DstItem, SrcView, F> IndexView<Key> for MapIndexItem<Key, DstItem, SrcView, F>
where
Key: Clone + Send + Sync,
SrcView: IndexView<Key> + ?Sized,
F: Fn(&Key, &SrcView::Item) -> DstItem + Send + Sync,
{
type Item = DstItem;
fn get(&self, key: &Key) -> Option<Self::Item> {
self.src_view
.get(key)
.as_ref()
.map(|item| (self.f)(key, item))
}
fn area(&self) -> IndexArea<Key> {
self.src_view.area()
}
}
impl<Key, DstItem, SrcView, F> Observer<SrcView> for MapIndexItem<Key, DstItem, SrcView, F>
where
Key: Clone + Send + Sync,
SrcView: IndexView<Key> + ?Sized,
F: Fn(&Key, &SrcView::Item) -> DstItem + Send + Sync,
{
fn reset(&mut self, view: Option<Arc<SrcView>>) {
let old_area = self.area();
self.src_view = view;
self.cast.notify(&old_area);
self.cast.notify(&self.src_view.area())
}
fn notify(&mut self, area: &IndexArea<Key>) {
self.cast.notify(area);
}
}

View File

@ -1,145 +0,0 @@
pub use {
crate::{
core::{
InnerViewPort, Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View, ViewPort,
},
grid::GridView,
index::{IndexArea, IndexView},
},
std::sync::RwLock,
std::{boxed::Box, sync::Arc},
};
impl<SrcKey, Item> OuterViewPort<dyn IndexView<SrcKey, Item = Item>>
where
SrcKey: Clone + Send + Sync + 'static,
Item: 'static,
{
pub fn map_key<
DstKey: Clone + Send + Sync + 'static,
F1: Fn(&SrcKey) -> DstKey + Send + Sync + 'static,
F2: Fn(&DstKey) -> Option<SrcKey> + Send + Sync + 'static,
>(
&self,
f1: F1,
f2: F2,
) -> OuterViewPort<dyn IndexView<DstKey, Item = Item>> {
let port = ViewPort::new();
port.add_update_hook(Arc::new(self.0.clone()));
let map = MapIndexKey::new(port.inner(), f1, f2);
self.add_observer(map.clone());
port.into_outer()
}
}
impl<Item> OuterViewPort<dyn IndexView<usize, Item = Item>>
where
Item: 'static,
{
pub fn to_grid_horizontal(&self) -> OuterViewPort<dyn GridView<Item = Item>> {
self.map_key(
|idx| cgmath::Point2::new(*idx as i16, 0),
|pt| if pt.y == 0 { Some(pt.x as usize) } else { None },
)
}
pub fn to_grid_vertical(&self) -> OuterViewPort<dyn GridView<Item = Item>> {
self.map_key(
|idx| cgmath::Point2::new(0, *idx as i16),
|pt| if pt.x == 0 { Some(pt.y as usize) } else { None },
)
}
}
pub struct MapIndexKey<DstKey, SrcKey, SrcView, F1, F2>
where
DstKey: Clone + Send + Sync,
SrcKey: Clone + Send + Sync,
SrcView: IndexView<SrcKey> + ?Sized,
F1: Fn(&SrcKey) -> DstKey + Send + Sync,
F2: Fn(&DstKey) -> Option<SrcKey> + Send + Sync,
{
src_view: Option<Arc<SrcView>>,
f1: F1,
f2: F2,
cast: Arc<RwLock<ObserverBroadcast<dyn IndexView<DstKey, Item = SrcView::Item>>>>,
}
impl<DstKey, SrcKey, SrcView, F1, F2> MapIndexKey<DstKey, SrcKey, SrcView, F1, F2>
where
DstKey: Clone + Send + Sync + 'static,
SrcKey: Clone + Send + Sync + 'static,
SrcView: IndexView<SrcKey> + ?Sized + 'static,
SrcView::Item: 'static,
F1: Fn(&SrcKey) -> DstKey + Send + Sync + 'static,
F2: Fn(&DstKey) -> Option<SrcKey> + Send + Sync + 'static,
{
fn new(
port: InnerViewPort<dyn IndexView<DstKey, Item = SrcView::Item>>,
f1: F1,
f2: F2,
) -> Arc<RwLock<Self>> {
let map = Arc::new(RwLock::new(MapIndexKey {
src_view: None,
f1,
f2,
cast: port.get_broadcast(),
}));
port.set_view(Some(map.clone()));
map
}
}
impl<DstKey, SrcKey, SrcView, F1, F2> View for MapIndexKey<DstKey, SrcKey, SrcView, F1, F2>
where
DstKey: Clone + Send + Sync,
SrcKey: Clone + Send + Sync,
SrcView: IndexView<SrcKey> + ?Sized,
F1: Fn(&SrcKey) -> DstKey + Send + Sync,
F2: Fn(&DstKey) -> Option<SrcKey> + Send + Sync,
{
type Msg = IndexArea<DstKey>;
}
impl<DstKey, SrcKey, SrcView, F1, F2> IndexView<DstKey>
for MapIndexKey<DstKey, SrcKey, SrcView, F1, F2>
where
DstKey: Clone + Send + Sync,
SrcKey: Clone + Send + Sync,
SrcView: IndexView<SrcKey> + ?Sized,
F1: Fn(&SrcKey) -> DstKey + Send + Sync,
F2: Fn(&DstKey) -> Option<SrcKey> + Send + Sync,
{
type Item = SrcView::Item;
fn get(&self, key: &DstKey) -> Option<Self::Item> {
self.src_view.get(&(self.f2)(key)?)
}
fn area(&self) -> IndexArea<DstKey> {
self.src_view.area().map(&self.f1)
}
}
impl<DstKey, SrcKey, SrcView, F1, F2> Observer<SrcView>
for MapIndexKey<DstKey, SrcKey, SrcView, F1, F2>
where
DstKey: Clone + Send + Sync,
SrcKey: Clone + Send + Sync,
SrcView: IndexView<SrcKey> + ?Sized,
F1: Fn(&SrcKey) -> DstKey + Send + Sync,
F2: Fn(&DstKey) -> Option<SrcKey> + Send + Sync,
{
fn reset(&mut self, view: Option<Arc<SrcView>>) {
let old_area = self.area();
self.src_view = view;
self.cast.notify(&old_area);
self.cast.notify(&self.area());
}
fn notify(&mut self, msg: &IndexArea<SrcKey>) {
self.cast.notify(&msg.map(&self.f1));
}
}

View File

@ -1,130 +0,0 @@
pub mod buffer;
pub mod map_item;
pub mod map_key;
use {
crate::core::View,
std::sync::RwLock,
std::{
ops::{Deref, RangeInclusive},
sync::Arc,
},
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[derive(Clone)]
pub enum IndexArea<Key> {
Empty,
Full,
Set(Vec<Key>),
Range(RangeInclusive<Key>),
//Procedural(Arc<dyn Fn() -> Box<dyn Iterator<Item = Key>>>)
}
impl<Key> IndexArea<Key> {
pub fn map<T>(&self, f: impl Fn(&Key) -> T) -> IndexArea<T> {
match self {
IndexArea::Empty => IndexArea::Empty,
IndexArea::Full => IndexArea::Full,
IndexArea::Set(v) => IndexArea::Set(v.iter().map(&f).collect()),
IndexArea::Range(r) => IndexArea::Range(f(&r.start())..=f(&r.end())),
}
}
}
pub trait IndexView<Key>: View<Msg = IndexArea<Key>>
where
Key: Send + Sync,
{
type Item;
fn get(&self, key: &Key) -> Option<Self::Item>;
fn area(&self) -> IndexArea<Key> {
IndexArea::Full
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<Key, V> IndexView<Key> for RwLock<V>
where
Key: Send + Sync,
V: IndexView<Key> + ?Sized,
{
type Item = V::Item;
fn get(&self, key: &Key) -> Option<Self::Item> {
self.read().unwrap().get(key)
}
fn area(&self) -> IndexArea<Key> {
self.read().unwrap().area()
}
}
impl<Key, V> IndexView<Key> for Arc<V>
where
Key: Send + Sync,
V: IndexView<Key> + ?Sized,
{
type Item = V::Item;
fn get(&self, key: &Key) -> Option<Self::Item> {
self.deref().get(key)
}
fn area(&self) -> IndexArea<Key> {
self.deref().area()
}
}
impl<Key, V> IndexView<Key> for Option<V>
where
Key: Send + Sync,
V: IndexView<Key>,
{
type Item = V::Item;
fn get(&self, key: &Key) -> Option<Self::Item> {
self.as_ref()?.get(key)
}
fn area(&self) -> IndexArea<Key> {
if let Some(v) = self.as_ref() {
v.area()
} else {
IndexArea::Empty
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
/*
pub trait ImplIndexView : Send + Sync {
type Key : Send + Sync;
type Value;
fn get(&self, key: &Self::Key) -> Option<Self::Value>;
fn area(&self) -> Option<Vec<Self::Key>> {
None
}
}
impl<V: ImplIndexView> View for V {
type Msg = V::Key;
}
impl<V: ImplIndexView> IndexView<V::Key> for V {
type Item = V::Value;
fn get(&self, key: &V::Key) -> Option<Self::Item> {
(self as &V).get(key)
}
fn area(&self) -> Option<Vec<V::Key>> {
(self as &V).area()
}
}
*/

View File

@ -1,57 +1,34 @@
#![feature(trait_alias)]
// general
pub mod core;
pub mod type_system;
pub mod projection;
pub mod commander;
pub mod utils;
// semantics
pub mod singleton;
pub mod sequence;
pub mod index;
pub mod grid;
// implementation
pub mod vec;
// editors
pub mod product;
pub mod sum;
pub mod list;
pub mod tree;
pub mod diagnostics;
// high-level types
pub mod char;
pub mod integer;
// display
pub mod terminal;
pub mod utils;
pub mod editors;
pub mod tree;
pub mod type_system;
pub mod diagnostics;
pub mod commander;
//pub mod product;
//pub mod sum;
//pub mod list;
pub fn magic_header() {
eprintln!("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>");
}
/*
pub trait StringGen {
fn get_string(&self) -> String;
}
use crate::terminal::TerminalEditor;
use crate::{tree::{TreeNav}, diagnostics::Diagnostics, terminal::TerminalView, core::{OuterViewPort}};
*/
use r3vi::view::OuterViewPort;
use crate::terminal::TerminalView;
pub trait PtySegment {
fn pty_view(&self) -> OuterViewPort<dyn TerminalView>;
}
pub trait Nested
: TerminalEditor
+ TreeNav
// + TreeType
+ Diagnostics
+ Send
+ Sync
+ std::any::Any
{}

View File

@ -1,163 +0,0 @@
use {
crate::{
core::{OuterViewPort, ViewPort},
type_system::{Context, TypeTerm},
list::{
ListCursor,
ListSegment,
ListSegmentSequence,
ListCursorMode
},
sequence::{SequenceView},
singleton::{SingletonBuffer, SingletonView},
terminal::{TerminalView},
tree::{NestedNode, TreeNav},
vec::{VecBuffer, MutableVecAccess},
PtySegment
},
std::sync::{Arc, RwLock},
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct ListEditor {
pub(super) cursor: SingletonBuffer<ListCursor>,
pub(crate) data: VecBuffer<NestedNode>,
pub(super) addr_port: OuterViewPort<dyn SequenceView<Item = isize>>,
pub(super) mode_port: OuterViewPort<dyn SingletonView<Item = ListCursorMode>>,
pub(crate) ctx: Arc<RwLock<Context>>,
pub(super) typ: TypeTerm,
pub(super) depth: usize,
pub(super) cur_dist: Arc<RwLock<usize>>,
}
impl ListEditor {
pub fn new(
ctx: Arc<RwLock<Context>>,
typ: TypeTerm,
depth: usize
) -> Self {
let mut cursor = SingletonBuffer::new(ListCursor::default());
let mut data = VecBuffer::<NestedNode>::new();
ListEditor {
mode_port: cursor
.get_port()
.map({
let data = data.clone();
move |c| {
let ip = SingletonBuffer::new(c.mode).get_port();
match c.mode {
ListCursorMode::Insert => ip,
ListCursorMode::Select => {
if let Some(idx) = c.idx {
data.get(idx as usize).get_mode_view()
} else {
ip
}
}
}
}
})
.flatten(),
addr_port: VecBuffer::<OuterViewPort<dyn SequenceView<Item = isize>>>::with_data(
vec![
cursor.get_port()
.to_sequence()
.filter_map(|cur| cur.idx),
cursor.get_port()
.map({
let data = data.clone();
move |cur| {
if cur.mode == ListCursorMode::Select {
if let Some(idx) = cur.idx {
if idx >= 0 && idx < data.len() as isize {
return data.get(idx as usize).get_addr_view();
}
}
}
OuterViewPort::default()
}
})
.to_sequence()
.flatten()
])
.get_port()
.to_sequence()
.flatten(),
cursor,
data,
ctx,
typ,
depth,
cur_dist: Arc::new(RwLock::new(0)),
}
}
pub fn get_seg_seq_view(
&self,
) -> OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>> {
let seg_seq = ListSegmentSequence::new(
self.get_cursor_port(),
self.get_data_port(),
self.depth
);
let se = seg_seq.read().unwrap();
se.get_view().map(move |segment| segment.pty_view())
}
pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = NestedNode>> {
self.data.get_port().to_sequence()
}
pub fn get_cursor_port(&self) -> OuterViewPort<dyn SingletonView<Item = ListCursor>> {
self.cursor.get_port()
}
pub fn get_item(&self) -> Option<NestedNode> {
if let Some(idx) = self.cursor.get().idx {
let idx = crate::utils::modulo(idx as isize, self.data.len() as isize) as usize;
if idx < self.data.len() {
Some(self.data.get(idx))
} else {
None
}
} else {
None
}
}
pub fn get_item_mut(&mut self) -> Option<MutableVecAccess<NestedNode>> {
if let Some(idx) = self.cursor.get().idx {
let idx = crate::utils::modulo(idx as isize, self.data.len() as isize) as usize;
if idx < self.data.len() {
Some(self.data.get_mut(idx))
} else {
None
}
} else {
None
}
}
/// split the list off at the current cursor position and return the second half
/*
pub fn split(&mut self) -> ListEditor<ItemEditor> {
let mut le = ListEditor::new(self.make_item_editor.clone());
let p = self.cursor.get();
for i in p.idx .. self.data.len() {
le.data.push( self.data[p.idx] );
self.data.remove(p.idx);
}
le.goto(TreeCursor::home());
le
}
*/
pub fn clear(&mut self) {
self.data.clear();
}
}

View File

@ -1,12 +0,0 @@
pub mod cursor;
pub mod segment;
pub mod editor;
pub mod nav;
pub mod pty_editor;
pub use cursor::{ListCursor, ListCursorMode};
pub use segment::{ListSegment, ListSegmentSequence};
pub use editor::ListEditor;
pub use pty_editor::PTYListEditor;

View File

@ -1,216 +0,0 @@
use {
crate::{
core::{OuterViewPort},
type_system::{Context, TypeTerm},
list::{
ListCursor, ListCursorMode,
ListEditor
},
sequence::{SequenceView, decorator::{SeqDecorStyle, PTYSeqDecorate}},
terminal::{
TerminalEditor, TerminalEditorResult, TerminalEvent,
TerminalView,
},
tree::{TreeCursor, TreeNav, TreeNavResult},
diagnostics::{Diagnostics},
tree::NestedNode, Nested,
commander::Commander
},
std::sync::{Arc, RwLock},
termion::event::{Event, Key},
cgmath::Vector2
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct PTYListEditor {
pub editor: Arc<RwLock<ListEditor>>,
split_char: Option<char>,
depth: usize
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl PTYListEditor {
pub fn new(
ctx: Arc<RwLock<Context>>,
typ: TypeTerm,
split_char: Option<char>,
depth: usize
) -> Self {
Self::from_editor(
ListEditor::new(ctx, typ, depth), split_char, depth)
}
pub fn from_editor(
editor: ListEditor,
split_char: Option<char>,
depth: usize
) -> Self {
PTYListEditor {
split_char,
depth,
editor: Arc::new(RwLock::new(editor)),
}
}
pub fn into_node(self, style: SeqDecorStyle) -> NestedNode {
let editor = Arc::new(RwLock::new(self));
let ed = editor.read().unwrap();
let edd = ed.editor.read().unwrap();
NestedNode::new()
.set_cmd(editor.clone())
.set_nav(ed.editor.clone())
.set_ctx(edd.ctx.clone())
.set_view(edd.get_seg_seq_view().pty_decorate(style, ed.depth))
.set_diag(
edd.get_data_port()
.enumerate()
.map(
|(idx, item_editor)| {
let idx = *idx;
item_editor
.get_msg_port()
.map(
move |msg| {
let mut msg = msg.clone();
msg.addr.insert(0, idx);
msg
}
)
}
)
.flatten()
)
}
pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = NestedNode>> {
self.editor.read().unwrap().get_data_port()
}
pub fn clear(&mut self) {
self.editor.write().unwrap().clear();
}
pub fn get_item(&self) -> Option<NestedNode> {
self.editor.read().unwrap().get_item()
}
pub fn set_depth(&mut self, depth: usize) {
self.depth = depth;
}
}
impl Commander for PTYListEditor {
type Cmd = TerminalEvent;
fn send_cmd(&mut self, event: &TerminalEvent) {
let mut e = self.editor.write().unwrap();
let mut cur = e.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 <= e.data.len() as isize {
cur.idx = Some(idx as isize - 1);
e.cursor.set(cur);
e.data.remove(idx as usize - 1);
}
}
TerminalEvent::Input(Event::Key(Key::Delete)) => {
if idx < e.data.len() as isize {
e.data.remove(idx as usize);
}
}
TerminalEvent::Input(Event::Key(Key::Char('\t')))
| TerminalEvent::Input(Event::Key(Key::Insert)) => {
e.set_leaf_mode(ListCursorMode::Select);
}
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
e.goto(TreeCursor::none());
}
_ => {
let mut new_edit = Context::make_editor(&e.ctx, e.typ.clone(), self.depth+1).unwrap();
e.data.insert(idx as usize, new_edit.clone());
e.set_leaf_mode(ListCursorMode::Select);
new_edit.goto(TreeCursor::home());
new_edit.handle_terminal_event(event);
if self.split_char.is_none() {
e.cursor.set(ListCursor {
mode: ListCursorMode::Insert,
idx: Some(idx as isize + 1),
});
}
}
},
ListCursorMode::Select => {
match event {
TerminalEvent::Input(Event::Key(Key::Char('\t')))
| TerminalEvent::Input(Event::Key(Key::Insert)) => {
e.set_leaf_mode(ListCursorMode::Insert);
}
TerminalEvent::Input(Event::Key(Key::Char(c))) => {
if Some(*c) == self.split_char {
let c = e.cursor.get();
e.goto(TreeCursor::none());
e.cursor.set(ListCursor {
mode: ListCursorMode::Insert,
idx: Some(1 + c.idx.unwrap_or(0))
});
} else {
if let Some(mut ce) = e.get_item_mut() {
ce.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char(*c))));
//match
if self.split_char.is_none() {
// TerminalEditorResult::Exit =>
{
e.cursor.set(ListCursor {
mode: ListCursorMode::Insert,
idx: Some(idx as isize + 1),
});
}
// TerminalEditorResult::Continue => {
// }
}
}
}
}
ev => {
if let Some(mut ce) = e.get_item_mut() {
ce.handle_terminal_event(ev);
/*
TerminalEvent::Input(Event::Key(Key::Backspace)) => {
e.data.remove(idx as usize);
e.cursor.set(ListCursor {
mode: ListCursorMode::Insert,
idx: Some(idx as isize),
});
}
_ => {
e.cursor.set(ListCursor {
mode: ListCursorMode::Insert,
idx: Some(idx as isize + 1),
});
}
}
}
TerminalEditorResult::Continue => {
}
}
*/
}
}
}
}
}
}
}
}

View File

@ -1,239 +0,0 @@
use {
crate::{
core::{
channel::{queue_channel, set_channel, ChannelData, ChannelReceiver, ChannelSender},
port::UpdateTask,
Observer, ObserverExt, OuterViewPort, View,
},
index::{IndexArea, IndexView},
sequence::SequenceView,
singleton::SingletonView,
},
std::sync::RwLock,
std::{
any::Any,
cmp::max,
collections::HashMap,
hash::Hash,
sync::{Arc, Weak},
},
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct ProjectionHelper<ArgKey, P>
where
ArgKey: Clone + Hash + Eq,
P: Send + Sync + 'static,
{
keepalive: HashMap<ArgKey, (usize, Arc<dyn Any + Send + Sync>)>,
proj: Arc<RwLock<Weak<RwLock<P>>>>,
update_hooks: Arc<RwLock<Vec<Arc<dyn UpdateTask>>>>,
}
impl<ArgKey, P> ProjectionHelper<ArgKey, P>
where
ArgKey: Clone + Hash + Eq,
P: Send + Sync + 'static,
{
pub fn new(update_hooks: Arc<RwLock<Vec<Arc<dyn UpdateTask>>>>) -> Self {
ProjectionHelper {
keepalive: HashMap::new(),
proj: Arc::new(RwLock::new(Weak::new())),
update_hooks,
}
}
pub fn set_proj(&mut self, proj: &Arc<RwLock<P>>) {
*self.proj.write().unwrap() = Arc::downgrade(proj);
}
// todo: make this functions generic over the View
// this does currently not work because Observer<V> is not implemented for ProjectionArg for *all* V.
pub fn new_singleton_arg<Item: 'static>(
&mut self,
arg_key: ArgKey,
port: OuterViewPort<dyn SingletonView<Item = Item>>,
notify: impl Fn(&mut P, &()) + Send + Sync + 'static,
) -> Arc<RwLock<Option<Arc<dyn SingletonView<Item = Item>>>>> {
port.add_observer(self.new_arg(arg_key, Arc::new(port.0.clone()), notify, set_channel()));
port.get_view_arc()
}
pub fn new_sequence_arg<Item: 'static>(
&mut self,
arg_key: ArgKey,
port: OuterViewPort<dyn SequenceView<Item = Item>>,
notify: impl Fn(&mut P, &usize) + Send + Sync + 'static,
) -> Arc<RwLock<Option<Arc<dyn SequenceView<Item = Item>>>>> {
port.add_observer(self.new_arg(arg_key, Arc::new(port.0.clone()), notify, set_channel()));
port.get_view_arc()
}
pub fn new_index_arg<Key: Clone + Send + Sync + 'static, Item: 'static>(
&mut self,
arg_key: ArgKey,
port: OuterViewPort<dyn IndexView<Key, Item = Item>>,
notify: impl Fn(&mut P, &IndexArea<Key>) + Send + Sync + 'static,
) -> Arc<RwLock<Option<Arc<dyn IndexView<Key, Item = Item>>>>> {
port.add_observer(self.new_arg(arg_key, Arc::new(port.0.clone()), notify, queue_channel()));
port.get_view_arc()
}
pub fn new_arg<V: View + ?Sized + 'static, D: ChannelData<Item = V::Msg> + 'static>(
&mut self,
arg_key: ArgKey,
src_update: Arc<dyn UpdateTask>,
notify: impl Fn(&mut P, &V::Msg) + Send + Sync + 'static,
(tx, rx): (ChannelSender<D>, ChannelReceiver<D>),
) -> Arc<RwLock<ProjectionArg<P, V, D>>>
where
V::Msg: Send + Sync,
D::IntoIter: Send + Sync + 'static,
{
self.remove_arg(&arg_key);
let arg = Arc::new(RwLock::new(ProjectionArg {
src: None,
notify: Box::new(notify),
proj: self.proj.clone(),
rx,
tx,
}));
let mut hooks = self.update_hooks.write().unwrap();
let idx = hooks.len();
hooks.push(src_update);
hooks.push(arg.clone());
self.keepalive.insert(arg_key, (idx, arg.clone()));
arg
}
pub fn remove_arg(&mut self, arg_key: &ArgKey) {
let mut hooks = self.update_hooks.write().unwrap();
if let Some((idx, _arg)) = self.keepalive.remove(arg_key) {
hooks.remove(idx);
hooks.remove(idx);
for (_, (j, _)) in self.keepalive.iter_mut() {
if *j > idx {
*j -= 2;
}
}
}
}
}
/// Special Observer which can access the state of the projection on notify
/// also handles the reset()
pub struct ProjectionArg<P, V, D>
where
P: Send + Sync + 'static,
V: View + ?Sized,
D: ChannelData<Item = V::Msg>,
D::IntoIter: Send + Sync,
{
src: Option<Arc<V>>,
notify: Box<dyn Fn(&mut P, &V::Msg) + Send + Sync + 'static>,
proj: Arc<RwLock<Weak<RwLock<P>>>>,
rx: ChannelReceiver<D>,
tx: ChannelSender<D>,
}
impl<P, V, D> UpdateTask for ProjectionArg<P, V, D>
where
P: Send + Sync + 'static,
V: View + ?Sized,
D: ChannelData<Item = V::Msg>,
D::IntoIter: Send + Sync,
{
fn update(&self) {
if let Some(p) = self.proj.read().unwrap().upgrade() {
if let Some(data) = self.rx.try_recv() {
for msg in data {
//eprintln!("proj update {:?}", msg);
(self.notify)(&mut *p.write().unwrap(), &msg);
}
}
} else {
//eprintln!("proj update: upgrade fail");
}
}
}
impl<P, V, D> UpdateTask for RwLock<ProjectionArg<P, V, D>>
where
P: Send + Sync + 'static,
V: View + ?Sized,
D: ChannelData<Item = V::Msg>,
D::IntoIter: Send + Sync,
{
fn update(&self) {
self.read().unwrap().update();
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<P, Item, D> Observer<dyn SingletonView<Item = Item>>
for ProjectionArg<P, dyn SingletonView<Item = Item>, D>
where
P: Send + Sync + 'static,
D: ChannelData<Item = ()>,
D::IntoIter: Send + Sync,
{
fn reset(&mut self, new_src: Option<Arc<dyn SingletonView<Item = Item>>>) {
self.src = new_src;
self.notify(&());
}
fn notify(&mut self, msg: &()) {
self.tx.send(msg.clone());
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<P, Item, D> Observer<dyn SequenceView<Item = Item>>
for ProjectionArg<P, dyn SequenceView<Item = Item>, D>
where
P: Send + Sync + 'static,
D: ChannelData<Item = usize>,
D::IntoIter: Send + Sync,
{
fn reset(&mut self, new_src: Option<Arc<dyn SequenceView<Item = Item>>>) {
let old_len = self.src.len().unwrap_or(0);
self.src = new_src;
let new_len = self.src.len().unwrap_or(0);
self.notify_each(0..max(old_len, new_len));
}
fn notify(&mut self, msg: &usize) {
self.tx.send(*msg);
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<P, Key, Item, D> Observer<dyn IndexView<Key, Item = Item>>
for ProjectionArg<P, dyn IndexView<Key, Item = Item>, D>
where
P: Send + Sync + 'static,
Key: Clone + Send + Sync,
D: ChannelData<Item = IndexArea<Key>>,
D::IntoIter: Send + Sync,
{
fn reset(&mut self, new_src: Option<Arc<dyn IndexView<Key, Item = Item>>>) {
let old_area = self.src.area();
self.src = new_src;
self.notify(&old_area);
self.notify(&self.src.area())
}
fn notify(&mut self, msg: &IndexArea<Key>) {
self.tx.send(msg.clone());
}
}

View File

@ -1,256 +0,0 @@
use {
crate::{
core::{View, OuterViewPort, Observer, ViewPort, ObserverBroadcast},
projection::ProjectionHelper,
sequence::SequenceView,
terminal::{make_label, TerminalView},
},
std::sync::Arc,
std::sync::RwLock,
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
// Wrap
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct Wrapped<T>
where T: Send + Sync + 'static
{
pub(super) opening: T,
pub(super) closing: T,
pub(super) items: Arc<dyn SequenceView<Item = T>>,
pub(super) cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = T>>>>,
pub(super) proj_helper: ProjectionHelper<(), Self>,
}
impl<T> View for Wrapped<T>
where T: Clone + Send + Sync + 'static
{
type Msg = usize;
}
impl<T> SequenceView for Wrapped<T>
where T: Clone + Send + Sync + 'static
{
type Item = T;
fn len(&self) -> Option<usize> {
Some(self.items.len()? + 2)
}
fn get(&self, idx: &usize) -> Option<Self::Item> {
let l = self.items.len().unwrap_or((-2 as i32) as usize);
if *idx < l+2 {
Some(
if *idx == 0 {
self.opening.clone()
} else if *idx < l+1 {
self.items.get(&(*idx - 1))?
} else {
self.closing.clone()
})
} else {
None
}
}
}
pub trait Wrap<T> {
fn wrap(&self, opening: T, closing: T) -> OuterViewPort<dyn SequenceView<Item = T>>;
}
impl<T> Wrap<T> for OuterViewPort<dyn SequenceView<Item = T>>
where T: Clone + Send + Sync + 'static
{
fn wrap(&self, opening: T, closing: T) -> OuterViewPort<dyn SequenceView<Item = T>> {
let port = ViewPort::new();
let mut proj_helper = ProjectionHelper::new(port.update_hooks.clone());
let w = Arc::new(RwLock::new(Wrapped {
opening,
closing,
items: proj_helper.new_sequence_arg((), self.clone(), |s: &mut Wrapped<T>, item_idx| {
s.cast.notify(&(*item_idx + 1));
s.cast.notify(&(*item_idx + 2));
}),
cast: port.get_cast(),
proj_helper,
}));
w.write().unwrap().proj_helper.set_proj(&w);
port.set_view(Some(w.clone()));
port.into_outer()
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
// Separate
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct Separated<T>
where T: Send + Sync + 'static
{
pub(super) delimiter: T,
pub(super) items: Arc<dyn SequenceView<Item = T>>,
pub(super) cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = T>>>>,
pub(super) proj_helper: ProjectionHelper<(), Self>,
}
impl<T> View for Separated<T>
where T: Clone + Send + Sync + 'static
{
type Msg = usize;
}
impl<T> SequenceView for Separated<T>
where T: Clone + Send + Sync + 'static
{
type Item = T;
fn len(&self) -> Option<usize> {
let l = self.items.len()?;
if l == 0 {
Some(0)
} else if l == 1 {
Some(1)
} else {
Some(l*2 - 1)
}
}
fn get(&self, idx: &usize) -> Option<T> {
let l = self.items.len().unwrap_or(usize::MAX);
if *idx+1 < l*2 {
if *idx % 2 == 0 {
self.items.get(&(*idx / 2))
} else {
Some(self.delimiter.clone())
}
} else {
None
}
}
}
pub trait Separate<T> {
fn separate(&self, delimiter: T) -> OuterViewPort<dyn SequenceView<Item = T>>;
}
impl<T> Separate<T> for OuterViewPort<dyn SequenceView<Item = T>>
where T: Clone + Send + Sync + 'static
{
fn separate(&self, delimiter: T) -> OuterViewPort<dyn SequenceView<Item = T>> {
let port = ViewPort::new();
let mut proj_helper = ProjectionHelper::new(port.update_hooks.clone());
let w = Arc::new(RwLock::new(Separated {
delimiter,
items: proj_helper.new_sequence_arg(
(),
self.clone(),
|s: &mut Separated<T>, item_idx| {
s.cast.notify(&(*item_idx * 2));
if *item_idx > 0 {
s.cast.notify(&(*item_idx * 2 - 1));
}
}),
cast: port.get_cast(),
proj_helper,
}));
w.write().unwrap().proj_helper.set_proj(&w);
port.set_view(Some(w.clone()));
port.into_outer()
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[derive(Clone, Copy)]
pub enum SeqDecorStyle {
Plain,
HorizontalSexpr,
VerticalSexpr,
DoubleQuote,
Tuple,
EnumSet,
Path,
Hex
}
pub trait PTYSeqDecorate {
fn pty_decorate(
&self,
style: SeqDecorStyle,
depth: usize
) -> OuterViewPort<dyn TerminalView>;
}
impl PTYSeqDecorate for OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>
{
fn pty_decorate(
&self,
style: SeqDecorStyle,
_depth: usize
) -> OuterViewPort<dyn TerminalView> {
match style {
SeqDecorStyle::Plain => self
.to_grid_horizontal()
.flatten(),
SeqDecorStyle::HorizontalSexpr => self
.separate(make_label(" "))
.wrap(make_label("("), make_label(")"))
.to_grid_horizontal()
.flatten(),
SeqDecorStyle::VerticalSexpr => self
.wrap(make_label("("), make_label(")"))
.to_grid_vertical()
.flatten(),
SeqDecorStyle::DoubleQuote => self
.wrap(make_label("\""), make_label("\""))
.to_grid_horizontal()
.flatten(),
/*
SeqDecorStyle::FlexibleSexpr => self
.line_warp(width)
.map(|v| v.decorate(make_label(""")make_label(",") ", depth).to_grid_horizontal())
.decorate(make_label("("), make_label(")"), "", depth)
.to_grid_vertical()
.flatten(),
*/
SeqDecorStyle::Tuple => self
.separate(make_label(", "))
.wrap(make_label("("), make_label(")"))
.to_grid_horizontal()
.flatten(),
SeqDecorStyle::EnumSet => self
.separate(make_label(", "))
.wrap(make_label("{"), make_label("}"))
.to_grid_horizontal()
.flatten(),
SeqDecorStyle::Path => self
.separate(make_label("/"))
.wrap(make_label("<"), make_label(">"))
.to_grid_horizontal()
.flatten(),
SeqDecorStyle::Hex => self
.wrap(make_label("0x"), make_label(""))
.to_grid_horizontal()
.flatten(),
}
}
}

View File

@ -1,86 +0,0 @@
use {
crate::{
core::{Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View, ViewPort},
sequence::SequenceView,
},
std::sync::Arc,
std::sync::RwLock,
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<Item: 'static> OuterViewPort<dyn SequenceView<Item = Item>> {
pub fn enumerate(&self) -> OuterViewPort<dyn SequenceView<Item = (usize, Item)>> {
let port = ViewPort::new();
port.add_update_hook(Arc::new(self.0.clone()));
let view = Arc::new(RwLock::new(EnumerateSequence {
src_view: None,
cast: port.inner().get_broadcast(),
}));
self.add_observer(view.clone());
port.inner().set_view(Some(view));
port.into_outer()
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct EnumerateSequence<SrcView>
where
SrcView: SequenceView + ?Sized,
{
src_view: Option<Arc<SrcView>>,
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = (usize, SrcView::Item)>>>>,
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<SrcView> View for EnumerateSequence<SrcView>
where
SrcView: SequenceView + ?Sized,
{
type Msg = usize;
}
impl<SrcView> SequenceView for EnumerateSequence<SrcView>
where
SrcView: SequenceView + ?Sized
{
type Item = (usize, SrcView::Item);
fn len(&self) -> Option<usize> {
self.src_view.len()
}
fn get(&self, idx: &usize) -> Option<(usize, SrcView::Item)> {
self.src_view.get(idx).map(|item| (*idx, item))
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<SrcView> Observer<SrcView> for EnumerateSequence<SrcView>
where
SrcView: SequenceView + ?Sized
{
fn reset(&mut self, view: Option<Arc<SrcView>>) {
let old_len = self.len();
self.src_view = view;
let new_len = self.len();
if let Some(len) = old_len {
self.cast.notify_each(0..len);
}
if let Some(len) = new_len {
self.cast.notify_each(0..len);
}
}
fn notify(&mut self, msg: &usize) {
self.cast.notify(msg);
}
}

View File

@ -1,160 +0,0 @@
use {
crate::{
core::{Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View, ViewPort},
sequence::SequenceView,
},
std::sync::Arc,
std::sync::RwLock,
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<V: SequenceView + ?Sized + 'static> OuterViewPort<V> {
pub fn filter<P: Fn(&V::Item) -> bool + Send + Sync + 'static>(
&self,
pred: P,
) -> OuterViewPort<dyn SequenceView<Item = V::Item>> {
let port = ViewPort::new();
port.add_update_hook(Arc::new(self.0.clone()));
let filter = Arc::new(RwLock::new(Filter {
src_view: None,
pred,
old_preds: RwLock::new(Vec::new()),
cast: port.inner().get_broadcast(),
}));
self.add_observer(filter.clone());
port.inner().set_view(Some(filter));
port.into_outer()
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
struct Filter<SrcView, P>
where
SrcView: SequenceView + ?Sized + 'static,
P: Fn(&SrcView::Item) -> bool + Send + Sync + 'static,
{
src_view: Option<Arc<SrcView>>,
pred: P,
old_preds: RwLock<Vec<bool>>,
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = SrcView::Item>>>>,
}
impl<SrcView, P> Filter<SrcView, P>
where
SrcView: SequenceView + ?Sized + 'static,
P: Fn(&SrcView::Item) -> bool + Send + Sync + 'static,
{
fn get_offset(&self, idx: usize) -> usize {
if let Some(v) = self.src_view.clone() {
let mut i = 0;
let mut j = 0;
let mut offset = 0;
while let (Some(x), true) = (v.get(&i), j <= idx) {
if (self.pred)(&x) {
j += 1;
} else {
offset += 1;
}
i += 1;
}
offset
} else {
0
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<SrcView, P> View for Filter<SrcView, P>
where
SrcView: SequenceView + ?Sized + 'static,
P: Fn(&SrcView::Item) -> bool + Send + Sync + 'static,
{
type Msg = usize;
}
impl<SrcView, P> SequenceView for Filter<SrcView, P>
where
SrcView: SequenceView + ?Sized + 'static,
P: Fn(&SrcView::Item) -> bool + Send + Sync + 'static,
{
type Item = SrcView::Item;
fn len(&self) -> Option<usize> {
if let Some(src_len) = self.src_view.len() {
Some(src_len - self.get_offset(src_len))
} else {
None
}
}
fn get(&self, idx: &usize) -> Option<Self::Item> {
self.src_view.get(&(idx + self.get_offset(*idx)))
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<SrcView, P> Observer<SrcView> for Filter<SrcView, P>
where
SrcView: SequenceView + ?Sized + 'static,
P: Fn(&SrcView::Item) -> bool + Send + Sync + 'static,
{
fn reset(&mut self, new_src: Option<Arc<SrcView>>) {
let old_len = self.len();
self.src_view = new_src;
self.old_preds = RwLock::new(Vec::new());
let new_len = self.len();
if let Some(len) = old_len {
self.cast.notify_each(0..len);
}
if let Some(len) = new_len {
self.cast.notify_each(0..len);
}
}
fn notify(&mut self, idx: &usize) {
let l = self.len().unwrap_or(0) + 1;
let np = if let Some(x) = self.src_view.get(idx) {
(self.pred)(&x)
} else {
false
};
let mut opds = self.old_preds.write().unwrap();
opds.resize_with(1 + *idx, || false);
let op = opds.get(*idx).cloned().unwrap_or(false);
*opds.get_mut(*idx).unwrap() = np;
drop(opds);
let i = (0..*idx)
.map(|j| {
if let Some(x) = self.src_view.get(&j) {
if (self.pred)(&x) {
1
} else {
0
}
} else {
0
}
})
.sum();
if np != op {
self.cast.notify_each(i..l);
} else {
self.cast.notify(&i);
}
}
}

View File

@ -1,183 +0,0 @@
use {
crate::{
core::{
port::UpdateTask, InnerViewPort, Observer, ObserverBroadcast, ObserverExt,
OuterViewPort, View, ViewPort,
},
projection::ProjectionHelper,
sequence::SequenceView,
},
std::sync::RwLock,
std::{collections::BTreeMap, sync::Arc},
};
impl<Item> OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = Item>>>>
where
Item: 'static,
{
pub fn flatten(&self) -> OuterViewPort<dyn SequenceView<Item = Item>> {
let port = ViewPort::new();
Flatten::new(self.clone(), port.inner());
port.into_outer()
}
}
pub struct Chunk<Item>
where
Item: 'static,
{
offset: usize,
len: usize,
view: Arc<dyn SequenceView<Item = Item>>,
}
pub struct Flatten<Item>
where
Item: 'static,
{
length: usize,
top: Arc<dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = Item>>>>,
chunks: BTreeMap<usize, Chunk<Item>>,
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = Item>>>>,
proj_helper: ProjectionHelper<usize, Self>,
}
impl<Item> View for Flatten<Item>
where
Item: 'static,
{
type Msg = usize;
}
impl<Item> SequenceView for Flatten<Item>
where
Item: 'static,
{
type Item = Item;
fn get(&self, idx: &usize) -> Option<Self::Item> {
let chunk = self.chunks.get(&self.get_chunk_idx(*idx)?)?;
chunk.view.get(&(*idx - chunk.offset))
}
fn len(&self) -> Option<usize> {
Some(self.length)
}
}
impl<Item> Flatten<Item>
where
Item: 'static,
{
pub fn new(
top_port: OuterViewPort<
dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = Item>>>,
>,
out_port: InnerViewPort<dyn SequenceView<Item = Item>>,
) -> Arc<RwLock<Self>> {
let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone());
let flat = Arc::new(RwLock::new(Flatten {
length: 0,
top: proj_helper.new_sequence_arg(usize::MAX, top_port, |s: &mut Self, chunk_idx| {
s.update_chunk(*chunk_idx);
}),
chunks: BTreeMap::new(),
cast: out_port.get_broadcast(),
proj_helper,
}));
flat.write().unwrap().proj_helper.set_proj(&flat);
out_port.set_view(Some(flat.clone()));
flat
}
/// the top-sequence has changed the item at chunk_idx,
/// create a new observer for the contained sub sequence
fn update_chunk(&mut self, chunk_idx: usize) {
if let Some(chunk_port) = self.top.get(&chunk_idx) {
self.chunks.insert(
chunk_idx,
Chunk {
offset: 0, // will be adjusted by update_offsets() later
len: 0,
view: self.proj_helper.new_sequence_arg(
chunk_idx,
chunk_port.clone(),
move |s: &mut Self, idx| {
if let Some(chunk) = s.chunks.get(&chunk_idx) {
let chunk_offset = chunk.offset;
let chunk_len = chunk.view.len().unwrap_or(0);
let mut dirty_idx = Vec::new();
if chunk.len != chunk_len {
dirty_idx = s.update_all_offsets();
}
s.cast.notify(&(idx + chunk_offset));
s.cast.notify_each(dirty_idx);
} else {
let dirty_idx = s.update_all_offsets();
s.cast.notify_each(dirty_idx);
}
},
),
},
);
chunk_port.0.update();
let dirty_idx = self.update_all_offsets();
self.cast.notify_each(dirty_idx);
} else {
// todo:
self.proj_helper.remove_arg(&chunk_idx);
self.chunks.remove(&chunk_idx);
let dirty_idx = self.update_all_offsets();
self.cast.notify_each(dirty_idx);
}
}
/// recalculate all chunk offsets beginning at start_idx
/// and update length of flattened sequence
fn update_all_offsets(&mut self) -> Vec<usize> {
let mut dirty_idx = Vec::new();
let mut cur_offset = 0;
for (_chunk_idx, chunk) in self.chunks.iter_mut() {
let old_offset = chunk.offset;
chunk.offset = cur_offset;
chunk.len = chunk.view.len().unwrap_or(0);
if old_offset != cur_offset {
dirty_idx.extend(
std::cmp::min(old_offset, cur_offset)
..std::cmp::max(old_offset, cur_offset) + chunk.len,
);
}
cur_offset += chunk.len;
}
let old_length = self.length;
self.length = cur_offset;
dirty_idx.extend(self.length..old_length);
dirty_idx
}
/// given an index in the flattened sequence,
/// which sub-sequence does it belong to?
fn get_chunk_idx(&self, glob_idx: usize) -> Option<usize> {
let mut offset = 0;
for (chunk_idx, chunk) in self.chunks.iter() {
offset += chunk.view.len().unwrap_or(0);
if glob_idx < offset {
return Some(*chunk_idx);
}
}
None
}
}

View File

@ -1,105 +0,0 @@
use {
crate::{
core::{Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View, ViewPort},
sequence::SequenceView,
},
std::sync::Arc,
std::sync::RwLock,
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<Item: 'static> OuterViewPort<dyn SequenceView<Item = Item>> {
pub fn map<DstItem: 'static, F: Fn(&Item) -> DstItem + Send + Sync + 'static>(
&self,
f: F,
) -> OuterViewPort<dyn SequenceView<Item = DstItem>> {
let port = ViewPort::new();
port.add_update_hook(Arc::new(self.0.clone()));
let map = Arc::new(RwLock::new(MapSequenceItem {
src_view: None,
f,
cast: port.inner().get_broadcast(),
}));
self.add_observer(map.clone());
port.inner().set_view(Some(map));
port.into_outer()
}
pub fn filter_map<
DstItem: Clone + 'static,
F: Fn(&Item) -> Option<DstItem> + Send + Sync + 'static,
>(
&self,
f: F,
) -> OuterViewPort<dyn SequenceView<Item = DstItem>> {
self.map(f)
.filter(|x| x.is_some())
.map(|x| x.clone().unwrap())
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct MapSequenceItem<DstItem, SrcView, F>
where
SrcView: SequenceView + ?Sized,
F: Fn(&SrcView::Item) -> DstItem + Send + Sync,
{
src_view: Option<Arc<SrcView>>,
f: F,
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = DstItem>>>>,
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<DstItem, SrcView, F> View for MapSequenceItem<DstItem, SrcView, F>
where
SrcView: SequenceView + ?Sized,
F: Fn(&SrcView::Item) -> DstItem + Send + Sync,
{
type Msg = usize;
}
impl<DstItem, SrcView, F> SequenceView for MapSequenceItem<DstItem, SrcView, F>
where
SrcView: SequenceView + ?Sized,
F: Fn(&SrcView::Item) -> DstItem + Send + Sync,
{
type Item = DstItem;
fn len(&self) -> Option<usize> {
self.src_view.len()
}
fn get(&self, idx: &usize) -> Option<DstItem> {
self.src_view.get(idx).as_ref().map(|item| (self.f)(item))
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<DstItem, SrcView, F> Observer<SrcView> for MapSequenceItem<DstItem, SrcView, F>
where
SrcView: SequenceView + ?Sized,
F: Fn(&SrcView::Item) -> DstItem + Send + Sync,
{
fn reset(&mut self, view: Option<Arc<SrcView>>) {
let old_len = self.len();
self.src_view = view;
let new_len = self.len();
if let Some(len) = old_len {
self.cast.notify_each(0..len);
}
if let Some(len) = new_len {
self.cast.notify_each(0..len);
}
}
fn notify(&mut self, msg: &usize) {
self.cast.notify(msg);
}
}

View File

@ -1,97 +0,0 @@
pub mod filter;
pub mod map;
pub mod enumerate;
pub mod seq2idx;
pub mod flatten;
pub mod decorator;
pub use seq2idx::Sequence2Index;
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
use crate::core::View;
pub trait SequenceView: View<Msg = usize> {
type Item;
fn get(&self, idx: &usize) -> Option<Self::Item>;
fn len(&self) -> Option<usize>;
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub trait SequenceViewExt: SequenceView {
fn iter<'a>(&'a self) -> SequenceViewIter<'a, Self> {
SequenceViewIter { view: self, cur: 0 }
}
}
impl<V: SequenceView + ?Sized> SequenceViewExt for V {}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct SequenceViewIter<'a, V>
where
V: SequenceView + ?Sized,
{
view: &'a V,
cur: usize,
}
impl<'a, V> Iterator for SequenceViewIter<'a, V>
where
V: SequenceView + ?Sized,
{
type Item = V::Item;
fn next(&mut self) -> Option<Self::Item> {
let i = self.cur;
self.cur += 1;
self.view.get(&i)
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
use std::sync::RwLock;
use std::{ops::Deref, sync::Arc};
impl<V: SequenceView + ?Sized> SequenceView for RwLock<V> {
type Item = V::Item;
fn get(&self, idx: &usize) -> Option<Self::Item> {
self.read().unwrap().get(idx)
}
fn len(&self) -> Option<usize> {
self.read().unwrap().len()
}
}
impl<V: SequenceView + ?Sized> SequenceView for Arc<V> {
type Item = V::Item;
fn get(&self, idx: &usize) -> Option<Self::Item> {
self.deref().get(idx)
}
fn len(&self) -> Option<usize> {
self.deref().len()
}
}
impl<V: SequenceView> SequenceView for Option<V> {
type Item = V::Item;
fn get(&self, idx: &usize) -> Option<Self::Item> {
(self.as_ref()? as &V).get(idx)
}
fn len(&self) -> Option<usize> {
if let Some(v) = self.as_ref() {
v.len()
} else {
Some(0)
}
}
}

View File

@ -1,99 +0,0 @@
use {
crate::{
core::{InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View, ViewPort},
grid::GridView,
index::{IndexArea, IndexView},
sequence::SequenceView,
},
std::sync::Arc,
std::sync::RwLock,
};
/// Transforms a SequenceView into IndexView<usize>
pub struct Sequence2Index<SrcView>
where
SrcView: SequenceView + ?Sized + 'static,
{
src_view: Option<Arc<SrcView>>,
cast: Arc<RwLock<ObserverBroadcast<dyn IndexView<usize, Item = SrcView::Item>>>>,
}
impl<SrcView> Sequence2Index<SrcView>
where
SrcView: SequenceView + ?Sized + 'static,
{
pub fn new(
port: InnerViewPort<dyn IndexView<usize, Item = SrcView::Item>>,
) -> Arc<RwLock<Self>> {
let s2i = Arc::new(RwLock::new(Sequence2Index {
src_view: None,
cast: port.get_broadcast(),
}));
port.set_view(Some(s2i.clone()));
s2i
}
}
impl<Item: 'static> OuterViewPort<dyn SequenceView<Item = Item>> {
pub fn to_index(&self) -> OuterViewPort<dyn IndexView<usize, Item = Item>> {
let port = ViewPort::new();
port.add_update_hook(Arc::new(self.0.clone()));
self.add_observer(Sequence2Index::new(port.inner()));
port.into_outer()
}
pub fn to_grid_horizontal(&self) -> OuterViewPort<dyn GridView<Item = Item>> {
self.to_index().to_grid_horizontal()
}
pub fn to_grid_vertical(&self) -> OuterViewPort<dyn GridView<Item = Item>> {
self.to_index().to_grid_vertical()
}
}
impl<SrcView> View for Sequence2Index<SrcView>
where
SrcView: SequenceView + ?Sized + 'static,
{
type Msg = IndexArea<usize>;
}
impl<SrcView> IndexView<usize> for Sequence2Index<SrcView>
where
SrcView: SequenceView + ?Sized + 'static,
{
type Item = SrcView::Item;
fn get(&self, key: &usize) -> Option<Self::Item> {
self.src_view.get(key)
}
fn area(&self) -> IndexArea<usize> {
if let Some(len) = self.src_view.len() {
if len > 0 {
IndexArea::Range(0..=len - 1)
} else {
IndexArea::Empty
}
} else {
IndexArea::Full
}
}
}
impl<SrcView> Observer<SrcView> for Sequence2Index<SrcView>
where
SrcView: SequenceView + ?Sized + 'static,
{
fn reset(&mut self, view: Option<Arc<SrcView>>) {
let old_area = self.area();
self.src_view = view;
self.cast.notify(&old_area);
self.cast.notify(&self.area());
}
fn notify(&mut self, idx: &usize) {
self.cast.notify(&IndexArea::Set(vec![*idx]));
}
}

View File

@ -1,124 +0,0 @@
use {
crate::{
core::{InnerViewPort, OuterViewPort, View, ViewPort},
singleton::SingletonView,
},
std::sync::RwLock,
std::{
ops::{Deref, DerefMut},
sync::Arc,
},
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct SingletonBufferView<T: Clone + Send + Sync + 'static>(Arc<RwLock<T>>);
impl<T> View for SingletonBufferView<T>
where
T: Clone + Send + Sync + 'static,
{
type Msg = ();
}
impl<T> SingletonView for SingletonBufferView<T>
where
T: Clone + Send + Sync + 'static,
{
type Item = T;
fn get(&self) -> Self::Item {
self.0.read().unwrap().clone()
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[derive(Clone)]
pub struct SingletonBuffer<T>
where
T: Clone + Send + Sync + 'static,
{
value: Arc<RwLock<T>>,
port: InnerViewPort<dyn SingletonView<Item = T>>
}
impl<T> SingletonBuffer<T>
where
T: Clone + Send + Sync + 'static,
{
pub fn with_port(value: T, port: InnerViewPort<dyn SingletonView<Item = T>>) -> Self {
let value = Arc::new(RwLock::new(value));
port.set_view(Some(Arc::new(SingletonBufferView(value.clone()))));
SingletonBuffer {
value,
port
}
}
pub fn new(value: T) -> Self {
SingletonBuffer::with_port(value, ViewPort::new().into_inner())
}
pub fn get_port(&self) -> OuterViewPort<dyn SingletonView<Item = T>> {
self.port.0.outer()
}
pub fn get(&self) -> T {
self.value.read().unwrap().clone()
}
pub fn get_mut(&self) -> MutableSingletonAccess<T> {
MutableSingletonAccess {
buf: self.clone(),
val: self.get(),
}
}
pub fn set(&mut self, new_value: T) {
let mut v = self.value.write().unwrap();
*v = new_value;
drop(v);
self.port.notify(&());
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct MutableSingletonAccess<T>
where
T: Clone + Send + Sync + 'static,
{
buf: SingletonBuffer<T>,
val: T,
}
impl<T> Deref for MutableSingletonAccess<T>
where
T: Clone + Send + Sync + 'static,
{
type Target = T;
fn deref(&self) -> &T {
&self.val
}
}
impl<T> DerefMut for MutableSingletonAccess<T>
where
T: Clone + Send + Sync + 'static,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.val
}
}
impl<T> Drop for MutableSingletonAccess<T>
where
T: Clone + Send + Sync + 'static,
{
fn drop(&mut self) {
self.buf.set(self.val.clone());
}
}

View File

@ -1,88 +0,0 @@
use {
crate::{
core::{
port::UpdateTask, InnerViewPort, Observer, ObserverBroadcast, ObserverExt,
OuterViewPort, View, ViewPort,
},
projection::ProjectionHelper,
singleton::SingletonView,
},
std::sync::RwLock,
std::{collections::BTreeMap, sync::Arc},
};
impl<Item> OuterViewPort<dyn SingletonView<Item = OuterViewPort<dyn SingletonView<Item = Item>>>>
where
Item: 'static + Default,
{
pub fn flatten(&self) -> OuterViewPort<dyn SingletonView<Item = Item>> {
let port = ViewPort::new();
Flatten::new(self.clone(), port.inner());
port.into_outer()
}
}
pub struct Flatten<Item>
where
Item: 'static + Default,
{
outer: Arc<dyn SingletonView<Item = OuterViewPort<dyn SingletonView<Item = Item>>>>,
inner: OuterViewPort<dyn SingletonView<Item = Item>>,
cast: Arc<RwLock<ObserverBroadcast<dyn SingletonView<Item = Item>>>>,
proj: ProjectionHelper<usize, Self>
}
impl<Item> View for Flatten<Item>
where
Item: 'static + Default,
{
type Msg = ();
}
impl<Item> SingletonView for Flatten<Item>
where
Item: 'static + Default,
{
type Item = Item;
fn get(&self) -> Self::Item {
if let Some(i) = self.inner.get_view() {
i.get()
} else {
Item::default()
}
}
}
impl<Item> Flatten<Item>
where
Item: 'static + Default,
{
pub fn new(
top_port: OuterViewPort<
dyn SingletonView<Item = OuterViewPort<dyn SingletonView<Item = Item>>>,
>,
out_port: InnerViewPort<dyn SingletonView<Item = Item>>,
) -> Arc<RwLock<Self>> {
let mut proj = ProjectionHelper::new(out_port.0.update_hooks.clone());
let flat = Arc::new(RwLock::new(Flatten {
outer: proj.new_singleton_arg(0, top_port, |s: &mut Self, _msg| {
s.inner = s.outer.get();
s.proj.new_singleton_arg(1, s.inner.clone(), |s: &mut Self, _msg| {
s.cast.notify(&());
});
//s.inner.0.update();
}),
inner: OuterViewPort::default(),
cast: out_port.get_broadcast(),
proj,
}));
flat.write().unwrap().proj.set_proj(&flat);
out_port.set_view(Some(flat.clone()));
flat
}
}

View File

@ -1,81 +0,0 @@
use {
crate::{
core::{Observer, ObserverBroadcast, OuterViewPort, View, ViewPort},
singleton::SingletonView,
},
std::sync::Arc,
std::sync::RwLock,
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<Item: 'static> OuterViewPort<dyn SingletonView<Item = Item>> {
pub fn map<DstItem: 'static, F: Fn(Item) -> DstItem + Send + Sync + 'static>(
&self,
f: F,
) -> OuterViewPort<dyn SingletonView<Item = DstItem>> {
let port = ViewPort::new();
port.add_update_hook(Arc::new(self.0.clone()));
let map = Arc::new(RwLock::new(MapSingleton {
src_view: None,
f,
cast: port.inner().get_broadcast(),
}));
self.add_observer(map.clone());
port.inner().set_view(Some(map));
port.into_outer()
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct MapSingleton<DstItem, SrcView, F>
where
SrcView: SingletonView + ?Sized,
F: Fn(SrcView::Item) -> DstItem + Send + Sync,
{
src_view: Option<Arc<SrcView>>,
f: F,
cast: Arc<RwLock<ObserverBroadcast<dyn SingletonView<Item = DstItem>>>>,
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<DstItem, SrcView, F> View for MapSingleton<DstItem, SrcView, F>
where
SrcView: SingletonView + ?Sized,
F: Fn(SrcView::Item) -> DstItem + Send + Sync,
{
type Msg = ();
}
impl<DstItem, SrcView, F> SingletonView for MapSingleton<DstItem, SrcView, F>
where
SrcView: SingletonView + ?Sized,
F: Fn(SrcView::Item) -> DstItem + Send + Sync,
{
type Item = DstItem;
fn get(&self) -> DstItem {
(self.f)(self.src_view.as_ref().unwrap().get())
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<DstItem, SrcView, F> Observer<SrcView> for MapSingleton<DstItem, SrcView, F>
where
SrcView: SingletonView + ?Sized,
F: Fn(SrcView::Item) -> DstItem + Send + Sync,
{
fn reset(&mut self, view: Option<Arc<SrcView>>) {
self.src_view = view;
self.cast.notify(&());
}
fn notify(&mut self, msg: &()) {
self.cast.notify(msg);
}
}

View File

@ -1,66 +0,0 @@
pub mod buffer;
pub mod map;
pub mod flatten;
pub mod to_index;
pub mod to_sequence;
use {
crate::core::View,
std::sync::RwLock,
std::{ops::Deref, sync::Arc},
};
pub use buffer::SingletonBuffer;
// TODO: #[ImplForArc, ImplForRwLock]
pub trait SingletonView: View<Msg = ()> {
type Item;
fn get(&self) -> Self::Item;
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<V: SingletonView + ?Sized> SingletonView for RwLock<V> {
type Item = V::Item;
fn get(&self) -> Self::Item {
self.read().unwrap().get()
}
}
impl<V: SingletonView + ?Sized> SingletonView for Arc<V> {
type Item = V::Item;
fn get(&self) -> Self::Item {
self.deref().get()
}
}
impl<V: SingletonView> SingletonView for Option<V>
where
V::Item: Default,
{
type Item = V::Item;
fn get(&self) -> Self::Item {
if let Some(s) = self.as_ref() {
s.get()
} else {
V::Item::default()
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
/*
impl<T> OuterViewPort<dyn SingletonView<Item = T>> {
pub fn get(&self) -> T {
self.get_view().unrwap().read().unwrap().get();
}
pub fn map<U: Send + Sync + 'static>(&self, f: impl Fn(T) -> U) -> OuterViewPort<dyn SingletonView<Item = U>> {
}
}
*/

View File

@ -1,91 +0,0 @@
use {
crate::{
core::{Observer, ObserverBroadcast, OuterViewPort, View, ViewPort},
grid::GridView,
index::{IndexArea, IndexView},
singleton::SingletonView,
},
std::sync::Arc,
std::sync::RwLock,
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<Item: 'static> OuterViewPort<dyn SingletonView<Item = Item>> {
pub fn to_index(&self) -> OuterViewPort<dyn IndexView<(), Item = Item>> {
let port = ViewPort::new();
port.add_update_hook(Arc::new(self.0.clone()));
let map = Arc::new(RwLock::new(Singleton2Index {
src_view: None,
cast: port.inner().get_broadcast(),
}));
self.add_observer(map.clone());
port.inner().set_view(Some(map));
port.into_outer()
}
pub fn to_grid(&self) -> OuterViewPort<dyn GridView<Item = Item>> {
self.to_index().map_key(
|_msg: &()| cgmath::Point2::new(0, 0),
|pt| {
if pt.x == 0 && pt.y == 0 {
Some(())
} else {
None
}
},
)
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct Singleton2Index<SrcView>
where
SrcView: SingletonView + ?Sized,
{
src_view: Option<Arc<SrcView>>,
cast: Arc<RwLock<ObserverBroadcast<dyn IndexView<(), Item = SrcView::Item>>>>,
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<SrcView> View for Singleton2Index<SrcView>
where
SrcView: SingletonView + ?Sized,
{
type Msg = IndexArea<()>;
}
impl<SrcView> IndexView<()> for Singleton2Index<SrcView>
where
SrcView: SingletonView + ?Sized,
{
type Item = SrcView::Item;
fn area(&self) -> IndexArea<()> {
IndexArea::Set(vec![ () ])
}
fn get(&self, _msg: &()) -> Option<Self::Item> {
Some(self.src_view.as_ref().unwrap().get())
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<SrcView> Observer<SrcView> for Singleton2Index<SrcView>
where
SrcView: SingletonView + ?Sized,
{
fn reset(&mut self, view: Option<Arc<SrcView>>) {
self.src_view = view;
self.cast.notify(&IndexArea::Set(vec![ () ]));
}
fn notify(&mut self, _: &()) {
self.cast.notify(&IndexArea::Set(vec![ () ]));
}
}

View File

@ -1,81 +0,0 @@
use {
crate::{
core::{Observer, ObserverBroadcast, OuterViewPort, View, ViewPort},
sequence::{SequenceView},
singleton::SingletonView,
},
std::sync::Arc,
std::sync::RwLock,
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<Item: 'static> OuterViewPort<dyn SingletonView<Item = Item>> {
pub fn to_sequence(&self) -> OuterViewPort<dyn SequenceView<Item = Item>> {
let port = ViewPort::new();
port.add_update_hook(Arc::new(self.0.clone()));
let map = Arc::new(RwLock::new(Singleton2Sequence {
src_view: None,
cast: port.inner().get_broadcast(),
}));
self.add_observer(map.clone());
port.inner().set_view(Some(map));
port.into_outer()
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct Singleton2Sequence<SrcView>
where
SrcView: SingletonView + ?Sized,
{
src_view: Option<Arc<SrcView>>,
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = SrcView::Item>>>>,
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<SrcView> View for Singleton2Sequence<SrcView>
where
SrcView: SingletonView + ?Sized,
{
type Msg = usize;
}
impl<SrcView> SequenceView for Singleton2Sequence<SrcView>
where
SrcView: SingletonView + ?Sized,
{
type Item = SrcView::Item;
fn get(&self, idx: &usize) -> Option<Self::Item> {
if *idx == 0 {
Some(self.src_view.as_ref()?.get())
} else {
None
}
}
fn len(&self) -> Option<usize> {
Some(if self.src_view.is_some() { 1 } else { 0 })
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<SrcView> Observer<SrcView> for Singleton2Sequence<SrcView>
where
SrcView: SingletonView + ?Sized,
{
fn reset(&mut self, view: Option<Arc<SrcView>>) {
self.src_view = view;
self.cast.notify(&0);
}
fn notify(&mut self, _: &()) {
self.cast.notify(&0);
}
}

View File

@ -1,10 +1,15 @@
use {
//async_std::{io::{Read, ReadExt}},
r3vi::{
view::{
InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View, ViewPort,
index::*,
singleton::*,
},
buffer::{singleton::*, index_hashmap::*},
projection::projection_helper::ProjectionHelper,
},
crate::{
core::{InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View, ViewPort},
index::{buffer::IndexBuffer, IndexArea, IndexView},
projection::ProjectionHelper,
singleton::{SingletonBuffer, SingletonView},
terminal::{TerminalAtom, TerminalStyle, TerminalView},
},
cgmath::{Point2, Vector2},

View File

@ -1,10 +1,12 @@
use {
crate::{
core::{InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View},
index::{IndexArea, IndexView},
projection::ProjectionHelper,
terminal::{TerminalAtom, TerminalView},
r3vi::{
view::{
InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View,
index::*,
},
projection::projection_helper::*,
},
crate::{terminal::{TerminalAtom, TerminalView}},
cgmath::Point2,
std::sync::Arc,
std::sync::RwLock,

View File

@ -11,7 +11,7 @@ pub use {
terminal::{Terminal, TerminalEvent},
};
use crate::grid::GridView;
use r3vi::view::grid::*;
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
@ -32,9 +32,9 @@ pub trait TerminalEditor {
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
use {
crate::{
core::{OuterViewPort, ViewPort},
vec::VecBuffer,
r3vi::{
view::{OuterViewPort},
buffer::vec::*,
},
cgmath::Point2,
};
@ -54,19 +54,25 @@ pub fn make_label(s: &str) -> OuterViewPort<dyn TerminalView> {
v
}
impl OuterViewPort<dyn TerminalView> {
pub fn with_style(&self, style: TerminalStyle) -> OuterViewPort<dyn TerminalView> {
pub trait TerminalProjections {
fn with_style(&self, style: TerminalStyle) -> OuterViewPort<dyn TerminalView>;
fn with_fg_color(&self, col: (u8, u8, u8)) -> OuterViewPort<dyn TerminalView>;
fn with_bg_color(&self, col: (u8, u8, u8)) -> OuterViewPort<dyn TerminalView>;
}
impl TerminalProjections for OuterViewPort<dyn TerminalView> {
fn with_style(&self, style: TerminalStyle) -> OuterViewPort<dyn TerminalView> {
self.map_item(
move |_idx, a|
a.add_style_front(style)
)
}
pub fn with_fg_color(&self, col: (u8, u8, u8)) -> OuterViewPort<dyn TerminalView> {
fn with_fg_color(&self, col: (u8, u8, u8)) -> OuterViewPort<dyn TerminalView> {
self.with_style(TerminalStyle::fg_color(col))
}
pub fn with_bg_color(&self, col: (u8, u8, u8)) -> OuterViewPort<dyn TerminalView> {
fn with_bg_color(&self, col: (u8, u8, u8)) -> OuterViewPort<dyn TerminalView> {
self.with_style(TerminalStyle::bg_color(col))
}
}

View File

@ -1,13 +1,13 @@
use {
super::{TerminalStyle, TerminalView},
crate::{
core::{
r3vi::{
view::{
channel::{queue_channel, set_channel, ChannelReceiver, ChannelSender},
Observer, OuterViewPort,
},
grid::GridWindowIterator,
index::IndexArea,
grid::*,
index::*,
}
},
super::{TerminalStyle, TerminalView},
async_std::{stream::StreamExt, task},
cgmath::{Point2, Vector2},
signal_hook,

View File

@ -1,5 +1,5 @@
use {
crate::list::ListCursorMode
crate::editors::list::ListCursorMode
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>

View File

@ -1,15 +1,24 @@
use {
crate::list::ListCursorMode,
crate::tree::TreeCursor,
crate::vec::VecBuffer,
crate::core::{OuterViewPort},
crate::sequence::{SequenceView, decorator::Separate},
crate::singleton::{SingletonBuffer, SingletonView},
cgmath::Vector2,
r3vi::{
view::{
OuterViewPort,
singleton::*,
sequence::*,
},
buffer::{
singleton::SingletonBuffer,
vec::VecBuffer
},
projection::{
decorate_sequence::*,
}
},
crate::{
terminal::{TerminalView, TerminalStyle, make_label}
}
editors::list::ListCursorMode,
tree::TreeCursor,
terminal::{TerminalView, TerminalProjections, make_label}
},
cgmath::Vector2,
};
#[derive(Clone, Copy, Eq, PartialEq)]
@ -76,6 +85,21 @@ pub trait TreeNav {
self.goto(c)
}
fn get_leaf_mode(&mut self) -> ListCursorMode {
self.get_cursor().leaf_mode
}
fn toggle_leaf_mode(&mut self) -> TreeNavResult {
let old_mode = self.get_leaf_mode();
self.set_leaf_mode(
match old_mode {
ListCursorMode::Insert => ListCursorMode::Select,
ListCursorMode::Select => ListCursorMode::Insert
}
);
TreeNavResult::Continue
}
fn up(&mut self) -> TreeNavResult {
self.goby(Vector2::new(0, -1))
}

View File

@ -1,40 +1,58 @@
use {
std::sync::{Arc, RwLock},
std::{sync::{Arc, RwLock}, any::Any},
cgmath::Vector2,
r3vi::{
view::{
ViewPort, OuterViewPort, AnyOuterViewPort,
singleton::*,
sequence::*
},
buffer::{singleton::*}
},
crate::{
core::{ViewPort, OuterViewPort, AnyOuterViewPort},
type_system::{ReprTree, Context},
singleton::{SingletonBuffer, SingletonView},
sequence::SequenceView,
terminal::{TerminalView, TerminalEvent, TerminalEditor, TerminalEditorResult},
diagnostics::{Diagnostics, Message},
tree::{TreeNav, TreeCursor, TreeNavResult},
list::{ListCursorMode},
editors::list::{ListCursorMode},
commander::ObjCommander,
vec::VecBuffer,
Nested
}
};
#[derive(Clone)]
pub struct NestedNode {
/// context
pub ctx: Option<Arc<RwLock<Context>>>,
// pub abs: Option<Arc<RwLock<ReprTree>>>,
/// abstract editor
pub editor: Option<Arc<dyn Any + Send + Sync>>,
/// abstract data view
pub data: Option<Arc<RwLock<ReprTree>>>,
/// display view
pub view: Option<OuterViewPort<dyn TerminalView>>,
/// diagnostics
pub diag: Option<OuterViewPort<dyn SequenceView<Item = Message>>>,
/// commander
pub cmd: Option<Arc<RwLock<dyn ObjCommander + Send + Sync>>>,
/// tree navigation
pub tree_nav: Option<Arc<RwLock<dyn TreeNav + Send + Sync>>>,
}
impl ObjCommander for NestedNode {
fn send_cmd_obj(&mut self, cmd_obj: Arc<RwLock<ReprTree>>) {
if let Some(cmd) = self.cmd.as_ref() {
// todo: filter out tree-nav cmds and send them to tree_nav
cmd.write().unwrap().send_cmd_obj(cmd_obj);
}
}
}
// todo: remove that at some point
impl TerminalEditor for NestedNode {
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
self.get_view()
@ -109,13 +127,18 @@ impl TreeNav for NestedNode {
}
}
impl Diagnostics for NestedNode {}
impl Nested for NestedNode {}
impl Diagnostics for NestedNode {
fn get_msg_port(&self) -> OuterViewPort<dyn SequenceView<Item = Message>> {
self.get_diag()
}
}
impl NestedNode {
pub fn new() -> Self {
NestedNode {
ctx: None,
data: None,
editor: None,
view: None,
diag: None,
cmd: None,
@ -128,6 +151,16 @@ impl NestedNode {
self
}
pub fn set_data(mut self, data: Arc<RwLock<ReprTree>>) -> Self {
self.data = Some(data);
self
}
pub fn set_editor(mut self, editor: Arc<dyn Any + Send + Sync>) -> Self {
self.editor = Some(editor);
self
}
pub fn set_view(mut self, view: OuterViewPort<dyn TerminalView>) -> Self {
self.view = Some(view);
self

View File

@ -1,6 +1,5 @@
use {
crate::{
core::{AnyOuterViewPort, OuterViewPort, View},
type_system::{TypeDict, TypeTerm, TypeID, ReprTree},
tree::NestedNode
},
@ -50,6 +49,9 @@ pub struct Context {
/// objects
objects: HashMap<String, Arc<RwLock<ReprTree>>>,
/// types that can be edited as lists
list_types: Vec<TypeID>,
/// editors
editor_ctors: HashMap<TypeID, Arc<dyn Fn(Arc<RwLock<Self>>, TypeTerm, usize) -> Option<NestedNode> + Send + Sync>>,
@ -72,6 +74,10 @@ impl Context {
default_constructors: HashMap::new(),
morphism_constructors: HashMap::new(),
objects: HashMap::new(),
list_types: match parent.as_ref() {
Some(p) => p.read().unwrap().list_types.clone(),
None => Vec::new()
},
parent,
}
}
@ -80,8 +86,22 @@ impl Context {
Context::with_parent(None)
}
pub fn add_typename(&mut self, tn: String) {
self.type_dict.write().unwrap().add_typename(tn);
pub fn add_typename(&mut self, tn: String) -> TypeID {
self.type_dict.write().unwrap().add_typename(tn)
}
pub fn add_list_typename(&mut self, tn: String) {
let tid = self.add_typename(tn);
self.list_types.push( tid );
}
pub fn is_list_type(&self, t: &TypeTerm) -> bool {
match t {
TypeTerm::Type { id, args: _ } => {
self.list_types.contains(id)
}
_ => false
}
}
pub fn get_typeid(&self, tn: &str) -> Option<TypeID> {
@ -98,9 +118,12 @@ impl Context {
pub fn add_editor_ctor(&mut self, tn: &str, mk_editor: Arc<dyn Fn(Arc<RwLock<Self>>, TypeTerm, usize) -> Option<NestedNode> + Send + Sync>) {
let mut dict = self.type_dict.write().unwrap();
let tyid = dict
.get_typeid(&tn.into())
.unwrap_or( dict.add_typename(tn.into()) );
let tyid =
if let Some(tyid) = dict.get_typeid(&tn.into()) {
tyid
} else {
dict.add_typename(tn.into())
};
self.editor_ctors.insert(tyid, mk_editor);
}
@ -122,7 +145,20 @@ impl Context {
let mk_editor = ctx.read().unwrap().get_editor_ctor(&type_term)?;
mk_editor(ctx.clone(), type_term, depth)
}
/*
pub fn enrich_editor(
node: NestedNode,
typ: TypeTerm
) -> NestedNode {
// create view
// create commander
}
*/
pub fn add_morphism(
&mut self,
morph_type: MorphismType,

View File

@ -1,15 +1,20 @@
use {
crate::{
type_system::{TypeTerm, Context},
integer::{DigitEditor, PosIntEditor},
list::{PTYListEditor},
sequence::{decorator::{SeqDecorStyle}},
sum::SumEditor,
char::CharEditor,
type_system::{Context, TypeTerm, ReprTree},
editors::{
char::*,
list::*,
integer::*,
product::*,
sum::*
},
tree::{NestedNode},
terminal::{TerminalEditor},
diagnostics::{Diagnostics},
type_system::TypeTermEditor,
Nested
},
std::sync::{Arc, RwLock},
cgmath::Point2
};
pub fn init_mem_ctx(parent: Arc<RwLock<Context>>) -> Arc<RwLock<Context>> {
@ -30,7 +35,9 @@ pub fn init_editor_ctx(parent: Arc<RwLock<Context>>) -> Arc<RwLock<Context>> {
}
)
);
ctx.write().unwrap().add_list_typename("Sequence".into());
ctx.write().unwrap().add_list_typename("List".into());
ctx.write().unwrap().add_editor_ctor(
"List", Arc::new(
|ctx: Arc<RwLock<Context>>, ty: TypeTerm, depth: usize| {
@ -39,44 +46,13 @@ pub fn init_editor_ctx(parent: Arc<RwLock<Context>>) -> Arc<RwLock<Context>> {
id: _, args
} => {
if args.len() > 0 {
// todo: factor style out of type arGS
let style = if args.len() > 1 {
match args[1] {
TypeTerm::Num(0) => SeqDecorStyle::Plain,
TypeTerm::Num(1) => SeqDecorStyle::HorizontalSexpr,
TypeTerm::Num(2) => SeqDecorStyle::VerticalSexpr,
TypeTerm::Num(3) => SeqDecorStyle::DoubleQuote,
TypeTerm::Num(4) => SeqDecorStyle::Tuple,
TypeTerm::Num(5) => SeqDecorStyle::EnumSet,
TypeTerm::Num(6) => SeqDecorStyle::Path,
_ => SeqDecorStyle::HorizontalSexpr
}
} else {
SeqDecorStyle::HorizontalSexpr
};
let delim = if args.len() > 1 {
match args[1] {
TypeTerm::Num(0) => None,
TypeTerm::Num(1) => Some(' '),
TypeTerm::Num(2) => Some('\n'),
TypeTerm::Num(3) => None,
TypeTerm::Num(4) => Some(','),
TypeTerm::Num(5) => Some(','),
TypeTerm::Num(6) => Some('/'),
_ => None
}
}else {
None
};
Some(
PTYListEditor::new(
ctx.clone(),
ctx,
args[0].clone(),
delim,
depth
).into_node(style)
ListStyle::HorizontalSexpr,
depth + 1
).into_node()
)
} else {
None
@ -88,30 +64,49 @@ pub fn init_editor_ctx(parent: Arc<RwLock<Context>>) -> Arc<RwLock<Context>> {
)
);
ctx.write().unwrap().add_list_typename("Symbol".into());
ctx.write().unwrap().add_editor_ctor(
"Symbol", Arc::new(
|ctx: Arc<RwLock<Context>>, _ty: TypeTerm, depth: usize| {
Context::make_editor(
&ctx,
ctx.read().unwrap().type_term_from_str("( List Char 0 )").unwrap(),
depth
)
let mut node = PTYListEditor::new(
ctx.clone(),
ctx.read().unwrap().type_term_from_str("( Char )").unwrap(),
ListStyle::Plain,
depth + 1
).into_node();
node.data = Some(ReprTree::ascend(
&node.data.unwrap(),
ctx.read().unwrap().type_term_from_str("( Symbol )").unwrap()
));
Some(node)
}
)
);
ctx.write().unwrap().add_list_typename("String".into());
ctx.write().unwrap().add_editor_ctor(
"String", Arc::new(
|ctx: Arc<RwLock<Context>>, _ty: TypeTerm, depth: usize| {
Context::make_editor(
&ctx,
ctx.read().unwrap().type_term_from_str("( List Char 3 )").unwrap(),
depth
)
let mut node = PTYListEditor::new(
ctx.clone(),
ctx.read().unwrap().type_term_from_str("( Char )").unwrap(),
ListStyle::DoubleQuote,
depth + 1
).into_node();
node.data = Some(ReprTree::ascend(
&node.data.unwrap(),
ctx.read().unwrap().type_term_from_str("( String )").unwrap()
));
Some(node)
}
)
);
ctx.write().unwrap().add_list_typename("TypeTerm".into());
ctx.write().unwrap().add_editor_ctor(
"TypeTerm", Arc::new(
|ctx: Arc<RwLock<Context>>, _ty: TypeTerm, depth: usize| {
@ -120,7 +115,7 @@ pub fn init_editor_ctx(parent: Arc<RwLock<Context>>) -> Arc<RwLock<Context>> {
)
);
ctx.write().unwrap().add_typename("TerminalEvent".into());
ctx.write().unwrap().add_typename("TerminalEvent".into());
ctx
}
@ -128,10 +123,9 @@ pub fn init_math_ctx(parent: Arc<RwLock<Context>>) -> Arc<RwLock<Context>> {
let ctx = Arc::new(RwLock::new(Context::with_parent(Some(parent))));
ctx.write().unwrap().add_typename("MachineInt".into());
ctx.write().unwrap().add_typename("u32".into());
ctx.write().unwrap().add_typename("BigEndian".into());
//ctx.write().unwrap().add_typename("Digit".into());
ctx.write().unwrap().add_editor_ctor(
"Digit", Arc::new(
|ctx: Arc<RwLock<Context>>, ty: TypeTerm, _depth: usize| {
@ -142,8 +136,9 @@ pub fn init_math_ctx(parent: Arc<RwLock<Context>>) -> Arc<RwLock<Context>> {
if args.len() > 0 {
match args[0] {
TypeTerm::Num(radix) => {
let node = DigitEditor::new(ctx.clone(), radix as u32).into_node();
Some(
DigitEditor::new(ctx.clone(), radix as u32).into_node()
node
)
},
_ => None
@ -157,7 +152,8 @@ pub fn init_math_ctx(parent: Arc<RwLock<Context>>) -> Arc<RwLock<Context>> {
}
)
);
ctx.write().unwrap().add_list_typename("PosInt".into());
ctx.write().unwrap().add_editor_ctor(
"PosInt", Arc::new(
|ctx: Arc<RwLock<Context>>, ty: TypeTerm, _depth: usize| {
@ -184,32 +180,88 @@ pub fn init_math_ctx(parent: Arc<RwLock<Context>>) -> Arc<RwLock<Context>> {
)
);
ctx.write().unwrap().add_list_typename("RGB".into());
ctx.write().unwrap().add_editor_ctor(
"RGB", Arc::new(
|ctx: Arc<RwLock<Context>>, ty: TypeTerm, depth: usize| {
let editor = ProductEditor::new(depth, ctx.clone())
.with_t(Point2::new(0, 0), "r: ")
.with_n(Point2::new(1, 0),
vec![
ctx.read().unwrap().type_term_from_str("( PosInt 16 BigEndian )").unwrap()
])
.with_t(Point2::new(0, 1), "g: ")
.with_n(Point2::new(1, 1),
vec![
ctx.read().unwrap().type_term_from_str("( PosInt 16 BigEndian )").unwrap()
])
.with_t(Point2::new(0, 2), "b: ")
.with_n(Point2::new(1, 2),
vec![
ctx.read().unwrap().type_term_from_str("( PosInt 16 BigEndian )").unwrap()
]
);
let view = editor.get_term_view();
let diag = editor.get_msg_port();
let editor = Arc::new(RwLock::new(editor));
let node = NestedNode::new()
.set_ctx(ctx)
.set_cmd(editor.clone())
.set_nav(editor.clone())
.set_view(view)
.set_diag(diag)
;
Some(node)
}
));
ctx
}
pub fn init_os_ctx(parent: Arc<RwLock<Context>>) -> Arc<RwLock<Context>> {
let ctx = Arc::new(RwLock::new(Context::with_parent(Some(parent))));
ctx.write().unwrap().add_list_typename("PathSegment".into());
ctx.write().unwrap().add_editor_ctor(
"PathSegment", Arc::new(
|ctx: Arc<RwLock<Context>>, _ty: TypeTerm, depth: usize| {
Context::make_editor(
&ctx,
ctx.read().unwrap().type_term_from_str("( List Char 0 )").unwrap(),
depth
)
let mut node = PTYListEditor::new(
ctx.clone(),
ctx.read().unwrap().type_term_from_str("( Char )").unwrap(),
ListStyle::Plain,
depth + 1
).into_node();
node.data = Some(ReprTree::ascend(
&node.data.unwrap(),
ctx.read().unwrap().type_term_from_str("( PathSegment )").unwrap()
));
Some(node)
}
)
);
ctx.write().unwrap().add_list_typename("Path".into());
ctx.write().unwrap().add_editor_ctor(
"Path", Arc::new(
|ctx: Arc<RwLock<Context>>, _ty: TypeTerm, depth: usize| {
Context::make_editor(
&ctx,
ctx.read().unwrap().type_term_from_str("( List PathSegment 6 )").unwrap(),
depth+1
)
let mut node = PTYListEditor::new(
ctx.clone(),
ctx.read().unwrap().type_term_from_str("( PathSegment )").unwrap(),
ListStyle::Path,
depth + 1
).into_node();
node.data = Some(ReprTree::ascend(
&node.data.unwrap(),
ctx.read().unwrap().type_term_from_str("( Path )").unwrap()
));
Some(node)
}
)
);

View File

@ -1,3 +1,4 @@
pub mod type_term;
pub mod repr_tree;
pub mod context;

View File

@ -1,8 +1,7 @@
use {
r3vi::view::{AnyOuterViewPort, OuterViewPort, View},
crate::{
core::{AnyOuterViewPort, OuterViewPort, View},
type_system::{TypeDict, TypeTerm, TypeID},
tree::NestedNode
type_system::{TypeTerm}
},
std::{
collections::HashMap,
@ -28,6 +27,10 @@ impl ReprTree {
}
}
pub fn get_type(&self) -> &TypeTerm {
&self.type_tag
}
pub fn new_leaf(type_tag: TypeTerm, port: AnyOuterViewPort) -> Arc<RwLock<Self>> {
let mut tree = ReprTree::new(type_tag);
tree.insert_leaf(vec![].into_iter(), port);

View File

@ -1,15 +1,21 @@
use {
r3vi::{
view::{
OuterViewPort,
sequence::*
}
},
crate::{
core::{OuterViewPort},
type_system::{Context},
terminal::{TerminalEvent, TerminalView, TerminalEditor, TerminalEditorResult},
sequence::{SequenceView, decorator::SeqDecorStyle},
list::{PTYListEditor},
editors::{
list::*,
sum::*,
char::CharEditor,
integer::PosIntEditor,
},
tree::{TreeNav, TreeCursor, TreeNavResult},
diagnostics::{Diagnostics, Message},
sum::SumEditor,
char::CharEditor,
integer::PosIntEditor,
tree::NestedNode,
commander::Commander,
PtySegment
@ -42,7 +48,7 @@ impl TypeTermEditor {
ty: TypeTermVar::Any,
sum_edit: Arc::new(RwLock::new(SumEditor::new(
vec![
Context::make_editor( &ctx, ctx.read().unwrap().type_term_from_str("( List TypeTerm 1 )").unwrap(), depth + 1).unwrap(),
Context::make_editor( &ctx, ctx.read().unwrap().type_term_from_str("( List TypeTerm )").unwrap(), depth + 1).unwrap(),
Context::make_editor( &ctx, ctx.read().unwrap().type_term_from_str("( PosInt 10 )").unwrap(), depth + 1 ).unwrap(),
Context::make_editor( &ctx, ctx.read().unwrap().type_term_from_str("( Symbol )").unwrap(), depth + 1 ).unwrap()
])))
@ -50,19 +56,22 @@ impl TypeTermEditor {
}
pub fn into_node(self) -> NestedNode {
let ctx = self.ctx.clone();
let sum_edit = self.sum_edit.clone();
let view = sum_edit.read().unwrap().pty_view();
let editor = Arc::new(RwLock::new(self));
NestedNode::new()
.set_ctx(self.ctx.clone())
.set_nav(self.sum_edit.clone())
.set_cmd(self.sum_edit.clone())
.set_view(
self.sum_edit.read().unwrap().pty_view()
)
.set_ctx(ctx)
.set_nav(sum_edit)
.set_cmd(editor.clone())
.set_view(view)
}
}
impl Commander for TypeTermEditor {
type Cmd = TerminalEvent;
fn send_cmd(&mut self, event: &TerminalEvent) {
match event {
TerminalEvent::Input( termion::event::Event::Key(Key::Char(c)) ) => {
@ -89,8 +98,9 @@ impl Commander for TypeTermEditor {
};
},
_ => {
/*
if *c == '(' {
let _child = Arc::new(RwLock::new(TypeTermEditor {
let child = TypeTermEditor {
ctx: self.ctx.clone(),
ty: self.ty.clone(),
sum_edit: Arc::new(RwLock::new(SumEditor::new(
@ -99,17 +109,18 @@ impl Commander for TypeTermEditor {
self.sum_edit.read().unwrap().editors[1].clone(),
self.sum_edit.read().unwrap().editors[2].clone(),
])))
}));
};
self.ty = TypeTermVar::List;
self.sum_edit.write().unwrap().select(0);
/*
let l = self.node.editors[0].clone();
let l = l.downcast::<RwLock<PTYListEditor<TypeTermEditor>>>().unwrap();
l.write().unwrap().data.push(child);
*/
} else {
self.sum_edit.write().unwrap().send_cmd( event );
}
let l = self.sum_edit.read().unwrap().editors[0].clone();
let l = l.editor.clone().unwrap().downcast::<RwLock<ListEditor>>().unwrap();
l.write().unwrap().insert(TypeTermEditor::new(self.ctx.clone(), 1).into_node());
} else {
*/
self.sum_edit.write().unwrap().send_cmd( event );
//}
}
}
},

View File

@ -1,166 +0,0 @@
use {
crate::{
core::{InnerViewPort, OuterViewPort, View, ViewPort},
vec::VecDiff,
},
std::sync::RwLock,
std::{
ops::{Deref, DerefMut},
sync::Arc,
},
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<T> View for Vec<T>
where
T: Clone + Send + Sync + 'static,
{
type Msg = VecDiff<T>;
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[derive(Clone)]
pub struct VecBuffer<T>
where
T: Clone + Send + Sync + 'static,
{
data: Arc<RwLock<Vec<T>>>,
port: InnerViewPort<RwLock<Vec<T>>>
}
impl<T> VecBuffer<T>
where
T: Clone + Send + Sync + 'static,
{
pub fn with_data_port(data: Vec<T>, port: InnerViewPort<RwLock<Vec<T>>>) -> Self {
let data = Arc::new(RwLock::new(data));
port.set_view(Some(data.clone()));
for x in data.read().unwrap().iter().cloned() {
port.notify(&VecDiff::Push(x));
}
VecBuffer {
data,
port
}
}
pub fn with_data(data: Vec<T>) -> Self {
VecBuffer::with_data_port(data, ViewPort::new().into_inner())
}
pub fn with_port(port: InnerViewPort<RwLock<Vec<T>>>) -> Self {
VecBuffer::with_data_port(vec![], port)
}
pub fn new() -> Self {
VecBuffer::with_port(ViewPort::new().into_inner())
}
pub fn get_port(&self) -> OuterViewPort<RwLock<Vec<T>>> {
self.port.0.outer()
}
pub fn apply_diff(&mut self, diff: VecDiff<T>) {
let mut data = self.data.write().unwrap();
match &diff {
VecDiff::Clear => {
data.clear();
}
VecDiff::Push(val) => {
data.push(val.clone());
}
VecDiff::Remove(idx) => {
data.remove(*idx);
}
VecDiff::Insert { idx, val } => {
data.insert(*idx, val.clone());
}
VecDiff::Update { idx, val } => {
data[*idx] = val.clone();
}
}
drop(data);
self.port.notify(&diff);
}
pub fn len(&self) -> usize {
self.data.read().unwrap().len()
}
pub fn get(&self, idx: usize) -> T {
self.data.read().unwrap()[idx].clone()
}
pub fn clear(&mut self) {
self.apply_diff(VecDiff::Clear);
}
pub fn push(&mut self, val: T) {
self.apply_diff(VecDiff::Push(val));
}
pub fn remove(&mut self, idx: usize) {
self.apply_diff(VecDiff::Remove(idx));
}
pub fn insert(&mut self, idx: usize, val: T) {
self.apply_diff(VecDiff::Insert { idx, val });
}
pub fn update(&mut self, idx: usize, val: T) {
self.apply_diff(VecDiff::Update { idx, val });
}
pub fn get_mut(&mut self, idx: usize) -> MutableVecAccess<T> {
MutableVecAccess {
buf: self.clone(),
idx,
val: self.get(idx),
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct MutableVecAccess<T>
where
T: Clone + Send + Sync + 'static,
{
buf: VecBuffer<T>,
idx: usize,
val: T,
}
impl<T> Deref for MutableVecAccess<T>
where
T: Clone + Send + Sync + 'static,
{
type Target = T;
fn deref(&self) -> &T {
&self.val
}
}
impl<T> DerefMut for MutableVecAccess<T>
where
T: Clone + Send + Sync + 'static,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.val
}
}
impl<T> Drop for MutableVecAccess<T>
where
T: Clone + Send + Sync + 'static,
{
fn drop(&mut self) {
self.buf.update(self.idx, self.val.clone());
}
}

View File

@ -1,19 +0,0 @@
pub mod buffer;
pub mod vec2bin;
pub mod vec2json;
pub mod vec2seq;
pub use buffer::{VecBuffer, MutableVecAccess};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
use serde::{Deserialize, Serialize};
#[derive(Clone, Serialize, Deserialize)]
pub enum VecDiff<T> {
Clear,
Push(T),
Remove(usize),
Insert { idx: usize, val: T },
Update { idx: usize, val: T },
}

View File

@ -1,81 +0,0 @@
use {
crate::{
core::{Observer, OuterViewPort},
vec::VecDiff,
},
serde::Serialize,
std::sync::RwLock,
std::{io::Write, sync::Arc},
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
/// Serialization Observer for `Vec`
pub struct VecBinWriter<T, W>
where
T: Clone + Send + Sync + 'static,
W: Write + Send + Sync,
{
data: Option<Arc<RwLock<Vec<T>>>>,
out: RwLock<W>,
}
impl<T> OuterViewPort<RwLock<Vec<T>>>
where
T: Clone + Serialize + Send + Sync + 'static,
{
pub fn serialize_bin<W: Write + Send + Sync + 'static>(
&self,
out: W,
) -> Arc<RwLock<VecBinWriter<T, W>>> {
let writer = Arc::new(RwLock::new(VecBinWriter {
data: None,
out: RwLock::new(out),
}));
self.add_observer(writer.clone());
writer
}
}
impl<T, W> Observer<RwLock<Vec<T>>> for VecBinWriter<T, W>
where
T: Clone + Serialize + Send + Sync + 'static,
W: Write + Send + Sync,
{
fn reset(&mut self, view: Option<Arc<RwLock<Vec<T>>>>) {
self.data = view;
let mut out = self.out.write().unwrap();
out.write(
&bincode::serialized_size(&VecDiff::<T>::Clear)
.unwrap()
.to_le_bytes(),
)
.expect("");
out.write(&bincode::serialize(&VecDiff::<T>::Clear).unwrap())
.expect("");
if let Some(data) = self.data.as_ref() {
for x in data.read().unwrap().iter() {
out.write(
&bincode::serialized_size(&VecDiff::Push(x))
.unwrap()
.to_le_bytes(),
)
.expect("");
out.write(&bincode::serialize(&VecDiff::Push(x)).unwrap())
.expect("");
}
}
out.flush().expect("");
}
fn notify(&mut self, diff: &VecDiff<T>) {
let mut out = self.out.write().unwrap();
out.write(&bincode::serialized_size(diff).unwrap().to_le_bytes())
.expect("");
out.write(&bincode::serialize(diff).unwrap()).expect("");
out.flush().expect("");
}
}

View File

@ -1,110 +0,0 @@
use {
crate::{
core::{Observer, OuterViewPort},
vec::{VecBuffer, VecDiff},
},
async_std::{
io::{Read, ReadExt},
stream::StreamExt,
},
serde::{de::DeserializeOwned, Serialize},
std::sync::RwLock,
std::{io::Write, sync::Arc},
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct VecJsonWriter<T, W>
where
T: Clone + Send + Sync + 'static,
W: Write + Send + Sync,
{
data: Option<Arc<RwLock<Vec<T>>>>,
out: RwLock<W>,
}
impl<T> OuterViewPort<RwLock<Vec<T>>>
where
T: Clone + Serialize + Send + Sync + 'static,
{
pub fn serialize_json<W: Write + Send + Sync + 'static>(
&self,
out: W,
) -> Arc<RwLock<VecJsonWriter<T, W>>> {
let writer = Arc::new(RwLock::new(VecJsonWriter {
data: None,
out: RwLock::new(out),
}));
self.add_observer(writer.clone());
writer
}
}
impl<T, W> Observer<RwLock<Vec<T>>> for VecJsonWriter<T, W>
where
T: Clone + Serialize + Send + Sync + 'static,
W: Write + Send + Sync,
{
fn reset(&mut self, view: Option<Arc<RwLock<Vec<T>>>>) {
self.data = view;
self.out
.write()
.unwrap()
.write(
&serde_json::to_string(&VecDiff::<T>::Clear)
.unwrap()
.as_bytes(),
)
.expect("");
self.out.write().unwrap().write(b"\n").expect("");
if let Some(data) = self.data.as_ref() {
for x in data.read().unwrap().iter() {
self.out
.write()
.unwrap()
.write(&serde_json::to_string(&VecDiff::Push(x)).unwrap().as_bytes())
.expect("");
self.out.write().unwrap().write(b"\n").expect("");
}
}
self.out.write().unwrap().flush().expect("");
}
fn notify(&mut self, diff: &VecDiff<T>) {
self.out
.write()
.unwrap()
.write(serde_json::to_string(diff).unwrap().as_bytes())
.expect("");
self.out.write().unwrap().write(b"\n").expect("");
self.out.write().unwrap().flush().expect("");
}
}
impl<T> VecBuffer<T>
where
T: DeserializeOwned + Clone + Send + Sync + 'static,
{
pub async fn from_json<R: Read + async_std::io::Read + Unpin>(&mut self, read: R) {
let mut bytes = read.bytes();
let mut s = String::new();
while let Some(Ok(b)) = bytes.next().await {
match b {
b'\n' => {
if s.len() > 0 {
let diff =
serde_json::from_str::<VecDiff<T>>(&s).expect("error parsing json");
self.apply_diff(diff);
s.clear();
}
}
c => {
s.push(c as char);
}
}
}
}
}

View File

@ -1,118 +0,0 @@
use {
crate::{
core::{
InnerViewPort, Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View, ViewPort,
},
sequence::SequenceView,
vec::VecDiff,
},
std::sync::Arc,
std::sync::RwLock,
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
/// Adapter View implementing `Sequence` for `Vec`
pub struct VecSequence<T>
where
T: Clone + Send + Sync + 'static,
{
cur_len: usize,
data: Option<Arc<RwLock<Vec<T>>>>,
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = T>>>>,
}
impl<T> VecSequence<T>
where
T: Clone + Send + Sync + 'static,
{
pub fn new(port: InnerViewPort<dyn SequenceView<Item = T>>) -> Arc<RwLock<Self>> {
let seq = Arc::new(RwLock::new(VecSequence {
cur_len: 0,
data: None,
cast: port.get_broadcast(),
}));
port.set_view(Some(seq.clone()));
seq
}
}
impl<T> Observer<RwLock<Vec<T>>> for VecSequence<T>
where
T: Clone + Send + Sync + 'static,
{
fn reset(&mut self, view: Option<Arc<RwLock<Vec<T>>>>) {
let old_len = self.cur_len;
self.data = view;
let new_len = if let Some(data) = self.data.as_ref() {
data.read().unwrap().len()
} else {
0
};
self.cur_len = new_len;
self.cast.notify_each(0..std::cmp::max(old_len, new_len));
}
fn notify(&mut self, diff: &VecDiff<T>) {
match diff {
VecDiff::Clear => {
self.cast.notify_each(0..self.cur_len);
self.cur_len = 0
}
VecDiff::Push(_) => {
self.cast.notify(&self.cur_len);
self.cur_len += 1;
}
VecDiff::Remove(idx) => {
self.cast.notify_each(*idx..self.cur_len);
self.cur_len -= 1;
}
VecDiff::Insert { idx, val: _ } => {
self.cur_len += 1;
self.cast.notify_each(*idx..self.cur_len);
}
VecDiff::Update { idx, val: _ } => {
self.cast.notify(&idx);
}
}
}
}
impl<T> View for VecSequence<T>
where
T: Clone + Send + Sync + 'static,
{
type Msg = usize;
}
impl<T> SequenceView for VecSequence<T>
where
T: Clone + Send + Sync + 'static,
{
type Item = T;
fn get(&self, idx: &usize) -> Option<T> {
self.data.as_ref()?.read().unwrap().get(*idx).cloned()
}
fn len(&self) -> Option<usize> {
Some(self.cur_len)
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<T> OuterViewPort<RwLock<Vec<T>>>
where
T: Clone + Send + Sync + 'static,
{
pub fn to_sequence(&self) -> OuterViewPort<dyn SequenceView<Item = T>> {
let port = ViewPort::new();
port.add_update_hook(Arc::new(self.0.clone()));
let vec_seq = VecSequence::new(port.inner());
self.add_observer(vec_seq.clone());
port.into_outer()
}
}

View File

@ -5,5 +5,5 @@
# to the user in the error, instead of "error: invalid channel name '[toolchain]'".
[toolchain]
channel = "nightly-2021-10-26"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
channel = "nightly"

View File

@ -1,19 +0,0 @@
[package]
name = "sdf_editor"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
nako = {git= "https://git.exobiont.de/senvas/nako.git"}
nako_std = {git= "https://git.exobiont.de/senvas/nako.git"}
nakorender = {git="https://git.exobiont.de/senvas/nako.git", default-features = false}
nested = { path = "../nested" }
cgmath = "*"
termion = "*"
font-kit = "*"
[dependencies.async-std]
version = "1.9.0"
features = ["unstable", "attributes"]

View File

@ -1,438 +0,0 @@
use{
std::{
sync::{Arc, RwLock, Mutex},
collections::HashMap
},
cgmath::{Point2, Vector2},
termion::event::{Event, Key},
nested::{
core::{
View,
ViewPort,
Observer,
ObserverExt,
OuterViewPort,
port::UpdateTask
},
singleton::{SingletonBuffer, SingletonView},
sequence::{SequenceView},
integer::{PosIntEditor},
terminal::{Terminal, TerminalAtom, TerminalStyle, TerminalView, TerminalCompositor, TerminalEvent, TerminalEditor},
list::{ListEditor},
tree_nav::{TreeNav}
},
nako::{
stream::{SecondaryStream2d, PrimaryStream2d},
glam::{Vec2, Vec3, UVec2, IVec2},
operations::{
planar::primitives2d::Box2d,
volumetric::{Color, Union, Round},
},
},
nakorender::{
backend::{Backend, LayerId, LayerId2d, LayerInfo},
marp::MarpBackend,
winit, camera::Camera2d
},
nako_std::{
text::Character
},
std::{fs::File, io::Read, mem::needs_drop, path::Path},
font_kit::font::Font,
};
// projects a Sequence of ints to a color tuple
struct ColorCollector {
src_view: Option<Arc<dyn SequenceView<Item = u32>>>,
color: SingletonBuffer<(u8, u8, u8)>
}
impl ColorCollector {
fn update(&mut self) {
if let Some(l) = self.src_view.as_ref() {
let r = l.get(&0).unwrap_or(0);
let g = l.get(&1).unwrap_or(0);
let b = l.get(&2).unwrap_or(0);
self.color.set((r as u8, g as u8, b as u8));
}
}
}
impl Observer<dyn SequenceView<Item = u32>> for ColorCollector {
fn reset(&mut self, new_view: Option<Arc<dyn SequenceView<Item = u32>>>) {
self.src_view = new_view;
self.update();
}
fn notify(&mut self, idx: &usize) {
self.update();
}
}
struct SdfTerm {
src_view: Option<Arc<dyn TerminalView>>,
bg_layers: HashMap<Point2<i16>, (bool, LayerId2d)>,
fg_layers: HashMap<Point2<i16>, (bool, LayerId2d)>,
font_height: u32,
//font: Mutex<Font>,
renderer: Arc<Mutex<MarpBackend>>
}
impl SdfTerm {
pub fn new(renderer: Arc<Mutex<MarpBackend>>) -> Self {
SdfTerm {
src_view: None,
bg_layers: HashMap::new(),
fg_layers: HashMap::new(),
font_height: 60,
//font: Mutex::new(Font::from_path(Path::new("/usr/share/fonts/TTF/FiraCode-Medium.ttf"),0).unwrap()),
renderer
}
}
pub fn get_order(&self) -> Vec<LayerId> {
vec![
self.bg_layers.iter(),
self.fg_layers.iter()
]
.into_iter()
.flatten()
.filter_map(
|(_pt,(active,id))|
if *active {
Some((*id).into())
} else {
None
})
.collect::<Vec<_>>()
}
pub fn update(&mut self, pt: &Point2<i16>) {
if self.bg_layers.get(pt).is_none() {
let id = self.renderer.lock().unwrap().new_layer_2d();
self.renderer.lock().unwrap().update_camera_2d(
id.into(),
Camera2d {
extent: Vec2::new(0.5, 1.0),
location: Vec2::new(0.0, 0.0),
rotation: 0.0
});
self.renderer.lock().unwrap().set_layer_info(
id.into(),
LayerInfo {
extent: UVec2::new(1 + self.font_height / 2, self.font_height),
location: IVec2::new(pt.x as i32 * self.font_height as i32 / 2, pt.y as i32 * self.font_height as i32)
});
self.bg_layers.insert(*pt, (false, id));
}
if self.fg_layers.get(pt).is_none() {
let id = self.renderer.lock().unwrap().new_layer_2d();
self.renderer.lock().unwrap().update_camera_2d(
id.into(),
Camera2d {
extent: Vec2::new(0.5, 1.0),
location: Vec2::new(0.0, 0.0),
rotation: 0.0
});
self.renderer.lock().unwrap().set_layer_info(
id.into(),
LayerInfo {
extent: UVec2::new(1 + self.font_height / 2, self.font_height),
location: IVec2::new(pt.x as i32 * self.font_height as i32 / 2, pt.y as i32 * self.font_height as i32)
});
self.fg_layers.insert(*pt, (false, id));
}
if let Some(atom) = self.src_view.get(pt) {
// background layer
if let Some((r,g,b)) = atom.style.bg_color {
let mut stream = PrimaryStream2d::new()
.push(
SecondaryStream2d::new(
Union,
Box2d {
extent: Vec2::new(0.6, 1.0)
}
).push_mod(
Color(
Vec3::new(
(r as f32 / 255.0).clamp(0.0, 1.0),
(g as f32 / 255.0).clamp(0.0, 1.0),
(b as f32 / 255.0).clamp(0.0, 1.0),
)
)
).build()
);
self.renderer.lock().unwrap().update_sdf_2d(self.bg_layers.get(pt).unwrap().1, stream.build());
self.bg_layers.get_mut(pt).unwrap().0 = true;
} else {
self.bg_layers.get_mut(pt).unwrap().0 = false;
}
// foreground layer
if let Some(c) = atom.c {
let font = Font::from_path(Path::new("/usr/share/fonts/TTF/FiraCode-Light.ttf"),0).unwrap();
let mut ch = Character::from_font(&font, c).with_size(1.0).with_tesselation_factor(0.01);
let (r,g,b) = atom.style.fg_color.unwrap_or((0, 0, 0));
ch.color = Vec3::new(
(r as f32 / 255.0).clamp(0.0, 1.0),
(g as f32 / 255.0).clamp(0.0, 1.0),
(b as f32 / 255.0).clamp(0.0, 1.0),
);
let mut stream = PrimaryStream2d::new();
stream = ch.record_character(stream);
self.renderer.lock().unwrap().update_sdf_2d(self.fg_layers.get(pt).unwrap().1, stream.build());
self.fg_layers.get_mut(pt).unwrap().0 = true;
} else {
self.fg_layers.get_mut(pt).unwrap().0 = false;
}
} else {
self.bg_layers.get_mut(pt).unwrap().0 = false;
self.fg_layers.get_mut(pt).unwrap().0 = false;
}
}
}
impl Observer<dyn TerminalView> for SdfTerm {
fn reset(&mut self, new_view: Option<Arc<dyn TerminalView>>) {
self.src_view = new_view;
for pt in self.src_view.area().unwrap_or(vec![]) {
self.notify(&pt);
}
}
fn notify(&mut self, pt: &Point2<i16>) {
self.update(pt);
}
}
#[async_std::main]
async fn main() {
let term_port = ViewPort::new();
let compositor = TerminalCompositor::new(term_port.inner());
let mut color_editor = ListEditor::new(
|| {
Arc::new(RwLock::new(PosIntEditor::new(16)))
},
nested::list::ListEditorStyle::HorizontalSexpr
);
color_editor.goto(nested::tree_nav::TreeCursor {
leaf_mode: nested::list::ListCursorMode::Insert,
tree_addr: vec![ 0 ]
});
let color_port = ViewPort::new();
let color_collector = Arc::new(RwLock::new(ColorCollector {
src_view: None,
color: SingletonBuffer::new((200, 200, 0), color_port.inner())
}));
let col_seq_port = color_editor.get_data_port().map(
|sub_editor| sub_editor.read().unwrap().get_value()
);
color_port.add_update_hook(Arc::new(col_seq_port.0.clone()));
col_seq_port.add_observer(
color_collector.clone()
);
compositor.write().unwrap().push(color_editor.get_term_view().offset(Vector2::new(0, 0)));
let event_loop = nakorender::winit::event_loop::EventLoop::new();
let window = nakorender::winit::window::Window::new(&event_loop).unwrap();
let mut renderer = Arc::new(Mutex::new(nakorender::marp::MarpBackend::new(&window, &event_loop)));
// terminal view
let mut sdf_term = Arc::new(RwLock::new(SdfTerm::new(renderer.clone())));
term_port.outer().add_observer(sdf_term.clone());
// color preview
let color_view = color_port.outer().get_view();
let color_layer_id = renderer.lock().unwrap().new_layer_2d();
renderer.lock().unwrap().update_camera_2d(color_layer_id, Camera2d{
extent: Vec2::new(4.0, 4.0),
location: Vec2::new(-2.0, -2.0),
rotation: 0.0
});
renderer.lock().unwrap().set_layer_info(color_layer_id.into(), LayerInfo{
extent: UVec2::new(600, 600),
location: IVec2::new(200,100)
});
event_loop.run(move |event, _target, control_flow|{
//Set to polling for now, might be overwritten
//TODO: Maybe we want to use "WAIT" for the ui thread? However, the renderer.lock().unwrap()s don't work that hard
//if nothing changes. So should be okay for a alpha style programm.
*control_flow = winit::event_loop::ControlFlow::Poll;
//now check if a rerender was requested, or if we worked on all
//events on that batch
match event{
winit::event::Event::WindowEvent{window_id: _, event: winit::event::WindowEvent::Resized(newsize)} => {
}
winit::event::Event::WindowEvent{window_id: _, event: winit::event::WindowEvent::KeyboardInput{ device_id, input, is_synthetic }} => {
if input.state == winit::event::ElementState::Pressed {
if let Some(kc) = input.virtual_keycode {
match kc {
winit::event::VirtualKeyCode::Space |
winit::event::VirtualKeyCode::Return => {
color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char(' '))));
}
winit::event::VirtualKeyCode::Key0 |
winit::event::VirtualKeyCode::Numpad0 => {
color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('0'))));
}
winit::event::VirtualKeyCode::Key1 |
winit::event::VirtualKeyCode::Numpad1 => {
color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('1'))));
}
winit::event::VirtualKeyCode::Key2 |
winit::event::VirtualKeyCode::Numpad2 => {
color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('2'))));
}
winit::event::VirtualKeyCode::Key3 |
winit::event::VirtualKeyCode::Numpad3 => {
color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('3'))));
}
winit::event::VirtualKeyCode::Key4 |
winit::event::VirtualKeyCode::Numpad4 => {
color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('4'))));
}
winit::event::VirtualKeyCode::Key5 |
winit::event::VirtualKeyCode::Numpad5 => {
color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('5'))));
}
winit::event::VirtualKeyCode::Key6 |
winit::event::VirtualKeyCode::Numpad6 => {
color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('6'))));
}
winit::event::VirtualKeyCode::Key7 |
winit::event::VirtualKeyCode::Numpad7 => {
color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('7'))));
}
winit::event::VirtualKeyCode::Key8 |
winit::event::VirtualKeyCode::Numpad8 => {
color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('8'))));
}
winit::event::VirtualKeyCode::Key9 |
winit::event::VirtualKeyCode::Numpad9 => {
color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('9'))));
}
winit::event::VirtualKeyCode::A => {
color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('a'))));
}
winit::event::VirtualKeyCode::B => {
color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('b'))));
}
winit::event::VirtualKeyCode::C => {
color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('c'))));
}
winit::event::VirtualKeyCode::D => {
color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('d'))));
}
winit::event::VirtualKeyCode::E => {
color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('e'))));
}
winit::event::VirtualKeyCode::F => {
color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char('f'))));
}
winit::event::VirtualKeyCode::Tab => {
color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Insert)));
}
winit::event::VirtualKeyCode::Delete => {
color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Delete)));
}
winit::event::VirtualKeyCode::Back => {
color_editor.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Backspace)));
}
winit::event::VirtualKeyCode::Left => {
color_editor.pxev();
}
winit::event::VirtualKeyCode::Right => {
color_editor.nexd();
}
winit::event::VirtualKeyCode::Up => {
color_editor.up();
}
winit::event::VirtualKeyCode::Down => {
color_editor.dn();
color_editor.goto_home();
}
winit::event::VirtualKeyCode::Home => {
color_editor.goto_home();
}
winit::event::VirtualKeyCode::End => {
color_editor.goto_end();
}
_ => {
}
}
}
}
}
winit::event::Event::MainEventsCleared => {
window.request_redraw();
}
winit::event::Event::RedrawRequested(_) => {
color_port.update();
term_port.update();
let c = color_view.get();
let color_stream = PrimaryStream2d::new()
.push(
SecondaryStream2d::new(
Union,
Box2d {
extent: Vec2::new(0.5, 0.5)
}
).push_mod(
Color(
Vec3::new(
(c.0 as f32 / 255.0).clamp(0.0, 1.0),
(c.1 as f32 / 255.0).clamp(0.0, 1.0),
(c.2 as f32 / 255.0).clamp(0.0, 1.0),
)
)
).push_mod(
Round{radius: 0.2}
).build()
).build();
renderer.lock().unwrap().update_sdf_2d(color_layer_id, color_stream);
renderer.lock().unwrap().set_layer_order(
vec![
vec![ color_layer_id.into() ].into_iter(),
sdf_term.read().unwrap().get_order().into_iter()
]
.into_iter()
.flatten()
.collect::<Vec<_>>()
.as_slice()
);
renderer.lock().unwrap().render(&window);
}
_ => {},
}
})
}

View File

@ -1,16 +0,0 @@
[package]
name = "shell"
version = "0.1.0"
edition = "2018"
[dependencies]
nested = { path = "../nested" }
cgmath = "*"
termion = "*"
bincode = "*"
libc = "0.2.*"
portable-pty = "0.4.0"
[dependencies.async-std]
version = "1.9.0"
features = ["unstable", "attributes"]

View File

@ -1,93 +0,0 @@
ShellTerm :=
| Lit : "«String»" | "«Path»~«Sep Char '/'»~«Seq Char»~«TerminatedArray AsciiChar~Byte 0»"
| Var : $«ProcessArgument~~«PositionalInt 10 BigEndian»»
| Sub : $(«Process»)
$PATH:Sequence Path
:SeparatedSequence Char '/'
:Sequence Sequence Char
:
:SeparatedSequence Char ':'
:Sequence Char
&OsString~
~List Char~Vec Byte
Seq
Vec
Sep
read :: Sep -> Seq
read (Sep xs) d ->
deco :: Style -> Seq ->
ShellTerm::eval t:ShellTerm -> String {
match t {
ShellTerm::Lit "s:«String»" -> {
}
ShellTerm::Var var:$
}
}
$PATH : Sequence Path ~ SeparatedSequence Char ':'
ShellTerm::eval := «» -> «»
«Path» :> «»
Path := [ PathSegment ] ~ List
[Char]
:separator '/'
:
a: Int x b: Int
( a b )
// Process is a Structure Type
Process := {
env : Symbol -> ShellTerm
exe : Path
args : [ShellTerm]
stdin : Pipe
}
// OsString is an Abstraction Type
[OsString] := [Sequence AsciiChar] ~ [Sequence Byte] ~ [TerminatedSequence Byte 0] ~ [Pointer Byte] ~ [MachineWord]
execve := {
Process
~ { env : Symbol, exe: Path~, }
->
}
precedence of operators: '~' < ':' < '[ ]' < '{ }'
<Ls> := [ < ]
Process exe=/bin/ls : Process := {
args : [ProcessArgument] ~ []
}
:> «PosixShellScript ~ String» { ... }
:> «TerminalView» { ... }
»ProcessId«~»MachineInt«~»MachineWord«~»Register«
«ProcessId»~«MachineInt»~«MachineWord»~«Register»
Pipe::read = {
fd: const ( FileDescriptor ~ MachineInt ~ Register ~ EAX )
buf: ( Array Byte ~ )
} ->
stdout := «ProcessId» -> «FileDescriptor»~«MachineInt»~«Register»~«EAX»
poorly-written shell scripts often do not handle filenames with spaces.

View File

@ -1,10 +0,0 @@
ls :: [files]:<Set Path>
[options]:<Set String>
: (view ls) (template
(decorate files EnumSet)
((λx.xx) a) = aa
-> (process files.to_seq.(map |x|{ }) )

View File

@ -1,330 +0,0 @@
use {
std::{
sync::{Arc, RwLock},
collections::HashMap
},
cgmath::{Vector2, Point2},
termion::event::{Event, Key},
nested::{
vec::VecBuffer,
list::{ListEditor, PTYListEditor},
sequence::{SequenceView, decorator::{Separate, Wrap, SeqDecorStyle}},
core::{TypeTerm, Context},
core::{OuterViewPort, ViewPort},
index::{IndexArea, IndexView},
char_editor::CharEditor,
terminal::{
TerminalAtom, TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle, TerminalView, make_label
},
tree::{TreeCursor, TreeNav, TreeNavResult},
diagnostics::{Diagnostics},
product::ProductEditor,
sum::SumEditor,
Nested
}
};
trait Action {
fn make_editor(&self, ctx: Arc<RwLock<Context>>) -> Arc<RwLock<dyn Nested + Send + Sync>>;
}
pub struct ActCd {}
impl Action for ActCd {
fn make_editor(&self, ctx: Arc<RwLock<Context>>) -> Arc<RwLock<dyn Nested + Send + Sync>> {
let depth = 1;
Arc::new(RwLock::new(ProductEditor::new(depth, ctx.clone())
.with_n(Point2::new(0, 0), vec![ ctx.read().unwrap().type_term_from_str("( Path )").unwrap() ] )
)) as Arc<RwLock<dyn Nested + Send + Sync>>
}
}
pub struct ActLs {}
impl Action for ActLs {
fn make_editor(&self, ctx: Arc<RwLock<Context>>) -> Arc<RwLock<dyn Nested + Send + Sync>> {
let depth = 1;
Arc::new(RwLock::new(ProductEditor::new(depth, ctx.clone())
.with_t(Point2::new(1, 0), " Files")
.with_n(Point2::new(0, 0), vec![ ctx.read().unwrap().type_term_from_str("( List Path )").unwrap() ] )
.with_t(Point2::new(1, 1), " Options")
.with_n(Point2::new(0, 1), vec![ ctx.read().unwrap().type_term_from_str("( List String )").unwrap() ] )
)) as Arc<RwLock<dyn Nested + Send + Sync>>
}
}
pub struct ActEcho {}
impl Action for ActEcho {
fn make_editor(&self, ctx: Arc<RwLock<Context>>) -> Arc<RwLock<dyn Nested + Send + Sync>> {
let depth = 1;
let a = Arc::new(RwLock::new(ProductEditor::new(depth, ctx.clone())
.with_n(Point2::new(0, 0), vec![ ctx.read().unwrap().type_term_from_str("( String )").unwrap() ] )
)) as Arc<RwLock<dyn Nested + Send + Sync>>;
let b = Arc::new(RwLock::new(ProductEditor::new(depth, ctx.clone())
.with_n(Point2::new(0, 0), vec![ ctx.read().unwrap().type_term_from_str("( PosInt 16 BigEndian )").unwrap() ] )
)) as Arc<RwLock<dyn Nested + Send + Sync>>;
let mut x = Arc::new(RwLock::new( SumEditor::new(
vec![
a, b
]
) ));
x.write().unwrap().select(0);
x
}
}
pub struct ActCp {}
impl Action for ActCp {
fn make_editor(&self, ctx: Arc<RwLock<Context>>) -> Arc<RwLock<dyn Nested + Send + Sync>> {
let depth = 1;
Arc::new(RwLock::new(ProductEditor::new(depth, ctx.clone())
.with_t(Point2::new(1, 1), " Source")
.with_n(Point2::new(0, 1), vec![ ctx.read().unwrap().type_term_from_str("( Path )").unwrap() ] )
.with_t(Point2::new(1, 2), " Destination")
.with_n(Point2::new(0, 2), vec![ ctx.read().unwrap().type_term_from_str("( Path )").unwrap() ] )
.with_t(Point2::new(1, 3), " Options")
.with_n(Point2::new(0, 3), vec![ ctx.read().unwrap().type_term_from_str("( List Symbol )").unwrap() ] )
)) as Arc<RwLock<dyn Nested + Send + Sync>>
}
}
pub struct ActNum {}
impl Action for ActNum {
fn make_editor(&self, ctx: Arc<RwLock<Context>>) -> Arc<RwLock<dyn Nested + Send + Sync>> {
let depth = 1;
Arc::new(RwLock::new(ProductEditor::new(depth, ctx.clone())
.with_t(Point2::new(1, 1), " Value")
.with_n(Point2::new(0, 1), vec![ ctx.read().unwrap().type_term_from_str("( PosInt 16 BigEndian )").unwrap() ] )
.with_t(Point2::new(1, 2), " Radix")
.with_n(Point2::new(0, 2), vec![ ctx.read().unwrap().type_term_from_str("( PosInt 10 BigEndian )").unwrap() ] )
)) as Arc<RwLock<dyn Nested + Send + Sync>>
// Arc::new(RwLock::new(nested::integer::PosIntEditor::new(10)))
}
}
pub struct ActLet {}
impl Action for ActLet {
fn make_editor(&self, ctx: Arc<RwLock<Context>>) -> Arc<RwLock<dyn Nested + Send + Sync>> {
let depth = 1;
Arc::new(RwLock::new(ProductEditor::new(depth, ctx.clone())
.with_n(Point2::new(0, 0), vec![ ctx.read().unwrap().type_term_from_str("( Symbol )").unwrap() ] )
.with_t(Point2::new(1, 0), " : ")
.with_n(Point2::new(2, 0), vec![ ctx.read().unwrap().type_term_from_str("( TypeTerm )").unwrap() ] )
.with_t(Point2::new(3, 0), " := ")
.with_n(Point2::new(4, 0), vec![ ctx.read().unwrap().type_term_from_str("( PosInt 16 BigEndian )").unwrap() ] )
)) as Arc<RwLock<dyn Nested + Send + Sync>>
}
}
pub struct Commander {
ctx: Arc<RwLock<Context>>,
cmds: HashMap<String, Arc<dyn Action + Send + Sync>>,
valid: Arc<RwLock<bool>>,
confirmed: bool,
symbol_editor: PTYListEditor<CharEditor>,
cmd_editor: Option<Arc<RwLock<dyn Nested + Send + Sync>>>,
view_elements: VecBuffer<OuterViewPort<dyn TerminalView>>,
out_port: OuterViewPort<dyn TerminalView>,
m_buf: VecBuffer<OuterViewPort<dyn SequenceView<Item = nested::diagnostics::Message>>>,
msg_port: OuterViewPort<dyn SequenceView<Item = nested::diagnostics::Message>>
}
impl Commander {
pub fn new(ctx: Arc<RwLock<Context>>) -> Self {
let port = ViewPort::new();
let mut view_elements = VecBuffer::with_port(port.inner());
let symbol_editor = PTYListEditor::new(
|| {
Arc::new(RwLock::new(CharEditor::new()))
},
SeqDecorStyle::Plain,
'\n',
0
);
let valid = Arc::new(RwLock::new(false));
view_elements.push(symbol_editor
.get_term_view()
.map_item({
let valid = valid.clone();
move
|pos, mut a| {
if *valid.read().unwrap() {
a.add_style_back(TerminalStyle::fg_color((0,255,0)))
} else {
a.add_style_back(TerminalStyle::fg_color((255,0,0)))
}
}
}));
let mut cmds = HashMap::new();
cmds.insert("let".into(), Arc::new(ActLet{}) as Arc<dyn Action + Send + Sync>);
cmds.insert("cd".into(), Arc::new(ActCd{}) as Arc<dyn Action + Send + Sync>);
cmds.insert("echo".into(), Arc::new(ActEcho{}) as Arc<dyn Action + Send + Sync>);
cmds.insert("ls".into(), Arc::new(ActLs{}) as Arc<dyn Action + Send + Sync>);
cmds.insert("cp".into(), Arc::new(ActCp{}) as Arc<dyn Action + Send + Sync>);
cmds.insert("num".into(), Arc::new(ActNum{}) as Arc<dyn Action + Send + Sync>);
let m_buf = VecBuffer::new();
let mut c = Commander {
ctx,
cmds,
valid,
confirmed: false,
symbol_editor,
cmd_editor: None,
view_elements,
out_port: port.outer()
.to_sequence()
.separate(make_label(" "))
.to_grid_horizontal()
.flatten(),
msg_port: m_buf.get_port()
.to_sequence()
.flatten(),
m_buf
};
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), true) = (self.cmd_editor.as_ref(), self.confirmed) {
match event {
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
let mut c = cmd_editor.write().unwrap();
if c.nexd() == TreeNavResult::Exit {
// run
c.goto(TreeCursor::none());
TerminalEditorResult::Exit
} else {
TerminalEditorResult::Continue
}
}
event => {
cmd_editor.write().unwrap().handle_terminal_event(event)
}
}
} else {
match event {
TerminalEvent::Input(Event::Key(Key::Char(' '))) |
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
if let Some(editor) = &self.cmd_editor {
self.confirmed = true;
self.symbol_editor.up();
editor.write().unwrap().qpxev();
*self.view_elements.get_mut(1) = editor.read().unwrap().get_term_view();
self.m_buf.push(editor.read().unwrap().get_msg_port());
if *event == TerminalEvent::Input(Event::Key(Key::Char('\n'))) {
return self.handle_terminal_event(event);
}
} else {
// undefined command
let mut b = VecBuffer::new();
b.push(nested::diagnostics::make_error(nested::terminal::make_label(&format!("invalid symbol {}", self.symbol_editor.get_string()))));
self.m_buf.clear();
self.m_buf.push(b.get_port().to_sequence());
}
TerminalEditorResult::Continue
}
event => {
self.m_buf.clear();
let res = self.symbol_editor.handle_terminal_event(event);
let symbol = self.symbol_editor.get_string();
if let Some(action) = self.cmds.get(&symbol) {
let editor = action.make_editor(self.ctx.clone());
if self.view_elements.len() == 1 {
self.view_elements.push(editor.read().unwrap().get_term_view().map_item(|p,a| a.add_style_front(TerminalStyle::fg_color((80,80,80)))));
} else {
*self.view_elements.get_mut(1) = editor.read().unwrap().get_term_view().map_item(|p,a| a.add_style_front(TerminalStyle::fg_color((80,80,80))));
}
self.cmd_editor = Some(editor);
*self.valid.write().unwrap() = true;
} else {
/*
let mut b = VecBuffer::new();
b.push(nested::diagnostics::make_error(nested::terminal::make_label(&format!("invalid symbol {}", self.symbol_editor.get_string()))));
self.m_buf.push(b.get_port().to_sequence());
*/
self.cmd_editor = None;
*self.valid.write().unwrap() = false;
if self.view_elements.len() > 1 {
self.view_elements.remove(1);
}
}
res
}
}
}
}
}
impl Diagnostics for Commander {
fn get_msg_port(&self) -> OuterViewPort<dyn SequenceView<Item = nested::diagnostics::Message>> {
self.msg_port.clone()
}
}
impl TreeNav for Commander {
fn get_cursor(&self) -> TreeCursor {
if let (Some(cmd_editor), true) = (self.cmd_editor.as_ref(), self.confirmed) {
cmd_editor.write().unwrap().get_cursor()
} else {
self.symbol_editor.get_cursor()
}
}
fn get_cursor_warp(&self) -> TreeCursor {
if let (Some(cmd_editor), true) = (self.cmd_editor.as_ref(), self.confirmed) {
cmd_editor.write().unwrap().get_cursor_warp()
} else {
self.symbol_editor.get_cursor_warp()
}
}
fn goby(&mut self, dir: Vector2<isize>) -> TreeNavResult {
if let (Some(cmd_editor), true) = (self.cmd_editor.as_ref(), self.confirmed) {
cmd_editor.write().unwrap().goby(dir)
} else {
self.symbol_editor.goby(dir)
}
}
fn goto(&mut self, cur: TreeCursor) -> TreeNavResult {
if let (Some(cmd_editor), true) = (self.cmd_editor.as_ref(), self.confirmed) {
cmd_editor.write().unwrap().goto(cur)
} else {
self.symbol_editor.goto(cur)
}
}
}
impl Nested for Commander {}

View File

@ -1,18 +0,0 @@
use {
nested::commander::Commander,
nested::terminal::TerminalEvent
};
struct Incubator {
}
impl Commander for Incubator {
type Cmd = TerminalEvent;
fn send_cmd(&mut self, cmd: &TerminalEvent) {
}
}

View File

@ -1,302 +0,0 @@
extern crate portable_pty;
mod pty;
mod incubator;
// TODO rewrite process & command with incubator rules
//mod process;
//mod command;
use {
cgmath::{Point2, Vector2},
nested::{
core::{port::UpdateTask, Observer, AnyOuterViewPort, ViewPort},
type_system::{Context, ReprTree},
index::IndexArea,
singleton::{SingletonView, SingletonBuffer},
list::{ListCursorMode, PTYListEditor},
sequence::{decorator::{SeqDecorStyle, Separate}},
terminal::{
make_label, Terminal, TerminalAtom, TerminalCompositor, TerminalEditor,
TerminalEditorResult, TerminalEvent, TerminalStyle,
},
tree::{TreeNav, TreeCursor, TreeNavResult},
vec::VecBuffer,
diagnostics::{Diagnostics},
index::{buffer::IndexBuffer},
commander::Commander
},
std::sync::{Arc, RwLock},
termion::event::{Event, Key},
};
#[async_std::main]
async fn main() {
let term_port = ViewPort::new();
let compositor = TerminalCompositor::new(term_port.inner());
let mut term = Terminal::new(term_port.outer());
let term_writer = term.get_writer();
let portmutex = Arc::new(RwLock::new(()));
// Update Loop //
let tp = term_port.clone();
async_std::task::spawn({
let portmutex = portmutex.clone();
async move {
loop {
{
let _l = portmutex.write().unwrap();
tp.update();
}
async_std::task::sleep(std::time::Duration::from_millis(10)).await;
}
}
});
// Type Context //
let ctx = Arc::new(RwLock::new(Context::new()));
let ctx = nested::type_system::init_mem_ctx(ctx);
let ctx = nested::type_system::init_editor_ctx(ctx);
let ctx = nested::type_system::init_math_ctx(ctx);
let ctx = nested::type_system::init_os_ctx(ctx);
let vb = VecBuffer::<char>::new();
let rt_char = ReprTree::new_leaf(
ctx.read().unwrap().type_term_from_str("( Vec Char )").unwrap(),
AnyOuterViewPort::from(vb.get_port())
);
let rt_digit = ReprTree::ascend(&rt_char, ctx.read().unwrap().type_term_from_str("( List ( Digit 10 ) )").unwrap());
rt_digit.write().unwrap().insert_branch(
ReprTree::new_leaf(
ctx.read().unwrap().type_term_from_str("( Vec MachineInt )").unwrap(),
AnyOuterViewPort::from(
vb.get_port().to_sequence().map(
|c: &char| {
c.to_digit(10).unwrap()
}
)
)
)
);
/*
ctx.write().unwrap().add_morphism(
MorphismType{
mode: MorphismMode::Iso,
src_type:
},
Box::new(
|repr| {
RadixProjection::new(
)
}
)
);
*/
let c = ctx.clone();
let mut process_list_editor =
PTYListEditor::new(
ctx.clone(),
c.read().unwrap().type_term_from_str("( List Path 1 )").unwrap(),
SeqDecorStyle::Plain,
Some('\n'),
3
);
async_std::task::spawn(async move {
let mut table = nested::index::buffer::IndexBuffer::new();
let magic =
make_label("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>")
.map_item(|pos, atom| {
atom.add_style_back(TerminalStyle::fg_color((
5,
((80 + (pos.x * 30) % 100) as u8),
(55 + (pos.x * 15) % 180) as u8,
)))
});
let mut cur_size = nested::singleton::SingletonBuffer::new(Vector2::new(10, 10));
table.insert_iter(vec![
(Point2::new(0, 0), magic.clone()),
(Point2::new(0, 1), process_list_editor.editor.read().unwrap().get_cursor_widget()),
(Point2::new(0, 2), magic.clone()),
(Point2::new(0, 3), make_label(" ")),
(Point2::new(0, 4),
process_list_editor
.editor.read().unwrap()
.get_seg_seq_view()
.enumerate()
.map(
|(n, segment)| {
let mut buf = IndexBuffer::new();
buf.insert_iter(vec![
(Point2::new(0, 0),
make_label(match n+1 {
1 => "I) ",
2 => "II) ",
3 => "III) ",
4 => "IV) ",
5 => "V) ",
6 => "VI) ",
7 => "VII) ",
8 => "IIX) ",
9 => "IX) ",
10 => "X) ",
_ => ""
})),
(Point2::new(1, 0), segment.clone())
]);
buf.get_port()
}
)
.separate({
let mut buf = IndexBuffer::new();
buf.insert(Point2::new(1,0), make_label(" ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~").with_fg_color((40,40,40))
);
buf.get_port()
})
.to_grid_vertical()
.flatten()
.flatten()
),
(Point2::new(0, 5), make_label(" ")),
(Point2::new(0, 6), magic.clone()),
(Point2::new(0, 7), process_list_editor.diag.map(
|entry| {
let mut b = VecBuffer::new();
b.push(
make_label("@").with_style(
TerminalStyle::bold(true)
.add(TerminalStyle::fg_color((120,120,0))))
);
for x in entry.addr.iter() {
b.push(
make_label(&format!("{}", x)).with_fg_color((0, 100, 20))
);
b.push(
make_label(".")
.map_item(|_p,a| a
.add_style_back(TerminalStyle::bold(true))
.add_style_back(TerminalStyle::fg_color((120,120,0))))
);
}
b.push(entry.port.clone());
b.get_port()
.to_sequence()
.to_grid_horizontal()
.flatten()
.map_item(move |_p,a| {
let select = false;
if select {
a.add_style_back(TerminalStyle::fg_color((60,60,60)))
} else {
*a
}
})
}
).to_grid_vertical().flatten())
]);
let (_w, _h) = termion::terminal_size().unwrap();
compositor
.write()
.unwrap()
.push(table.get_port().flatten().offset(Vector2::new(3, 0)));
process_list_editor.editor.write().unwrap().goto(TreeCursor {
leaf_mode: ListCursorMode::Insert,
tree_addr: vec![0],
});
loop {
let ev = term.next_event().await;
let _l = portmutex.write().unwrap();
if let TerminalEvent::Resize(new_size) = ev {
cur_size.set(new_size);
term_port.inner().get_broadcast().notify(&IndexArea::Full);
continue;
}
/*
if let Some(process_editor) = process_list_editor.get_item() {
let mut pe = process_editor.write().unwrap();
/*
if pe.is_captured() {
if let TerminalEditorResult::Exit = pe.handle_terminal_event(&ev) {
drop(pe);
process_list_editor.up();
process_list_editor.nexd();
}
continue;
}
*/
}
*/
match ev {
TerminalEvent::Input(Event::Key(Key::Ctrl('d'))) => break,
TerminalEvent::Input(Event::Key(Key::Ctrl('l'))) => {
process_list_editor.editor.write().unwrap().goto(TreeCursor {
leaf_mode: ListCursorMode::Insert,
tree_addr: vec![0],
});
//process_list_editor.clear();
}
TerminalEvent::Input(Event::Key(Key::Left)) => {
process_list_editor.editor.write().unwrap().pxev();
}
TerminalEvent::Input(Event::Key(Key::Right)) => {
process_list_editor.editor.write().unwrap().nexd();
}
TerminalEvent::Input(Event::Key(Key::Up)) => {
if process_list_editor.editor.write().unwrap().up() == TreeNavResult::Exit {
process_list_editor.editor.write().unwrap().dn();
}
}
TerminalEvent::Input(Event::Key(Key::Down)) => {
process_list_editor.editor.write().unwrap().dn();
// == TreeNavResult::Continue {
//process_list_editor.goto_home();
//}
}
TerminalEvent::Input(Event::Key(Key::Home)) => {
process_list_editor.editor.write().unwrap().qpxev();
}
TerminalEvent::Input(Event::Key(Key::End)) => {
process_list_editor.editor.write().unwrap().qnexd();
}
TerminalEvent::Input(Event::Key(Key::Char('\t'))) => {
let mut c = process_list_editor.editor.read().unwrap().get_cursor();
c.leaf_mode = match c.leaf_mode {
ListCursorMode::Select => ListCursorMode::Insert,
ListCursorMode::Insert => ListCursorMode::Select
};
process_list_editor.editor.write().unwrap().goto(c);
}
ev => {
process_list_editor.send_cmd(&ev);
}
}
}
drop(term);
drop(term_port);
});
term_writer.show().await.expect("output error!");
}

View File

@ -1,277 +0,0 @@
use {
crate::pty::{PTYStatus, PTY},
nested::{
core::{OuterViewPort, ViewPort},
list::{ListCursorMode, PTYListEditor},
sequence::{SequenceView, SequenceViewExt, decorator::{SeqDecorStyle, Separate, Wrap}},
singleton::SingletonView,
char_editor::CharEditor,
terminal::{
TerminalAtom, TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle,
TerminalView,
},
tree::{TreeCursor, TreeNav, TreeNavResult},
diagnostics::Diagnostics,
Nested
},
std::sync::Arc,
std::sync::RwLock,
termion::event::{Event, Key},
cgmath::Vector2
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct ProcessArg {
editor:
PTYListEditor<CharEditor>,
}
impl ProcessArg {
pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = char>> {
self.editor.get_data_port().map(|char_editor| {
char_editor
.read()
.unwrap()
.get_port()
.get_view()
.unwrap()
.get()
.unwrap()
})
}
}
impl TerminalEditor for ProcessArg {
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
self.editor.get_term_view()
}
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
match event {
TerminalEvent::Input(Event::Key(Key::Char(' ')))
| TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
self.editor.up();
TerminalEditorResult::Exit
}
event => self.editor.handle_terminal_event(event),
}
}
}
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 goby(&mut self, dir: Vector2<isize>) -> TreeNavResult {
self.editor.goby(dir)
}
}
impl Diagnostics for ProcessArg {
}
impl Nested for ProcessArg {}
pub struct ProcessLauncher {
cmd_editor: PTYListEditor<ProcessArg>,
pty: Option<crate::pty::PTY>,
_ptybox: Arc<RwLock<crate::ascii_box::AsciiBox>>,
suspended: bool,
pty_port: ViewPort<dyn TerminalView>,
status_port: ViewPort<dyn SingletonView<Item = PTYStatus>>,
comp_port: ViewPort<dyn TerminalView>,
_compositor: Arc<RwLock<nested::terminal::TerminalCompositor>>,
}
impl ProcessLauncher {
pub fn new() -> Self {
let pty_port = ViewPort::new();
let status_port = ViewPort::new();
let comp_port = ViewPort::new();
let box_port = ViewPort::<dyn TerminalView>::new();
let compositor = nested::terminal::TerminalCompositor::new(comp_port.inner());
let cmd_editor = PTYListEditor::new(
Box::new(|| {
Arc::new(RwLock::new(ProcessArg {
editor: PTYListEditor::new(
Box::new(|| Arc::new(RwLock::new(CharEditor::new()))),
SeqDecorStyle::Plain,
'\n',
1
),
}))
}) as Box<dyn Fn() -> Arc<RwLock<ProcessArg>> + Send + Sync>,
SeqDecorStyle::HorizontalSexpr,
' ',
0
);
compositor.write().unwrap().push(
box_port
.outer()
.map_item(|_idx, x| x.add_style_back(TerminalStyle::fg_color((90, 120, 100)))),
);
compositor.write().unwrap().push(
cmd_editor.get_term_view()
);
ProcessLauncher {
cmd_editor,
pty: None,
_ptybox: crate::ascii_box::AsciiBox::new(
cgmath::Vector2::new(0, 0),
pty_port.outer().map_item(|_, a: &TerminalAtom| {
a.add_style_back(TerminalStyle::fg_color((230, 230, 230)))
}),
box_port.inner(),
),
suspended: false,
pty_port,
status_port,
comp_port,
_compositor: compositor,
}
}
pub fn launch_pty(&mut self) {
let mut strings = Vec::new();
let v = self.cmd_editor.get_data_port().get_view().unwrap();
for i in 0..v.len().unwrap_or(0) {
let arg_view = v
.get(&i)
.unwrap()
.read()
.unwrap()
.get_data_port()
.get_view()
.unwrap();
strings.push(arg_view.iter().collect::<String>());
}
if strings.len() > 0 {
// Spawn a shell into the pty
let mut cmd = crate::pty::CommandBuilder::new(strings[0].as_str());
cmd.args(&strings[1..]);
cmd.cwd(".");
self.cmd_editor.goto(TreeCursor {
leaf_mode: ListCursorMode::Insert,
tree_addr: vec![],
});
self.pty = PTY::new(
cmd,
cgmath::Vector2::new(120, 40),
self.pty_port.inner(),
self.status_port.inner(),
);
}
}
pub fn is_captured(&self) -> bool {
self.pty.is_some() && !self.suspended
}
}
impl TerminalEditor for ProcessLauncher {
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
self.comp_port.outer()
}
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
// todo: move to observer of status view
if let PTYStatus::Done { status: _ } = self.status_port.outer().get_view().get() {
self.pty = None;
self.suspended = false;
}
match event {
TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) => {
// todo: sigterm instead of kill?
if let Some(pty) = self.pty.as_mut() {
pty.kill();
}
self.pty = None;
self.suspended = false;
self.cmd_editor.goto(TreeCursor {
leaf_mode: ListCursorMode::Insert,
tree_addr: vec![],
});
TerminalEditorResult::Exit
}
TerminalEvent::Input(Event::Key(Key::Ctrl('z'))) => {
self.suspended = true;
self.cmd_editor.goto(TreeCursor {
leaf_mode: ListCursorMode::Insert,
tree_addr: vec![],
});
TerminalEditorResult::Exit
}
event => {
if let Some(pty) = self.pty.as_mut() {
pty.handle_terminal_event(event);
TerminalEditorResult::Continue
} else {
match event {
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
// launch command
self.launch_pty();
TerminalEditorResult::Continue
}
event => self.cmd_editor.handle_terminal_event(event),
}
}
}
}
}
}
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;
if let PTYStatus::Done { status: _ } = self.status_port.outer().get_view().get() {
self.pty = None;
}
if self.pty.is_none() {
self.cmd_editor.goto(cur)
} else {
self.cmd_editor.goto(TreeCursor {
leaf_mode: ListCursorMode::Select,
tree_addr: vec![],
});
TreeNavResult::Continue
}
}
fn goby(&mut self, dir: Vector2<isize>) -> TreeNavResult {
self.cmd_editor.goby(dir)
}
}
impl Diagnostics for ProcessLauncher {
}
impl Nested for ProcessLauncher {}

View File

@ -1,167 +0,0 @@
use {
cgmath::Vector2,
nested::{
core::InnerViewPort,
singleton::{SingletonBuffer, SingletonView},
terminal::{TerminalEditorResult, TerminalEvent, TerminalView},
},
std::sync::{Arc, Mutex},
termion::event::{Event, Key},
};
pub use portable_pty::CommandBuilder;
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[derive(Clone)]
pub enum PTYStatus {
Running { pid: u32 },
Done { status: portable_pty::ExitStatus },
}
impl Default for PTYStatus {
fn default() -> Self {
PTYStatus::Running { pid: 0 }
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct PTY {
master: Mutex<Box<dyn portable_pty::MasterPty + Send>>,
child: Arc<Mutex<Box<dyn portable_pty::Child + Send + Sync>>>,
}
impl PTY {
pub fn new(
cmd: portable_pty::CommandBuilder,
max_size: Vector2<i16>,
term_port: InnerViewPort<dyn TerminalView>,
status_port: InnerViewPort<dyn SingletonView<Item = PTYStatus>>,
) -> Option<Self> {
// Create a new pty
let pair = portable_pty::native_pty_system()
.openpty(portable_pty::PtySize {
rows: max_size.y as u16,
cols: max_size.x as u16,
// Not all systems support pixel_width, pixel_height,
// but it is good practice to set it to something
// that matches the size of the selected font. That
// is more complex than can be shown here in this
// brief example though!
pixel_width: 0,
pixel_height: 0,
})
.unwrap();
if let Ok(child) = pair.slave.spawn_command(cmd) {
let mut reader = pair.master.try_clone_reader().unwrap();
let mut status_buf = SingletonBuffer::with_port(
PTYStatus::Running {
pid: child.process_id().expect(""),
},
status_port,
);
let child = Arc::new(Mutex::new(child));
async_std::task::spawn_blocking(move || {
nested::terminal::ansi_parser::read_ansi_from(&mut reader, max_size, term_port);
});
async_std::task::spawn_blocking({
let child = child.clone();
move || loop {
if let Ok(Some(status)) = child.lock().unwrap().try_wait() {
status_buf.set(PTYStatus::Done { status });
break;
}
std::thread::sleep(std::time::Duration::from_millis(10));
}
});
Some(PTY {
master: Mutex::new(pair.master),
child,
})
} else {
None
}
}
pub fn kill(&mut self) {
self.child.lock().unwrap().kill().unwrap();
}
pub fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
match event {
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
self.master.lock().unwrap().write(&[13]).unwrap();
TerminalEditorResult::Continue
}
TerminalEvent::Input(Event::Key(Key::Char(c))) => {
write!(self.master.lock().unwrap(), "{}", c).unwrap();
TerminalEditorResult::Continue
}
TerminalEvent::Input(Event::Key(Key::Esc)) => {
self.master.lock().unwrap().write(&[0x1b]).unwrap();
TerminalEditorResult::Continue
}
TerminalEvent::Input(Event::Key(Key::Backspace)) => {
self.master.lock().unwrap().write(&[0x8]).unwrap();
TerminalEditorResult::Continue
}
TerminalEvent::Input(Event::Key(Key::F(n))) => {
self.master
.lock()
.unwrap()
.write(&[
0x1b,
0x0a,
match n {
11 => 133,
12 => 134,
n => 58 + n,
},
])
.unwrap();
TerminalEditorResult::Continue
}
TerminalEvent::Input(Event::Key(Key::Up)) => {
self.master
.lock()
.unwrap()
.write(&[b'\x1B', b'[', b'A'])
.unwrap();
TerminalEditorResult::Continue
}
TerminalEvent::Input(Event::Key(Key::Down)) => {
self.master
.lock()
.unwrap()
.write(&[b'\x1B', b'[', b'B'])
.unwrap();
TerminalEditorResult::Continue
}
TerminalEvent::Input(Event::Key(Key::Right)) => {
self.master
.lock()
.unwrap()
.write(&[b'\x1B', b'[', b'C'])
.unwrap();
TerminalEditorResult::Continue
}
TerminalEvent::Input(Event::Key(Key::Left)) => {
self.master
.lock()
.unwrap()
.write(&[b'\x1B', b'[', b'D'])
.unwrap();
TerminalEditorResult::Continue
}
_ => TerminalEditorResult::Exit,
}
}
}