1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
use textmode::Textmode as _;
pub struct Nbsh {
repl: crate::repl::Repl,
history: crate::history::History,
}
impl Nbsh {
pub fn new() -> Self {
Self {
repl: crate::repl::Repl::new(),
history: crate::history::History::new(),
}
}
pub async fn run(self) -> anyhow::Result<()> {
let mut input = textmode::Input::new().await?;
let mut output = textmode::Output::new().await?;
// avoid the guards getting stuck in a task that doesn't run to
// completion
let _input_guard = input.take_raw_guard();
let _output_guard = output.take_screen_guard();
let (run_w, run_r) = async_std::channel::unbounded();
let (render_w, render_r) = async_std::channel::unbounded();
self.render(&mut output).await.unwrap();
let locked_self =
async_std::sync::Arc::new(async_std::sync::Mutex::new(self));
let readline_self = std::sync::Arc::clone(&locked_self);
let readline_render = render_w.clone();
let readline_task = async_std::task::spawn(async move {
loop {
let key = input.read_key().await.unwrap();
let mut self_ = readline_self.lock_arc().await;
let (last, cmd) = self_.handle_key(key);
if last {
break;
}
if let Some(cmd) = cmd {
run_w.send(cmd).await.unwrap();
}
readline_render.send(()).await.unwrap();
}
});
let history_self = std::sync::Arc::clone(&locked_self);
let history_render = render_w.clone();
async_std::task::spawn(async move {
while let Ok(cmd) = run_r.recv().await {
let mut self_ = history_self.lock_arc().await;
self_
.history
.run(&cmd, history_render.clone())
.await
.unwrap();
}
});
let render_self = std::sync::Arc::clone(&locked_self);
async_std::task::spawn(async move {
while let Ok(()) = render_r.recv().await {
while let Ok(()) = render_r.try_recv() {}
let self_ = render_self.lock_arc().await;
self_.render(&mut output).await.unwrap();
}
});
readline_task.await;
Ok(())
}
fn handle_key(
&mut self,
key: Option<textmode::Key>,
) -> (bool, Option<String>) {
let mut cmd = None;
match key {
Some(textmode::Key::String(s)) => self.repl.add_input(&s),
Some(textmode::Key::Char(c)) => {
self.repl.add_input(&c.to_string());
}
Some(textmode::Key::Ctrl(b'c')) => self.repl.clear_input(),
Some(textmode::Key::Ctrl(b'd')) | None => return (true, None),
Some(textmode::Key::Ctrl(b'm')) => {
cmd = Some(self.repl.input());
self.repl.clear_input();
}
Some(textmode::Key::Backspace) => self.repl.backspace(),
_ => {}
}
(false, cmd)
}
async fn render(&self, out: &mut textmode::Output) -> anyhow::Result<()> {
out.clear();
self.history.render(out, self.repl.lines()).await?;
self.repl.render(out).await?;
out.refresh().await?;
Ok(())
}
}
|