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
use super::*;
impl Output<Read> {
/// Construct new, empty output.
pub fn new() -> Self {
let state = Read {
buf: String::new(),
prompt_start: 0,
prompt_end: 0,
lines_idx: 0,
start: 0,
};
Self {
state,
buf: String::new(),
lines_pos: Vec::new(),
tx: None,
}
}
/// Finished read state, move to write.
pub fn into_write(self) -> Output<Write> {
let Output {
buf, lines_pos, tx, ..
} = self;
let state = Write;
Output {
state,
buf,
lines_pos,
tx,
}
}
/// Overwrite the current input line buffer with `input`.
pub fn replace_line_input(&mut self, input: &str) {
self.buf.truncate(self.state.prompt_end);
self.lines_pos.truncate(self.state.lines_idx);
self.push_str(input);
self.state.buf.replace_range(self.state.start.., input);
}
/// Trigger a new input line. This stores previous input internally
/// and stacks the buffers.
pub fn new_line(&mut self) {
self.push_ch('\n');
self.state.buf.push('\n');
self.state.start = self.state.buf.len();
self.state.lines_idx = self.lines_len();
self.state.prompt_start = self.buf.len();
self.state.prompt_end = self.buf.len();
}
/// Returns the current input buffer.
pub fn input_buffer(&self) -> &str {
&self.state.buf
}
/// Returns last line of the input buffer.
pub fn input_buf_line(&self) -> &str {
&self.buf[self.state.prompt_end..]
}
/// Sets the prompt text. Will overwrite previous prompt.
/// Only sets prompt on current line.
///
/// # Line Changes
/// Does _not_ trigger line change event.
///
/// # Panics
/// Panics if _prompt_ contains a new line.
pub fn set_prompt(&mut self, prompt: &str) {
if prompt.contains('\n') {
panic!("prompt cannot contain new line character");
}
self.buf
.replace_range(self.state.prompt_start..self.state.prompt_end, prompt);
self.state.prompt_end = self.state.prompt_start + prompt.len();
}
/// Sets the prompt text. Will overwrite previous prompt.
/// Only sets prompt on current line.
///
/// # Line Changes
/// _Always_ triggers a line change event.
///
/// # Panics
/// Panics if _prompt_ contains a new line.
pub fn set_prompt_and_trigger(&mut self, prompt: &str) {
self.set_prompt(prompt);
self.send_line_chg();
}
}
#[test]
fn multiline_input_consistency() {
let mut o = Output::new();
o.replace_line_input("Hello\nWorld");
let expected = "Hello\nWorld";
assert_eq!(o.input_buffer(), expected);
let mut o = Output::new();
o.replace_line_input("Hello");
o.new_line();
o.replace_line_input("World");
assert_eq!(o.input_buffer(), expected);
}