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"
|
ctrlc = "3.2.1"
|
||||||
bumpalo = { version = "3.8.0", features = ["boxed"] }
|
bumpalo = { version = "3.8.0", features = ["boxed"] }
|
||||||
stretch2 = { path = "../../Tinkering/stretch2" }
|
stretch2 = { path = "../../Tinkering/stretch2" }
|
||||||
|
tokio = { version = "1.15.0", features = ["full"] }
|
||||||
|
futures = "0.3.19"
|
||||||
# stretch2 = { git = "https://github.com/elbaro/stretch2.git" }
|
# stretch2 = { git = "https://github.com/elbaro/stretch2.git" }
|
||||||
@@ -19,7 +19,6 @@ static App: FC<()> = |cx| {
|
|||||||
justify_content: "center",
|
justify_content: "center",
|
||||||
align_items: "center",
|
align_items: "center",
|
||||||
|
|
||||||
|
|
||||||
"Hello world!"
|
"Hello world!"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ fn main() {
|
|||||||
let mut dom = VirtualDom::new(app);
|
let mut dom = VirtualDom::new(app);
|
||||||
dom.rebuild();
|
dom.rebuild();
|
||||||
|
|
||||||
rink::render_vdom(&dom).unwrap();
|
rink::render_vdom(&mut dom).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn app(cx: Scope) -> Element {
|
fn app(cx: Scope) -> Element {
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ fn main() {
|
|||||||
let mut dom = VirtualDom::new(app);
|
let mut dom = VirtualDom::new(app);
|
||||||
dom.rebuild();
|
dom.rebuild();
|
||||||
|
|
||||||
rink::render_vdom(&dom).unwrap();
|
rink::render_vdom(&mut dom).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn app(cx: Scope) -> Element {
|
fn app(cx: Scope) -> Element {
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ fn main() {
|
|||||||
let mut dom = VirtualDom::new(app);
|
let mut dom = VirtualDom::new(app);
|
||||||
dom.rebuild();
|
dom.rebuild();
|
||||||
|
|
||||||
rink::render_vdom(&dom).unwrap();
|
rink::render_vdom(&mut dom).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn app(cx: Scope) -> Element {
|
fn app(cx: Scope) -> Element {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ fn main() {
|
|||||||
let mut dom = VirtualDom::new(app);
|
let mut dom = VirtualDom::new(app);
|
||||||
dom.rebuild();
|
dom.rebuild();
|
||||||
|
|
||||||
rink::render_vdom(&dom).unwrap();
|
rink::render_vdom(&mut dom).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn app(cx: Scope) -> Element {
|
fn app(cx: Scope) -> Element {
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ fn main() {
|
|||||||
let mut dom = VirtualDom::new(app);
|
let mut dom = VirtualDom::new(app);
|
||||||
dom.rebuild();
|
dom.rebuild();
|
||||||
|
|
||||||
rink::render_vdom(&dom).unwrap();
|
rink::render_vdom(&mut dom).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn app(cx: Scope) -> Element {
|
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);
|
let mut dom = VirtualDom::new(app);
|
||||||
dom.rebuild();
|
dom.rebuild();
|
||||||
|
|
||||||
rink::render_vdom(&dom).unwrap();
|
rink::render_vdom(&mut dom).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn app(cx: Scope) -> Element {
|
fn app(cx: Scope) -> Element {
|
||||||
|
|||||||
+109
-82
@@ -1,14 +1,15 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use crossterm::{
|
use crossterm::{
|
||||||
event::{self, DisableMouseCapture, EnableMouseCapture, Event as TermEvent, KeyCode, KeyEvent},
|
event::{DisableMouseCapture, EnableMouseCapture, Event as TermEvent, KeyCode, KeyEvent},
|
||||||
execute,
|
execute,
|
||||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||||
};
|
};
|
||||||
|
use dioxus::core::exports::futures_channel::mpsc::unbounded;
|
||||||
use dioxus::core::*;
|
use dioxus::core::*;
|
||||||
|
use futures::{future::Either, pin_mut, StreamExt};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
io,
|
io,
|
||||||
sync::mpsc,
|
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
use stretch2::{prelude::Size, Stretch};
|
use stretch2::{prelude::Size, Stretch};
|
||||||
@@ -28,22 +29,10 @@ pub struct TuiNode<'a> {
|
|||||||
pub node: &'a VNode<'a>,
|
pub node: &'a VNode<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_vdom(vdom: &VirtualDom) -> Result<()> {
|
pub fn render_vdom(vdom: &mut 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();
|
|
||||||
|
|
||||||
// Setup input handling
|
// Setup input handling
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, mut rx) = unbounded();
|
||||||
|
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let tick_rate = Duration::from_millis(100);
|
let tick_rate = Duration::from_millis(100);
|
||||||
let mut last_tick = Instant::now();
|
let mut last_tick = Instant::now();
|
||||||
@@ -53,93 +42,131 @@ pub fn render_vdom(vdom: &VirtualDom) -> Result<()> {
|
|||||||
.checked_sub(last_tick.elapsed())
|
.checked_sub(last_tick.elapsed())
|
||||||
.unwrap_or_else(|| Duration::from_secs(0));
|
.unwrap_or_else(|| Duration::from_secs(0));
|
||||||
|
|
||||||
if event::poll(timeout).unwrap() {
|
if crossterm::event::poll(timeout).unwrap() {
|
||||||
if let TermEvent::Key(key) = event::read().unwrap() {
|
let evt = crossterm::event::read().unwrap();
|
||||||
tx.send(InputEvent::UserInput(key)).unwrap();
|
tx.unbounded_send(InputEvent::UserInput(evt)).unwrap();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if last_tick.elapsed() >= tick_rate {
|
if last_tick.elapsed() >= tick_rate {
|
||||||
tx.send(InputEvent::Tick).unwrap();
|
tx.unbounded_send(InputEvent::Tick).unwrap();
|
||||||
last_tick = Instant::now();
|
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 {
|
terminal.clear().unwrap();
|
||||||
let dims = terminal.size().unwrap();
|
|
||||||
let width = dims.width;
|
|
||||||
let height = dims.height;
|
|
||||||
|
|
||||||
/*
|
loop {
|
||||||
-> collect all the nodes with their layout
|
let dims = terminal.size().unwrap();
|
||||||
-> solve their layout
|
let width = dims.width;
|
||||||
-> render the nodes in the right place with tui/crosstream
|
let height = dims.height;
|
||||||
-> while rendering, apply styling
|
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
*/
|
use simd to compare lines for diffing?
|
||||||
let mut layout = Stretch::new();
|
|
||||||
let mut nodes = HashMap::new();
|
|
||||||
|
|
||||||
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| {
|
todo: reuse the layout and node objects.
|
||||||
//
|
our work_with_deadline method can tell us which nodes are dirty.
|
||||||
render::render_vnode(frame, &layout, &mut nodes, vdom, root_node);
|
*/
|
||||||
assert!(nodes.is_empty());
|
let mut layout = Stretch::new();
|
||||||
})?;
|
let mut nodes = HashMap::new();
|
||||||
|
|
||||||
match rx.recv()? {
|
let root_node = vdom.base_scope().root_node();
|
||||||
InputEvent::UserInput(event) => match event.code {
|
layout::collect_layout(&mut layout, &mut nodes, vdom, root_node);
|
||||||
KeyCode::Char('q') => {
|
/*
|
||||||
disable_raw_mode()?;
|
Compute the layout given th terminal size
|
||||||
execute!(
|
*/
|
||||||
terminal.backend_mut(),
|
let node_id = root_node.try_mounted_id().unwrap();
|
||||||
LeaveAlternateScreen,
|
let root_layout = nodes[&node_id].layout;
|
||||||
DisableMouseCapture
|
layout.compute_layout(
|
||||||
)?;
|
root_layout,
|
||||||
terminal.show_cursor()?;
|
Size {
|
||||||
break;
|
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
|
|
||||||
},
|
vdom.work_with_deadline(|| false);
|
||||||
InputEvent::Tick => {} // tick
|
|
||||||
InputEvent::Close => {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
disable_raw_mode()?;
|
disable_raw_mode()?;
|
||||||
execute!(
|
execute!(
|
||||||
terminal.backend_mut(),
|
terminal.backend_mut(),
|
||||||
LeaveAlternateScreen,
|
LeaveAlternateScreen,
|
||||||
DisableMouseCapture
|
DisableMouseCapture
|
||||||
)?;
|
)?;
|
||||||
terminal.show_cursor()?;
|
terminal.show_cursor()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
enum InputEvent {
|
enum InputEvent {
|
||||||
UserInput(KeyEvent),
|
UserInput(TermEvent),
|
||||||
Close,
|
Close,
|
||||||
Tick,
|
Tick,
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user