on master help sign in
fixed async loop
065cbceJan Hrastnik
.gitignore+1
@@ -1 +1,2 @@
1target
1target
2+helix-term/rustfmt.toml
helix-term/src/editor.rs+36−33
@@ -1,14 +1,15 @@
1−use std::io::{self, stdout, Write};
2−use std::path::PathBuf;
3−
4use crossterm::{
1use crossterm::{
5 cursor,
2 cursor,
6 cursor::position,
3 cursor::position,
7− event::{self, read, Event, KeyCode, KeyEvent},
4+ event::{self, read, Event, EventStream, KeyCode, KeyEvent},
8 execute, queue, style,
5 execute, queue, style,
9 terminal::{self, disable_raw_mode, enable_raw_mode},
6 terminal::{self, disable_raw_mode, enable_raw_mode},
10 Result,
7 Result,
11};
8};
9+use futures::{future::FutureExt, select, StreamExt};
10+use std::io::{self, stdout, Write};
11+use std::path::PathBuf;
12+use std::time::Duration;
12
13
13const HELP: &str = r#"
14const HELP: &str = r#"
14 - Use q to quit
15 - Use q to quit
@@ -20,40 +21,40 @@ pub struct Editor {
20}
21}
21
22
22impl Editor {
23impl Editor {
23− pub fn read_char() -> Result<char> {
24+ pub async fn print_events() {
24− loop {
25+ let mut reader = EventStream::new();
25− if let Ok(Event::Key(KeyEvent {
26− code: KeyCode::Char(c),
27− ..
28− })) = event::read()
29− {
30− return Ok(c);
31− }
32− }
33− }
34−
35− pub async fn print_events() -> Result<()> {
36 loop {
26 loop {
37 // Handle key events
27 // Handle key events
38− match Editor::read_char()? {
28+ let mut event = reader.next().await;
29+ match event {
30+ Some(Ok(x)) => {
31+ if let Event::Key(KeyEvent {
32+ code: KeyCode::Char(c),
33+ ..
34+ }) = x
35+ {
36+ match c {
39− 'h' => execute!(io::stdout(), cursor::MoveLeft(1))?,
37+ 'h' => execute!(io::stdout(), cursor::MoveLeft(1)).unwrap(),
40− 'j' => execute!(io::stdout(), cursor::MoveDown(1))?,
38+ 'j' => execute!(io::stdout(), cursor::MoveDown(1)).unwrap(),
41− 'k' => execute!(io::stdout(), cursor::MoveUp(1))?,
39+ 'k' => execute!(io::stdout(), cursor::MoveUp(1)).unwrap(),
42− 'l' => execute!(io::stdout(), cursor::MoveRight(1))?,
40+ 'l' => execute!(io::stdout(), cursor::MoveRight(1)).unwrap(),
43− 'q' => {
41+ 'q' => {
44− execute!(
42+ execute!(
45− io::stdout(),
43+ io::stdout(),
46− style::ResetColor,
44+ style::ResetColor,
47− cursor::Show,
45+ cursor::Show,
48− terminal::LeaveAlternateScreen
46+ terminal::LeaveAlternateScreen
49− )?;
47+ );
50− break;
48+ break;
49+ }
50+ _ => println!("{:?}", x),
51+ }
52+ }
51 }
53 }
52− _ => println!("use 'q' to quit."),
54+ Some(Err(x)) => panic!(x),
55+ None => break,
53 }
56 }
54 }
57 }
55−
56− Ok(())
57 }
58 }
58
59
59 pub fn run() -> Result<()> {
60 pub fn run() -> Result<()> {
@@ -85,6 +86,8 @@ impl Editor {
85 // Send a shutdown signal.
86 // Send a shutdown signal.
86 drop(s);
87 drop(s);
87
88
89+ execute!(stdout, terminal::LeaveAlternateScreen)?;
90+
88 // Wait for threads to finish.
91 // Wait for threads to finish.
89 for t in threads {
92 for t in threads {
90 t.join().unwrap();
93 t.join().unwrap();
helix-term/src/test.rsnew file+100
@@ -0,0 +1,100 @@
1+//! Demonstrates how to read events asynchronously with async-std.
2+//!
3+//! cargo run --features="event-stream" --example event-stream-async-std
4+
5+use std::{
6+ io::{stdout, Write},
7+ time::Duration,
8+};
9+
10+use futures::{future::FutureExt, select, StreamExt};
11+use smol::Timer;
12+// use futures_timer::Delay;
13+
14+use crossterm::{
15+ cursor::position,
16+ event::{DisableMouseCapture, EnableMouseCapture, Event, EventStream, KeyCode},
17+ execute,
18+ terminal::{disable_raw_mode, enable_raw_mode},
19+ Result,
20+};
21+
22+const HELP: &str = r#"EventStream based on futures::Stream with async-std
23+ - Keyboard, mouse and terminal resize events enabled
24+ - Prints "." every second if there's no event
25+ - Hit "c" to print current cursor position
26+ - Use Esc to quit
27+"#;
28+
29+async fn print_events() {
30+ let mut reader = EventStream::new();
31+
32+ loop {
33+ let mut delay = Timer::after(Duration::from_millis(1_000)).fuse();
34+ let mut event = reader.next().fuse();
35+
36+ select! {
37+ _ = delay => { println!(".\r"); },
38+ maybe_event = event => {
39+ match maybe_event {
40+ Some(Ok(event)) => {
41+ println!("Event::{:?}\r", event);
42+
43+ if event == Event::Key(KeyCode::Char('c').into()) {
44+ println!("Cursor position: {:?}\r", position());
45+
46+ }
47+
48+ println!("test");
49+
50+ if event == Event::Key(KeyCode::Esc.into()) {
51+ break;
52+ }
53+ }
54+ Some(Err(e)) => println!("Error: {:?}\r", e),
55+ None => break,
56+ }
57+ }
58+ };
59+ }
60+}
61+
62+fn main() -> Result<()> {
63+ println!("{}", HELP);
64+
65+ enable_raw_mode()?;
66+
67+ let mut stdout = stdout();
68+ execute!(stdout, EnableMouseCapture)?;
69+
70+ use std::thread;
71+
72+ // Same number of threads as there are CPU cores.
73+ let num_threads = num_cpus::get().max(1);
74+
75+ // A channel that sends the shutdown signal.
76+ let (s, r) = piper::chan::<()>(0);
77+ let mut threads = Vec::new();
78+
79+ // Create an executor thread pool.
80+ for _ in 0..num_threads {
81+ // Spawn an executor thread that waits for the shutdown signal.
82+ let r = r.clone();
83+ threads.push(thread::spawn(move || smol::run(r.recv())));
84+ }
85+
86+ // No need to `run()`, now we can just block on the main future.
87+ smol::block_on(print_events());
88+
89+ // Send a shutdown signal.
90+ drop(s);
91+
92+ // Wait for threads to finish.
93+ for t in threads {
94+ t.join().unwrap();
95+ }
96+
97+ execute!(stdout, DisableMouseCapture)?;
98+
99+ disable_raw_mode()
100+}