fix warnings & format
This commit is contained in:
parent
bf8a949cdd
commit
411b773ab5
61 changed files with 2759 additions and 2741 deletions
|
@ -1,8 +1,7 @@
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{Read, Write},
|
io::{Read, Write},
|
||||||
os::unix::io::FromRawFd
|
os::unix::io::FromRawFd,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn fib(n: u64) -> u64 {
|
fn fib(n: u64) -> u64 {
|
||||||
|
@ -10,7 +9,7 @@ fn fib(n: u64) -> u64 {
|
||||||
let mut y1 = 1;
|
let mut y1 = 1;
|
||||||
let mut y2 = 0;
|
let mut y2 = 0;
|
||||||
|
|
||||||
for _ in 0 .. n {
|
for _ in 0..n {
|
||||||
y = y1 + y2;
|
y = y1 + y2;
|
||||||
y2 = y1;
|
y2 = y1;
|
||||||
y1 = y;
|
y1 = y;
|
||||||
|
@ -26,26 +25,32 @@ fn main() {
|
||||||
|
|
||||||
nested::magic_header();
|
nested::magic_header();
|
||||||
|
|
||||||
eprintln!("
|
eprintln!(
|
||||||
interface (Sequence ℕ) 0 1");
|
"
|
||||||
|
interface (Sequence ℕ) 0 1"
|
||||||
|
);
|
||||||
|
|
||||||
let mut f0 = unsafe { File::from_raw_fd(0) };
|
let mut f0 = unsafe { File::from_raw_fd(0) };
|
||||||
eprintln!("
|
eprintln!(
|
||||||
|
"
|
||||||
>0: n
|
>0: n
|
||||||
( ℕ )
|
( ℕ )
|
||||||
( MachineInt )
|
( MachineInt )
|
||||||
( MachineWord )
|
( MachineWord )
|
||||||
( Stream MachineSyllab )
|
( Stream MachineSyllab )
|
||||||
");
|
"
|
||||||
|
);
|
||||||
|
|
||||||
let mut f1 = unsafe { File::from_raw_fd(1) };
|
let mut f1 = unsafe { File::from_raw_fd(1) };
|
||||||
eprintln!("
|
eprintln!(
|
||||||
|
"
|
||||||
<1: n'th fibonacci number
|
<1: n'th fibonacci number
|
||||||
( ℕ )
|
( ℕ )
|
||||||
( MachineInt )
|
( MachineInt )
|
||||||
( MachineWord )
|
( MachineWord )
|
||||||
( Stream MachineSyllab )
|
( Stream MachineSyllab )
|
||||||
");
|
"
|
||||||
|
);
|
||||||
|
|
||||||
nested::magic_header();
|
nested::magic_header();
|
||||||
|
|
||||||
|
@ -55,4 +60,3 @@ interface (Sequence ℕ) 0 1");
|
||||||
bytes = fib(n).to_le_bytes();
|
bytes = fib(n).to_le_bytes();
|
||||||
f1.write(&bytes).expect("");
|
f1.write(&bytes).expect("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
|
use std::{fs::File, io::Read, os::unix::io::FromRawFd};
|
||||||
use std::{
|
|
||||||
fs::File,
|
|
||||||
io::{Read},
|
|
||||||
os::unix::io::FromRawFd
|
|
||||||
};
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
nested::magic_header();
|
nested::magic_header();
|
||||||
|
@ -11,15 +6,18 @@ fn main() {
|
||||||
nested::magic_header();
|
nested::magic_header();
|
||||||
|
|
||||||
let mut f0 = unsafe { File::from_raw_fd(0) };
|
let mut f0 = unsafe { File::from_raw_fd(0) };
|
||||||
eprintln!("
|
eprintln!(
|
||||||
|
"
|
||||||
>0:
|
>0:
|
||||||
( ℕ )
|
( ℕ )
|
||||||
( MachineInt )
|
( MachineInt )
|
||||||
( MachineWord )
|
( MachineWord )
|
||||||
( Stream MachineSyllab )
|
( Stream MachineSyllab )
|
||||||
");
|
"
|
||||||
|
);
|
||||||
|
|
||||||
eprintln!("
|
eprintln!(
|
||||||
|
"
|
||||||
<1:
|
<1:
|
||||||
( ℕ )
|
( ℕ )
|
||||||
( PositionalInt 10 BigEndian )
|
( PositionalInt 10 BigEndian )
|
||||||
|
@ -27,7 +25,8 @@ fn main() {
|
||||||
( Sequence UTF-8-Char )
|
( Sequence UTF-8-Char )
|
||||||
( Stream UTF-8-Char )
|
( Stream UTF-8-Char )
|
||||||
( Stream MachineSyllab )
|
( Stream MachineSyllab )
|
||||||
");
|
"
|
||||||
|
);
|
||||||
|
|
||||||
nested::magic_header();
|
nested::magic_header();
|
||||||
|
|
||||||
|
@ -35,4 +34,3 @@ fn main() {
|
||||||
f0.read_exact(&mut bytes).expect("");
|
f0.read_exact(&mut bytes).expect("");
|
||||||
println!("{}", u64::from_le_bytes(bytes));
|
println!("{}", u64::from_le_bytes(bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,55 +1,68 @@
|
||||||
|
use nested::{
|
||||||
use {
|
core::{TypeDict, ViewPort},
|
||||||
nested::{
|
integer::RadixProjection,
|
||||||
core::{
|
vec::VecBuffer,
|
||||||
ViewPort,
|
|
||||||
TypeDict
|
|
||||||
},
|
|
||||||
vec::{VecBuffer},
|
|
||||||
integer::{RadixProjection}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[async_std::main]
|
#[async_std::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
let mut td = TypeDict::new();
|
let mut td = TypeDict::new();
|
||||||
for tn in vec![
|
for tn in vec![
|
||||||
"MachineWord", "MachineInt", "MachineSyllab",
|
"MachineWord",
|
||||||
"Vec", "Stream", "Json",
|
"MachineInt",
|
||||||
"Sequence", "UTF-8-Char",
|
"MachineSyllab",
|
||||||
"PositionalInt", "Digit", "LittleEndian", "BigEndian",
|
"Vec",
|
||||||
"DiffStream", "ℕ",
|
"Stream",
|
||||||
"$src_radix", "$dst_radix"
|
"Json",
|
||||||
] { td.add_typename(tn.into()); }
|
"Sequence",
|
||||||
|
"UTF-8-Char",
|
||||||
|
"PositionalInt",
|
||||||
|
"Digit",
|
||||||
|
"LittleEndian",
|
||||||
|
"BigEndian",
|
||||||
|
"DiffStream",
|
||||||
|
"ℕ",
|
||||||
|
"$src_radix",
|
||||||
|
"$dst_radix",
|
||||||
|
] {
|
||||||
|
td.add_typename(tn.into());
|
||||||
|
}
|
||||||
|
|
||||||
let radix_types = vec![
|
let radix_types = vec![
|
||||||
td.type_term_from_str("( ℕ )").unwrap(),
|
td.type_term_from_str("( ℕ )").unwrap(),
|
||||||
td.type_term_from_str("( PositionalInt 10 LittleEndian )").unwrap(),
|
td.type_term_from_str("( PositionalInt 10 LittleEndian )")
|
||||||
|
.unwrap(),
|
||||||
td.type_term_from_str("( Sequence ( Digit 10 ) )").unwrap(),
|
td.type_term_from_str("( Sequence ( Digit 10 ) )").unwrap(),
|
||||||
td.type_term_from_str("( Sequence UTF-8-Char )").unwrap(),
|
td.type_term_from_str("( Sequence UTF-8-Char )").unwrap(),
|
||||||
td.type_term_from_str("( Sequence MachineSyllab )").unwrap()
|
td.type_term_from_str("( Sequence MachineSyllab )").unwrap(),
|
||||||
];
|
];
|
||||||
|
|
||||||
let src_types = vec![
|
let src_types = vec![
|
||||||
td.type_term_from_str("( ℕ )").unwrap(),
|
td.type_term_from_str("( ℕ )").unwrap(),
|
||||||
td.type_term_from_str("( PositionalInt $src_radix LittleEndian )").unwrap(),
|
td.type_term_from_str("( PositionalInt $src_radix LittleEndian )")
|
||||||
td.type_term_from_str("( Sequence ( Digit $src_radix ) )").unwrap(),
|
.unwrap(),
|
||||||
|
td.type_term_from_str("( Sequence ( Digit $src_radix ) )")
|
||||||
|
.unwrap(),
|
||||||
td.type_term_from_str("( Sequence MachineInt )").unwrap(),
|
td.type_term_from_str("( Sequence MachineInt )").unwrap(),
|
||||||
td.type_term_from_str("( DiffStream ( Vec MachineInt ) )").unwrap(),
|
td.type_term_from_str("( DiffStream ( Vec MachineInt ) )")
|
||||||
|
.unwrap(),
|
||||||
td.type_term_from_str("( Json )").unwrap(),
|
td.type_term_from_str("( Json )").unwrap(),
|
||||||
td.type_term_from_str("( Stream UTF-8-Char )").unwrap(),
|
td.type_term_from_str("( Stream UTF-8-Char )").unwrap(),
|
||||||
td.type_term_from_str("( Stream MachineSyllab )").unwrap()
|
td.type_term_from_str("( Stream MachineSyllab )").unwrap(),
|
||||||
];
|
];
|
||||||
|
|
||||||
let dst_types = vec![
|
let dst_types = vec![
|
||||||
td.type_term_from_str("( ℕ )").unwrap(),
|
td.type_term_from_str("( ℕ )").unwrap(),
|
||||||
td.type_term_from_str("( PositionalInt $dst_radix LittleEndian )").unwrap(),
|
td.type_term_from_str("( PositionalInt $dst_radix LittleEndian )")
|
||||||
td.type_term_from_str("( Sequence ( Digit $dst_radix ) )").unwrap(),
|
.unwrap(),
|
||||||
|
td.type_term_from_str("( Sequence ( Digit $dst_radix ) )")
|
||||||
|
.unwrap(),
|
||||||
td.type_term_from_str("( Sequence MachineInt )").unwrap(),
|
td.type_term_from_str("( Sequence MachineInt )").unwrap(),
|
||||||
td.type_term_from_str("( DiffStream ( Vec MachineInt ) )").unwrap(),
|
td.type_term_from_str("( DiffStream ( Vec MachineInt ) )")
|
||||||
|
.unwrap(),
|
||||||
td.type_term_from_str("( Json )").unwrap(),
|
td.type_term_from_str("( Json )").unwrap(),
|
||||||
td.type_term_from_str("( Stream UTF-8-Char )").unwrap(),
|
td.type_term_from_str("( Stream UTF-8-Char )").unwrap(),
|
||||||
td.type_term_from_str("( Stream MachineSyllab )").unwrap()
|
td.type_term_from_str("( Stream MachineSyllab )").unwrap(),
|
||||||
];
|
];
|
||||||
|
|
||||||
nested::magic_header();
|
nested::magic_header();
|
||||||
|
@ -99,27 +112,26 @@ async fn main() {
|
||||||
src_radix,
|
src_radix,
|
||||||
dst_radix,
|
dst_radix,
|
||||||
src_digits_port.outer().to_sequence(),
|
src_digits_port.outer().to_sequence(),
|
||||||
dst_digits_port.inner()
|
dst_digits_port.inner(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// output dst digits
|
// output dst digits
|
||||||
let writer = {
|
let writer = {
|
||||||
use std::{
|
use std::os::unix::io::FromRawFd;
|
||||||
os::unix::io::FromRawFd
|
|
||||||
};
|
|
||||||
|
|
||||||
dst_digits_port.outer().serialize_json(unsafe { std::fs::File::from_raw_fd(1) })
|
dst_digits_port
|
||||||
|
.outer()
|
||||||
|
.serialize_json(unsafe { std::fs::File::from_raw_fd(1) })
|
||||||
};
|
};
|
||||||
|
|
||||||
// start reading src digits
|
// start reading src digits
|
||||||
{
|
{
|
||||||
use async_std::{
|
use async_std::os::unix::io::FromRawFd;
|
||||||
os::unix::io::FromRawFd
|
|
||||||
};
|
|
||||||
|
|
||||||
src_digits.from_json(unsafe { async_std::fs::File::from_raw_fd(0) }).await;
|
src_digits
|
||||||
|
.from_json(unsafe { async_std::fs::File::from_raw_fd(0) })
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
drop(writer);
|
drop(writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{Read, Write},
|
io::{Read, Write},
|
||||||
os::unix::io::FromRawFd
|
os::unix::io::FromRawFd,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -10,16 +9,19 @@ fn main() {
|
||||||
eprintln!(" Parse MachineInt from String");
|
eprintln!(" Parse MachineInt from String");
|
||||||
nested::magic_header();
|
nested::magic_header();
|
||||||
|
|
||||||
eprintln!("
|
eprintln!(
|
||||||
|
"
|
||||||
$1: radix
|
$1: radix
|
||||||
( ℕ )
|
( ℕ )
|
||||||
( PositionalInt 10 BigEndian )
|
( PositionalInt 10 BigEndian )
|
||||||
( Sequence ( Digit 10 ) )
|
( Sequence ( Digit 10 ) )
|
||||||
( Sequence UTF-8-Char )
|
( Sequence UTF-8-Char )
|
||||||
( Sequence MachineSyllab )
|
( Sequence MachineSyllab )
|
||||||
");
|
"
|
||||||
|
);
|
||||||
|
|
||||||
eprintln!("
|
eprintln!(
|
||||||
|
"
|
||||||
>0: n
|
>0: n
|
||||||
( ℕ )
|
( ℕ )
|
||||||
( PositionalInt $radix BigEndian )
|
( PositionalInt $radix BigEndian )
|
||||||
|
@ -27,15 +29,18 @@ $1: radix
|
||||||
( Sequence UTF-8-Char )
|
( Sequence UTF-8-Char )
|
||||||
( Stream UTF-8-Char )
|
( Stream UTF-8-Char )
|
||||||
( Stream MachineSyllab )
|
( Stream MachineSyllab )
|
||||||
");
|
"
|
||||||
|
);
|
||||||
|
|
||||||
eprintln!("
|
eprintln!(
|
||||||
|
"
|
||||||
<1: n
|
<1: n
|
||||||
( ℕ )
|
( ℕ )
|
||||||
( MachineInt )
|
( MachineInt )
|
||||||
( MachineWord )
|
( MachineWord )
|
||||||
( Stream MachineSyllab )
|
( Stream MachineSyllab )
|
||||||
");
|
"
|
||||||
|
);
|
||||||
|
|
||||||
nested::magic_header();
|
nested::magic_header();
|
||||||
|
|
||||||
|
@ -55,6 +60,10 @@ $1: radix
|
||||||
let mut chars = Vec::new();
|
let mut chars = Vec::new();
|
||||||
f0.read_to_end(&mut chars).expect("");
|
f0.read_to_end(&mut chars).expect("");
|
||||||
chars.retain(|c| (*c as char).is_alphanumeric());
|
chars.retain(|c| (*c as char).is_alphanumeric());
|
||||||
f1.write(&u64::from_str_radix(&String::from_utf8_lossy(&chars), radix).unwrap().to_le_bytes()).expect("");
|
f1.write(
|
||||||
|
&u64::from_str_radix(&String::from_utf8_lossy(&chars), radix)
|
||||||
|
.unwrap()
|
||||||
|
.to_le_bytes(),
|
||||||
|
)
|
||||||
|
.expect("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,17 @@
|
||||||
use std::{
|
use std::{collections::HashMap, hash::Hash};
|
||||||
collections::HashMap,
|
|
||||||
hash::Hash
|
|
||||||
};
|
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub struct Bimap<V: Eq + Hash, Λ: Eq + Hash> {
|
pub struct Bimap<V: Eq + Hash, Λ: Eq + Hash> {
|
||||||
pub mλ: HashMap::<V, Λ>,
|
pub mλ: HashMap<V, Λ>,
|
||||||
pub my: HashMap::<Λ, V>
|
pub my: HashMap<Λ, V>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: Eq + Hash + Clone, Λ: Eq + Hash + Clone> Bimap<V, Λ> {
|
impl<V: Eq + Hash + Clone, Λ: Eq + Hash + Clone> Bimap<V, Λ> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Bimap {
|
Bimap {
|
||||||
mλ: HashMap::new(),
|
mλ: HashMap::new(),
|
||||||
my: HashMap::new()
|
my: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,4 +22,3 @@ impl<V: Eq + Hash + Clone, Λ: Eq + Hash + Clone> Bimap<V, Λ> {
|
||||||
}
|
}
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
|
|
|
@ -1,70 +1,69 @@
|
||||||
use {
|
use {
|
||||||
|
crate::core::Observer,
|
||||||
|
async_std::stream::Stream,
|
||||||
core::{
|
core::{
|
||||||
task::{Poll, Context, Waker},
|
pin::Pin,
|
||||||
pin::Pin
|
task::{Context, Poll, Waker},
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
sync::{Arc, Mutex},
|
|
||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
hash::Hash
|
hash::Hash,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
},
|
},
|
||||||
async_std::{
|
|
||||||
stream::Stream
|
|
||||||
},
|
|
||||||
|
|
||||||
crate::{
|
|
||||||
core::{Observer}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*\
|
||||||
/*\
|
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
Traits
|
Traits
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
\*/
|
\*/
|
||||||
pub trait ChannelData : Default + IntoIterator + Send + Sync {
|
pub trait ChannelData: Default + IntoIterator + Send + Sync {
|
||||||
fn channel_insert(&mut self, x: Self::Item);
|
fn channel_insert(&mut self, x: Self::Item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*\
|
||||||
/*\
|
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
Queue Channel
|
Queue Channel
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
\*/
|
\*/
|
||||||
impl<T> ChannelData for Vec<T>
|
impl<T> ChannelData for Vec<T>
|
||||||
where T: Send + Sync {
|
where
|
||||||
|
T: Send + Sync,
|
||||||
|
{
|
||||||
fn channel_insert(&mut self, x: T) {
|
fn channel_insert(&mut self, x: T) {
|
||||||
self.push(x);
|
self.push(x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*\
|
/*\
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
Set Channel
|
Set Channel
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
\*/
|
\*/
|
||||||
impl<T> ChannelData for HashSet<T>
|
impl<T> ChannelData for HashSet<T>
|
||||||
where T: Eq + Hash + Send + Sync {
|
where
|
||||||
|
T: Eq + Hash + Send + Sync,
|
||||||
|
{
|
||||||
fn channel_insert(&mut self, x: T) {
|
fn channel_insert(&mut self, x: T) {
|
||||||
self.insert(x);
|
self.insert(x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*\
|
/*\
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
Singleton Channel
|
Singleton Channel
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
\*/
|
\*/
|
||||||
impl<T> ChannelData for Option<T>
|
impl<T> ChannelData for Option<T>
|
||||||
where T: Send + Sync {
|
where
|
||||||
|
T: Send + Sync,
|
||||||
|
{
|
||||||
fn channel_insert(&mut self, x: T) {
|
fn channel_insert(&mut self, x: T) {
|
||||||
*self = Some(x);
|
*self = Some(x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*\
|
/*\
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
Channel
|
Channel
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
@ -73,7 +72,7 @@ struct ChannelState<Data: ChannelData> {
|
||||||
send_buf: Option<Data>,
|
send_buf: Option<Data>,
|
||||||
recv_iter: Option<Data::IntoIter>,
|
recv_iter: Option<Data::IntoIter>,
|
||||||
num_senders: usize,
|
num_senders: usize,
|
||||||
waker: Option<Waker>
|
waker: Option<Waker>,
|
||||||
}
|
}
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
@ -84,7 +83,9 @@ pub struct ChannelReceiver<Data: ChannelData>(Arc<Mutex<ChannelState<Data>>>);
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl<Data: ChannelData> ChannelSender<Data>
|
impl<Data: ChannelData> ChannelSender<Data>
|
||||||
where Data::IntoIter: Send + Sync {
|
where
|
||||||
|
Data::IntoIter: Send + Sync,
|
||||||
|
{
|
||||||
pub fn send(&self, msg: Data::Item) {
|
pub fn send(&self, msg: Data::Item) {
|
||||||
let mut state = self.0.lock().unwrap();
|
let mut state = self.0.lock().unwrap();
|
||||||
|
|
||||||
|
@ -102,7 +103,10 @@ where Data::IntoIter: Send + Sync {
|
||||||
|
|
||||||
use crate::core::View;
|
use crate::core::View;
|
||||||
impl<V: View + ?Sized, Data: ChannelData<Item = V::Msg>> Observer<V> for ChannelSender<Data>
|
impl<V: View + ?Sized, Data: ChannelData<Item = V::Msg>> Observer<V> for ChannelSender<Data>
|
||||||
where V::Msg: Clone, Data::IntoIter: Send + Sync {
|
where
|
||||||
|
V::Msg: Clone,
|
||||||
|
Data::IntoIter: Send + Sync,
|
||||||
|
{
|
||||||
fn notify(&mut self, msg: &V::Msg) {
|
fn notify(&mut self, msg: &V::Msg) {
|
||||||
self.send(msg.clone());
|
self.send(msg.clone());
|
||||||
}
|
}
|
||||||
|
@ -164,15 +168,12 @@ impl<Data: ChannelData> std::future::Future for ChannelRead<Data> {
|
||||||
impl<Data: ChannelData> Stream for ChannelReceiver<Data> {
|
impl<Data: ChannelData> Stream for ChannelReceiver<Data> {
|
||||||
type Item = Data::Item;
|
type Item = Data::Item;
|
||||||
|
|
||||||
fn poll_next(
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>
|
|
||||||
) -> Poll<Option<Self::Item>> {
|
|
||||||
let mut state = self.0.lock().unwrap();
|
let mut state = self.0.lock().unwrap();
|
||||||
|
|
||||||
if let Some(recv_iter) = state.recv_iter.as_mut() {
|
if let Some(recv_iter) = state.recv_iter.as_mut() {
|
||||||
if let Some(val) = recv_iter.next() {
|
if let Some(val) = recv_iter.next() {
|
||||||
return Poll::Ready(Some(val))
|
return Poll::Ready(Some(val));
|
||||||
} else {
|
} else {
|
||||||
state.recv_iter = None
|
state.recv_iter = None
|
||||||
}
|
}
|
||||||
|
@ -191,23 +192,24 @@ impl<Data: ChannelData> Stream for ChannelReceiver<Data> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*\
|
/*\
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
Factory Functions
|
Factory Functions
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
\*/
|
\*/
|
||||||
pub fn channel<Data: ChannelData>() -> (ChannelSender<Data>, ChannelReceiver<Data>) {
|
pub fn channel<Data: ChannelData>() -> (ChannelSender<Data>, ChannelReceiver<Data>) {
|
||||||
let state = Arc::new(Mutex::new(ChannelState{
|
let state = Arc::new(Mutex::new(ChannelState {
|
||||||
send_buf: None,
|
send_buf: None,
|
||||||
recv_iter: None,
|
recv_iter: None,
|
||||||
num_senders: 1,
|
num_senders: 1,
|
||||||
waker: None
|
waker: None,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
(ChannelSender(state.clone()), ChannelReceiver(state))
|
(ChannelSender(state.clone()), ChannelReceiver(state))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_channel<T: Eq + Hash + Send + Sync>() -> (ChannelSender<HashSet<T>>, ChannelReceiver<HashSet<T>>) {
|
pub fn set_channel<T: Eq + Hash + Send + Sync>(
|
||||||
|
) -> (ChannelSender<HashSet<T>>, ChannelReceiver<HashSet<T>>) {
|
||||||
channel::<HashSet<T>>()
|
channel::<HashSet<T>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,7 +217,7 @@ pub fn queue_channel<T: Send + Sync>() -> (ChannelSender<Vec<T>>, ChannelReceive
|
||||||
channel::<Vec<T>>()
|
channel::<Vec<T>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn singleton_channel<T: Send + Sync>() -> (ChannelSender<Option<T>>, ChannelReceiver<Option<T>>) {
|
pub fn singleton_channel<T: Send + Sync>() -> (ChannelSender<Option<T>>, ChannelReceiver<Option<T>>)
|
||||||
|
{
|
||||||
channel::<Option<T>>()
|
channel::<Option<T>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,12 @@
|
||||||
use {
|
use {
|
||||||
|
crate::core::{
|
||||||
|
type_term::{TypeDict, TypeTerm},
|
||||||
|
AnyOuterViewPort, OuterViewPort, View,
|
||||||
|
},
|
||||||
std::{
|
std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
sync::{Arc, RwLock}
|
sync::{Arc, RwLock},
|
||||||
},
|
},
|
||||||
crate::{
|
|
||||||
core::{
|
|
||||||
type_term::{
|
|
||||||
TypeTerm,
|
|
||||||
TypeDict
|
|
||||||
},
|
|
||||||
View,
|
|
||||||
OuterViewPort,
|
|
||||||
AnyOuterViewPort
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
@ -21,37 +14,31 @@ use {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ReprTree {
|
pub struct ReprTree {
|
||||||
port: Option<AnyOuterViewPort>,
|
port: Option<AnyOuterViewPort>,
|
||||||
branches: HashMap<TypeTerm, Arc<RwLock<ReprTree>>>
|
branches: HashMap<TypeTerm, Arc<RwLock<ReprTree>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReprTree {
|
impl ReprTree {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
ReprTree {
|
ReprTree {
|
||||||
port: None,
|
port: None,
|
||||||
branches: HashMap::new()
|
branches: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_leaf(
|
pub fn new_leaf(port: AnyOuterViewPort) -> Arc<RwLock<Self>> {
|
||||||
port: AnyOuterViewPort
|
|
||||||
) -> Arc<RwLock<Self>> {
|
|
||||||
let mut tree = ReprTree::new();
|
let mut tree = ReprTree::new();
|
||||||
tree.insert_leaf(vec![].into_iter(), port);
|
tree.insert_leaf(vec![].into_iter(), port);
|
||||||
Arc::new(RwLock::new(tree))
|
Arc::new(RwLock::new(tree))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_branch(
|
pub fn insert_branch(&mut self, type_tag: TypeTerm, repr: Arc<RwLock<ReprTree>>) {
|
||||||
&mut self,
|
|
||||||
type_tag: TypeTerm,
|
|
||||||
repr: Arc<RwLock<ReprTree>>
|
|
||||||
) {
|
|
||||||
self.branches.insert(type_tag, repr);
|
self.branches.insert(type_tag, repr);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_leaf(
|
pub fn insert_leaf(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut type_ladder: impl Iterator<Item = TypeTerm>,
|
mut type_ladder: impl Iterator<Item = TypeTerm>,
|
||||||
port: AnyOuterViewPort
|
port: AnyOuterViewPort,
|
||||||
) {
|
) {
|
||||||
if let Some(type_term) = type_ladder.next() {
|
if let Some(type_term) = type_ladder.next() {
|
||||||
if let Some(next_repr) = self.branches.get(&type_term) {
|
if let Some(next_repr) = self.branches.get(&type_term) {
|
||||||
|
@ -72,39 +59,45 @@ impl ReprTree {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Object {
|
pub struct Object {
|
||||||
pub type_tag: TypeTerm,
|
pub type_tag: TypeTerm,
|
||||||
pub repr: Arc<RwLock<ReprTree>>
|
pub repr: Arc<RwLock<ReprTree>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Object {
|
impl Object {
|
||||||
pub fn get_port<V: View + ?Sized + 'static>(&self) -> Option<OuterViewPort<V>> where V::Msg: Clone {
|
pub fn get_port<V: View + ?Sized + 'static>(&self) -> Option<OuterViewPort<V>>
|
||||||
Some(self.repr.read().unwrap().port.clone()?.downcast::<V>().ok().unwrap())
|
where
|
||||||
|
V::Msg: Clone,
|
||||||
|
{
|
||||||
|
Some(
|
||||||
|
self.repr
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.port
|
||||||
|
.clone()?
|
||||||
|
.downcast::<V>()
|
||||||
|
.ok()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn downcast(&self, dst_type: TypeTerm) -> Option<Object> {
|
pub fn downcast(&self, dst_type: TypeTerm) -> Option<Object> {
|
||||||
if let Some(repr) = self.repr.read().unwrap().branches.get(&dst_type) {
|
if let Some(repr) = self.repr.read().unwrap().branches.get(&dst_type) {
|
||||||
Some(Object {
|
Some(Object {
|
||||||
type_tag: dst_type,
|
type_tag: dst_type,
|
||||||
repr: repr.clone()
|
repr: repr.clone(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn downcast_ladder(
|
fn downcast_ladder(&self, repr_ladder: impl Iterator<Item = TypeTerm>) -> Option<Object> {
|
||||||
&self,
|
repr_ladder.fold(Some(self.clone()), |s, t| s?.downcast(t.clone()))
|
||||||
repr_ladder: impl Iterator<Item = TypeTerm>
|
|
||||||
) -> Option<Object> {
|
|
||||||
repr_ladder.fold(
|
|
||||||
Some(self.clone()),
|
|
||||||
|s, t| s?.downcast(t.clone())
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_iso_repr(
|
pub fn add_iso_repr(
|
||||||
&self,
|
&self,
|
||||||
type_ladder: impl Iterator<Item = TypeTerm>,
|
type_ladder: impl Iterator<Item = TypeTerm>,
|
||||||
morphism_constructors: &HashMap<MorphismType, Box<dyn Fn(Object) -> Object>>
|
morphism_constructors: &HashMap<MorphismType, Box<dyn Fn(Object) -> Object>>,
|
||||||
) {
|
) {
|
||||||
let mut cur_repr = self.repr.clone();
|
let mut cur_repr = self.repr.clone();
|
||||||
|
|
||||||
|
@ -117,21 +110,21 @@ impl Object {
|
||||||
let mut obj = None;
|
let mut obj = None;
|
||||||
|
|
||||||
for src_type in cur_repr.read().unwrap().branches.keys() {
|
for src_type in cur_repr.read().unwrap().branches.keys() {
|
||||||
if let Some(ctor) = morphism_constructors.get(
|
if let Some(ctor) = morphism_constructors.get(&MorphismType {
|
||||||
&MorphismType {
|
mode: MorphismMode::Iso,
|
||||||
mode: MorphismMode::Iso,
|
src_type: src_type.clone(),
|
||||||
src_type: src_type.clone(),
|
dst_type: dst_type.clone(),
|
||||||
dst_type: dst_type.clone()
|
}) {
|
||||||
}
|
let new_obj = ctor(Object {
|
||||||
) {
|
type_tag: src_type.clone(),
|
||||||
let new_obj = ctor(
|
repr: cur_repr
|
||||||
Object {
|
.read()
|
||||||
type_tag: src_type.clone(),
|
.unwrap()
|
||||||
repr: cur_repr.read().unwrap()
|
.branches
|
||||||
.branches
|
.get(&src_type)
|
||||||
.get(&src_type).unwrap().clone()
|
.unwrap()
|
||||||
}
|
.clone(),
|
||||||
);
|
});
|
||||||
|
|
||||||
assert!(new_obj.type_tag == dst_type);
|
assert!(new_obj.type_tag == dst_type);
|
||||||
|
|
||||||
|
@ -141,7 +134,10 @@ impl Object {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(obj) = obj {
|
if let Some(obj) = obj {
|
||||||
cur_repr.write().unwrap().insert_branch(obj.type_tag, obj.repr);
|
cur_repr
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.insert_branch(obj.type_tag, obj.repr);
|
||||||
} else {
|
} else {
|
||||||
panic!("could not find matching isomorphism!");
|
panic!("could not find matching isomorphism!");
|
||||||
}
|
}
|
||||||
|
@ -152,7 +148,7 @@ impl Object {
|
||||||
pub fn add_mono_repr<'a>(
|
pub fn add_mono_repr<'a>(
|
||||||
&self,
|
&self,
|
||||||
type_ladder: impl Iterator<Item = TypeTerm>,
|
type_ladder: impl Iterator<Item = TypeTerm>,
|
||||||
morphism_constructors: &HashMap<MorphismType, Box<dyn Fn(Object) -> Object>>
|
morphism_constructors: &HashMap<MorphismType, Box<dyn Fn(Object) -> Object>>,
|
||||||
) {
|
) {
|
||||||
let mut cur_type = self.type_tag.clone();
|
let mut cur_type = self.type_tag.clone();
|
||||||
let mut cur_repr = self.repr.clone();
|
let mut cur_repr = self.repr.clone();
|
||||||
|
@ -163,24 +159,27 @@ impl Object {
|
||||||
cur_type = dst_type;
|
cur_type = dst_type;
|
||||||
cur_repr = next_repr.clone();
|
cur_repr = next_repr.clone();
|
||||||
} else {
|
} else {
|
||||||
if let Some(constructor) = morphism_constructors.get(
|
if let Some(constructor) = morphism_constructors.get(&MorphismType {
|
||||||
&MorphismType {
|
mode: MorphismMode::Mono,
|
||||||
mode: MorphismMode::Mono,
|
src_type: cur_type.clone(),
|
||||||
src_type: cur_type.clone(),
|
dst_type: dst_type.clone(),
|
||||||
dst_type: dst_type.clone()
|
}) {
|
||||||
}
|
let new_obj = constructor(Object {
|
||||||
) {
|
type_tag: cur_type.clone(),
|
||||||
let new_obj = constructor(
|
repr: cur_repr
|
||||||
Object {
|
.read()
|
||||||
type_tag: cur_type.clone(),
|
.unwrap()
|
||||||
repr: cur_repr.read().unwrap()
|
.branches
|
||||||
.branches
|
.get(&cur_type)
|
||||||
.get(&cur_type).unwrap().clone()
|
.unwrap()
|
||||||
}
|
.clone(),
|
||||||
);
|
});
|
||||||
|
|
||||||
assert!(new_obj.type_tag == dst_type);
|
assert!(new_obj.type_tag == dst_type);
|
||||||
cur_repr.write().unwrap().insert_branch(new_obj.type_tag.clone(), new_obj.repr.clone());
|
cur_repr
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.insert_branch(new_obj.type_tag.clone(), new_obj.repr.clone());
|
||||||
|
|
||||||
cur_type = new_obj.type_tag;
|
cur_type = new_obj.type_tag;
|
||||||
cur_repr = new_obj.repr;
|
cur_repr = new_obj.repr;
|
||||||
|
@ -193,7 +192,7 @@ impl Object {
|
||||||
pub fn epi_cast<'a>(
|
pub fn epi_cast<'a>(
|
||||||
&self,
|
&self,
|
||||||
_type_ladder: impl Iterator<Item = TypeTerm>,
|
_type_ladder: impl Iterator<Item = TypeTerm>,
|
||||||
_morphism_constructors: &HashMap<MorphismType, Box<dyn Fn(Object) -> Object>>
|
_morphism_constructors: &HashMap<MorphismType, Box<dyn Fn(Object) -> Object>>,
|
||||||
) {
|
) {
|
||||||
// todo
|
// todo
|
||||||
}
|
}
|
||||||
|
@ -220,14 +219,14 @@ pub enum MorphismMode {
|
||||||
Epi,
|
Epi,
|
||||||
|
|
||||||
/// Any other function
|
/// Any other function
|
||||||
Any
|
Any,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Hash, PartialEq, Eq)]
|
#[derive(Clone, Hash, PartialEq, Eq)]
|
||||||
pub struct MorphismType {
|
pub struct MorphismType {
|
||||||
pub mode: MorphismMode,
|
pub mode: MorphismMode,
|
||||||
pub src_type: TypeTerm,
|
pub src_type: TypeTerm,
|
||||||
pub dst_type: TypeTerm
|
pub dst_type: TypeTerm,
|
||||||
}
|
}
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
@ -237,7 +236,7 @@ pub struct Context {
|
||||||
default_constructors: HashMap<TypeTerm, Box<dyn Fn() -> Object + Send + Sync>>,
|
default_constructors: HashMap<TypeTerm, Box<dyn Fn() -> Object + Send + Sync>>,
|
||||||
morphism_constructors: HashMap<MorphismType, Box<dyn Fn(Object) -> Object + Send + Sync>>,
|
morphism_constructors: HashMap<MorphismType, Box<dyn Fn(Object) -> Object + Send + Sync>>,
|
||||||
objects: HashMap<String, Object>,
|
objects: HashMap<String, Object>,
|
||||||
parent: Option<Arc<RwLock<Context>>>
|
parent: Option<Arc<RwLock<Context>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
|
@ -247,7 +246,7 @@ impl Context {
|
||||||
default_constructors: HashMap::new(),
|
default_constructors: HashMap::new(),
|
||||||
morphism_constructors: HashMap::new(),
|
morphism_constructors: HashMap::new(),
|
||||||
objects: HashMap::new(),
|
objects: HashMap::new(),
|
||||||
parent
|
parent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,17 +265,13 @@ impl Context {
|
||||||
pub fn add_morphism(
|
pub fn add_morphism(
|
||||||
&mut self,
|
&mut self,
|
||||||
morph_type: MorphismType,
|
morph_type: MorphismType,
|
||||||
morph_fn: Box<dyn Fn(Object) -> Object + Send + Sync>
|
morph_fn: Box<dyn Fn(Object) -> Object + Send + Sync>,
|
||||||
) {
|
) {
|
||||||
self.morphism_constructors.insert(morph_type, morph_fn);
|
self.morphism_constructors.insert(morph_type, morph_fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// adds an object without any representations
|
/// adds an object without any representations
|
||||||
pub fn add_obj(
|
pub fn add_obj(&mut self, name: String, typename: &str) {
|
||||||
&mut self,
|
|
||||||
name: String,
|
|
||||||
typename: &str
|
|
||||||
) {
|
|
||||||
let type_tag = self.type_dict.type_term_from_str(typename).unwrap();
|
let type_tag = self.type_dict.type_term_from_str(typename).unwrap();
|
||||||
|
|
||||||
self.objects.insert(
|
self.objects.insert(
|
||||||
|
@ -286,16 +281,13 @@ impl Context {
|
||||||
} else {
|
} else {
|
||||||
Object {
|
Object {
|
||||||
type_tag,
|
type_tag,
|
||||||
repr: Arc::new(RwLock::new(ReprTree::new()))
|
repr: Arc::new(RwLock::new(ReprTree::new())),
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_obj(
|
pub fn get_obj(&self, name: &String) -> Option<Object> {
|
||||||
&self,
|
|
||||||
name: &String
|
|
||||||
) -> Option<Object> {
|
|
||||||
if let Some(obj) = self.objects.get(name) {
|
if let Some(obj) = self.objects.get(name) {
|
||||||
Some(obj.clone())
|
Some(obj.clone())
|
||||||
} else if let Some(parent) = self.parent.as_ref() {
|
} else if let Some(parent) = self.parent.as_ref() {
|
||||||
|
@ -305,19 +297,16 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_obj_port<
|
pub fn get_obj_port<'a, V: View + ?Sized + 'static>(
|
||||||
'a,
|
|
||||||
V: View + ?Sized + 'static
|
|
||||||
>(
|
|
||||||
&self,
|
&self,
|
||||||
name: &str,
|
name: &str,
|
||||||
type_ladder: impl Iterator<Item = &'a str>
|
type_ladder: impl Iterator<Item = &'a str>,
|
||||||
) -> Option<OuterViewPort<V>>
|
) -> Option<OuterViewPort<V>>
|
||||||
where V::Msg: Clone {
|
where
|
||||||
|
V::Msg: Clone,
|
||||||
|
{
|
||||||
self.get_obj(&name.into())?
|
self.get_obj(&name.into())?
|
||||||
.downcast_ladder(
|
.downcast_ladder(type_ladder.map(|tn| self.type_dict.type_term_from_str(tn).unwrap()))?
|
||||||
type_ladder.map(|tn| self.type_dict.type_term_from_str(tn).unwrap())
|
|
||||||
)?
|
|
||||||
.get_port()
|
.get_port()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,43 +314,40 @@ impl Context {
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &str,
|
name: &str,
|
||||||
type_ladder: impl Iterator<Item = &'a str>,
|
type_ladder: impl Iterator<Item = &'a str>,
|
||||||
port: AnyOuterViewPort
|
port: AnyOuterViewPort,
|
||||||
) {
|
) {
|
||||||
self.get_obj(&name.to_string()).unwrap()
|
self.get_obj(&name.to_string())
|
||||||
.repr.write().unwrap()
|
.unwrap()
|
||||||
|
.repr
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
.insert_leaf(
|
.insert_leaf(
|
||||||
type_ladder.map(|tn| self.type_dict.type_term_from_str(tn).unwrap()),
|
type_ladder.map(|tn| self.type_dict.type_term_from_str(tn).unwrap()),
|
||||||
port
|
port,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn epi_cast(
|
pub fn epi_cast(&mut self, name: &str, typename: &str) {
|
||||||
&mut self,
|
|
||||||
name: &str,
|
|
||||||
typename: &str
|
|
||||||
) {
|
|
||||||
let dst_type = self.type_dict.type_term_from_str(typename).unwrap();
|
let dst_type = self.type_dict.type_term_from_str(typename).unwrap();
|
||||||
let old_obj = self.objects.get(&name.to_string()).unwrap().clone();
|
let old_obj = self.objects.get(&name.to_string()).unwrap().clone();
|
||||||
let new_obj =
|
let new_obj = if let Some(ctor) = self.morphism_constructors.get(&MorphismType {
|
||||||
if let Some(ctor) = self.morphism_constructors.get(
|
mode: MorphismMode::Epi,
|
||||||
&MorphismType {
|
src_type: old_obj.type_tag.clone(),
|
||||||
mode: MorphismMode::Epi,
|
dst_type: dst_type.clone(),
|
||||||
src_type: old_obj.type_tag.clone(),
|
}) {
|
||||||
dst_type: dst_type.clone()
|
ctor(old_obj.clone())
|
||||||
}
|
} else {
|
||||||
) {
|
Object {
|
||||||
ctor(old_obj.clone())
|
type_tag: dst_type,
|
||||||
} else {
|
repr: Arc::new(RwLock::new(ReprTree::new())),
|
||||||
Object {
|
}
|
||||||
type_tag: dst_type,
|
};
|
||||||
repr: Arc::new(RwLock::new(ReprTree::new()))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
new_obj.repr.write().unwrap().insert_branch(
|
new_obj
|
||||||
old_obj.type_tag,
|
.repr
|
||||||
old_obj.repr
|
.write()
|
||||||
);
|
.unwrap()
|
||||||
|
.insert_branch(old_obj.type_tag, old_obj.repr);
|
||||||
|
|
||||||
self.objects.insert(name.to_string(), new_obj);
|
self.objects.insert(name.to_string(), new_obj);
|
||||||
}
|
}
|
||||||
|
@ -369,9 +355,11 @@ impl Context {
|
||||||
pub fn mono_view<'a, V: View + ?Sized + 'static>(
|
pub fn mono_view<'a, V: View + ?Sized + 'static>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &str,
|
name: &str,
|
||||||
type_ladder: impl Iterator<Item = &'a str>
|
type_ladder: impl Iterator<Item = &'a str>,
|
||||||
) -> Option<OuterViewPort<V>>
|
) -> Option<OuterViewPort<V>>
|
||||||
where V::Msg: Clone {
|
where
|
||||||
|
V::Msg: Clone,
|
||||||
|
{
|
||||||
if let Some(p) = self.get_obj_port(name, type_ladder) {
|
if let Some(p) = self.get_obj_port(name, type_ladder) {
|
||||||
Some(p)
|
Some(p)
|
||||||
} else {
|
} else {
|
||||||
|
@ -391,4 +379,3 @@ impl Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
|
|
|
@ -1,47 +1,17 @@
|
||||||
|
|
||||||
pub mod view;
|
|
||||||
pub mod observer;
|
|
||||||
pub mod channel;
|
pub mod channel;
|
||||||
|
pub mod context;
|
||||||
|
pub mod observer;
|
||||||
pub mod port;
|
pub mod port;
|
||||||
pub mod type_term;
|
pub mod type_term;
|
||||||
pub mod context;
|
pub mod view;
|
||||||
|
|
||||||
pub use {
|
pub use {
|
||||||
view::{View},
|
channel::{queue_channel, set_channel, singleton_channel, ChannelReceiver, ChannelSender},
|
||||||
observer::{
|
context::{Context, MorphismMode, MorphismType, Object, ReprTree},
|
||||||
Observer,
|
observer::{NotifyFnObserver, Observer, ObserverBroadcast, ObserverExt, ResetFnObserver},
|
||||||
ObserverExt,
|
|
||||||
ObserverBroadcast,
|
|
||||||
NotifyFnObserver,
|
|
||||||
ResetFnObserver
|
|
||||||
},
|
|
||||||
channel::{
|
|
||||||
ChannelReceiver,
|
|
||||||
ChannelSender,
|
|
||||||
set_channel,
|
|
||||||
queue_channel,
|
|
||||||
singleton_channel
|
|
||||||
},
|
|
||||||
port::{
|
port::{
|
||||||
ViewPort,
|
AnyInnerViewPort, AnyOuterViewPort, AnyViewPort, InnerViewPort, OuterViewPort, ViewPort,
|
||||||
InnerViewPort,
|
|
||||||
OuterViewPort,
|
|
||||||
AnyViewPort,
|
|
||||||
AnyOuterViewPort,
|
|
||||||
AnyInnerViewPort,
|
|
||||||
},
|
},
|
||||||
type_term::{
|
type_term::{TypeDict, TypeID, TypeTerm},
|
||||||
TypeID,
|
view::View,
|
||||||
TypeTerm,
|
|
||||||
TypeDict,
|
|
||||||
},
|
|
||||||
context::{
|
|
||||||
ReprTree,
|
|
||||||
Object,
|
|
||||||
Context,
|
|
||||||
MorphismMode,
|
|
||||||
MorphismType
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,18 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::core::{
|
||||||
core::{
|
channel::{channel, ChannelReceiver, ChannelSender},
|
||||||
View,
|
View,
|
||||||
channel::{channel, ChannelSender, ChannelReceiver}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
std::{
|
std::sync::RwLock,
|
||||||
sync::{Arc, Weak}
|
std::sync::{Arc, Weak},
|
||||||
},
|
|
||||||
std::sync::RwLock
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*\
|
/*\
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
Observer
|
Observer
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
\*/
|
\*/
|
||||||
pub trait Observer<V: View + ?Sized> : Send + Sync {
|
pub trait Observer<V: View + ?Sized>: Send + Sync {
|
||||||
fn reset(&mut self, _view: Option<Arc<V>>) {}
|
fn reset(&mut self, _view: Option<Arc<V>>) {}
|
||||||
fn notify(&mut self, msg: &V::Msg);
|
fn notify(&mut self, msg: &V::Msg);
|
||||||
}
|
}
|
||||||
|
@ -35,7 +31,7 @@ impl<V: View + ?Sized, O: Observer<V>> Observer<V> for Arc<RwLock<O>> {
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub trait ObserverExt<V: View + ?Sized> : Observer<V> {
|
pub trait ObserverExt<V: View + ?Sized>: Observer<V> {
|
||||||
fn notify_each(&mut self, it: impl IntoIterator<Item = V::Msg>);
|
fn notify_each(&mut self, it: impl IntoIterator<Item = V::Msg>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,25 +43,30 @@ impl<V: View + ?Sized, T: Observer<V>> ObserverExt<V> for T {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*\
|
/*\
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
Broadcast
|
Broadcast
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
\*/
|
\*/
|
||||||
pub struct ObserverBroadcast<V: View + ?Sized>
|
pub struct ObserverBroadcast<V: View + ?Sized>
|
||||||
where V::Msg : Send + Sync {
|
where
|
||||||
|
V::Msg: Send + Sync,
|
||||||
|
{
|
||||||
rx: ChannelReceiver<Vec<V::Msg>>,
|
rx: ChannelReceiver<Vec<V::Msg>>,
|
||||||
tx: ChannelSender<Vec<V::Msg>>,
|
tx: ChannelSender<Vec<V::Msg>>,
|
||||||
observers: Vec<Weak<RwLock<dyn Observer<V>>>>
|
observers: Vec<Weak<RwLock<dyn Observer<V>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: View + ?Sized> ObserverBroadcast<V>
|
impl<V: View + ?Sized> ObserverBroadcast<V>
|
||||||
where V::Msg : Clone + Send + Sync {
|
where
|
||||||
|
V::Msg: Clone + Send + Sync,
|
||||||
|
{
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let (tx, rx) = channel::<Vec<V::Msg>>();
|
let (tx, rx) = channel::<Vec<V::Msg>>();
|
||||||
ObserverBroadcast {
|
ObserverBroadcast {
|
||||||
rx, tx,
|
rx,
|
||||||
observers: Vec::new()
|
tx,
|
||||||
|
observers: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +95,9 @@ where V::Msg : Clone + Send + Sync {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: View + ?Sized> Observer<V> for ObserverBroadcast<V>
|
impl<V: View + ?Sized> Observer<V> for ObserverBroadcast<V>
|
||||||
where V::Msg: Clone {
|
where
|
||||||
|
V::Msg: Clone,
|
||||||
|
{
|
||||||
fn reset(&mut self, view: Option<Arc<V>>) {
|
fn reset(&mut self, view: Option<Arc<V>>) {
|
||||||
for o in self.iter() {
|
for o in self.iter() {
|
||||||
o.write().unwrap().reset(view.clone());
|
o.write().unwrap().reset(view.clone());
|
||||||
|
@ -109,26 +112,32 @@ where V::Msg: Clone {
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub struct NotifyFnObserver<V, F>
|
pub struct NotifyFnObserver<V, F>
|
||||||
where V: View + ?Sized,
|
where
|
||||||
F: Fn(&V::Msg) + Send + Sync {
|
V: View + ?Sized,
|
||||||
|
F: Fn(&V::Msg) + Send + Sync,
|
||||||
|
{
|
||||||
f: F,
|
f: F,
|
||||||
_phantom: std::marker::PhantomData<V>
|
_phantom: std::marker::PhantomData<V>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, F> NotifyFnObserver<V, F>
|
impl<V, F> NotifyFnObserver<V, F>
|
||||||
where V: View + ?Sized,
|
where
|
||||||
F: Fn(&V::Msg) + Send + Sync {
|
V: View + ?Sized,
|
||||||
|
F: Fn(&V::Msg) + Send + Sync,
|
||||||
|
{
|
||||||
pub fn new(f: F) -> Self {
|
pub fn new(f: F) -> Self {
|
||||||
NotifyFnObserver {
|
NotifyFnObserver {
|
||||||
f,
|
f,
|
||||||
_phantom: std::marker::PhantomData
|
_phantom: std::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, F> Observer<V> for NotifyFnObserver<V, F>
|
impl<V, F> Observer<V> for NotifyFnObserver<V, F>
|
||||||
where V: View + ?Sized,
|
where
|
||||||
F: Fn(&V::Msg) + Send + Sync {
|
V: View + ?Sized,
|
||||||
|
F: Fn(&V::Msg) + Send + Sync,
|
||||||
|
{
|
||||||
fn notify(&mut self, msg: &V::Msg) {
|
fn notify(&mut self, msg: &V::Msg) {
|
||||||
(self.f)(msg);
|
(self.f)(msg);
|
||||||
}
|
}
|
||||||
|
@ -137,30 +146,34 @@ where V: View + ?Sized,
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub struct ResetFnObserver<V, F>
|
pub struct ResetFnObserver<V, F>
|
||||||
where V: View + ?Sized,
|
where
|
||||||
F: Fn(Option<Arc<V>>) + Send + Sync {
|
V: View + ?Sized,
|
||||||
|
F: Fn(Option<Arc<V>>) + Send + Sync,
|
||||||
|
{
|
||||||
f: F,
|
f: F,
|
||||||
_phantom: std::marker::PhantomData<V>
|
_phantom: std::marker::PhantomData<V>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, F> ResetFnObserver<V, F>
|
impl<V, F> ResetFnObserver<V, F>
|
||||||
where V: View + ?Sized,
|
where
|
||||||
F: Fn(Option<Arc<V>>) + Send + Sync {
|
V: View + ?Sized,
|
||||||
|
F: Fn(Option<Arc<V>>) + Send + Sync,
|
||||||
|
{
|
||||||
pub fn new(f: F) -> Self {
|
pub fn new(f: F) -> Self {
|
||||||
ResetFnObserver {
|
ResetFnObserver {
|
||||||
f,
|
f,
|
||||||
_phantom: std::marker::PhantomData
|
_phantom: std::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, F> Observer<V> for ResetFnObserver<V, F>
|
impl<V, F> Observer<V> for ResetFnObserver<V, F>
|
||||||
where V: View + ?Sized,
|
where
|
||||||
F: Fn(Option<Arc<V>>) + Send + Sync {
|
V: View + ?Sized,
|
||||||
|
F: Fn(Option<Arc<V>>) + Send + Sync,
|
||||||
|
{
|
||||||
fn notify(&mut self, _msg: &V::Msg) {}
|
fn notify(&mut self, _msg: &V::Msg) {}
|
||||||
fn reset(&mut self, view: Option<Arc<V>>) {
|
fn reset(&mut self, view: Option<Arc<V>>) {
|
||||||
(self.f)(view);
|
(self.f)(view);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,15 @@
|
||||||
use {
|
use {
|
||||||
std::sync::Arc,
|
crate::core::{NotifyFnObserver, Observer, ObserverBroadcast, ResetFnObserver, View},
|
||||||
std::any::Any,
|
std::any::Any,
|
||||||
|
std::sync::Arc,
|
||||||
std::sync::RwLock,
|
std::sync::RwLock,
|
||||||
crate::core::{
|
|
||||||
View,
|
|
||||||
Observer,
|
|
||||||
ObserverBroadcast,
|
|
||||||
NotifyFnObserver,
|
|
||||||
ResetFnObserver
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub trait UpdateTask: Send + Sync {
|
||||||
pub trait UpdateTask : Send + Sync {
|
|
||||||
fn update(&self);
|
fn update(&self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*\
|
/*\
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
View Port
|
View Port
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
@ -24,16 +17,18 @@ pub trait UpdateTask : Send + Sync {
|
||||||
pub struct ViewPort<V: View + ?Sized> {
|
pub struct ViewPort<V: View + ?Sized> {
|
||||||
view: Arc<RwLock<Option<Arc<V>>>>,
|
view: Arc<RwLock<Option<Arc<V>>>>,
|
||||||
cast: Arc<RwLock<ObserverBroadcast<V>>>,
|
cast: Arc<RwLock<ObserverBroadcast<V>>>,
|
||||||
pub update_hooks: Arc<RwLock<Vec<Arc<dyn UpdateTask>>>>
|
pub update_hooks: Arc<RwLock<Vec<Arc<dyn UpdateTask>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: View + ?Sized> ViewPort<V>
|
impl<V: View + ?Sized> ViewPort<V>
|
||||||
where V::Msg: Clone {
|
where
|
||||||
|
V::Msg: Clone,
|
||||||
|
{
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
ViewPort {
|
ViewPort {
|
||||||
view: Arc::new(RwLock::new(None)),
|
view: Arc::new(RwLock::new(None)),
|
||||||
cast: Arc::new(RwLock::new(ObserverBroadcast::new())),
|
cast: Arc::new(RwLock::new(ObserverBroadcast::new())),
|
||||||
update_hooks: Arc::new(RwLock::new(Vec::new()))
|
update_hooks: Arc::new(RwLock::new(Vec::new())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,8 +46,14 @@ where V::Msg: Clone {
|
||||||
|
|
||||||
pub fn add_observer(&self, observer: Arc<RwLock<dyn Observer<V>>>) {
|
pub fn add_observer(&self, observer: Arc<RwLock<dyn Observer<V>>>) {
|
||||||
self.update();
|
self.update();
|
||||||
self.cast.write().unwrap().add_observer(Arc::downgrade(&observer));
|
self.cast
|
||||||
observer.write().unwrap().reset(self.view.read().unwrap().clone());
|
.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>) {
|
pub fn add_update_hook(&self, hook_cast: Arc<dyn UpdateTask>) {
|
||||||
|
@ -60,47 +61,42 @@ where V::Msg: Clone {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inner(&self) -> InnerViewPort<V> {
|
pub fn inner(&self) -> InnerViewPort<V> {
|
||||||
InnerViewPort(
|
InnerViewPort(ViewPort {
|
||||||
ViewPort{
|
view: self.view.clone(),
|
||||||
view: self.view.clone(),
|
cast: self.cast.clone(),
|
||||||
cast: self.cast.clone(),
|
update_hooks: self.update_hooks.clone(),
|
||||||
update_hooks: self.update_hooks.clone()
|
})
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn outer(&self) -> OuterViewPort<V> {
|
pub fn outer(&self) -> OuterViewPort<V> {
|
||||||
OuterViewPort(
|
OuterViewPort(ViewPort {
|
||||||
ViewPort{
|
view: self.view.clone(),
|
||||||
view: self.view.clone(),
|
cast: self.cast.clone(),
|
||||||
cast: self.cast.clone(),
|
update_hooks: self.update_hooks.clone(),
|
||||||
update_hooks: self.update_hooks.clone()
|
})
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_inner(self) -> InnerViewPort<V> {
|
pub fn into_inner(self) -> InnerViewPort<V> {
|
||||||
InnerViewPort(
|
InnerViewPort(ViewPort {
|
||||||
ViewPort{
|
view: self.view,
|
||||||
view: self.view,
|
cast: self.cast,
|
||||||
cast: self.cast,
|
update_hooks: self.update_hooks,
|
||||||
update_hooks: self.update_hooks
|
})
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_outer(self) -> OuterViewPort<V> {
|
pub fn into_outer(self) -> OuterViewPort<V> {
|
||||||
OuterViewPort(
|
OuterViewPort(ViewPort {
|
||||||
ViewPort{
|
view: self.view,
|
||||||
view: self.view,
|
cast: self.cast,
|
||||||
cast: self.cast,
|
update_hooks: self.update_hooks,
|
||||||
update_hooks: self.update_hooks
|
})
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: View + ?Sized> UpdateTask for ViewPort<V> where V::Msg: Clone + Send + Sync{
|
impl<V: View + ?Sized> UpdateTask for ViewPort<V>
|
||||||
|
where
|
||||||
|
V::Msg: Clone + Send + Sync,
|
||||||
|
{
|
||||||
fn update(&self) {
|
fn update(&self) {
|
||||||
let v = {
|
let v = {
|
||||||
let t = self.update_hooks.read().unwrap();
|
let t = self.update_hooks.read().unwrap();
|
||||||
|
@ -115,26 +111,34 @@ impl<V: View + ?Sized> UpdateTask for ViewPort<V> where V::Msg: Clone + Send + S
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<V: View + ?Sized> Clone for ViewPort<V>
|
impl<V: View + ?Sized> Clone for ViewPort<V>
|
||||||
where V::Msg: Clone {
|
where
|
||||||
|
V::Msg: Clone,
|
||||||
|
{
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
ViewPort {
|
ViewPort {
|
||||||
view: self.view.clone(),
|
view: self.view.clone(),
|
||||||
cast: self.cast.clone(),
|
cast: self.cast.clone(),
|
||||||
update_hooks: self.update_hooks.clone()
|
update_hooks: self.update_hooks.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub struct InnerViewPort<V: View + ?Sized>(pub ViewPort<V>) where V::Msg: Clone;
|
pub struct InnerViewPort<V: View + ?Sized>(pub ViewPort<V>)
|
||||||
pub struct OuterViewPort<V: View + ?Sized>(pub ViewPort<V>) where V::Msg: Clone;
|
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 {
|
impl<V: View + ?Sized> InnerViewPort<V>
|
||||||
|
where
|
||||||
|
V::Msg: Clone,
|
||||||
|
{
|
||||||
pub fn get_broadcast(&self) -> Arc<RwLock<ObserverBroadcast<V>>> {
|
pub fn get_broadcast(&self) -> Arc<RwLock<ObserverBroadcast<V>>> {
|
||||||
self.0.cast.clone()
|
self.0.cast.clone()
|
||||||
}
|
}
|
||||||
|
@ -154,7 +158,9 @@ impl<V: View + ?Sized> InnerViewPort<V> where V::Msg: Clone {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: View + ?Sized> Clone for InnerViewPort<V>
|
impl<V: View + ?Sized> Clone for InnerViewPort<V>
|
||||||
where V::Msg: Clone {
|
where
|
||||||
|
V::Msg: Clone,
|
||||||
|
{
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
InnerViewPort(self.0.clone())
|
InnerViewPort(self.0.clone())
|
||||||
}
|
}
|
||||||
|
@ -163,7 +169,9 @@ where V::Msg: Clone {
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl<V: View + ?Sized + 'static> OuterViewPort<V>
|
impl<V: View + ?Sized + 'static> OuterViewPort<V>
|
||||||
where V::Msg: Clone {
|
where
|
||||||
|
V::Msg: Clone,
|
||||||
|
{
|
||||||
pub fn get_view(&self) -> Option<Arc<V>> {
|
pub fn get_view(&self) -> Option<Arc<V>> {
|
||||||
self.0.view.read().unwrap().clone()
|
self.0.view.read().unwrap().clone()
|
||||||
}
|
}
|
||||||
|
@ -172,18 +180,27 @@ where V::Msg: Clone {
|
||||||
self.0.view.clone()
|
self.0.view.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_observer(&self, observer: Arc<RwLock<dyn Observer<V>>>) -> Arc<RwLock<Option<Arc<V>>>> {
|
pub fn add_observer(
|
||||||
|
&self,
|
||||||
|
observer: Arc<RwLock<dyn Observer<V>>>,
|
||||||
|
) -> Arc<RwLock<Option<Arc<V>>>> {
|
||||||
self.0.add_observer(observer);
|
self.0.add_observer(observer);
|
||||||
self.get_view_arc()
|
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>>> {
|
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)));
|
let obs = Arc::new(RwLock::new(ResetFnObserver::new(reset)));
|
||||||
self.add_observer(obs.clone());
|
self.add_observer(obs.clone());
|
||||||
obs
|
obs
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_notify_fn<F: Fn(&V::Msg) + Send + Sync + 'static>(&self, notify: F) -> Arc<RwLock<NotifyFnObserver<V, F>>> {
|
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)));
|
let obs = Arc::new(RwLock::new(NotifyFnObserver::new(notify)));
|
||||||
self.add_observer(obs.clone());
|
self.add_observer(obs.clone());
|
||||||
obs
|
obs
|
||||||
|
@ -191,7 +208,9 @@ where V::Msg: Clone {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: View + ?Sized> Clone for OuterViewPort<V>
|
impl<V: View + ?Sized> Clone for OuterViewPort<V>
|
||||||
where V::Msg: Clone {
|
where
|
||||||
|
V::Msg: Clone,
|
||||||
|
{
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
OuterViewPort(self.0.clone())
|
OuterViewPort(self.0.clone())
|
||||||
}
|
}
|
||||||
|
@ -223,7 +242,7 @@ where V::Msg: Clone {
|
||||||
pub struct AnyViewPort {
|
pub struct AnyViewPort {
|
||||||
view: Arc<dyn Any + Send + Sync + 'static>,
|
view: Arc<dyn Any + Send + Sync + 'static>,
|
||||||
cast: Arc<dyn Any + Send + Sync + 'static>,
|
cast: Arc<dyn Any + Send + Sync + 'static>,
|
||||||
update_hooks: Arc<RwLock<Vec<Arc<dyn UpdateTask>>>>
|
update_hooks: Arc<RwLock<Vec<Arc<dyn UpdateTask>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AnyViewPort {
|
impl AnyViewPort {
|
||||||
|
@ -231,10 +250,14 @@ impl AnyViewPort {
|
||||||
match (
|
match (
|
||||||
self.view.clone().downcast::<RwLock<Option<Arc<V>>>>(),
|
self.view.clone().downcast::<RwLock<Option<Arc<V>>>>(),
|
||||||
self.cast.clone().downcast::<RwLock<ObserverBroadcast<V>>>(),
|
self.cast.clone().downcast::<RwLock<ObserverBroadcast<V>>>(),
|
||||||
self.update_hooks.clone()
|
self.update_hooks.clone(),
|
||||||
) {
|
) {
|
||||||
(Ok(view), Ok(cast), update_hooks) => Ok(ViewPort{view, cast, update_hooks}),
|
(Ok(view), Ok(cast), update_hooks) => Ok(ViewPort {
|
||||||
_ => Err(self)
|
view,
|
||||||
|
cast,
|
||||||
|
update_hooks,
|
||||||
|
}),
|
||||||
|
_ => Err(self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -244,7 +267,7 @@ impl<V: View + ?Sized + 'static> From<ViewPort<V>> for AnyViewPort {
|
||||||
AnyViewPort {
|
AnyViewPort {
|
||||||
view: port.view as Arc<dyn Any + Send + Sync + 'static>,
|
view: port.view as Arc<dyn Any + Send + Sync + 'static>,
|
||||||
cast: port.cast as Arc<dyn Any + Send + Sync + 'static>,
|
cast: port.cast as Arc<dyn Any + Send + Sync + 'static>,
|
||||||
update_hooks: port.update_hooks
|
update_hooks: port.update_hooks,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -258,38 +281,47 @@ pub struct AnyOuterViewPort(AnyViewPort);
|
||||||
pub struct AnyInnerViewPort(AnyViewPort);
|
pub struct AnyInnerViewPort(AnyViewPort);
|
||||||
|
|
||||||
impl AnyOuterViewPort {
|
impl AnyOuterViewPort {
|
||||||
pub fn downcast<V: View + ?Sized + 'static>(self) -> Result<OuterViewPort<V>, AnyViewPort> where V::Msg: Clone {
|
pub fn downcast<V: View + ?Sized + 'static>(self) -> Result<OuterViewPort<V>, AnyViewPort>
|
||||||
|
where
|
||||||
|
V::Msg: Clone,
|
||||||
|
{
|
||||||
Ok(OuterViewPort(self.0.downcast::<V>()?))
|
Ok(OuterViewPort(self.0.downcast::<V>()?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: View + ?Sized + 'static> From<OuterViewPort<V>> for AnyOuterViewPort
|
impl<V: View + ?Sized + 'static> From<OuterViewPort<V>> for AnyOuterViewPort
|
||||||
where V::Msg: Clone {
|
where
|
||||||
|
V::Msg: Clone,
|
||||||
|
{
|
||||||
fn from(port: OuterViewPort<V>) -> Self {
|
fn from(port: OuterViewPort<V>) -> Self {
|
||||||
AnyOuterViewPort(AnyViewPort{
|
AnyOuterViewPort(AnyViewPort {
|
||||||
view: port.0.view as Arc<dyn Any + Send + Sync + 'static>,
|
view: port.0.view as Arc<dyn Any + Send + Sync + 'static>,
|
||||||
cast: port.0.cast as Arc<dyn Any + Send + Sync + 'static>,
|
cast: port.0.cast as Arc<dyn Any + Send + Sync + 'static>,
|
||||||
update_hooks: port.0.update_hooks
|
update_hooks: port.0.update_hooks,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AnyInnerViewPort {
|
impl AnyInnerViewPort {
|
||||||
pub fn downcast<V: View + ?Sized + 'static>(self) -> Result<InnerViewPort<V>, AnyViewPort> where V::Msg: Clone {
|
pub fn downcast<V: View + ?Sized + 'static>(self) -> Result<InnerViewPort<V>, AnyViewPort>
|
||||||
|
where
|
||||||
|
V::Msg: Clone,
|
||||||
|
{
|
||||||
Ok(InnerViewPort(self.0.downcast::<V>()?))
|
Ok(InnerViewPort(self.0.downcast::<V>()?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: View + ?Sized + 'static> From<InnerViewPort<V>> for AnyInnerViewPort
|
impl<V: View + ?Sized + 'static> From<InnerViewPort<V>> for AnyInnerViewPort
|
||||||
where V::Msg: Clone {
|
where
|
||||||
|
V::Msg: Clone,
|
||||||
|
{
|
||||||
fn from(port: InnerViewPort<V>) -> Self {
|
fn from(port: InnerViewPort<V>) -> Self {
|
||||||
AnyInnerViewPort(AnyViewPort{
|
AnyInnerViewPort(AnyViewPort {
|
||||||
view: port.0.view as Arc<dyn Any + Send + Sync + 'static>,
|
view: port.0.view as Arc<dyn Any + Send + Sync + 'static>,
|
||||||
cast: port.0.cast as Arc<dyn Any + Send + Sync + 'static>,
|
cast: port.0.cast as Arc<dyn Any + Send + Sync + 'static>,
|
||||||
update_hooks: port.0.update_hooks
|
update_hooks: port.0.update_hooks,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,4 @@
|
||||||
use {
|
use {crate::bimap::Bimap, std::collections::HashMap};
|
||||||
std::{
|
|
||||||
collections::HashMap
|
|
||||||
},
|
|
||||||
crate::{
|
|
||||||
bimap::Bimap,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
|
@ -15,20 +8,17 @@ pub type TypeID = u64;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum TypeTerm {
|
pub enum TypeTerm {
|
||||||
Type {
|
Type { id: TypeID, args: Vec<TypeTerm> },
|
||||||
id: TypeID,
|
Num(i64),
|
||||||
args: Vec<TypeTerm>
|
|
||||||
},
|
|
||||||
Num(i64)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeTerm {
|
impl TypeTerm {
|
||||||
pub fn new(id: TypeID) -> Self {
|
pub fn new(id: TypeID) -> Self {
|
||||||
TypeTerm::Type{ id, args: vec![] }
|
TypeTerm::Type { id, args: vec![] }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn arg(&mut self, t: TypeTerm) -> &mut Self {
|
pub fn arg(&mut self, t: TypeTerm) -> &mut Self {
|
||||||
if let TypeTerm::Type{ id: _, args } = self {
|
if let TypeTerm::Type { id: _, args } = self {
|
||||||
args.push(t);
|
args.push(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +36,7 @@ impl TypeTerm {
|
||||||
match token {
|
match token {
|
||||||
"(" => {
|
"(" => {
|
||||||
term_stack.push(None);
|
term_stack.push(None);
|
||||||
},
|
}
|
||||||
")" => {
|
")" => {
|
||||||
let t = term_stack.pop().unwrap();
|
let t = term_stack.pop().unwrap();
|
||||||
if term_stack.len() > 0 {
|
if term_stack.len() > 0 {
|
||||||
|
@ -59,19 +49,24 @@ impl TypeTerm {
|
||||||
} else {
|
} else {
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
atom => {
|
atom => {
|
||||||
let f = term_stack.last_mut().unwrap();
|
let f = term_stack.last_mut().unwrap();
|
||||||
|
|
||||||
match f {
|
match f {
|
||||||
Some(f) =>
|
Some(f) => {
|
||||||
if atom.chars().nth(0).unwrap().is_numeric() {
|
if atom.chars().nth(0).unwrap().is_numeric() {
|
||||||
f.num_arg(i64::from_str_radix(atom, 10).unwrap());
|
f.num_arg(i64::from_str_radix(atom, 10).unwrap());
|
||||||
} else {
|
} else {
|
||||||
f.arg(TypeTerm::new(*names.get(atom).expect(&format!("invalid atom {}", atom))));
|
f.arg(TypeTerm::new(
|
||||||
|
*names.get(atom).expect(&format!("invalid atom {}", atom)),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
None => {
|
None => {
|
||||||
*f = Some(TypeTerm::new(*names.get(atom).expect(&format!("invalid atom {}", atom))));
|
*f = Some(TypeTerm::new(
|
||||||
|
*names.get(atom).expect(&format!("invalid atom {}", atom)),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,64 +79,60 @@ impl TypeTerm {
|
||||||
// only adds parenthesis where args.len > 0
|
// only adds parenthesis where args.len > 0
|
||||||
pub fn to_str1(&self, names: &HashMap<u64, String>) -> String {
|
pub fn to_str1(&self, names: &HashMap<u64, String>) -> String {
|
||||||
match self {
|
match self {
|
||||||
TypeTerm::Type{ id, args } =>
|
TypeTerm::Type { id, args } => {
|
||||||
if args.len() > 0 {
|
if args.len() > 0 {
|
||||||
format!(
|
format!(
|
||||||
"( {} {})",
|
"( {} {})",
|
||||||
names[id],
|
names[id],
|
||||||
if args.len() > 0 {
|
if args.len() > 0 {
|
||||||
args.iter().fold(
|
args.iter().fold(String::new(), |str, term| {
|
||||||
String::new(),
|
format!("{}{} ", str, term.to_str1(names))
|
||||||
|str, term| format!("{}{} ", str, term.to_str1(names) )
|
})
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
names[id].clone()
|
names[id].clone()
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TypeTerm::Num(n) =>
|
TypeTerm::Num(n) => format!("{}", n),
|
||||||
format!("{}", n)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// always adds an enclosing pair of parenthesis
|
// always adds an enclosing pair of parenthesis
|
||||||
pub fn to_str(&self, names: &HashMap<u64, String>) -> String {
|
pub fn to_str(&self, names: &HashMap<u64, String>) -> String {
|
||||||
match self {
|
match self {
|
||||||
TypeTerm::Type{ id, args } =>
|
TypeTerm::Type { id, args } => format!(
|
||||||
format!(
|
"( {} {})",
|
||||||
"( {} {})",
|
names[id],
|
||||||
names[id],
|
if args.len() > 0 {
|
||||||
if args.len() > 0 {
|
args.iter().fold(String::new(), |str, term| {
|
||||||
args.iter().fold(
|
format!("{}{} ", str, term.to_str1(names))
|
||||||
String::new(),
|
})
|
||||||
|str, term| format!("{}{} ", str, term.to_str1(names) )
|
} else {
|
||||||
)
|
String::new()
|
||||||
} else {
|
}
|
||||||
String::new()
|
),
|
||||||
}),
|
|
||||||
|
|
||||||
TypeTerm::Num(n) =>
|
TypeTerm::Num(n) => format!("{}", n),
|
||||||
format!("{}", n)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub struct TypeDict {
|
pub struct TypeDict {
|
||||||
typenames: Bimap::<String, u64>,
|
typenames: Bimap<String, u64>,
|
||||||
type_id_counter: u64
|
type_id_counter: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeDict {
|
impl TypeDict {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
TypeDict {
|
TypeDict {
|
||||||
typenames: Bimap::new(),
|
typenames: Bimap::new(),
|
||||||
type_id_counter: 0
|
type_id_counter: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,4 +151,3 @@ impl TypeDict {
|
||||||
}
|
}
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
|
/*\
|
||||||
/*\
|
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
View
|
View
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
\*/
|
\*/
|
||||||
pub trait View : Send + Sync {
|
pub trait View: Send + Sync {
|
||||||
/// Notification message for the observers
|
/// Notification message for the observers
|
||||||
type Msg : Send + Sync;
|
type Msg: Send + Sync;
|
||||||
}
|
}
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
@ -25,4 +24,3 @@ impl<V: View + ?Sized> View for Arc<V> {
|
||||||
impl<V: View> View for Option<V> {
|
impl<V: View> View for Option<V> {
|
||||||
type Msg = V::Msg;
|
type Msg = V::Msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,19 @@
|
||||||
use {
|
use {
|
||||||
std::{
|
|
||||||
sync::Arc,
|
|
||||||
cmp::max,
|
|
||||||
collections::HashMap
|
|
||||||
},
|
|
||||||
std::sync::RwLock,
|
|
||||||
cgmath::{Point2, Vector2},
|
|
||||||
crate::{
|
crate::{
|
||||||
core::{
|
core::{InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View, ViewPort},
|
||||||
View, Observer, ObserverBroadcast,
|
|
||||||
ViewPort, InnerViewPort, OuterViewPort,
|
|
||||||
port::UpdateTask
|
|
||||||
},
|
|
||||||
grid::{GridView, GridWindowIterator},
|
grid::{GridView, GridWindowIterator},
|
||||||
index::{IndexArea, IndexView},
|
index::{IndexArea, IndexView},
|
||||||
projection::ProjectionHelper
|
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>>>>
|
impl<Item> OuterViewPort<dyn GridView<Item = OuterViewPort<dyn GridView<Item = Item>>>>
|
||||||
where Item: 'static{
|
where
|
||||||
|
Item: 'static,
|
||||||
|
{
|
||||||
pub fn flatten(&self) -> OuterViewPort<dyn GridView<Item = Item>> {
|
pub fn flatten(&self) -> OuterViewPort<dyn GridView<Item = Item>> {
|
||||||
let port = ViewPort::new();
|
let port = ViewPort::new();
|
||||||
port.add_update_hook(Arc::new(self.0.clone()));
|
port.add_update_hook(Arc::new(self.0.clone()));
|
||||||
|
@ -29,31 +23,35 @@ where Item: 'static{
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Chunk<Item>
|
pub struct Chunk<Item>
|
||||||
where Item: 'static
|
where
|
||||||
|
Item: 'static,
|
||||||
{
|
{
|
||||||
offset: Vector2<i16>,
|
offset: Vector2<i16>,
|
||||||
limit: Point2<i16>,
|
limit: Point2<i16>,
|
||||||
view: Arc<dyn GridView<Item = Item>>
|
view: Arc<dyn GridView<Item = Item>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Flatten<Item>
|
pub struct Flatten<Item>
|
||||||
where Item: 'static
|
where
|
||||||
|
Item: 'static,
|
||||||
{
|
{
|
||||||
limit: Point2<i16>,
|
limit: Point2<i16>,
|
||||||
top: Arc<dyn GridView<Item = OuterViewPort<dyn GridView<Item = Item>>>>,
|
top: Arc<dyn GridView<Item = OuterViewPort<dyn GridView<Item = Item>>>>,
|
||||||
chunks: HashMap<Point2<i16>, Chunk<Item>>,
|
chunks: HashMap<Point2<i16>, Chunk<Item>>,
|
||||||
cast: Arc<RwLock<ObserverBroadcast<dyn GridView<Item = Item>>>>,
|
cast: Arc<RwLock<ObserverBroadcast<dyn GridView<Item = Item>>>>,
|
||||||
proj_helper: ProjectionHelper<Point2<i16>, Self>
|
proj_helper: ProjectionHelper<Point2<i16>, Self>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Item> View for Flatten<Item>
|
impl<Item> View for Flatten<Item>
|
||||||
where Item: 'static
|
where
|
||||||
|
Item: 'static,
|
||||||
{
|
{
|
||||||
type Msg = IndexArea<Point2<i16>>;
|
type Msg = IndexArea<Point2<i16>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Item> IndexView<Point2<i16>> for Flatten<Item>
|
impl<Item> IndexView<Point2<i16>> for Flatten<Item>
|
||||||
where Item: 'static
|
where
|
||||||
|
Item: 'static,
|
||||||
{
|
{
|
||||||
type Item = Item;
|
type Item = Item;
|
||||||
|
|
||||||
|
@ -64,38 +62,36 @@ where Item: 'static
|
||||||
}
|
}
|
||||||
|
|
||||||
fn area(&self) -> IndexArea<Point2<i16>> {
|
fn area(&self) -> IndexArea<Point2<i16>> {
|
||||||
IndexArea::Range(
|
IndexArea::Range(Point2::new(0, 0)..=self.limit)
|
||||||
Point2::new(0, 0) ..= self.limit
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: remove unused projection args (bot-views) if they get replaced by a new viewport */
|
/* TODO: remove unused projection args (bot-views) if they get replaced by a new viewport */
|
||||||
impl<Item> Flatten<Item>
|
impl<Item> Flatten<Item>
|
||||||
where Item: 'static
|
where
|
||||||
|
Item: 'static,
|
||||||
{
|
{
|
||||||
pub fn new(
|
pub fn new(
|
||||||
top_port: OuterViewPort<dyn GridView<Item = OuterViewPort<dyn GridView<Item = Item>>>>,
|
top_port: OuterViewPort<dyn GridView<Item = OuterViewPort<dyn GridView<Item = Item>>>>,
|
||||||
out_port: InnerViewPort<dyn GridView<Item = Item>>
|
out_port: InnerViewPort<dyn GridView<Item = Item>>,
|
||||||
) -> Arc<RwLock<Self>> {
|
) -> Arc<RwLock<Self>> {
|
||||||
let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone());
|
let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone());
|
||||||
|
|
||||||
let flat = Arc::new(RwLock::new(
|
let flat = Arc::new(RwLock::new(Flatten {
|
||||||
Flatten {
|
limit: Point2::new(0, 0),
|
||||||
limit: Point2::new(0, 0),
|
top: proj_helper.new_index_arg(
|
||||||
top: proj_helper.new_index_arg(
|
Point2::new(-1, -1),
|
||||||
Point2::new(-1, -1),
|
top_port,
|
||||||
top_port,
|
|s: &mut Self, chunk_area| {
|
||||||
|s: &mut Self, chunk_area| {
|
for chunk_idx in chunk_area.iter() {
|
||||||
for chunk_idx in chunk_area.iter() {
|
s.update_chunk(chunk_idx);
|
||||||
s.update_chunk(chunk_idx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
),
|
},
|
||||||
chunks: HashMap::new(),
|
),
|
||||||
cast: out_port.get_broadcast(),
|
chunks: HashMap::new(),
|
||||||
proj_helper
|
cast: out_port.get_broadcast(),
|
||||||
}));
|
proj_helper,
|
||||||
|
}));
|
||||||
|
|
||||||
flat.write().unwrap().proj_helper.set_proj(&flat);
|
flat.write().unwrap().proj_helper.set_proj(&flat);
|
||||||
out_port.set_view(Some(flat.clone()));
|
out_port.set_view(Some(flat.clone()));
|
||||||
|
@ -117,26 +113,23 @@ where Item: 'static
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(chunk) = s.chunks.get(&chunk_idx) {
|
if let Some(chunk) = s.chunks.get(&chunk_idx) {
|
||||||
s.cast.notify(
|
s.cast.notify(&area.map(|pt| pt + chunk.offset));
|
||||||
&area.map(|pt| pt + chunk.offset)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(chunk) = self.chunks.get_mut(&chunk_idx) {
|
if let Some(chunk) = self.chunks.get_mut(&chunk_idx) {
|
||||||
chunk.view = view;
|
chunk.view = view;
|
||||||
self.cast.notify(
|
self.cast
|
||||||
&chunk.view.area().map(|pt| pt + chunk.offset)
|
.notify(&chunk.view.area().map(|pt| pt + chunk.offset));
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
self.chunks.insert(
|
self.chunks.insert(
|
||||||
chunk_idx,
|
chunk_idx,
|
||||||
Chunk {
|
Chunk {
|
||||||
offset: Vector2::new(-1, -1),
|
offset: Vector2::new(-1, -1),
|
||||||
limit: Point2::new(-1, -1),
|
limit: Point2::new(-1, -1),
|
||||||
view
|
view,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +137,7 @@ where Item: 'static
|
||||||
} else {
|
} else {
|
||||||
self.proj_helper.remove_arg(&chunk_idx);
|
self.proj_helper.remove_arg(&chunk_idx);
|
||||||
|
|
||||||
if let Some(chunk) = self.chunks.remove(&chunk_idx) {
|
if let Some(_chunk) = self.chunks.remove(&chunk_idx) {
|
||||||
self.update_all_offsets();
|
self.update_all_offsets();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,67 +147,73 @@ where Item: 'static
|
||||||
/// and update size of flattened grid
|
/// and update size of flattened grid
|
||||||
fn update_all_offsets(&mut self) {
|
fn update_all_offsets(&mut self) {
|
||||||
let top_range = self.top.area().range();
|
let top_range = self.top.area().range();
|
||||||
let mut col_widths = vec![0 as i16; (top_range.end().x+1) as usize];
|
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];
|
let mut row_heights = vec![0 as i16; (top_range.end().y + 1) as usize];
|
||||||
|
|
||||||
for chunk_idx in GridWindowIterator::from(top_range.clone()) {
|
for chunk_idx in GridWindowIterator::from(top_range.clone()) {
|
||||||
if let Some(chunk) = self.chunks.get_mut(&chunk_idx) {
|
if let Some(chunk) = self.chunks.get_mut(&chunk_idx) {
|
||||||
let chunk_range = chunk.view.area().range();
|
let chunk_range = chunk.view.area().range();
|
||||||
let lim = *chunk_range.end();
|
let lim = *chunk_range.end();
|
||||||
|
|
||||||
col_widths[chunk_idx.x as usize] =
|
col_widths[chunk_idx.x as usize] = max(
|
||||||
max(
|
col_widths[chunk_idx.x as usize],
|
||||||
col_widths[chunk_idx.x as usize],
|
if lim.x < 0 { 0 } else { lim.x + 1 },
|
||||||
if lim.x < 0 { 0 } else { lim.x+1 }
|
);
|
||||||
);
|
row_heights[chunk_idx.y as usize] = max(
|
||||||
row_heights[chunk_idx.y as usize] =
|
row_heights[chunk_idx.y as usize],
|
||||||
max(
|
if lim.y < 0 { 0 } else { lim.y + 1 },
|
||||||
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()) {
|
for chunk_idx in GridWindowIterator::from(top_range.clone()) {
|
||||||
if let Some(chunk) = self.chunks.get_mut(&chunk_idx) {
|
if let Some(chunk) = self.chunks.get_mut(&chunk_idx) {
|
||||||
let old_offset = chunk.offset;
|
let _old_offset = chunk.offset;
|
||||||
let old_limit = chunk.limit;
|
let _old_limit = chunk.limit;
|
||||||
|
|
||||||
chunk.limit = *chunk.view.area().range().end();
|
chunk.limit = *chunk.view.area().range().end();
|
||||||
chunk.offset = Vector2::new(
|
chunk.offset = Vector2::new(
|
||||||
(0 .. chunk_idx.x as usize).map(|x| col_widths[x]).sum(),
|
(0..chunk_idx.x as usize).map(|x| col_widths[x]).sum(),
|
||||||
(0 .. chunk_idx.y as usize).map(|y| row_heights[y]).sum()
|
(0..chunk_idx.y as usize).map(|y| row_heights[y]).sum(),
|
||||||
);
|
);
|
||||||
/*
|
/*
|
||||||
if old_offset != chunk.offset {
|
if old_offset != chunk.offset {
|
||||||
self.cast.notify(
|
self.cast.notify(
|
||||||
&IndexArea::Range(
|
&IndexArea::Range(
|
||||||
Point2::new(
|
Point2::new(
|
||||||
std::cmp::min(old_offset.x, chunk.offset.x),
|
std::cmp::min(old_offset.x, chunk.offset.x),
|
||||||
std::cmp::min(old_offset.y, chunk.offset.y)
|
std::cmp::min(old_offset.y, chunk.offset.y)
|
||||||
)
|
)
|
||||||
..= Point2::new(
|
..= Point2::new(
|
||||||
std::cmp::max(old_offset.x + old_limit.x, chunk.offset.x + chunk.limit.x),
|
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)
|
std::cmp::max(old_offset.y + old_limit.y, chunk.offset.y + chunk.limit.y)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let old_limit = self.limit;
|
let old_limit = self.limit;
|
||||||
self.limit = Point2::new(
|
self.limit = Point2::new(
|
||||||
(0 ..= top_range.end().x as usize).map(|x| col_widths[x]).sum::<i16>() - 1,
|
(0..=top_range.end().x as usize)
|
||||||
(0 ..= top_range.end().y as usize).map(|y| row_heights[y]).sum::<i16>() - 1,
|
.map(|x| col_widths[x])
|
||||||
|
.sum::<i16>()
|
||||||
|
- 1,
|
||||||
|
(0..=top_range.end().y as usize)
|
||||||
|
.map(|y| row_heights[y])
|
||||||
|
.sum::<i16>()
|
||||||
|
- 1,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.cast.notify(
|
self.cast.notify(&IndexArea::Range(
|
||||||
&IndexArea::Range(
|
Point2::new(0, 0)
|
||||||
Point2::new(0, 0) ..= Point2::new(max(self.limit.x, old_limit.x), max(self.limit.y, old_limit.y))
|
..=Point2::new(
|
||||||
)
|
max(self.limit.x, old_limit.x),
|
||||||
);
|
max(self.limit.y, old_limit.y),
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// given an index in the flattened sequence,
|
/// given an index in the flattened sequence,
|
||||||
|
@ -233,4 +232,3 @@ where Item: 'static
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
|
|
||||||
use {
|
use {
|
||||||
|
crate::index::{IndexArea, IndexView},
|
||||||
|
cgmath::Point2,
|
||||||
std::{
|
std::{
|
||||||
|
cmp::{max, min},
|
||||||
ops::RangeInclusive,
|
ops::RangeInclusive,
|
||||||
cmp::{min, max}
|
|
||||||
},
|
},
|
||||||
cgmath::{Point2},
|
|
||||||
crate::index::{IndexArea, IndexView}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
@ -14,8 +13,8 @@ pub trait GridView = IndexView<Point2<i16>>;
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub mod offset;
|
|
||||||
pub mod flatten;
|
pub mod flatten;
|
||||||
|
pub mod offset;
|
||||||
pub mod window_iterator;
|
pub mod window_iterator;
|
||||||
|
|
||||||
pub use window_iterator::GridWindowIterator;
|
pub use window_iterator::GridWindowIterator;
|
||||||
|
@ -23,7 +22,6 @@ pub use window_iterator::GridWindowIterator;
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl IndexArea<Point2<i16>> {
|
impl IndexArea<Point2<i16>> {
|
||||||
|
|
||||||
// todo: this is not perfect (e.g. diagonals are inefficient)
|
// todo: this is not perfect (e.g. diagonals are inefficient)
|
||||||
pub fn iter(&self) -> GridWindowIterator {
|
pub fn iter(&self) -> GridWindowIterator {
|
||||||
GridWindowIterator::from(self.range())
|
GridWindowIterator::from(self.range())
|
||||||
|
@ -31,52 +29,46 @@ impl IndexArea<Point2<i16>> {
|
||||||
|
|
||||||
pub fn range(&self) -> RangeInclusive<Point2<i16>> {
|
pub fn range(&self) -> RangeInclusive<Point2<i16>> {
|
||||||
match self {
|
match self {
|
||||||
IndexArea::Empty => Point2::new(i16::MAX, i16::MAX) ..= Point2::new(i16::MIN, i16::MIN),
|
IndexArea::Empty => Point2::new(i16::MAX, i16::MAX)..=Point2::new(i16::MIN, i16::MIN),
|
||||||
IndexArea::Full => panic!("range from full grid area"),
|
IndexArea::Full => panic!("range from full grid area"),
|
||||||
IndexArea::Set(v) =>
|
IndexArea::Set(v) => {
|
||||||
Point2::new(
|
Point2::new(
|
||||||
v.iter().map(|p| p.x).min().unwrap_or(0),
|
v.iter().map(|p| p.x).min().unwrap_or(0),
|
||||||
v.iter().map(|p| p.y).min().unwrap_or(0)
|
v.iter().map(|p| p.y).min().unwrap_or(0),
|
||||||
) ..=
|
)
|
||||||
Point2::new(
|
..=Point2::new(
|
||||||
v.iter().map(|p| p.x).max().unwrap_or(0),
|
v.iter().map(|p| p.x).max().unwrap_or(0),
|
||||||
v.iter().map(|p| p.y).max().unwrap_or(0)
|
v.iter().map(|p| p.y).max().unwrap_or(0),
|
||||||
),
|
)
|
||||||
IndexArea::Range(r) => r.clone()
|
}
|
||||||
|
IndexArea::Range(r) => r.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn union(self, other: IndexArea<Point2<i16>>) -> IndexArea<Point2<i16>> {
|
pub fn union(self, other: IndexArea<Point2<i16>>) -> IndexArea<Point2<i16>> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(IndexArea::Empty, a) |
|
(IndexArea::Empty, a) | (a, IndexArea::Empty) => a,
|
||||||
(a, IndexArea::Empty) => a,
|
|
||||||
|
|
||||||
(IndexArea::Full, _) |
|
(IndexArea::Full, _) | (_, IndexArea::Full) => IndexArea::Full,
|
||||||
(_, IndexArea::Full) => IndexArea::Full,
|
|
||||||
|
|
||||||
(IndexArea::Set(mut va), IndexArea::Set(mut vb)) => {
|
(IndexArea::Set(mut va), IndexArea::Set(vb)) => {
|
||||||
va.extend(vb.into_iter());
|
va.extend(vb.into_iter());
|
||||||
IndexArea::Set(va)
|
IndexArea::Set(va)
|
||||||
},
|
}
|
||||||
|
|
||||||
(IndexArea::Range(r), IndexArea::Set(mut v)) |
|
(IndexArea::Range(r), IndexArea::Set(mut v))
|
||||||
(IndexArea::Set(mut v), IndexArea::Range(r)) => {
|
| (IndexArea::Set(mut v), IndexArea::Range(r)) => {
|
||||||
v.extend(GridWindowIterator::from(r));
|
v.extend(GridWindowIterator::from(r));
|
||||||
IndexArea::Set(v)
|
IndexArea::Set(v)
|
||||||
},
|
}
|
||||||
|
|
||||||
(IndexArea::Range(ra), IndexArea::Range(rb)) => IndexArea::Range(
|
(IndexArea::Range(ra), IndexArea::Range(rb)) => IndexArea::Range(
|
||||||
Point2::new(
|
Point2::new(
|
||||||
min(ra.start().x, rb.start().x),
|
min(ra.start().x, rb.start().x),
|
||||||
min(ra.start().y, rb.start().y)
|
min(ra.start().y, rb.start().y),
|
||||||
)
|
)
|
||||||
..=
|
..=Point2::new(max(ra.end().x, rb.end().x), max(ra.end().y, rb.end().y)),
|
||||||
Point2::new(
|
),
|
||||||
max(ra.end().x, rb.end().x),
|
|
||||||
max(ra.end().y, rb.end().y)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,15 @@
|
||||||
use {
|
use {
|
||||||
|
crate::{core::OuterViewPort, grid::GridView},
|
||||||
cgmath::Vector2,
|
cgmath::Vector2,
|
||||||
crate::{
|
|
||||||
core::OuterViewPort,
|
|
||||||
grid::GridView
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl<Item> OuterViewPort<dyn GridView<Item = Item>>
|
impl<Item> OuterViewPort<dyn GridView<Item = Item>>
|
||||||
where Item: 'static {
|
where
|
||||||
|
Item: 'static,
|
||||||
|
{
|
||||||
pub fn offset(&self, offset: Vector2<i16>) -> OuterViewPort<dyn GridView<Item = Item>> {
|
pub fn offset(&self, offset: Vector2<i16>) -> OuterViewPort<dyn GridView<Item = Item>> {
|
||||||
self.map_key(
|
self.map_key(move |pt| pt + offset, move |pt| Some(pt - offset))
|
||||||
move |pt| pt + offset,
|
|
||||||
move |pt| Some(pt - offset)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
|
|
||||||
use {
|
use {
|
||||||
|
cgmath::Point2,
|
||||||
std::ops::{Range, RangeInclusive},
|
std::ops::{Range, RangeInclusive},
|
||||||
cgmath::{Point2}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub struct GridWindowIterator {
|
pub struct GridWindowIterator {
|
||||||
next: Point2<i16>,
|
next: Point2<i16>,
|
||||||
range: Range<Point2<i16>>
|
range: Range<Point2<i16>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
@ -17,7 +16,7 @@ impl From<Range<Point2<i16>>> for GridWindowIterator {
|
||||||
fn from(range: Range<Point2<i16>>) -> Self {
|
fn from(range: Range<Point2<i16>>) -> Self {
|
||||||
GridWindowIterator {
|
GridWindowIterator {
|
||||||
next: range.start,
|
next: range.start,
|
||||||
range
|
range,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +25,7 @@ impl From<RangeInclusive<Point2<i16>>> for GridWindowIterator {
|
||||||
fn from(range: RangeInclusive<Point2<i16>>) -> Self {
|
fn from(range: RangeInclusive<Point2<i16>>) -> Self {
|
||||||
GridWindowIterator {
|
GridWindowIterator {
|
||||||
next: *range.start(),
|
next: *range.start(),
|
||||||
range: *range.start() .. Point2::new(range.end().x+1, range.end().y+1)
|
range: *range.start()..Point2::new(range.end().x + 1, range.end().y + 1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +40,7 @@ impl Iterator for GridWindowIterator {
|
||||||
if self.next.x < self.range.end.x {
|
if self.next.x < self.range.end.x {
|
||||||
let next = self.next;
|
let next = self.next;
|
||||||
|
|
||||||
if self.next.x+1 < self.range.end.x {
|
if self.next.x + 1 < self.range.end.x {
|
||||||
self.next.x += 1;
|
self.next.x += 1;
|
||||||
} else {
|
} else {
|
||||||
self.next.x = self.range.start.x;
|
self.next.x = self.range.start.x;
|
||||||
|
@ -57,4 +56,3 @@ impl Iterator for GridWindowIterator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,36 +1,29 @@
|
||||||
|
|
||||||
use {
|
use {
|
||||||
std::{
|
crate::{
|
||||||
sync::Arc,
|
core::{InnerViewPort, Observer, ObserverBroadcast, View},
|
||||||
collections::HashMap,
|
index::{IndexArea, IndexView},
|
||||||
hash::Hash
|
|
||||||
},
|
},
|
||||||
std::sync::RwLock,
|
std::sync::RwLock,
|
||||||
crate::{
|
std::{collections::HashMap, hash::Hash, sync::Arc},
|
||||||
core::{
|
|
||||||
Observer,
|
|
||||||
ObserverBroadcast,
|
|
||||||
View,
|
|
||||||
InnerViewPort
|
|
||||||
},
|
|
||||||
index::{IndexArea, IndexView}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct IndexBufferView<Key, Item>(Arc<RwLock<HashMap<Key, Item>>>)
|
pub struct IndexBufferView<Key, Item>(Arc<RwLock<HashMap<Key, Item>>>)
|
||||||
where Key: Clone + Hash + Eq + Send + Sync + 'static,
|
where
|
||||||
Item: Clone + Send + Sync + 'static;
|
Key: Clone + Hash + Eq + Send + Sync + 'static,
|
||||||
|
Item: Clone + Send + Sync + 'static;
|
||||||
|
|
||||||
impl<Key, Item> View for IndexBufferView<Key, Item>
|
impl<Key, Item> View for IndexBufferView<Key, Item>
|
||||||
where Key: Clone + Hash + Eq + Send + Sync + 'static,
|
where
|
||||||
Item: Clone + Send + Sync + 'static
|
Key: Clone + Hash + Eq + Send + Sync + 'static,
|
||||||
|
Item: Clone + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
type Msg = IndexArea<Key>;
|
type Msg = IndexArea<Key>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Key, Item> IndexView<Key> for IndexBufferView<Key, Item>
|
impl<Key, Item> IndexView<Key> for IndexBufferView<Key, Item>
|
||||||
where Key: Clone + Hash + Eq + Send + Sync + 'static,
|
where
|
||||||
Item: Clone + Send + Sync + 'static
|
Key: Clone + Hash + Eq + Send + Sync + 'static,
|
||||||
|
Item: Clone + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
type Item = Item;
|
type Item = Item;
|
||||||
|
|
||||||
|
@ -44,16 +37,18 @@ where Key: Clone + Hash + Eq + Send + Sync + 'static,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IndexBuffer<Key, Item>
|
pub struct IndexBuffer<Key, Item>
|
||||||
where Key: Clone + Hash + Eq + Send + Sync + 'static,
|
where
|
||||||
Item: Clone + Send + Sync + 'static
|
Key: Clone + Hash + Eq + Send + Sync + 'static,
|
||||||
|
Item: Clone + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
data: Arc<RwLock<HashMap<Key, Item>>>,
|
data: Arc<RwLock<HashMap<Key, Item>>>,
|
||||||
cast: Arc<RwLock<ObserverBroadcast<dyn IndexView<Key, Item = Item>>>>
|
cast: Arc<RwLock<ObserverBroadcast<dyn IndexView<Key, Item = Item>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Key, Item> IndexBuffer<Key, Item>
|
impl<Key, Item> IndexBuffer<Key, Item>
|
||||||
where Key: Clone + Hash + Eq + Send + Sync + 'static,
|
where
|
||||||
Item: Clone + Send + Sync + 'static
|
Key: Clone + Hash + Eq + Send + Sync + 'static,
|
||||||
|
Item: Clone + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
pub fn new(port: InnerViewPort<dyn IndexView<Key, Item = Item>>) -> Self {
|
pub fn new(port: InnerViewPort<dyn IndexView<Key, Item = Item>>) -> Self {
|
||||||
let data = Arc::new(RwLock::new(HashMap::<Key, Item>::new()));
|
let data = Arc::new(RwLock::new(HashMap::<Key, Item>::new()));
|
||||||
|
@ -61,17 +56,19 @@ where Key: Clone + Hash + Eq + Send + Sync + 'static,
|
||||||
|
|
||||||
IndexBuffer {
|
IndexBuffer {
|
||||||
data,
|
data,
|
||||||
cast: port.get_broadcast()
|
cast: port.get_broadcast(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, key: Key, item: Item) {
|
pub fn insert(&mut self, key: Key, item: Item) {
|
||||||
self.data.write().unwrap().insert(key.clone(), item);
|
self.data.write().unwrap().insert(key.clone(), item);
|
||||||
self.cast.notify(&IndexArea::Set(vec![ key ]));
|
self.cast.notify(&IndexArea::Set(vec![key]));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_iter<T>(&mut self, iter: T)
|
pub fn insert_iter<T>(&mut self, iter: T)
|
||||||
where T: IntoIterator<Item = (Key, Item)> {
|
where
|
||||||
|
T: IntoIterator<Item = (Key, Item)>,
|
||||||
|
{
|
||||||
for (key, item) in iter {
|
for (key, item) in iter {
|
||||||
self.insert(key, item);
|
self.insert(key, item);
|
||||||
}
|
}
|
||||||
|
@ -79,7 +76,6 @@ where Key: Clone + Hash + Eq + Send + Sync + 'static,
|
||||||
|
|
||||||
pub fn remove(&mut self, key: Key) {
|
pub fn remove(&mut self, key: Key) {
|
||||||
self.data.write().unwrap().remove(&key);
|
self.data.write().unwrap().remove(&key);
|
||||||
self.cast.notify(&IndexArea::Set(vec![ key ]));
|
self.cast.notify(&IndexArea::Set(vec![key]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,33 +1,22 @@
|
||||||
pub use {
|
pub use {
|
||||||
std::{
|
|
||||||
sync::Arc,
|
|
||||||
boxed::Box
|
|
||||||
},
|
|
||||||
std::sync::RwLock,
|
|
||||||
crate::{
|
crate::{
|
||||||
core::{
|
core::{
|
||||||
View,
|
InnerViewPort, Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View, ViewPort,
|
||||||
Observer,
|
|
||||||
ObserverExt,
|
|
||||||
ObserverBroadcast,
|
|
||||||
ViewPort,
|
|
||||||
InnerViewPort,
|
|
||||||
OuterViewPort
|
|
||||||
},
|
},
|
||||||
index::{IndexArea, IndexView}
|
index::{IndexArea, IndexView},
|
||||||
}
|
},
|
||||||
|
std::sync::RwLock,
|
||||||
|
std::{boxed::Box, sync::Arc},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<Key, Item> OuterViewPort<dyn IndexView<Key, Item = Item>>
|
impl<Key, Item> OuterViewPort<dyn IndexView<Key, Item = Item>>
|
||||||
where Key: Clone + Send + Sync + 'static,
|
where
|
||||||
Item: Send + Sync + 'static
|
Key: Clone + Send + Sync + 'static,
|
||||||
|
Item: Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
pub fn map_item<
|
pub fn map_item<DstItem: 'static, F: Fn(&Key, &Item) -> DstItem + Send + Sync + 'static>(
|
||||||
DstItem: 'static,
|
|
||||||
F: Fn(&Key, &Item) -> DstItem + Send + Sync + 'static
|
|
||||||
>(
|
|
||||||
&self,
|
&self,
|
||||||
f: F
|
f: F,
|
||||||
) -> OuterViewPort<dyn IndexView<Key, Item = DstItem>> {
|
) -> OuterViewPort<dyn IndexView<Key, Item = DstItem>> {
|
||||||
let port = ViewPort::new();
|
let port = ViewPort::new();
|
||||||
port.add_update_hook(Arc::new(self.0.clone()));
|
port.add_update_hook(Arc::new(self.0.clone()));
|
||||||
|
@ -39,32 +28,29 @@ where Key: Clone + Send + Sync + 'static,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MapIndexItem<Key, DstItem, SrcView, F>
|
pub struct MapIndexItem<Key, DstItem, SrcView, F>
|
||||||
where Key: Clone + Send + Sync,
|
where
|
||||||
SrcView: IndexView<Key> + ?Sized,
|
Key: Clone + Send + Sync,
|
||||||
F: Fn(&Key, &SrcView::Item) -> DstItem + Send + Sync
|
SrcView: IndexView<Key> + ?Sized,
|
||||||
|
F: Fn(&Key, &SrcView::Item) -> DstItem + Send + Sync,
|
||||||
{
|
{
|
||||||
src_view: Option<Arc<SrcView>>,
|
src_view: Option<Arc<SrcView>>,
|
||||||
f: F,
|
f: F,
|
||||||
cast: Arc<RwLock<ObserverBroadcast<dyn IndexView<Key, Item = DstItem>>>>
|
cast: Arc<RwLock<ObserverBroadcast<dyn IndexView<Key, Item = DstItem>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Key, DstItem, SrcView, F> MapIndexItem<Key, DstItem, SrcView, F>
|
impl<Key, DstItem, SrcView, F> MapIndexItem<Key, DstItem, SrcView, F>
|
||||||
where Key: Clone + Send + Sync + 'static,
|
where
|
||||||
DstItem: 'static,
|
Key: Clone + Send + Sync + 'static,
|
||||||
SrcView: IndexView<Key> + ?Sized + 'static,
|
DstItem: 'static,
|
||||||
F: Fn(&Key, &SrcView::Item) -> DstItem + Send + Sync + 'static
|
SrcView: IndexView<Key> + ?Sized + 'static,
|
||||||
|
F: Fn(&Key, &SrcView::Item) -> DstItem + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
fn new(
|
fn new(port: InnerViewPort<dyn IndexView<Key, Item = DstItem>>, f: F) -> Arc<RwLock<Self>> {
|
||||||
port: InnerViewPort<dyn IndexView<Key, Item = DstItem>>,
|
let map = Arc::new(RwLock::new(MapIndexItem {
|
||||||
f: F
|
src_view: None,
|
||||||
) -> Arc<RwLock<Self>> {
|
f,
|
||||||
let map = Arc::new(RwLock::new(
|
cast: port.get_broadcast(),
|
||||||
MapIndexItem {
|
}));
|
||||||
src_view: None,
|
|
||||||
f,
|
|
||||||
cast: port.get_broadcast()
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
port.set_view(Some(map.clone()));
|
port.set_view(Some(map.clone()));
|
||||||
map
|
map
|
||||||
|
@ -72,22 +58,27 @@ where Key: Clone + Send + Sync + 'static,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Key, DstItem, SrcView, F> View for MapIndexItem<Key, DstItem, SrcView, F>
|
impl<Key, DstItem, SrcView, F> View for MapIndexItem<Key, DstItem, SrcView, F>
|
||||||
where Key: Clone + Send + Sync,
|
where
|
||||||
SrcView: IndexView<Key> + ?Sized,
|
Key: Clone + Send + Sync,
|
||||||
F: Fn(&Key, &SrcView::Item) -> DstItem + Send + Sync
|
SrcView: IndexView<Key> + ?Sized,
|
||||||
|
F: Fn(&Key, &SrcView::Item) -> DstItem + Send + Sync,
|
||||||
{
|
{
|
||||||
type Msg = IndexArea<Key>;
|
type Msg = IndexArea<Key>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Key, DstItem, SrcView, F> IndexView<Key> for MapIndexItem<Key, DstItem, SrcView, F>
|
impl<Key, DstItem, SrcView, F> IndexView<Key> for MapIndexItem<Key, DstItem, SrcView, F>
|
||||||
where Key: Clone + Send + Sync,
|
where
|
||||||
SrcView: IndexView<Key> + ?Sized,
|
Key: Clone + Send + Sync,
|
||||||
F: Fn(&Key, &SrcView::Item) -> DstItem + Send + Sync
|
SrcView: IndexView<Key> + ?Sized,
|
||||||
|
F: Fn(&Key, &SrcView::Item) -> DstItem + Send + Sync,
|
||||||
{
|
{
|
||||||
type Item = DstItem;
|
type Item = DstItem;
|
||||||
|
|
||||||
fn get(&self, key: &Key) -> Option<Self::Item> {
|
fn get(&self, key: &Key) -> Option<Self::Item> {
|
||||||
self.src_view.get(key).as_ref().map(|item| (self.f)(key, item))
|
self.src_view
|
||||||
|
.get(key)
|
||||||
|
.as_ref()
|
||||||
|
.map(|item| (self.f)(key, item))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn area(&self) -> IndexArea<Key> {
|
fn area(&self) -> IndexArea<Key> {
|
||||||
|
@ -96,9 +87,10 @@ where Key: Clone + Send + Sync,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Key, DstItem, SrcView, F> Observer<SrcView> for MapIndexItem<Key, DstItem, SrcView, F>
|
impl<Key, DstItem, SrcView, F> Observer<SrcView> for MapIndexItem<Key, DstItem, SrcView, F>
|
||||||
where Key: Clone + Send + Sync,
|
where
|
||||||
SrcView: IndexView<Key> + ?Sized,
|
Key: Clone + Send + Sync,
|
||||||
F: Fn(&Key, &SrcView::Item) -> DstItem + Send + Sync
|
SrcView: IndexView<Key> + ?Sized,
|
||||||
|
F: Fn(&Key, &SrcView::Item) -> DstItem + Send + Sync,
|
||||||
{
|
{
|
||||||
fn reset(&mut self, view: Option<Arc<SrcView>>) {
|
fn reset(&mut self, view: Option<Arc<SrcView>>) {
|
||||||
let old_area = self.area();
|
let old_area = self.area();
|
||||||
|
@ -113,4 +105,3 @@ where Key: Clone + Send + Sync,
|
||||||
self.cast.notify(area);
|
self.cast.notify(area);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,19 @@
|
||||||
pub use {
|
pub use {
|
||||||
std::{
|
|
||||||
sync::Arc,
|
|
||||||
boxed::Box
|
|
||||||
},
|
|
||||||
std::sync::RwLock,
|
|
||||||
crate::{
|
crate::{
|
||||||
core::{
|
core::{
|
||||||
View,
|
InnerViewPort, Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View, ViewPort,
|
||||||
Observer,
|
|
||||||
ObserverExt,
|
|
||||||
ObserverBroadcast,
|
|
||||||
ViewPort,
|
|
||||||
InnerViewPort,
|
|
||||||
OuterViewPort
|
|
||||||
},
|
},
|
||||||
|
grid::GridView,
|
||||||
index::{IndexArea, IndexView},
|
index::{IndexArea, IndexView},
|
||||||
grid::{GridView}
|
},
|
||||||
}
|
std::sync::RwLock,
|
||||||
|
std::{boxed::Box, sync::Arc},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<SrcKey, Item> OuterViewPort<dyn IndexView<SrcKey, Item = Item>>
|
impl<SrcKey, Item> OuterViewPort<dyn IndexView<SrcKey, Item = Item>>
|
||||||
where SrcKey: Clone + Send + Sync + 'static,
|
where
|
||||||
Item: 'static
|
SrcKey: Clone + Send + Sync + 'static,
|
||||||
|
Item: 'static,
|
||||||
{
|
{
|
||||||
pub fn map_key<
|
pub fn map_key<
|
||||||
DstKey: Clone + Send + Sync + 'static,
|
DstKey: Clone + Send + Sync + 'static,
|
||||||
|
@ -30,7 +22,7 @@ where SrcKey: Clone + Send + Sync + 'static,
|
||||||
>(
|
>(
|
||||||
&self,
|
&self,
|
||||||
f1: F1,
|
f1: F1,
|
||||||
f2: F2
|
f2: F2,
|
||||||
) -> OuterViewPort<dyn IndexView<DstKey, Item = Item>> {
|
) -> OuterViewPort<dyn IndexView<DstKey, Item = Item>> {
|
||||||
let port = ViewPort::new();
|
let port = ViewPort::new();
|
||||||
port.add_update_hook(Arc::new(self.0.clone()));
|
port.add_update_hook(Arc::new(self.0.clone()));
|
||||||
|
@ -42,57 +34,58 @@ where SrcKey: Clone + Send + Sync + 'static,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Item> OuterViewPort<dyn IndexView<usize, Item = Item>>
|
impl<Item> OuterViewPort<dyn IndexView<usize, Item = Item>>
|
||||||
where Item: 'static
|
where
|
||||||
|
Item: 'static,
|
||||||
{
|
{
|
||||||
pub fn to_grid_horizontal(&self) -> OuterViewPort<dyn GridView<Item = Item>> {
|
pub fn to_grid_horizontal(&self) -> OuterViewPort<dyn GridView<Item = Item>> {
|
||||||
self.map_key(
|
self.map_key(
|
||||||
|idx| cgmath::Point2::new(*idx as i16, 0),
|
|idx| cgmath::Point2::new(*idx as i16, 0),
|
||||||
|pt| if pt.y == 0 { Some(pt.x as usize) } else { None }
|
|pt| if pt.y == 0 { Some(pt.x as usize) } else { None },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_grid_vertical(&self) -> OuterViewPort<dyn GridView<Item = Item>> {
|
pub fn to_grid_vertical(&self) -> OuterViewPort<dyn GridView<Item = Item>> {
|
||||||
self.map_key(
|
self.map_key(
|
||||||
|idx| cgmath::Point2::new(0, *idx as i16),
|
|idx| cgmath::Point2::new(0, *idx as i16),
|
||||||
|pt| if pt.x == 0 { Some(pt.y as usize) } else { None }
|
|pt| if pt.x == 0 { Some(pt.y as usize) } else { None },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MapIndexKey<DstKey, SrcKey, SrcView, F1, F2>
|
pub struct MapIndexKey<DstKey, SrcKey, SrcView, F1, F2>
|
||||||
where DstKey: Clone + Send + Sync,
|
where
|
||||||
SrcKey: Clone + Send + Sync,
|
DstKey: Clone + Send + Sync,
|
||||||
SrcView: IndexView<SrcKey> + ?Sized,
|
SrcKey: Clone + Send + Sync,
|
||||||
F1: Fn(&SrcKey) -> DstKey + Send + Sync,
|
SrcView: IndexView<SrcKey> + ?Sized,
|
||||||
F2: Fn(&DstKey) -> Option<SrcKey> + Send + Sync,
|
F1: Fn(&SrcKey) -> DstKey + Send + Sync,
|
||||||
|
F2: Fn(&DstKey) -> Option<SrcKey> + Send + Sync,
|
||||||
{
|
{
|
||||||
src_view: Option<Arc<SrcView>>,
|
src_view: Option<Arc<SrcView>>,
|
||||||
f1: F1,
|
f1: F1,
|
||||||
f2: F2,
|
f2: F2,
|
||||||
cast: Arc<RwLock<ObserverBroadcast<dyn IndexView<DstKey, Item = SrcView::Item>>>>
|
cast: Arc<RwLock<ObserverBroadcast<dyn IndexView<DstKey, Item = SrcView::Item>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<DstKey, SrcKey, SrcView, F1, F2> MapIndexKey<DstKey, SrcKey, SrcView, F1, F2>
|
impl<DstKey, SrcKey, SrcView, F1, F2> MapIndexKey<DstKey, SrcKey, SrcView, F1, F2>
|
||||||
where DstKey: Clone + Send + Sync + 'static,
|
where
|
||||||
SrcKey: Clone + Send + Sync + 'static,
|
DstKey: Clone + Send + Sync + 'static,
|
||||||
SrcView: IndexView<SrcKey> + ?Sized + 'static,
|
SrcKey: Clone + Send + Sync + 'static,
|
||||||
SrcView::Item: 'static,
|
SrcView: IndexView<SrcKey> + ?Sized + 'static,
|
||||||
F1: Fn(&SrcKey) -> DstKey + Send + Sync + 'static,
|
SrcView::Item: 'static,
|
||||||
F2: Fn(&DstKey) -> Option<SrcKey> + Send + Sync + 'static,
|
F1: Fn(&SrcKey) -> DstKey + Send + Sync + 'static,
|
||||||
|
F2: Fn(&DstKey) -> Option<SrcKey> + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
fn new(
|
fn new(
|
||||||
port: InnerViewPort<dyn IndexView<DstKey, Item = SrcView::Item>>,
|
port: InnerViewPort<dyn IndexView<DstKey, Item = SrcView::Item>>,
|
||||||
f1: F1,
|
f1: F1,
|
||||||
f2: F2
|
f2: F2,
|
||||||
) -> Arc<RwLock<Self>> {
|
) -> Arc<RwLock<Self>> {
|
||||||
let map = Arc::new(RwLock::new(
|
let map = Arc::new(RwLock::new(MapIndexKey {
|
||||||
MapIndexKey {
|
src_view: None,
|
||||||
src_view: None,
|
f1,
|
||||||
f1,
|
f2,
|
||||||
f2,
|
cast: port.get_broadcast(),
|
||||||
cast: port.get_broadcast()
|
}));
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
port.set_view(Some(map.clone()));
|
port.set_view(Some(map.clone()));
|
||||||
map
|
map
|
||||||
|
@ -100,21 +93,24 @@ where DstKey: Clone + Send + Sync + 'static,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<DstKey, SrcKey, SrcView, F1, F2> View for MapIndexKey<DstKey, SrcKey, SrcView, F1, F2>
|
impl<DstKey, SrcKey, SrcView, F1, F2> View for MapIndexKey<DstKey, SrcKey, SrcView, F1, F2>
|
||||||
where DstKey: Clone + Send + Sync,
|
where
|
||||||
SrcKey: Clone + Send + Sync,
|
DstKey: Clone + Send + Sync,
|
||||||
SrcView: IndexView<SrcKey> + ?Sized,
|
SrcKey: Clone + Send + Sync,
|
||||||
F1: Fn(&SrcKey) -> DstKey + Send + Sync,
|
SrcView: IndexView<SrcKey> + ?Sized,
|
||||||
F2: Fn(&DstKey) -> Option<SrcKey> + Send + Sync,
|
F1: Fn(&SrcKey) -> DstKey + Send + Sync,
|
||||||
|
F2: Fn(&DstKey) -> Option<SrcKey> + Send + Sync,
|
||||||
{
|
{
|
||||||
type Msg = IndexArea<DstKey>;
|
type Msg = IndexArea<DstKey>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<DstKey, SrcKey, SrcView, F1, F2> IndexView<DstKey> for MapIndexKey<DstKey, SrcKey, SrcView, F1, F2>
|
impl<DstKey, SrcKey, SrcView, F1, F2> IndexView<DstKey>
|
||||||
where DstKey: Clone + Send + Sync,
|
for MapIndexKey<DstKey, SrcKey, SrcView, F1, F2>
|
||||||
SrcKey: Clone + Send + Sync,
|
where
|
||||||
SrcView: IndexView<SrcKey> + ?Sized,
|
DstKey: Clone + Send + Sync,
|
||||||
F1: Fn(&SrcKey) -> DstKey + Send + Sync,
|
SrcKey: Clone + Send + Sync,
|
||||||
F2: Fn(&DstKey) -> Option<SrcKey> + Send + Sync,
|
SrcView: IndexView<SrcKey> + ?Sized,
|
||||||
|
F1: Fn(&SrcKey) -> DstKey + Send + Sync,
|
||||||
|
F2: Fn(&DstKey) -> Option<SrcKey> + Send + Sync,
|
||||||
{
|
{
|
||||||
type Item = SrcView::Item;
|
type Item = SrcView::Item;
|
||||||
|
|
||||||
|
@ -127,12 +123,14 @@ where DstKey: Clone + Send + Sync,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<DstKey, SrcKey, SrcView, F1, F2> Observer<SrcView> for MapIndexKey<DstKey, SrcKey, SrcView, F1, F2>
|
impl<DstKey, SrcKey, SrcView, F1, F2> Observer<SrcView>
|
||||||
where DstKey: Clone + Send + Sync,
|
for MapIndexKey<DstKey, SrcKey, SrcView, F1, F2>
|
||||||
SrcKey: Clone + Send + Sync,
|
where
|
||||||
SrcView: IndexView<SrcKey> + ?Sized,
|
DstKey: Clone + Send + Sync,
|
||||||
F1: Fn(&SrcKey) -> DstKey + Send + Sync,
|
SrcKey: Clone + Send + Sync,
|
||||||
F2: Fn(&DstKey) -> Option<SrcKey> + 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>>) {
|
fn reset(&mut self, view: Option<Arc<SrcView>>) {
|
||||||
let old_area = self.area();
|
let old_area = self.area();
|
||||||
|
@ -145,4 +143,3 @@ where DstKey: Clone + Send + Sync,
|
||||||
self.cast.notify(&msg.map(&self.f1));
|
self.cast.notify(&msg.map(&self.f1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
|
pub mod buffer;
|
||||||
pub mod map_item;
|
pub mod map_item;
|
||||||
pub mod map_key;
|
pub mod map_key;
|
||||||
pub mod buffer;
|
|
||||||
|
|
||||||
use {
|
use {
|
||||||
std::{
|
crate::core::View,
|
||||||
sync::Arc,
|
|
||||||
ops::{Deref, RangeInclusive},
|
|
||||||
},
|
|
||||||
std::sync::RwLock,
|
std::sync::RwLock,
|
||||||
crate::core::View
|
std::{
|
||||||
|
ops::{Deref, RangeInclusive},
|
||||||
|
sync::Arc,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
@ -29,13 +28,15 @@ impl<Key> IndexArea<Key> {
|
||||||
IndexArea::Empty => IndexArea::Empty,
|
IndexArea::Empty => IndexArea::Empty,
|
||||||
IndexArea::Full => IndexArea::Full,
|
IndexArea::Full => IndexArea::Full,
|
||||||
IndexArea::Set(v) => IndexArea::Set(v.iter().map(&f).collect()),
|
IndexArea::Set(v) => IndexArea::Set(v.iter().map(&f).collect()),
|
||||||
IndexArea::Range(r) => IndexArea::Range(f(&r.start()) ..= f(&r.end()))
|
IndexArea::Range(r) => IndexArea::Range(f(&r.start())..=f(&r.end())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait IndexView<Key> : View<Msg = IndexArea<Key>>
|
pub trait IndexView<Key>: View<Msg = IndexArea<Key>>
|
||||||
where Key: Send + Sync {
|
where
|
||||||
|
Key: Send + Sync,
|
||||||
|
{
|
||||||
type Item;
|
type Item;
|
||||||
|
|
||||||
fn get(&self, key: &Key) -> Option<Self::Item>;
|
fn get(&self, key: &Key) -> Option<Self::Item>;
|
||||||
|
@ -48,8 +49,9 @@ where Key: Send + Sync {
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl<Key, V> IndexView<Key> for RwLock<V>
|
impl<Key, V> IndexView<Key> for RwLock<V>
|
||||||
where Key: Send + Sync,
|
where
|
||||||
V: IndexView<Key> + ?Sized
|
Key: Send + Sync,
|
||||||
|
V: IndexView<Key> + ?Sized,
|
||||||
{
|
{
|
||||||
type Item = V::Item;
|
type Item = V::Item;
|
||||||
|
|
||||||
|
@ -63,8 +65,9 @@ where Key: Send + Sync,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Key, V> IndexView<Key> for Arc<V>
|
impl<Key, V> IndexView<Key> for Arc<V>
|
||||||
where Key: Send + Sync,
|
where
|
||||||
V: IndexView<Key> + ?Sized
|
Key: Send + Sync,
|
||||||
|
V: IndexView<Key> + ?Sized,
|
||||||
{
|
{
|
||||||
type Item = V::Item;
|
type Item = V::Item;
|
||||||
|
|
||||||
|
@ -78,8 +81,9 @@ where Key: Send + Sync,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Key, V> IndexView<Key> for Option<V>
|
impl<Key, V> IndexView<Key> for Option<V>
|
||||||
where Key: Send + Sync,
|
where
|
||||||
V: IndexView<Key>
|
Key: Send + Sync,
|
||||||
|
V: IndexView<Key>,
|
||||||
{
|
{
|
||||||
type Item = V::Item;
|
type Item = V::Item;
|
||||||
|
|
||||||
|
|
|
@ -1,35 +1,27 @@
|
||||||
use {
|
use {
|
||||||
std::sync::{Arc, RwLock},
|
|
||||||
crate::{
|
crate::{
|
||||||
core::{InnerViewPort, OuterViewPort},
|
core::{InnerViewPort, OuterViewPort},
|
||||||
|
projection::ProjectionHelper,
|
||||||
sequence::SequenceView,
|
sequence::SequenceView,
|
||||||
vec::VecBuffer,
|
vec::VecBuffer,
|
||||||
projection::ProjectionHelper
|
},
|
||||||
}
|
std::sync::{Arc, RwLock},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn posint_add(
|
fn posint_add(
|
||||||
radix: usize,
|
radix: usize,
|
||||||
a: impl SequenceView<Item = usize>,
|
a: impl SequenceView<Item = usize>,
|
||||||
b: impl SequenceView<Item = usize>
|
b: impl SequenceView<Item = usize>,
|
||||||
) -> Vec<usize> {
|
) -> Vec<usize> {
|
||||||
let mut carry = 0;
|
let mut carry = 0;
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
|
|
||||||
for digit_idx in 0 .. std::cmp::max(a.len().unwrap_or(0), b.len().unwrap_or(0)) {
|
for digit_idx in 0..std::cmp::max(a.len().unwrap_or(0), b.len().unwrap_or(0)) {
|
||||||
let sum =
|
let sum = a.get(&digit_idx).unwrap_or(0) + b.get(&digit_idx).unwrap_or(0) + carry;
|
||||||
a.get(&digit_idx).unwrap_or(0) +
|
|
||||||
b.get(&digit_idx).unwrap_or(0) +
|
|
||||||
carry;
|
|
||||||
|
|
||||||
result.push(sum % radix);
|
result.push(sum % radix);
|
||||||
|
|
||||||
carry =
|
carry = if sum > radix { sum - radix } else { 0 };
|
||||||
if sum > radix {
|
|
||||||
sum - radix
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if carry > 0 {
|
if carry > 0 {
|
||||||
|
@ -44,7 +36,7 @@ pub struct Add {
|
||||||
a: Arc<dyn SequenceView<Item = usize>>, // PosInt, Little Endian
|
a: Arc<dyn SequenceView<Item = usize>>, // PosInt, Little Endian
|
||||||
b: Arc<dyn SequenceView<Item = usize>>, // PosInt, Little Endian
|
b: Arc<dyn SequenceView<Item = usize>>, // PosInt, Little Endian
|
||||||
c: VecBuffer<usize>,
|
c: VecBuffer<usize>,
|
||||||
_proj_helper: ProjectionHelper<usize, Self>
|
_proj_helper: ProjectionHelper<usize, Self>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Add {
|
impl Add {
|
||||||
|
@ -52,18 +44,16 @@ impl Add {
|
||||||
radix: usize,
|
radix: usize,
|
||||||
a: OuterViewPort<dyn SequenceView<Item = usize>>,
|
a: OuterViewPort<dyn SequenceView<Item = usize>>,
|
||||||
b: OuterViewPort<dyn SequenceView<Item = usize>>,
|
b: OuterViewPort<dyn SequenceView<Item = usize>>,
|
||||||
c: InnerViewPort<RwLock<Vec<usize>>>//<dyn SequenceView<Item = usize>>
|
c: InnerViewPort<RwLock<Vec<usize>>>, //<dyn SequenceView<Item = usize>>
|
||||||
) -> Arc<RwLock<Self>> {
|
) -> Arc<RwLock<Self>> {
|
||||||
let mut proj_helper = ProjectionHelper::new(c.0.update_hooks.clone());
|
let mut proj_helper = ProjectionHelper::new(c.0.update_hooks.clone());
|
||||||
let add = Arc::new(RwLock::new(
|
let add = Arc::new(RwLock::new(Add {
|
||||||
Add {
|
radix,
|
||||||
radix,
|
a: proj_helper.new_sequence_arg(0, a, |s: &mut Self, _digit_idx| s.update()),
|
||||||
a: proj_helper.new_sequence_arg(0, a, |s: &mut Self, _digit_idx| s.update()),
|
b: proj_helper.new_sequence_arg(1, b, |s: &mut Self, _digit_idx| s.update()),
|
||||||
b: proj_helper.new_sequence_arg(1, b, |s: &mut Self, _digit_idx| s.update()),
|
c: VecBuffer::new(c),
|
||||||
c: VecBuffer::new(c),
|
_proj_helper: proj_helper,
|
||||||
_proj_helper: proj_helper
|
}));
|
||||||
}
|
|
||||||
));
|
|
||||||
add
|
add
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
use {
|
use {
|
||||||
|
crate::{
|
||||||
|
core::{OuterViewPort, ViewPort},
|
||||||
|
list::{sexpr::ListDecoration, ListEditor},
|
||||||
|
sequence::{SequenceView, SequenceViewExt},
|
||||||
|
singleton::{SingletonBuffer, SingletonView},
|
||||||
|
terminal::{
|
||||||
|
TerminalAtom, TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle,
|
||||||
|
TerminalView,
|
||||||
|
},
|
||||||
|
tree_nav::{TerminalTreeEditor, TreeCursor, TreeNav, TreeNavResult},
|
||||||
|
},
|
||||||
std::sync::Arc,
|
std::sync::Arc,
|
||||||
std::sync::RwLock,
|
std::sync::RwLock,
|
||||||
termion::event::{Key, Event},
|
termion::event::{Event, Key},
|
||||||
cgmath::Point2,
|
|
||||||
crate::{
|
|
||||||
core::{ViewPort, OuterViewPort, Observer},
|
|
||||||
singleton::{SingletonView, SingletonBuffer},
|
|
||||||
sequence::{SequenceView, SequenceViewExt},
|
|
||||||
vec::VecBuffer,
|
|
||||||
terminal::{TerminalAtom, TerminalStyle, TerminalView, TerminalEvent, TerminalEditor, TerminalEditorResult},
|
|
||||||
tree_nav::{TreeNav, TreeNavResult, TerminalTreeEditor, TreeCursor},
|
|
||||||
list::{ListEditor, ListEditorStyle, sexpr::ListDecoration}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
@ -24,19 +25,17 @@ pub struct DigitEditor {
|
||||||
|
|
||||||
impl DigitEditor {
|
impl DigitEditor {
|
||||||
pub fn new(radix: u32) -> Self {
|
pub fn new(radix: u32) -> Self {
|
||||||
let mut data_port = ViewPort::new();
|
let data_port = ViewPort::new();
|
||||||
DigitEditor {
|
DigitEditor {
|
||||||
radix,
|
radix,
|
||||||
data: SingletonBuffer::new(None, data_port.inner()),
|
data: SingletonBuffer::new(None, data_port.inner()),
|
||||||
data_port
|
data_port,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_data_port(&self) -> OuterViewPort<dyn SingletonView<Item = Option<u32>>> {
|
pub fn get_data_port(&self) -> OuterViewPort<dyn SingletonView<Item = Option<u32>>> {
|
||||||
let radix = self.radix;
|
let radix = self.radix;
|
||||||
self.data_port.outer().map(
|
self.data_port.outer().map(move |c| c?.to_digit(radix))
|
||||||
move |c| c?.to_digit(radix)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,42 +43,44 @@ impl TreeNav for DigitEditor {}
|
||||||
impl TerminalEditor for DigitEditor {
|
impl TerminalEditor for DigitEditor {
|
||||||
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
|
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
|
||||||
let radix = self.radix;
|
let radix = self.radix;
|
||||||
self.data_port.outer().map(
|
self.data_port
|
||||||
move |c| TerminalAtom::new(
|
.outer()
|
||||||
c.unwrap_or('?'),
|
.map(move |c| {
|
||||||
if c.unwrap_or('?').to_digit(radix).is_some() {
|
TerminalAtom::new(
|
||||||
TerminalStyle::fg_color((100, 140, 100))
|
c.unwrap_or('?'),
|
||||||
} else {
|
if c.unwrap_or('?').to_digit(radix).is_some() {
|
||||||
//TerminalStyle::bg_color((90, 10, 10))
|
TerminalStyle::fg_color((100, 140, 100))
|
||||||
TerminalStyle::fg_color((200, 40, 40))
|
} else {
|
||||||
}
|
//TerminalStyle::bg_color((90, 10, 10))
|
||||||
)
|
TerminalStyle::fg_color((200, 40, 40))
|
||||||
).to_grid()
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.to_grid()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
||||||
match event {
|
match event {
|
||||||
TerminalEvent::Input(Event::Key(Key::Char(' '))) |
|
TerminalEvent::Input(Event::Key(Key::Char(' ')))
|
||||||
TerminalEvent::Input(Event::Key(Key::Char('\n'))) =>
|
| TerminalEvent::Input(Event::Key(Key::Char('\n'))) => TerminalEditorResult::Exit,
|
||||||
TerminalEditorResult::Exit,
|
|
||||||
TerminalEvent::Input(Event::Key(Key::Char(c))) => {
|
TerminalEvent::Input(Event::Key(Key::Char(c))) => {
|
||||||
self.data.set(Some(*c));
|
self.data.set(Some(*c));
|
||||||
TerminalEditorResult::Exit
|
TerminalEditorResult::Exit
|
||||||
}
|
}
|
||||||
TerminalEvent::Input(Event::Key(Key::Backspace)) |
|
TerminalEvent::Input(Event::Key(Key::Backspace))
|
||||||
TerminalEvent::Input(Event::Key(Key::Delete)) => {
|
| TerminalEvent::Input(Event::Key(Key::Delete)) => {
|
||||||
self.data.set(None);
|
self.data.set(None);
|
||||||
TerminalEditorResult::Exit
|
TerminalEditorResult::Exit
|
||||||
}
|
}
|
||||||
_ => TerminalEditorResult::Continue
|
_ => TerminalEditorResult::Continue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PosIntEditor {
|
pub struct PosIntEditor {
|
||||||
radix: u32,
|
radix: u32,
|
||||||
digits_editor: ListEditor< DigitEditor,
|
digits_editor:
|
||||||
Box<dyn Fn() -> Arc<RwLock<DigitEditor>> + Send + Sync + 'static> >
|
ListEditor<DigitEditor, Box<dyn Fn() -> Arc<RwLock<DigitEditor>> + Send + Sync + 'static>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PosIntEditor {
|
impl PosIntEditor {
|
||||||
|
@ -87,26 +88,33 @@ impl PosIntEditor {
|
||||||
PosIntEditor {
|
PosIntEditor {
|
||||||
radix,
|
radix,
|
||||||
digits_editor: ListEditor::new(
|
digits_editor: ListEditor::new(
|
||||||
Box::new(
|
Box::new(move || Arc::new(RwLock::new(DigitEditor::new(radix)))),
|
||||||
move || {
|
crate::list::ListEditorStyle::Hex,
|
||||||
Arc::new(RwLock::new(DigitEditor::new(radix)))
|
),
|
||||||
}
|
|
||||||
),
|
|
||||||
crate::list::ListEditorStyle::Hex
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = u32>> {
|
pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = u32>> {
|
||||||
let radix = self.radix;
|
let radix = self.radix;
|
||||||
self.digits_editor.get_data_port()
|
self.digits_editor
|
||||||
.filter_map(move |digit_editor| digit_editor.read().unwrap().data.get()?.to_digit(radix))
|
.get_data_port()
|
||||||
|
.filter_map(move |digit_editor| {
|
||||||
|
digit_editor.read().unwrap().data.get()?.to_digit(radix)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_value(&self) -> u32 {
|
pub fn get_value(&self) -> u32 {
|
||||||
let mut value = 0;
|
let mut value = 0;
|
||||||
let mut weight = 1;
|
let mut weight = 1;
|
||||||
for digit_value in self.get_data_port().get_view().unwrap().iter().collect::<Vec<_>>().into_iter().rev() {
|
for digit_value in self
|
||||||
|
.get_data_port()
|
||||||
|
.get_view()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.into_iter()
|
||||||
|
.rev()
|
||||||
|
{
|
||||||
value += digit_value * weight;
|
value += digit_value * weight;
|
||||||
weight *= self.radix;
|
weight *= self.radix;
|
||||||
}
|
}
|
||||||
|
@ -116,14 +124,30 @@ impl PosIntEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TreeNav for PosIntEditor {
|
impl TreeNav for PosIntEditor {
|
||||||
fn get_cursor(&self) -> TreeCursor { self.digits_editor.get_cursor() }
|
fn get_cursor(&self) -> TreeCursor {
|
||||||
fn goto(&mut self, cur: TreeCursor) -> TreeNavResult { self.digits_editor.goto(cur) }
|
self.digits_editor.get_cursor()
|
||||||
fn goto_home(&mut self) -> TreeNavResult { self.digits_editor.goto_home() }
|
}
|
||||||
fn goto_end(&mut self) -> TreeNavResult { self.digits_editor.goto_end() }
|
fn goto(&mut self, cur: TreeCursor) -> TreeNavResult {
|
||||||
fn pxev(&mut self) -> TreeNavResult { self.digits_editor.pxev() }
|
self.digits_editor.goto(cur)
|
||||||
fn nexd(&mut self) -> TreeNavResult { self.digits_editor.nexd() }
|
}
|
||||||
fn up(&mut self) -> TreeNavResult { self.digits_editor.up() }
|
fn goto_home(&mut self) -> TreeNavResult {
|
||||||
fn dn(&mut self) -> TreeNavResult { self.digits_editor.dn() }
|
self.digits_editor.goto_home()
|
||||||
|
}
|
||||||
|
fn goto_end(&mut self) -> TreeNavResult {
|
||||||
|
self.digits_editor.goto_end()
|
||||||
|
}
|
||||||
|
fn pxev(&mut self) -> TreeNavResult {
|
||||||
|
self.digits_editor.pxev()
|
||||||
|
}
|
||||||
|
fn nexd(&mut self) -> TreeNavResult {
|
||||||
|
self.digits_editor.nexd()
|
||||||
|
}
|
||||||
|
fn up(&mut self) -> TreeNavResult {
|
||||||
|
self.digits_editor.up()
|
||||||
|
}
|
||||||
|
fn dn(&mut self) -> TreeNavResult {
|
||||||
|
self.digits_editor.dn()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TerminalEditor for PosIntEditor {
|
impl TerminalEditor for PosIntEditor {
|
||||||
|
@ -136,11 +160,11 @@ impl TerminalEditor for PosIntEditor {
|
||||||
8 => "0o",
|
8 => "0o",
|
||||||
10 => "0d",
|
10 => "0d",
|
||||||
16 => "0x",
|
16 => "0x",
|
||||||
_ => ""
|
_ => "",
|
||||||
},
|
},
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
0
|
0,
|
||||||
)
|
)
|
||||||
.to_grid_horizontal()
|
.to_grid_horizontal()
|
||||||
.flatten()
|
.flatten()
|
||||||
|
@ -148,14 +172,13 @@ impl TerminalEditor for PosIntEditor {
|
||||||
|
|
||||||
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
||||||
match event {
|
match event {
|
||||||
TerminalEvent::Input(Event::Key(Key::Char(' '))) |
|
TerminalEvent::Input(Event::Key(Key::Char(' ')))
|
||||||
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
|
| TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
|
||||||
self.digits_editor.up();
|
self.digits_editor.up();
|
||||||
TerminalEditorResult::Exit
|
TerminalEditorResult::Exit
|
||||||
}
|
}
|
||||||
|
|
||||||
event => self.digits_editor.handle_terminal_event(event)
|
event => self.digits_editor.handle_terminal_event(event),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
|
|
||||||
pub mod radix;
|
|
||||||
pub mod add;
|
pub mod add;
|
||||||
pub mod editor;
|
pub mod editor;
|
||||||
|
pub mod radix;
|
||||||
|
|
||||||
pub use {
|
pub use {
|
||||||
radix::RadixProjection,
|
|
||||||
add::Add,
|
add::Add,
|
||||||
editor::{DigitEditor, PosIntEditor}
|
editor::{DigitEditor, PosIntEditor},
|
||||||
|
radix::RadixProjection,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,17 @@
|
||||||
use {
|
use {
|
||||||
std::sync::{Arc, RwLock},
|
|
||||||
crate::{
|
crate::{
|
||||||
core::{
|
core::{InnerViewPort, Observer, OuterViewPort},
|
||||||
Observer,
|
|
||||||
InnerViewPort,
|
|
||||||
OuterViewPort
|
|
||||||
},
|
|
||||||
sequence::SequenceView,
|
sequence::SequenceView,
|
||||||
vec::VecBuffer
|
vec::VecBuffer,
|
||||||
}
|
},
|
||||||
|
std::sync::{Arc, RwLock},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct RadixProjection {
|
pub struct RadixProjection {
|
||||||
src_radix: usize,
|
src_radix: usize,
|
||||||
dst_radix: usize,
|
dst_radix: usize,
|
||||||
src_digits: Option<Arc<dyn SequenceView<Item = usize>>>,
|
src_digits: Option<Arc<dyn SequenceView<Item = usize>>>,
|
||||||
dst_digits: RwLock<VecBuffer<usize>>
|
dst_digits: RwLock<VecBuffer<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RadixProjection {
|
impl RadixProjection {
|
||||||
|
@ -23,17 +19,15 @@ impl RadixProjection {
|
||||||
src_radix: usize,
|
src_radix: usize,
|
||||||
dst_radix: usize,
|
dst_radix: usize,
|
||||||
src_digits: OuterViewPort<dyn SequenceView<Item = usize>>,
|
src_digits: OuterViewPort<dyn SequenceView<Item = usize>>,
|
||||||
dst_digits: InnerViewPort<RwLock<Vec<usize>>>
|
dst_digits: InnerViewPort<RwLock<Vec<usize>>>,
|
||||||
) -> Arc<RwLock<Self>> {
|
) -> Arc<RwLock<Self>> {
|
||||||
dst_digits.0.add_update_hook(Arc::new(src_digits.0.clone()));
|
dst_digits.0.add_update_hook(Arc::new(src_digits.0.clone()));
|
||||||
let proj = Arc::new(RwLock::new(
|
let proj = Arc::new(RwLock::new(RadixProjection {
|
||||||
RadixProjection {
|
src_radix,
|
||||||
src_radix,
|
dst_radix,
|
||||||
dst_radix,
|
src_digits: None,
|
||||||
src_digits: None,
|
dst_digits: RwLock::new(VecBuffer::new(dst_digits)),
|
||||||
dst_digits: RwLock::new(VecBuffer::new(dst_digits))
|
}));
|
||||||
}
|
|
||||||
));
|
|
||||||
src_digits.add_observer(proj.clone());
|
src_digits.add_observer(proj.clone());
|
||||||
proj
|
proj
|
||||||
}
|
}
|
||||||
|
@ -41,7 +35,7 @@ impl RadixProjection {
|
||||||
fn machine_int(&self) -> usize {
|
fn machine_int(&self) -> usize {
|
||||||
let mut val = 0;
|
let mut val = 0;
|
||||||
let mut r = 1;
|
let mut r = 1;
|
||||||
for i in 0 .. self.src_digits.len().unwrap_or(0) {
|
for i in 0..self.src_digits.len().unwrap_or(0) {
|
||||||
val += r * self.src_digits.get(&i).unwrap();
|
val += r * self.src_digits.get(&i).unwrap();
|
||||||
r *= self.src_radix;
|
r *= self.src_radix;
|
||||||
}
|
}
|
||||||
|
@ -64,18 +58,18 @@ impl RadixProjection {
|
||||||
|
|
||||||
fn _update_dst_digit(&mut self, _idx: usize) {
|
fn _update_dst_digit(&mut self, _idx: usize) {
|
||||||
/*
|
/*
|
||||||
let v = 0; // calculate new digit value
|
let v = 0; // calculate new digit value
|
||||||
|
|
||||||
// which src-digits are responsible?
|
// which src-digits are responsible?
|
||||||
|
|
||||||
if idx < self.dst_digits.len() {
|
if idx < self.dst_digits.len() {
|
||||||
self.dst_digits.get_mut(idx) = v;
|
self.dst_digits.get_mut(idx) = v;
|
||||||
} else if idx == self.dst_digits.len() {
|
} else if idx == self.dst_digits.len() {
|
||||||
self.dst_digits.push(v);
|
self.dst_digits.push(v);
|
||||||
} else {
|
} else {
|
||||||
// error
|
// error
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,14 +3,14 @@
|
||||||
pub mod core;
|
pub mod core;
|
||||||
pub mod projection;
|
pub mod projection;
|
||||||
|
|
||||||
pub mod singleton;
|
|
||||||
pub mod index;
|
|
||||||
pub mod grid;
|
pub mod grid;
|
||||||
pub mod sequence;
|
pub mod index;
|
||||||
pub mod vec;
|
|
||||||
pub mod terminal;
|
|
||||||
pub mod integer;
|
pub mod integer;
|
||||||
pub mod list;
|
pub mod list;
|
||||||
|
pub mod sequence;
|
||||||
|
pub mod singleton;
|
||||||
|
pub mod terminal;
|
||||||
|
pub mod vec;
|
||||||
|
|
||||||
pub mod tree_nav;
|
pub mod tree_nav;
|
||||||
|
|
||||||
|
@ -21,4 +21,3 @@ pub mod bimap;
|
||||||
pub fn magic_header() {
|
pub fn magic_header() {
|
||||||
eprintln!("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>");
|
eprintln!("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,21 @@
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
pub enum ListCursorMode {
|
pub enum ListCursorMode {
|
||||||
Insert,
|
Insert,
|
||||||
Select,
|
Select,
|
||||||
Modify
|
Modify,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
pub struct ListCursor {
|
pub struct ListCursor {
|
||||||
pub mode: ListCursorMode,
|
pub mode: ListCursorMode,
|
||||||
pub idx: Option<usize>
|
pub idx: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ListCursor {
|
impl Default for ListCursor {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
ListCursor {
|
ListCursor {
|
||||||
mode: ListCursorMode::Select,
|
mode: ListCursorMode::Select,
|
||||||
idx: None
|
idx: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,4 +31,3 @@ pub trait ListNav {
|
||||||
fn get_cursor(&self) -> Option<ListCursor>;
|
fn get_cursor(&self) -> Option<ListCursor>;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,21 @@
|
||||||
use {
|
use {
|
||||||
|
crate::{
|
||||||
|
core::{OuterViewPort, ViewPort},
|
||||||
|
list::{
|
||||||
|
editor_view::{ListEditorView, ListEditorViewSegment},
|
||||||
|
ListCursor, ListCursorMode, ListDecoration, SExprView,
|
||||||
|
},
|
||||||
|
sequence::SequenceView,
|
||||||
|
singleton::{SingletonBuffer, SingletonView},
|
||||||
|
terminal::{
|
||||||
|
make_label, TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle,
|
||||||
|
TerminalView,
|
||||||
|
},
|
||||||
|
tree_nav::{TerminalTreeEditor, TreeCursor, TreeNav, TreeNavResult},
|
||||||
|
vec::VecBuffer,
|
||||||
|
},
|
||||||
std::sync::{Arc, RwLock},
|
std::sync::{Arc, RwLock},
|
||||||
termion::event::{Event, Key},
|
termion::event::{Event, Key},
|
||||||
crate::{
|
|
||||||
core::{
|
|
||||||
ViewPort,
|
|
||||||
OuterViewPort,
|
|
||||||
},
|
|
||||||
singleton::{SingletonView, SingletonBuffer},
|
|
||||||
sequence::{SequenceView},
|
|
||||||
vec::{VecBuffer},
|
|
||||||
terminal::{
|
|
||||||
TerminalView,
|
|
||||||
TerminalStyle,
|
|
||||||
TerminalEvent,
|
|
||||||
TerminalEditor,
|
|
||||||
TerminalEditorResult,
|
|
||||||
make_label
|
|
||||||
},
|
|
||||||
list::{SExprView, ListDecoration, ListCursor, ListCursorMode, editor_view::{ListEditorView, ListEditorViewSegment}},
|
|
||||||
tree_nav::{TreeCursor, TreeNav, TreeNavResult, TerminalTreeEditor}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
@ -30,15 +26,16 @@ pub enum ListEditorStyle {
|
||||||
String,
|
String,
|
||||||
Clist,
|
Clist,
|
||||||
Hex,
|
Hex,
|
||||||
Plain
|
Plain,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ListEditor<ItemEditor, FnMakeItemEditor>
|
pub struct ListEditor<ItemEditor, FnMakeItemEditor>
|
||||||
where ItemEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
|
where
|
||||||
FnMakeItemEditor: Fn() -> Arc<RwLock<ItemEditor>>
|
ItemEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
|
||||||
|
FnMakeItemEditor: Fn() -> Arc<RwLock<ItemEditor>>,
|
||||||
{
|
{
|
||||||
cursor: SingletonBuffer<ListCursor>,
|
cursor: SingletonBuffer<ListCursor>,
|
||||||
pub data: VecBuffer<Arc<RwLock<ItemEditor>>>,
|
data: VecBuffer<Arc<RwLock<ItemEditor>>>,
|
||||||
|
|
||||||
cursor_port: ViewPort<dyn SingletonView<Item = ListCursor>>,
|
cursor_port: ViewPort<dyn SingletonView<Item = ListCursor>>,
|
||||||
data_port: ViewPort<RwLock<Vec<Arc<RwLock<ItemEditor>>>>>,
|
data_port: ViewPort<RwLock<Vec<Arc<RwLock<ItemEditor>>>>>,
|
||||||
|
@ -46,23 +43,25 @@ where ItemEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
|
||||||
make_item_editor: FnMakeItemEditor,
|
make_item_editor: FnMakeItemEditor,
|
||||||
|
|
||||||
style: ListEditorStyle,
|
style: ListEditorStyle,
|
||||||
level: usize,
|
_level: usize,
|
||||||
cur_dist: Arc<RwLock<usize>>,
|
cur_dist: Arc<RwLock<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<ItemEditor, FnMakeItemEditor> TreeNav for ListEditor<ItemEditor, FnMakeItemEditor>
|
impl<ItemEditor, FnMakeItemEditor> TreeNav for ListEditor<ItemEditor, FnMakeItemEditor>
|
||||||
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
where
|
||||||
FnMakeItemEditor: Fn() -> Arc<RwLock<ItemEditor>>
|
ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
|
FnMakeItemEditor: Fn() -> Arc<RwLock<ItemEditor>>,
|
||||||
{
|
{
|
||||||
fn get_cursor(&self) -> TreeCursor {
|
fn get_cursor(&self) -> TreeCursor {
|
||||||
let cur = self.cursor.get();
|
let cur = self.cursor.get();
|
||||||
match cur.mode {
|
match cur.mode {
|
||||||
ListCursorMode::Insert |
|
ListCursorMode::Insert | ListCursorMode::Select => TreeCursor {
|
||||||
ListCursorMode::Select => {
|
leaf_mode: cur.mode,
|
||||||
TreeCursor {
|
tree_addr: if let Some(i) = cur.idx {
|
||||||
leaf_mode: cur.mode,
|
vec![i]
|
||||||
tree_addr: if let Some(i) = cur.idx { vec![ i ] } else { vec![] }
|
} else {
|
||||||
}
|
vec![]
|
||||||
|
},
|
||||||
},
|
},
|
||||||
ListCursorMode::Modify => {
|
ListCursorMode::Modify => {
|
||||||
if let Some(i) = cur.idx {
|
if let Some(i) = cur.idx {
|
||||||
|
@ -74,7 +73,7 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
}
|
}
|
||||||
TreeCursor {
|
TreeCursor {
|
||||||
leaf_mode: cur.mode,
|
leaf_mode: cur.mode,
|
||||||
tree_addr: vec![]
|
tree_addr: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,31 +90,30 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
}
|
}
|
||||||
|
|
||||||
if new_cur.tree_addr.len() == 1 {
|
if new_cur.tree_addr.len() == 1 {
|
||||||
self.cursor.set(ListCursor{
|
self.cursor.set(ListCursor {
|
||||||
mode: new_cur.leaf_mode,
|
mode: new_cur.leaf_mode,
|
||||||
idx: Some(new_cur.tree_addr[0])
|
idx: Some(new_cur.tree_addr[0]),
|
||||||
});
|
});
|
||||||
TreeNavResult::Continue
|
TreeNavResult::Continue
|
||||||
} else if new_cur.tree_addr.len() > 1 && new_cur.tree_addr[0] < self.data.len() {
|
} else if new_cur.tree_addr.len() > 1 && new_cur.tree_addr[0] < self.data.len() {
|
||||||
self.cursor.set(ListCursor {
|
self.cursor.set(ListCursor {
|
||||||
mode: ListCursorMode::Modify,
|
mode: ListCursorMode::Modify,
|
||||||
idx: Some(new_cur.tree_addr[0])
|
idx: Some(new_cur.tree_addr[0]),
|
||||||
});
|
});
|
||||||
|
|
||||||
let ne = self.data.get_mut(new_cur.tree_addr[0]);
|
let ne = self.data.get_mut(new_cur.tree_addr[0]);
|
||||||
let mut nxt_edit = ne.write().unwrap();
|
let mut nxt_edit = ne.write().unwrap();
|
||||||
|
|
||||||
nxt_edit.goto(
|
nxt_edit.goto(TreeCursor {
|
||||||
TreeCursor {
|
leaf_mode: new_cur.leaf_mode,
|
||||||
leaf_mode: new_cur.leaf_mode,
|
tree_addr: new_cur.tree_addr[1..].iter().cloned().collect(),
|
||||||
tree_addr: new_cur.tree_addr[1..].iter().cloned().collect()
|
});
|
||||||
});
|
|
||||||
|
|
||||||
TreeNavResult::Continue
|
TreeNavResult::Continue
|
||||||
} else {
|
} else {
|
||||||
self.cursor.set(ListCursor {
|
self.cursor.set(ListCursor {
|
||||||
mode: new_cur.leaf_mode,
|
mode: new_cur.leaf_mode,
|
||||||
idx: None
|
idx: None,
|
||||||
});
|
});
|
||||||
TreeNavResult::Continue
|
TreeNavResult::Continue
|
||||||
}
|
}
|
||||||
|
@ -126,12 +124,10 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
let i = cur.idx.unwrap_or(0);
|
let i = cur.idx.unwrap_or(0);
|
||||||
|
|
||||||
if self.data.len() == 0 && cur.idx.is_none() {
|
if self.data.len() == 0 && cur.idx.is_none() {
|
||||||
self.cursor.set(
|
self.cursor.set(ListCursor {
|
||||||
ListCursor {
|
mode: ListCursorMode::Insert,
|
||||||
mode: ListCursorMode::Insert,
|
idx: Some(0),
|
||||||
idx: Some(0)
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
return TreeNavResult::Continue;
|
return TreeNavResult::Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,17 +145,15 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
}
|
}
|
||||||
ListCursorMode::Select => {
|
ListCursorMode::Select => {
|
||||||
if self.data.len() == 0 && cur.idx.is_none() {
|
if self.data.len() == 0 && cur.idx.is_none() {
|
||||||
self.cursor.set(
|
self.cursor.set(ListCursor {
|
||||||
ListCursor {
|
mode: ListCursorMode::Insert,
|
||||||
mode: ListCursorMode::Insert,
|
idx: Some(0),
|
||||||
idx: Some(0)
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
return TreeNavResult::Continue;
|
return TreeNavResult::Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if i+1 < self.data.len() || cur.idx.is_none() {
|
if i + 1 < self.data.len() || cur.idx.is_none() {
|
||||||
cur.idx = Some(self.data.len()-1);
|
cur.idx = Some(self.data.len() - 1);
|
||||||
self.cursor.set(cur);
|
self.cursor.set(cur);
|
||||||
TreeNavResult::Continue
|
TreeNavResult::Continue
|
||||||
} else {
|
} else {
|
||||||
|
@ -173,19 +167,17 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
let cur_mode = cur_edit.get_cursor().leaf_mode;
|
let cur_mode = cur_edit.get_cursor().leaf_mode;
|
||||||
let depth = cur_edit.get_cursor().tree_addr.len();
|
let depth = cur_edit.get_cursor().tree_addr.len();
|
||||||
match cur_edit.goto_end() {
|
match cur_edit.goto_end() {
|
||||||
TreeNavResult::Continue => {
|
TreeNavResult::Continue => TreeNavResult::Continue,
|
||||||
TreeNavResult::Continue
|
|
||||||
}
|
|
||||||
TreeNavResult::Exit => {
|
TreeNavResult::Exit => {
|
||||||
drop(cur_edit);
|
drop(cur_edit);
|
||||||
|
|
||||||
self.up();
|
self.up();
|
||||||
|
|
||||||
if i+1 < self.data.len() {
|
if i + 1 < self.data.len() {
|
||||||
self.set_mode(ListCursorMode::Select);
|
self.set_mode(ListCursorMode::Select);
|
||||||
self.nexd();
|
self.nexd();
|
||||||
|
|
||||||
for x in 1 .. depth {
|
for _x in 1..depth {
|
||||||
self.dn();
|
self.dn();
|
||||||
self.goto_home();
|
self.goto_home();
|
||||||
}
|
}
|
||||||
|
@ -211,25 +203,24 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
fn goto_home(&mut self) -> TreeNavResult {
|
fn goto_home(&mut self) -> TreeNavResult {
|
||||||
let cur = self.cursor.get();
|
let cur = self.cursor.get();
|
||||||
if self.data.len() == 0 && cur.idx.is_none() {
|
if self.data.len() == 0 && cur.idx.is_none() {
|
||||||
self.cursor.set(
|
self.cursor.set(ListCursor {
|
||||||
ListCursor {
|
mode: ListCursorMode::Insert,
|
||||||
mode: ListCursorMode::Insert,
|
idx: Some(0),
|
||||||
idx: Some(0)
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
return TreeNavResult::Continue;
|
return TreeNavResult::Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
match cur.mode {
|
match cur.mode {
|
||||||
ListCursorMode::Insert |
|
ListCursorMode::Insert | ListCursorMode::Select => {
|
||||||
ListCursorMode::Select => {
|
|
||||||
if cur.idx != Some(0) {
|
if cur.idx != Some(0) {
|
||||||
self.cursor.set(
|
self.cursor.set(ListCursor {
|
||||||
ListCursor {
|
mode: if self.data.len() == 0 {
|
||||||
mode: if self.data.len() == 0 { ListCursorMode::Insert } else { cur.mode },
|
ListCursorMode::Insert
|
||||||
idx: Some(0)
|
} else {
|
||||||
}
|
cur.mode
|
||||||
);
|
},
|
||||||
|
idx: Some(0),
|
||||||
|
});
|
||||||
TreeNavResult::Continue
|
TreeNavResult::Continue
|
||||||
} else {
|
} else {
|
||||||
self.cursor.set(ListCursor::default());
|
self.cursor.set(ListCursor::default());
|
||||||
|
@ -253,7 +244,7 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
self.set_mode(ListCursorMode::Select);
|
self.set_mode(ListCursorMode::Select);
|
||||||
self.pxev();
|
self.pxev();
|
||||||
|
|
||||||
for x in 1 .. depth {
|
for _x in 1..depth {
|
||||||
self.dn();
|
self.dn();
|
||||||
self.goto_end();
|
self.goto_end();
|
||||||
}
|
}
|
||||||
|
@ -267,7 +258,7 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
|
|
||||||
TreeNavResult::Exit
|
TreeNavResult::Exit
|
||||||
}
|
}
|
||||||
TreeNavResult::Continue => TreeNavResult::Continue
|
TreeNavResult::Continue => TreeNavResult::Continue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -294,7 +285,7 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
|
|
||||||
self.cursor.set(ListCursor {
|
self.cursor.set(ListCursor {
|
||||||
mode: cur.mode,
|
mode: cur.mode,
|
||||||
idx: None
|
idx: None,
|
||||||
});
|
});
|
||||||
TreeNavResult::Exit
|
TreeNavResult::Exit
|
||||||
}
|
}
|
||||||
|
@ -302,25 +293,20 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
fn dn(&mut self) -> TreeNavResult {
|
fn dn(&mut self) -> TreeNavResult {
|
||||||
let cur = self.cursor.get();
|
let cur = self.cursor.get();
|
||||||
match cur.mode {
|
match cur.mode {
|
||||||
ListCursorMode::Insert |
|
ListCursorMode::Insert | ListCursorMode::Select => {
|
||||||
ListCursorMode::Select => {
|
|
||||||
if let Some(i) = cur.idx {
|
if let Some(i) = cur.idx {
|
||||||
if i < self.data.len() {
|
if i < self.data.len() {
|
||||||
self.set_mode(ListCursorMode::Modify);
|
self.set_mode(ListCursorMode::Modify);
|
||||||
self.data.get_mut(i).write().unwrap().goto(
|
self.data.get_mut(i).write().unwrap().goto(TreeCursor {
|
||||||
TreeCursor {
|
leaf_mode: cur.mode,
|
||||||
leaf_mode: cur.mode,
|
tree_addr: vec![],
|
||||||
tree_addr: vec![]
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
*self.cur_dist.write().unwrap() += 1;
|
*self.cur_dist.write().unwrap() += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TreeNavResult::Continue
|
TreeNavResult::Continue
|
||||||
}
|
}
|
||||||
ListCursorMode::Modify => {
|
ListCursorMode::Modify => self.get_item().unwrap().write().unwrap().dn(),
|
||||||
self.get_item().unwrap().write().unwrap().dn()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,8 +314,7 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
let mut cur = self.cursor.get();
|
let mut cur = self.cursor.get();
|
||||||
if let Some(i) = cur.idx {
|
if let Some(i) = cur.idx {
|
||||||
match cur.mode {
|
match cur.mode {
|
||||||
ListCursorMode::Insert |
|
ListCursorMode::Insert | ListCursorMode::Select => {
|
||||||
ListCursorMode::Select => {
|
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
cur.idx = Some(i - 1);
|
cur.idx = Some(i - 1);
|
||||||
self.cursor.set(cur);
|
self.cursor.set(cur);
|
||||||
|
@ -355,7 +340,7 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
self.set_mode(ListCursorMode::Select);
|
self.set_mode(ListCursorMode::Select);
|
||||||
self.pxev();
|
self.pxev();
|
||||||
|
|
||||||
for x in 1 .. depth {
|
for _x in 1..depth {
|
||||||
self.dn();
|
self.dn();
|
||||||
self.goto_end();
|
self.goto_end();
|
||||||
}
|
}
|
||||||
|
@ -367,8 +352,8 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
} else {
|
} else {
|
||||||
TreeNavResult::Exit
|
TreeNavResult::Exit
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
TreeNavResult::Continue => TreeNavResult::Continue
|
TreeNavResult::Continue => TreeNavResult::Continue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -392,7 +377,7 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ListCursorMode::Select => {
|
ListCursorMode::Select => {
|
||||||
if i+1 < self.data.len() {
|
if i + 1 < self.data.len() {
|
||||||
cur.idx = Some(i + 1);
|
cur.idx = Some(i + 1);
|
||||||
self.cursor.set(cur);
|
self.cursor.set(cur);
|
||||||
TreeNavResult::Continue
|
TreeNavResult::Continue
|
||||||
|
@ -414,12 +399,11 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
drop(ce);
|
drop(ce);
|
||||||
self.up();
|
self.up();
|
||||||
|
|
||||||
if i+1 < self.data.len() {
|
if i + 1 < self.data.len() {
|
||||||
|
|
||||||
self.set_mode(ListCursorMode::Select);
|
self.set_mode(ListCursorMode::Select);
|
||||||
self.nexd();
|
self.nexd();
|
||||||
|
|
||||||
for x in 1 .. depth {
|
for _x in 1..depth {
|
||||||
self.dn();
|
self.dn();
|
||||||
self.goto_home();
|
self.goto_home();
|
||||||
}
|
}
|
||||||
|
@ -432,7 +416,7 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
TreeNavResult::Exit
|
TreeNavResult::Exit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TreeNavResult::Continue => TreeNavResult::Continue
|
TreeNavResult::Continue => TreeNavResult::Continue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -443,8 +427,9 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<ItemEditor, FnMakeItemEditor> TerminalEditor for ListEditor<ItemEditor, FnMakeItemEditor>
|
impl<ItemEditor, FnMakeItemEditor> TerminalEditor for ListEditor<ItemEditor, FnMakeItemEditor>
|
||||||
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
where
|
||||||
FnMakeItemEditor: Fn() -> Arc<RwLock<ItemEditor>>
|
ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
|
FnMakeItemEditor: Fn() -> Arc<RwLock<ItemEditor>>,
|
||||||
{
|
{
|
||||||
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
|
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
|
||||||
match self.style {
|
match self.style {
|
||||||
|
@ -454,7 +439,7 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
ListEditorStyle::String => self.string_view(),
|
ListEditorStyle::String => self.string_view(),
|
||||||
ListEditorStyle::Clist => self.clist_view(),
|
ListEditorStyle::Clist => self.clist_view(),
|
||||||
ListEditorStyle::Hex => self.hex_view(),
|
ListEditorStyle::Hex => self.hex_view(),
|
||||||
ListEditorStyle::Plain => self.plain_view()
|
ListEditorStyle::Plain => self.plain_view(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,77 +447,71 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
let mut cur = self.cursor.get();
|
let mut cur = self.cursor.get();
|
||||||
if let Some(idx) = cur.idx {
|
if let Some(idx) = cur.idx {
|
||||||
match cur.mode {
|
match cur.mode {
|
||||||
ListCursorMode::Insert => {
|
ListCursorMode::Insert => match event {
|
||||||
match event {
|
TerminalEvent::Input(Event::Key(Key::Backspace)) => {
|
||||||
TerminalEvent::Input(Event::Key(Key::Backspace)) => {
|
if idx > 0 && idx <= self.data.len() {
|
||||||
if idx > 0 && idx <= self.data.len() {
|
cur.idx = Some(idx - 1);
|
||||||
cur.idx = Some(idx-1);
|
self.cursor.set(cur);
|
||||||
self.cursor.set(cur);
|
self.data.remove(idx - 1);
|
||||||
self.data.remove(idx-1);
|
|
||||||
TerminalEditorResult::Continue
|
|
||||||
} else {
|
|
||||||
TerminalEditorResult::Exit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TerminalEvent::Input(Event::Key(Key::Delete)) => {
|
|
||||||
if idx < self.data.len() {
|
|
||||||
self.data.remove(idx);
|
|
||||||
TerminalEditorResult::Continue
|
|
||||||
} else {
|
|
||||||
TerminalEditorResult::Exit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TerminalEvent::Input(Event::Key(Key::Char('\t'))) |
|
|
||||||
TerminalEvent::Input(Event::Key(Key::Insert)) => {
|
|
||||||
self.set_mode(ListCursorMode::Select);
|
|
||||||
TerminalEditorResult::Continue
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let new_edit = (self.make_item_editor)();
|
|
||||||
self.data.insert(idx, new_edit.clone());
|
|
||||||
self.dn();
|
|
||||||
self.goto_home();
|
|
||||||
|
|
||||||
match new_edit.write().unwrap().handle_terminal_event(event) {
|
|
||||||
TerminalEditorResult::Exit => {
|
|
||||||
self.cursor.set(ListCursor {
|
|
||||||
mode: ListCursorMode::Insert,
|
|
||||||
idx: Some(idx+1)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
TerminalEditorResult::Continue
|
TerminalEditorResult::Continue
|
||||||
|
} else {
|
||||||
|
TerminalEditorResult::Exit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
TerminalEvent::Input(Event::Key(Key::Delete)) => {
|
||||||
ListCursorMode::Select => {
|
if idx < self.data.len() {
|
||||||
match event {
|
|
||||||
TerminalEvent::Input(Event::Key(Key::Char('\t'))) |
|
|
||||||
TerminalEvent::Input(Event::Key(Key::Insert)) => {
|
|
||||||
self.set_mode(ListCursorMode::Insert);
|
|
||||||
TerminalEditorResult::Continue
|
|
||||||
}
|
|
||||||
TerminalEvent::Input(Event::Key(Key::Delete)) => {
|
|
||||||
self.data.remove(idx);
|
self.data.remove(idx);
|
||||||
|
TerminalEditorResult::Continue
|
||||||
|
} else {
|
||||||
|
TerminalEditorResult::Exit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TerminalEvent::Input(Event::Key(Key::Char('\t')))
|
||||||
|
| TerminalEvent::Input(Event::Key(Key::Insert)) => {
|
||||||
|
self.set_mode(ListCursorMode::Select);
|
||||||
|
TerminalEditorResult::Continue
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let new_edit = (self.make_item_editor)();
|
||||||
|
self.data.insert(idx, new_edit.clone());
|
||||||
|
self.dn();
|
||||||
|
self.goto_home();
|
||||||
|
|
||||||
if self.data.len() == 0 {
|
match new_edit.write().unwrap().handle_terminal_event(event) {
|
||||||
self.cursor.set(ListCursor::default());
|
TerminalEditorResult::Exit => {
|
||||||
} else if idx == self.data.len() {
|
|
||||||
self.cursor.set(ListCursor {
|
self.cursor.set(ListCursor {
|
||||||
mode: ListCursorMode::Select,
|
mode: ListCursorMode::Insert,
|
||||||
idx: Some(idx-1)
|
idx: Some(idx + 1),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
TerminalEditorResult::Continue
|
_ => {}
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
TerminalEditorResult::Continue
|
|
||||||
}
|
}
|
||||||
|
TerminalEditorResult::Continue
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
ListCursorMode::Select => match event {
|
||||||
|
TerminalEvent::Input(Event::Key(Key::Char('\t')))
|
||||||
|
| TerminalEvent::Input(Event::Key(Key::Insert)) => {
|
||||||
|
self.set_mode(ListCursorMode::Insert);
|
||||||
|
TerminalEditorResult::Continue
|
||||||
|
}
|
||||||
|
TerminalEvent::Input(Event::Key(Key::Delete)) => {
|
||||||
|
self.data.remove(idx);
|
||||||
|
|
||||||
|
if self.data.len() == 0 {
|
||||||
|
self.cursor.set(ListCursor::default());
|
||||||
|
} else if idx == self.data.len() {
|
||||||
|
self.cursor.set(ListCursor {
|
||||||
|
mode: ListCursorMode::Select,
|
||||||
|
idx: Some(idx - 1),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
TerminalEditorResult::Continue
|
||||||
|
}
|
||||||
|
_ => TerminalEditorResult::Continue,
|
||||||
|
},
|
||||||
ListCursorMode::Modify => {
|
ListCursorMode::Modify => {
|
||||||
let mut ce = self.data.get_mut(idx);
|
let ce = self.data.get_mut(idx);
|
||||||
let mut cur_edit = ce.write().unwrap();
|
let mut cur_edit = ce.write().unwrap();
|
||||||
|
|
||||||
match cur_edit.handle_terminal_event(event) {
|
match cur_edit.handle_terminal_event(event) {
|
||||||
|
@ -546,7 +525,7 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
// todo: join instead of remove
|
// todo: join instead of remove
|
||||||
self.cursor.set(ListCursor {
|
self.cursor.set(ListCursor {
|
||||||
mode: ListCursorMode::Insert,
|
mode: ListCursorMode::Insert,
|
||||||
idx: Some(idx)
|
idx: Some(idx),
|
||||||
});
|
});
|
||||||
|
|
||||||
self.data.remove(idx);
|
self.data.remove(idx);
|
||||||
|
@ -556,11 +535,11 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
|
|
||||||
self.cursor.set(ListCursor {
|
self.cursor.set(ListCursor {
|
||||||
mode: ListCursorMode::Insert,
|
mode: ListCursorMode::Insert,
|
||||||
idx: Some(idx+1)
|
idx: Some(idx + 1),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
TerminalEditorResult::Continue => {}
|
TerminalEditorResult::Continue => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -574,50 +553,55 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<ItemEditor, FnMakeItemEditor> ListEditor<ItemEditor, FnMakeItemEditor>
|
impl<ItemEditor, FnMakeItemEditor> ListEditor<ItemEditor, FnMakeItemEditor>
|
||||||
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
where
|
||||||
FnMakeItemEditor: Fn() -> Arc<RwLock<ItemEditor>>
|
ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
|
FnMakeItemEditor: Fn() -> Arc<RwLock<ItemEditor>>,
|
||||||
{
|
{
|
||||||
pub fn get_seg_seq_view(&self) -> OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>> {
|
pub fn get_seg_seq_view(
|
||||||
|
&self,
|
||||||
|
) -> OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>> {
|
||||||
let segment_view_port = ViewPort::<dyn SequenceView<Item = ListEditorViewSegment>>::new();
|
let segment_view_port = ViewPort::<dyn SequenceView<Item = ListEditorViewSegment>>::new();
|
||||||
ListEditorView::new(
|
ListEditorView::new(
|
||||||
self.cursor_port.outer(),
|
self.cursor_port.outer(),
|
||||||
self.data_port.outer().to_sequence().map(|ed| ed.read().unwrap().get_term_view()),
|
self.data_port
|
||||||
segment_view_port.inner()
|
.outer()
|
||||||
|
.to_sequence()
|
||||||
|
.map(|ed| ed.read().unwrap().get_term_view()),
|
||||||
|
segment_view_port.inner(),
|
||||||
);
|
);
|
||||||
|
|
||||||
segment_view_port.into_outer()
|
segment_view_port.into_outer().map(move |segment| {
|
||||||
.map(
|
let cursor_col = (90, 60, 200);
|
||||||
move |segment| {
|
match segment {
|
||||||
let cursor_col = (90, 60, 200);
|
ListEditorViewSegment::InsertCursor => {
|
||||||
match segment {
|
make_label("|").map_item(move |_pt, atom| {
|
||||||
ListEditorViewSegment::InsertCursor =>
|
atom.add_style_back(TerminalStyle::fg_color(cursor_col))
|
||||||
make_label("|")
|
.add_style_back(TerminalStyle::bold(true))
|
||||||
.map_item(
|
})
|
||||||
move |_pt, atom|
|
|
||||||
atom.add_style_back(TerminalStyle::fg_color(cursor_col))
|
|
||||||
.add_style_back(TerminalStyle::bold(true))
|
|
||||||
),
|
|
||||||
ListEditorViewSegment::Select(sub_view) =>
|
|
||||||
sub_view.map_item(
|
|
||||||
move |_pt, atom| {
|
|
||||||
let old_col = atom.style.bg_color.unwrap_or(cursor_col);
|
|
||||||
atom.add_style_front(TerminalStyle::bg_color(((old_col.0 as f32 * 0.4) as u8, (old_col.1 as f32 * 0.4) as u8, (old_col.2 as f32 * 0.4) as u8)))
|
|
||||||
}
|
|
||||||
),
|
|
||||||
ListEditorViewSegment::Modify(sub_view) => {
|
|
||||||
sub_view.clone().map_item(
|
|
||||||
move |_pt, atom| {
|
|
||||||
let old_col = atom.style.bg_color.unwrap_or(cursor_col);
|
|
||||||
atom.add_style_front(TerminalStyle::bg_color(((old_col.0 as f32 * 0.4) as u8, (old_col.1 as f32 * 0.4) as u8, (old_col.2 as f32 * 0.4) as u8)))
|
|
||||||
}
|
|
||||||
//.add_style_back(TerminalStyle::bold(true))
|
|
||||||
)
|
|
||||||
},
|
|
||||||
ListEditorViewSegment::View(sub_view) =>
|
|
||||||
sub_view.clone()
|
|
||||||
}
|
}
|
||||||
|
ListEditorViewSegment::Select(sub_view) => sub_view.map_item(move |_pt, atom| {
|
||||||
|
let old_col = atom.style.bg_color.unwrap_or(cursor_col);
|
||||||
|
atom.add_style_front(TerminalStyle::bg_color((
|
||||||
|
(old_col.0 as f32 * 0.4) as u8,
|
||||||
|
(old_col.1 as f32 * 0.4) as u8,
|
||||||
|
(old_col.2 as f32 * 0.4) as u8,
|
||||||
|
)))
|
||||||
|
}),
|
||||||
|
ListEditorViewSegment::Modify(sub_view) => {
|
||||||
|
sub_view.clone().map_item(
|
||||||
|
move |_pt, atom| {
|
||||||
|
let old_col = atom.style.bg_color.unwrap_or(cursor_col);
|
||||||
|
atom.add_style_front(TerminalStyle::bg_color((
|
||||||
|
(old_col.0 as f32 * 0.4) as u8,
|
||||||
|
(old_col.1 as f32 * 0.4) as u8,
|
||||||
|
(old_col.2 as f32 * 0.4) as u8,
|
||||||
|
)))
|
||||||
|
}, //.add_style_back(TerminalStyle::bold(true))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
)
|
ListEditorViewSegment::View(sub_view) => sub_view.clone(),
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn horizontal_sexpr_view(&self) -> OuterViewPort<dyn TerminalView> {
|
pub fn horizontal_sexpr_view(&self) -> OuterViewPort<dyn TerminalView> {
|
||||||
|
@ -639,7 +623,6 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
self.get_seg_seq_view()
|
self.get_seg_seq_view()
|
||||||
.decorate("\"", "\"", "", 1)
|
.decorate("\"", "\"", "", 1)
|
||||||
.to_grid_horizontal()
|
.to_grid_horizontal()
|
||||||
|
|
||||||
.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -658,16 +641,14 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn plain_view(&self) -> OuterViewPort<dyn TerminalView> {
|
pub fn plain_view(&self) -> OuterViewPort<dyn TerminalView> {
|
||||||
self.get_seg_seq_view()
|
self.get_seg_seq_view().to_grid_horizontal().flatten()
|
||||||
.to_grid_horizontal()
|
|
||||||
.flatten()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(make_item_editor: FnMakeItemEditor, style: ListEditorStyle) -> Self {
|
pub fn new(make_item_editor: FnMakeItemEditor, style: ListEditorStyle) -> Self {
|
||||||
let cursor_port = ViewPort::new();
|
let cursor_port = ViewPort::new();
|
||||||
let data_port = ViewPort::new();
|
let data_port = ViewPort::new();
|
||||||
let mut cursor = SingletonBuffer::new(ListCursor::default(), cursor_port.inner());
|
let cursor = SingletonBuffer::new(ListCursor::default(), cursor_port.inner());
|
||||||
let mut data = VecBuffer::<Arc<RwLock<ItemEditor>>>::new(data_port.inner());
|
let data = VecBuffer::<Arc<RwLock<ItemEditor>>>::new(data_port.inner());
|
||||||
|
|
||||||
let mut le = ListEditor {
|
let mut le = ListEditor {
|
||||||
data,
|
data,
|
||||||
|
@ -677,8 +658,8 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
|
|
||||||
style,
|
style,
|
||||||
make_item_editor,
|
make_item_editor,
|
||||||
level: 0,
|
_level: 0,
|
||||||
cur_dist: Arc::new(RwLock::new(0))
|
cur_dist: Arc::new(RwLock::new(0)),
|
||||||
};
|
};
|
||||||
le.set_style(style);
|
le.set_style(style);
|
||||||
le
|
le
|
||||||
|
@ -708,6 +689,10 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.data.clear();
|
||||||
|
}
|
||||||
|
|
||||||
fn set_idx(&mut self, idx: isize) {
|
fn set_idx(&mut self, idx: isize) {
|
||||||
let cur = self.cursor.get();
|
let cur = self.cursor.get();
|
||||||
let mode = cur.mode;
|
let mode = cur.mode;
|
||||||
|
@ -715,12 +700,12 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
if idx < 0 {
|
if idx < 0 {
|
||||||
self.cursor.set(ListCursor {
|
self.cursor.set(ListCursor {
|
||||||
mode,
|
mode,
|
||||||
idx: Some((self.data.len() as isize + idx) as usize)
|
idx: Some((self.data.len() as isize + idx) as usize),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
self.cursor.set(ListCursor {
|
self.cursor.set(ListCursor {
|
||||||
mode,
|
mode,
|
||||||
idx: Some(idx as usize)
|
idx: Some(idx as usize),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -728,12 +713,10 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
fn set_mode(&mut self, mode: ListCursorMode) {
|
fn set_mode(&mut self, mode: ListCursorMode) {
|
||||||
let mut cur = self.cursor.get();
|
let mut cur = self.cursor.get();
|
||||||
|
|
||||||
if cur.mode == ListCursorMode::Insert &&
|
if cur.mode == ListCursorMode::Insert && mode != ListCursorMode::Insert {
|
||||||
mode != ListCursorMode::Insert
|
|
||||||
{
|
|
||||||
if let Some(idx) = cur.idx {
|
if let Some(idx) = cur.idx {
|
||||||
if idx == self.data.len() && idx > 0 {
|
if idx == self.data.len() && idx > 0 {
|
||||||
cur.idx = Some(idx-1);
|
cur.idx = Some(idx - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -745,8 +728,9 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<ItemEditor, FnMakeItemEditor> ListEditor<ItemEditor, FnMakeItemEditor>
|
impl<ItemEditor, FnMakeItemEditor> ListEditor<ItemEditor, FnMakeItemEditor>
|
||||||
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
where
|
||||||
FnMakeItemEditor: Fn() -> Arc<RwLock<ItemEditor>>
|
ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
|
FnMakeItemEditor: Fn() -> Arc<RwLock<ItemEditor>>,
|
||||||
{
|
{
|
||||||
fn set_leaf_mode(&mut self, mode: ListCursorMode) {
|
fn set_leaf_mode(&mut self, mode: ListCursorMode) {
|
||||||
let mut c = self.get_cursor();
|
let mut c = self.get_cursor();
|
||||||
|
@ -754,4 +738,3 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
self.goto(c);
|
self.goto(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,30 +1,21 @@
|
||||||
use {
|
use {
|
||||||
|
crate::{
|
||||||
|
core::{InnerViewPort, Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View},
|
||||||
|
list::{ListCursor, ListCursorMode},
|
||||||
|
projection::ProjectionHelper,
|
||||||
|
sequence::SequenceView,
|
||||||
|
singleton::SingletonView,
|
||||||
|
terminal::TerminalView,
|
||||||
|
},
|
||||||
std::sync::Arc,
|
std::sync::Arc,
|
||||||
std::sync::RwLock,
|
std::sync::RwLock,
|
||||||
crate::{
|
|
||||||
core::{
|
|
||||||
View,
|
|
||||||
InnerViewPort,
|
|
||||||
OuterViewPort,
|
|
||||||
Observer,
|
|
||||||
ObserverExt,
|
|
||||||
ObserverBroadcast
|
|
||||||
},
|
|
||||||
projection::ProjectionHelper,
|
|
||||||
|
|
||||||
singleton::SingletonView,
|
|
||||||
sequence::SequenceView,
|
|
||||||
terminal::TerminalView,
|
|
||||||
|
|
||||||
list::{ListCursor, ListCursorMode}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub enum ListEditorViewSegment {
|
pub enum ListEditorViewSegment {
|
||||||
InsertCursor,
|
InsertCursor,
|
||||||
View(OuterViewPort<dyn TerminalView>),
|
View(OuterViewPort<dyn TerminalView>),
|
||||||
Select(OuterViewPort<dyn TerminalView>),
|
Select(OuterViewPort<dyn TerminalView>),
|
||||||
Modify(OuterViewPort<dyn TerminalView>)
|
Modify(OuterViewPort<dyn TerminalView>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ListEditorView {
|
pub struct ListEditorView {
|
||||||
|
@ -33,7 +24,7 @@ pub struct ListEditorView {
|
||||||
cur_cursor: ListCursor,
|
cur_cursor: ListCursor,
|
||||||
|
|
||||||
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = ListEditorViewSegment>>>>,
|
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = ListEditorViewSegment>>>>,
|
||||||
proj_helper: ProjectionHelper<usize, Self>
|
proj_helper: ProjectionHelper<usize, Self>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl View for ListEditorView {
|
impl View for ListEditorView {
|
||||||
|
@ -45,43 +36,43 @@ impl SequenceView for ListEditorView {
|
||||||
|
|
||||||
fn len(&self) -> Option<usize> {
|
fn len(&self) -> Option<usize> {
|
||||||
match self.cursor.get().mode {
|
match self.cursor.get().mode {
|
||||||
ListCursorMode::Insert => Some(self.data.len()? + if self.cur_cursor.idx.is_some() { 1 } else { 0 }),
|
ListCursorMode::Insert => {
|
||||||
_ => self.data.len()
|
Some(self.data.len()? + if self.cur_cursor.idx.is_some() { 1 } else { 0 })
|
||||||
|
}
|
||||||
|
_ => self.data.len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self, idx: &usize) -> Option<Self::Item> {
|
fn get(&self, idx: &usize) -> Option<Self::Item> {
|
||||||
Some(
|
Some(if let Some(cur) = self.cur_cursor.idx {
|
||||||
if let Some(cur) = self.cur_cursor.idx {
|
match self.cur_cursor.mode {
|
||||||
match self.cur_cursor.mode {
|
ListCursorMode::Select => {
|
||||||
ListCursorMode::Select => {
|
if *idx == cur {
|
||||||
if *idx == cur {
|
ListEditorViewSegment::Select(self.data.get(&idx)?)
|
||||||
ListEditorViewSegment::Select(self.data.get(&idx)?)
|
} else {
|
||||||
} else {
|
ListEditorViewSegment::View(self.data.get(&idx)?)
|
||||||
ListEditorViewSegment::View(self.data.get(&idx)?)
|
}
|
||||||
}
|
}
|
||||||
}
|
ListCursorMode::Insert => {
|
||||||
ListCursorMode::Insert => {
|
if *idx < cur {
|
||||||
if *idx < cur {
|
ListEditorViewSegment::View(self.data.get(&idx)?)
|
||||||
ListEditorViewSegment::View(self.data.get(&idx)?)
|
} else if *idx == cur {
|
||||||
} else if *idx == cur {
|
ListEditorViewSegment::InsertCursor
|
||||||
ListEditorViewSegment::InsertCursor
|
} else {
|
||||||
} else {
|
ListEditorViewSegment::View(self.data.get(&(idx - 1))?)
|
||||||
ListEditorViewSegment::View(self.data.get(&(idx-1))?)
|
}
|
||||||
}
|
}
|
||||||
}
|
ListCursorMode::Modify => {
|
||||||
ListCursorMode::Modify => {
|
if *idx == cur {
|
||||||
if *idx == cur {
|
ListEditorViewSegment::Modify(self.data.get(&idx)?)
|
||||||
ListEditorViewSegment::Modify(self.data.get(&idx)?)
|
} else {
|
||||||
} else {
|
ListEditorViewSegment::View(self.data.get(&idx)?)
|
||||||
ListEditorViewSegment::View(self.data.get(&idx)?)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
ListEditorViewSegment::View(self.data.get(&idx)?)
|
|
||||||
}
|
}
|
||||||
)
|
} else {
|
||||||
|
ListEditorViewSegment::View(self.data.get(&idx)?)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,49 +80,39 @@ impl ListEditorView {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
cursor_port: OuterViewPort<dyn SingletonView<Item = ListCursor>>,
|
cursor_port: OuterViewPort<dyn SingletonView<Item = ListCursor>>,
|
||||||
data_port: OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>,
|
data_port: OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>,
|
||||||
out_port: InnerViewPort<dyn SequenceView<Item = ListEditorViewSegment>>
|
out_port: InnerViewPort<dyn SequenceView<Item = ListEditorViewSegment>>,
|
||||||
) -> Arc<RwLock<Self>> {
|
) -> Arc<RwLock<Self>> {
|
||||||
let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone());
|
let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone());
|
||||||
let proj = Arc::new(RwLock::new(
|
let proj = Arc::new(RwLock::new(ListEditorView {
|
||||||
ListEditorView {
|
cur_cursor: ListCursor::default(),
|
||||||
cur_cursor: ListCursor::default(),
|
cursor: proj_helper.new_singleton_arg(0, cursor_port, |s: &mut Self, _msg| {
|
||||||
cursor: proj_helper.new_singleton_arg(
|
let _old_cursor = s.cur_cursor;
|
||||||
0,
|
let new_cursor = s.cursor.get();
|
||||||
cursor_port,
|
s.cur_cursor = new_cursor;
|
||||||
|s: &mut Self, _msg| {
|
|
||||||
let old_cursor = s.cur_cursor;
|
|
||||||
let new_cursor = s.cursor.get();
|
|
||||||
s.cur_cursor = new_cursor;
|
|
||||||
|
|
||||||
s.cast.notify_each(
|
s.cast.notify_each(0..=s.data.len().unwrap_or(0) + 1);
|
||||||
0 ..= s.data.len().unwrap_or(0)+1
|
}),
|
||||||
);
|
data: proj_helper.new_sequence_arg(1, data_port, |s: &mut Self, idx| {
|
||||||
}),
|
if let Some(cur_idx) = s.cur_cursor.idx {
|
||||||
data: proj_helper.new_sequence_arg(
|
match s.cur_cursor.mode {
|
||||||
1,
|
ListCursorMode::Insert => {
|
||||||
data_port,
|
if *idx < cur_idx {
|
||||||
|s: &mut Self, idx| {
|
|
||||||
if let Some(cur_idx) = s.cur_cursor.idx {
|
|
||||||
match s.cur_cursor.mode {
|
|
||||||
ListCursorMode::Insert => {
|
|
||||||
if *idx < cur_idx {
|
|
||||||
s.cast.notify(idx);
|
|
||||||
} else {
|
|
||||||
s.cast.notify(&(*idx + 1));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
s.cast.notify(idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
s.cast.notify(idx);
|
s.cast.notify(idx);
|
||||||
|
} else {
|
||||||
|
s.cast.notify(&(*idx + 1));
|
||||||
}
|
}
|
||||||
}),
|
}
|
||||||
cast: out_port.get_broadcast(),
|
_ => {
|
||||||
proj_helper
|
s.cast.notify(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s.cast.notify(idx);
|
||||||
}
|
}
|
||||||
));
|
}),
|
||||||
|
cast: out_port.get_broadcast(),
|
||||||
|
proj_helper,
|
||||||
|
}));
|
||||||
|
|
||||||
proj.write().unwrap().proj_helper.set_proj(&proj);
|
proj.write().unwrap().proj_helper.set_proj(&proj);
|
||||||
out_port.set_view(Some(proj.clone()));
|
out_port.set_view(Some(proj.clone()));
|
||||||
|
@ -139,4 +120,3 @@ impl ListEditorView {
|
||||||
proj
|
proj
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
|
|
||||||
pub mod sexpr;
|
|
||||||
pub mod cursor;
|
pub mod cursor;
|
||||||
pub mod editor;
|
pub mod editor;
|
||||||
pub mod editor_view;
|
pub mod editor_view;
|
||||||
|
pub mod sexpr;
|
||||||
|
|
||||||
pub use sexpr::{SExprView, ListDecoration};
|
pub use cursor::{ListCursor, ListCursorMode};
|
||||||
pub use cursor::{ListCursorMode, ListCursor};
|
|
||||||
pub use editor::{ListEditor, ListEditorStyle};
|
pub use editor::{ListEditor, ListEditorStyle};
|
||||||
|
pub use sexpr::{ListDecoration, SExprView};
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
core::{InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View, ViewPort},
|
core::{InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View, ViewPort},
|
||||||
|
index::IndexArea,
|
||||||
projection::ProjectionHelper,
|
projection::ProjectionHelper,
|
||||||
sequence::SequenceView,
|
sequence::SequenceView,
|
||||||
index::{IndexArea},
|
|
||||||
terminal::{make_label, TerminalStyle, TerminalView},
|
terminal::{make_label, TerminalStyle, TerminalView},
|
||||||
},
|
},
|
||||||
cgmath::Point2,
|
cgmath::Point2,
|
||||||
|
@ -150,7 +150,8 @@ impl IndexView<Point2<i16>> for VerticalSexprDecorator {
|
||||||
|
|
||||||
fn area(&self) -> IndexArea<Point2<i16>> {
|
fn area(&self) -> IndexArea<Point2<i16>> {
|
||||||
IndexArea::Range(
|
IndexArea::Range(
|
||||||
Point2::new(0, 0) ..= Point2::new(2, std::cmp::max(self.items.len().unwrap() as i16 - 1, 0))
|
Point2::new(0, 0)
|
||||||
|
..=Point2::new(2, std::cmp::max(self.items.len().unwrap() as i16 - 1, 0)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,11 +217,9 @@ impl VerticalSexprDecorator {
|
||||||
opening_port: make_label(opening),
|
opening_port: make_label(opening),
|
||||||
closing_port: make_label(closing),
|
closing_port: make_label(closing),
|
||||||
items: proj_helper.new_sequence_arg((), items_port, |s: &mut Self, item_idx| {
|
items: proj_helper.new_sequence_arg((), items_port, |s: &mut Self, item_idx| {
|
||||||
s.cast.notify(
|
s.cast.notify(&IndexArea::Range(
|
||||||
&IndexArea::Range(
|
Point2::new(0, *item_idx as i16)..=Point2::new(2, *item_idx as i16),
|
||||||
Point2::new(0, *item_idx as i16) ..= Point2::new(2, *item_idx as i16)
|
));
|
||||||
)
|
|
||||||
);
|
|
||||||
}),
|
}),
|
||||||
list_style: TerminalStyle::fg_color(match level {
|
list_style: TerminalStyle::fg_color(match level {
|
||||||
0 => (200, 120, 10),
|
0 => (200, 120, 10),
|
||||||
|
|
|
@ -1,51 +1,46 @@
|
||||||
use {
|
use {
|
||||||
std::{
|
|
||||||
cmp::{max},
|
|
||||||
any::Any,
|
|
||||||
sync::{Arc, Weak},
|
|
||||||
hash::Hash,
|
|
||||||
collections::HashMap
|
|
||||||
},
|
|
||||||
std::sync::RwLock,
|
|
||||||
crate::{
|
crate::{
|
||||||
core::{
|
core::{
|
||||||
View,
|
channel::{queue_channel, set_channel, ChannelData, ChannelReceiver, ChannelSender},
|
||||||
Observer, ObserverExt,
|
|
||||||
port::UpdateTask,
|
port::UpdateTask,
|
||||||
OuterViewPort,
|
Observer, ObserverExt, OuterViewPort, View,
|
||||||
channel::{
|
|
||||||
ChannelSender, ChannelReceiver,
|
|
||||||
ChannelData,
|
|
||||||
set_channel,
|
|
||||||
queue_channel
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
singleton::{SingletonView},
|
index::{IndexArea, IndexView},
|
||||||
sequence::{SequenceView},
|
sequence::SequenceView,
|
||||||
index::{IndexArea, IndexView}
|
singleton::SingletonView,
|
||||||
}
|
},
|
||||||
|
std::sync::RwLock,
|
||||||
|
std::{
|
||||||
|
any::Any,
|
||||||
|
cmp::max,
|
||||||
|
collections::HashMap,
|
||||||
|
hash::Hash,
|
||||||
|
sync::{Arc, Weak},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub struct ProjectionHelper<ArgKey, P>
|
pub struct ProjectionHelper<ArgKey, P>
|
||||||
where ArgKey: Clone + Hash + Eq,
|
where
|
||||||
P: Send + Sync + 'static
|
ArgKey: Clone + Hash + Eq,
|
||||||
|
P: Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
keepalive: HashMap<ArgKey, (usize, Arc<dyn Any + Send + Sync>)>,
|
keepalive: HashMap<ArgKey, (usize, Arc<dyn Any + Send + Sync>)>,
|
||||||
proj: Arc<RwLock<Weak<RwLock<P>>>>,
|
proj: Arc<RwLock<Weak<RwLock<P>>>>,
|
||||||
update_hooks: Arc<RwLock<Vec<Arc<dyn UpdateTask>>>>
|
update_hooks: Arc<RwLock<Vec<Arc<dyn UpdateTask>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<ArgKey, P> ProjectionHelper<ArgKey, P>
|
impl<ArgKey, P> ProjectionHelper<ArgKey, P>
|
||||||
where ArgKey: Clone + Hash + Eq,
|
where
|
||||||
P: Send + Sync + 'static
|
ArgKey: Clone + Hash + Eq,
|
||||||
|
P: Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
pub fn new(update_hooks: Arc<RwLock<Vec<Arc<dyn UpdateTask>>>>) -> Self {
|
pub fn new(update_hooks: Arc<RwLock<Vec<Arc<dyn UpdateTask>>>>) -> Self {
|
||||||
ProjectionHelper {
|
ProjectionHelper {
|
||||||
keepalive: HashMap::new(),
|
keepalive: HashMap::new(),
|
||||||
proj: Arc::new(RwLock::new(Weak::new())),
|
proj: Arc::new(RwLock::new(Weak::new())),
|
||||||
update_hooks
|
update_hooks,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +55,7 @@ where ArgKey: Clone + Hash + Eq,
|
||||||
&mut self,
|
&mut self,
|
||||||
arg_key: ArgKey,
|
arg_key: ArgKey,
|
||||||
port: OuterViewPort<dyn SingletonView<Item = Item>>,
|
port: OuterViewPort<dyn SingletonView<Item = Item>>,
|
||||||
notify: impl Fn(&mut P, &()) + Send + Sync + 'static
|
notify: impl Fn(&mut P, &()) + Send + Sync + 'static,
|
||||||
) -> Arc<RwLock<Option<Arc<dyn SingletonView<Item = Item>>>>> {
|
) -> 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.add_observer(self.new_arg(arg_key, Arc::new(port.0.clone()), notify, set_channel()));
|
||||||
port.get_view_arc()
|
port.get_view_arc()
|
||||||
|
@ -70,7 +65,7 @@ where ArgKey: Clone + Hash + Eq,
|
||||||
&mut self,
|
&mut self,
|
||||||
arg_key: ArgKey,
|
arg_key: ArgKey,
|
||||||
port: OuterViewPort<dyn SequenceView<Item = Item>>,
|
port: OuterViewPort<dyn SequenceView<Item = Item>>,
|
||||||
notify: impl Fn(&mut P, &usize) + Send + Sync + 'static
|
notify: impl Fn(&mut P, &usize) + Send + Sync + 'static,
|
||||||
) -> Arc<RwLock<Option<Arc<dyn SequenceView<Item = Item>>>>> {
|
) -> 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.add_observer(self.new_arg(arg_key, Arc::new(port.0.clone()), notify, set_channel()));
|
||||||
port.get_view_arc()
|
port.get_view_arc()
|
||||||
|
@ -80,35 +75,32 @@ where ArgKey: Clone + Hash + Eq,
|
||||||
&mut self,
|
&mut self,
|
||||||
arg_key: ArgKey,
|
arg_key: ArgKey,
|
||||||
port: OuterViewPort<dyn IndexView<Key, Item = Item>>,
|
port: OuterViewPort<dyn IndexView<Key, Item = Item>>,
|
||||||
notify: impl Fn(&mut P, &IndexArea<Key>) + Send + Sync + 'static
|
notify: impl Fn(&mut P, &IndexArea<Key>) + Send + Sync + 'static,
|
||||||
) -> Arc<RwLock<Option<Arc<dyn IndexView<Key, Item = Item>>>>> {
|
) -> 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.add_observer(self.new_arg(arg_key, Arc::new(port.0.clone()), notify, queue_channel()));
|
||||||
port.get_view_arc()
|
port.get_view_arc()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_arg<
|
pub fn new_arg<V: View + ?Sized + 'static, D: ChannelData<Item = V::Msg> + 'static>(
|
||||||
V: View + ?Sized + 'static,
|
|
||||||
D: ChannelData<Item = V::Msg> + 'static
|
|
||||||
>(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
arg_key: ArgKey,
|
arg_key: ArgKey,
|
||||||
src_update: Arc<dyn UpdateTask>,
|
src_update: Arc<dyn UpdateTask>,
|
||||||
notify: impl Fn(&mut P, &V::Msg) + Send + Sync + 'static,
|
notify: impl Fn(&mut P, &V::Msg) + Send + Sync + 'static,
|
||||||
(tx, rx): (ChannelSender<D>, ChannelReceiver<D>)
|
(tx, rx): (ChannelSender<D>, ChannelReceiver<D>),
|
||||||
)
|
) -> Arc<RwLock<ProjectionArg<P, V, D>>>
|
||||||
-> Arc<RwLock<ProjectionArg<P, V, D>>>
|
where
|
||||||
where V::Msg: Send + Sync,
|
V::Msg: Send + Sync,
|
||||||
D::IntoIter: Send + Sync + 'static
|
D::IntoIter: Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
self.remove_arg(&arg_key);
|
self.remove_arg(&arg_key);
|
||||||
|
|
||||||
let arg = Arc::new(RwLock::new(
|
let arg = Arc::new(RwLock::new(ProjectionArg {
|
||||||
ProjectionArg {
|
src: None,
|
||||||
src: None,
|
notify: Box::new(notify),
|
||||||
notify: Box::new(notify),
|
proj: self.proj.clone(),
|
||||||
proj: self.proj.clone(),
|
rx,
|
||||||
rx, tx
|
tx,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let mut hooks = self.update_hooks.write().unwrap();
|
let mut hooks = self.update_hooks.write().unwrap();
|
||||||
let idx = hooks.len();
|
let idx = hooks.len();
|
||||||
|
@ -121,7 +113,7 @@ where ArgKey: Clone + Hash + Eq,
|
||||||
|
|
||||||
pub fn remove_arg(&mut self, arg_key: &ArgKey) {
|
pub fn remove_arg(&mut self, arg_key: &ArgKey) {
|
||||||
let mut hooks = self.update_hooks.write().unwrap();
|
let mut hooks = self.update_hooks.write().unwrap();
|
||||||
if let Some((idx, arg)) = self.keepalive.remove(arg_key) {
|
if let Some((idx, _arg)) = self.keepalive.remove(arg_key) {
|
||||||
hooks.remove(idx);
|
hooks.remove(idx);
|
||||||
hooks.remove(idx);
|
hooks.remove(idx);
|
||||||
for (_, (j, _)) in self.keepalive.iter_mut() {
|
for (_, (j, _)) in self.keepalive.iter_mut() {
|
||||||
|
@ -136,33 +128,32 @@ where ArgKey: Clone + Hash + Eq,
|
||||||
/// Special Observer which can access the state of the projection on notify
|
/// Special Observer which can access the state of the projection on notify
|
||||||
/// also handles the reset()
|
/// also handles the reset()
|
||||||
pub struct ProjectionArg<P, V, D>
|
pub struct ProjectionArg<P, V, D>
|
||||||
where P: Send + Sync + 'static,
|
where
|
||||||
V: View + ?Sized,
|
P: Send + Sync + 'static,
|
||||||
D: ChannelData<Item = V::Msg>,
|
V: View + ?Sized,
|
||||||
D::IntoIter: Send + Sync
|
D: ChannelData<Item = V::Msg>,
|
||||||
|
D::IntoIter: Send + Sync,
|
||||||
{
|
{
|
||||||
src: Option<Arc<V>>,
|
src: Option<Arc<V>>,
|
||||||
notify: Box<dyn Fn(&mut P, &V::Msg) + Send + Sync + 'static>,
|
notify: Box<dyn Fn(&mut P, &V::Msg) + Send + Sync + 'static>,
|
||||||
proj: Arc<RwLock<Weak<RwLock<P>>>>,
|
proj: Arc<RwLock<Weak<RwLock<P>>>>,
|
||||||
rx: ChannelReceiver<D>,
|
rx: ChannelReceiver<D>,
|
||||||
tx: ChannelSender<D>
|
tx: ChannelSender<D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P, V, D> UpdateTask for ProjectionArg<P, V, D>
|
impl<P, V, D> UpdateTask for ProjectionArg<P, V, D>
|
||||||
where P: Send + Sync + 'static,
|
where
|
||||||
V: View + ?Sized,
|
P: Send + Sync + 'static,
|
||||||
D: ChannelData<Item = V::Msg>,
|
V: View + ?Sized,
|
||||||
D::IntoIter: Send + Sync
|
D: ChannelData<Item = V::Msg>,
|
||||||
|
D::IntoIter: Send + Sync,
|
||||||
{
|
{
|
||||||
fn update(&self) {
|
fn update(&self) {
|
||||||
if let Some(p) = self.proj.read().unwrap().upgrade() {
|
if let Some(p) = self.proj.read().unwrap().upgrade() {
|
||||||
if let Some(data) = self.rx.try_recv() {
|
if let Some(data) = self.rx.try_recv() {
|
||||||
for msg in data {
|
for msg in data {
|
||||||
//eprintln!("proj update {:?}", msg);
|
//eprintln!("proj update {:?}", msg);
|
||||||
(self.notify)(
|
(self.notify)(&mut *p.write().unwrap(), &msg);
|
||||||
&mut *p.write().unwrap(),
|
|
||||||
&msg
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -172,10 +163,11 @@ where P: Send + Sync + 'static,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P, V, D> UpdateTask for RwLock<ProjectionArg<P, V, D>>
|
impl<P, V, D> UpdateTask for RwLock<ProjectionArg<P, V, D>>
|
||||||
where P: Send + Sync + 'static,
|
where
|
||||||
V: View + ?Sized,
|
P: Send + Sync + 'static,
|
||||||
D: ChannelData<Item = V::Msg>,
|
V: View + ?Sized,
|
||||||
D::IntoIter: Send + Sync
|
D: ChannelData<Item = V::Msg>,
|
||||||
|
D::IntoIter: Send + Sync,
|
||||||
{
|
{
|
||||||
fn update(&self) {
|
fn update(&self) {
|
||||||
self.read().unwrap().update();
|
self.read().unwrap().update();
|
||||||
|
@ -184,10 +176,12 @@ where P: Send + Sync + 'static,
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl<P, Item, D> Observer<dyn SingletonView<Item = Item>> for ProjectionArg<P, dyn SingletonView<Item = Item>, D>
|
impl<P, Item, D> Observer<dyn SingletonView<Item = Item>>
|
||||||
where P: Send + Sync + 'static,
|
for ProjectionArg<P, dyn SingletonView<Item = Item>, D>
|
||||||
D: ChannelData<Item = ()>,
|
where
|
||||||
D::IntoIter: Send + Sync
|
P: Send + Sync + 'static,
|
||||||
|
D: ChannelData<Item = ()>,
|
||||||
|
D::IntoIter: Send + Sync,
|
||||||
{
|
{
|
||||||
fn reset(&mut self, new_src: Option<Arc<dyn SingletonView<Item = Item>>>) {
|
fn reset(&mut self, new_src: Option<Arc<dyn SingletonView<Item = Item>>>) {
|
||||||
self.src = new_src;
|
self.src = new_src;
|
||||||
|
@ -201,17 +195,19 @@ where P: Send + Sync + 'static,
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl<P, Item, D> Observer<dyn SequenceView<Item = Item>> for ProjectionArg<P, dyn SequenceView<Item = Item>, D>
|
impl<P, Item, D> Observer<dyn SequenceView<Item = Item>>
|
||||||
where P: Send + Sync + 'static,
|
for ProjectionArg<P, dyn SequenceView<Item = Item>, D>
|
||||||
D: ChannelData<Item = usize>,
|
where
|
||||||
D::IntoIter: Send + Sync
|
P: Send + Sync + 'static,
|
||||||
|
D: ChannelData<Item = usize>,
|
||||||
|
D::IntoIter: Send + Sync,
|
||||||
{
|
{
|
||||||
fn reset(&mut self, new_src: Option<Arc<dyn SequenceView<Item = Item>>>) {
|
fn reset(&mut self, new_src: Option<Arc<dyn SequenceView<Item = Item>>>) {
|
||||||
let old_len = self.src.len().unwrap_or(0);
|
let old_len = self.src.len().unwrap_or(0);
|
||||||
self.src = new_src;
|
self.src = new_src;
|
||||||
let new_len = self.src.len().unwrap_or(0);
|
let new_len = self.src.len().unwrap_or(0);
|
||||||
|
|
||||||
self.notify_each(0 .. max(old_len, new_len));
|
self.notify_each(0..max(old_len, new_len));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn notify(&mut self, msg: &usize) {
|
fn notify(&mut self, msg: &usize) {
|
||||||
|
@ -221,11 +217,13 @@ where P: Send + Sync + 'static,
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl<P, Key, Item, D> Observer<dyn IndexView<Key, Item = Item>> for ProjectionArg<P, dyn IndexView<Key, Item = Item>, D>
|
impl<P, Key, Item, D> Observer<dyn IndexView<Key, Item = Item>>
|
||||||
where P: Send + Sync + 'static,
|
for ProjectionArg<P, dyn IndexView<Key, Item = Item>, D>
|
||||||
Key: Clone + Send + Sync,
|
where
|
||||||
D: ChannelData<Item = IndexArea<Key>>,
|
P: Send + Sync + 'static,
|
||||||
D::IntoIter: Send + Sync
|
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>>>) {
|
fn reset(&mut self, new_src: Option<Arc<dyn IndexView<Key, Item = Item>>>) {
|
||||||
let old_area = self.src.area();
|
let old_area = self.src.area();
|
||||||
|
@ -239,4 +237,3 @@ where P: Send + Sync + 'static,
|
||||||
self.tx.send(msg.clone());
|
self.tx.send(msg.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,33 +1,28 @@
|
||||||
use {
|
use {
|
||||||
|
crate::{
|
||||||
|
core::{Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View, ViewPort},
|
||||||
|
sequence::SequenceView,
|
||||||
|
},
|
||||||
std::sync::Arc,
|
std::sync::Arc,
|
||||||
std::sync::RwLock,
|
std::sync::RwLock,
|
||||||
crate::{
|
|
||||||
sequence::{SequenceView},
|
|
||||||
core::{
|
|
||||||
Observer, ObserverExt, ObserverBroadcast,
|
|
||||||
View, ViewPort, OuterViewPort
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl<V: SequenceView + ?Sized + 'static> OuterViewPort<V>
|
impl<V: SequenceView + ?Sized + 'static> OuterViewPort<V> {
|
||||||
{
|
pub fn filter<P: Fn(&V::Item) -> bool + Send + Sync + 'static>(
|
||||||
pub fn filter<
|
&self,
|
||||||
P: Fn(&V::Item) -> bool + Send + Sync + 'static
|
pred: P,
|
||||||
>(&self, pred: P) -> OuterViewPort<dyn SequenceView<Item = V::Item>> {
|
) -> OuterViewPort<dyn SequenceView<Item = V::Item>> {
|
||||||
let port = ViewPort::new();
|
let port = ViewPort::new();
|
||||||
port.add_update_hook(Arc::new(self.0.clone()));
|
port.add_update_hook(Arc::new(self.0.clone()));
|
||||||
|
|
||||||
let filter = Arc::new(RwLock::new(
|
let filter = Arc::new(RwLock::new(Filter {
|
||||||
Filter {
|
src_view: None,
|
||||||
src_view: None,
|
pred,
|
||||||
pred,
|
old_preds: RwLock::new(Vec::new()),
|
||||||
old_preds: RwLock::new(Vec::new()),
|
cast: port.inner().get_broadcast(),
|
||||||
cast: port.inner().get_broadcast()
|
}));
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
self.add_observer(filter.clone());
|
self.add_observer(filter.clone());
|
||||||
port.inner().set_view(Some(filter));
|
port.inner().set_view(Some(filter));
|
||||||
|
@ -38,18 +33,20 @@ impl<V: SequenceView + ?Sized + 'static> OuterViewPort<V>
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
struct Filter<SrcView, P>
|
struct Filter<SrcView, P>
|
||||||
where SrcView: SequenceView + ?Sized + 'static,
|
where
|
||||||
P: Fn(&SrcView::Item) -> bool + Send + Sync + 'static
|
SrcView: SequenceView + ?Sized + 'static,
|
||||||
|
P: Fn(&SrcView::Item) -> bool + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
src_view: Option<Arc<SrcView>>,
|
src_view: Option<Arc<SrcView>>,
|
||||||
pred: P,
|
pred: P,
|
||||||
old_preds: RwLock<Vec<bool>>,
|
old_preds: RwLock<Vec<bool>>,
|
||||||
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = SrcView::Item>>>>
|
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = SrcView::Item>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SrcView, P> Filter<SrcView, P>
|
impl<SrcView, P> Filter<SrcView, P>
|
||||||
where SrcView: SequenceView + ?Sized + 'static,
|
where
|
||||||
P: Fn(&SrcView::Item) -> bool + Send + Sync + 'static
|
SrcView: SequenceView + ?Sized + 'static,
|
||||||
|
P: Fn(&SrcView::Item) -> bool + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
fn get_offset(&self, idx: usize) -> usize {
|
fn get_offset(&self, idx: usize) -> usize {
|
||||||
if let Some(v) = self.src_view.clone() {
|
if let Some(v) = self.src_view.clone() {
|
||||||
|
@ -63,12 +60,12 @@ where SrcView: SequenceView + ?Sized + 'static,
|
||||||
} else {
|
} else {
|
||||||
offset += 1;
|
offset += 1;
|
||||||
}
|
}
|
||||||
i+=1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
offset
|
offset
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,36 +73,39 @@ where SrcView: SequenceView + ?Sized + 'static,
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl<SrcView, P> View for Filter<SrcView, P>
|
impl<SrcView, P> View for Filter<SrcView, P>
|
||||||
where SrcView: SequenceView + ?Sized + 'static,
|
where
|
||||||
P: Fn(&SrcView::Item) -> bool + Send + Sync + 'static
|
SrcView: SequenceView + ?Sized + 'static,
|
||||||
|
P: Fn(&SrcView::Item) -> bool + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
type Msg = usize;
|
type Msg = usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SrcView, P> SequenceView for Filter<SrcView, P>
|
impl<SrcView, P> SequenceView for Filter<SrcView, P>
|
||||||
where SrcView: SequenceView + ?Sized + 'static,
|
where
|
||||||
P: Fn(&SrcView::Item) -> bool + Send + Sync + 'static
|
SrcView: SequenceView + ?Sized + 'static,
|
||||||
|
P: Fn(&SrcView::Item) -> bool + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
type Item = SrcView::Item;
|
type Item = SrcView::Item;
|
||||||
|
|
||||||
fn len(&self) -> Option<usize> {
|
fn len(&self) -> Option<usize> {
|
||||||
if let Some(src_len) = self.src_view.len() {
|
if let Some(src_len) = self.src_view.len() {
|
||||||
Some(src_len - self.get_offset(src_len) )
|
Some(src_len - self.get_offset(src_len))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self, idx: &usize) -> Option<Self::Item> {
|
fn get(&self, idx: &usize) -> Option<Self::Item> {
|
||||||
self.src_view.get(&( idx + self.get_offset(*idx) ))
|
self.src_view.get(&(idx + self.get_offset(*idx)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl<SrcView, P> Observer<SrcView> for Filter<SrcView, P>
|
impl<SrcView, P> Observer<SrcView> for Filter<SrcView, P>
|
||||||
where SrcView: SequenceView + ?Sized + 'static,
|
where
|
||||||
P: Fn(&SrcView::Item) -> bool + Send + Sync + 'static
|
SrcView: SequenceView + ?Sized + 'static,
|
||||||
|
P: Fn(&SrcView::Item) -> bool + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
fn reset(&mut self, new_src: Option<Arc<SrcView>>) {
|
fn reset(&mut self, new_src: Option<Arc<SrcView>>) {
|
||||||
let old_len = self.len();
|
let old_len = self.len();
|
||||||
|
@ -113,44 +113,48 @@ where SrcView: SequenceView + ?Sized + 'static,
|
||||||
self.old_preds = RwLock::new(Vec::new());
|
self.old_preds = RwLock::new(Vec::new());
|
||||||
let new_len = self.len();
|
let new_len = self.len();
|
||||||
|
|
||||||
if let Some(len) = old_len { self.cast.notify_each(0 .. len); }
|
if let Some(len) = old_len {
|
||||||
if let Some(len) = new_len { self.cast.notify_each(0 .. 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) {
|
fn notify(&mut self, idx: &usize) {
|
||||||
let l = self.len().unwrap_or(0)+1;
|
let l = self.len().unwrap_or(0) + 1;
|
||||||
let np =
|
let np = if let Some(x) = self.src_view.get(idx) {
|
||||||
if let Some(x) = self.src_view.get(idx) {
|
(self.pred)(&x)
|
||||||
(self.pred)(&x)
|
} else {
|
||||||
} else {
|
false
|
||||||
false
|
};
|
||||||
};
|
|
||||||
|
|
||||||
let mut opds = self.old_preds.write().unwrap();
|
let mut opds = self.old_preds.write().unwrap();
|
||||||
|
|
||||||
opds.resize_with(1+*idx, || false);
|
opds.resize_with(1 + *idx, || false);
|
||||||
let op = opds.get(*idx).cloned().unwrap_or(false);
|
let op = opds.get(*idx).cloned().unwrap_or(false);
|
||||||
*opds.get_mut(*idx).unwrap() = np;
|
*opds.get_mut(*idx).unwrap() = np;
|
||||||
|
|
||||||
drop(opds);
|
drop(opds);
|
||||||
|
|
||||||
let i =
|
let i = (0..*idx)
|
||||||
(0 .. *idx)
|
.map(|j| {
|
||||||
.map(
|
|
||||||
|j|
|
|
||||||
if let Some(x) = self.src_view.get(&j) {
|
if let Some(x) = self.src_view.get(&j) {
|
||||||
if (self.pred)(&x) { 1 } else { 0 }
|
if (self.pred)(&x) {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
)
|
})
|
||||||
.sum();
|
.sum();
|
||||||
|
|
||||||
if np != op {
|
if np != op {
|
||||||
self.cast.notify_each(i .. l);
|
self.cast.notify_each(i..l);
|
||||||
} else {
|
} else {
|
||||||
self.cast.notify(&i);
|
self.cast.notify(&i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,20 @@
|
||||||
use {
|
use {
|
||||||
std::{
|
|
||||||
sync::Arc,
|
|
||||||
collections::BTreeMap
|
|
||||||
},
|
|
||||||
std::sync::RwLock,
|
|
||||||
crate::{
|
crate::{
|
||||||
core::{
|
core::{
|
||||||
View, Observer, ObserverBroadcast, ObserverExt,
|
port::UpdateTask, InnerViewPort, Observer, ObserverBroadcast, ObserverExt,
|
||||||
ViewPort, InnerViewPort, OuterViewPort,
|
OuterViewPort, View, ViewPort,
|
||||||
port::UpdateTask
|
|
||||||
},
|
},
|
||||||
|
projection::ProjectionHelper,
|
||||||
sequence::SequenceView,
|
sequence::SequenceView,
|
||||||
projection::ProjectionHelper
|
},
|
||||||
}
|
std::sync::RwLock,
|
||||||
|
std::{collections::BTreeMap, sync::Arc},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<Item> OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = Item>>>>
|
impl<Item> OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = Item>>>>
|
||||||
where Item: 'static{
|
where
|
||||||
|
Item: 'static,
|
||||||
|
{
|
||||||
pub fn flatten(&self) -> OuterViewPort<dyn SequenceView<Item = Item>> {
|
pub fn flatten(&self) -> OuterViewPort<dyn SequenceView<Item = Item>> {
|
||||||
let port = ViewPort::new();
|
let port = ViewPort::new();
|
||||||
Flatten::new(self.clone(), port.inner());
|
Flatten::new(self.clone(), port.inner());
|
||||||
|
@ -25,31 +23,35 @@ where Item: 'static{
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Chunk<Item>
|
pub struct Chunk<Item>
|
||||||
where Item: 'static
|
where
|
||||||
|
Item: 'static,
|
||||||
{
|
{
|
||||||
offset: usize,
|
offset: usize,
|
||||||
len: usize,
|
len: usize,
|
||||||
view: Arc<dyn SequenceView<Item = Item>>
|
view: Arc<dyn SequenceView<Item = Item>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Flatten<Item>
|
pub struct Flatten<Item>
|
||||||
where Item: 'static
|
where
|
||||||
|
Item: 'static,
|
||||||
{
|
{
|
||||||
length: usize,
|
length: usize,
|
||||||
top: Arc<dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = Item>>>>,
|
top: Arc<dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = Item>>>>,
|
||||||
chunks: BTreeMap<usize, Chunk<Item>>,
|
chunks: BTreeMap<usize, Chunk<Item>>,
|
||||||
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = Item>>>>,
|
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = Item>>>>,
|
||||||
proj_helper: ProjectionHelper<usize, Self>
|
proj_helper: ProjectionHelper<usize, Self>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Item> View for Flatten<Item>
|
impl<Item> View for Flatten<Item>
|
||||||
where Item: 'static
|
where
|
||||||
|
Item: 'static,
|
||||||
{
|
{
|
||||||
type Msg = usize;
|
type Msg = usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Item> SequenceView for Flatten<Item>
|
impl<Item> SequenceView for Flatten<Item>
|
||||||
where Item: 'static
|
where
|
||||||
|
Item: 'static,
|
||||||
{
|
{
|
||||||
type Item = Item;
|
type Item = Item;
|
||||||
|
|
||||||
|
@ -65,28 +67,26 @@ where Item: 'static
|
||||||
|
|
||||||
/* TODO: remove unused projection args (bot-views) if they get replaced by a new viewport */
|
/* TODO: remove unused projection args (bot-views) if they get replaced by a new viewport */
|
||||||
impl<Item> Flatten<Item>
|
impl<Item> Flatten<Item>
|
||||||
where Item: 'static
|
where
|
||||||
|
Item: 'static,
|
||||||
{
|
{
|
||||||
pub fn new(
|
pub fn new(
|
||||||
top_port: OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = Item>>>>,
|
top_port: OuterViewPort<
|
||||||
out_port: InnerViewPort<dyn SequenceView<Item = Item>>
|
dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = Item>>>,
|
||||||
|
>,
|
||||||
|
out_port: InnerViewPort<dyn SequenceView<Item = Item>>,
|
||||||
) -> Arc<RwLock<Self>> {
|
) -> Arc<RwLock<Self>> {
|
||||||
let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone());
|
let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone());
|
||||||
|
|
||||||
let flat = Arc::new(RwLock::new(
|
let flat = Arc::new(RwLock::new(Flatten {
|
||||||
Flatten {
|
length: 0,
|
||||||
length: 0,
|
top: proj_helper.new_sequence_arg(usize::MAX, top_port, |s: &mut Self, chunk_idx| {
|
||||||
top: proj_helper.new_sequence_arg(
|
s.update_chunk(*chunk_idx);
|
||||||
usize::MAX,
|
}),
|
||||||
top_port,
|
chunks: BTreeMap::new(),
|
||||||
|s: &mut Self, chunk_idx| {
|
cast: out_port.get_broadcast(),
|
||||||
s.update_chunk(*chunk_idx);
|
proj_helper,
|
||||||
}
|
}));
|
||||||
),
|
|
||||||
chunks: BTreeMap::new(),
|
|
||||||
cast: out_port.get_broadcast(),
|
|
||||||
proj_helper
|
|
||||||
}));
|
|
||||||
|
|
||||||
flat.write().unwrap().proj_helper.set_proj(&flat);
|
flat.write().unwrap().proj_helper.set_proj(&flat);
|
||||||
out_port.set_view(Some(flat.clone()));
|
out_port.set_view(Some(flat.clone()));
|
||||||
|
@ -118,9 +118,9 @@ where Item: 'static
|
||||||
s.cast.notify(&(idx + chunk_offset));
|
s.cast.notify(&(idx + chunk_offset));
|
||||||
s.cast.notify_each(dirty_idx);
|
s.cast.notify_each(dirty_idx);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
)
|
),
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
chunk_port.0.update();
|
chunk_port.0.update();
|
||||||
|
@ -152,7 +152,7 @@ where Item: 'static
|
||||||
if old_offset != cur_offset {
|
if old_offset != cur_offset {
|
||||||
dirty_idx.extend(
|
dirty_idx.extend(
|
||||||
std::cmp::min(old_offset, cur_offset)
|
std::cmp::min(old_offset, cur_offset)
|
||||||
.. std::cmp::max(old_offset, cur_offset) + chunk.len
|
..std::cmp::max(old_offset, cur_offset) + chunk.len,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +162,7 @@ where Item: 'static
|
||||||
let old_length = self.length;
|
let old_length = self.length;
|
||||||
self.length = cur_offset;
|
self.length = cur_offset;
|
||||||
|
|
||||||
dirty_idx.extend(self.length .. old_length);
|
dirty_idx.extend(self.length..old_length);
|
||||||
dirty_idx
|
dirty_idx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,4 +179,3 @@ where Item: 'static
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,18 @@
|
||||||
use {
|
use {
|
||||||
|
crate::{
|
||||||
|
core::{Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View, ViewPort},
|
||||||
|
sequence::SequenceView,
|
||||||
|
},
|
||||||
std::sync::Arc,
|
std::sync::Arc,
|
||||||
std::sync::RwLock,
|
std::sync::RwLock,
|
||||||
crate::{
|
|
||||||
sequence::{SequenceView},
|
|
||||||
core::{
|
|
||||||
Observer, ObserverExt, ObserverBroadcast,
|
|
||||||
View, ViewPort, OuterViewPort
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl<Item: 'static> OuterViewPort<dyn SequenceView<Item = Item>> {
|
impl<Item: 'static> OuterViewPort<dyn SequenceView<Item = Item>> {
|
||||||
pub fn map<
|
pub fn map<DstItem: 'static, F: Fn(&Item) -> DstItem + Send + Sync + 'static>(
|
||||||
DstItem: 'static,
|
|
||||||
F: Fn(&Item) -> DstItem + Send + Sync + 'static
|
|
||||||
>(
|
|
||||||
&self,
|
&self,
|
||||||
f: F
|
f: F,
|
||||||
) -> OuterViewPort<dyn SequenceView<Item = DstItem>> {
|
) -> OuterViewPort<dyn SequenceView<Item = DstItem>> {
|
||||||
let port = ViewPort::new();
|
let port = ViewPort::new();
|
||||||
port.add_update_hook(Arc::new(self.0.clone()));
|
port.add_update_hook(Arc::new(self.0.clone()));
|
||||||
|
@ -26,7 +20,7 @@ impl<Item: 'static> OuterViewPort<dyn SequenceView<Item = Item>> {
|
||||||
let map = Arc::new(RwLock::new(MapSequenceItem {
|
let map = Arc::new(RwLock::new(MapSequenceItem {
|
||||||
src_view: None,
|
src_view: None,
|
||||||
f,
|
f,
|
||||||
cast: port.inner().get_broadcast()
|
cast: port.inner().get_broadcast(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
self.add_observer(map.clone());
|
self.add_observer(map.clone());
|
||||||
|
@ -36,10 +30,10 @@ impl<Item: 'static> OuterViewPort<dyn SequenceView<Item = Item>> {
|
||||||
|
|
||||||
pub fn filter_map<
|
pub fn filter_map<
|
||||||
DstItem: Clone + 'static,
|
DstItem: Clone + 'static,
|
||||||
F: Fn(&Item) -> Option<DstItem> + Send + Sync + 'static
|
F: Fn(&Item) -> Option<DstItem> + Send + Sync + 'static,
|
||||||
>(
|
>(
|
||||||
&self,
|
&self,
|
||||||
f: F
|
f: F,
|
||||||
) -> OuterViewPort<dyn SequenceView<Item = DstItem>> {
|
) -> OuterViewPort<dyn SequenceView<Item = DstItem>> {
|
||||||
self.map(f)
|
self.map(f)
|
||||||
.filter(|x| x.is_some())
|
.filter(|x| x.is_some())
|
||||||
|
@ -50,26 +44,29 @@ impl<Item: 'static> OuterViewPort<dyn SequenceView<Item = Item>> {
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub struct MapSequenceItem<DstItem, SrcView, F>
|
pub struct MapSequenceItem<DstItem, SrcView, F>
|
||||||
where SrcView: SequenceView + ?Sized,
|
where
|
||||||
F: Fn(&SrcView::Item) -> DstItem + Send + Sync
|
SrcView: SequenceView + ?Sized,
|
||||||
|
F: Fn(&SrcView::Item) -> DstItem + Send + Sync,
|
||||||
{
|
{
|
||||||
src_view: Option<Arc<SrcView>>,
|
src_view: Option<Arc<SrcView>>,
|
||||||
f: F,
|
f: F,
|
||||||
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = DstItem>>>>
|
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = DstItem>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl<DstItem, SrcView, F> View for MapSequenceItem<DstItem, SrcView, F>
|
impl<DstItem, SrcView, F> View for MapSequenceItem<DstItem, SrcView, F>
|
||||||
where SrcView: SequenceView + ?Sized,
|
where
|
||||||
F: Fn(&SrcView::Item) -> DstItem + Send + Sync
|
SrcView: SequenceView + ?Sized,
|
||||||
|
F: Fn(&SrcView::Item) -> DstItem + Send + Sync,
|
||||||
{
|
{
|
||||||
type Msg = usize;
|
type Msg = usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<DstItem, SrcView, F> SequenceView for MapSequenceItem<DstItem, SrcView, F>
|
impl<DstItem, SrcView, F> SequenceView for MapSequenceItem<DstItem, SrcView, F>
|
||||||
where SrcView: SequenceView + ?Sized,
|
where
|
||||||
F: Fn(&SrcView::Item) -> DstItem + Send + Sync
|
SrcView: SequenceView + ?Sized,
|
||||||
|
F: Fn(&SrcView::Item) -> DstItem + Send + Sync,
|
||||||
{
|
{
|
||||||
type Item = DstItem;
|
type Item = DstItem;
|
||||||
|
|
||||||
|
@ -85,20 +82,24 @@ where SrcView: SequenceView + ?Sized,
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl<DstItem, SrcView, F> Observer<SrcView> for MapSequenceItem<DstItem, SrcView, F>
|
impl<DstItem, SrcView, F> Observer<SrcView> for MapSequenceItem<DstItem, SrcView, F>
|
||||||
where SrcView: SequenceView + ?Sized,
|
where
|
||||||
F: Fn(&SrcView::Item) -> DstItem + Send + Sync
|
SrcView: SequenceView + ?Sized,
|
||||||
|
F: Fn(&SrcView::Item) -> DstItem + Send + Sync,
|
||||||
{
|
{
|
||||||
fn reset(&mut self, view: Option<Arc<SrcView>>) {
|
fn reset(&mut self, view: Option<Arc<SrcView>>) {
|
||||||
let old_len = self.len();
|
let old_len = self.len();
|
||||||
self.src_view = view;
|
self.src_view = view;
|
||||||
let new_len = self.len();
|
let new_len = self.len();
|
||||||
|
|
||||||
if let Some(len) = old_len { self.cast.notify_each(0 .. len ); }
|
if let Some(len) = old_len {
|
||||||
if let Some(len) = new_len { self.cast.notify_each(0 .. 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) {
|
fn notify(&mut self, msg: &usize) {
|
||||||
self.cast.notify(msg);
|
self.cast.notify(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
|
|
||||||
pub mod seq2idx;
|
|
||||||
pub mod map;
|
|
||||||
pub mod filter;
|
pub mod filter;
|
||||||
pub mod flatten;
|
pub mod flatten;
|
||||||
|
pub mod map;
|
||||||
|
pub mod seq2idx;
|
||||||
|
|
||||||
pub use seq2idx::{Sequence2Index};
|
pub use seq2idx::Sequence2Index;
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
use crate::core::View;
|
use crate::core::View;
|
||||||
|
|
||||||
pub trait SequenceView : View<Msg = usize> {
|
pub trait SequenceView: View<Msg = usize> {
|
||||||
type Item;
|
type Item;
|
||||||
|
|
||||||
fn get(&self, idx: &usize) -> Option<Self::Item>;
|
fn get(&self, idx: &usize) -> Option<Self::Item>;
|
||||||
|
@ -19,12 +18,9 @@ pub trait SequenceView : View<Msg = usize> {
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub trait SequenceViewExt : SequenceView {
|
pub trait SequenceViewExt: SequenceView {
|
||||||
fn iter<'a>(&'a self) -> SequenceViewIter<'a, Self> {
|
fn iter<'a>(&'a self) -> SequenceViewIter<'a, Self> {
|
||||||
SequenceViewIter {
|
SequenceViewIter { view: self, cur: 0 }
|
||||||
view: self,
|
|
||||||
cur: 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,14 +29,16 @@ impl<V: SequenceView + ?Sized> SequenceViewExt for V {}
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub struct SequenceViewIter<'a, V>
|
pub struct SequenceViewIter<'a, V>
|
||||||
where V: SequenceView + ?Sized
|
where
|
||||||
|
V: SequenceView + ?Sized,
|
||||||
{
|
{
|
||||||
view: &'a V,
|
view: &'a V,
|
||||||
cur: usize
|
cur: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, V> Iterator for SequenceViewIter<'a, V>
|
impl<'a, V> Iterator for SequenceViewIter<'a, V>
|
||||||
where V: SequenceView + ?Sized
|
where
|
||||||
|
V: SequenceView + ?Sized,
|
||||||
{
|
{
|
||||||
type Item = V::Item;
|
type Item = V::Item;
|
||||||
|
|
||||||
|
@ -53,11 +51,8 @@ where V: SequenceView + ?Sized
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
use std::{
|
|
||||||
sync::Arc,
|
|
||||||
ops::{Deref}
|
|
||||||
};
|
|
||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
|
use std::{ops::Deref, sync::Arc};
|
||||||
|
|
||||||
impl<V: SequenceView + ?Sized> SequenceView for RwLock<V> {
|
impl<V: SequenceView + ?Sized> SequenceView for RwLock<V> {
|
||||||
type Item = V::Item;
|
type Item = V::Item;
|
||||||
|
@ -98,4 +93,3 @@ impl<V: SequenceView> SequenceView for Option<V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,37 +1,34 @@
|
||||||
use {
|
use {
|
||||||
std::{
|
|
||||||
sync::Arc
|
|
||||||
},
|
|
||||||
std::sync::RwLock,
|
|
||||||
crate::{
|
crate::{
|
||||||
core::{
|
core::{InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View, ViewPort},
|
||||||
View, Observer, ObserverBroadcast,
|
grid::GridView,
|
||||||
ViewPort, InnerViewPort, OuterViewPort
|
|
||||||
},
|
|
||||||
sequence::SequenceView,
|
|
||||||
index::{IndexArea, IndexView},
|
index::{IndexArea, IndexView},
|
||||||
grid::GridView
|
sequence::SequenceView,
|
||||||
}
|
},
|
||||||
|
std::sync::Arc,
|
||||||
|
std::sync::RwLock,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Transforms a SequenceView into IndexView<usize>
|
/// Transforms a SequenceView into IndexView<usize>
|
||||||
pub struct Sequence2Index<SrcView>
|
pub struct Sequence2Index<SrcView>
|
||||||
where SrcView: SequenceView + ?Sized + 'static {
|
where
|
||||||
|
SrcView: SequenceView + ?Sized + 'static,
|
||||||
|
{
|
||||||
src_view: Option<Arc<SrcView>>,
|
src_view: Option<Arc<SrcView>>,
|
||||||
cast: Arc<RwLock<ObserverBroadcast<dyn IndexView<usize, Item = SrcView::Item>>>>
|
cast: Arc<RwLock<ObserverBroadcast<dyn IndexView<usize, Item = SrcView::Item>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SrcView> Sequence2Index<SrcView>
|
impl<SrcView> Sequence2Index<SrcView>
|
||||||
where SrcView: SequenceView + ?Sized + 'static {
|
where
|
||||||
|
SrcView: SequenceView + ?Sized + 'static,
|
||||||
|
{
|
||||||
pub fn new(
|
pub fn new(
|
||||||
port: InnerViewPort<dyn IndexView<usize, Item = SrcView::Item>>
|
port: InnerViewPort<dyn IndexView<usize, Item = SrcView::Item>>,
|
||||||
) -> Arc<RwLock<Self>> {
|
) -> Arc<RwLock<Self>> {
|
||||||
let s2i = Arc::new(RwLock::new(
|
let s2i = Arc::new(RwLock::new(Sequence2Index {
|
||||||
Sequence2Index {
|
src_view: None,
|
||||||
src_view: None,
|
cast: port.get_broadcast(),
|
||||||
cast: port.get_broadcast()
|
}));
|
||||||
}
|
|
||||||
));
|
|
||||||
port.set_view(Some(s2i.clone()));
|
port.set_view(Some(s2i.clone()));
|
||||||
s2i
|
s2i
|
||||||
}
|
}
|
||||||
|
@ -55,12 +52,16 @@ impl<Item: 'static> OuterViewPort<dyn SequenceView<Item = Item>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SrcView> View for Sequence2Index<SrcView>
|
impl<SrcView> View for Sequence2Index<SrcView>
|
||||||
where SrcView: SequenceView + ?Sized + 'static {
|
where
|
||||||
|
SrcView: SequenceView + ?Sized + 'static,
|
||||||
|
{
|
||||||
type Msg = IndexArea<usize>;
|
type Msg = IndexArea<usize>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SrcView> IndexView<usize> for Sequence2Index<SrcView>
|
impl<SrcView> IndexView<usize> for Sequence2Index<SrcView>
|
||||||
where SrcView: SequenceView + ?Sized + 'static {
|
where
|
||||||
|
SrcView: SequenceView + ?Sized + 'static,
|
||||||
|
{
|
||||||
type Item = SrcView::Item;
|
type Item = SrcView::Item;
|
||||||
|
|
||||||
fn get(&self, key: &usize) -> Option<Self::Item> {
|
fn get(&self, key: &usize) -> Option<Self::Item> {
|
||||||
|
@ -70,7 +71,7 @@ where SrcView: SequenceView + ?Sized + 'static {
|
||||||
fn area(&self) -> IndexArea<usize> {
|
fn area(&self) -> IndexArea<usize> {
|
||||||
if let Some(len) = self.src_view.len() {
|
if let Some(len) = self.src_view.len() {
|
||||||
if len > 0 {
|
if len > 0 {
|
||||||
IndexArea::Range(0 ..= len-1)
|
IndexArea::Range(0..=len - 1)
|
||||||
} else {
|
} else {
|
||||||
IndexArea::Empty
|
IndexArea::Empty
|
||||||
}
|
}
|
||||||
|
@ -81,7 +82,9 @@ where SrcView: SequenceView + ?Sized + 'static {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SrcView> Observer<SrcView> for Sequence2Index<SrcView>
|
impl<SrcView> Observer<SrcView> for Sequence2Index<SrcView>
|
||||||
where SrcView: SequenceView + ?Sized + 'static {
|
where
|
||||||
|
SrcView: SequenceView + ?Sized + 'static,
|
||||||
|
{
|
||||||
fn reset(&mut self, view: Option<Arc<SrcView>>) {
|
fn reset(&mut self, view: Option<Arc<SrcView>>) {
|
||||||
let old_area = self.area();
|
let old_area = self.area();
|
||||||
self.src_view = view;
|
self.src_view = view;
|
||||||
|
@ -91,7 +94,6 @@ where SrcView: SequenceView + ?Sized + 'static {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn notify(&mut self, idx: &usize) {
|
fn notify(&mut self, idx: &usize) {
|
||||||
self.cast.notify(&IndexArea::Set(vec![ *idx ]));
|
self.cast.notify(&IndexArea::Set(vec![*idx]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,13 @@
|
||||||
use {
|
use {
|
||||||
std::{
|
crate::{
|
||||||
sync::{Arc},
|
core::{InnerViewPort, Observer, ObserverBroadcast, View},
|
||||||
ops::{Deref, DerefMut}
|
singleton::SingletonView,
|
||||||
},
|
},
|
||||||
std::sync::RwLock,
|
std::sync::RwLock,
|
||||||
crate::{
|
std::{
|
||||||
core::{
|
ops::{Deref, DerefMut},
|
||||||
Observer,
|
sync::Arc,
|
||||||
ObserverBroadcast,
|
},
|
||||||
View,
|
|
||||||
InnerViewPort
|
|
||||||
},
|
|
||||||
singleton::{SingletonView}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
@ -20,12 +15,16 @@ use {
|
||||||
pub struct SingletonBufferView<T: Clone + Send + Sync + 'static>(Arc<RwLock<T>>);
|
pub struct SingletonBufferView<T: Clone + Send + Sync + 'static>(Arc<RwLock<T>>);
|
||||||
|
|
||||||
impl<T> View for SingletonBufferView<T>
|
impl<T> View for SingletonBufferView<T>
|
||||||
where T: Clone + Send + Sync + 'static {
|
where
|
||||||
|
T: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
type Msg = ();
|
type Msg = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> SingletonView for SingletonBufferView<T>
|
impl<T> SingletonView for SingletonBufferView<T>
|
||||||
where T: Clone + Send + Sync + 'static {
|
where
|
||||||
|
T: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
type Item = T;
|
type Item = T;
|
||||||
|
|
||||||
fn get(&self) -> Self::Item {
|
fn get(&self) -> Self::Item {
|
||||||
|
@ -37,23 +36,24 @@ where T: Clone + Send + Sync + 'static {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SingletonBuffer<T>
|
pub struct SingletonBuffer<T>
|
||||||
where T: Clone + Send + Sync + 'static {
|
where
|
||||||
|
T: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
value: Arc<RwLock<T>>,
|
value: Arc<RwLock<T>>,
|
||||||
cast: Arc<RwLock<ObserverBroadcast<dyn SingletonView<Item = T>>>>
|
cast: Arc<RwLock<ObserverBroadcast<dyn SingletonView<Item = T>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> SingletonBuffer<T>
|
impl<T> SingletonBuffer<T>
|
||||||
where T: Clone + Send + Sync + 'static {
|
where
|
||||||
pub fn new(
|
T: Clone + Send + Sync + 'static,
|
||||||
value: T,
|
{
|
||||||
port: InnerViewPort<dyn SingletonView<Item = T>>
|
pub fn new(value: T, port: InnerViewPort<dyn SingletonView<Item = T>>) -> Self {
|
||||||
) -> Self {
|
|
||||||
let value = Arc::new(RwLock::new(value));
|
let value = Arc::new(RwLock::new(value));
|
||||||
port.set_view(Some(Arc::new(SingletonBufferView(value.clone()))));
|
port.set_view(Some(Arc::new(SingletonBufferView(value.clone()))));
|
||||||
|
|
||||||
SingletonBuffer {
|
SingletonBuffer {
|
||||||
value,
|
value,
|
||||||
cast: port.get_broadcast()
|
cast: port.get_broadcast(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ where T: Clone + Send + Sync + 'static {
|
||||||
pub fn get_mut(&self) -> MutableSingletonAccess<T> {
|
pub fn get_mut(&self) -> MutableSingletonAccess<T> {
|
||||||
MutableSingletonAccess {
|
MutableSingletonAccess {
|
||||||
buf: self.clone(),
|
buf: self.clone(),
|
||||||
val: self.get()
|
val: self.get(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,13 +79,17 @@ where T: Clone + Send + Sync + 'static {
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub struct MutableSingletonAccess<T>
|
pub struct MutableSingletonAccess<T>
|
||||||
where T: Clone + Send + Sync + 'static {
|
where
|
||||||
|
T: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
buf: SingletonBuffer<T>,
|
buf: SingletonBuffer<T>,
|
||||||
val: T,
|
val: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Deref for MutableSingletonAccess<T>
|
impl<T> Deref for MutableSingletonAccess<T>
|
||||||
where T: Clone + Send + Sync + 'static {
|
where
|
||||||
|
T: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
fn deref(&self) -> &T {
|
fn deref(&self) -> &T {
|
||||||
|
@ -94,17 +98,19 @@ where T: Clone + Send + Sync + 'static {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> DerefMut for MutableSingletonAccess<T>
|
impl<T> DerefMut for MutableSingletonAccess<T>
|
||||||
where T: Clone + Send + Sync + 'static {
|
where
|
||||||
|
T: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
&mut self.val
|
&mut self.val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Drop for MutableSingletonAccess<T>
|
impl<T> Drop for MutableSingletonAccess<T>
|
||||||
where T: Clone + Send + Sync + 'static {
|
where
|
||||||
|
T: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.buf.set(self.val.clone());
|
self.buf.set(self.val.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,18 @@
|
||||||
use {
|
use {
|
||||||
|
crate::{
|
||||||
|
core::{Observer, ObserverBroadcast, OuterViewPort, View, ViewPort},
|
||||||
|
singleton::SingletonView,
|
||||||
|
},
|
||||||
std::sync::Arc,
|
std::sync::Arc,
|
||||||
std::sync::RwLock,
|
std::sync::RwLock,
|
||||||
crate::{
|
|
||||||
singleton::{SingletonView},
|
|
||||||
core::{
|
|
||||||
Observer, ObserverBroadcast,
|
|
||||||
View, ViewPort, OuterViewPort
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl<Item: 'static> OuterViewPort<dyn SingletonView<Item = Item>> {
|
impl<Item: 'static> OuterViewPort<dyn SingletonView<Item = Item>> {
|
||||||
pub fn map<
|
pub fn map<DstItem: 'static, F: Fn(Item) -> DstItem + Send + Sync + 'static>(
|
||||||
DstItem: 'static,
|
|
||||||
F: Fn(Item) -> DstItem + Send + Sync + 'static
|
|
||||||
>(
|
|
||||||
&self,
|
&self,
|
||||||
f: F
|
f: F,
|
||||||
) -> OuterViewPort<dyn SingletonView<Item = DstItem>> {
|
) -> OuterViewPort<dyn SingletonView<Item = DstItem>> {
|
||||||
let port = ViewPort::new();
|
let port = ViewPort::new();
|
||||||
port.add_update_hook(Arc::new(self.0.clone()));
|
port.add_update_hook(Arc::new(self.0.clone()));
|
||||||
|
@ -26,7 +20,7 @@ impl<Item: 'static> OuterViewPort<dyn SingletonView<Item = Item>> {
|
||||||
let map = Arc::new(RwLock::new(MapSingleton {
|
let map = Arc::new(RwLock::new(MapSingleton {
|
||||||
src_view: None,
|
src_view: None,
|
||||||
f,
|
f,
|
||||||
cast: port.inner().get_broadcast()
|
cast: port.inner().get_broadcast(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
self.add_observer(map.clone());
|
self.add_observer(map.clone());
|
||||||
|
@ -38,26 +32,29 @@ impl<Item: 'static> OuterViewPort<dyn SingletonView<Item = Item>> {
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub struct MapSingleton<DstItem, SrcView, F>
|
pub struct MapSingleton<DstItem, SrcView, F>
|
||||||
where SrcView: SingletonView + ?Sized,
|
where
|
||||||
F: Fn(SrcView::Item) -> DstItem + Send + Sync
|
SrcView: SingletonView + ?Sized,
|
||||||
|
F: Fn(SrcView::Item) -> DstItem + Send + Sync,
|
||||||
{
|
{
|
||||||
src_view: Option<Arc<SrcView>>,
|
src_view: Option<Arc<SrcView>>,
|
||||||
f: F,
|
f: F,
|
||||||
cast: Arc<RwLock<ObserverBroadcast<dyn SingletonView<Item = DstItem>>>>
|
cast: Arc<RwLock<ObserverBroadcast<dyn SingletonView<Item = DstItem>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl<DstItem, SrcView, F> View for MapSingleton<DstItem, SrcView, F>
|
impl<DstItem, SrcView, F> View for MapSingleton<DstItem, SrcView, F>
|
||||||
where SrcView: SingletonView + ?Sized,
|
where
|
||||||
F: Fn(SrcView::Item) -> DstItem + Send + Sync
|
SrcView: SingletonView + ?Sized,
|
||||||
|
F: Fn(SrcView::Item) -> DstItem + Send + Sync,
|
||||||
{
|
{
|
||||||
type Msg = ();
|
type Msg = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<DstItem, SrcView, F> SingletonView for MapSingleton<DstItem, SrcView, F>
|
impl<DstItem, SrcView, F> SingletonView for MapSingleton<DstItem, SrcView, F>
|
||||||
where SrcView: SingletonView + ?Sized,
|
where
|
||||||
F: Fn(SrcView::Item) -> DstItem + Send + Sync
|
SrcView: SingletonView + ?Sized,
|
||||||
|
F: Fn(SrcView::Item) -> DstItem + Send + Sync,
|
||||||
{
|
{
|
||||||
type Item = DstItem;
|
type Item = DstItem;
|
||||||
|
|
||||||
|
@ -69,8 +66,9 @@ where SrcView: SingletonView + ?Sized,
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl<DstItem, SrcView, F> Observer<SrcView> for MapSingleton<DstItem, SrcView, F>
|
impl<DstItem, SrcView, F> Observer<SrcView> for MapSingleton<DstItem, SrcView, F>
|
||||||
where SrcView: SingletonView + ?Sized,
|
where
|
||||||
F: Fn(SrcView::Item) -> DstItem + Send + Sync
|
SrcView: SingletonView + ?Sized,
|
||||||
|
F: Fn(SrcView::Item) -> DstItem + Send + Sync,
|
||||||
{
|
{
|
||||||
fn reset(&mut self, view: Option<Arc<SrcView>>) {
|
fn reset(&mut self, view: Option<Arc<SrcView>>) {
|
||||||
self.src_view = view;
|
self.src_view = view;
|
||||||
|
@ -81,4 +79,3 @@ where SrcView: SingletonView + ?Sized,
|
||||||
self.cast.notify(msg);
|
self.cast.notify(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,18 @@
|
||||||
|
|
||||||
pub mod buffer;
|
pub mod buffer;
|
||||||
pub mod map;
|
pub mod map;
|
||||||
pub mod to_index;
|
pub mod to_index;
|
||||||
//pub mod unwrap;
|
//pub mod unwrap;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
std::{
|
crate::core::View,
|
||||||
sync::Arc,
|
|
||||||
ops::Deref
|
|
||||||
},
|
|
||||||
std::sync::RwLock,
|
std::sync::RwLock,
|
||||||
crate::core::{View}
|
std::{ops::Deref, sync::Arc},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use buffer::SingletonBuffer;
|
pub use buffer::SingletonBuffer;
|
||||||
|
|
||||||
// TODO: #[ImplForArc, ImplForRwLock]
|
// TODO: #[ImplForArc, ImplForRwLock]
|
||||||
pub trait SingletonView : View<Msg = ()> {
|
pub trait SingletonView: View<Msg = ()> {
|
||||||
type Item;
|
type Item;
|
||||||
|
|
||||||
fn get(&self) -> Self::Item;
|
fn get(&self) -> Self::Item;
|
||||||
|
@ -41,7 +37,9 @@ impl<V: SingletonView + ?Sized> SingletonView for Arc<V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: SingletonView> SingletonView for Option<V>
|
impl<V: SingletonView> SingletonView for Option<V>
|
||||||
where V::Item: Default{
|
where
|
||||||
|
V::Item: Default,
|
||||||
|
{
|
||||||
type Item = V::Item;
|
type Item = V::Item;
|
||||||
|
|
||||||
fn get(&self) -> Self::Item {
|
fn get(&self) -> Self::Item {
|
||||||
|
@ -65,4 +63,3 @@ impl<T> OuterViewPort<dyn SingletonView<Item = T>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
use {
|
use {
|
||||||
|
crate::{
|
||||||
|
core::{Observer, ObserverBroadcast, OuterViewPort, View, ViewPort},
|
||||||
|
grid::GridView,
|
||||||
|
index::{IndexArea, IndexView},
|
||||||
|
singleton::SingletonView,
|
||||||
|
},
|
||||||
std::sync::Arc,
|
std::sync::Arc,
|
||||||
std::sync::RwLock,
|
std::sync::RwLock,
|
||||||
crate::{
|
|
||||||
singleton::{SingletonView},
|
|
||||||
index::{IndexArea, IndexView},
|
|
||||||
grid::{GridView},
|
|
||||||
core::{
|
|
||||||
Observer, ObserverBroadcast,
|
|
||||||
View, ViewPort, OuterViewPort
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
@ -21,7 +18,7 @@ impl<Item: 'static> OuterViewPort<dyn SingletonView<Item = Item>> {
|
||||||
|
|
||||||
let map = Arc::new(RwLock::new(Singleton2Index {
|
let map = Arc::new(RwLock::new(Singleton2Index {
|
||||||
src_view: None,
|
src_view: None,
|
||||||
cast: port.inner().get_broadcast()
|
cast: port.inner().get_broadcast(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
self.add_observer(map.clone());
|
self.add_observer(map.clone());
|
||||||
|
@ -30,33 +27,41 @@ impl<Item: 'static> OuterViewPort<dyn SingletonView<Item = Item>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_grid(&self) -> OuterViewPort<dyn GridView<Item = Item>> {
|
pub fn to_grid(&self) -> OuterViewPort<dyn GridView<Item = Item>> {
|
||||||
self.to_index()
|
self.to_index().map_key(
|
||||||
.map_key(
|
|_msg: &()| cgmath::Point2::new(0, 0),
|
||||||
|_msg: &()| cgmath::Point2::new(0, 0),
|
|pt| {
|
||||||
|pt| if pt.x == 0 && pt.y == 0 { Some(()) } else { None }
|
if pt.x == 0 && pt.y == 0 {
|
||||||
)
|
Some(())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub struct Singleton2Index<SrcView>
|
pub struct Singleton2Index<SrcView>
|
||||||
where SrcView: SingletonView + ?Sized
|
where
|
||||||
|
SrcView: SingletonView + ?Sized,
|
||||||
{
|
{
|
||||||
src_view: Option<Arc<SrcView>>,
|
src_view: Option<Arc<SrcView>>,
|
||||||
cast: Arc<RwLock<ObserverBroadcast<dyn IndexView<(), Item = SrcView::Item>>>>
|
cast: Arc<RwLock<ObserverBroadcast<dyn IndexView<(), Item = SrcView::Item>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl<SrcView> View for Singleton2Index<SrcView>
|
impl<SrcView> View for Singleton2Index<SrcView>
|
||||||
where SrcView: SingletonView + ?Sized
|
where
|
||||||
|
SrcView: SingletonView + ?Sized,
|
||||||
{
|
{
|
||||||
type Msg = IndexArea<()>;
|
type Msg = IndexArea<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SrcView> IndexView<()> for Singleton2Index<SrcView>
|
impl<SrcView> IndexView<()> for Singleton2Index<SrcView>
|
||||||
where SrcView: SingletonView + ?Sized
|
where
|
||||||
|
SrcView: SingletonView + ?Sized,
|
||||||
{
|
{
|
||||||
type Item = SrcView::Item;
|
type Item = SrcView::Item;
|
||||||
|
|
||||||
|
@ -72,7 +77,8 @@ where SrcView: SingletonView + ?Sized
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl<SrcView> Observer<SrcView> for Singleton2Index<SrcView>
|
impl<SrcView> Observer<SrcView> for Singleton2Index<SrcView>
|
||||||
where SrcView: SingletonView + ?Sized
|
where
|
||||||
|
SrcView: SingletonView + ?Sized,
|
||||||
{
|
{
|
||||||
fn reset(&mut self, view: Option<Arc<SrcView>>) {
|
fn reset(&mut self, view: Option<Arc<SrcView>>) {
|
||||||
self.src_view = view;
|
self.src_view = view;
|
||||||
|
@ -83,4 +89,3 @@ where SrcView: SingletonView + ?Sized
|
||||||
self.cast.notify(&IndexArea::Full);
|
self.cast.notify(&IndexArea::Full);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,30 +1,32 @@
|
||||||
use {
|
use {
|
||||||
|
crate::{
|
||||||
|
core::{OuterViewPort, ViewPort},
|
||||||
|
list::{sexpr::ListDecoration, ListEditor},
|
||||||
|
sequence::SequenceView,
|
||||||
|
singleton::{SingletonBuffer, SingletonView},
|
||||||
|
terminal::{
|
||||||
|
TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle, TerminalView,
|
||||||
|
},
|
||||||
|
tree_nav::{TreeCursor, TreeNav, TreeNavResult},
|
||||||
|
},
|
||||||
std::sync::Arc,
|
std::sync::Arc,
|
||||||
std::sync::RwLock,
|
std::sync::RwLock,
|
||||||
termion::event::{Key, Event},
|
termion::event::{Event, Key},
|
||||||
crate::{
|
|
||||||
core::{ViewPort, OuterViewPort},
|
|
||||||
singleton::{SingletonView, SingletonBuffer},
|
|
||||||
sequence::{SequenceView},
|
|
||||||
terminal::{TerminalView, TerminalStyle, TerminalEvent, TerminalEditor, TerminalEditorResult},
|
|
||||||
list::{ListEditor, sexpr::ListDecoration},
|
|
||||||
tree_nav::{TreeNav, TreeNavResult, TreeCursor}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub struct CharEditor {
|
pub struct CharEditor {
|
||||||
data: SingletonBuffer<Option<char>>,
|
data: SingletonBuffer<Option<char>>,
|
||||||
data_port: ViewPort<dyn SingletonView<Item = Option<char>>>
|
data_port: ViewPort<dyn SingletonView<Item = Option<char>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CharEditor {
|
impl CharEditor {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut data_port = ViewPort::new();
|
let data_port = ViewPort::new();
|
||||||
CharEditor {
|
CharEditor {
|
||||||
data: SingletonBuffer::new(None, data_port.inner()),
|
data: SingletonBuffer::new(None, data_port.inner()),
|
||||||
data_port
|
data_port,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,28 +38,26 @@ impl CharEditor {
|
||||||
impl TreeNav for CharEditor {}
|
impl TreeNav for CharEditor {}
|
||||||
impl TerminalEditor for CharEditor {
|
impl TerminalEditor for CharEditor {
|
||||||
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
|
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
|
||||||
crate::terminal::make_label(
|
crate::terminal::make_label(&if let Some(c) = self.data.get() {
|
||||||
&if let Some(c) = self.data.get() {
|
c.to_string()
|
||||||
c.to_string()
|
} else {
|
||||||
} else {
|
"".to_string()
|
||||||
"".to_string()
|
})
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
||||||
match event {
|
match event {
|
||||||
TerminalEvent::Input(Event::Key(Key::Char('\n'))) =>
|
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => TerminalEditorResult::Continue,
|
||||||
TerminalEditorResult::Continue,
|
|
||||||
TerminalEvent::Input(Event::Key(Key::Char(c))) => {
|
TerminalEvent::Input(Event::Key(Key::Char(c))) => {
|
||||||
self.data.set(Some(*c));
|
self.data.set(Some(*c));
|
||||||
TerminalEditorResult::Exit
|
TerminalEditorResult::Exit
|
||||||
}
|
}
|
||||||
TerminalEvent::Input(Event::Key(Key::Backspace)) |
|
TerminalEvent::Input(Event::Key(Key::Backspace))
|
||||||
TerminalEvent::Input(Event::Key(Key::Delete)) => {
|
| TerminalEvent::Input(Event::Key(Key::Delete)) => {
|
||||||
self.data.set(None);
|
self.data.set(None);
|
||||||
TerminalEditorResult::Exit
|
TerminalEditorResult::Exit
|
||||||
}
|
}
|
||||||
_ => TerminalEditorResult::Continue
|
_ => TerminalEditorResult::Continue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,41 +65,52 @@ impl TerminalEditor for CharEditor {
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub struct StringEditor {
|
pub struct StringEditor {
|
||||||
chars_editor: ListEditor< CharEditor,
|
chars_editor:
|
||||||
Box<dyn Fn() -> Arc<RwLock<CharEditor>> + Send + Sync + 'static> >
|
ListEditor<CharEditor, Box<dyn Fn() -> Arc<RwLock<CharEditor>> + Send + Sync + 'static>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StringEditor {
|
impl StringEditor {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
StringEditor {
|
StringEditor {
|
||||||
chars_editor: ListEditor::new(
|
chars_editor: ListEditor::new(
|
||||||
Box::new(
|
Box::new(move || Arc::new(RwLock::new(CharEditor::new()))),
|
||||||
move || {
|
crate::list::ListEditorStyle::String,
|
||||||
Arc::new(RwLock::new(CharEditor::new()))
|
),
|
||||||
}
|
|
||||||
),
|
|
||||||
crate::list::ListEditorStyle::String
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = char>> {
|
pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = char>> {
|
||||||
self.chars_editor.get_data_port()
|
self.chars_editor
|
||||||
.map(
|
.get_data_port()
|
||||||
|char_editor| char_editor.read().unwrap().data.get().unwrap()
|
.map(|char_editor| char_editor.read().unwrap().data.get().unwrap())
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TreeNav for StringEditor {
|
impl TreeNav for StringEditor {
|
||||||
fn get_cursor(&self) -> TreeCursor { self.chars_editor.get_cursor() }
|
fn get_cursor(&self) -> TreeCursor {
|
||||||
fn goto(&mut self, cur: TreeCursor) -> TreeNavResult { self.chars_editor.goto(cur) }
|
self.chars_editor.get_cursor()
|
||||||
fn goto_home(&mut self) -> TreeNavResult { self.chars_editor.goto_home() }
|
}
|
||||||
fn goto_end(&mut self) -> TreeNavResult { self.chars_editor.goto_end() }
|
fn goto(&mut self, cur: TreeCursor) -> TreeNavResult {
|
||||||
fn pxev(&mut self) -> TreeNavResult { self.chars_editor.pxev() }
|
self.chars_editor.goto(cur)
|
||||||
fn nexd(&mut self) -> TreeNavResult { self.chars_editor.nexd() }
|
}
|
||||||
fn up(&mut self) -> TreeNavResult { self.chars_editor.up() }
|
fn goto_home(&mut self) -> TreeNavResult {
|
||||||
fn dn(&mut self) -> TreeNavResult { TreeNavResult::Exit }
|
self.chars_editor.goto_home()
|
||||||
|
}
|
||||||
|
fn goto_end(&mut self) -> TreeNavResult {
|
||||||
|
self.chars_editor.goto_end()
|
||||||
|
}
|
||||||
|
fn pxev(&mut self) -> TreeNavResult {
|
||||||
|
self.chars_editor.pxev()
|
||||||
|
}
|
||||||
|
fn nexd(&mut self) -> TreeNavResult {
|
||||||
|
self.chars_editor.nexd()
|
||||||
|
}
|
||||||
|
fn up(&mut self) -> TreeNavResult {
|
||||||
|
self.chars_editor.up()
|
||||||
|
}
|
||||||
|
fn dn(&mut self) -> TreeNavResult {
|
||||||
|
TreeNavResult::Exit
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TerminalEditor for StringEditor {
|
impl TerminalEditor for StringEditor {
|
||||||
|
@ -109,10 +120,7 @@ impl TerminalEditor for StringEditor {
|
||||||
.decorate("\"", "\"", "", 1)
|
.decorate("\"", "\"", "", 1)
|
||||||
.to_grid_horizontal()
|
.to_grid_horizontal()
|
||||||
.flatten()
|
.flatten()
|
||||||
.map_item(
|
.map_item(|_idx, atom| atom.add_style_back(TerminalStyle::fg_color((120, 200, 10))))
|
||||||
|_idx, atom|
|
|
||||||
atom.add_style_back(TerminalStyle::fg_color((120, 200, 10)))
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
||||||
|
@ -121,8 +129,7 @@ impl TerminalEditor for StringEditor {
|
||||||
self.chars_editor.up();
|
self.chars_editor.up();
|
||||||
TerminalEditorResult::Exit
|
TerminalEditorResult::Exit
|
||||||
}
|
}
|
||||||
event => self.chars_editor.handle_terminal_event(event)
|
event => self.chars_editor.handle_terminal_event(event),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,37 +1,25 @@
|
||||||
use {
|
use {
|
||||||
std::{
|
|
||||||
sync::{Arc, RwLock},
|
|
||||||
pin::Pin,
|
|
||||||
fs::File,
|
|
||||||
os::unix::io::FromRawFd
|
|
||||||
},
|
|
||||||
std::io::Read,
|
|
||||||
//async_std::{io::{Read, ReadExt}},
|
//async_std::{io::{Read, ReadExt}},
|
||||||
crate::{
|
crate::{
|
||||||
core::{View, InnerViewPort, OuterViewPort, ViewPort, Observer, ObserverBroadcast},
|
core::{InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View, ViewPort},
|
||||||
|
index::{buffer::IndexBuffer, IndexArea, IndexView},
|
||||||
projection::ProjectionHelper,
|
projection::ProjectionHelper,
|
||||||
terminal::{
|
singleton::{SingletonBuffer, SingletonView},
|
||||||
TerminalAtom,
|
terminal::{TerminalAtom, TerminalStyle, TerminalView},
|
||||||
TerminalStyle,
|
|
||||||
TerminalView
|
|
||||||
},
|
|
||||||
singleton::{
|
|
||||||
SingletonBuffer,
|
|
||||||
SingletonView
|
|
||||||
},
|
|
||||||
index::{
|
|
||||||
buffer::IndexBuffer,
|
|
||||||
IndexView,
|
|
||||||
IndexArea
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
cgmath::{Vector2, Point2},
|
cgmath::{Point2, Vector2},
|
||||||
vte::{Params, Parser, Perform}
|
std::io::Read,
|
||||||
|
std::sync::{Arc, RwLock},
|
||||||
|
vte::{Params, Parser, Perform},
|
||||||
};
|
};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub fn read_ansi_from<R: Read + Unpin>(ansi_reader: &mut R, max_size: Vector2<i16>, port: InnerViewPort<dyn TerminalView>) {
|
pub fn read_ansi_from<R: Read + Unpin>(
|
||||||
|
ansi_reader: &mut R,
|
||||||
|
max_size: Vector2<i16>,
|
||||||
|
port: InnerViewPort<dyn TerminalView>,
|
||||||
|
) {
|
||||||
let mut statemachine = Parser::new();
|
let mut statemachine = Parser::new();
|
||||||
|
|
||||||
let buf_port = ViewPort::new();
|
let buf_port = ViewPort::new();
|
||||||
|
@ -56,17 +44,16 @@ pub fn read_ansi_from<R: Read + Unpin>(ansi_reader: &mut R, max_size: Vector2<i1
|
||||||
blue: (0, 111, 184),
|
blue: (0, 111, 184),
|
||||||
magenta: (118, 38, 113),
|
magenta: (118, 38, 113),
|
||||||
cyan: (44, 181, 233),
|
cyan: (44, 181, 233),
|
||||||
white: (204, 204, 204)
|
white: (204, 204, 204),
|
||||||
},
|
},
|
||||||
|
|
||||||
pty_proj: PtyView::new(
|
_pty_proj: PtyView::new(
|
||||||
buf_port.outer(),
|
buf_port.outer(),
|
||||||
cursor_port.outer().map(|x| Some(x)),
|
cursor_port.outer().map(|x| Some(x)),
|
||||||
offset_port.outer().map(|x| Some(x)),
|
offset_port.outer().map(|x| Some(x)),
|
||||||
size_port.outer().map(|x| Some(x)),
|
size_port.outer().map(|x| Some(x)),
|
||||||
|
port,
|
||||||
port
|
),
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut buf = [0; 2048];
|
let mut buf = [0; 2048];
|
||||||
|
@ -78,11 +65,11 @@ pub fn read_ansi_from<R: Read + Unpin>(ansi_reader: &mut R, max_size: Vector2<i1
|
||||||
for byte in &buf[..n] {
|
for byte in &buf[..n] {
|
||||||
statemachine.advance(&mut performer, *byte);
|
statemachine.advance(&mut performer, *byte);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Err(err) => {
|
Err(_err) => {
|
||||||
//println!("err: {}", err);
|
//println!("err: {}", err);
|
||||||
break;
|
break;
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,14 +80,22 @@ enum TTYColor {
|
||||||
Rgb(u8, u8, u8),
|
Rgb(u8, u8, u8),
|
||||||
|
|
||||||
// 3-Bit/4-Bit colors
|
// 3-Bit/4-Bit colors
|
||||||
Black, LightBlack,
|
Black,
|
||||||
Red, LightRed,
|
LightBlack,
|
||||||
Green, LightGreen,
|
Red,
|
||||||
Yellow, LightYellow,
|
LightRed,
|
||||||
Blue, LightBlue,
|
Green,
|
||||||
Magenta,LightMagenta,
|
LightGreen,
|
||||||
Cyan, LightCyan,
|
Yellow,
|
||||||
White, LightWhite,
|
LightYellow,
|
||||||
|
Blue,
|
||||||
|
LightBlue,
|
||||||
|
Magenta,
|
||||||
|
LightMagenta,
|
||||||
|
Cyan,
|
||||||
|
LightCyan,
|
||||||
|
White,
|
||||||
|
LightWhite,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ColorPalett {
|
struct ColorPalett {
|
||||||
|
@ -117,7 +112,7 @@ struct ColorPalett {
|
||||||
impl ColorPalett {
|
impl ColorPalett {
|
||||||
fn get_rgb(&self, col: &TTYColor) -> (u8, u8, u8) {
|
fn get_rgb(&self, col: &TTYColor) -> (u8, u8, u8) {
|
||||||
match col {
|
match col {
|
||||||
TTYColor::Rgb(r,g,b) => (*r,*g,*b),
|
TTYColor::Rgb(r, g, b) => (*r, *g, *b),
|
||||||
TTYColor::Black | TTYColor::LightBlack => self.black,
|
TTYColor::Black | TTYColor::LightBlack => self.black,
|
||||||
TTYColor::Red | TTYColor::LightRed => self.red,
|
TTYColor::Red | TTYColor::LightRed => self.red,
|
||||||
TTYColor::Green | TTYColor::LightGreen => self.green,
|
TTYColor::Green | TTYColor::LightGreen => self.green,
|
||||||
|
@ -146,7 +141,7 @@ struct PtyView {
|
||||||
max_pt: Point2<i16>,
|
max_pt: Point2<i16>,
|
||||||
|
|
||||||
cast: Arc<RwLock<ObserverBroadcast<dyn TerminalView>>>,
|
cast: Arc<RwLock<ObserverBroadcast<dyn TerminalView>>>,
|
||||||
proj_helper: ProjectionHelper<usize, Self>
|
proj_helper: ProjectionHelper<usize, Self>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl View for PtyView {
|
impl View for PtyView {
|
||||||
|
@ -160,13 +155,16 @@ impl IndexView<Point2<i16>> for PtyView {
|
||||||
let atom = self.buf.get(&(pt + self.old_offset));
|
let atom = self.buf.get(&(pt + self.old_offset));
|
||||||
if self.old_curpos == *pt {
|
if self.old_curpos == *pt {
|
||||||
if let Some(mut a) = atom {
|
if let Some(mut a) = atom {
|
||||||
let bg_col = a.style.fg_color.unwrap_or((255,255,255));
|
let bg_col = a.style.fg_color.unwrap_or((255, 255, 255));
|
||||||
let fg_col = a.style.bg_color.unwrap_or((0,0,0));
|
let fg_col = a.style.bg_color.unwrap_or((0, 0, 0));
|
||||||
a.style.fg_color = Some(fg_col);
|
a.style.fg_color = Some(fg_col);
|
||||||
a.style.bg_color = Some(bg_col);
|
a.style.bg_color = Some(bg_col);
|
||||||
Some(a)
|
Some(a)
|
||||||
} else {
|
} else {
|
||||||
Some(TerminalAtom::new(' ', TerminalStyle::bg_color((255, 255, 255))))
|
Some(TerminalAtom::new(
|
||||||
|
' ',
|
||||||
|
TerminalStyle::bg_color((255, 255, 255)),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
atom
|
atom
|
||||||
|
@ -174,10 +172,13 @@ impl IndexView<Point2<i16>> for PtyView {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn area(&self) -> IndexArea<Point2<i16>> {
|
fn area(&self) -> IndexArea<Point2<i16>> {
|
||||||
IndexArea::Range(Point2::new(0, 0) ..= Point2::new(
|
IndexArea::Range(
|
||||||
std::cmp::max(self.old_curpos.x, self.max_pt.x),
|
Point2::new(0, 0)
|
||||||
std::cmp::max(self.old_curpos.y, self.max_pt.y)
|
..=Point2::new(
|
||||||
))
|
std::cmp::max(self.old_curpos.x, self.max_pt.x),
|
||||||
|
std::cmp::max(self.old_curpos.y, self.max_pt.y),
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,85 +189,67 @@ impl PtyView {
|
||||||
offset_port: OuterViewPort<dyn SingletonView<Item = Option<Vector2<i16>>>>,
|
offset_port: OuterViewPort<dyn SingletonView<Item = Option<Vector2<i16>>>>,
|
||||||
size_port: OuterViewPort<dyn SingletonView<Item = Option<Vector2<i16>>>>,
|
size_port: OuterViewPort<dyn SingletonView<Item = Option<Vector2<i16>>>>,
|
||||||
|
|
||||||
out_port: InnerViewPort<dyn TerminalView>
|
out_port: InnerViewPort<dyn TerminalView>,
|
||||||
) -> Arc<RwLock<Self>> {
|
) -> Arc<RwLock<Self>> {
|
||||||
let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone());
|
let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone());
|
||||||
let proj = Arc::new(RwLock::new(
|
let proj = Arc::new(RwLock::new(PtyView {
|
||||||
PtyView {
|
old_curpos: Point2::new(0, 0),
|
||||||
old_curpos: Point2::new(0, 0),
|
old_size: Vector2::new(0, 0),
|
||||||
old_size: Vector2::new(0, 0),
|
old_offset: Vector2::new(0, 0),
|
||||||
old_offset: Vector2::new(0, 0),
|
max_pt: Point2::new(0, 0),
|
||||||
max_pt: Point2::new(0, 0),
|
|
||||||
|
|
||||||
curpos: proj_helper.new_singleton_arg(
|
curpos: proj_helper.new_singleton_arg(0, curpos_port, |s: &mut Self, _msg| {
|
||||||
0,
|
s.cast.notify(&IndexArea::Set(vec![s.old_curpos]));
|
||||||
curpos_port,
|
s.old_curpos = s.curpos.get().unwrap_or(Point2::new(0, 0));
|
||||||
|s: &mut Self, _msg| {
|
s.cast.notify(&IndexArea::Set(vec![s.old_curpos]));
|
||||||
s.cast.notify(&IndexArea::Set(vec![ s.old_curpos ]));
|
}),
|
||||||
s.old_curpos = s.curpos.get().unwrap_or(Point2::new(0,0));
|
|
||||||
s.cast.notify(&IndexArea::Set(vec![ s.old_curpos ]));
|
|
||||||
}),
|
|
||||||
|
|
||||||
offset: proj_helper.new_singleton_arg(
|
offset: proj_helper.new_singleton_arg(1, offset_port, |s: &mut Self, _msg| {
|
||||||
1,
|
// todo
|
||||||
offset_port,
|
let new_offset = s.offset.get().unwrap_or(Vector2::new(0, 0));
|
||||||
|s: &mut Self, _msg| {
|
if s.old_offset != new_offset {
|
||||||
// todo
|
s.old_offset = new_offset;
|
||||||
let new_offset = s.offset.get().unwrap_or(Vector2::new(0, 0));
|
s.cast.notify(&s.area());
|
||||||
if s.old_offset != new_offset {
|
|
||||||
s.old_offset = new_offset;
|
|
||||||
s.cast.notify(&s.area());
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
size: proj_helper.new_singleton_arg(
|
|
||||||
2,
|
|
||||||
size_port,
|
|
||||||
|s: &mut Self, _msg| {
|
|
||||||
let new_size = s.size.get().unwrap_or(Vector2::new(0, 0));
|
|
||||||
if s.old_size != new_size {
|
|
||||||
s.old_size = new_size;
|
|
||||||
s.cast.notify(&s.area());
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
buf: proj_helper.new_index_arg(
|
|
||||||
3,
|
|
||||||
buf_port,
|
|
||||||
|s: &mut Self, area| {
|
|
||||||
let size = s.old_size;
|
|
||||||
let area = area.map(
|
|
||||||
|pt| {
|
|
||||||
*pt - s.old_offset
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if s.max_pt.x < size.x || s.max_pt.y < size.y {
|
|
||||||
match &area {
|
|
||||||
IndexArea::Empty => {}
|
|
||||||
IndexArea::Full => {}
|
|
||||||
IndexArea::Range(_) => {}
|
|
||||||
IndexArea::Set(v) => {
|
|
||||||
let mx = v.iter().map(|pt| pt.x).max().unwrap_or(0);
|
|
||||||
if mx > s.max_pt.x && mx < size.x {
|
|
||||||
s.max_pt.x = mx;
|
|
||||||
}
|
|
||||||
|
|
||||||
let my = v.iter().map(|pt| pt.y).max().unwrap_or(0);
|
|
||||||
if my > s.max_pt.y && my < size.y {
|
|
||||||
s.max_pt.y = my;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s.cast.notify(&area);
|
|
||||||
}),
|
|
||||||
|
|
||||||
cast: out_port.get_broadcast(),
|
|
||||||
proj_helper
|
|
||||||
}
|
}
|
||||||
));
|
}),
|
||||||
|
|
||||||
|
size: proj_helper.new_singleton_arg(2, size_port, |s: &mut Self, _msg| {
|
||||||
|
let new_size = s.size.get().unwrap_or(Vector2::new(0, 0));
|
||||||
|
if s.old_size != new_size {
|
||||||
|
s.old_size = new_size;
|
||||||
|
s.cast.notify(&s.area());
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
buf: proj_helper.new_index_arg(3, buf_port, |s: &mut Self, area| {
|
||||||
|
let size = s.old_size;
|
||||||
|
let area = area.map(|pt| *pt - s.old_offset);
|
||||||
|
|
||||||
|
if s.max_pt.x < size.x || s.max_pt.y < size.y {
|
||||||
|
match &area {
|
||||||
|
IndexArea::Empty => {}
|
||||||
|
IndexArea::Full => {}
|
||||||
|
IndexArea::Range(_) => {}
|
||||||
|
IndexArea::Set(v) => {
|
||||||
|
let mx = v.iter().map(|pt| pt.x).max().unwrap_or(0);
|
||||||
|
if mx > s.max_pt.x && mx < size.x {
|
||||||
|
s.max_pt.x = mx;
|
||||||
|
}
|
||||||
|
|
||||||
|
let my = v.iter().map(|pt| pt.y).max().unwrap_or(0);
|
||||||
|
if my > s.max_pt.y && my < size.y {
|
||||||
|
s.max_pt.y = my;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s.cast.notify(&area);
|
||||||
|
}),
|
||||||
|
|
||||||
|
cast: out_port.get_broadcast(),
|
||||||
|
proj_helper,
|
||||||
|
}));
|
||||||
|
|
||||||
proj.write().unwrap().proj_helper.set_proj(&proj);
|
proj.write().unwrap().proj_helper.set_proj(&proj);
|
||||||
out_port.set_view(Some(proj.clone()));
|
out_port.set_view(Some(proj.clone()));
|
||||||
|
@ -288,12 +271,12 @@ struct PerfAtom {
|
||||||
|
|
||||||
colors: ColorPalett,
|
colors: ColorPalett,
|
||||||
|
|
||||||
pty_proj: Arc<RwLock<PtyView>>
|
_pty_proj: Arc<RwLock<PtyView>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PerfAtom {
|
impl PerfAtom {
|
||||||
fn write_atom(&mut self, pos: Point2<i16>, atom: Option<TerminalAtom>) {
|
fn write_atom(&mut self, pos: Point2<i16>, atom: Option<TerminalAtom>) {
|
||||||
if let Some(mut a) = atom {
|
if let Some(a) = atom {
|
||||||
self.buf.insert(pos + self.offset.get(), a);
|
self.buf.insert(pos + self.offset.get(), a);
|
||||||
} else {
|
} else {
|
||||||
self.buf.remove(pos);
|
self.buf.remove(pos);
|
||||||
|
@ -310,11 +293,15 @@ impl PerfAtom {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_fg_color(&mut self, col: &TTYColor) {
|
fn set_fg_color(&mut self, col: &TTYColor) {
|
||||||
self.cursty = self.cursty.add(TerminalStyle::fg_color(self.colors.get_rgb(col)));
|
self.cursty = self
|
||||||
|
.cursty
|
||||||
|
.add(TerminalStyle::fg_color(self.colors.get_rgb(col)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_bg_color(&mut self, col: &TTYColor) {
|
fn set_bg_color(&mut self, col: &TTYColor) {
|
||||||
self.cursty = self.cursty.add(TerminalStyle::bg_color(self.colors.get_rgb(col)));
|
self.cursty = self
|
||||||
|
.cursty
|
||||||
|
.add(TerminalStyle::bg_color(self.colors.get_rgb(col)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn linefeed(&mut self) {
|
fn linefeed(&mut self) {
|
||||||
|
@ -322,7 +309,7 @@ impl PerfAtom {
|
||||||
let mut c = self.cursor.get_mut();
|
let mut c = self.cursor.get_mut();
|
||||||
c.x = 0;
|
c.x = 0;
|
||||||
|
|
||||||
if c.y+1 >= size.y {
|
if c.y + 1 >= size.y {
|
||||||
self.scroll_up(1);
|
self.scroll_up(1);
|
||||||
} else {
|
} else {
|
||||||
c.y += 1;
|
c.y += 1;
|
||||||
|
@ -365,14 +352,14 @@ impl PerfAtom {
|
||||||
c.y += n as i16;
|
c.y += n as i16;
|
||||||
} else {
|
} else {
|
||||||
let r = (n as i16) - (s.y - 1 - c.y);
|
let r = (n as i16) - (s.y - 1 - c.y);
|
||||||
c.y = s.y-1;
|
c.y = s.y - 1;
|
||||||
self.scroll_up(r as usize);
|
self.scroll_up(r as usize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cursor_pxev(&mut self, n: usize) {
|
fn cursor_pxev(&mut self, n: usize) {
|
||||||
let mut c = self.cursor.get_mut();
|
let mut c = self.cursor.get_mut();
|
||||||
let s = self.size.get();
|
let _s = self.size.get();
|
||||||
|
|
||||||
if c.y - (n as i16) >= 0 {
|
if c.y - (n as i16) >= 0 {
|
||||||
c.y -= n as i16;
|
c.y -= n as i16;
|
||||||
|
@ -392,7 +379,7 @@ impl PerfAtom {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_blank_lines(&mut self, n: usize) {
|
fn insert_blank_lines(&mut self, _n: usize) {
|
||||||
//eprintln!("insert blank lines");
|
//eprintln!("insert blank lines");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,7 +424,7 @@ impl Perform for PerfAtom {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hook(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) {
|
fn hook(&mut self, _params: &Params, _intermediates: &[u8], _ignore: bool, _c: char) {
|
||||||
/*
|
/*
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[hook] params={:?}, intermediates={:?}, ignore={:?}, char={:?}",
|
"[hook] params={:?}, intermediates={:?}, ignore={:?}, char={:?}",
|
||||||
|
@ -446,7 +433,7 @@ impl Perform for PerfAtom {
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
fn put(&mut self, byte: u8) {
|
fn put(&mut self, _byte: u8) {
|
||||||
/*
|
/*
|
||||||
eprintln!("[put] {:02x}", byte);
|
eprintln!("[put] {:02x}", byte);
|
||||||
*/
|
*/
|
||||||
|
@ -456,7 +443,7 @@ impl Perform for PerfAtom {
|
||||||
//eprintln!("[unhook]");
|
//eprintln!("[unhook]");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) {
|
fn osc_dispatch(&mut self, params: &[&[u8]], _bell_terminated: bool) {
|
||||||
//eprintln!("[osc_dispatch] params={:?} bell_terminated={}", params, bell_terminated);
|
//eprintln!("[osc_dispatch] params={:?} bell_terminated={}", params, bell_terminated);
|
||||||
|
|
||||||
match params[0] {
|
match params[0] {
|
||||||
|
@ -465,97 +452,99 @@ impl Perform for PerfAtom {
|
||||||
// Reset background color
|
// Reset background color
|
||||||
b"111" => self.set_bg_color(&TTYColor::Black),
|
b"111" => self.set_bg_color(&TTYColor::Black),
|
||||||
// Reset text cursor color
|
// Reset text cursor color
|
||||||
b"112" => {},
|
b"112" => {}
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn csi_dispatch(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) {
|
fn csi_dispatch(&mut self, params: &Params, _intermediates: &[u8], _ignore: bool, c: char) {
|
||||||
let mut piter = params.into_iter();
|
let mut piter = params.into_iter();
|
||||||
match c {
|
match c {
|
||||||
// Set SGR
|
// Set SGR
|
||||||
'm' => while let Some(n) = piter.next() {
|
'm' => {
|
||||||
match n[0] {
|
while let Some(n) = piter.next() {
|
||||||
0 => {
|
match n[0] {
|
||||||
self.cursty = TerminalStyle::default();
|
0 => {
|
||||||
self.curinv = false;
|
self.cursty = TerminalStyle::default();
|
||||||
|
self.curinv = false;
|
||||||
|
}
|
||||||
|
1 => self.cursty = self.cursty.add(TerminalStyle::bold(true)),
|
||||||
|
3 => self.cursty = self.cursty.add(TerminalStyle::italic(true)),
|
||||||
|
4 => self.cursty = self.cursty.add(TerminalStyle::underline(true)),
|
||||||
|
7 => self.curinv = true,
|
||||||
|
27 => self.curinv = false,
|
||||||
|
|
||||||
|
30 => self.set_fg_color(&TTYColor::Black),
|
||||||
|
40 => self.set_bg_color(&TTYColor::Black),
|
||||||
|
90 => self.set_fg_color(&TTYColor::LightBlack),
|
||||||
|
100 => self.set_bg_color(&TTYColor::LightBlack),
|
||||||
|
31 => self.set_fg_color(&TTYColor::Red),
|
||||||
|
41 => self.set_bg_color(&TTYColor::Red),
|
||||||
|
91 => self.set_fg_color(&TTYColor::LightRed),
|
||||||
|
101 => self.set_bg_color(&TTYColor::LightRed),
|
||||||
|
32 => self.set_fg_color(&TTYColor::Green),
|
||||||
|
42 => self.set_bg_color(&TTYColor::Green),
|
||||||
|
92 => self.set_fg_color(&TTYColor::LightGreen),
|
||||||
|
102 => self.set_bg_color(&TTYColor::LightGreen),
|
||||||
|
33 => self.set_fg_color(&TTYColor::Yellow),
|
||||||
|
43 => self.set_bg_color(&TTYColor::Yellow),
|
||||||
|
93 => self.set_fg_color(&TTYColor::LightYellow),
|
||||||
|
103 => self.set_bg_color(&TTYColor::LightYellow),
|
||||||
|
34 => self.set_fg_color(&TTYColor::Blue),
|
||||||
|
44 => self.set_bg_color(&TTYColor::Blue),
|
||||||
|
94 => self.set_fg_color(&TTYColor::LightBlue),
|
||||||
|
104 => self.set_bg_color(&TTYColor::LightBlue),
|
||||||
|
35 => self.set_fg_color(&TTYColor::Magenta),
|
||||||
|
45 => self.set_bg_color(&TTYColor::Magenta),
|
||||||
|
95 => self.set_fg_color(&TTYColor::LightMagenta),
|
||||||
|
105 => self.set_bg_color(&TTYColor::LightMagenta),
|
||||||
|
36 => self.set_fg_color(&TTYColor::Cyan),
|
||||||
|
46 => self.set_bg_color(&TTYColor::Cyan),
|
||||||
|
96 => self.set_fg_color(&TTYColor::LightCyan),
|
||||||
|
106 => self.set_bg_color(&TTYColor::LightCyan),
|
||||||
|
37 => self.set_fg_color(&TTYColor::White),
|
||||||
|
47 => self.set_bg_color(&TTYColor::White),
|
||||||
|
97 => self.set_fg_color(&TTYColor::LightWhite),
|
||||||
|
107 => self.set_bg_color(&TTYColor::LightWhite),
|
||||||
|
|
||||||
|
38 => {
|
||||||
|
let x = piter.next().unwrap();
|
||||||
|
match x[0] {
|
||||||
|
2 => {
|
||||||
|
let r = piter.next().unwrap()[0] as u8;
|
||||||
|
let g = piter.next().unwrap()[0] as u8;
|
||||||
|
let b = piter.next().unwrap()[0] as u8;
|
||||||
|
self.set_fg_color(&TTYColor::Rgb(r, g, b));
|
||||||
|
}
|
||||||
|
5 => {
|
||||||
|
let v = piter.next().unwrap();
|
||||||
|
let rgb = ansi_colours::rgb_from_ansi256(v[0] as u8);
|
||||||
|
self.set_fg_color(&TTYColor::Rgb(rgb.0, rgb.1, rgb.2));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
48 => {
|
||||||
|
let x = piter.next().unwrap();
|
||||||
|
match x[0] {
|
||||||
|
2 => {
|
||||||
|
let r = piter.next().unwrap()[0] as u8;
|
||||||
|
let g = piter.next().unwrap()[0] as u8;
|
||||||
|
let b = piter.next().unwrap()[0] as u8;
|
||||||
|
self.set_bg_color(&TTYColor::Rgb(r, g, b));
|
||||||
|
}
|
||||||
|
5 => {
|
||||||
|
let v = piter.next().unwrap();
|
||||||
|
let rgb = ansi_colours::rgb_from_ansi256(v[0] as u8);
|
||||||
|
self.set_bg_color(&TTYColor::Rgb(rgb.0, rgb.1, rgb.2));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
1 => self.cursty = self.cursty.add(TerminalStyle::bold(true)),
|
|
||||||
3 => self.cursty = self.cursty.add(TerminalStyle::italic(true)),
|
|
||||||
4 => self.cursty = self.cursty.add(TerminalStyle::underline(true)),
|
|
||||||
7 => self.curinv = true,
|
|
||||||
27 => self.curinv = false,
|
|
||||||
|
|
||||||
30 => self.set_fg_color(&TTYColor::Black),
|
|
||||||
40 => self.set_bg_color(&TTYColor::Black),
|
|
||||||
90 => self.set_fg_color(&TTYColor::LightBlack),
|
|
||||||
100 => self.set_bg_color(&TTYColor::LightBlack),
|
|
||||||
31 => self.set_fg_color(&TTYColor::Red),
|
|
||||||
41 => self.set_bg_color(&TTYColor::Red),
|
|
||||||
91 => self.set_fg_color(&TTYColor::LightRed),
|
|
||||||
101 => self.set_bg_color(&TTYColor::LightRed),
|
|
||||||
32 => self.set_fg_color(&TTYColor::Green),
|
|
||||||
42 => self.set_bg_color(&TTYColor::Green),
|
|
||||||
92 => self.set_fg_color(&TTYColor::LightGreen),
|
|
||||||
102 => self.set_bg_color(&TTYColor::LightGreen),
|
|
||||||
33 => self.set_fg_color(&TTYColor::Yellow),
|
|
||||||
43 => self.set_bg_color(&TTYColor::Yellow),
|
|
||||||
93 => self.set_fg_color(&TTYColor::LightYellow),
|
|
||||||
103 => self.set_bg_color(&TTYColor::LightYellow),
|
|
||||||
34 => self.set_fg_color(&TTYColor::Blue),
|
|
||||||
44 => self.set_bg_color(&TTYColor::Blue),
|
|
||||||
94 => self.set_fg_color(&TTYColor::LightBlue),
|
|
||||||
104 => self.set_bg_color(&TTYColor::LightBlue),
|
|
||||||
35 => self.set_fg_color(&TTYColor::Magenta),
|
|
||||||
45 => self.set_bg_color(&TTYColor::Magenta),
|
|
||||||
95 => self.set_fg_color(&TTYColor::LightMagenta),
|
|
||||||
105 => self.set_bg_color(&TTYColor::LightMagenta),
|
|
||||||
36 => self.set_fg_color(&TTYColor::Cyan),
|
|
||||||
46 => self.set_bg_color(&TTYColor::Cyan),
|
|
||||||
96 => self.set_fg_color(&TTYColor::LightCyan),
|
|
||||||
106 => self.set_bg_color(&TTYColor::LightCyan),
|
|
||||||
37 => self.set_fg_color(&TTYColor::White),
|
|
||||||
47 => self.set_bg_color(&TTYColor::White),
|
|
||||||
97 => self.set_fg_color(&TTYColor::LightWhite),
|
|
||||||
107 => self.set_bg_color(&TTYColor::LightWhite),
|
|
||||||
|
|
||||||
38 => {
|
|
||||||
let x = piter.next().unwrap();
|
|
||||||
match x[0] {
|
|
||||||
2 => {
|
|
||||||
let r = piter.next().unwrap()[0] as u8;
|
|
||||||
let g = piter.next().unwrap()[0] as u8;
|
|
||||||
let b = piter.next().unwrap()[0] as u8;
|
|
||||||
self.set_fg_color(&TTYColor::Rgb(r,g,b));
|
|
||||||
},
|
|
||||||
5 => {
|
|
||||||
let v = piter.next().unwrap();
|
|
||||||
let rgb = ansi_colours::rgb_from_ansi256(v[0] as u8);
|
|
||||||
self.set_fg_color(&TTYColor::Rgb(rgb.0, rgb.1, rgb.2));
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
48 => {
|
|
||||||
let x = piter.next().unwrap();
|
|
||||||
match x[0] {
|
|
||||||
2 => {
|
|
||||||
let r = piter.next().unwrap()[0] as u8;
|
|
||||||
let g = piter.next().unwrap()[0] as u8;
|
|
||||||
let b = piter.next().unwrap()[0] as u8;
|
|
||||||
self.set_bg_color(&TTYColor::Rgb(r,g,b));
|
|
||||||
},
|
|
||||||
5 => {
|
|
||||||
let v = piter.next().unwrap();
|
|
||||||
let rgb = ansi_colours::rgb_from_ansi256(v[0] as u8);
|
|
||||||
self.set_bg_color(&TTYColor::Rgb(rgb.0, rgb.1, rgb.2));
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'@' => {
|
'@' => {
|
||||||
|
@ -564,8 +553,12 @@ impl Perform for PerfAtom {
|
||||||
self.print(' ');
|
self.print(' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'A' => { self.cursor_up(piter.next().unwrap_or(&[1])[0] as usize); }
|
'A' => {
|
||||||
'B' => { self.cursor_dn(piter.next().unwrap_or(&[1])[0] as usize); }
|
self.cursor_up(piter.next().unwrap_or(&[1])[0] as usize);
|
||||||
|
}
|
||||||
|
'B' => {
|
||||||
|
self.cursor_dn(piter.next().unwrap_or(&[1])[0] as usize);
|
||||||
|
}
|
||||||
'C' | 'a' => {
|
'C' | 'a' => {
|
||||||
self.cursor_nexd(piter.next().unwrap_or(&[1])[0] as usize);
|
self.cursor_nexd(piter.next().unwrap_or(&[1])[0] as usize);
|
||||||
}
|
}
|
||||||
|
@ -587,7 +580,6 @@ impl Perform for PerfAtom {
|
||||||
let mut c = self.cursor.get_mut();
|
let mut c = self.cursor.get_mut();
|
||||||
c.x = 0;
|
c.x = 0;
|
||||||
c.y -= piter.next().unwrap_or(&[1])[0] as i16;
|
c.y -= piter.next().unwrap_or(&[1])[0] as i16;
|
||||||
|
|
||||||
}
|
}
|
||||||
'G' | '`' => {
|
'G' | '`' => {
|
||||||
self.cursor.get_mut().x = piter.next().unwrap_or(&[1])[0] as i16 - 1;
|
self.cursor.get_mut().x = piter.next().unwrap_or(&[1])[0] as i16 - 1;
|
||||||
|
@ -600,7 +592,6 @@ impl Perform for PerfAtom {
|
||||||
'J' => {
|
'J' => {
|
||||||
let x = piter.next().unwrap_or(&[0 as u16; 1]);
|
let x = piter.next().unwrap_or(&[0 as u16; 1]);
|
||||||
match x[0] {
|
match x[0] {
|
||||||
|
|
||||||
// clear from cursor until end of screen
|
// clear from cursor until end of screen
|
||||||
0 => {
|
0 => {
|
||||||
let mut pos = self.cursor.get();
|
let mut pos = self.cursor.get();
|
||||||
|
@ -613,7 +604,7 @@ impl Perform for PerfAtom {
|
||||||
pos.y += 1;
|
pos.y += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
// clear from cursor to begin
|
// clear from cursor to begin
|
||||||
1 => {
|
1 => {
|
||||||
|
@ -633,8 +624,8 @@ impl Perform for PerfAtom {
|
||||||
|
|
||||||
// erase entire screen
|
// erase entire screen
|
||||||
2 => {
|
2 => {
|
||||||
for y in 0 .. 100 {
|
for y in 0..100 {
|
||||||
for x in 0 .. self.size.get().x {
|
for x in 0..self.size.get().x {
|
||||||
self.write_atom(Point2::new(x, y), None);
|
self.write_atom(Point2::new(x, y), None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -649,30 +640,38 @@ impl Perform for PerfAtom {
|
||||||
'K' => {
|
'K' => {
|
||||||
let x = piter.next().unwrap_or(&[0]);
|
let x = piter.next().unwrap_or(&[0]);
|
||||||
match x[0] {
|
match x[0] {
|
||||||
|
|
||||||
// clear from cursor until end of line
|
// clear from cursor until end of line
|
||||||
0 => {
|
0 => {
|
||||||
let c = self.cursor.get();
|
let c = self.cursor.get();
|
||||||
for x in c.x .. self.size.get().x {
|
for x in c.x..self.size.get().x {
|
||||||
self.write_atom(Point2::new(x, c.y), Some(TerminalAtom::new(' ', self.get_style())));
|
self.write_atom(
|
||||||
|
Point2::new(x, c.y),
|
||||||
|
Some(TerminalAtom::new(' ', self.get_style())),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
// clear from start of line until cursor
|
// clear from start of line until cursor
|
||||||
1 => {
|
1 => {
|
||||||
let c = self.cursor.get();
|
let c = self.cursor.get();
|
||||||
for x in 0 .. c.x {
|
for x in 0..c.x {
|
||||||
self.write_atom(Point2::new(x, c.y), Some(TerminalAtom::new(' ', self.get_style())));
|
self.write_atom(
|
||||||
|
Point2::new(x, c.y),
|
||||||
|
Some(TerminalAtom::new(' ', self.get_style())),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
// clear entire line
|
// clear entire line
|
||||||
2 => {
|
2 => {
|
||||||
let c = self.cursor.get();
|
let c = self.cursor.get();
|
||||||
for x in 0 .. self.size.get().x {
|
for x in 0..self.size.get().x {
|
||||||
self.write_atom(Point2::new(x, c.y), Some(TerminalAtom::new(' ', self.get_style())));
|
self.write_atom(
|
||||||
|
Point2::new(x, c.y),
|
||||||
|
Some(TerminalAtom::new(' ', self.get_style())),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
// invalid
|
// invalid
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -685,80 +684,89 @@ impl Perform for PerfAtom {
|
||||||
'M' => {
|
'M' => {
|
||||||
//eprintln!("delete lines");
|
//eprintln!("delete lines");
|
||||||
/*
|
/*
|
||||||
let n = piter.next().unwrap_or(&[1])[0] as i16;
|
let n = piter.next().unwrap_or(&[1])[0] as i16;
|
||||||
for y in 0 .. n {
|
for y in 0 .. n {
|
||||||
for x in 0 .. self.size.get().x {
|
for x in 0 .. self.size.get().x {
|
||||||
self.write_atom(Point2::new(x, self.cursor.y+y), None);
|
self.write_atom(Point2::new(x, self.cursor.y+y), None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
'P' => {
|
'P' => {
|
||||||
for x in 0 .. piter.next().unwrap_or(&[1])[0] {
|
for x in 0 .. piter.next().unwrap_or(&[1])[0] {
|
||||||
self.backspace();
|
self.backspace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
'X' => {
|
'X' => {
|
||||||
//eprintln!("delete chars");
|
//eprintln!("delete chars");
|
||||||
let c = self.cursor.get();
|
let c = self.cursor.get();
|
||||||
for x in 0 .. piter.next().unwrap_or(&[1])[0] {
|
for x in 0..piter.next().unwrap_or(&[1])[0] {
|
||||||
self.write_atom(Point2::new(c.x + x as i16, c.y), Some(TerminalAtom::new(' ', self.get_style())));
|
self.write_atom(
|
||||||
|
Point2::new(c.x + x as i16, c.y),
|
||||||
|
Some(TerminalAtom::new(' ', self.get_style())),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
'S' => { self.scroll_up(piter.next().unwrap_or(&[1])[0] as usize); }
|
'S' => {
|
||||||
'T' => { self.scroll_dn(piter.next().unwrap_or(&[1])[0] as usize); }
|
self.scroll_up(piter.next().unwrap_or(&[1])[0] as usize);
|
||||||
's' => { self.save_cursor_position(); }
|
}
|
||||||
'u' => { self.restore_cursor_position(); }
|
'T' => {
|
||||||
|
self.scroll_dn(piter.next().unwrap_or(&[1])[0] as usize);
|
||||||
|
}
|
||||||
|
's' => {
|
||||||
|
self.save_cursor_position();
|
||||||
|
}
|
||||||
|
'u' => {
|
||||||
|
self.restore_cursor_position();
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
/*
|
/*
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[csi_dispatch] params={:#?}, intermediates={:?}, ignore={:?}, char={:?}",
|
"[csi_dispatch] params={:#?}, intermediates={:?}, ignore={:?}, char={:?}",
|
||||||
params, intermediates, ignore, c
|
params, intermediates, ignore, c
|
||||||
);
|
);
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) {
|
fn esc_dispatch(&mut self, intermediates: &[u8], _ignore: bool, byte: u8) {
|
||||||
match (byte, intermediates) {
|
match (byte, intermediates) {
|
||||||
//(b'B', intermediates) => configure_charset!(StandardCharset::Ascii, intermediates),
|
//(b'B', intermediates) => configure_charset!(StandardCharset::Ascii, intermediates),
|
||||||
(b'D', []) => self.linefeed(),
|
(b'D', []) => self.linefeed(),
|
||||||
(b'E', []) => {
|
(b'E', []) => {
|
||||||
self.linefeed();
|
self.linefeed();
|
||||||
self.carriage_return();
|
self.carriage_return();
|
||||||
},
|
}
|
||||||
/*
|
/*
|
||||||
(b'H', []) => self.handler.set_horizontal_tabstop(),
|
(b'H', []) => self.handler.set_horizontal_tabstop(),
|
||||||
(b'M', []) => self.handler.reverse_index(),
|
(b'M', []) => self.handler.reverse_index(),
|
||||||
(b'Z', []) => self.handler.identify_terminal(None),
|
(b'Z', []) => self.handler.identify_terminal(None),
|
||||||
(b'c', []) => self.handler.reset_state(),
|
(b'c', []) => self.handler.reset_state(),
|
||||||
(b'0', intermediates) => {
|
(b'0', intermediates) => {
|
||||||
configure_charset!(StandardCharset::SpecialCharacterAndLineDrawing, intermediates)
|
configure_charset!(StandardCharset::SpecialCharacterAndLineDrawing, intermediates)
|
||||||
},
|
},
|
||||||
*/
|
*/
|
||||||
(b'7', []) => self.save_cursor_position(),
|
(b'7', []) => self.save_cursor_position(),
|
||||||
//(b'8', [b'#']) => self.handler.decaln(),
|
//(b'8', [b'#']) => self.handler.decaln(),
|
||||||
(b'8', []) => self.restore_cursor_position(),
|
(b'8', []) => self.restore_cursor_position(),
|
||||||
/*
|
/*
|
||||||
(b'=', []) => self.handler.set_keypad_application_mode(),
|
(b'=', []) => self.handler.set_keypad_application_mode(),
|
||||||
(b'>', []) => self.handler.unset_keypad_application_mode(),
|
(b'>', []) => self.handler.unset_keypad_application_mode(),
|
||||||
**/
|
**/
|
||||||
// String terminator, do nothing (parser handles as string terminator).
|
// String terminator, do nothing (parser handles as string terminator).
|
||||||
(b'\\', []) => (),
|
(b'\\', []) => (),
|
||||||
_ => {
|
_ => {
|
||||||
/*
|
/*
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"unhandled esc_dispatch intermediates={:?}, ignore={:?}, byte={:02x}",
|
"unhandled esc_dispatch intermediates={:?}, ignore={:?}, byte={:02x}",
|
||||||
intermediates, ignore, byte
|
intermediates, ignore, byte
|
||||||
);
|
);
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use {
|
use {
|
||||||
super::TerminalStyle,
|
super::TerminalStyle,
|
||||||
serde::{Serialize, Deserialize}
|
serde::{Deserialize, Serialize},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
|
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
|
||||||
pub struct TerminalAtom {
|
pub struct TerminalAtom {
|
||||||
pub c: Option<char>,
|
pub c: Option<char>,
|
||||||
pub style: TerminalStyle
|
pub style: TerminalStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TerminalAtom {
|
impl TerminalAtom {
|
||||||
|
@ -15,7 +15,10 @@ impl TerminalAtom {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_bg(bg_color: (u8, u8, u8)) -> Self {
|
pub fn new_bg(bg_color: (u8, u8, u8)) -> Self {
|
||||||
TerminalAtom { c: None, style: TerminalStyle::bg_color(bg_color) }
|
TerminalAtom {
|
||||||
|
c: None,
|
||||||
|
style: TerminalStyle::bg_color(bg_color),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_style_front(mut self, style: TerminalStyle) -> Self {
|
pub fn add_style_front(mut self, style: TerminalStyle) -> Self {
|
||||||
|
@ -33,7 +36,7 @@ impl From<char> for TerminalAtom {
|
||||||
fn from(c: char) -> Self {
|
fn from(c: char) -> Self {
|
||||||
TerminalAtom {
|
TerminalAtom {
|
||||||
c: Some(c),
|
c: Some(c),
|
||||||
style: TerminalStyle::default()
|
style: TerminalStyle::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +45,7 @@ impl From<Option<char>> for TerminalAtom {
|
||||||
fn from(c: Option<char>) -> Self {
|
fn from(c: Option<char>) -> Self {
|
||||||
TerminalAtom {
|
TerminalAtom {
|
||||||
c,
|
c,
|
||||||
style: TerminalStyle::default()
|
style: TerminalStyle::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,8 +54,7 @@ impl From<&char> for TerminalAtom {
|
||||||
fn from(c: &char) -> Self {
|
fn from(c: &char) -> Self {
|
||||||
TerminalAtom {
|
TerminalAtom {
|
||||||
c: Some(*c),
|
c: Some(*c),
|
||||||
style: TerminalStyle::default()
|
style: TerminalStyle::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
use {
|
use {
|
||||||
std::{
|
|
||||||
sync::{Arc}
|
|
||||||
},
|
|
||||||
std::sync::RwLock,
|
|
||||||
cgmath::Point2,
|
|
||||||
crate::{
|
crate::{
|
||||||
core::{InnerViewPort, OuterViewPort, View, Observer, ObserverBroadcast},
|
core::{InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View},
|
||||||
index::{IndexArea, IndexView},
|
index::{IndexArea, IndexView},
|
||||||
|
projection::ProjectionHelper,
|
||||||
terminal::{TerminalAtom, TerminalView},
|
terminal::{TerminalAtom, TerminalView},
|
||||||
projection::ProjectionHelper
|
},
|
||||||
}
|
cgmath::Point2,
|
||||||
|
std::sync::Arc,
|
||||||
|
std::sync::RwLock,
|
||||||
};
|
};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
@ -17,22 +15,18 @@ use {
|
||||||
pub struct TerminalCompositor {
|
pub struct TerminalCompositor {
|
||||||
layers: Vec<Arc<dyn TerminalView>>,
|
layers: Vec<Arc<dyn TerminalView>>,
|
||||||
cast: Arc<RwLock<ObserverBroadcast<dyn TerminalView>>>,
|
cast: Arc<RwLock<ObserverBroadcast<dyn TerminalView>>>,
|
||||||
proj_helper: ProjectionHelper<usize, Self>
|
proj_helper: ProjectionHelper<usize, Self>,
|
||||||
}
|
}
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl TerminalCompositor {
|
impl TerminalCompositor {
|
||||||
pub fn new(
|
pub fn new(port: InnerViewPort<dyn TerminalView>) -> Arc<RwLock<Self>> {
|
||||||
port: InnerViewPort<dyn TerminalView>
|
let comp = Arc::new(RwLock::new(TerminalCompositor {
|
||||||
) -> Arc<RwLock<Self>> {
|
layers: Vec::new(),
|
||||||
let comp = Arc::new(RwLock::new(
|
cast: port.get_broadcast(),
|
||||||
TerminalCompositor {
|
proj_helper: ProjectionHelper::new(port.0.update_hooks.clone()),
|
||||||
layers: Vec::new(),
|
}));
|
||||||
cast: port.get_broadcast(),
|
|
||||||
proj_helper: ProjectionHelper::new(port.0.update_hooks.clone())
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
comp.write().unwrap().proj_helper.set_proj(&comp);
|
comp.write().unwrap().proj_helper.set_proj(&comp);
|
||||||
port.set_view(Some(comp.clone()));
|
port.set_view(Some(comp.clone()));
|
||||||
|
@ -43,13 +37,10 @@ impl TerminalCompositor {
|
||||||
pub fn push(&mut self, v: OuterViewPort<dyn TerminalView>) {
|
pub fn push(&mut self, v: OuterViewPort<dyn TerminalView>) {
|
||||||
let idx = self.layers.len();
|
let idx = self.layers.len();
|
||||||
self.layers.push(
|
self.layers.push(
|
||||||
self.proj_helper.new_index_arg(
|
self.proj_helper
|
||||||
idx,
|
.new_index_arg(idx, v, |s: &mut Self, area| {
|
||||||
v,
|
|
||||||
|s: &mut Self, area| {
|
|
||||||
s.cast.notify(area);
|
s.cast.notify(area);
|
||||||
}
|
}),
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,4 +78,3 @@ impl IndexView<Point2<i16>> for TerminalCompositor {
|
||||||
area
|
area
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,17 @@
|
||||||
pub mod style;
|
|
||||||
pub mod atom;
|
|
||||||
pub mod terminal;
|
|
||||||
pub mod compositor;
|
|
||||||
pub mod ansi_parser;
|
pub mod ansi_parser;
|
||||||
|
pub mod atom;
|
||||||
|
pub mod compositor;
|
||||||
|
pub mod style;
|
||||||
|
pub mod terminal;
|
||||||
|
|
||||||
pub use {
|
pub use {
|
||||||
style::{TerminalStyle},
|
atom::TerminalAtom,
|
||||||
atom::{TerminalAtom},
|
|
||||||
terminal::{Terminal, TerminalEvent},
|
|
||||||
compositor::TerminalCompositor,
|
compositor::TerminalCompositor,
|
||||||
|
style::TerminalStyle,
|
||||||
|
terminal::{Terminal, TerminalEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
use {
|
use crate::grid::GridView;
|
||||||
crate::{
|
|
||||||
grid::GridView
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
|
@ -25,7 +21,7 @@ pub trait TerminalView = GridView<Item = TerminalAtom>;
|
||||||
|
|
||||||
pub enum TerminalEditorResult {
|
pub enum TerminalEditorResult {
|
||||||
Continue,
|
Continue,
|
||||||
Exit
|
Exit,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TerminalEditor {
|
pub trait TerminalEditor {
|
||||||
|
@ -37,25 +33,25 @@ pub trait TerminalEditor {
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
core::{OuterViewPort, ViewPort},
|
||||||
vec::VecBuffer,
|
vec::VecBuffer,
|
||||||
core::{ViewPort, OuterViewPort}
|
|
||||||
},
|
},
|
||||||
cgmath::Point2
|
cgmath::Point2,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn make_label(s: &str) -> OuterViewPort<dyn TerminalView> {
|
pub fn make_label(s: &str) -> OuterViewPort<dyn TerminalView> {
|
||||||
let label_port = ViewPort::new();
|
let label_port = ViewPort::new();
|
||||||
let mut label = VecBuffer::with_data(s.chars().collect(), label_port.inner());
|
let _label = VecBuffer::with_data(s.chars().collect(), label_port.inner());
|
||||||
|
|
||||||
let v = label_port.outer()
|
let v = label_port
|
||||||
|
.outer()
|
||||||
.to_sequence()
|
.to_sequence()
|
||||||
.map(|c| TerminalAtom::from(c))
|
.map(|c| TerminalAtom::from(c))
|
||||||
.to_index()
|
.to_index()
|
||||||
.map_key(
|
.map_key(
|
||||||
|idx| Point2::new(*idx as i16, 0),
|
|idx| Point2::new(*idx as i16, 0),
|
||||||
|pt| if pt.y == 0 { Some(pt.x as usize) } else { None }
|
|pt| if pt.y == 0 { Some(pt.x as usize) } else { None },
|
||||||
);
|
);
|
||||||
|
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Default, Copy, Clone, PartialEq, Serialize, Deserialize, Debug)]
|
#[derive(Default, Copy, Clone, PartialEq, Serialize, Deserialize, Debug)]
|
||||||
pub struct TerminalStyle {
|
pub struct TerminalStyle {
|
||||||
|
@ -6,7 +6,7 @@ pub struct TerminalStyle {
|
||||||
pub bg_color: Option<(u8, u8, u8)>,
|
pub bg_color: Option<(u8, u8, u8)>,
|
||||||
pub bold: Option<bool>,
|
pub bold: Option<bool>,
|
||||||
pub italic: Option<bool>,
|
pub italic: Option<bool>,
|
||||||
pub underline: Option<bool>
|
pub underline: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TerminalStyle {
|
impl TerminalStyle {
|
||||||
|
@ -85,4 +85,3 @@ impl std::fmt::Display for TerminalStyle {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,44 +1,32 @@
|
||||||
use {
|
use {
|
||||||
std::{
|
super::{TerminalStyle, TerminalView},
|
||||||
sync::Arc,
|
|
||||||
io::{Write, stdout, stdin},
|
|
||||||
collections::HashSet
|
|
||||||
},
|
|
||||||
std::sync::RwLock,
|
|
||||||
async_std::{
|
|
||||||
stream::StreamExt,
|
|
||||||
task
|
|
||||||
},
|
|
||||||
signal_hook,
|
|
||||||
signal_hook_async_std::Signals,
|
|
||||||
cgmath::{Vector2, Point2},
|
|
||||||
termion::{
|
|
||||||
raw::IntoRawMode,
|
|
||||||
input::{TermRead, MouseTerminal}
|
|
||||||
},
|
|
||||||
crate::{
|
crate::{
|
||||||
core::{
|
core::{
|
||||||
OuterViewPort,
|
channel::{queue_channel, set_channel, ChannelReceiver, ChannelSender},
|
||||||
Observer,
|
Observer, OuterViewPort,
|
||||||
channel::{
|
|
||||||
ChannelReceiver,
|
|
||||||
ChannelSender,
|
|
||||||
queue_channel,
|
|
||||||
set_channel
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
index::{IndexArea},
|
grid::GridWindowIterator,
|
||||||
grid::{GridWindowIterator}
|
index::IndexArea,
|
||||||
},
|
},
|
||||||
super::{
|
async_std::{stream::StreamExt, task},
|
||||||
TerminalStyle,
|
cgmath::{Point2, Vector2},
|
||||||
TerminalView
|
signal_hook,
|
||||||
|
signal_hook_async_std::Signals,
|
||||||
|
std::sync::RwLock,
|
||||||
|
std::{
|
||||||
|
collections::HashSet,
|
||||||
|
io::{stdin, stdout, Write},
|
||||||
|
sync::Arc,
|
||||||
|
},
|
||||||
|
termion::{
|
||||||
|
input::{MouseTerminal, TermRead},
|
||||||
|
raw::IntoRawMode,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub enum TerminalEvent {
|
pub enum TerminalEvent {
|
||||||
Resize(Vector2<i16>),
|
Resize(Vector2<i16>),
|
||||||
Input(termion::event::Event)
|
Input(termion::event::Event),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Terminal {
|
pub struct Terminal {
|
||||||
|
@ -46,24 +34,22 @@ pub struct Terminal {
|
||||||
_observer: Arc<RwLock<TermOutObserver>>,
|
_observer: Arc<RwLock<TermOutObserver>>,
|
||||||
|
|
||||||
events: ChannelReceiver<Vec<TerminalEvent>>,
|
events: ChannelReceiver<Vec<TerminalEvent>>,
|
||||||
_signal_handle: signal_hook_async_std::Handle
|
_signal_handle: signal_hook_async_std::Handle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Terminal {
|
impl Terminal {
|
||||||
pub fn new(
|
pub fn new(port: OuterViewPort<dyn TerminalView>) -> Self {
|
||||||
port: OuterViewPort<dyn TerminalView>
|
|
||||||
) -> Self {
|
|
||||||
let (dirty_pos_tx, dirty_pos_rx) = set_channel();
|
let (dirty_pos_tx, dirty_pos_rx) = set_channel();
|
||||||
|
|
||||||
let writer = Arc::new(TermOutWriter {
|
let writer = Arc::new(TermOutWriter {
|
||||||
out: RwLock::new(MouseTerminal::from(stdout().into_raw_mode().unwrap())),
|
out: RwLock::new(MouseTerminal::from(stdout().into_raw_mode().unwrap())),
|
||||||
dirty_pos_rx,
|
dirty_pos_rx,
|
||||||
view: port.get_view_arc()
|
view: port.get_view_arc(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let observer = Arc::new(RwLock::new(TermOutObserver {
|
let observer = Arc::new(RwLock::new(TermOutObserver {
|
||||||
dirty_pos_tx,
|
dirty_pos_tx,
|
||||||
writer: writer.clone()
|
writer: writer.clone(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
port.add_observer(observer.clone());
|
port.add_observer(observer.clone());
|
||||||
|
@ -82,7 +68,7 @@ impl Terminal {
|
||||||
event_tx.send(TerminalEvent::Resize(Vector2::new(w as i16, h as i16)));
|
event_tx.send(TerminalEvent::Resize(Vector2::new(w as i16, h as i16)));
|
||||||
|
|
||||||
// and again on SIGWINCH
|
// and again on SIGWINCH
|
||||||
let signals = Signals::new(&[ signal_hook::consts::signal::SIGWINCH ]).unwrap();
|
let signals = Signals::new(&[signal_hook::consts::signal::SIGWINCH]).unwrap();
|
||||||
let handle = signals.handle();
|
let handle = signals.handle();
|
||||||
|
|
||||||
task::spawn(async move {
|
task::spawn(async move {
|
||||||
|
@ -90,9 +76,9 @@ impl Terminal {
|
||||||
while let Some(signal) = signals.next().await {
|
while let Some(signal) = signals.next().await {
|
||||||
match signal {
|
match signal {
|
||||||
signal_hook::consts::signal::SIGWINCH => {
|
signal_hook::consts::signal::SIGWINCH => {
|
||||||
let (w,h) = termion::terminal_size().unwrap();
|
let (w, h) = termion::terminal_size().unwrap();
|
||||||
event_tx.send(TerminalEvent::Resize(Vector2::new(w as i16, h as i16)));
|
event_tx.send(TerminalEvent::Resize(Vector2::new(w as i16, h as i16)));
|
||||||
},
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,7 +88,7 @@ impl Terminal {
|
||||||
writer,
|
writer,
|
||||||
_observer: observer,
|
_observer: observer,
|
||||||
events: event_rx,
|
events: event_rx,
|
||||||
_signal_handle: handle
|
_signal_handle: handle,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,16 +103,18 @@ impl Terminal {
|
||||||
|
|
||||||
struct TermOutObserver {
|
struct TermOutObserver {
|
||||||
dirty_pos_tx: ChannelSender<HashSet<Point2<i16>>>,
|
dirty_pos_tx: ChannelSender<HashSet<Point2<i16>>>,
|
||||||
writer: Arc<TermOutWriter>
|
writer: Arc<TermOutWriter>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TermOutObserver {
|
impl TermOutObserver {
|
||||||
fn send_area(&mut self, area: IndexArea<Point2<i16>>) {
|
fn send_area(&mut self, area: IndexArea<Point2<i16>>) {
|
||||||
match area {
|
match area {
|
||||||
IndexArea::Empty => {},
|
IndexArea::Empty => {}
|
||||||
IndexArea::Full => {
|
IndexArea::Full => {
|
||||||
let (w, h) = termion::terminal_size().unwrap();
|
let (w, h) = termion::terminal_size().unwrap();
|
||||||
for pos in GridWindowIterator::from(Point2::new(0, 0) .. Point2::new(w as i16, h as i16)) {
|
for pos in
|
||||||
|
GridWindowIterator::from(Point2::new(0, 0)..Point2::new(w as i16, h as i16))
|
||||||
|
{
|
||||||
self.dirty_pos_tx.send(pos);
|
self.dirty_pos_tx.send(pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,7 +148,7 @@ impl Observer<dyn TerminalView> for TermOutObserver {
|
||||||
pub struct TermOutWriter {
|
pub struct TermOutWriter {
|
||||||
out: RwLock<MouseTerminal<termion::raw::RawTerminal<std::io::Stdout>>>,
|
out: RwLock<MouseTerminal<termion::raw::RawTerminal<std::io::Stdout>>>,
|
||||||
dirty_pos_rx: ChannelReceiver<HashSet<Point2<i16>>>,
|
dirty_pos_rx: ChannelReceiver<HashSet<Point2<i16>>>,
|
||||||
view: Arc<RwLock<Option<Arc<dyn TerminalView>>>>
|
view: Arc<RwLock<Option<Arc<dyn TerminalView>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TermOutWriter {
|
impl TermOutWriter {
|
||||||
|
@ -173,36 +161,45 @@ impl TermOutWriter {
|
||||||
impl TermOutWriter {
|
impl TermOutWriter {
|
||||||
pub async fn show(&self) -> std::io::Result<()> {
|
pub async fn show(&self) -> std::io::Result<()> {
|
||||||
// init
|
// init
|
||||||
write!(self.out.write().unwrap(), "{}{}{}",
|
write!(
|
||||||
termion::cursor::Hide,
|
self.out.write().unwrap(),
|
||||||
termion::cursor::Goto(1, 1),
|
"{}{}{}",
|
||||||
termion::style::Reset)?;
|
termion::cursor::Hide,
|
||||||
|
termion::cursor::Goto(1, 1),
|
||||||
|
termion::style::Reset
|
||||||
|
)?;
|
||||||
|
|
||||||
let mut cur_pos = Point2::<i16>::new(0, 0);
|
let mut cur_pos = Point2::<i16>::new(0, 0);
|
||||||
let mut cur_style = TerminalStyle::default();
|
let mut cur_style = TerminalStyle::default();
|
||||||
|
|
||||||
// draw atoms until view port is destroyed
|
// draw atoms until view port is destroyed
|
||||||
while let Some(dirty_pos) = self.dirty_pos_rx.recv().await {
|
while let Some(dirty_pos) = self.dirty_pos_rx.recv().await {
|
||||||
let (w, h) = termion::terminal_size().unwrap();
|
let (w, _h) = termion::terminal_size().unwrap();
|
||||||
|
|
||||||
if let Some(view) = self.view.read().unwrap().as_ref() {
|
if let Some(view) = self.view.read().unwrap().as_ref() {
|
||||||
let mut out = self.out.write().unwrap();
|
let mut out = self.out.write().unwrap();
|
||||||
|
|
||||||
let d = dirty_pos.into_iter().filter(|p| p.x >= 0 && p.y >= 0 && p.x < w as i16 && p.y < w as i16);//.collect::<Vec<_>>();
|
let d = dirty_pos
|
||||||
/*
|
.into_iter()
|
||||||
d.sort_by(|a,b| {
|
.filter(|p| p.x >= 0 && p.y >= 0 && p.x < w as i16 && p.y < w as i16); //.collect::<Vec<_>>();
|
||||||
if a.y < b.y {
|
/*
|
||||||
std::cmp::Ordering::Less
|
d.sort_by(|a,b| {
|
||||||
} else if a.y == b.y {
|
if a.y < b.y {
|
||||||
a.x.cmp(&b.x)
|
std::cmp::Ordering::Less
|
||||||
} else {
|
} else if a.y == b.y {
|
||||||
std::cmp::Ordering::Greater
|
a.x.cmp(&b.x)
|
||||||
}
|
} else {
|
||||||
});
|
std::cmp::Ordering::Greater
|
||||||
*/
|
}
|
||||||
|
});
|
||||||
|
*/
|
||||||
for pos in d {
|
for pos in d {
|
||||||
if pos != cur_pos {
|
if pos != cur_pos {
|
||||||
write!(out, "{}", termion::cursor::Goto(pos.x as u16 + 1, pos.y as u16 + 1))?;
|
write!(
|
||||||
|
out,
|
||||||
|
"{}",
|
||||||
|
termion::cursor::Goto(pos.x as u16 + 1, pos.y as u16 + 1)
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(atom) = view.get(&pos) {
|
if let Some(atom) = view.get(&pos) {
|
||||||
|
@ -232,4 +229,3 @@ impl TermOutWriter {
|
||||||
std::io::Result::Ok(())
|
std::io::Result::Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
|
|
||||||
use crate::list::ListCursorMode;
|
use crate::list::ListCursorMode;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
pub enum TreeNavResult {
|
pub enum TreeNavResult {
|
||||||
Continue,
|
Continue,
|
||||||
Exit
|
Exit,
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
impl From<TreeNavResult> for TerminalEditorResult {
|
impl From<TreeNavResult> for TerminalEditorResult {
|
||||||
|
@ -19,14 +18,14 @@ impl From<TreeNavResult> for TerminalEditorResult {
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
pub struct TreeCursor {
|
pub struct TreeCursor {
|
||||||
pub leaf_mode: ListCursorMode,
|
pub leaf_mode: ListCursorMode,
|
||||||
pub tree_addr: Vec<usize>
|
pub tree_addr: Vec<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TreeCursor {
|
impl Default for TreeCursor {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
TreeCursor {
|
TreeCursor {
|
||||||
leaf_mode: ListCursorMode::Select,
|
leaf_mode: ListCursorMode::Select,
|
||||||
tree_addr: vec![]
|
tree_addr: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,7 +55,7 @@ pub trait TreeNav {
|
||||||
TreeNavResult::Exit
|
TreeNavResult::Exit
|
||||||
}
|
}
|
||||||
|
|
||||||
fn goto(&mut self, new_cursor: TreeCursor) -> TreeNavResult {
|
fn goto(&mut self, _new_cursor: TreeCursor) -> TreeNavResult {
|
||||||
TreeNavResult::Exit
|
TreeNavResult::Exit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +64,6 @@ pub trait TreeNav {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::terminal::{TerminalView, TerminalEditor};
|
use crate::terminal::{TerminalEditor};
|
||||||
|
|
||||||
pub trait TerminalTreeEditor = TerminalEditor + TreeNav;
|
pub trait TerminalTreeEditor = TerminalEditor + TreeNav;
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
use {
|
use {
|
||||||
std::{
|
crate::{
|
||||||
sync::Arc,
|
core::{InnerViewPort, Observer, ObserverBroadcast, View},
|
||||||
ops::{Deref, DerefMut},
|
vec::VecDiff,
|
||||||
},
|
},
|
||||||
std::sync::RwLock,
|
std::sync::RwLock,
|
||||||
crate::{
|
std::{
|
||||||
core::{View, Observer, ObserverBroadcast, InnerViewPort},
|
ops::{Deref, DerefMut},
|
||||||
vec::VecDiff
|
sync::Arc,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl<T> View for Vec<T>
|
impl<T> View for Vec<T>
|
||||||
where T: Clone + Send + Sync + 'static {
|
where
|
||||||
|
T: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
type Msg = VecDiff<T>;
|
type Msg = VecDiff<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,19 +23,18 @@ where T: Clone + Send + Sync + 'static {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct VecBuffer<T>
|
pub struct VecBuffer<T>
|
||||||
where T: Clone + Send + Sync + 'static
|
where
|
||||||
|
T: Clone + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
data: Arc<RwLock<Vec<T>>>,
|
data: Arc<RwLock<Vec<T>>>,
|
||||||
cast: Arc<RwLock<ObserverBroadcast<RwLock<Vec<T>>>>>
|
cast: Arc<RwLock<ObserverBroadcast<RwLock<Vec<T>>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> VecBuffer<T>
|
impl<T> VecBuffer<T>
|
||||||
where T: Clone + Send + Sync + 'static
|
where
|
||||||
|
T: Clone + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
pub fn with_data(
|
pub fn with_data(data: Vec<T>, port: InnerViewPort<RwLock<Vec<T>>>) -> Self {
|
||||||
data: Vec<T>,
|
|
||||||
port: InnerViewPort<RwLock<Vec<T>>>
|
|
||||||
) -> Self {
|
|
||||||
let mut b = VecBuffer::new(port);
|
let mut b = VecBuffer::new(port);
|
||||||
for x in data.into_iter() {
|
for x in data.into_iter() {
|
||||||
b.push(x);
|
b.push(x);
|
||||||
|
@ -45,17 +46,30 @@ where T: Clone + Send + Sync + 'static
|
||||||
pub fn new(port: InnerViewPort<RwLock<Vec<T>>>) -> Self {
|
pub fn new(port: InnerViewPort<RwLock<Vec<T>>>) -> Self {
|
||||||
let data = Arc::new(RwLock::new(Vec::new()));
|
let data = Arc::new(RwLock::new(Vec::new()));
|
||||||
port.set_view(Some(data.clone()));
|
port.set_view(Some(data.clone()));
|
||||||
VecBuffer { data, cast: port.get_broadcast() }
|
VecBuffer {
|
||||||
|
data,
|
||||||
|
cast: port.get_broadcast(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_diff(&mut self, diff: VecDiff<T>) {
|
pub fn apply_diff(&mut self, diff: VecDiff<T>) {
|
||||||
let mut data = self.data.write().unwrap();
|
let mut data = self.data.write().unwrap();
|
||||||
match &diff {
|
match &diff {
|
||||||
VecDiff::Clear => { data.clear(); },
|
VecDiff::Clear => {
|
||||||
VecDiff::Push(val) => { data.push(val.clone()); },
|
data.clear();
|
||||||
VecDiff::Remove(idx) => { data.remove(*idx); },
|
}
|
||||||
VecDiff::Insert{ idx, val } => { data.insert(*idx, val.clone()); },
|
VecDiff::Push(val) => {
|
||||||
VecDiff::Update{ idx, val } => { data[*idx] = val.clone(); }
|
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);
|
drop(data);
|
||||||
|
|
||||||
|
@ -83,18 +97,18 @@ where T: Clone + Send + Sync + 'static
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, idx: usize, val: T) {
|
pub fn insert(&mut self, idx: usize, val: T) {
|
||||||
self.apply_diff(VecDiff::Insert{ idx, val });
|
self.apply_diff(VecDiff::Insert { idx, val });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, idx: usize, val: T) {
|
pub fn update(&mut self, idx: usize, val: T) {
|
||||||
self.apply_diff(VecDiff::Update{ idx, val });
|
self.apply_diff(VecDiff::Update { idx, val });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut(&mut self, idx: usize) -> MutableVecAccess<T> {
|
pub fn get_mut(&mut self, idx: usize) -> MutableVecAccess<T> {
|
||||||
MutableVecAccess {
|
MutableVecAccess {
|
||||||
buf: self.clone(),
|
buf: self.clone(),
|
||||||
idx,
|
idx,
|
||||||
val: self.get(idx)
|
val: self.get(idx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,14 +116,18 @@ where T: Clone + Send + Sync + 'static
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub struct MutableVecAccess<T>
|
pub struct MutableVecAccess<T>
|
||||||
where T: Clone + Send + Sync + 'static {
|
where
|
||||||
|
T: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
buf: VecBuffer<T>,
|
buf: VecBuffer<T>,
|
||||||
idx: usize,
|
idx: usize,
|
||||||
val: T,
|
val: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Deref for MutableVecAccess<T>
|
impl<T> Deref for MutableVecAccess<T>
|
||||||
where T: Clone + Send + Sync + 'static {
|
where
|
||||||
|
T: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
fn deref(&self) -> &T {
|
fn deref(&self) -> &T {
|
||||||
|
@ -118,17 +136,19 @@ where T: Clone + Send + Sync + 'static {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> DerefMut for MutableVecAccess<T>
|
impl<T> DerefMut for MutableVecAccess<T>
|
||||||
where T: Clone + Send + Sync + 'static {
|
where
|
||||||
|
T: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
&mut self.val
|
&mut self.val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Drop for MutableVecAccess<T>
|
impl<T> Drop for MutableVecAccess<T>
|
||||||
where T: Clone + Send + Sync + 'static {
|
where
|
||||||
|
T: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.buf.update(self.idx, self.val.clone());
|
self.buf.update(self.idx, self.val.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,19 @@
|
||||||
|
|
||||||
pub mod buffer;
|
pub mod buffer;
|
||||||
pub mod vec2seq;
|
|
||||||
pub mod vec2json;
|
|
||||||
pub mod vec2bin;
|
pub mod vec2bin;
|
||||||
|
pub mod vec2json;
|
||||||
|
pub mod vec2seq;
|
||||||
|
|
||||||
pub use {
|
pub use buffer::VecBuffer;
|
||||||
buffer::VecBuffer
|
|
||||||
};
|
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
use {
|
use serde::{Deserialize, Serialize};
|
||||||
serde::{Serialize, Deserialize}
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub enum VecDiff<T> {
|
pub enum VecDiff<T> {
|
||||||
Clear,
|
Clear,
|
||||||
Push(T),
|
Push(T),
|
||||||
Remove(usize),
|
Remove(usize),
|
||||||
Insert{ idx: usize, val: T },
|
Insert { idx: usize, val: T },
|
||||||
Update{ idx: usize, val: T }
|
Update { idx: usize, val: T },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,56 +1,70 @@
|
||||||
use {
|
use {
|
||||||
std::{
|
|
||||||
sync::Arc,
|
|
||||||
io::Write
|
|
||||||
},
|
|
||||||
std::sync::RwLock,
|
|
||||||
serde::Serialize,
|
|
||||||
crate::{
|
crate::{
|
||||||
core::{Observer, OuterViewPort},
|
core::{Observer, OuterViewPort},
|
||||||
vec::VecDiff
|
vec::VecDiff,
|
||||||
}
|
},
|
||||||
|
serde::Serialize,
|
||||||
|
std::sync::RwLock,
|
||||||
|
std::{io::Write, sync::Arc},
|
||||||
};
|
};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
/// Serialization Observer for `Vec`
|
/// Serialization Observer for `Vec`
|
||||||
pub struct VecBinWriter<T, W>
|
pub struct VecBinWriter<T, W>
|
||||||
where T: Clone + Send + Sync + 'static,
|
where
|
||||||
W: Write + Send + Sync {
|
T: Clone + Send + Sync + 'static,
|
||||||
|
W: Write + Send + Sync,
|
||||||
|
{
|
||||||
data: Option<Arc<RwLock<Vec<T>>>>,
|
data: Option<Arc<RwLock<Vec<T>>>>,
|
||||||
out: RwLock<W>
|
out: RwLock<W>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<T> OuterViewPort<RwLock<Vec<T>>>
|
impl<T> OuterViewPort<RwLock<Vec<T>>>
|
||||||
where T: Clone + Serialize + Send + Sync + 'static {
|
where
|
||||||
pub fn serialize_bin<W: Write + Send + Sync + 'static>(&self, out: W) -> Arc<RwLock<VecBinWriter<T, W>>> {
|
T: Clone + Serialize + Send + Sync + 'static,
|
||||||
let writer = Arc::new(RwLock::new(
|
{
|
||||||
VecBinWriter {
|
pub fn serialize_bin<W: Write + Send + Sync + 'static>(
|
||||||
data: None,
|
&self,
|
||||||
out: RwLock::new(out),
|
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());
|
self.add_observer(writer.clone());
|
||||||
writer
|
writer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, W> Observer<RwLock<Vec<T>>> for VecBinWriter<T, W>
|
impl<T, W> Observer<RwLock<Vec<T>>> for VecBinWriter<T, W>
|
||||||
where T: Clone + Serialize + Send + Sync + 'static,
|
where
|
||||||
W: Write + Send + Sync
|
T: Clone + Serialize + Send + Sync + 'static,
|
||||||
|
W: Write + Send + Sync,
|
||||||
{
|
{
|
||||||
fn reset(&mut self, view: Option<Arc<RwLock<Vec<T>>>>) {
|
fn reset(&mut self, view: Option<Arc<RwLock<Vec<T>>>>) {
|
||||||
self.data = view;
|
self.data = view;
|
||||||
let mut out = self.out.write().unwrap();
|
let mut out = self.out.write().unwrap();
|
||||||
|
|
||||||
out.write(&bincode::serialized_size(&VecDiff::<T>::Clear).unwrap().to_le_bytes()).expect("");
|
out.write(
|
||||||
out.write(&bincode::serialize(&VecDiff::<T>::Clear).unwrap()).expect("");
|
&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() {
|
if let Some(data) = self.data.as_ref() {
|
||||||
for x in data.read().unwrap().iter() {
|
for x in data.read().unwrap().iter() {
|
||||||
out.write(&bincode::serialized_size(&VecDiff::Push(x)).unwrap().to_le_bytes()).expect("");
|
out.write(
|
||||||
out.write(&bincode::serialize(&VecDiff::Push(x)).unwrap()).expect("");
|
&bincode::serialized_size(&VecDiff::Push(x))
|
||||||
|
.unwrap()
|
||||||
|
.to_le_bytes(),
|
||||||
|
)
|
||||||
|
.expect("");
|
||||||
|
out.write(&bincode::serialize(&VecDiff::Push(x)).unwrap())
|
||||||
|
.expect("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,9 +73,9 @@ where T: Clone + Serialize + Send + Sync + 'static,
|
||||||
|
|
||||||
fn notify(&mut self, diff: &VecDiff<T>) {
|
fn notify(&mut self, diff: &VecDiff<T>) {
|
||||||
let mut out = self.out.write().unwrap();
|
let mut out = self.out.write().unwrap();
|
||||||
out.write(&bincode::serialized_size(diff).unwrap().to_le_bytes()).expect("");
|
out.write(&bincode::serialized_size(diff).unwrap().to_le_bytes())
|
||||||
|
.expect("");
|
||||||
out.write(&bincode::serialize(diff).unwrap()).expect("");
|
out.write(&bincode::serialize(diff).unwrap()).expect("");
|
||||||
out.flush().expect("");
|
out.flush().expect("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,56 +1,71 @@
|
||||||
use {
|
use {
|
||||||
std::{
|
|
||||||
sync::Arc,
|
|
||||||
io::Write
|
|
||||||
},
|
|
||||||
std::sync::RwLock,
|
|
||||||
async_std::{
|
|
||||||
io::{Read, ReadExt},
|
|
||||||
stream::{StreamExt}
|
|
||||||
},
|
|
||||||
serde::{Serialize, de::DeserializeOwned},
|
|
||||||
crate::{
|
crate::{
|
||||||
core::{Observer, OuterViewPort},
|
core::{Observer, OuterViewPort},
|
||||||
vec::{VecDiff, VecBuffer}
|
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>
|
pub struct VecJsonWriter<T, W>
|
||||||
where T: Clone + Send + Sync + 'static,
|
where
|
||||||
W: Write + Send + Sync {
|
T: Clone + Send + Sync + 'static,
|
||||||
|
W: Write + Send + Sync,
|
||||||
|
{
|
||||||
data: Option<Arc<RwLock<Vec<T>>>>,
|
data: Option<Arc<RwLock<Vec<T>>>>,
|
||||||
out: RwLock<W>
|
out: RwLock<W>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> OuterViewPort<RwLock<Vec<T>>>
|
impl<T> OuterViewPort<RwLock<Vec<T>>>
|
||||||
where T: Clone + Serialize + Send + Sync + 'static {
|
where
|
||||||
pub fn serialize_json<W: Write + Send + Sync + 'static>(&self, out: W) -> Arc<RwLock<VecJsonWriter<T, W>>> {
|
T: Clone + Serialize + Send + Sync + 'static,
|
||||||
let writer = Arc::new(RwLock::new(
|
{
|
||||||
VecJsonWriter {
|
pub fn serialize_json<W: Write + Send + Sync + 'static>(
|
||||||
data: None,
|
&self,
|
||||||
out: RwLock::new(out),
|
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());
|
self.add_observer(writer.clone());
|
||||||
writer
|
writer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, W> Observer<RwLock<Vec<T>>> for VecJsonWriter<T, W>
|
impl<T, W> Observer<RwLock<Vec<T>>> for VecJsonWriter<T, W>
|
||||||
where T: Clone + Serialize + Send + Sync + 'static,
|
where
|
||||||
W: Write + Send + Sync
|
T: Clone + Serialize + Send + Sync + 'static,
|
||||||
|
W: Write + Send + Sync,
|
||||||
{
|
{
|
||||||
fn reset(&mut self, view: Option<Arc<RwLock<Vec<T>>>>) {
|
fn reset(&mut self, view: Option<Arc<RwLock<Vec<T>>>>) {
|
||||||
self.data = view;
|
self.data = view;
|
||||||
|
|
||||||
self.out.write().unwrap().write(&serde_json::to_string(&VecDiff::<T>::Clear).unwrap().as_bytes()).expect("");
|
self.out
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.write(
|
||||||
|
&serde_json::to_string(&VecDiff::<T>::Clear)
|
||||||
|
.unwrap()
|
||||||
|
.as_bytes(),
|
||||||
|
)
|
||||||
|
.expect("");
|
||||||
self.out.write().unwrap().write(b"\n").expect("");
|
self.out.write().unwrap().write(b"\n").expect("");
|
||||||
|
|
||||||
if let Some(data) = self.data.as_ref() {
|
if let Some(data) = self.data.as_ref() {
|
||||||
for x in data.read().unwrap().iter() {
|
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(&serde_json::to_string(&VecDiff::Push(x)).unwrap().as_bytes())
|
||||||
|
.expect("");
|
||||||
self.out.write().unwrap().write(b"\n").expect("");
|
self.out.write().unwrap().write(b"\n").expect("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,14 +74,19 @@ where T: Clone + Serialize + Send + Sync + 'static,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn notify(&mut self, diff: &VecDiff<T>) {
|
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(serde_json::to_string(diff).unwrap().as_bytes())
|
||||||
|
.expect("");
|
||||||
self.out.write().unwrap().write(b"\n").expect("");
|
self.out.write().unwrap().write(b"\n").expect("");
|
||||||
self.out.write().unwrap().flush().expect("");
|
self.out.write().unwrap().flush().expect("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> VecBuffer<T>
|
impl<T> VecBuffer<T>
|
||||||
where T: DeserializeOwned + Clone + Send + Sync + 'static
|
where
|
||||||
|
T: DeserializeOwned + Clone + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
pub async fn from_json<R: Read + async_std::io::Read + Unpin>(&mut self, read: R) {
|
pub async fn from_json<R: Read + async_std::io::Read + Unpin>(&mut self, read: R) {
|
||||||
let mut bytes = read.bytes();
|
let mut bytes = read.bytes();
|
||||||
|
@ -75,11 +95,12 @@ where T: DeserializeOwned + Clone + Send + Sync + 'static
|
||||||
match b {
|
match b {
|
||||||
b'\n' => {
|
b'\n' => {
|
||||||
if s.len() > 0 {
|
if s.len() > 0 {
|
||||||
let diff = serde_json::from_str::<VecDiff<T>>(&s).expect("error parsing json");
|
let diff =
|
||||||
|
serde_json::from_str::<VecDiff<T>>(&s).expect("error parsing json");
|
||||||
self.apply_diff(diff);
|
self.apply_diff(diff);
|
||||||
s.clear();
|
s.clear();
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
c => {
|
c => {
|
||||||
s.push(c as char);
|
s.push(c as char);
|
||||||
}
|
}
|
||||||
|
@ -87,5 +108,3 @@ where T: DeserializeOwned + Clone + Send + Sync + 'static
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,78 +1,78 @@
|
||||||
use {
|
use {
|
||||||
std::{
|
|
||||||
sync::Arc,
|
|
||||||
},
|
|
||||||
std::sync::RwLock,
|
|
||||||
crate::{
|
crate::{
|
||||||
core::{View, Observer, ObserverExt, ObserverBroadcast, ViewPort, InnerViewPort, OuterViewPort},
|
core::{
|
||||||
|
InnerViewPort, Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View, ViewPort,
|
||||||
|
},
|
||||||
sequence::SequenceView,
|
sequence::SequenceView,
|
||||||
vec::VecDiff
|
vec::VecDiff,
|
||||||
}
|
},
|
||||||
|
std::sync::Arc,
|
||||||
|
std::sync::RwLock,
|
||||||
};
|
};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
/// Adapter View implementing `Sequence` for `Vec`
|
/// Adapter View implementing `Sequence` for `Vec`
|
||||||
pub struct VecSequence<T>
|
pub struct VecSequence<T>
|
||||||
where T: Clone + Send + Sync + 'static {
|
where
|
||||||
|
T: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
cur_len: usize,
|
cur_len: usize,
|
||||||
data: Option<Arc<RwLock<Vec<T>>>>,
|
data: Option<Arc<RwLock<Vec<T>>>>,
|
||||||
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = T>>>>
|
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = T>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<T> VecSequence<T>
|
impl<T> VecSequence<T>
|
||||||
where T: Clone + Send + Sync + 'static {
|
where
|
||||||
pub fn new(
|
T: Clone + Send + Sync + 'static,
|
||||||
port: InnerViewPort<dyn SequenceView<Item = T>>
|
{
|
||||||
) -> Arc<RwLock<Self>> {
|
pub fn new(port: InnerViewPort<dyn SequenceView<Item = T>>) -> Arc<RwLock<Self>> {
|
||||||
let seq = Arc::new(RwLock::new(
|
let seq = Arc::new(RwLock::new(VecSequence {
|
||||||
VecSequence {
|
cur_len: 0,
|
||||||
cur_len: 0,
|
data: None,
|
||||||
data: None,
|
cast: port.get_broadcast(),
|
||||||
cast: port.get_broadcast()
|
}));
|
||||||
}
|
|
||||||
));
|
|
||||||
port.set_view(Some(seq.clone()));
|
port.set_view(Some(seq.clone()));
|
||||||
seq
|
seq
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Observer<RwLock<Vec<T>>> for VecSequence<T>
|
impl<T> Observer<RwLock<Vec<T>>> for VecSequence<T>
|
||||||
where T: Clone + Send + Sync + 'static {
|
where
|
||||||
|
T: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
fn reset(&mut self, view: Option<Arc<RwLock<Vec<T>>>>) {
|
fn reset(&mut self, view: Option<Arc<RwLock<Vec<T>>>>) {
|
||||||
let old_len = self.cur_len;
|
let old_len = self.cur_len;
|
||||||
self.data = view;
|
self.data = view;
|
||||||
let new_len =
|
let new_len = if let Some(data) = self.data.as_ref() {
|
||||||
if let Some(data) = self.data.as_ref() {
|
data.read().unwrap().len()
|
||||||
data.read().unwrap().len()
|
} else {
|
||||||
} else {
|
0
|
||||||
0
|
};
|
||||||
};
|
|
||||||
|
|
||||||
self.cur_len = new_len;
|
self.cur_len = new_len;
|
||||||
self.cast.notify_each(0 .. std::cmp::max(old_len, new_len));
|
self.cast.notify_each(0..std::cmp::max(old_len, new_len));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn notify(&mut self, diff: &VecDiff<T>) {
|
fn notify(&mut self, diff: &VecDiff<T>) {
|
||||||
match diff {
|
match diff {
|
||||||
VecDiff::Clear => {
|
VecDiff::Clear => {
|
||||||
self.cast.notify_each(0 .. self.cur_len);
|
self.cast.notify_each(0..self.cur_len);
|
||||||
self.cur_len = 0
|
self.cur_len = 0
|
||||||
},
|
}
|
||||||
VecDiff::Push(_) => {
|
VecDiff::Push(_) => {
|
||||||
self.cast.notify(&self.cur_len);
|
self.cast.notify(&self.cur_len);
|
||||||
self.cur_len += 1;
|
self.cur_len += 1;
|
||||||
},
|
}
|
||||||
VecDiff::Remove(idx) => {
|
VecDiff::Remove(idx) => {
|
||||||
self.cast.notify_each(*idx .. self.cur_len);
|
self.cast.notify_each(*idx..self.cur_len);
|
||||||
self.cur_len -= 1;
|
self.cur_len -= 1;
|
||||||
},
|
}
|
||||||
VecDiff::Insert{ idx, val: _ } => {
|
VecDiff::Insert { idx, val: _ } => {
|
||||||
self.cur_len += 1;
|
self.cur_len += 1;
|
||||||
self.cast.notify_each(*idx .. self.cur_len);
|
self.cast.notify_each(*idx..self.cur_len);
|
||||||
},
|
}
|
||||||
VecDiff::Update{ idx, val: _ } => {
|
VecDiff::Update { idx, val: _ } => {
|
||||||
self.cast.notify(&idx);
|
self.cast.notify(&idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,18 +80,20 @@ where T: Clone + Send + Sync + 'static {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> View for VecSequence<T>
|
impl<T> View for VecSequence<T>
|
||||||
where T: Clone + Send + Sync + 'static {
|
where
|
||||||
|
T: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
type Msg = usize;
|
type Msg = usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> SequenceView for VecSequence<T>
|
impl<T> SequenceView for VecSequence<T>
|
||||||
where T: Clone + Send + Sync + 'static {
|
where
|
||||||
|
T: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
type Item = T;
|
type Item = T;
|
||||||
|
|
||||||
fn get(&self, idx: &usize) -> Option<T> {
|
fn get(&self, idx: &usize) -> Option<T> {
|
||||||
self.data.as_ref()?
|
self.data.as_ref()?.read().unwrap().get(*idx).cloned()
|
||||||
.read().unwrap()
|
|
||||||
.get(*idx).cloned()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn len(&self) -> Option<usize> {
|
fn len(&self) -> Option<usize> {
|
||||||
|
@ -102,7 +104,9 @@ where T: Clone + Send + Sync + 'static {
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
impl<T> OuterViewPort<RwLock<Vec<T>>>
|
impl<T> OuterViewPort<RwLock<Vec<T>>>
|
||||||
where T: Clone + Send + Sync + 'static {
|
where
|
||||||
|
T: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
pub fn to_sequence(&self) -> OuterViewPort<dyn SequenceView<Item = T>> {
|
pub fn to_sequence(&self) -> OuterViewPort<dyn SequenceView<Item = T>> {
|
||||||
let port = ViewPort::new();
|
let port = ViewPort::new();
|
||||||
port.add_update_hook(Arc::new(self.0.clone()));
|
port.add_update_hook(Arc::new(self.0.clone()));
|
||||||
|
@ -112,5 +116,3 @@ where T: Clone + Send + Sync + 'static {
|
||||||
port.into_outer()
|
port.into_outer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,52 +1,38 @@
|
||||||
|
use {
|
||||||
use{
|
|
||||||
std::sync::{Arc, RwLock},
|
|
||||||
cgmath::{Point2, Vector2},
|
cgmath::{Point2, Vector2},
|
||||||
nested::{
|
nested::{
|
||||||
core::{
|
core::{InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View},
|
||||||
View,
|
|
||||||
ViewPort,
|
|
||||||
InnerViewPort,
|
|
||||||
OuterViewPort,
|
|
||||||
Observer,
|
|
||||||
ObserverExt,
|
|
||||||
ObserverBroadcast,
|
|
||||||
context::{ReprTree, Object, MorphismType, MorphismMode, Context},
|
|
||||||
port::{UpdateTask}},
|
|
||||||
index::{IndexArea, IndexView},
|
index::{IndexArea, IndexView},
|
||||||
grid::{GridWindowIterator},
|
terminal::{TerminalAtom, TerminalView},
|
||||||
terminal::{
|
},
|
||||||
Terminal,
|
std::sync::{Arc, RwLock},
|
||||||
TerminalStyle,
|
|
||||||
TerminalAtom,
|
|
||||||
TerminalCompositor,
|
|
||||||
TerminalEvent,
|
|
||||||
make_label,
|
|
||||||
TerminalView,
|
|
||||||
TerminalEditor},
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct AsciiBox {
|
pub struct AsciiBox {
|
||||||
content: Option<Arc<dyn TerminalView>>,
|
content: Option<Arc<dyn TerminalView>>,
|
||||||
extent: Vector2<i16>,
|
extent: Vector2<i16>,
|
||||||
|
|
||||||
cast: Arc<RwLock<ObserverBroadcast<dyn TerminalView>>>
|
cast: Arc<RwLock<ObserverBroadcast<dyn TerminalView>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsciiBox {
|
impl AsciiBox {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
extent: Vector2<i16>,
|
extent: Vector2<i16>,
|
||||||
content_port: OuterViewPort<dyn TerminalView>,
|
content_port: OuterViewPort<dyn TerminalView>,
|
||||||
output_port: InnerViewPort<dyn TerminalView>
|
output_port: InnerViewPort<dyn TerminalView>,
|
||||||
) -> Arc<RwLock<Self>> {
|
) -> Arc<RwLock<Self>> {
|
||||||
let ascii_box = Arc::new(RwLock::new(AsciiBox {
|
let ascii_box = Arc::new(RwLock::new(AsciiBox {
|
||||||
content: None,
|
content: None,
|
||||||
extent,
|
extent,
|
||||||
cast: output_port.get_broadcast()
|
cast: output_port.get_broadcast(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
output_port.0.update_hooks.write().unwrap().push(Arc::new(content_port.0.clone()));
|
output_port
|
||||||
|
.0
|
||||||
|
.update_hooks
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.push(Arc::new(content_port.0.clone()));
|
||||||
output_port.set_view(Some(ascii_box.clone()));
|
output_port.set_view(Some(ascii_box.clone()));
|
||||||
content_port.add_observer(ascii_box.clone());
|
content_port.add_observer(ascii_box.clone());
|
||||||
|
|
||||||
|
@ -57,19 +43,20 @@ impl AsciiBox {
|
||||||
if self.extent != new_extent {
|
if self.extent != new_extent {
|
||||||
let old_extent = self.extent;
|
let old_extent = self.extent;
|
||||||
self.extent = new_extent;
|
self.extent = new_extent;
|
||||||
self.cast.notify(
|
self.cast.notify(&IndexArea::Range(
|
||||||
&IndexArea::Range(
|
Point2::new(0, 0)
|
||||||
Point2::new(0, 0) ..=
|
..=Point2::new(
|
||||||
Point2::new(
|
1 + std::cmp::max(old_extent.x, new_extent.x),
|
||||||
1+std::cmp::max(old_extent.x, new_extent.x),
|
1 + std::cmp::max(old_extent.y, new_extent.y),
|
||||||
1+std::cmp::max(old_extent.y, new_extent.y))));
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fit_content(&mut self) {
|
pub fn fit_content(&mut self) {
|
||||||
if let Some(c) = self.content.as_ref() {
|
if let Some(c) = self.content.as_ref() {
|
||||||
let p = *c.area().range().end();
|
let p = *c.area().range().end();
|
||||||
self.resize(Vector2::new(p.x+1, p.y+1));
|
self.resize(Vector2::new(p.x + 1, p.y + 1));
|
||||||
} else {
|
} else {
|
||||||
self.resize(Vector2::new(0, 0));
|
self.resize(Vector2::new(0, 0));
|
||||||
}
|
}
|
||||||
|
@ -96,42 +83,40 @@ impl IndexView<Point2<i16>> for AsciiBox {
|
||||||
type Item = TerminalAtom;
|
type Item = TerminalAtom;
|
||||||
|
|
||||||
fn get(&self, pt: &Point2<i16>) -> Option<TerminalAtom> {
|
fn get(&self, pt: &Point2<i16>) -> Option<TerminalAtom> {
|
||||||
if pt.x == 0 || pt.x == self.extent.x+1 {
|
if pt.x == 0 || pt.x == self.extent.x + 1 {
|
||||||
// vertical line
|
// vertical line
|
||||||
if pt.y == 0 && pt.x == 0 {
|
if pt.y == 0 && pt.x == 0 {
|
||||||
Some(TerminalAtom::from('╭'))
|
Some(TerminalAtom::from('╭'))
|
||||||
} else if pt.y == 0 && pt.x == self.extent.x+1 {
|
} else if pt.y == 0 && pt.x == self.extent.x + 1 {
|
||||||
Some(TerminalAtom::from('╮'))
|
Some(TerminalAtom::from('╮'))
|
||||||
} else if pt.y > 0 && pt.y < self.extent.y+1 {
|
} else if pt.y > 0 && pt.y < self.extent.y + 1 {
|
||||||
Some(TerminalAtom::from('│'))
|
Some(TerminalAtom::from('│'))
|
||||||
} else if pt.y == self.extent.y+1 && pt.x == 0 {
|
} else if pt.y == self.extent.y + 1 && pt.x == 0 {
|
||||||
Some(TerminalAtom::from('╰'))
|
Some(TerminalAtom::from('╰'))
|
||||||
} else if pt.y == self.extent.y+1 && pt.x == self.extent.x+1 {
|
} else if pt.y == self.extent.y + 1 && pt.x == self.extent.x + 1 {
|
||||||
Some(TerminalAtom::from('╯'))
|
Some(TerminalAtom::from('╯'))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
} else if pt.y == 0 || pt.y == self.extent.y+1 {
|
} else if pt.y == 0 || pt.y == self.extent.y + 1 {
|
||||||
// horizontal line
|
// horizontal line
|
||||||
if pt.x > 0 && pt.x < self.extent.x+1 {
|
if pt.x > 0 && pt.x < self.extent.x + 1 {
|
||||||
Some(TerminalAtom::from('─'))
|
Some(TerminalAtom::from('─'))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
} else if
|
} else if pt.x > 0 && pt.y > 0 && pt.x < self.extent.x + 1 && pt.y < self.extent.y + 1 {
|
||||||
pt.x > 0 &&
|
Some(
|
||||||
pt.y > 0 &&
|
self.content
|
||||||
pt.x < self.extent.x+1 &&
|
.get(&(pt - Vector2::new(1, 1)))
|
||||||
pt.y < self.extent.y+1
|
.unwrap_or(TerminalAtom::from(' ')),
|
||||||
{
|
)
|
||||||
Some(self.content.get(&(pt - Vector2::new(1, 1))).unwrap_or(TerminalAtom::from(' ')))
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn area(&self) -> IndexArea<Point2<i16>> {
|
fn area(&self) -> IndexArea<Point2<i16>> {
|
||||||
IndexArea::Range(Point2::new(0, 0) ..= Point2::new(1,1)+self.extent)
|
IndexArea::Range(Point2::new(0, 0)..=Point2::new(1, 1) + self.extent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,52 +1,28 @@
|
||||||
|
|
||||||
extern crate portable_pty;
|
extern crate portable_pty;
|
||||||
|
|
||||||
|
mod ascii_box;
|
||||||
mod monstera;
|
mod monstera;
|
||||||
mod process;
|
mod process;
|
||||||
mod pty;
|
mod pty;
|
||||||
mod ascii_box;
|
|
||||||
|
|
||||||
mod plot;
|
mod plot;
|
||||||
|
|
||||||
use{
|
use {
|
||||||
std::sync::{Arc, RwLock},
|
crate::process::ProcessLauncher,
|
||||||
cgmath::{Point2, Vector2},
|
cgmath::{Point2, Vector2},
|
||||||
termion::event::{Event, Key},
|
|
||||||
nested::{
|
nested::{
|
||||||
core::{
|
core::{port::UpdateTask, Observer, OuterViewPort, ViewPort},
|
||||||
View,
|
index::IndexArea,
|
||||||
ViewPort,
|
list::{ListCursorMode, ListEditor, ListEditorStyle},
|
||||||
InnerViewPort,
|
|
||||||
OuterViewPort,
|
|
||||||
Observer,
|
|
||||||
ObserverExt,
|
|
||||||
ObserverBroadcast,
|
|
||||||
context::{ReprTree, Object, MorphismType, MorphismMode, Context},
|
|
||||||
port::{UpdateTask}},
|
|
||||||
index::{IndexView, IndexArea},
|
|
||||||
grid::{GridWindowIterator},
|
|
||||||
sequence::{SequenceView, SequenceViewExt},
|
|
||||||
vec::{VecBuffer},
|
|
||||||
integer::{RadixProjection, DigitEditor, PosIntEditor},
|
|
||||||
terminal::{
|
terminal::{
|
||||||
Terminal,
|
make_label, Terminal, TerminalAtom, TerminalCompositor, TerminalEditor,
|
||||||
TerminalStyle,
|
TerminalEditorResult, TerminalEvent, TerminalStyle, TerminalView,
|
||||||
TerminalAtom,
|
|
||||||
TerminalCompositor,
|
|
||||||
TerminalEvent,
|
|
||||||
make_label,
|
|
||||||
TerminalView,
|
|
||||||
TerminalEditor,
|
|
||||||
TerminalEditorResult
|
|
||||||
},
|
},
|
||||||
string_editor::{StringEditor},
|
tree_nav::{TerminalTreeEditor, TreeCursor, TreeNavResult},
|
||||||
tree_nav::{TreeNav, TreeNavResult, TreeCursor, TerminalTreeEditor},
|
vec::VecBuffer,
|
||||||
list::{SExprView, ListCursorMode, ListEditor, ListEditorStyle},
|
|
||||||
projection::ProjectionHelper
|
|
||||||
},
|
},
|
||||||
crate::{
|
std::sync::{Arc, RwLock},
|
||||||
process::ProcessLauncher
|
termion::event::{Event, Key},
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[async_std::main]
|
#[async_std::main]
|
||||||
|
@ -57,223 +33,252 @@ async fn main() {
|
||||||
let mut term = Terminal::new(term_port.outer());
|
let mut term = Terminal::new(term_port.outer());
|
||||||
let term_writer = term.get_writer();
|
let term_writer = term.get_writer();
|
||||||
|
|
||||||
async_std::task::spawn(
|
async_std::task::spawn(async move {
|
||||||
async move {
|
let table_port =
|
||||||
let table_port = ViewPort::<dyn nested::grid::GridView<Item = OuterViewPort<dyn TerminalView>>>::new();
|
ViewPort::<dyn nested::grid::GridView<Item = OuterViewPort<dyn TerminalView>>>::new();
|
||||||
let mut table_buf = nested::index::buffer::IndexBuffer::new(table_port.inner());
|
let mut table_buf = nested::index::buffer::IndexBuffer::new(table_port.inner());
|
||||||
|
|
||||||
let magic =
|
let magic =
|
||||||
make_label("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>")
|
make_label("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>").map_item(|pos, atom| {
|
||||||
.map_item(
|
atom.add_style_back(TerminalStyle::fg_color((
|
||||||
|pos, atom|
|
5,
|
||||||
atom.add_style_back(
|
((80 + (pos.x * 30) % 100) as u8),
|
||||||
TerminalStyle::fg_color(
|
(55 + (pos.x * 15) % 180) as u8,
|
||||||
(5,
|
)))
|
||||||
((80+(pos.x*30)%100) as u8),
|
|
||||||
(55+(pos.x*15)%180) as u8)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
let cur_size_port = ViewPort::new();
|
|
||||||
let mut cur_size = nested::singleton::SingletonBuffer::new(Vector2::new(10, 10), cur_size_port.inner());
|
|
||||||
|
|
||||||
let status_chars_port = ViewPort::new();
|
|
||||||
let mut status_chars = VecBuffer::new(status_chars_port.inner());
|
|
||||||
|
|
||||||
let mut process_list_editor = ListEditor::new(
|
|
||||||
Box::new(|| {
|
|
||||||
Arc::new(RwLock::new(
|
|
||||||
ProcessLauncher::new()
|
|
||||||
))
|
|
||||||
}),
|
|
||||||
ListEditorStyle::VerticalSexpr
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
let plist_vec_port = ViewPort::new();
|
|
||||||
let mut plist = VecBuffer::new(plist_vec_port.inner());
|
|
||||||
|
|
||||||
async_std::task::spawn(async move {
|
|
||||||
let (w, h) = termion::terminal_size().unwrap();
|
|
||||||
let mut x : usize = 0;
|
|
||||||
loop {
|
|
||||||
let val =
|
|
||||||
(
|
|
||||||
5.0 + (x as f32 / 3.0).sin() * 5.0 +
|
|
||||||
2.0 + ((7+x) as f32 / 5.0).sin() * 2.0 +
|
|
||||||
2.0 + ((9+x) as f32 / 10.0).cos() * 3.0
|
|
||||||
) as usize;
|
|
||||||
|
|
||||||
if x < w as usize {
|
|
||||||
plist.push(val);
|
|
||||||
} else {
|
|
||||||
*plist.get_mut(x % (w as usize)) = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
x+=1;
|
|
||||||
async_std::task::sleep(std::time::Duration::from_millis(10)).await;
|
|
||||||
|
|
||||||
if x%(w as usize) == 0 {
|
|
||||||
async_std::task::sleep(std::time::Duration::from_secs(3)).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let plot_port = ViewPort::new();
|
let cur_size_port = ViewPort::new();
|
||||||
let plot = crate::plot::Plot::new(plist_vec_port.outer().to_sequence(), plot_port.inner());
|
let mut cur_size =
|
||||||
|
nested::singleton::SingletonBuffer::new(Vector2::new(10, 10), cur_size_port.inner());
|
||||||
|
|
||||||
table_buf.insert_iter(vec![
|
let status_chars_port = ViewPort::new();
|
||||||
(Point2::new(0, 0), magic.clone()),
|
let mut status_chars = VecBuffer::new(status_chars_port.inner());
|
||||||
(Point2::new(0, 1), status_chars_port.outer().to_sequence().to_grid_horizontal()),
|
|
||||||
(Point2::new(0, 2), magic.clone()),
|
|
||||||
(Point2::new(0, 3), process_list_editor.get_term_view()),
|
|
||||||
]);
|
|
||||||
|
|
||||||
let (w, h) = termion::terminal_size().unwrap();
|
let mut process_list_editor = ListEditor::new(
|
||||||
|
Box::new(|| Arc::new(RwLock::new(ProcessLauncher::new()))),
|
||||||
|
ListEditorStyle::VerticalSexpr,
|
||||||
|
);
|
||||||
|
|
||||||
compositor.write().unwrap().push(
|
let plist_vec_port = ViewPort::new();
|
||||||
plot_port.outer()
|
let mut plist = VecBuffer::new(plist_vec_port.inner());
|
||||||
.map_item(|pt,a| {
|
|
||||||
a.add_style_back(TerminalStyle::fg_color((255 - pt.y as u8 * 8, 100, pt.y as u8 *15)))
|
|
||||||
})
|
|
||||||
.offset(Vector2::new(0,h as i16-20))
|
|
||||||
);
|
|
||||||
|
|
||||||
compositor.write().unwrap().push(
|
|
||||||
monstera::make_monstera()
|
|
||||||
.offset(Vector2::new(w as i16-38, 0)));
|
|
||||||
|
|
||||||
compositor.write().unwrap().push(
|
|
||||||
table_port.outer()
|
|
||||||
.flatten()
|
|
||||||
.offset(Vector2::new(3, 0))
|
|
||||||
);
|
|
||||||
|
|
||||||
process_list_editor.goto(TreeCursor {
|
|
||||||
leaf_mode: ListCursorMode::Insert,
|
|
||||||
tree_addr: vec![ 0 ]
|
|
||||||
});
|
|
||||||
|
|
||||||
let tp = term_port.clone();
|
|
||||||
async_std::task::spawn(
|
|
||||||
async move {
|
|
||||||
loop {
|
|
||||||
tp.update();
|
|
||||||
async_std::task::sleep(std::time::Duration::from_millis(10)).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
async_std::task::spawn(async move {
|
||||||
|
let (w, _h) = termion::terminal_size().unwrap();
|
||||||
|
let mut x: usize = 0;
|
||||||
loop {
|
loop {
|
||||||
status_chars.clear();
|
let val = (5.0
|
||||||
let cur = process_list_editor.get_cursor();
|
+ (x as f32 / 3.0).sin() * 5.0
|
||||||
|
+ 2.0
|
||||||
|
+ ((7 + x) as f32 / 5.0).sin() * 2.0
|
||||||
|
+ 2.0
|
||||||
|
+ ((9 + x) as f32 / 10.0).cos() * 3.0) as usize;
|
||||||
|
|
||||||
if cur.tree_addr.len() > 0 {
|
if x < w as usize {
|
||||||
status_chars.push(TerminalAtom::new('@', TerminalStyle::fg_color((120, 80, 80)).add(TerminalStyle::bold(true))));
|
plist.push(val);
|
||||||
for x in cur.tree_addr {
|
|
||||||
for c in format!("{}", x).chars() {
|
|
||||||
status_chars.push(TerminalAtom::new(c, TerminalStyle::fg_color((0, 100, 20))));
|
|
||||||
}
|
|
||||||
status_chars.push(TerminalAtom::new('.', TerminalStyle::fg_color((120, 80, 80))));
|
|
||||||
}
|
|
||||||
|
|
||||||
status_chars.push(TerminalAtom::new(':', TerminalStyle::fg_color((120, 80, 80)).add(TerminalStyle::bold(true))));
|
|
||||||
for c in
|
|
||||||
match cur.leaf_mode {
|
|
||||||
ListCursorMode::Insert => "INSERT",
|
|
||||||
ListCursorMode::Select => "SELECT",
|
|
||||||
ListCursorMode::Modify => "MODIFY"
|
|
||||||
}.chars()
|
|
||||||
{
|
|
||||||
status_chars.push(TerminalAtom::new(c, TerminalStyle::fg_color((200, 200, 20))));
|
|
||||||
}
|
|
||||||
status_chars.push(TerminalAtom::new(':', TerminalStyle::fg_color((120, 80, 80)).add(TerminalStyle::bold(true))));
|
|
||||||
} else {
|
} else {
|
||||||
for c in "Press <DN> to enter".chars() {
|
*plist.get_mut(x % (w as usize)) = val;
|
||||||
status_chars.push(TerminalAtom::new(c, TerminalStyle::fg_color((200, 200, 20))));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let ev = term.next_event().await;
|
x += 1;
|
||||||
|
async_std::task::sleep(std::time::Duration::from_millis(10)).await;
|
||||||
|
|
||||||
if let TerminalEvent::Resize(new_size) = ev {
|
if x % (w as usize) == 0 {
|
||||||
cur_size.set(new_size);
|
async_std::task::sleep(std::time::Duration::from_secs(3)).await;
|
||||||
term_port.inner().get_broadcast().notify(&IndexArea::Full);
|
}
|
||||||
continue;
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let plot_port = ViewPort::new();
|
||||||
|
let _plot = crate::plot::Plot::new(plist_vec_port.outer().to_sequence(), plot_port.inner());
|
||||||
|
|
||||||
|
table_buf.insert_iter(vec![
|
||||||
|
(Point2::new(0, 0), magic.clone()),
|
||||||
|
(
|
||||||
|
Point2::new(0, 1),
|
||||||
|
status_chars_port.outer().to_sequence().to_grid_horizontal(),
|
||||||
|
),
|
||||||
|
(Point2::new(0, 2), magic.clone()),
|
||||||
|
(Point2::new(0, 3), process_list_editor.get_term_view()),
|
||||||
|
]);
|
||||||
|
|
||||||
|
let (w, h) = termion::terminal_size().unwrap();
|
||||||
|
|
||||||
|
compositor.write().unwrap().push(
|
||||||
|
plot_port
|
||||||
|
.outer()
|
||||||
|
.map_item(|pt, a| {
|
||||||
|
a.add_style_back(TerminalStyle::fg_color((
|
||||||
|
255 - pt.y as u8 * 8,
|
||||||
|
100,
|
||||||
|
pt.y as u8 * 15,
|
||||||
|
)))
|
||||||
|
})
|
||||||
|
.offset(Vector2::new(0, h as i16 - 20)),
|
||||||
|
);
|
||||||
|
|
||||||
|
compositor
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.push(monstera::make_monstera().offset(Vector2::new(w as i16 - 38, 0)));
|
||||||
|
|
||||||
|
compositor
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.push(table_port.outer().flatten().offset(Vector2::new(3, 0)));
|
||||||
|
|
||||||
|
process_list_editor.goto(TreeCursor {
|
||||||
|
leaf_mode: ListCursorMode::Insert,
|
||||||
|
tree_addr: vec![0],
|
||||||
|
});
|
||||||
|
|
||||||
|
let tp = term_port.clone();
|
||||||
|
async_std::task::spawn(async move {
|
||||||
|
loop {
|
||||||
|
tp.update();
|
||||||
|
async_std::task::sleep(std::time::Duration::from_millis(10)).await;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
loop {
|
||||||
|
status_chars.clear();
|
||||||
|
let cur = process_list_editor.get_cursor();
|
||||||
|
|
||||||
|
if cur.tree_addr.len() > 0 {
|
||||||
|
status_chars.push(TerminalAtom::new(
|
||||||
|
'@',
|
||||||
|
TerminalStyle::fg_color((120, 80, 80)).add(TerminalStyle::bold(true)),
|
||||||
|
));
|
||||||
|
for x in cur.tree_addr {
|
||||||
|
for c in format!("{}", x).chars() {
|
||||||
|
status_chars
|
||||||
|
.push(TerminalAtom::new(c, TerminalStyle::fg_color((0, 100, 20))));
|
||||||
|
}
|
||||||
|
status_chars.push(TerminalAtom::new(
|
||||||
|
'.',
|
||||||
|
TerminalStyle::fg_color((120, 80, 80)),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(process_editor) = process_list_editor.get_item() {
|
status_chars.push(TerminalAtom::new(
|
||||||
let mut pe = process_editor.write().unwrap();
|
':',
|
||||||
if pe.is_captured() {
|
TerminalStyle::fg_color((120, 80, 80)).add(TerminalStyle::bold(true)),
|
||||||
if let TerminalEditorResult::Exit = pe.handle_terminal_event(&ev) {
|
));
|
||||||
drop(pe);
|
for c in match cur.leaf_mode {
|
||||||
process_list_editor.up();
|
ListCursorMode::Insert => "INSERT",
|
||||||
process_list_editor.nexd();
|
ListCursorMode::Select => "SELECT",
|
||||||
}
|
ListCursorMode::Modify => "MODIFY",
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
.chars()
|
||||||
|
{
|
||||||
|
status_chars.push(TerminalAtom::new(
|
||||||
|
c,
|
||||||
|
TerminalStyle::fg_color((200, 200, 20)),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
status_chars.push(TerminalAtom::new(
|
||||||
|
':',
|
||||||
|
TerminalStyle::fg_color((120, 80, 80)).add(TerminalStyle::bold(true)),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
for c in "Press <DN> to enter".chars() {
|
||||||
|
status_chars.push(TerminalAtom::new(
|
||||||
|
c,
|
||||||
|
TerminalStyle::fg_color((200, 200, 20)),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match ev {
|
let ev = term.next_event().await;
|
||||||
TerminalEvent::Input(Event::Key(Key::Ctrl('d'))) => break,
|
|
||||||
TerminalEvent::Input(Event::Key(Key::Ctrl('l'))) => {
|
if let TerminalEvent::Resize(new_size) = ev {
|
||||||
process_list_editor.goto(TreeCursor {
|
cur_size.set(new_size);
|
||||||
leaf_mode: ListCursorMode::Insert,
|
term_port.inner().get_broadcast().notify(&IndexArea::Full);
|
||||||
tree_addr: vec![ 0 ]
|
continue;
|
||||||
});
|
}
|
||||||
process_list_editor.data.clear();
|
|
||||||
},
|
if let Some(process_editor) = process_list_editor.get_item() {
|
||||||
TerminalEvent::Input(Event::Key(Key::Left)) => {
|
let mut pe = process_editor.write().unwrap();
|
||||||
process_list_editor.pxev();
|
if pe.is_captured() {
|
||||||
}
|
if let TerminalEditorResult::Exit = pe.handle_terminal_event(&ev) {
|
||||||
TerminalEvent::Input(Event::Key(Key::Right)) => {
|
drop(pe);
|
||||||
|
process_list_editor.up();
|
||||||
process_list_editor.nexd();
|
process_list_editor.nexd();
|
||||||
}
|
}
|
||||||
TerminalEvent::Input(Event::Key(Key::Up)) => {
|
continue;
|
||||||
if process_list_editor.up() == TreeNavResult::Exit {
|
}
|
||||||
process_list_editor.dn();
|
}
|
||||||
process_list_editor.goto_home();
|
|
||||||
}
|
match ev {
|
||||||
}
|
TerminalEvent::Input(Event::Key(Key::Ctrl('d'))) => break,
|
||||||
TerminalEvent::Input(Event::Key(Key::Down)) => {
|
TerminalEvent::Input(Event::Key(Key::Ctrl('l'))) => {
|
||||||
if process_list_editor.dn() == TreeNavResult::Continue {
|
process_list_editor.goto(TreeCursor {
|
||||||
process_list_editor.goto_home();
|
leaf_mode: ListCursorMode::Insert,
|
||||||
}
|
tree_addr: vec![0],
|
||||||
}
|
});
|
||||||
TerminalEvent::Input(Event::Key(Key::Home)) => {
|
process_list_editor.clear();
|
||||||
|
}
|
||||||
|
TerminalEvent::Input(Event::Key(Key::Left)) => {
|
||||||
|
process_list_editor.pxev();
|
||||||
|
}
|
||||||
|
TerminalEvent::Input(Event::Key(Key::Right)) => {
|
||||||
|
process_list_editor.nexd();
|
||||||
|
}
|
||||||
|
TerminalEvent::Input(Event::Key(Key::Up)) => {
|
||||||
|
if process_list_editor.up() == TreeNavResult::Exit {
|
||||||
|
process_list_editor.dn();
|
||||||
process_list_editor.goto_home();
|
process_list_editor.goto_home();
|
||||||
}
|
}
|
||||||
TerminalEvent::Input(Event::Key(Key::End)) => {
|
}
|
||||||
process_list_editor.goto_end();
|
TerminalEvent::Input(Event::Key(Key::Down)) => {
|
||||||
|
if process_list_editor.dn() == TreeNavResult::Continue {
|
||||||
|
process_list_editor.goto_home();
|
||||||
}
|
}
|
||||||
ev => {
|
}
|
||||||
if process_list_editor.get_cursor().leaf_mode == ListCursorMode::Select {
|
TerminalEvent::Input(Event::Key(Key::Home)) => {
|
||||||
match ev {
|
process_list_editor.goto_home();
|
||||||
TerminalEvent::Input(Event::Key(Key::Char('l'))) => { process_list_editor.up(); },
|
}
|
||||||
TerminalEvent::Input(Event::Key(Key::Char('a'))) => { process_list_editor.dn(); },
|
TerminalEvent::Input(Event::Key(Key::End)) => {
|
||||||
TerminalEvent::Input(Event::Key(Key::Char('i'))) => { process_list_editor.pxev(); },
|
process_list_editor.goto_end();
|
||||||
TerminalEvent::Input(Event::Key(Key::Char('e'))) => { process_list_editor.nexd(); },
|
}
|
||||||
TerminalEvent::Input(Event::Key(Key::Char('u'))) => { process_list_editor.goto_home(); },
|
ev => {
|
||||||
TerminalEvent::Input(Event::Key(Key::Char('o'))) => { process_list_editor.goto_end(); },
|
if process_list_editor.get_cursor().leaf_mode == ListCursorMode::Select {
|
||||||
_ => {
|
match ev {
|
||||||
process_list_editor.handle_terminal_event(&ev);
|
TerminalEvent::Input(Event::Key(Key::Char('l'))) => {
|
||||||
}
|
process_list_editor.up();
|
||||||
}
|
}
|
||||||
} else {
|
TerminalEvent::Input(Event::Key(Key::Char('a'))) => {
|
||||||
if let TerminalEditorResult::Exit = process_list_editor.handle_terminal_event(&ev) {
|
process_list_editor.dn();
|
||||||
|
}
|
||||||
|
TerminalEvent::Input(Event::Key(Key::Char('i'))) => {
|
||||||
|
process_list_editor.pxev();
|
||||||
|
}
|
||||||
|
TerminalEvent::Input(Event::Key(Key::Char('e'))) => {
|
||||||
process_list_editor.nexd();
|
process_list_editor.nexd();
|
||||||
}
|
}
|
||||||
|
TerminalEvent::Input(Event::Key(Key::Char('u'))) => {
|
||||||
|
process_list_editor.goto_home();
|
||||||
|
}
|
||||||
|
TerminalEvent::Input(Event::Key(Key::Char('o'))) => {
|
||||||
|
process_list_editor.goto_end();
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
process_list_editor.handle_terminal_event(&ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let TerminalEditorResult::Exit =
|
||||||
|
process_list_editor.handle_terminal_event(&ev)
|
||||||
|
{
|
||||||
|
process_list_editor.nexd();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
drop(term);
|
|
||||||
drop(term_port);
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
drop(term);
|
||||||
|
drop(term_port);
|
||||||
|
});
|
||||||
|
|
||||||
term_writer.show().await.expect("output error!");
|
term_writer.show().await.expect("output error!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,15 @@
|
||||||
|
|
||||||
use {
|
use {
|
||||||
cgmath::Point2,
|
cgmath::Point2,
|
||||||
nested::{
|
nested::{
|
||||||
core::{ViewPort, OuterViewPort},
|
core::{OuterViewPort, ViewPort},
|
||||||
|
terminal::{make_label, TerminalStyle, TerminalView},
|
||||||
vec::VecBuffer,
|
vec::VecBuffer,
|
||||||
terminal::{
|
},
|
||||||
TerminalStyle, TerminalView, make_label
|
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn make_monstera() -> OuterViewPort<dyn TerminalView> {
|
pub fn make_monstera() -> OuterViewPort<dyn TerminalView> {
|
||||||
let monstera_lines_port = ViewPort::new();
|
let monstera_lines_port = ViewPort::new();
|
||||||
let monstera_lines = VecBuffer::with_data(
|
let _monstera_lines = VecBuffer::with_data(
|
||||||
vec![
|
vec![
|
||||||
make_label(" |"),
|
make_label(" |"),
|
||||||
make_label(" |"),
|
make_label(" |"),
|
||||||
|
@ -36,21 +33,19 @@ pub fn make_monstera() -> OuterViewPort<dyn TerminalView> {
|
||||||
make_label(" *. ( | ) .*"),
|
make_label(" *. ( | ) .*"),
|
||||||
make_label(" \\_ . | . _/"),
|
make_label(" \\_ . | . _/"),
|
||||||
make_label(" \\ | /"),
|
make_label(" \\ | /"),
|
||||||
make_label(" .")
|
make_label(" ."),
|
||||||
],
|
],
|
||||||
monstera_lines_port.inner()
|
monstera_lines_port.inner(),
|
||||||
);
|
);
|
||||||
|
|
||||||
monstera_lines_port.outer()
|
monstera_lines_port
|
||||||
|
.outer()
|
||||||
.to_sequence()
|
.to_sequence()
|
||||||
.to_index()
|
.to_index()
|
||||||
.map_key(
|
.map_key(
|
||||||
|idx| Point2::new(0 as i16, *idx as i16),
|
|idx| Point2::new(0 as i16, *idx as i16),
|
||||||
|pt| if pt.x == 0 { Some(pt.y as usize) } else { None }
|
|pt| if pt.x == 0 { Some(pt.y as usize) } else { None },
|
||||||
)
|
)
|
||||||
.flatten()
|
.flatten()
|
||||||
.map_item(
|
.map_item(|_p, at| at.add_style_back(TerminalStyle::fg_color((0, 100, 10))))
|
||||||
|p, at| at.add_style_back(TerminalStyle::fg_color((0,100,10)))
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,49 +1,20 @@
|
||||||
use{
|
use {
|
||||||
std::sync::{Arc, RwLock},
|
cgmath::Point2,
|
||||||
cgmath::{Point2, Vector2},
|
|
||||||
termion::event::{Event, Key},
|
|
||||||
nested::{
|
nested::{
|
||||||
core::{
|
core::{InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View},
|
||||||
View,
|
sequence::{SequenceView},
|
||||||
ViewPort,
|
index::{IndexArea, IndexView},
|
||||||
InnerViewPort,
|
projection::ProjectionHelper,
|
||||||
OuterViewPort,
|
terminal::{TerminalAtom, TerminalView},
|
||||||
Observer,
|
|
||||||
ObserverExt,
|
|
||||||
ObserverBroadcast,
|
|
||||||
context::{ReprTree, Object, MorphismType, MorphismMode, Context},
|
|
||||||
port::{UpdateTask}},
|
|
||||||
index::{IndexView, IndexArea},
|
|
||||||
grid::{GridWindowIterator},
|
|
||||||
sequence::{SequenceView, SequenceViewExt},
|
|
||||||
vec::{VecBuffer},
|
|
||||||
integer::{RadixProjection, DigitEditor, PosIntEditor},
|
|
||||||
terminal::{
|
|
||||||
Terminal,
|
|
||||||
TerminalStyle,
|
|
||||||
TerminalAtom,
|
|
||||||
TerminalCompositor,
|
|
||||||
TerminalEvent,
|
|
||||||
make_label,
|
|
||||||
TerminalView,
|
|
||||||
TerminalEditor,
|
|
||||||
TerminalEditorResult
|
|
||||||
},
|
|
||||||
string_editor::{StringEditor},
|
|
||||||
tree_nav::{TreeNav, TreeNavResult, TreeCursor, TerminalTreeEditor},
|
|
||||||
list::{SExprView, ListCursorMode, ListEditor, ListEditorStyle},
|
|
||||||
projection::ProjectionHelper
|
|
||||||
},
|
},
|
||||||
crate::{
|
std::sync::{Arc, RwLock},
|
||||||
process::ProcessLauncher
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Plot {
|
pub struct Plot {
|
||||||
limit: usize,
|
limit: usize,
|
||||||
data: Arc<dyn SequenceView<Item = usize>>,
|
data: Arc<dyn SequenceView<Item = usize>>,
|
||||||
cast: Arc<RwLock<ObserverBroadcast<dyn TerminalView>>>,
|
cast: Arc<RwLock<ObserverBroadcast<dyn TerminalView>>>,
|
||||||
proj_helper: ProjectionHelper<(), Self>
|
proj_helper: ProjectionHelper<(), Self>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl View for Plot {
|
impl View for Plot {
|
||||||
|
@ -58,25 +29,21 @@ impl IndexView<Point2<i16>> for Plot {
|
||||||
if let Some(cur_val) = self.data.get(&(pt.x as usize)) {
|
if let Some(cur_val) = self.data.get(&(pt.x as usize)) {
|
||||||
if cur_val <= self.limit {
|
if cur_val <= self.limit {
|
||||||
if pt.y == (self.limit - cur_val) as i16 {
|
if pt.y == (self.limit - cur_val) as i16 {
|
||||||
return Some(TerminalAtom::from(
|
return Some(TerminalAtom::from(if cur_val < 4 {
|
||||||
if cur_val < 4 { 'o' }
|
'o'
|
||||||
else if cur_val < 8 { 'O' }
|
} else if cur_val < 8 {
|
||||||
else { '*' }
|
'O'
|
||||||
));
|
} else {
|
||||||
|
'*'
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if pt.x > 0 {
|
if pt.x > 0 {
|
||||||
if let Some(prev_val) = self.data.get(&((pt.x-1) as usize)) {
|
if let Some(prev_val) = self.data.get(&((pt.x - 1) as usize)) {
|
||||||
if
|
if (pt.y > (self.limit - prev_val) as i16
|
||||||
(
|
&& pt.y < (self.limit - cur_val) as i16)
|
||||||
pt.y > (self.limit - prev_val) as i16 &&
|
|| (pt.y < (self.limit - prev_val) as i16
|
||||||
pt.y < (self.limit - cur_val) as i16
|
&& pt.y > (self.limit - cur_val) as i16)
|
||||||
)
|
|
||||||
||
|
|
||||||
(
|
|
||||||
pt.y < (self.limit - prev_val) as i16 &&
|
|
||||||
pt.y > (self.limit - cur_val) as i16
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
return Some(TerminalAtom::from('.'));
|
return Some(TerminalAtom::from('.'));
|
||||||
}
|
}
|
||||||
|
@ -89,11 +56,7 @@ impl IndexView<Point2<i16>> for Plot {
|
||||||
|
|
||||||
fn area(&self) -> IndexArea<Point2<i16>> {
|
fn area(&self) -> IndexArea<Point2<i16>> {
|
||||||
IndexArea::Range(
|
IndexArea::Range(
|
||||||
Point2::new(0,0)
|
Point2::new(0, 0)..=Point2::new(self.data.len().unwrap_or(0) as i16, self.limit as i16),
|
||||||
..= Point2::new(
|
|
||||||
self.data.len().unwrap_or(0) as i16,
|
|
||||||
self.limit as i16
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,34 +64,27 @@ impl IndexView<Point2<i16>> for Plot {
|
||||||
impl Plot {
|
impl Plot {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
data_port: OuterViewPort<dyn SequenceView<Item = usize>>,
|
data_port: OuterViewPort<dyn SequenceView<Item = usize>>,
|
||||||
out_port: InnerViewPort<dyn TerminalView>
|
out_port: InnerViewPort<dyn TerminalView>,
|
||||||
) -> Arc<RwLock<Self>> {
|
) -> Arc<RwLock<Self>> {
|
||||||
let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone());
|
let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone());
|
||||||
let proj = Arc::new(RwLock::new(
|
let proj = Arc::new(RwLock::new(Plot {
|
||||||
Plot {
|
data: proj_helper.new_sequence_arg((), data_port, |s: &mut Self, idx| {
|
||||||
data: proj_helper.new_sequence_arg(
|
let val = s.data.get(idx).unwrap_or(0);
|
||||||
(),
|
|
||||||
data_port,
|
|
||||||
|s: &mut Self, idx| {
|
|
||||||
let val = s.data.get(idx).unwrap_or(0);
|
|
||||||
|
|
||||||
if val > s.limit {
|
if val > s.limit {
|
||||||
s.limit = val;
|
s.limit = val;
|
||||||
s.cast.notify(&s.area());
|
s.cast.notify(&s.area());
|
||||||
} else {
|
} else {
|
||||||
s.cast.notify(&IndexArea::Range(
|
s.cast.notify(&IndexArea::Range(
|
||||||
Point2::new(*idx as i16, 0)
|
Point2::new(*idx as i16, 0)..=Point2::new(*idx as i16, s.limit as i16),
|
||||||
..= Point2::new(*idx as i16, s.limit as i16)
|
));
|
||||||
));
|
}
|
||||||
}
|
}),
|
||||||
}
|
|
||||||
),
|
|
||||||
|
|
||||||
limit: 0,
|
limit: 0,
|
||||||
cast: out_port.get_broadcast(),
|
cast: out_port.get_broadcast(),
|
||||||
proj_helper
|
proj_helper,
|
||||||
}
|
}));
|
||||||
));
|
|
||||||
|
|
||||||
proj.write().unwrap().proj_helper.set_proj(&proj);
|
proj.write().unwrap().proj_helper.set_proj(&proj);
|
||||||
out_port.set_view(Some(proj.clone()));
|
out_port.set_view(Some(proj.clone()));
|
||||||
|
@ -136,4 +92,3 @@ impl Plot {
|
||||||
proj
|
proj
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,39 +1,41 @@
|
||||||
use {
|
use {
|
||||||
std::{
|
crate::pty::{PTYStatus, PTY},
|
||||||
sync::Arc,
|
|
||||||
process::Command,
|
|
||||||
os::unix::io::{FromRawFd, AsRawFd},
|
|
||||||
},
|
|
||||||
std::sync::RwLock,
|
|
||||||
termion::event::{Key, Event},
|
|
||||||
cgmath::Point2,
|
|
||||||
nested::{
|
nested::{
|
||||||
core::{ViewPort, OuterViewPort, InnerViewPort, Observer},
|
core::{OuterViewPort, ViewPort},
|
||||||
singleton::{SingletonView, SingletonBuffer},
|
list::{sexpr::ListDecoration, ListCursorMode, ListEditor, ListEditorStyle},
|
||||||
sequence::{SequenceView, SequenceViewExt},
|
sequence::{SequenceView, SequenceViewExt},
|
||||||
index::buffer::IndexBuffer,
|
singleton::SingletonView,
|
||||||
vec::VecBuffer,
|
|
||||||
terminal::{TerminalAtom, TerminalStyle, TerminalView, TerminalEvent, TerminalEditor, TerminalEditorResult, make_label},
|
|
||||||
tree_nav::{TreeNav, TreeNavResult, TerminalTreeEditor, TreeCursor},
|
|
||||||
list::{ListCursorMode, ListEditor, ListEditorStyle, sexpr::ListDecoration},
|
|
||||||
string_editor::CharEditor,
|
string_editor::CharEditor,
|
||||||
|
terminal::{
|
||||||
|
TerminalAtom, TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle,
|
||||||
|
TerminalView,
|
||||||
|
},
|
||||||
|
tree_nav::{TerminalTreeEditor, TreeCursor, TreeNav, TreeNavResult},
|
||||||
},
|
},
|
||||||
crate::pty::{PTY, PTYStatus}
|
std::sync::Arc,
|
||||||
|
std::sync::RwLock,
|
||||||
|
termion::event::{Event, Key},
|
||||||
};
|
};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
pub struct ProcessArg {
|
pub struct ProcessArg {
|
||||||
editor: ListEditor< CharEditor,
|
editor:
|
||||||
Box<dyn Fn() -> Arc<RwLock<CharEditor>> + Send + Sync + 'static> >
|
ListEditor<CharEditor, Box<dyn Fn() -> Arc<RwLock<CharEditor>> + Send + Sync + 'static>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProcessArg {
|
impl ProcessArg {
|
||||||
pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = char>> {
|
pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = char>> {
|
||||||
self.editor.get_data_port()
|
self.editor.get_data_port().map(|char_editor| {
|
||||||
.map(
|
char_editor
|
||||||
|char_editor| char_editor.read().unwrap().get_data_port().get_view().unwrap().get().unwrap()
|
.read()
|
||||||
)
|
.unwrap()
|
||||||
|
.get_data_port()
|
||||||
|
.get_view()
|
||||||
|
.unwrap()
|
||||||
|
.get()
|
||||||
|
.unwrap()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,41 +49,56 @@ impl TerminalEditor for ProcessArg {
|
||||||
|
|
||||||
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
||||||
match event {
|
match event {
|
||||||
TerminalEvent::Input(Event::Key(Key::Char(' '))) |
|
TerminalEvent::Input(Event::Key(Key::Char(' ')))
|
||||||
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
|
| TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
|
||||||
self.editor.up();
|
self.editor.up();
|
||||||
TerminalEditorResult::Exit
|
TerminalEditorResult::Exit
|
||||||
}
|
}
|
||||||
|
|
||||||
event => self.editor.handle_terminal_event(event)
|
event => self.editor.handle_terminal_event(event),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TreeNav for ProcessArg {
|
impl TreeNav for ProcessArg {
|
||||||
fn get_cursor(&self) -> TreeCursor { self.editor.get_cursor() }
|
fn get_cursor(&self) -> TreeCursor {
|
||||||
fn goto(&mut self, cur: TreeCursor) -> TreeNavResult { self.editor.goto(cur) }
|
self.editor.get_cursor()
|
||||||
fn goto_home(&mut self) -> TreeNavResult { self.editor.goto_home() }
|
}
|
||||||
fn goto_end(&mut self) -> TreeNavResult { self.editor.goto_end() }
|
fn goto(&mut self, cur: TreeCursor) -> TreeNavResult {
|
||||||
fn pxev(&mut self) -> TreeNavResult { self.editor.pxev() }
|
self.editor.goto(cur)
|
||||||
fn nexd(&mut self) -> TreeNavResult { self.editor.nexd() }
|
}
|
||||||
fn up(&mut self) -> TreeNavResult { self.editor.up() }
|
fn goto_home(&mut self) -> TreeNavResult {
|
||||||
fn dn(&mut self) -> TreeNavResult { self.editor.dn() }
|
self.editor.goto_home()
|
||||||
|
}
|
||||||
|
fn goto_end(&mut self) -> TreeNavResult {
|
||||||
|
self.editor.goto_end()
|
||||||
|
}
|
||||||
|
fn pxev(&mut self) -> TreeNavResult {
|
||||||
|
self.editor.pxev()
|
||||||
|
}
|
||||||
|
fn nexd(&mut self) -> TreeNavResult {
|
||||||
|
self.editor.nexd()
|
||||||
|
}
|
||||||
|
fn up(&mut self) -> TreeNavResult {
|
||||||
|
self.editor.up()
|
||||||
|
}
|
||||||
|
fn dn(&mut self) -> TreeNavResult {
|
||||||
|
self.editor.dn()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ProcessLauncher {
|
pub struct ProcessLauncher {
|
||||||
cmd_editor: ListEditor<
|
cmd_editor:
|
||||||
ProcessArg, Box<dyn Fn() -> Arc<RwLock<ProcessArg>> + Send + Sync + 'static>
|
ListEditor<ProcessArg, Box<dyn Fn() -> Arc<RwLock<ProcessArg>> + Send + Sync + 'static>>,
|
||||||
>,
|
|
||||||
pty: Option<crate::pty::PTY>,
|
pty: Option<crate::pty::PTY>,
|
||||||
ptybox: Arc<RwLock<crate::ascii_box::AsciiBox>>,
|
_ptybox: Arc<RwLock<crate::ascii_box::AsciiBox>>,
|
||||||
suspended: bool,
|
suspended: bool,
|
||||||
|
|
||||||
pty_port: ViewPort<dyn TerminalView>,
|
pty_port: ViewPort<dyn TerminalView>,
|
||||||
status_port: ViewPort<dyn SingletonView<Item = PTYStatus>>,
|
status_port: ViewPort<dyn SingletonView<Item = PTYStatus>>,
|
||||||
|
|
||||||
comp_port: ViewPort<dyn TerminalView>,
|
comp_port: ViewPort<dyn TerminalView>,
|
||||||
compositor: Arc<RwLock<nested::terminal::TerminalCompositor>>
|
_compositor: Arc<RwLock<nested::terminal::TerminalCompositor>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProcessLauncher {
|
impl ProcessLauncher {
|
||||||
|
@ -93,50 +110,45 @@ impl ProcessLauncher {
|
||||||
let compositor = nested::terminal::TerminalCompositor::new(comp_port.inner());
|
let compositor = nested::terminal::TerminalCompositor::new(comp_port.inner());
|
||||||
|
|
||||||
let cmd_editor = ListEditor::new(
|
let cmd_editor = ListEditor::new(
|
||||||
Box::new(
|
Box::new(|| {
|
||||||
|| {
|
Arc::new(RwLock::new(ProcessArg {
|
||||||
Arc::new(RwLock::new(ProcessArg {
|
editor: ListEditor::new(
|
||||||
editor: ListEditor::new(
|
Box::new(|| Arc::new(RwLock::new(CharEditor::new()))),
|
||||||
Box::new(
|
ListEditorStyle::Plain,
|
||||||
|| {
|
),
|
||||||
Arc::new(RwLock::new(CharEditor::new()))
|
}))
|
||||||
}
|
}) as Box<dyn Fn() -> Arc<RwLock<ProcessArg>> + Send + Sync>,
|
||||||
),
|
ListEditorStyle::Plain,
|
||||||
ListEditorStyle::Plain)
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
) as Box::<dyn Fn() -> Arc<RwLock<ProcessArg>> + Send + Sync>,
|
|
||||||
ListEditorStyle::Plain
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
compositor.write().unwrap().push(
|
compositor.write().unwrap().push(
|
||||||
box_port.outer()
|
box_port
|
||||||
.map_item(|_idx, x| x.add_style_back(TerminalStyle::fg_color((90, 120, 100))))
|
.outer()
|
||||||
|
.map_item(|_idx, x| x.add_style_back(TerminalStyle::fg_color((90, 120, 100)))),
|
||||||
);
|
);
|
||||||
compositor.write().unwrap().push(
|
compositor.write().unwrap().push(
|
||||||
cmd_editor
|
cmd_editor
|
||||||
.get_seg_seq_view()
|
.get_seg_seq_view()
|
||||||
.decorate("$(", ")", " ", 0)
|
.decorate("$(", ")", " ", 0)
|
||||||
.to_grid_horizontal()
|
.to_grid_horizontal()
|
||||||
.flatten()
|
.flatten(),
|
||||||
);
|
);
|
||||||
|
|
||||||
ProcessLauncher {
|
ProcessLauncher {
|
||||||
cmd_editor,
|
cmd_editor,
|
||||||
pty: None,
|
pty: None,
|
||||||
ptybox: crate::ascii_box::AsciiBox::new(
|
_ptybox: crate::ascii_box::AsciiBox::new(
|
||||||
cgmath::Vector2::new(0, 0),
|
cgmath::Vector2::new(0, 0),
|
||||||
pty_port.outer()
|
pty_port.outer().map_item(|_, a: &TerminalAtom| {
|
||||||
.map_item(|_,a:&TerminalAtom| a.add_style_back(TerminalStyle::fg_color((230, 230, 230)))),
|
a.add_style_back(TerminalStyle::fg_color((230, 230, 230)))
|
||||||
box_port.inner()
|
}),
|
||||||
|
box_port.inner(),
|
||||||
),
|
),
|
||||||
suspended: false,
|
suspended: false,
|
||||||
pty_port,
|
pty_port,
|
||||||
status_port,
|
status_port,
|
||||||
comp_port,
|
comp_port,
|
||||||
compositor
|
_compositor: compositor,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,8 +156,15 @@ impl ProcessLauncher {
|
||||||
let mut strings = Vec::new();
|
let mut strings = Vec::new();
|
||||||
|
|
||||||
let v = self.cmd_editor.get_data_port().get_view().unwrap();
|
let v = self.cmd_editor.get_data_port().get_view().unwrap();
|
||||||
for i in 0 .. v.len().unwrap_or(0) {
|
for i in 0..v.len().unwrap_or(0) {
|
||||||
let arg_view = v.get(&i).unwrap().read().unwrap().get_data_port().get_view().unwrap();
|
let arg_view = v
|
||||||
|
.get(&i)
|
||||||
|
.unwrap()
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.get_data_port()
|
||||||
|
.get_view()
|
||||||
|
.unwrap();
|
||||||
strings.push(arg_view.iter().collect::<String>());
|
strings.push(arg_view.iter().collect::<String>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,10 +176,15 @@ impl ProcessLauncher {
|
||||||
|
|
||||||
self.cmd_editor.goto(TreeCursor {
|
self.cmd_editor.goto(TreeCursor {
|
||||||
leaf_mode: ListCursorMode::Insert,
|
leaf_mode: ListCursorMode::Insert,
|
||||||
tree_addr: vec![]
|
tree_addr: vec![],
|
||||||
});
|
});
|
||||||
|
|
||||||
self.pty = PTY::new(cmd, cgmath::Vector2::new(120, 40), self.pty_port.inner(), self.status_port.inner());
|
self.pty = PTY::new(
|
||||||
|
cmd,
|
||||||
|
cgmath::Vector2::new(120, 40),
|
||||||
|
self.pty_port.inner(),
|
||||||
|
self.status_port.inner(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,9 +199,8 @@ impl TerminalEditor for ProcessLauncher {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
||||||
|
|
||||||
// todo: move to observer of status view
|
// todo: move to observer of status view
|
||||||
if let PTYStatus::Done{ status } = self.status_port.outer().get_view().get() {
|
if let PTYStatus::Done { status: _ } = self.status_port.outer().get_view().get() {
|
||||||
self.pty = None;
|
self.pty = None;
|
||||||
self.suspended = false;
|
self.suspended = false;
|
||||||
}
|
}
|
||||||
|
@ -185,7 +208,7 @@ impl TerminalEditor for ProcessLauncher {
|
||||||
match event {
|
match event {
|
||||||
TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) => {
|
TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) => {
|
||||||
// todo: sigterm instead of kill?
|
// todo: sigterm instead of kill?
|
||||||
if let Some(mut pty) = self.pty.as_mut() {
|
if let Some(pty) = self.pty.as_mut() {
|
||||||
pty.kill();
|
pty.kill();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,15 +216,15 @@ impl TerminalEditor for ProcessLauncher {
|
||||||
self.suspended = false;
|
self.suspended = false;
|
||||||
self.cmd_editor.goto(TreeCursor {
|
self.cmd_editor.goto(TreeCursor {
|
||||||
leaf_mode: ListCursorMode::Insert,
|
leaf_mode: ListCursorMode::Insert,
|
||||||
tree_addr: vec![]
|
tree_addr: vec![],
|
||||||
});
|
});
|
||||||
TerminalEditorResult::Exit
|
TerminalEditorResult::Exit
|
||||||
},
|
}
|
||||||
TerminalEvent::Input(Event::Key(Key::Ctrl('z'))) => {
|
TerminalEvent::Input(Event::Key(Key::Ctrl('z'))) => {
|
||||||
self.suspended = true;
|
self.suspended = true;
|
||||||
self.cmd_editor.goto(TreeCursor {
|
self.cmd_editor.goto(TreeCursor {
|
||||||
leaf_mode: ListCursorMode::Insert,
|
leaf_mode: ListCursorMode::Insert,
|
||||||
tree_addr: vec![]
|
tree_addr: vec![],
|
||||||
});
|
});
|
||||||
TerminalEditorResult::Exit
|
TerminalEditorResult::Exit
|
||||||
}
|
}
|
||||||
|
@ -216,7 +239,7 @@ impl TerminalEditor for ProcessLauncher {
|
||||||
self.launch_pty();
|
self.launch_pty();
|
||||||
TerminalEditorResult::Continue
|
TerminalEditorResult::Continue
|
||||||
}
|
}
|
||||||
event => self.cmd_editor.handle_terminal_event(event)
|
event => self.cmd_editor.handle_terminal_event(event),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,7 +254,7 @@ impl TreeNav for ProcessLauncher {
|
||||||
|
|
||||||
fn goto(&mut self, cur: TreeCursor) -> TreeNavResult {
|
fn goto(&mut self, cur: TreeCursor) -> TreeNavResult {
|
||||||
self.suspended = false;
|
self.suspended = false;
|
||||||
if let PTYStatus::Done{status} = self.status_port.outer().get_view().get() {
|
if let PTYStatus::Done { status: _ } = self.status_port.outer().get_view().get() {
|
||||||
self.pty = None;
|
self.pty = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,7 +263,7 @@ impl TreeNav for ProcessLauncher {
|
||||||
} else {
|
} else {
|
||||||
self.cmd_editor.goto(TreeCursor {
|
self.cmd_editor.goto(TreeCursor {
|
||||||
leaf_mode: ListCursorMode::Select,
|
leaf_mode: ListCursorMode::Select,
|
||||||
tree_addr: vec![]
|
tree_addr: vec![],
|
||||||
});
|
});
|
||||||
TreeNavResult::Continue
|
TreeNavResult::Continue
|
||||||
}
|
}
|
||||||
|
@ -270,4 +293,3 @@ impl TreeNav for ProcessLauncher {
|
||||||
self.cmd_editor.dn()
|
self.cmd_editor.dn()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
141
shell/src/pty.rs
141
shell/src/pty.rs
|
@ -1,13 +1,12 @@
|
||||||
|
|
||||||
use {
|
use {
|
||||||
std::sync::{Arc, Mutex},
|
|
||||||
termion::event::{Key, Event},
|
|
||||||
cgmath::Vector2,
|
cgmath::Vector2,
|
||||||
nested::{
|
nested::{
|
||||||
core::{InnerViewPort},
|
core::InnerViewPort,
|
||||||
singleton::{SingletonView, SingletonBuffer},
|
singleton::{SingletonBuffer, SingletonView},
|
||||||
terminal::{TerminalView, TerminalEvent, TerminalEditorResult}
|
terminal::{TerminalEditorResult, TerminalEvent, TerminalView},
|
||||||
}
|
},
|
||||||
|
std::sync::{Arc, Mutex},
|
||||||
|
termion::event::{Event, Key},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use portable_pty::CommandBuilder;
|
pub use portable_pty::CommandBuilder;
|
||||||
|
@ -16,15 +15,13 @@ pub use portable_pty::CommandBuilder;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum PTYStatus {
|
pub enum PTYStatus {
|
||||||
Running{ pid: u32 },
|
Running { pid: u32 },
|
||||||
Done{ status: portable_pty::ExitStatus }
|
Done { status: portable_pty::ExitStatus },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PTYStatus {
|
impl Default for PTYStatus {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
PTYStatus::Running {
|
PTYStatus::Running { pid: 0 }
|
||||||
pid: 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +29,7 @@ impl Default for PTYStatus {
|
||||||
|
|
||||||
pub struct PTY {
|
pub struct PTY {
|
||||||
master: Mutex<Box<dyn portable_pty::MasterPty + Send>>,
|
master: Mutex<Box<dyn portable_pty::MasterPty + Send>>,
|
||||||
child: Arc<Mutex<Box<dyn portable_pty::Child + Send + Sync>>>
|
child: Arc<Mutex<Box<dyn portable_pty::Child + Send + Sync>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PTY {
|
impl PTY {
|
||||||
|
@ -40,51 +37,54 @@ impl PTY {
|
||||||
cmd: portable_pty::CommandBuilder,
|
cmd: portable_pty::CommandBuilder,
|
||||||
max_size: Vector2<i16>,
|
max_size: Vector2<i16>,
|
||||||
term_port: InnerViewPort<dyn TerminalView>,
|
term_port: InnerViewPort<dyn TerminalView>,
|
||||||
status_port: InnerViewPort<dyn SingletonView<Item = PTYStatus>>
|
status_port: InnerViewPort<dyn SingletonView<Item = PTYStatus>>,
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
|
|
||||||
// Create a new pty
|
// Create a new pty
|
||||||
let mut pair = portable_pty::native_pty_system().openpty(portable_pty::PtySize {
|
let pair = portable_pty::native_pty_system()
|
||||||
rows: max_size.y as u16,
|
.openpty(portable_pty::PtySize {
|
||||||
cols: max_size.x as u16,
|
rows: max_size.y as u16,
|
||||||
|
cols: max_size.x as u16,
|
||||||
|
|
||||||
// Not all systems support pixel_width, pixel_height,
|
// Not all systems support pixel_width, pixel_height,
|
||||||
// but it is good practice to set it to something
|
// but it is good practice to set it to something
|
||||||
// that matches the size of the selected font. That
|
// that matches the size of the selected font. That
|
||||||
// is more complex than can be shown here in this
|
// is more complex than can be shown here in this
|
||||||
// brief example though!
|
// brief example though!
|
||||||
pixel_width: 0,
|
pixel_width: 0,
|
||||||
pixel_height: 0,
|
pixel_height: 0,
|
||||||
}).unwrap();
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
if let Ok(mut child) = pair.slave.spawn_command(cmd) {
|
if let Ok(child) = pair.slave.spawn_command(cmd) {
|
||||||
let mut reader = pair.master.try_clone_reader().unwrap();
|
let mut reader = pair.master.try_clone_reader().unwrap();
|
||||||
let mut status_buf = SingletonBuffer::new(PTYStatus::Running{ pid: child.process_id().expect("") }, status_port);
|
let mut status_buf = SingletonBuffer::new(
|
||||||
|
PTYStatus::Running {
|
||||||
|
pid: child.process_id().expect(""),
|
||||||
|
},
|
||||||
|
status_port,
|
||||||
|
);
|
||||||
|
|
||||||
let child = Arc::new(Mutex::new(child));
|
let child = Arc::new(Mutex::new(child));
|
||||||
|
|
||||||
async_std::task::spawn_blocking(
|
async_std::task::spawn_blocking(move || {
|
||||||
move || {
|
nested::terminal::ansi_parser::read_ansi_from(&mut reader, max_size, term_port);
|
||||||
nested::terminal::ansi_parser::read_ansi_from(&mut reader, max_size, term_port);
|
});
|
||||||
});
|
|
||||||
|
|
||||||
async_std::task::spawn_blocking({
|
async_std::task::spawn_blocking({
|
||||||
let child = child.clone();
|
let child = child.clone();
|
||||||
move || {
|
move || loop {
|
||||||
loop {
|
if let Ok(Some(status)) = child.lock().unwrap().try_wait() {
|
||||||
if let Ok(Some(status)) = child.lock().unwrap().try_wait() {
|
status_buf.set(PTYStatus::Done { status });
|
||||||
status_buf.set(PTYStatus::Done{ status });
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Some(PTY {
|
Some(PTY {
|
||||||
master: Mutex::new(pair.master),
|
master: Mutex::new(pair.master),
|
||||||
child
|
child,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -92,7 +92,7 @@ impl PTY {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn kill(&mut self) {
|
pub fn kill(&mut self) {
|
||||||
self.child.lock().unwrap().kill();
|
self.child.lock().unwrap().kill().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
pub fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
||||||
|
@ -100,11 +100,11 @@ impl PTY {
|
||||||
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
|
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
|
||||||
self.master.lock().unwrap().write(&[13]).unwrap();
|
self.master.lock().unwrap().write(&[13]).unwrap();
|
||||||
TerminalEditorResult::Continue
|
TerminalEditorResult::Continue
|
||||||
},
|
}
|
||||||
TerminalEvent::Input(Event::Key(Key::Char(c))) => {
|
TerminalEvent::Input(Event::Key(Key::Char(c))) => {
|
||||||
write!(self.master.lock().unwrap(), "{}", c);
|
write!(self.master.lock().unwrap(), "{}", c).unwrap();
|
||||||
TerminalEditorResult::Continue
|
TerminalEditorResult::Continue
|
||||||
},
|
}
|
||||||
TerminalEvent::Input(Event::Key(Key::Esc)) => {
|
TerminalEvent::Input(Event::Key(Key::Esc)) => {
|
||||||
self.master.lock().unwrap().write(&[0x1b]).unwrap();
|
self.master.lock().unwrap().write(&[0x1b]).unwrap();
|
||||||
TerminalEditorResult::Continue
|
TerminalEditorResult::Continue
|
||||||
|
@ -114,37 +114,54 @@ impl PTY {
|
||||||
TerminalEditorResult::Continue
|
TerminalEditorResult::Continue
|
||||||
}
|
}
|
||||||
TerminalEvent::Input(Event::Key(Key::F(n))) => {
|
TerminalEvent::Input(Event::Key(Key::F(n))) => {
|
||||||
self.master.lock().unwrap().write(&[
|
self.master
|
||||||
0x1b,
|
.lock()
|
||||||
0x0a,
|
.unwrap()
|
||||||
match n {
|
.write(&[
|
||||||
11 => 133,
|
0x1b,
|
||||||
12 => 134,
|
0x0a,
|
||||||
n => 58 + n
|
match n {
|
||||||
}
|
11 => 133,
|
||||||
]).unwrap();
|
12 => 134,
|
||||||
|
n => 58 + n,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
.unwrap();
|
||||||
TerminalEditorResult::Continue
|
TerminalEditorResult::Continue
|
||||||
}
|
}
|
||||||
TerminalEvent::Input(Event::Key(Key::Up)) => {
|
TerminalEvent::Input(Event::Key(Key::Up)) => {
|
||||||
self.master.lock().unwrap().write(&[b'\x1B', b'[', b'A']).unwrap();
|
self.master
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.write(&[b'\x1B', b'[', b'A'])
|
||||||
|
.unwrap();
|
||||||
TerminalEditorResult::Continue
|
TerminalEditorResult::Continue
|
||||||
}
|
}
|
||||||
TerminalEvent::Input(Event::Key(Key::Down)) => {
|
TerminalEvent::Input(Event::Key(Key::Down)) => {
|
||||||
self.master.lock().unwrap().write(&[b'\x1B', b'[', b'B']).unwrap();
|
self.master
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.write(&[b'\x1B', b'[', b'B'])
|
||||||
|
.unwrap();
|
||||||
TerminalEditorResult::Continue
|
TerminalEditorResult::Continue
|
||||||
}
|
}
|
||||||
TerminalEvent::Input(Event::Key(Key::Right)) => {
|
TerminalEvent::Input(Event::Key(Key::Right)) => {
|
||||||
self.master.lock().unwrap().write(&[b'\x1B', b'[', b'C']).unwrap();
|
self.master
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.write(&[b'\x1B', b'[', b'C'])
|
||||||
|
.unwrap();
|
||||||
TerminalEditorResult::Continue
|
TerminalEditorResult::Continue
|
||||||
}
|
}
|
||||||
TerminalEvent::Input(Event::Key(Key::Left)) => {
|
TerminalEvent::Input(Event::Key(Key::Left)) => {
|
||||||
self.master.lock().unwrap().write(&[b'\x1B', b'[', b'D']).unwrap();
|
self.master
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.write(&[b'\x1B', b'[', b'D'])
|
||||||
|
.unwrap();
|
||||||
TerminalEditorResult::Continue
|
TerminalEditorResult::Continue
|
||||||
}
|
}
|
||||||
_ => {
|
_ => TerminalEditorResult::Exit,
|
||||||
TerminalEditorResult::Exit
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
#![feature(iter_advance_by)]
|
#![feature(iter_advance_by)]
|
||||||
|
|
||||||
use {
|
use {
|
||||||
|
cgmath::Point2,
|
||||||
|
nested::terminal::{TerminalAtom, TerminalStyle},
|
||||||
std::{
|
std::{
|
||||||
fs::File,
|
fs::File,
|
||||||
|
io::{stdin, Read, Write},
|
||||||
os::unix::io::FromRawFd,
|
os::unix::io::FromRawFd,
|
||||||
io::{Read, Write, stdin}
|
|
||||||
},
|
},
|
||||||
nested::{
|
vte::{Params, Parser, Perform},
|
||||||
terminal::{
|
|
||||||
TerminalAtom,
|
|
||||||
TerminalStyle
|
|
||||||
},
|
|
||||||
},
|
|
||||||
cgmath::Point2,
|
|
||||||
vte::{Params, Parser, Perform}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ColorPalett {
|
struct ColorPalett {
|
||||||
|
@ -24,7 +19,7 @@ struct ColorPalett {
|
||||||
blue: (u8, u8, u8),
|
blue: (u8, u8, u8),
|
||||||
magenta: (u8, u8, u8),
|
magenta: (u8, u8, u8),
|
||||||
cyan: (u8, u8, u8),
|
cyan: (u8, u8, u8),
|
||||||
white: (u8, u8, u8)
|
white: (u8, u8, u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PerfAtom {
|
struct PerfAtom {
|
||||||
|
@ -39,17 +34,16 @@ struct PerfAtom {
|
||||||
|
|
||||||
impl PerfAtom {
|
impl PerfAtom {
|
||||||
fn write_atom(&mut self, pos: Point2<i16>, atom: Option<TerminalAtom>) {
|
fn write_atom(&mut self, pos: Point2<i16>, atom: Option<TerminalAtom>) {
|
||||||
self.out.write(&bincode::serialize(&(pos, atom)).unwrap()).expect("");
|
self.out
|
||||||
|
.write(&bincode::serialize(&(pos, atom)).unwrap())
|
||||||
|
.expect("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Perform for PerfAtom {
|
impl Perform for PerfAtom {
|
||||||
fn print(&mut self, c: char) {
|
fn print(&mut self, c: char) {
|
||||||
//eprintln!("[print] {:?}", c);
|
//eprintln!("[print] {:?}", c);
|
||||||
self.write_atom(
|
self.write_atom(self.cursor, Some(TerminalAtom::new(c, self.style)));
|
||||||
self.cursor,
|
|
||||||
Some(TerminalAtom::new(c, self.style))
|
|
||||||
);
|
|
||||||
|
|
||||||
self.cursor.x += 1;
|
self.cursor.x += 1;
|
||||||
if self.cursor.x > self.term_width {
|
if self.cursor.x > self.term_width {
|
||||||
|
@ -64,7 +58,7 @@ impl Perform for PerfAtom {
|
||||||
b'\n' => {
|
b'\n' => {
|
||||||
self.cursor.x = 0;
|
self.cursor.x = 0;
|
||||||
self.cursor.y += 1;
|
self.cursor.y += 1;
|
||||||
},
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,7 +79,10 @@ impl Perform for PerfAtom {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) {
|
fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) {
|
||||||
eprintln!("[osc_dispatch] params={:?} bell_terminated={}", params, bell_terminated);
|
eprintln!(
|
||||||
|
"[osc_dispatch] params={:?} bell_terminated={}",
|
||||||
|
params, bell_terminated
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn csi_dispatch(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) {
|
fn csi_dispatch(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) {
|
||||||
|
@ -98,29 +95,60 @@ impl Perform for PerfAtom {
|
||||||
|
|
||||||
match c {
|
match c {
|
||||||
// Set SGR
|
// Set SGR
|
||||||
'm' => while let Some(n) = piter.next() {
|
'm' => {
|
||||||
match n[0] {
|
while let Some(n) = piter.next() {
|
||||||
|
match n[0] {
|
||||||
0 => self.style = TerminalStyle::default(),
|
0 => self.style = TerminalStyle::default(),
|
||||||
1 => self.style = self.style.add(TerminalStyle::bold(true)),
|
1 => self.style = self.style.add(TerminalStyle::bold(true)),
|
||||||
3 => self.style = self.style.add(TerminalStyle::italic(true)),
|
3 => self.style = self.style.add(TerminalStyle::italic(true)),
|
||||||
4 => self.style = self.style.add(TerminalStyle::underline(true)),
|
4 => self.style = self.style.add(TerminalStyle::underline(true)),
|
||||||
|
|
||||||
30 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.black)),
|
30 => {
|
||||||
40 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.black)),
|
self.style = self.style.add(TerminalStyle::fg_color(self.colors.black))
|
||||||
|
}
|
||||||
|
40 => {
|
||||||
|
self.style = self.style.add(TerminalStyle::bg_color(self.colors.black))
|
||||||
|
}
|
||||||
31 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.red)),
|
31 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.red)),
|
||||||
41 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.red)),
|
41 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.red)),
|
||||||
32 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.green)),
|
32 => {
|
||||||
42 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.green)),
|
self.style = self.style.add(TerminalStyle::fg_color(self.colors.green))
|
||||||
33 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.yellow)),
|
}
|
||||||
43 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.yellow)),
|
42 => {
|
||||||
34 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.blue)),
|
self.style = self.style.add(TerminalStyle::bg_color(self.colors.green))
|
||||||
44 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.blue)),
|
}
|
||||||
35 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.magenta)),
|
33 => {
|
||||||
45 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.magenta)),
|
self.style = self.style.add(TerminalStyle::fg_color(self.colors.yellow))
|
||||||
36 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.cyan)),
|
}
|
||||||
46 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.cyan)),
|
43 => {
|
||||||
37 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.white)),
|
self.style = self.style.add(TerminalStyle::bg_color(self.colors.yellow))
|
||||||
47 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.white)),
|
}
|
||||||
|
34 => {
|
||||||
|
self.style = self.style.add(TerminalStyle::fg_color(self.colors.blue))
|
||||||
|
}
|
||||||
|
44 => {
|
||||||
|
self.style = self.style.add(TerminalStyle::bg_color(self.colors.blue))
|
||||||
|
}
|
||||||
|
35 => {
|
||||||
|
self.style =
|
||||||
|
self.style.add(TerminalStyle::fg_color(self.colors.magenta))
|
||||||
|
}
|
||||||
|
45 => {
|
||||||
|
self.style =
|
||||||
|
self.style.add(TerminalStyle::bg_color(self.colors.magenta))
|
||||||
|
}
|
||||||
|
36 => {
|
||||||
|
self.style = self.style.add(TerminalStyle::fg_color(self.colors.cyan))
|
||||||
|
}
|
||||||
|
46 => {
|
||||||
|
self.style = self.style.add(TerminalStyle::bg_color(self.colors.cyan))
|
||||||
|
}
|
||||||
|
37 => {
|
||||||
|
self.style = self.style.add(TerminalStyle::fg_color(self.colors.white))
|
||||||
|
}
|
||||||
|
47 => {
|
||||||
|
self.style = self.style.add(TerminalStyle::bg_color(self.colors.white))
|
||||||
|
}
|
||||||
|
|
||||||
38 => {
|
38 => {
|
||||||
let x = piter.next().unwrap();
|
let x = piter.next().unwrap();
|
||||||
|
@ -129,15 +157,21 @@ impl Perform for PerfAtom {
|
||||||
let r = piter.next().unwrap();
|
let r = piter.next().unwrap();
|
||||||
let g = piter.next().unwrap();
|
let g = piter.next().unwrap();
|
||||||
let b = piter.next().unwrap();
|
let b = piter.next().unwrap();
|
||||||
self.style = self.style.add(TerminalStyle::fg_color((r[0] as u8, g[0] as u8, b[30] as u8)))
|
self.style = self.style.add(TerminalStyle::fg_color((
|
||||||
},
|
r[0] as u8,
|
||||||
|
g[0] as u8,
|
||||||
|
b[30] as u8,
|
||||||
|
)))
|
||||||
|
}
|
||||||
5 => {
|
5 => {
|
||||||
let v = piter.next().unwrap();
|
let v = piter.next().unwrap();
|
||||||
self.style = self.style.add(TerminalStyle::fg_color(ansi_colours::rgb_from_ansi256(v[0] as u8)))
|
self.style = self.style.add(TerminalStyle::fg_color(
|
||||||
},
|
ansi_colours::rgb_from_ansi256(v[0] as u8),
|
||||||
|
))
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
48 => {
|
48 => {
|
||||||
let x = piter.next().unwrap();
|
let x = piter.next().unwrap();
|
||||||
|
@ -146,31 +180,50 @@ impl Perform for PerfAtom {
|
||||||
let r = piter.next().unwrap();
|
let r = piter.next().unwrap();
|
||||||
let g = piter.next().unwrap();
|
let g = piter.next().unwrap();
|
||||||
let b = piter.next().unwrap();
|
let b = piter.next().unwrap();
|
||||||
self.style = self.style.add(TerminalStyle::bg_color((r[0] as u8, g[0] as u8, b[30] as u8)))
|
self.style = self.style.add(TerminalStyle::bg_color((
|
||||||
},
|
r[0] as u8,
|
||||||
|
g[0] as u8,
|
||||||
|
b[30] as u8,
|
||||||
|
)))
|
||||||
|
}
|
||||||
5 => {
|
5 => {
|
||||||
let v = piter.next().unwrap();
|
let v = piter.next().unwrap();
|
||||||
self.style = self.style.add(TerminalStyle::bg_color(ansi_colours::rgb_from_ansi256(v[0] as u8)))
|
self.style = self.style.add(TerminalStyle::bg_color(
|
||||||
},
|
ansi_colours::rgb_from_ansi256(v[0] as u8),
|
||||||
|
))
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
'H' => {
|
'H' => {
|
||||||
if let Some(y) = piter.next() { self.cursor.y = y[0] as i16 - 1 };
|
if let Some(y) = piter.next() {
|
||||||
if let Some(x) = piter.next() { self.cursor.x = x[0] as i16 - 1 };
|
self.cursor.y = y[0] as i16 - 1
|
||||||
|
};
|
||||||
|
if let Some(x) = piter.next() {
|
||||||
|
self.cursor.x = x[0] as i16 - 1
|
||||||
|
};
|
||||||
|
|
||||||
eprintln!("cursor at {:?}", self.cursor);
|
eprintln!("cursor at {:?}", self.cursor);
|
||||||
},
|
}
|
||||||
|
|
||||||
'A' => { self.cursor.y -= piter.next().unwrap()[0] as i16; }
|
'A' => {
|
||||||
'B' => { self.cursor.y += piter.next().unwrap()[0] as i16; }
|
self.cursor.y -= piter.next().unwrap()[0] as i16;
|
||||||
'C' => { self.cursor.x += piter.next().unwrap()[0] as i16; }
|
}
|
||||||
'D' => { self.cursor.x -= piter.next().unwrap()[0] as i16; }
|
'B' => {
|
||||||
|
self.cursor.y += piter.next().unwrap()[0] as i16;
|
||||||
|
}
|
||||||
|
'C' => {
|
||||||
|
self.cursor.x += piter.next().unwrap()[0] as i16;
|
||||||
|
}
|
||||||
|
'D' => {
|
||||||
|
self.cursor.x -= piter.next().unwrap()[0] as i16;
|
||||||
|
}
|
||||||
'E' => {
|
'E' => {
|
||||||
self.cursor.x = 0;
|
self.cursor.x = 0;
|
||||||
self.cursor.y += piter.next().unwrap()[0] as i16;
|
self.cursor.y += piter.next().unwrap()[0] as i16;
|
||||||
|
@ -179,15 +232,11 @@ impl Perform for PerfAtom {
|
||||||
'J' => {
|
'J' => {
|
||||||
let x = piter.next().unwrap_or(&[0 as u16; 1]);
|
let x = piter.next().unwrap_or(&[0 as u16; 1]);
|
||||||
match x[0] {
|
match x[0] {
|
||||||
0 => {
|
0 => {}
|
||||||
|
1 => {}
|
||||||
},
|
|
||||||
1 => {
|
|
||||||
|
|
||||||
}
|
|
||||||
2 => {
|
2 => {
|
||||||
for y in 0 .. 100 {
|
for y in 0..100 {
|
||||||
for x in 0 .. self.term_width {
|
for x in 0..self.term_width {
|
||||||
self.write_atom(Point2::new(x, y), None);
|
self.write_atom(Point2::new(x, y), None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -201,27 +250,26 @@ impl Perform for PerfAtom {
|
||||||
'K' => {
|
'K' => {
|
||||||
let x = piter.next().unwrap();
|
let x = piter.next().unwrap();
|
||||||
match x[0] {
|
match x[0] {
|
||||||
|
|
||||||
// clear cursor until end
|
// clear cursor until end
|
||||||
0 => {
|
0 => {
|
||||||
for x in self.cursor.x .. self.term_width {
|
for x in self.cursor.x..self.term_width {
|
||||||
self.write_atom(Point2::new(x, self.cursor.y), None);
|
self.write_atom(Point2::new(x, self.cursor.y), None);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
// clear start until cursor
|
// clear start until cursor
|
||||||
1 => {
|
1 => {
|
||||||
for x in 0 .. self.cursor.x {
|
for x in 0..self.cursor.x {
|
||||||
self.write_atom(Point2::new(x, self.cursor.y), None);
|
self.write_atom(Point2::new(x, self.cursor.y), None);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
// clear entire line
|
// clear entire line
|
||||||
2 => {
|
2 => {
|
||||||
for x in 0 .. self.term_width {
|
for x in 0..self.term_width {
|
||||||
self.write_atom(Point2::new(x, self.cursor.y), None);
|
self.write_atom(Point2::new(x, self.cursor.y), None);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
// invalid
|
// invalid
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -259,8 +307,8 @@ fn main() {
|
||||||
blue: (0, 111, 184),
|
blue: (0, 111, 184),
|
||||||
magenta: (118, 38, 113),
|
magenta: (118, 38, 113),
|
||||||
cyan: (44, 181, 233),
|
cyan: (44, 181, 233),
|
||||||
white: (204, 204, 204)
|
white: (204, 204, 204),
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut buf = [0; 2048];
|
let mut buf = [0; 2048];
|
||||||
|
@ -273,12 +321,11 @@ fn main() {
|
||||||
statemachine.advance(&mut performer, *byte);
|
statemachine.advance(&mut performer, *byte);
|
||||||
performer.out.flush().unwrap();
|
performer.out.flush().unwrap();
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!("err: {}", err);
|
println!("err: {}", err);
|
||||||
break;
|
break;
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
use {
|
use {
|
||||||
std::{
|
cgmath::{Point2, Vector2},
|
||||||
io::{Read, Write, stdout}
|
nested::terminal::{TerminalAtom, TerminalStyle},
|
||||||
},
|
std::io::{stdout, Read, Write},
|
||||||
nested::terminal::{
|
|
||||||
TerminalAtom,
|
|
||||||
TerminalStyle
|
|
||||||
},
|
|
||||||
termion::raw::IntoRawMode,
|
termion::raw::IntoRawMode,
|
||||||
cgmath::{Point2, Vector2}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut out = stdout().into_raw_mode().unwrap();
|
let mut out = stdout().into_raw_mode().unwrap();
|
||||||
write!(out, "{}{}{}",
|
write!(
|
||||||
termion::cursor::Hide,
|
out,
|
||||||
termion::cursor::Goto(1, 1),
|
"{}{}{}",
|
||||||
termion::style::Reset).unwrap();
|
termion::cursor::Hide,
|
||||||
|
termion::cursor::Goto(1, 1),
|
||||||
|
termion::style::Reset
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let mut cur_pos = Point2::<i16>::new(0, 0);
|
let mut cur_pos = Point2::<i16>::new(0, 0);
|
||||||
let mut cur_style = TerminalStyle::default();
|
let mut cur_style = TerminalStyle::default();
|
||||||
|
@ -26,7 +25,12 @@ fn main() {
|
||||||
match bincode::deserialize_from::<_, (Point2<i16>, Option<TerminalAtom>)>(input.by_ref()) {
|
match bincode::deserialize_from::<_, (Point2<i16>, Option<TerminalAtom>)>(input.by_ref()) {
|
||||||
Ok((pos, atom)) => {
|
Ok((pos, atom)) => {
|
||||||
if pos != cur_pos {
|
if pos != cur_pos {
|
||||||
write!(out, "{}", termion::cursor::Goto(pos.x as u16 + 1, pos.y as u16 + 1)).unwrap();
|
write!(
|
||||||
|
out,
|
||||||
|
"{}",
|
||||||
|
termion::cursor::Goto(pos.x as u16 + 1, pos.y as u16 + 1)
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(atom) = atom {
|
if let Some(atom) = atom {
|
||||||
|
@ -47,9 +51,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
match *err {
|
match *err {
|
||||||
bincode::ErrorKind::Io(_io_error) => {
|
bincode::ErrorKind::Io(_io_error) => break,
|
||||||
break
|
|
||||||
}
|
|
||||||
err => {
|
err => {
|
||||||
eprintln!("deserialization error\n{:?}", err);
|
eprintln!("deserialization error\n{:?}", err);
|
||||||
}
|
}
|
||||||
|
@ -63,4 +65,3 @@ fn main() {
|
||||||
write!(out, "{}", termion::cursor::Show).unwrap();
|
write!(out, "{}", termion::cursor::Show).unwrap();
|
||||||
out.flush().unwrap();
|
out.flush().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue