Skip to content

Commit f0a2cde

Browse files
authored
Merge branch 'rust-lang:main' into add/link-to-THIRD_PARTY-repository-for-Japanese-translations
2 parents e3ec0ab + 0c79f2e commit f0a2cde

File tree

9 files changed

+204
-57
lines changed

9 files changed

+204
-57
lines changed

Cargo.lock

Lines changed: 16 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ rust-version = "1.80"
2020

2121
[workspace.dependencies]
2222
serde = { version = "1.0.210", features = ["derive"] }
23-
toml_edit = { version = "0.22.21", default-features = false, features = ["parse", "serde"] }
23+
toml_edit = { version = "0.22.22", default-features = false, features = ["parse", "serde"] }
2424

2525
[package]
2626
name = "rustlings"
@@ -48,7 +48,7 @@ include = [
4848
[dependencies]
4949
ahash = { version = "0.8.11", default-features = false }
5050
anyhow = "1.0.89"
51-
clap = { version = "4.5.17", features = ["derive"] }
51+
clap = { version = "4.5.18", features = ["derive"] }
5252
crossterm = { version = "0.28.1", default-features = false, features = ["windows", "events"] }
5353
notify = { version = "6.1.1", default-features = false, features = ["macos_fsevent"] }
5454
os_pipe = "1.2.1"

rustlings-macros/info.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1144,7 +1144,7 @@ constants, but clippy recognizes those imprecise mathematical constants as a
11441144
source of potential error.
11451145
11461146
See the suggestions of the Clippy warning in the compile output and use the
1147-
appropriate replacement constant from `std::f32::consts`..."""
1147+
appropriate replacement constant from `std::f32::consts`."""
11481148

11491149
[[exercises]]
11501150
name = "clippy2"

src/app_state.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ impl AppState {
381381

382382
// Return the exercise index of the first pending exercise found.
383383
fn check_all_exercises(&self, stdout: &mut StdoutLock) -> Result<Option<usize>> {
384-
stdout.write_all(RERUNNING_ALL_EXERCISES_MSG)?;
384+
stdout.write_all(FINAL_CHECK_MSG)?;
385385
let n_exercises = self.exercises.len();
386386

387387
let status = thread::scope(|s| {
@@ -441,7 +441,10 @@ impl AppState {
441441
/// Mark the current exercise as done and move on to the next pending exercise if one exists.
442442
/// If all exercises are marked as done, run all of them to make sure that they are actually
443443
/// done. If an exercise which is marked as done fails, mark it as pending and continue on it.
444-
pub fn done_current_exercise(&mut self, stdout: &mut StdoutLock) -> Result<ExercisesProgress> {
444+
pub fn done_current_exercise<const CLEAR_BEFORE_FINAL_CHECK: bool>(
445+
&mut self,
446+
stdout: &mut StdoutLock,
447+
) -> Result<ExercisesProgress> {
445448
let exercise = &mut self.exercises[self.current_exercise_ind];
446449
if !exercise.done {
447450
exercise.done = true;
@@ -453,6 +456,12 @@ impl AppState {
453456
return Ok(ExercisesProgress::NewPending);
454457
}
455458

459+
if CLEAR_BEFORE_FINAL_CHECK {
460+
clear_terminal(stdout)?;
461+
} else {
462+
stdout.write_all(b"\n")?;
463+
}
464+
456465
if let Some(pending_exercise_ind) = self.check_all_exercises(stdout)? {
457466
stdout.write_all(b"\n\n")?;
458467

@@ -482,8 +491,7 @@ impl AppState {
482491

483492
const BAD_INDEX_ERR: &str = "The current exercise index is higher than the number of exercises";
484493
const STATE_FILE_HEADER: &[u8] = b"DON'T EDIT THIS FILE!\n\n";
485-
const RERUNNING_ALL_EXERCISES_MSG: &[u8] = b"
486-
All exercises seem to be done.
494+
const FINAL_CHECK_MSG: &[u8] = b"All exercises seem to be done.
487495
Recompiling and running all exercises to make sure that all of them are actually done.
488496
";
489497
const FENISH_LINE: &str = "+----------------------------------------------------+

src/run.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ pub fn run(app_state: &mut AppState) -> Result<()> {
4444
stdout.write_all(b"\n")?;
4545
}
4646

47-
match app_state.done_current_exercise(&mut stdout)? {
47+
match app_state.done_current_exercise::<false>(&mut stdout)? {
4848
ExercisesProgress::NewPending | ExercisesProgress::CurrentPending => {
4949
stdout.write_all(b"Next exercise: ")?;
5050
app_state

src/watch.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,11 @@ fn run_watch(
6969
// Prevent dropping the guard until the end of the function.
7070
// Otherwise, the file watcher exits.
7171
let _watcher_guard = if let Some(exercise_names) = notify_exercise_names {
72+
let notify_event_handler =
73+
NotifyEventHandler::build(watch_event_sender.clone(), exercise_names)?;
74+
7275
let mut watcher = RecommendedWatcher::new(
73-
NotifyEventHandler {
74-
sender: watch_event_sender.clone(),
75-
exercise_names,
76-
},
76+
notify_event_handler,
7777
Config::default().with_poll_interval(Duration::from_secs(1)),
7878
)
7979
.inspect_err(|_| eprintln!("{NOTIFY_ERR}"))?;
@@ -100,13 +100,14 @@ fn run_watch(
100100
ExercisesProgress::NewPending => watch_state.run_current_exercise(&mut stdout)?,
101101
ExercisesProgress::CurrentPending => (),
102102
},
103+
WatchEvent::Input(InputEvent::Run) => watch_state.run_current_exercise(&mut stdout)?,
103104
WatchEvent::Input(InputEvent::Hint) => watch_state.show_hint(&mut stdout)?,
104105
WatchEvent::Input(InputEvent::List) => return Ok(WatchExit::List),
106+
WatchEvent::Input(InputEvent::Reset) => watch_state.reset_exercise(&mut stdout)?,
105107
WatchEvent::Input(InputEvent::Quit) => {
106108
stdout.write_all(QUIT_MSG)?;
107109
break;
108110
}
109-
WatchEvent::Input(InputEvent::Run) => watch_state.run_current_exercise(&mut stdout)?,
110111
WatchEvent::FileChange { exercise_ind } => {
111112
watch_state.handle_file_change(exercise_ind, &mut stdout)?;
112113
}

src/watch/notify_event.rs

Lines changed: 78 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,71 @@
1+
use anyhow::{Context, Result};
12
use notify::{
2-
event::{MetadataKind, ModifyKind},
3+
event::{AccessKind, AccessMode, MetadataKind, ModifyKind, RenameMode},
34
Event, EventKind,
45
};
5-
use std::sync::{atomic::Ordering::Relaxed, mpsc::Sender};
6+
use std::{
7+
sync::{
8+
atomic::Ordering::Relaxed,
9+
mpsc::{sync_channel, RecvTimeoutError, Sender, SyncSender},
10+
},
11+
thread,
12+
time::Duration,
13+
};
614

715
use super::{WatchEvent, EXERCISE_RUNNING};
816

17+
const DEBOUNCE_DURATION: Duration = Duration::from_millis(200);
18+
919
pub struct NotifyEventHandler {
10-
pub sender: Sender<WatchEvent>,
11-
/// Used to report which exercise was modified.
12-
pub exercise_names: &'static [&'static [u8]],
20+
error_sender: Sender<WatchEvent>,
21+
// Sends the index of the updated exercise.
22+
update_sender: SyncSender<usize>,
23+
// Used to report which exercise was modified.
24+
exercise_names: &'static [&'static [u8]],
25+
}
26+
27+
impl NotifyEventHandler {
28+
pub fn build(
29+
watch_event_sender: Sender<WatchEvent>,
30+
exercise_names: &'static [&'static [u8]],
31+
) -> Result<Self> {
32+
let (update_sender, update_receiver) = sync_channel(0);
33+
let error_sender = watch_event_sender.clone();
34+
35+
// Debouncer
36+
thread::Builder::new()
37+
.spawn(move || {
38+
let mut exercise_updated = vec![false; exercise_names.len()];
39+
40+
loop {
41+
match update_receiver.recv_timeout(DEBOUNCE_DURATION) {
42+
Ok(exercise_ind) => exercise_updated[exercise_ind] = true,
43+
Err(RecvTimeoutError::Timeout) => {
44+
for (exercise_ind, updated) in exercise_updated.iter_mut().enumerate() {
45+
if *updated {
46+
if watch_event_sender
47+
.send(WatchEvent::FileChange { exercise_ind })
48+
.is_err()
49+
{
50+
break;
51+
}
52+
53+
*updated = false;
54+
}
55+
}
56+
}
57+
Err(RecvTimeoutError::Disconnected) => break,
58+
}
59+
}
60+
})
61+
.context("Failed to spawn a thread to debounce file changes")?;
62+
63+
Ok(Self {
64+
error_sender,
65+
update_sender,
66+
exercise_names,
67+
})
68+
}
1369
}
1470

1571
impl notify::EventHandler for NotifyEventHandler {
@@ -22,8 +78,8 @@ impl notify::EventHandler for NotifyEventHandler {
2278
Ok(v) => v,
2379
Err(e) => {
2480
// An error occurs when the receiver is dropped.
25-
// After dropping the receiver, the debouncer guard should also be dropped.
26-
let _ = self.sender.send(WatchEvent::NotifyErr(e));
81+
// After dropping the receiver, the watcher guard should also be dropped.
82+
let _ = self.error_sender.send(WatchEvent::NotifyErr(e));
2783
return;
2884
}
2985
};
@@ -32,6 +88,10 @@ impl notify::EventHandler for NotifyEventHandler {
3288
EventKind::Any => (),
3389
EventKind::Modify(modify_kind) => match modify_kind {
3490
ModifyKind::Any | ModifyKind::Data(_) => (),
91+
ModifyKind::Name(rename_mode) => match rename_mode {
92+
RenameMode::Any | RenameMode::To => (),
93+
RenameMode::From | RenameMode::Both | RenameMode::Other => return,
94+
},
3595
ModifyKind::Metadata(metadata_kind) => match metadata_kind {
3696
MetadataKind::Any | MetadataKind::WriteTime => (),
3797
MetadataKind::AccessTime
@@ -40,12 +100,17 @@ impl notify::EventHandler for NotifyEventHandler {
40100
| MetadataKind::Extended
41101
| MetadataKind::Other => return,
42102
},
43-
ModifyKind::Name(_) | ModifyKind::Other => return,
103+
ModifyKind::Other => return,
104+
},
105+
EventKind::Access(access_kind) => match access_kind {
106+
AccessKind::Any => (),
107+
AccessKind::Close(access_mode) => match access_mode {
108+
AccessMode::Any | AccessMode::Write => (),
109+
AccessMode::Execute | AccessMode::Read | AccessMode::Other => return,
110+
},
111+
AccessKind::Read | AccessKind::Open(_) | AccessKind::Other => return,
44112
},
45-
EventKind::Access(_)
46-
| EventKind::Create(_)
47-
| EventKind::Remove(_)
48-
| EventKind::Other => return,
113+
EventKind::Create(_) | EventKind::Remove(_) | EventKind::Other => return,
49114
}
50115

51116
let _ = input_event
@@ -62,6 +127,6 @@ impl notify::EventHandler for NotifyEventHandler {
62127
.iter()
63128
.position(|exercise_name| *exercise_name == file_name_without_ext)
64129
})
65-
.try_for_each(|exercise_ind| self.sender.send(WatchEvent::FileChange { exercise_ind }));
130+
.try_for_each(|exercise_ind| self.update_sender.send(exercise_ind));
66131
}
67132
}

0 commit comments

Comments
 (0)