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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use super::*;
impl<D> Default for Repl<Read, D> {
fn default() -> Self {
let data = ReplData::default();
let mut r = Repl {
state: Read {
output: Output::default(),
},
data,
more: false,
data_mrker: PhantomData,
};
r.draw_prompt();
r
}
}
/// > **These methods are available when the REPL is in the [`Read`] state.**
impl<D> Repl<Read, D> {
/// Overwrite the current line in the input buffer.
///
/// A line is considered if more input is required, the previous input stacked.
/// Only overwrites the most recent buffer.
pub fn line_input(&mut self, input: &str) {
self.state.output.replace_line_input(input);
}
/// The current input buffer.
pub fn input_buffer(&self) -> &str {
self.state.output.input_buffer()
}
/// The _line_ of the current input buffer.
///
/// This differs to the input buffer if there has been a requirement for
/// `More` input, say if a block `{` was started and not closed out. The
/// line is what has be set with `line_input`.
pub fn input_buffer_line(&self) -> &str {
self.state.output.input_buf_line()
}
/// Read the current contents of the input buffer.
/// This may move the repl into an evaluating state.
pub fn read(mut self) -> ReadResult<D> {
let treat_as_cmd = !self.data.cmdtree.at_root();
let result = crate::input::determine_result(
self.state.output.input_buffer(),
self.state.output.input_buf_line(),
treat_as_cmd,
);
// have to push after as can't take mutable brw and last line
// if done before will not register cmds
self.state.output.new_line();
if result == InputResult::More {
self.more = true;
self.draw_prompt();
ReadResult::Read(self)
} else {
self.more = false;
ReadResult::Eval(self.move_state(|s| Evaluate {
output: s.output.into_write(),
result,
}))
}
}
pub(super) fn draw_prompt(&mut self) {
self.state.output.set_prompt_and_trigger(&self.prompt(true));
}
/// The current output.
///
/// The output contains colouring ANSI escape codes, the prompt, and all input.
pub fn output(&self) -> &str {
self.state.output.buffer()
}
/// Begin listening to line change events on the output.
pub fn output_listen(&mut self) -> output::Receiver {
self.state.output.listen()
}
/// Close the sender side of the output channel.
pub fn close_channel(&mut self) {
self.state.output.close()
}
}
impl<D> ReadResult<D> {
#[cfg(test)]
pub fn unwrap_read(self) -> Repl<Read, D> {
match self {
ReadResult::Read(read) => read,
ReadResult::Eval(_) => panic!("unwrap_read ReadResult invoked on Eval variant."),
}
}
}
#[cfg(test)]
mod tests {
use crate as papyrus;
#[test]
fn test_line_input() {
let mut repl = repl!();
let _rx = repl.output_listen();
repl.line_input("test");
assert_eq!(repl.input_buffer(), "test");
repl.line_input(""); // check doesn't break
assert_eq!(repl.input_buffer(), "");
repl.line_input("{");
repl = repl.read().unwrap_read();
assert_eq!(repl.input_buffer(), "{\n");
repl.line_input("test");
assert_eq!(repl.input_buffer(), "{\ntest");
repl.line_input("");
assert_eq!(repl.input_buffer(), "{\n");
}
}