feat: add full async suport
This commit is contained in:
1 parent
2b4e3ae6e9
commit
c884f8c1b8
10 files changed
+168
-89
No files matched your search
@@ -15,4 +15,6 @@ hecs = "0.7.3"
|
||||
ctrlc = "3.2.1"
|
||||
bumpalo = { version = "3.8.0", features = ["boxed"] }
|
||||
stretch2 = { path = "../../Tinkering/stretch2" }
|
||||
tokio = { version = "1.15.0", features = ["full"] }
|
||||
futures = "0.3.19"
|
||||
# stretch2 = { git = "https://github.com/elbaro/stretch2.git" }
|
||||
@@ -19,7 +19,6 @@ static App: FC<()> = |cx| {
|
||||
justify_content: "center",
|
||||
align_items: "center",
|
||||
|
||||
|
||||
"Hello world!"
|
||||
}
|
||||
})
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ fn main() {
|
||||
let mut dom = VirtualDom::new(app);
|
||||
dom.rebuild();
|
||||
|
||||
rink::render_vdom(&dom).unwrap();
|
||||
rink::render_vdom(&mut dom).unwrap();
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ fn main() {
|
||||
let mut dom = VirtualDom::new(app);
|
||||
dom.rebuild();
|
||||
|
||||
rink::render_vdom(&dom).unwrap();
|
||||
rink::render_vdom(&mut dom).unwrap();
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ fn main() {
|
||||
let mut dom = VirtualDom::new(app);
|
||||
dom.rebuild();
|
||||
|
||||
rink::render_vdom(&dom).unwrap();
|
||||
rink::render_vdom(&mut dom).unwrap();
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
|
||||
@@ -4,7 +4,7 @@ fn main() {
|
||||
let mut dom = VirtualDom::new(app);
|
||||
dom.rebuild();
|
||||
|
||||
rink::render_vdom(&dom).unwrap();
|
||||
rink::render_vdom(&mut dom).unwrap();
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ fn main() {
|
||||
let mut dom = VirtualDom::new(app);
|
||||
dom.rebuild();
|
||||
|
||||
rink::render_vdom(&dom).unwrap();
|
||||
rink::render_vdom(&mut dom).unwrap();
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
use dioxus::prelude::*;
|
||||
|
||||
fn main() {
|
||||
let mut dom = VirtualDom::new(app);
|
||||
dom.rebuild();
|
||||
|
||||
rink::render_vdom(&mut dom).unwrap();
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let count = use_state(&cx, || 0);
|
||||
|
||||
use_future(&cx, || {
|
||||
let set_count = count.setter();
|
||||
let mut mycount = 0;
|
||||
let update = cx.schedule_update();
|
||||
async move {
|
||||
loop {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(50)).await;
|
||||
mycount += 1;
|
||||
set_count(mycount);
|
||||
update();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cx.render(rsx! {
|
||||
div { width: "100%",
|
||||
div { width: "50%", height: "5px", background_color: "blue", justify_content: "center", align_items: "center",
|
||||
"Hello {count}!"
|
||||
}
|
||||
div { width: "50%", height: "10px", background_color: "red", justify_content: "center", align_items: "center",
|
||||
"Hello {count}!"
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// use_future(&cx, || {
|
||||
// let set_count = count.setter();
|
||||
// let mut mycount = 0;
|
||||
// let update = cx.schedule_update();
|
||||
// async move {
|
||||
// loop {
|
||||
// tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
||||
// mycount += 1;
|
||||
// set_count(mycount);
|
||||
// update();
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
+1
-1
@@ -4,7 +4,7 @@ fn main() {
|
||||
let mut dom = VirtualDom::new(app);
|
||||
dom.rebuild();
|
||||
|
||||
rink::render_vdom(&dom).unwrap();
|
||||
rink::render_vdom(&mut dom).unwrap();
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
|
||||
+109
-82
@@ -1,14 +1,15 @@
|
||||
use anyhow::Result;
|
||||
use crossterm::{
|
||||
event::{self, DisableMouseCapture, EnableMouseCapture, Event as TermEvent, KeyCode, KeyEvent},
|
||||
event::{DisableMouseCapture, EnableMouseCapture, Event as TermEvent, KeyCode, KeyEvent},
|
||||
execute,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
use dioxus::core::exports::futures_channel::mpsc::unbounded;
|
||||
use dioxus::core::*;
|
||||
use futures::{future::Either, pin_mut, StreamExt};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
io,
|
||||
sync::mpsc,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use stretch2::{prelude::Size, Stretch};
|
||||
@@ -28,22 +29,10 @@ pub struct TuiNode<'a> {
|
||||
pub node: &'a VNode<'a>,
|
||||
}
|
||||
|
||||
pub fn render_vdom(vdom: &VirtualDom) -> Result<()> {
|
||||
/*
|
||||
Get the terminal to calcualte the layout from
|
||||
*/
|
||||
enable_raw_mode().unwrap();
|
||||
ctrlc::set_handler(move || {
|
||||
disable_raw_mode().unwrap();
|
||||
})
|
||||
.expect("Error setting Ctrl-C handler");
|
||||
let mut stdout = std::io::stdout();
|
||||
execute!(stdout, EnterAlternateScreen, EnableMouseCapture).unwrap();
|
||||
let backend = CrosstermBackend::new(io::stdout());
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
|
||||
pub fn render_vdom(vdom: &mut VirtualDom) -> Result<()> {
|
||||
// Setup input handling
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let (tx, mut rx) = unbounded();
|
||||
|
||||
std::thread::spawn(move || {
|
||||
let tick_rate = Duration::from_millis(100);
|
||||
let mut last_tick = Instant::now();
|
||||
@@ -53,93 +42,131 @@ pub fn render_vdom(vdom: &VirtualDom) -> Result<()> {
|
||||
.checked_sub(last_tick.elapsed())
|
||||
.unwrap_or_else(|| Duration::from_secs(0));
|
||||
|
||||
if event::poll(timeout).unwrap() {
|
||||
if let TermEvent::Key(key) = event::read().unwrap() {
|
||||
tx.send(InputEvent::UserInput(key)).unwrap();
|
||||
}
|
||||
if crossterm::event::poll(timeout).unwrap() {
|
||||
let evt = crossterm::event::read().unwrap();
|
||||
tx.unbounded_send(InputEvent::UserInput(evt)).unwrap();
|
||||
}
|
||||
|
||||
if last_tick.elapsed() >= tick_rate {
|
||||
tx.send(InputEvent::Tick).unwrap();
|
||||
tx.unbounded_send(InputEvent::Tick).unwrap();
|
||||
last_tick = Instant::now();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
terminal.clear().unwrap();
|
||||
tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()?
|
||||
.block_on(async {
|
||||
/*
|
||||
Get the terminal to calcualte the layout from
|
||||
*/
|
||||
enable_raw_mode().unwrap();
|
||||
let mut stdout = std::io::stdout();
|
||||
execute!(stdout, EnterAlternateScreen, EnableMouseCapture).unwrap();
|
||||
let backend = CrosstermBackend::new(io::stdout());
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
|
||||
loop {
|
||||
let dims = terminal.size().unwrap();
|
||||
let width = dims.width;
|
||||
let height = dims.height;
|
||||
terminal.clear().unwrap();
|
||||
|
||||
/*
|
||||
-> collect all the nodes with their layout
|
||||
-> solve their layout
|
||||
-> render the nodes in the right place with tui/crosstream
|
||||
-> while rendering, apply styling
|
||||
loop {
|
||||
let dims = terminal.size().unwrap();
|
||||
let width = dims.width;
|
||||
let height = dims.height;
|
||||
|
||||
use simd to compare lines for diffing?
|
||||
/*
|
||||
-> collect all the nodes with their layout
|
||||
-> solve their layout
|
||||
-> render the nodes in the right place with tui/crosstream
|
||||
-> while rendering, apply styling
|
||||
|
||||
*/
|
||||
let mut layout = Stretch::new();
|
||||
let mut nodes = HashMap::new();
|
||||
use simd to compare lines for diffing?
|
||||
|
||||
let root_node = vdom.base_scope().root_node();
|
||||
layout::collect_layout(&mut layout, &mut nodes, vdom, root_node);
|
||||
/*
|
||||
Compute the layout given th terminal size
|
||||
*/
|
||||
let node_id = root_node.try_mounted_id().unwrap();
|
||||
let root_layout = nodes[&node_id].layout;
|
||||
layout.compute_layout(
|
||||
root_layout,
|
||||
Size {
|
||||
width: stretch2::prelude::Number::Defined(width as f32),
|
||||
height: stretch2::prelude::Number::Defined(height as f32),
|
||||
},
|
||||
)?;
|
||||
|
||||
terminal.draw(|frame| {
|
||||
//
|
||||
render::render_vnode(frame, &layout, &mut nodes, vdom, root_node);
|
||||
assert!(nodes.is_empty());
|
||||
})?;
|
||||
todo: reuse the layout and node objects.
|
||||
our work_with_deadline method can tell us which nodes are dirty.
|
||||
*/
|
||||
let mut layout = Stretch::new();
|
||||
let mut nodes = HashMap::new();
|
||||
|
||||
match rx.recv()? {
|
||||
InputEvent::UserInput(event) => match event.code {
|
||||
KeyCode::Char('q') => {
|
||||
disable_raw_mode()?;
|
||||
execute!(
|
||||
terminal.backend_mut(),
|
||||
LeaveAlternateScreen,
|
||||
DisableMouseCapture
|
||||
)?;
|
||||
terminal.show_cursor()?;
|
||||
break;
|
||||
let root_node = vdom.base_scope().root_node();
|
||||
layout::collect_layout(&mut layout, &mut nodes, vdom, root_node);
|
||||
/*
|
||||
Compute the layout given th terminal size
|
||||
*/
|
||||
let node_id = root_node.try_mounted_id().unwrap();
|
||||
let root_layout = nodes[&node_id].layout;
|
||||
layout.compute_layout(
|
||||
root_layout,
|
||||
Size {
|
||||
width: stretch2::prelude::Number::Defined(width as f32),
|
||||
height: stretch2::prelude::Number::Defined(height as f32),
|
||||
},
|
||||
)?;
|
||||
|
||||
terminal.draw(|frame| {
|
||||
//
|
||||
render::render_vnode(frame, &layout, &mut nodes, vdom, root_node);
|
||||
assert!(nodes.is_empty());
|
||||
})?;
|
||||
|
||||
use futures::future::{select, Either};
|
||||
{
|
||||
let wait = vdom.wait_for_work();
|
||||
pin_mut!(wait);
|
||||
|
||||
match select(wait, rx.next()).await {
|
||||
Either::Left((a, b)) => {
|
||||
// println!("work");
|
||||
}
|
||||
Either::Right((evt, o)) => {
|
||||
// println!("event");
|
||||
match evt.unwrap() {
|
||||
InputEvent::UserInput(event) => match event {
|
||||
TermEvent::Key(key) => {
|
||||
match key.code {
|
||||
KeyCode::Char('q') => {
|
||||
disable_raw_mode()?;
|
||||
execute!(
|
||||
terminal.backend_mut(),
|
||||
LeaveAlternateScreen,
|
||||
DisableMouseCapture
|
||||
)?;
|
||||
terminal.show_cursor()?;
|
||||
break;
|
||||
}
|
||||
_ => {} // handle event
|
||||
}
|
||||
}
|
||||
TermEvent::Mouse(_) => {}
|
||||
TermEvent::Resize(_, _) => {}
|
||||
},
|
||||
InputEvent::Tick => {} // tick
|
||||
InputEvent::Close => {
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {} // handle event
|
||||
},
|
||||
InputEvent::Tick => {} // tick
|
||||
InputEvent::Close => {
|
||||
break;
|
||||
|
||||
vdom.work_with_deadline(|| false);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
disable_raw_mode()?;
|
||||
execute!(
|
||||
terminal.backend_mut(),
|
||||
LeaveAlternateScreen,
|
||||
DisableMouseCapture
|
||||
)?;
|
||||
terminal.show_cursor()?;
|
||||
disable_raw_mode()?;
|
||||
execute!(
|
||||
terminal.backend_mut(),
|
||||
LeaveAlternateScreen,
|
||||
DisableMouseCapture
|
||||
)?;
|
||||
terminal.show_cursor()?;
|
||||
|
||||
Ok(())
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
enum InputEvent {
|
||||
UserInput(KeyEvent),
|
||||
UserInput(TermEvent),
|
||||
Close,
|
||||
Tick,
|
||||
}
|
||||
Reference in new issue
Block a user