aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Hrastnik2020-06-07 12:11:08 +0000
committerBlaž Hrastnik2020-06-16 08:42:34 +0000
commit065cbcee9e63703e5ffb3a2c044ed0b49a2b7fff (patch)
tree18715a1ca9ad4b8732dde1cf3a6c2e75b1e87107
parent2985398adca2d790d72c60bad9f0e841829fdebc (diff)
fixed async loop
-rw-r--r--.gitignore1
-rw-r--r--helix-term/src/editor.rs69
-rw-r--r--helix-term/src/test.rs100
3 files changed, 137 insertions, 33 deletions
diff --git a/.gitignore b/.gitignore
index eb5a316c..f6ea6b5d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
target
+helix-term/rustfmt.toml
diff --git a/helix-term/src/editor.rs b/helix-term/src/editor.rs
index e2446578..24e2448a 100644
--- a/helix-term/src/editor.rs
+++ b/helix-term/src/editor.rs
@@ -1,14 +1,15 @@
-use std::io::{self, stdout, Write};
-use std::path::PathBuf;
-
use crossterm::{
cursor,
cursor::position,
- event::{self, read, Event, KeyCode, KeyEvent},
+ event::{self, read, Event, EventStream, KeyCode, KeyEvent},
execute, queue, style,
terminal::{self, disable_raw_mode, enable_raw_mode},
Result,
};
+use futures::{future::FutureExt, select, StreamExt};
+use std::io::{self, stdout, Write};
+use std::path::PathBuf;
+use std::time::Duration;
const HELP: &str = r#"
- Use q to quit
@@ -20,40 +21,40 @@ pub struct Editor {
}
impl Editor {
- pub fn read_char() -> Result<char> {
- loop {
- if let Ok(Event::Key(KeyEvent {
- code: KeyCode::Char(c),
- ..
- })) = event::read()
- {
- return Ok(c);
- }
- }
- }
-
- pub async fn print_events() -> Result<()> {
+ pub async fn print_events() {
+ let mut reader = EventStream::new();
loop {
// Handle key events
- match Editor::read_char()? {
- 'h' => execute!(io::stdout(), cursor::MoveLeft(1))?,
- 'j' => execute!(io::stdout(), cursor::MoveDown(1))?,
- 'k' => execute!(io::stdout(), cursor::MoveUp(1))?,
- 'l' => execute!(io::stdout(), cursor::MoveRight(1))?,
- 'q' => {
- execute!(
- io::stdout(),
- style::ResetColor,
- cursor::Show,
- terminal::LeaveAlternateScreen
- )?;
- break;
+ let mut event = reader.next().await;
+ match event {
+ Some(Ok(x)) => {
+ if let Event::Key(KeyEvent {
+ code: KeyCode::Char(c),
+ ..
+ }) = x
+ {
+ match c {
+ 'h' => execute!(io::stdout(), cursor::MoveLeft(1)).unwrap(),
+ 'j' => execute!(io::stdout(), cursor::MoveDown(1)).unwrap(),
+ 'k' => execute!(io::stdout(), cursor::MoveUp(1)).unwrap(),
+ 'l' => execute!(io::stdout(), cursor::MoveRight(1)).unwrap(),
+ 'q' => {
+ execute!(
+ io::stdout(),
+ style::ResetColor,
+ cursor::Show,
+ terminal::LeaveAlternateScreen
+ );
+ break;
+ }
+ _ => println!("{:?}", x),
+ }
+ }
}
- _ => println!("use 'q' to quit."),
+ Some(Err(x)) => panic!(x),
+ None => break,
}
}
-
- Ok(())
}
pub fn run() -> Result<()> {
@@ -85,6 +86,8 @@ impl Editor {
// Send a shutdown signal.
drop(s);
+ execute!(stdout, terminal::LeaveAlternateScreen)?;
+
// Wait for threads to finish.
for t in threads {
t.join().unwrap();
diff --git a/helix-term/src/test.rs b/helix-term/src/test.rs
new file mode 100644
index 00000000..12b4f377
--- /dev/null
+++ b/helix-term/src/test.rs
@@ -0,0 +1,100 @@
+//! Demonstrates how to read events asynchronously with async-std.
+//!
+//! cargo run --features="event-stream" --example event-stream-async-std
+
+use std::{
+ io::{stdout, Write},
+ time::Duration,
+};
+
+use futures::{future::FutureExt, select, StreamExt};
+use smol::Timer;
+// use futures_timer::Delay;
+
+use crossterm::{
+ cursor::position,
+ event::{DisableMouseCapture, EnableMouseCapture, Event, EventStream, KeyCode},
+ execute,
+ terminal::{disable_raw_mode, enable_raw_mode},
+ Result,
+};
+
+const HELP: &str = r#"EventStream based on futures::Stream with async-std
+ - Keyboard, mouse and terminal resize events enabled
+ - Prints "." every second if there's no event
+ - Hit "c" to print current cursor position
+ - Use Esc to quit
+"#;
+
+async fn print_events() {
+ let mut reader = EventStream::new();
+
+ loop {
+ let mut delay = Timer::after(Duration::from_millis(1_000)).fuse();
+ let mut event = reader.next().fuse();
+
+ select! {
+ _ = delay => { println!(".\r"); },
+ maybe_event = event => {
+ match maybe_event {
+ Some(Ok(event)) => {
+ println!("Event::{:?}\r", event);
+
+ if event == Event::Key(KeyCode::Char('c').into()) {
+ println!("Cursor position: {:?}\r", position());
+
+ }
+
+ println!("test");
+
+ if event == Event::Key(KeyCode::Esc.into()) {
+ break;
+ }
+ }
+ Some(Err(e)) => println!("Error: {:?}\r", e),
+ None => break,
+ }
+ }
+ };
+ }
+}
+
+fn main() -> Result<()> {
+ println!("{}", HELP);
+
+ enable_raw_mode()?;
+
+ let mut stdout = stdout();
+ execute!(stdout, EnableMouseCapture)?;
+
+ use std::thread;
+
+ // Same number of threads as there are CPU cores.
+ let num_threads = num_cpus::get().max(1);
+
+ // A channel that sends the shutdown signal.
+ let (s, r) = piper::chan::<()>(0);
+ let mut threads = Vec::new();
+
+ // Create an executor thread pool.
+ for _ in 0..num_threads {
+ // Spawn an executor thread that waits for the shutdown signal.
+ let r = r.clone();
+ threads.push(thread::spawn(move || smol::run(r.recv())));
+ }
+
+ // No need to `run()`, now we can just block on the main future.
+ smol::block_on(print_events());
+
+ // Send a shutdown signal.
+ drop(s);
+
+ // Wait for threads to finish.
+ for t in threads {
+ t.join().unwrap();
+ }
+
+ execute!(stdout, DisableMouseCapture)?;
+
+ disable_raw_mode()
+}