factor out r3vi and shell crates
This commit is contained in:
parent
d43d99c6d3
commit
6f942c8940
83 changed files with 1294 additions and 6389 deletions
14
Cargo.toml
14
Cargo.toml
|
@ -1,12 +1,10 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"nested",
|
"nested",
|
||||||
"terminal/display_server",
|
# "terminal/display_server",
|
||||||
"terminal/ansi_parser",
|
# "terminal/ansi_parser",
|
||||||
"shell",
|
# "math/str2int",
|
||||||
"sdf_editor",
|
# "math/int2str",
|
||||||
"math/str2int",
|
# "math/radix_transform",
|
||||||
"math/int2str",
|
# "math/fib"
|
||||||
"math/radix_transform",
|
|
||||||
"math/fib"
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -5,6 +5,7 @@ name = "nested"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
r3vi = { git = "https://git.exobiont.de/senvas/r3vi.git" }
|
||||||
no_deadlocks = "*"
|
no_deadlocks = "*"
|
||||||
cgmath = { version = "0.18.0", features = ["serde"] }
|
cgmath = { version = "0.18.0", features = ["serde"] }
|
||||||
termion = "1.5.5"
|
termion = "1.5.5"
|
||||||
|
|
|
@ -7,9 +7,9 @@ pub trait Commander {
|
||||||
|
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use crate::{
|
use crate::{
|
||||||
type_system::ReprTree,
|
type_system::ReprTree
|
||||||
singleton::SingletonView
|
|
||||||
};
|
};
|
||||||
|
use r3vi::view::singleton::*;
|
||||||
|
|
||||||
pub trait ObjCommander {
|
pub trait ObjCommander {
|
||||||
fn send_cmd_obj(&mut self, cmd_obj: Arc<RwLock<ReprTree>>);
|
fn send_cmd_obj(&mut self, cmd_obj: Arc<RwLock<ReprTree>>);
|
||||||
|
|
|
@ -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>>()
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
};
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -1,9 +1,9 @@
|
||||||
use {
|
use {
|
||||||
|
r3vi::{
|
||||||
|
view::{OuterViewPort, sequence::*},
|
||||||
|
buffer::{vec::*, index_hashmap::*}
|
||||||
|
},
|
||||||
crate::{
|
crate::{
|
||||||
core::{OuterViewPort},
|
|
||||||
sequence::{SequenceView},
|
|
||||||
vec::{VecBuffer},
|
|
||||||
index::{buffer::IndexBuffer},
|
|
||||||
terminal::{
|
terminal::{
|
||||||
TerminalView, TerminalStyle, make_label
|
TerminalView, TerminalStyle, make_label
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
use {
|
use {
|
||||||
|
r3vi::{
|
||||||
|
view::{
|
||||||
|
OuterViewPort,
|
||||||
|
singleton::*,
|
||||||
|
},
|
||||||
|
buffer::singleton::*
|
||||||
|
},
|
||||||
crate::{
|
crate::{
|
||||||
core::{OuterViewPort},
|
|
||||||
type_system::{Context},
|
type_system::{Context},
|
||||||
singleton::{SingletonBuffer, SingletonView},
|
|
||||||
terminal::{TerminalAtom, TerminalEvent, TerminalStyle},
|
terminal::{TerminalAtom, TerminalEvent, TerminalStyle},
|
||||||
tree::NestedNode,
|
tree::NestedNode,
|
||||||
commander::Commander
|
commander::Commander
|
||||||
|
@ -70,11 +75,11 @@ impl CharEditor {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
use crate::StringGen;
|
use crate::StringGen;
|
||||||
impl StringGen for CharEditor {
|
impl StringGen for CharEditor {
|
||||||
fn get_string(&self) -> String {
|
fn get_string(&self) -> String {
|
||||||
String::from(self.get())
|
String::from(self.get())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
|
@ -1,9 +1,13 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
r3vi::{
|
||||||
core::{InnerViewPort, OuterViewPort},
|
view::{
|
||||||
projection::ProjectionHelper,
|
InnerViewPort, OuterViewPort,
|
||||||
sequence::SequenceView,
|
sequence::*,
|
||||||
vec::VecBuffer,
|
},
|
||||||
|
buffer::{
|
||||||
|
vec::*
|
||||||
|
},
|
||||||
|
projection::projection_helper::*,
|
||||||
},
|
},
|
||||||
std::sync::{Arc, RwLock},
|
std::sync::{Arc, RwLock},
|
||||||
};
|
};
|
|
@ -1,26 +1,29 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
r3vi::{
|
||||||
core::{OuterViewPort},
|
view::{
|
||||||
type_system::{Context, TypeTerm},
|
OuterViewPort,
|
||||||
list::{PTYListEditor},
|
singleton::*,
|
||||||
sequence::{SequenceView, SequenceViewExt, decorator::{PTYSeqDecorate, SeqDecorStyle}},
|
|
||||||
singleton::{SingletonBuffer, SingletonView},
|
|
||||||
vec::{VecBuffer},
|
|
||||||
index::{buffer::IndexBuffer},
|
|
||||||
terminal::{
|
|
||||||
TerminalAtom, TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle,
|
|
||||||
TerminalView, make_label
|
|
||||||
},
|
},
|
||||||
tree::{TreeCursor, TreeNav, TreeNavResult},
|
buffer::{
|
||||||
diagnostics::{Diagnostics, Message},
|
singleton::*,
|
||||||
|
vec::*,
|
||||||
|
index_hashmap::*
|
||||||
|
}
|
||||||
|
},
|
||||||
|
crate::{
|
||||||
|
type_system::{Context, TypeTerm, ReprTree},
|
||||||
|
editors::list::{PTYListEditor, ListStyle},
|
||||||
|
terminal::{
|
||||||
|
TerminalAtom, TerminalEvent, TerminalStyle, make_label
|
||||||
|
},
|
||||||
|
diagnostics::{Message},
|
||||||
tree::NestedNode,
|
tree::NestedNode,
|
||||||
Nested,
|
|
||||||
commander::Commander
|
commander::Commander
|
||||||
},
|
},
|
||||||
std::sync::Arc,
|
std::sync::Arc,
|
||||||
std::sync::RwLock,
|
std::sync::RwLock,
|
||||||
termion::event::{Event, Key},
|
termion::event::{Event, Key},
|
||||||
cgmath::{Vector2, Point2}
|
cgmath::{Point2}
|
||||||
};
|
};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
@ -74,13 +77,15 @@ impl DigitEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_node(self) -> NestedNode {
|
pub fn into_node(self) -> NestedNode {
|
||||||
|
let data = self.get_data();
|
||||||
let editor = Arc::new(RwLock::new(self));
|
let editor = Arc::new(RwLock::new(self));
|
||||||
let ed = editor.read().unwrap();
|
let mut ed = editor.write().unwrap();
|
||||||
let r = ed.radix;
|
let r = ed.radix;
|
||||||
|
|
||||||
NestedNode::new()
|
NestedNode::new()
|
||||||
.set_ctx(ed.ctx.clone())
|
.set_ctx(ed.ctx.clone())
|
||||||
.set_cmd(editor.clone())
|
.set_cmd(editor.clone())
|
||||||
|
.set_data(data)
|
||||||
.set_view(
|
.set_view(
|
||||||
ed.data
|
ed.data
|
||||||
.get_port()
|
.get_port()
|
||||||
|
@ -106,6 +111,26 @@ impl DigitEditor {
|
||||||
let radix = self.radix;
|
let radix = self.radix;
|
||||||
self.data.get_port().map(move |c| c?.to_digit(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 {
|
pub struct PosIntEditor {
|
||||||
|
@ -115,24 +140,40 @@ pub struct PosIntEditor {
|
||||||
|
|
||||||
impl PosIntEditor {
|
impl PosIntEditor {
|
||||||
pub fn new(ctx: Arc<RwLock<Context>>, radix: u32) -> Self {
|
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 {
|
PosIntEditor {
|
||||||
radix,
|
radix,
|
||||||
digits: PTYListEditor::new(
|
digits: node
|
||||||
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
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
r3vi::{
|
||||||
core::{InnerViewPort, Observer, OuterViewPort},
|
view::{
|
||||||
sequence::SequenceView,
|
InnerViewPort, Observer, OuterViewPort,
|
||||||
vec::VecBuffer,
|
sequence::*,
|
||||||
|
},
|
||||||
|
buffer::{vec::*}
|
||||||
},
|
},
|
||||||
std::sync::{Arc, RwLock},
|
std::sync::{Arc, RwLock},
|
||||||
};
|
};
|
43
nested/src/editors/list/commander.rs
Normal file
43
nested/src/editors/list/commander.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
280
nested/src/editors/list/editor.rs
Normal file
280
nested/src/editors/list/editor.rs
Normal 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
15
nested/src/editors/list/mod.rs
Normal file
15
nested/src/editors/list/mod.rs
Normal 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}
|
||||||
|
};
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
use {
|
use {
|
||||||
|
r3vi::{
|
||||||
|
view::{
|
||||||
|
OuterViewPort,
|
||||||
|
singleton::*,
|
||||||
|
sequence::*
|
||||||
|
}
|
||||||
|
},
|
||||||
crate::{
|
crate::{
|
||||||
core::{OuterViewPort},
|
editors::list::{
|
||||||
sequence::{SequenceView},
|
|
||||||
list::{
|
|
||||||
ListCursor, ListCursorMode,
|
ListCursor, ListCursorMode,
|
||||||
ListEditor
|
editor::ListEditor
|
||||||
},
|
},
|
||||||
tree::{TreeCursor, TreeNav, TreeNavResult},
|
tree::{TreeCursor, TreeNav, TreeNavResult}
|
||||||
singleton::SingletonView,
|
|
||||||
Nested
|
|
||||||
},
|
},
|
||||||
cgmath::Vector2
|
cgmath::Vector2
|
||||||
};
|
};
|
432
nested/src/editors/list/pty_editor.rs
Normal file
432
nested/src/editors/list/pty_editor.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,14 @@
|
||||||
use {
|
use {
|
||||||
|
r3vi::{
|
||||||
|
view::{
|
||||||
|
Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View, ViewPort,
|
||||||
|
singleton::*,
|
||||||
|
sequence::*,
|
||||||
|
},
|
||||||
|
projection::projection_helper::*
|
||||||
|
},
|
||||||
crate::{
|
crate::{
|
||||||
core::{InnerViewPort, Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View, ViewPort},
|
editors::list::{ListCursor, ListCursorMode},
|
||||||
list::{ListCursor, ListCursorMode},
|
|
||||||
projection::ProjectionHelper,
|
|
||||||
sequence::SequenceView,
|
|
||||||
singleton::SingletonView,
|
|
||||||
terminal::{TerminalView, TerminalStyle, make_label},
|
terminal::{TerminalView, TerminalStyle, make_label},
|
||||||
tree::{NestedNode, TreeNav},
|
tree::{NestedNode, TreeNav},
|
||||||
utils::color::{bg_style_from_depth, fg_style_from_depth},
|
utils::color::{bg_style_from_depth, fg_style_from_depth},
|
7
nested/src/editors/mod.rs
Normal file
7
nested/src/editors/mod.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
pub mod char;
|
||||||
|
pub mod integer;
|
||||||
|
|
||||||
|
pub mod list;
|
||||||
|
pub mod product;
|
||||||
|
pub mod sum;
|
|
@ -1,16 +1,26 @@
|
||||||
use {
|
use {
|
||||||
|
r3vi::{
|
||||||
|
view::{
|
||||||
|
OuterViewPort,
|
||||||
|
sequence::*
|
||||||
|
},
|
||||||
|
buffer::{
|
||||||
|
vec::*,
|
||||||
|
index_hashmap::*
|
||||||
|
}
|
||||||
|
},
|
||||||
crate::{
|
crate::{
|
||||||
core::{OuterViewPort},
|
|
||||||
type_system::{TypeLadder, Context},
|
type_system::{TypeLadder, Context},
|
||||||
terminal::{
|
terminal::{
|
||||||
TerminalEditor, TerminalEditorResult,
|
TerminalEditor, TerminalEditorResult,
|
||||||
TerminalEvent, TerminalView
|
TerminalEvent, TerminalView
|
||||||
},
|
},
|
||||||
vec::{VecBuffer},
|
editors::{
|
||||||
index::{buffer::{IndexBuffer, MutableIndexAccess}},
|
list::ListCursorMode,
|
||||||
list::ListCursorMode,
|
product::{
|
||||||
product::{segment::ProductEditorSegment},
|
segment::ProductEditorSegment
|
||||||
sequence::{SequenceView},
|
}
|
||||||
|
},
|
||||||
tree::{TreeNav, TreeNavResult},
|
tree::{TreeNav, TreeNavResult},
|
||||||
diagnostics::{Diagnostics},
|
diagnostics::{Diagnostics},
|
||||||
terminal::{TerminalStyle},
|
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 {
|
impl TerminalEditor for ProductEditor {
|
||||||
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
|
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
|
||||||
let ctx = self.ctx.clone();
|
let ctx = self.ctx.clone();
|
|
@ -1,10 +1,11 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
type_system::Context,
|
type_system::Context,
|
||||||
list::ListCursorMode,
|
|
||||||
tree::{TreeNav, TreeNavResult, TreeCursor},
|
tree::{TreeNav, TreeNavResult, TreeCursor},
|
||||||
product::{segment::ProductEditorSegment, ProductEditor},
|
editors::{
|
||||||
Nested
|
list::ListCursorMode,
|
||||||
|
product::{segment::ProductEditorSegment, ProductEditor},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
cgmath::{Vector2},
|
cgmath::{Vector2},
|
||||||
std::{ops::{DerefMut}},
|
std::{ops::{DerefMut}},
|
||||||
|
@ -245,5 +246,3 @@ impl TreeNav for ProductEditor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Nested for ProductEditor {}
|
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
use {
|
use {
|
||||||
|
r3vi::{
|
||||||
|
view::{
|
||||||
|
OuterViewPort
|
||||||
|
}
|
||||||
|
},
|
||||||
crate::{
|
crate::{
|
||||||
core::{OuterViewPort},
|
|
||||||
type_system::{TypeLadder, Context},
|
type_system::{TypeLadder, Context},
|
||||||
terminal::{
|
terminal::{
|
||||||
TerminalStyle, TerminalView,
|
TerminalStyle, TerminalView,
|
|
@ -1,11 +1,19 @@
|
||||||
use {
|
use {
|
||||||
|
r3vi::{
|
||||||
|
view::{
|
||||||
|
ViewPort, OuterViewPort,
|
||||||
|
sequence::*,
|
||||||
|
},
|
||||||
|
buffer::{
|
||||||
|
vec::*
|
||||||
|
}
|
||||||
|
},
|
||||||
crate::{
|
crate::{
|
||||||
core::{ViewPort, OuterViewPort},
|
|
||||||
terminal::{
|
terminal::{
|
||||||
TerminalEditor, TerminalEditorResult,
|
TerminalEditor, TerminalEditorResult,
|
||||||
TerminalEvent, TerminalView
|
TerminalEvent, TerminalView
|
||||||
},
|
},
|
||||||
sequence::{SequenceView},
|
type_system::{Context},
|
||||||
tree::{TreeNav, TreeCursor, TreeNavResult},
|
tree::{TreeNav, TreeCursor, TreeNavResult},
|
||||||
diagnostics::{Diagnostics, Message},
|
diagnostics::{Diagnostics, Message},
|
||||||
tree::NestedNode,
|
tree::NestedNode,
|
||||||
|
@ -30,25 +38,26 @@ impl SumEditor {
|
||||||
editors: Vec< NestedNode >
|
editors: Vec< NestedNode >
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let port = ViewPort::new();
|
let port = ViewPort::new();
|
||||||
//let mut diag_buf = VecBuffer::new();
|
|
||||||
|
|
||||||
SumEditor {
|
SumEditor {
|
||||||
cur: 0,
|
cur: 0,
|
||||||
editors,
|
editors,
|
||||||
port,
|
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));
|
let editor = Arc::new(RwLock::new(self));
|
||||||
NestedNode::new()
|
NestedNode::new()
|
||||||
.set_view()
|
.set_ctx(ctx)
|
||||||
|
.set_view(view)
|
||||||
.set_cmd(editor.clone())
|
.set_cmd(editor.clone())
|
||||||
.set_nav(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 {
|
pub fn get(&self) -> NestedNode {
|
||||||
self.editors[ self.cur ].clone()
|
self.editors[ self.cur ].clone()
|
||||||
}
|
}
|
|
@ -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 ]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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)),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
|
@ -1,57 +1,34 @@
|
||||||
#![feature(trait_alias)]
|
#![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 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() {
|
pub fn magic_header() {
|
||||||
eprintln!("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>");
|
eprintln!("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
pub trait StringGen {
|
pub trait StringGen {
|
||||||
fn get_string(&self) -> String;
|
fn get_string(&self) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::terminal::TerminalEditor;
|
|
||||||
use crate::{tree::{TreeNav}, diagnostics::Diagnostics, terminal::TerminalView, core::{OuterViewPort}};
|
use crate::{tree::{TreeNav}, diagnostics::Diagnostics, terminal::TerminalView, core::{OuterViewPort}};
|
||||||
|
*/
|
||||||
|
|
||||||
|
use r3vi::view::OuterViewPort;
|
||||||
|
use crate::terminal::TerminalView;
|
||||||
|
|
||||||
pub trait PtySegment {
|
pub trait PtySegment {
|
||||||
fn pty_view(&self) -> OuterViewPort<dyn TerminalView>;
|
fn pty_view(&self) -> OuterViewPort<dyn TerminalView>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Nested
|
|
||||||
: TerminalEditor
|
|
||||||
+ TreeNav
|
|
||||||
// + TreeType
|
|
||||||
+ Diagnostics
|
|
||||||
+ Send
|
|
||||||
+ Sync
|
|
||||||
+ std::any::Any
|
|
||||||
{}
|
|
||||||
|
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
|
|
|
@ -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 => {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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]));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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>> {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
|
@ -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![ () ]));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +1,15 @@
|
||||||
use {
|
use {
|
||||||
//async_std::{io::{Read, ReadExt}},
|
//async_std::{io::{Read, ReadExt}},
|
||||||
|
r3vi::{
|
||||||
|
view::{
|
||||||
|
InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View, ViewPort,
|
||||||
|
index::*,
|
||||||
|
singleton::*,
|
||||||
|
},
|
||||||
|
buffer::{singleton::*, index_hashmap::*},
|
||||||
|
projection::projection_helper::ProjectionHelper,
|
||||||
|
},
|
||||||
crate::{
|
crate::{
|
||||||
core::{InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View, ViewPort},
|
|
||||||
index::{buffer::IndexBuffer, IndexArea, IndexView},
|
|
||||||
projection::ProjectionHelper,
|
|
||||||
singleton::{SingletonBuffer, SingletonView},
|
|
||||||
terminal::{TerminalAtom, TerminalStyle, TerminalView},
|
terminal::{TerminalAtom, TerminalStyle, TerminalView},
|
||||||
},
|
},
|
||||||
cgmath::{Point2, Vector2},
|
cgmath::{Point2, Vector2},
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
r3vi::{
|
||||||
core::{InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View},
|
view::{
|
||||||
index::{IndexArea, IndexView},
|
InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View,
|
||||||
projection::ProjectionHelper,
|
index::*,
|
||||||
terminal::{TerminalAtom, TerminalView},
|
},
|
||||||
|
projection::projection_helper::*,
|
||||||
},
|
},
|
||||||
|
crate::{terminal::{TerminalAtom, TerminalView}},
|
||||||
cgmath::Point2,
|
cgmath::Point2,
|
||||||
std::sync::Arc,
|
std::sync::Arc,
|
||||||
std::sync::RwLock,
|
std::sync::RwLock,
|
||||||
|
|
|
@ -11,7 +11,7 @@ pub use {
|
||||||
terminal::{Terminal, TerminalEvent},
|
terminal::{Terminal, TerminalEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::grid::GridView;
|
use r3vi::view::grid::*;
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
|
@ -32,9 +32,9 @@ pub trait TerminalEditor {
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
r3vi::{
|
||||||
core::{OuterViewPort, ViewPort},
|
view::{OuterViewPort},
|
||||||
vec::VecBuffer,
|
buffer::vec::*,
|
||||||
},
|
},
|
||||||
cgmath::Point2,
|
cgmath::Point2,
|
||||||
};
|
};
|
||||||
|
@ -54,19 +54,25 @@ pub fn make_label(s: &str) -> OuterViewPort<dyn TerminalView> {
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OuterViewPort<dyn TerminalView> {
|
pub trait TerminalProjections {
|
||||||
pub fn with_style(&self, style: TerminalStyle) -> OuterViewPort<dyn TerminalView> {
|
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(
|
self.map_item(
|
||||||
move |_idx, a|
|
move |_idx, a|
|
||||||
a.add_style_front(style)
|
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))
|
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))
|
self.with_style(TerminalStyle::bg_color(col))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
use {
|
use {
|
||||||
super::{TerminalStyle, TerminalView},
|
r3vi::{
|
||||||
crate::{
|
view::{
|
||||||
core::{
|
|
||||||
channel::{queue_channel, set_channel, ChannelReceiver, ChannelSender},
|
channel::{queue_channel, set_channel, ChannelReceiver, ChannelSender},
|
||||||
Observer, OuterViewPort,
|
Observer, OuterViewPort,
|
||||||
},
|
grid::*,
|
||||||
grid::GridWindowIterator,
|
index::*,
|
||||||
index::IndexArea,
|
}
|
||||||
},
|
},
|
||||||
|
super::{TerminalStyle, TerminalView},
|
||||||
async_std::{stream::StreamExt, task},
|
async_std::{stream::StreamExt, task},
|
||||||
cgmath::{Point2, Vector2},
|
cgmath::{Point2, Vector2},
|
||||||
signal_hook,
|
signal_hook,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use {
|
use {
|
||||||
crate::list::ListCursorMode
|
crate::editors::list::ListCursorMode
|
||||||
};
|
};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
|
@ -1,15 +1,24 @@
|
||||||
use {
|
use {
|
||||||
crate::list::ListCursorMode,
|
r3vi::{
|
||||||
crate::tree::TreeCursor,
|
view::{
|
||||||
crate::vec::VecBuffer,
|
OuterViewPort,
|
||||||
crate::core::{OuterViewPort},
|
singleton::*,
|
||||||
crate::sequence::{SequenceView, decorator::Separate},
|
sequence::*,
|
||||||
crate::singleton::{SingletonBuffer, SingletonView},
|
},
|
||||||
cgmath::Vector2,
|
buffer::{
|
||||||
|
singleton::SingletonBuffer,
|
||||||
|
vec::VecBuffer
|
||||||
|
},
|
||||||
|
projection::{
|
||||||
|
decorate_sequence::*,
|
||||||
|
}
|
||||||
|
},
|
||||||
crate::{
|
crate::{
|
||||||
terminal::{TerminalView, TerminalStyle, make_label}
|
editors::list::ListCursorMode,
|
||||||
|
tree::TreeCursor,
|
||||||
}
|
terminal::{TerminalView, TerminalProjections, make_label}
|
||||||
|
},
|
||||||
|
cgmath::Vector2,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
|
@ -76,6 +85,21 @@ pub trait TreeNav {
|
||||||
self.goto(c)
|
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 {
|
fn up(&mut self) -> TreeNavResult {
|
||||||
self.goby(Vector2::new(0, -1))
|
self.goby(Vector2::new(0, -1))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +1,58 @@
|
||||||
use {
|
use {
|
||||||
std::sync::{Arc, RwLock},
|
std::{sync::{Arc, RwLock}, any::Any},
|
||||||
cgmath::Vector2,
|
cgmath::Vector2,
|
||||||
|
r3vi::{
|
||||||
|
view::{
|
||||||
|
ViewPort, OuterViewPort, AnyOuterViewPort,
|
||||||
|
singleton::*,
|
||||||
|
sequence::*
|
||||||
|
},
|
||||||
|
buffer::{singleton::*}
|
||||||
|
},
|
||||||
crate::{
|
crate::{
|
||||||
core::{ViewPort, OuterViewPort, AnyOuterViewPort},
|
|
||||||
type_system::{ReprTree, Context},
|
type_system::{ReprTree, Context},
|
||||||
singleton::{SingletonBuffer, SingletonView},
|
|
||||||
sequence::SequenceView,
|
|
||||||
terminal::{TerminalView, TerminalEvent, TerminalEditor, TerminalEditorResult},
|
terminal::{TerminalView, TerminalEvent, TerminalEditor, TerminalEditorResult},
|
||||||
diagnostics::{Diagnostics, Message},
|
diagnostics::{Diagnostics, Message},
|
||||||
tree::{TreeNav, TreeCursor, TreeNavResult},
|
tree::{TreeNav, TreeCursor, TreeNavResult},
|
||||||
list::{ListCursorMode},
|
editors::list::{ListCursorMode},
|
||||||
commander::ObjCommander,
|
commander::ObjCommander,
|
||||||
vec::VecBuffer,
|
|
||||||
Nested
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct NestedNode {
|
pub struct NestedNode {
|
||||||
|
/// context
|
||||||
pub ctx: Option<Arc<RwLock<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>>,
|
pub view: Option<OuterViewPort<dyn TerminalView>>,
|
||||||
|
|
||||||
|
/// diagnostics
|
||||||
pub diag: Option<OuterViewPort<dyn SequenceView<Item = Message>>>,
|
pub diag: Option<OuterViewPort<dyn SequenceView<Item = Message>>>,
|
||||||
|
|
||||||
|
/// commander
|
||||||
pub cmd: Option<Arc<RwLock<dyn ObjCommander + Send + Sync>>>,
|
pub cmd: Option<Arc<RwLock<dyn ObjCommander + Send + Sync>>>,
|
||||||
|
|
||||||
|
/// tree navigation
|
||||||
pub tree_nav: Option<Arc<RwLock<dyn TreeNav + Send + Sync>>>,
|
pub tree_nav: Option<Arc<RwLock<dyn TreeNav + Send + Sync>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjCommander for NestedNode {
|
impl ObjCommander for NestedNode {
|
||||||
fn send_cmd_obj(&mut self, cmd_obj: Arc<RwLock<ReprTree>>) {
|
fn send_cmd_obj(&mut self, cmd_obj: Arc<RwLock<ReprTree>>) {
|
||||||
if let Some(cmd) = self.cmd.as_ref() {
|
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);
|
cmd.write().unwrap().send_cmd_obj(cmd_obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo: remove that at some point
|
||||||
impl TerminalEditor for NestedNode {
|
impl TerminalEditor for NestedNode {
|
||||||
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
|
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
|
||||||
self.get_view()
|
self.get_view()
|
||||||
|
@ -109,13 +127,18 @@ impl TreeNav for NestedNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Diagnostics for NestedNode {}
|
impl Diagnostics for NestedNode {
|
||||||
impl Nested for NestedNode {}
|
fn get_msg_port(&self) -> OuterViewPort<dyn SequenceView<Item = Message>> {
|
||||||
|
self.get_diag()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl NestedNode {
|
impl NestedNode {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
NestedNode {
|
NestedNode {
|
||||||
ctx: None,
|
ctx: None,
|
||||||
|
data: None,
|
||||||
|
editor: None,
|
||||||
view: None,
|
view: None,
|
||||||
diag: None,
|
diag: None,
|
||||||
cmd: None,
|
cmd: None,
|
||||||
|
@ -128,6 +151,16 @@ impl NestedNode {
|
||||||
self
|
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 {
|
pub fn set_view(mut self, view: OuterViewPort<dyn TerminalView>) -> Self {
|
||||||
self.view = Some(view);
|
self.view = Some(view);
|
||||||
self
|
self
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
core::{AnyOuterViewPort, OuterViewPort, View},
|
|
||||||
type_system::{TypeDict, TypeTerm, TypeID, ReprTree},
|
type_system::{TypeDict, TypeTerm, TypeID, ReprTree},
|
||||||
tree::NestedNode
|
tree::NestedNode
|
||||||
},
|
},
|
||||||
|
@ -50,6 +49,9 @@ pub struct Context {
|
||||||
/// objects
|
/// objects
|
||||||
objects: HashMap<String, Arc<RwLock<ReprTree>>>,
|
objects: HashMap<String, Arc<RwLock<ReprTree>>>,
|
||||||
|
|
||||||
|
/// types that can be edited as lists
|
||||||
|
list_types: Vec<TypeID>,
|
||||||
|
|
||||||
/// editors
|
/// editors
|
||||||
editor_ctors: HashMap<TypeID, Arc<dyn Fn(Arc<RwLock<Self>>, TypeTerm, usize) -> Option<NestedNode> + Send + Sync>>,
|
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(),
|
default_constructors: HashMap::new(),
|
||||||
morphism_constructors: HashMap::new(),
|
morphism_constructors: HashMap::new(),
|
||||||
objects: HashMap::new(),
|
objects: HashMap::new(),
|
||||||
|
list_types: match parent.as_ref() {
|
||||||
|
Some(p) => p.read().unwrap().list_types.clone(),
|
||||||
|
None => Vec::new()
|
||||||
|
},
|
||||||
parent,
|
parent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,8 +86,22 @@ impl Context {
|
||||||
Context::with_parent(None)
|
Context::with_parent(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_typename(&mut self, tn: String) {
|
pub fn add_typename(&mut self, tn: String) -> TypeID {
|
||||||
self.type_dict.write().unwrap().add_typename(tn);
|
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> {
|
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>) {
|
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 mut dict = self.type_dict.write().unwrap();
|
||||||
let tyid = dict
|
let tyid =
|
||||||
.get_typeid(&tn.into())
|
if let Some(tyid) = dict.get_typeid(&tn.into()) {
|
||||||
.unwrap_or( dict.add_typename(tn.into()) );
|
tyid
|
||||||
|
} else {
|
||||||
|
dict.add_typename(tn.into())
|
||||||
|
};
|
||||||
self.editor_ctors.insert(tyid, mk_editor);
|
self.editor_ctors.insert(tyid, mk_editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +145,20 @@ impl Context {
|
||||||
let mk_editor = ctx.read().unwrap().get_editor_ctor(&type_term)?;
|
let mk_editor = ctx.read().unwrap().get_editor_ctor(&type_term)?;
|
||||||
mk_editor(ctx.clone(), type_term, depth)
|
mk_editor(ctx.clone(), type_term, depth)
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
pub fn enrich_editor(
|
||||||
|
node: NestedNode,
|
||||||
|
typ: TypeTerm
|
||||||
|
) -> NestedNode {
|
||||||
|
|
||||||
|
|
||||||
|
// create view
|
||||||
|
|
||||||
|
// create commander
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
pub fn add_morphism(
|
pub fn add_morphism(
|
||||||
&mut self,
|
&mut self,
|
||||||
morph_type: MorphismType,
|
morph_type: MorphismType,
|
||||||
|
|
|
@ -1,15 +1,20 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
type_system::{TypeTerm, Context},
|
type_system::{Context, TypeTerm, ReprTree},
|
||||||
integer::{DigitEditor, PosIntEditor},
|
editors::{
|
||||||
list::{PTYListEditor},
|
char::*,
|
||||||
sequence::{decorator::{SeqDecorStyle}},
|
list::*,
|
||||||
sum::SumEditor,
|
integer::*,
|
||||||
char::CharEditor,
|
product::*,
|
||||||
|
sum::*
|
||||||
|
},
|
||||||
|
tree::{NestedNode},
|
||||||
|
terminal::{TerminalEditor},
|
||||||
|
diagnostics::{Diagnostics},
|
||||||
type_system::TypeTermEditor,
|
type_system::TypeTermEditor,
|
||||||
Nested
|
|
||||||
},
|
},
|
||||||
std::sync::{Arc, RwLock},
|
std::sync::{Arc, RwLock},
|
||||||
|
cgmath::Point2
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init_mem_ctx(parent: Arc<RwLock<Context>>) -> Arc<RwLock<Context>> {
|
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(
|
ctx.write().unwrap().add_editor_ctor(
|
||||||
"List", Arc::new(
|
"List", Arc::new(
|
||||||
|ctx: Arc<RwLock<Context>>, ty: TypeTerm, depth: usize| {
|
|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
|
id: _, args
|
||||||
} => {
|
} => {
|
||||||
if args.len() > 0 {
|
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(
|
Some(
|
||||||
PTYListEditor::new(
|
PTYListEditor::new(
|
||||||
ctx.clone(),
|
ctx,
|
||||||
args[0].clone(),
|
args[0].clone(),
|
||||||
delim,
|
ListStyle::HorizontalSexpr,
|
||||||
depth
|
depth + 1
|
||||||
).into_node(style)
|
).into_node()
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
None
|
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(
|
ctx.write().unwrap().add_editor_ctor(
|
||||||
"Symbol", Arc::new(
|
"Symbol", Arc::new(
|
||||||
|ctx: Arc<RwLock<Context>>, _ty: TypeTerm, depth: usize| {
|
|ctx: Arc<RwLock<Context>>, _ty: TypeTerm, depth: usize| {
|
||||||
Context::make_editor(
|
let mut node = PTYListEditor::new(
|
||||||
&ctx,
|
ctx.clone(),
|
||||||
ctx.read().unwrap().type_term_from_str("( List Char 0 )").unwrap(),
|
ctx.read().unwrap().type_term_from_str("( Char )").unwrap(),
|
||||||
depth
|
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(
|
ctx.write().unwrap().add_editor_ctor(
|
||||||
"String", Arc::new(
|
"String", Arc::new(
|
||||||
|ctx: Arc<RwLock<Context>>, _ty: TypeTerm, depth: usize| {
|
|ctx: Arc<RwLock<Context>>, _ty: TypeTerm, depth: usize| {
|
||||||
Context::make_editor(
|
let mut node = PTYListEditor::new(
|
||||||
&ctx,
|
ctx.clone(),
|
||||||
ctx.read().unwrap().type_term_from_str("( List Char 3 )").unwrap(),
|
ctx.read().unwrap().type_term_from_str("( Char )").unwrap(),
|
||||||
depth
|
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(
|
ctx.write().unwrap().add_editor_ctor(
|
||||||
"TypeTerm", Arc::new(
|
"TypeTerm", Arc::new(
|
||||||
|ctx: Arc<RwLock<Context>>, _ty: TypeTerm, depth: usize| {
|
|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
|
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))));
|
let ctx = Arc::new(RwLock::new(Context::with_parent(Some(parent))));
|
||||||
|
|
||||||
ctx.write().unwrap().add_typename("MachineInt".into());
|
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("BigEndian".into());
|
||||||
|
|
||||||
//ctx.write().unwrap().add_typename("Digit".into());
|
|
||||||
|
|
||||||
ctx.write().unwrap().add_editor_ctor(
|
ctx.write().unwrap().add_editor_ctor(
|
||||||
"Digit", Arc::new(
|
"Digit", Arc::new(
|
||||||
|ctx: Arc<RwLock<Context>>, ty: TypeTerm, _depth: usize| {
|
|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 {
|
if args.len() > 0 {
|
||||||
match args[0] {
|
match args[0] {
|
||||||
TypeTerm::Num(radix) => {
|
TypeTerm::Num(radix) => {
|
||||||
|
let node = DigitEditor::new(ctx.clone(), radix as u32).into_node();
|
||||||
Some(
|
Some(
|
||||||
DigitEditor::new(ctx.clone(), radix as u32).into_node()
|
node
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
_ => None
|
_ => 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(
|
ctx.write().unwrap().add_editor_ctor(
|
||||||
"PosInt", Arc::new(
|
"PosInt", Arc::new(
|
||||||
|ctx: Arc<RwLock<Context>>, ty: TypeTerm, _depth: usize| {
|
|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
|
ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_os_ctx(parent: Arc<RwLock<Context>>) -> Arc<RwLock<Context>> {
|
pub fn init_os_ctx(parent: Arc<RwLock<Context>>) -> Arc<RwLock<Context>> {
|
||||||
let ctx = Arc::new(RwLock::new(Context::with_parent(Some(parent))));
|
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(
|
ctx.write().unwrap().add_editor_ctor(
|
||||||
"PathSegment", Arc::new(
|
"PathSegment", Arc::new(
|
||||||
|ctx: Arc<RwLock<Context>>, _ty: TypeTerm, depth: usize| {
|
|ctx: Arc<RwLock<Context>>, _ty: TypeTerm, depth: usize| {
|
||||||
Context::make_editor(
|
let mut node = PTYListEditor::new(
|
||||||
&ctx,
|
ctx.clone(),
|
||||||
ctx.read().unwrap().type_term_from_str("( List Char 0 )").unwrap(),
|
ctx.read().unwrap().type_term_from_str("( Char )").unwrap(),
|
||||||
depth
|
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(
|
ctx.write().unwrap().add_editor_ctor(
|
||||||
"Path", Arc::new(
|
"Path", Arc::new(
|
||||||
|ctx: Arc<RwLock<Context>>, _ty: TypeTerm, depth: usize| {
|
|ctx: Arc<RwLock<Context>>, _ty: TypeTerm, depth: usize| {
|
||||||
Context::make_editor(
|
let mut node = PTYListEditor::new(
|
||||||
&ctx,
|
ctx.clone(),
|
||||||
ctx.read().unwrap().type_term_from_str("( List PathSegment 6 )").unwrap(),
|
ctx.read().unwrap().type_term_from_str("( PathSegment )").unwrap(),
|
||||||
depth+1
|
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)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
pub mod type_term;
|
pub mod type_term;
|
||||||
pub mod repr_tree;
|
pub mod repr_tree;
|
||||||
pub mod context;
|
pub mod context;
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
use {
|
use {
|
||||||
|
r3vi::view::{AnyOuterViewPort, OuterViewPort, View},
|
||||||
crate::{
|
crate::{
|
||||||
core::{AnyOuterViewPort, OuterViewPort, View},
|
type_system::{TypeTerm}
|
||||||
type_system::{TypeDict, TypeTerm, TypeID},
|
|
||||||
tree::NestedNode
|
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
collections::HashMap,
|
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>> {
|
pub fn new_leaf(type_tag: TypeTerm, port: AnyOuterViewPort) -> Arc<RwLock<Self>> {
|
||||||
let mut tree = ReprTree::new(type_tag);
|
let mut tree = ReprTree::new(type_tag);
|
||||||
tree.insert_leaf(vec![].into_iter(), port);
|
tree.insert_leaf(vec![].into_iter(), port);
|
||||||
|
|
|
@ -1,15 +1,21 @@
|
||||||
use {
|
use {
|
||||||
|
r3vi::{
|
||||||
|
view::{
|
||||||
|
OuterViewPort,
|
||||||
|
sequence::*
|
||||||
|
}
|
||||||
|
},
|
||||||
crate::{
|
crate::{
|
||||||
core::{OuterViewPort},
|
|
||||||
type_system::{Context},
|
type_system::{Context},
|
||||||
terminal::{TerminalEvent, TerminalView, TerminalEditor, TerminalEditorResult},
|
terminal::{TerminalEvent, TerminalView, TerminalEditor, TerminalEditorResult},
|
||||||
sequence::{SequenceView, decorator::SeqDecorStyle},
|
editors::{
|
||||||
list::{PTYListEditor},
|
list::*,
|
||||||
|
sum::*,
|
||||||
|
char::CharEditor,
|
||||||
|
integer::PosIntEditor,
|
||||||
|
},
|
||||||
tree::{TreeNav, TreeCursor, TreeNavResult},
|
tree::{TreeNav, TreeCursor, TreeNavResult},
|
||||||
diagnostics::{Diagnostics, Message},
|
diagnostics::{Diagnostics, Message},
|
||||||
sum::SumEditor,
|
|
||||||
char::CharEditor,
|
|
||||||
integer::PosIntEditor,
|
|
||||||
tree::NestedNode,
|
tree::NestedNode,
|
||||||
commander::Commander,
|
commander::Commander,
|
||||||
PtySegment
|
PtySegment
|
||||||
|
@ -42,7 +48,7 @@ impl TypeTermEditor {
|
||||||
ty: TypeTermVar::Any,
|
ty: TypeTermVar::Any,
|
||||||
sum_edit: Arc::new(RwLock::new(SumEditor::new(
|
sum_edit: Arc::new(RwLock::new(SumEditor::new(
|
||||||
vec![
|
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("( PosInt 10 )").unwrap(), depth + 1 ).unwrap(),
|
||||||
Context::make_editor( &ctx, ctx.read().unwrap().type_term_from_str("( Symbol )").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 {
|
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()
|
NestedNode::new()
|
||||||
.set_ctx(self.ctx.clone())
|
.set_ctx(ctx)
|
||||||
.set_nav(self.sum_edit.clone())
|
.set_nav(sum_edit)
|
||||||
.set_cmd(self.sum_edit.clone())
|
.set_cmd(editor.clone())
|
||||||
.set_view(
|
.set_view(view)
|
||||||
self.sum_edit.read().unwrap().pty_view()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Commander for TypeTermEditor {
|
impl Commander for TypeTermEditor {
|
||||||
type Cmd = TerminalEvent;
|
type Cmd = TerminalEvent;
|
||||||
|
|
||||||
fn send_cmd(&mut self, event: &TerminalEvent) {
|
fn send_cmd(&mut self, event: &TerminalEvent) {
|
||||||
match event {
|
match event {
|
||||||
TerminalEvent::Input( termion::event::Event::Key(Key::Char(c)) ) => {
|
TerminalEvent::Input( termion::event::Event::Key(Key::Char(c)) ) => {
|
||||||
|
@ -89,8 +98,9 @@ impl Commander for TypeTermEditor {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
|
/*
|
||||||
if *c == '(' {
|
if *c == '(' {
|
||||||
let _child = Arc::new(RwLock::new(TypeTermEditor {
|
let child = TypeTermEditor {
|
||||||
ctx: self.ctx.clone(),
|
ctx: self.ctx.clone(),
|
||||||
ty: self.ty.clone(),
|
ty: self.ty.clone(),
|
||||||
sum_edit: Arc::new(RwLock::new(SumEditor::new(
|
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[1].clone(),
|
||||||
self.sum_edit.read().unwrap().editors[2].clone(),
|
self.sum_edit.read().unwrap().editors[2].clone(),
|
||||||
])))
|
])))
|
||||||
}));
|
};
|
||||||
|
|
||||||
self.ty = TypeTermVar::List;
|
self.ty = TypeTermVar::List;
|
||||||
self.sum_edit.write().unwrap().select(0);
|
self.sum_edit.write().unwrap().select(0);
|
||||||
/*
|
|
||||||
let l = self.node.editors[0].clone();
|
let l = self.sum_edit.read().unwrap().editors[0].clone();
|
||||||
let l = l.downcast::<RwLock<PTYListEditor<TypeTermEditor>>>().unwrap();
|
let l = l.editor.clone().unwrap().downcast::<RwLock<ListEditor>>().unwrap();
|
||||||
l.write().unwrap().data.push(child);
|
l.write().unwrap().insert(TypeTermEditor::new(self.ctx.clone(), 1).into_node());
|
||||||
*/
|
} else {
|
||||||
} else {
|
*/
|
||||||
self.sum_edit.write().unwrap().send_cmd( event );
|
self.sum_edit.write().unwrap().send_cmd( event );
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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 },
|
|
||||||
}
|
|
|
@ -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("");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,5 +5,5 @@
|
||||||
# to the user in the error, instead of "error: invalid channel name '[toolchain]'".
|
# to the user in the error, instead of "error: invalid channel name '[toolchain]'".
|
||||||
|
|
||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "nightly-2021-10-26"
|
channel = "nightly"
|
||||||
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
|
|
||||||
|
|
|
@ -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"]
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
_ => {},
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
@ -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"]
|
|
93
shell/gram2
93
shell/gram2
|
@ -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.
|
|
||||||
|
|
|
@ -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|{ }) )
|
|
|
@ -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 {}
|
|
||||||
|
|
|
@ -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) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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!");
|
|
||||||
}
|
|
||||||
|
|
|
@ -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 {}
|
|
||||||
|
|
167
shell/src/pty.rs
167
shell/src/pty.rs
|
@ -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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue