Skip to content

Commit 159273e

Browse files
committed
Take stdout as argument in watch mode
1 parent 631f2db commit 159273e

File tree

2 files changed

+69
-83
lines changed

2 files changed

+69
-83
lines changed

src/watch.rs

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -72,35 +72,32 @@ pub fn watch(
7272

7373
let mut watch_state = WatchState::new(app_state, manual_run);
7474

75-
watch_state.run_current_exercise()?;
75+
let mut stdout = io::stdout().lock();
76+
watch_state.run_current_exercise(&mut stdout)?;
7677

7778
thread::spawn(move || terminal_event_handler(tx, manual_run));
7879

7980
while let Ok(event) = rx.recv() {
8081
match event {
81-
WatchEvent::Input(InputEvent::Next) => match watch_state.next_exercise()? {
82+
WatchEvent::Input(InputEvent::Next) => match watch_state.next_exercise(&mut stdout)? {
8283
ExercisesProgress::AllDone => break,
83-
ExercisesProgress::CurrentPending => watch_state.render()?,
84-
ExercisesProgress::NewPending => watch_state.run_current_exercise()?,
84+
ExercisesProgress::CurrentPending => watch_state.render(&mut stdout)?,
85+
ExercisesProgress::NewPending => watch_state.run_current_exercise(&mut stdout)?,
8586
},
86-
WatchEvent::Input(InputEvent::Hint) => {
87-
watch_state.show_hint()?;
88-
}
87+
WatchEvent::Input(InputEvent::Hint) => watch_state.show_hint(&mut stdout)?,
8988
WatchEvent::Input(InputEvent::List) => {
9089
return Ok(WatchExit::List);
9190
}
9291
WatchEvent::Input(InputEvent::Quit) => {
93-
watch_state.into_writer().write_all(QUIT_MSG)?;
92+
stdout.write_all(QUIT_MSG)?;
9493
break;
9594
}
96-
WatchEvent::Input(InputEvent::Run) => watch_state.run_current_exercise()?,
97-
WatchEvent::Input(InputEvent::Unrecognized) => watch_state.render()?,
95+
WatchEvent::Input(InputEvent::Run) => watch_state.run_current_exercise(&mut stdout)?,
96+
WatchEvent::Input(InputEvent::Unrecognized) => watch_state.render(&mut stdout)?,
9897
WatchEvent::FileChange { exercise_ind } => {
99-
watch_state.handle_file_change(exercise_ind)?;
100-
}
101-
WatchEvent::TerminalResize => {
102-
watch_state.render()?;
98+
watch_state.handle_file_change(exercise_ind, &mut stdout)?;
10399
}
100+
WatchEvent::TerminalResize => watch_state.render(&mut stdout)?,
104101
WatchEvent::NotifyErr(e) => {
105102
return Err(Error::from(e).context(NOTIFY_ERR));
106103
}

src/watch/state.rs

Lines changed: 58 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ enum DoneStatus {
2222
}
2323

2424
pub struct WatchState<'a> {
25-
stdout: StdoutLock<'a>,
2625
app_state: &'a mut AppState,
2726
output: Vec<u8>,
2827
show_hint: bool,
@@ -32,11 +31,7 @@ pub struct WatchState<'a> {
3231

3332
impl<'a> WatchState<'a> {
3433
pub fn new(app_state: &'a mut AppState, manual_run: bool) -> Self {
35-
// TODO: Take stdout as arg.
36-
let stdout = io::stdout().lock();
37-
3834
Self {
39-
stdout,
4035
app_state,
4136
output: Vec::with_capacity(OUTPUT_CAPACITY),
4237
show_hint: false,
@@ -45,16 +40,11 @@ impl<'a> WatchState<'a> {
4540
}
4641
}
4742

48-
#[inline]
49-
pub fn into_writer(self) -> StdoutLock<'a> {
50-
self.stdout
51-
}
52-
53-
pub fn run_current_exercise(&mut self) -> Result<()> {
43+
pub fn run_current_exercise(&mut self, stdout: &mut StdoutLock) -> Result<()> {
5444
self.show_hint = false;
5545

5646
writeln!(
57-
self.stdout,
47+
stdout,
5848
"\nChecking the exercise `{}`. Please wait…",
5949
self.app_state.current_exercise().name,
6050
)?;
@@ -78,11 +68,15 @@ impl<'a> WatchState<'a> {
7868
self.done_status = DoneStatus::Pending;
7969
}
8070

81-
self.render()?;
71+
self.render(stdout)?;
8272
Ok(())
8373
}
8474

85-
pub fn handle_file_change(&mut self, exercise_ind: usize) -> Result<()> {
75+
pub fn handle_file_change(
76+
&mut self,
77+
exercise_ind: usize,
78+
stdout: &mut StdoutLock,
79+
) -> Result<()> {
8680
// Don't skip exercises on file changes to avoid confusion from missing exercises.
8781
// Skipping exercises must be explicit in the interactive list.
8882
// But going back to an earlier exercise on file change is fine.
@@ -91,118 +85,113 @@ impl<'a> WatchState<'a> {
9185
}
9286

9387
self.app_state.set_current_exercise_ind(exercise_ind)?;
94-
self.run_current_exercise()
88+
self.run_current_exercise(stdout)
9589
}
9690

9791
/// Move on to the next exercise if the current one is done.
98-
pub fn next_exercise(&mut self) -> Result<ExercisesProgress> {
92+
pub fn next_exercise(&mut self, stdout: &mut StdoutLock) -> Result<ExercisesProgress> {
9993
if self.done_status == DoneStatus::Pending {
10094
return Ok(ExercisesProgress::CurrentPending);
10195
}
10296

103-
self.app_state.done_current_exercise(&mut self.stdout)
97+
self.app_state.done_current_exercise(stdout)
10498
}
10599

106-
fn show_prompt(&mut self) -> io::Result<()> {
100+
fn show_prompt(&self, stdout: &mut StdoutLock) -> io::Result<()> {
107101
if self.manual_run {
108-
self.stdout.queue(SetAttribute(Attribute::Bold))?;
109-
self.stdout.write_all(b"r")?;
110-
self.stdout.queue(ResetColor)?;
111-
self.stdout.write_all(b":run / ")?;
102+
stdout.queue(SetAttribute(Attribute::Bold))?;
103+
stdout.write_all(b"r")?;
104+
stdout.queue(ResetColor)?;
105+
stdout.write_all(b":run / ")?;
112106
}
113107

114108
if self.done_status != DoneStatus::Pending {
115-
self.stdout.queue(SetAttribute(Attribute::Bold))?;
116-
self.stdout.write_all(b"n")?;
117-
self.stdout.queue(ResetColor)?;
118-
self.stdout.write_all(b":")?;
119-
self.stdout.queue(SetAttribute(Attribute::Underlined))?;
120-
self.stdout.write_all(b"next")?;
121-
self.stdout.queue(ResetColor)?;
122-
self.stdout.write_all(b" / ")?;
109+
stdout.queue(SetAttribute(Attribute::Bold))?;
110+
stdout.write_all(b"n")?;
111+
stdout.queue(ResetColor)?;
112+
stdout.write_all(b":")?;
113+
stdout.queue(SetAttribute(Attribute::Underlined))?;
114+
stdout.write_all(b"next")?;
115+
stdout.queue(ResetColor)?;
116+
stdout.write_all(b" / ")?;
123117
}
124118

125119
if !self.show_hint {
126-
self.stdout.queue(SetAttribute(Attribute::Bold))?;
127-
self.stdout.write_all(b"h")?;
128-
self.stdout.queue(ResetColor)?;
129-
self.stdout.write_all(b":hint / ")?;
120+
stdout.queue(SetAttribute(Attribute::Bold))?;
121+
stdout.write_all(b"h")?;
122+
stdout.queue(ResetColor)?;
123+
stdout.write_all(b":hint / ")?;
130124
}
131125

132-
self.stdout.queue(SetAttribute(Attribute::Bold))?;
133-
self.stdout.write_all(b"l")?;
134-
self.stdout.queue(ResetColor)?;
135-
self.stdout.write_all(b":list / ")?;
126+
stdout.queue(SetAttribute(Attribute::Bold))?;
127+
stdout.write_all(b"l")?;
128+
stdout.queue(ResetColor)?;
129+
stdout.write_all(b":list / ")?;
136130

137-
self.stdout.queue(SetAttribute(Attribute::Bold))?;
138-
self.stdout.write_all(b"q")?;
139-
self.stdout.queue(ResetColor)?;
140-
self.stdout.write_all(b":quit ? ")?;
131+
stdout.queue(SetAttribute(Attribute::Bold))?;
132+
stdout.write_all(b"q")?;
133+
stdout.queue(ResetColor)?;
134+
stdout.write_all(b":quit ? ")?;
141135

142-
self.stdout.flush()
136+
stdout.flush()
143137
}
144138

145-
pub fn render(&mut self) -> io::Result<()> {
139+
pub fn render(&self, stdout: &mut StdoutLock) -> io::Result<()> {
146140
// Prevent having the first line shifted if clearing wasn't successful.
147-
self.stdout.write_all(b"\n")?;
148-
clear_terminal(&mut self.stdout)?;
141+
stdout.write_all(b"\n")?;
142+
clear_terminal(stdout)?;
149143

150-
self.stdout.write_all(&self.output)?;
144+
stdout.write_all(&self.output)?;
151145

152146
if self.show_hint {
153-
self.stdout
147+
stdout
154148
.queue(SetAttributes(
155149
Attributes::from(Attribute::Bold).with(Attribute::Underlined),
156150
))?
157151
.queue(SetForegroundColor(Color::Cyan))?;
158-
self.stdout.write_all(b"Hint\n")?;
159-
self.stdout.queue(ResetColor)?;
152+
stdout.write_all(b"Hint\n")?;
153+
stdout.queue(ResetColor)?;
160154

161-
self.stdout
162-
.write_all(self.app_state.current_exercise().hint.as_bytes())?;
163-
self.stdout.write_all(b"\n\n")?;
155+
stdout.write_all(self.app_state.current_exercise().hint.as_bytes())?;
156+
stdout.write_all(b"\n\n")?;
164157
}
165158

166159
if self.done_status != DoneStatus::Pending {
167-
self.stdout
160+
stdout
168161
.queue(SetAttribute(Attribute::Bold))?
169162
.queue(SetForegroundColor(Color::Green))?;
170-
self.stdout.write_all("Exercise done ✓\n".as_bytes())?;
171-
self.stdout.queue(ResetColor)?;
163+
stdout.write_all("Exercise done ✓\n".as_bytes())?;
164+
stdout.queue(ResetColor)?;
172165

173166
if let DoneStatus::DoneWithSolution(solution_path) = &self.done_status {
174-
solution_link_line(&mut self.stdout, solution_path)?;
167+
solution_link_line(stdout, solution_path)?;
175168
}
176169

177170
writeln!(
178-
self.stdout,
171+
stdout,
179172
"When done experimenting, enter `n` to move on to the next exercise 🦀\n",
180173
)?;
181174
}
182175

183176
let line_width = terminal::size()?.0;
184177
progress_bar(
185-
&mut self.stdout,
178+
stdout,
186179
self.app_state.n_done(),
187180
self.app_state.exercises().len() as u16,
188181
line_width,
189182
)?;
190183

191-
self.stdout.write_all(b"\nCurrent exercise: ")?;
192-
terminal_file_link(
193-
&mut self.stdout,
194-
self.app_state.current_exercise().path,
195-
Color::Blue,
196-
)?;
197-
self.stdout.write_all(b"\n\n")?;
184+
stdout.write_all(b"\nCurrent exercise: ")?;
185+
terminal_file_link(stdout, self.app_state.current_exercise().path, Color::Blue)?;
186+
stdout.write_all(b"\n\n")?;
198187

199-
self.show_prompt()?;
188+
self.show_prompt(stdout)?;
200189

201190
Ok(())
202191
}
203192

204-
pub fn show_hint(&mut self) -> io::Result<()> {
193+
pub fn show_hint(&mut self, stdout: &mut StdoutLock) -> io::Result<()> {
205194
self.show_hint = true;
206-
self.render()
195+
self.render(stdout)
207196
}
208197
}

0 commit comments

Comments
 (0)