summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app_state.rs60
-rw-r--r--src/cmd.rs2
-rw-r--r--src/dev.rs2
-rw-r--r--src/dev/check.rs60
-rw-r--r--src/dev/new.rs10
-rw-r--r--src/exercise.rs4
-rw-r--r--src/info_file.rs2
-rw-r--r--src/init.rs12
-rw-r--r--src/list.rs7
-rw-r--r--src/list/state.rs4
-rw-r--r--src/main.rs2
-rw-r--r--src/run.rs4
-rw-r--r--src/term.rs2
-rw-r--r--src/watch/notify_event.rs6
-rw-r--r--src/watch/state.rs9
-rw-r--r--src/watch/terminal_event.rs2
16 files changed, 111 insertions, 77 deletions
diff --git a/src/app_state.rs b/src/app_state.rs
index 5979150..d1c45d4 100644
--- a/src/app_state.rs
+++ b/src/app_state.rs
@@ -1,11 +1,11 @@
-use anyhow::{bail, Context, Error, Result};
-use crossterm::{cursor, terminal, QueueableCommand};
+use anyhow::{Context, Error, Result, bail};
+use crossterm::{QueueableCommand, cursor, terminal};
use std::{
collections::HashSet,
env,
fs::{File, OpenOptions},
io::{Read, Seek, StdoutLock, Write},
- path::{Path, MAIN_SEPARATOR_STR},
+ path::{MAIN_SEPARATOR_STR, Path},
process::{Command, Stdio},
sync::{
atomic::{AtomicUsize, Ordering::Relaxed},
@@ -427,32 +427,34 @@ impl AppState {
let next_exercise_ind = &next_exercise_ind;
let slf = &self;
thread::Builder::new()
- .spawn_scoped(s, move || loop {
- let exercise_ind = next_exercise_ind.fetch_add(1, Relaxed);
- let Some(exercise) = slf.exercises.get(exercise_ind) else {
- // No more exercises.
- break;
- };
-
- if exercise_progress_sender
- .send((exercise_ind, CheckProgress::Checking))
- .is_err()
- {
- break;
- };
-
- let success = exercise.run_exercise(None, &slf.cmd_runner);
- let progress = match success {
- Ok(true) => CheckProgress::Done,
- Ok(false) => CheckProgress::Pending,
- Err(_) => CheckProgress::None,
- };
-
- if exercise_progress_sender
- .send((exercise_ind, progress))
- .is_err()
- {
- break;
+ .spawn_scoped(s, move || {
+ loop {
+ let exercise_ind = next_exercise_ind.fetch_add(1, Relaxed);
+ let Some(exercise) = slf.exercises.get(exercise_ind) else {
+ // No more exercises.
+ break;
+ };
+
+ if exercise_progress_sender
+ .send((exercise_ind, CheckProgress::Checking))
+ .is_err()
+ {
+ break;
+ };
+
+ let success = exercise.run_exercise(None, &slf.cmd_runner);
+ let progress = match success {
+ Ok(true) => CheckProgress::Done,
+ Ok(false) => CheckProgress::Pending,
+ Err(_) => CheckProgress::None,
+ };
+
+ if exercise_progress_sender
+ .send((exercise_ind, progress))
+ .is_err()
+ {
+ break;
+ }
}
})
.context("Failed to spawn a thread to check all exercises")?;
diff --git a/src/cmd.rs b/src/cmd.rs
index 30f988a..551df8f 100644
--- a/src/cmd.rs
+++ b/src/cmd.rs
@@ -1,4 +1,4 @@
-use anyhow::{bail, Context, Result};
+use anyhow::{Context, Result, bail};
use serde::Deserialize;
use std::{
io::Read,
diff --git a/src/dev.rs b/src/dev.rs
index 8af40d6..354d77c 100644
--- a/src/dev.rs
+++ b/src/dev.rs
@@ -1,4 +1,4 @@
-use anyhow::{bail, Context, Result};
+use anyhow::{Context, Result, bail};
use clap::Subcommand;
use std::path::PathBuf;
diff --git a/src/dev/check.rs b/src/dev/check.rs
index 956c2be..aacc2f4 100644
--- a/src/dev/check.rs
+++ b/src/dev/check.rs
@@ -1,8 +1,8 @@
-use anyhow::{anyhow, bail, Context, Error, Result};
+use anyhow::{Context, Error, Result, anyhow, bail};
use std::{
cmp::Ordering,
collections::HashSet,
- fs::{self, read_dir, OpenOptions},
+ fs::{self, OpenOptions, read_dir},
io::{self, Read, Write},
path::{Path, PathBuf},
process::{Command, Stdio},
@@ -10,11 +10,11 @@ use std::{
};
use crate::{
- cargo_toml::{append_bins, bins_start_end_ind, BINS_BUFFER_CAPACITY},
+ CURRENT_FORMAT_VERSION,
+ cargo_toml::{BINS_BUFFER_CAPACITY, append_bins, bins_start_end_ind},
cmd::CmdRunner,
- exercise::{RunnableExercise, OUTPUT_CAPACITY},
+ exercise::{OUTPUT_CAPACITY, RunnableExercise},
info_file::{ExerciseInfo, InfoFile},
- CURRENT_FORMAT_VERSION,
};
const MAX_N_EXERCISES: usize = 999;
@@ -42,10 +42,14 @@ fn check_cargo_toml(
if old_bins != new_bins {
if cfg!(debug_assertions) {
- bail!("The file `dev/Cargo.toml` is outdated. Run `cargo run -- dev update` to update it. Then run `cargo run -- dev check` again");
+ bail!(
+ "The file `dev/Cargo.toml` is outdated. Run `cargo run -- dev update` to update it. Then run `cargo run -- dev check` again"
+ );
}
- bail!("The file `Cargo.toml` is outdated. Run `rustlings dev update` to update it. Then run `rustlings dev check` again");
+ bail!(
+ "The file `Cargo.toml` is outdated. Run `rustlings dev update` to update it. Then run `rustlings dev check` again"
+ );
}
Ok(())
@@ -63,7 +67,9 @@ fn check_info_file_exercises(info_file: &InfoFile) -> Result<HashSet<PathBuf>> {
bail!("Found an empty exercise name in `info.toml`");
}
if name.len() > MAX_EXERCISE_NAME_LEN {
- bail!("The length of the exercise name `{name}` is bigger than the maximum {MAX_EXERCISE_NAME_LEN}");
+ bail!(
+ "The length of the exercise name `{name}` is bigger than the maximum {MAX_EXERCISE_NAME_LEN}"
+ );
}
if let Some(c) = forbidden_char(name) {
bail!("Char `{c}` in the exercise name `{name}` is not allowed");
@@ -79,7 +85,9 @@ fn check_info_file_exercises(info_file: &InfoFile) -> Result<HashSet<PathBuf>> {
}
if exercise_info.hint.trim_ascii().is_empty() {
- bail!("The exercise `{name}` has an empty hint. Please provide a hint or at least tell the user why a hint isn't needed for this exercise");
+ bail!(
+ "The exercise `{name}` has an empty hint. Please provide a hint or at least tell the user why a hint isn't needed for this exercise"
+ );
}
if !names.insert(name) {
@@ -96,20 +104,28 @@ fn check_info_file_exercises(info_file: &InfoFile) -> Result<HashSet<PathBuf>> {
.with_context(|| format!("Failed to read the file {path}"))?;
if !file_buf.contains("fn main()") {
- bail!("The `main` function is missing in the file `{path}`.\nCreate at least an empty `main` function to avoid language server errors");
+ bail!(
+ "The `main` function is missing in the file `{path}`.\nCreate at least an empty `main` function to avoid language server errors"
+ );
}
if !file_buf.contains("// TODO") {
- bail!("Didn't find any `// TODO` comment in the file `{path}`.\nYou need to have at least one such comment to guide the user.");
+ bail!(
+ "Didn't find any `// TODO` comment in the file `{path}`.\nYou need to have at least one such comment to guide the user."
+ );
}
let contains_tests = file_buf.contains("#[test]\n");
if exercise_info.test {
if !contains_tests {
- bail!("The file `{path}` doesn't contain any tests. If you don't want to add tests to this exercise, set `test = false` for this exercise in the `info.toml` file");
+ bail!(
+ "The file `{path}` doesn't contain any tests. If you don't want to add tests to this exercise, set `test = false` for this exercise in the `info.toml` file"
+ );
}
} else if contains_tests {
- bail!("The file `{path}` contains tests annotated with `#[test]` but the exercise `{name}` has `test = false` in the `info.toml` file");
+ bail!(
+ "The file `{path}` contains tests annotated with `#[test]` but the exercise `{name}` has `test = false` in the `info.toml` file"
+ );
}
file_buf.clear();
@@ -125,7 +141,10 @@ fn check_info_file_exercises(info_file: &InfoFile) -> Result<HashSet<PathBuf>> {
// Only one level of directory nesting is allowed.
fn check_unexpected_files(dir: &str, allowed_rust_files: &HashSet<PathBuf>) -> Result<()> {
let unexpected_file = |path: &Path| {
- anyhow!("Found the file `{}`. Only `README.md` and Rust files related to an exercise in `info.toml` are allowed in the `{dir}` directory", path.display())
+ anyhow!(
+ "Found the file `{}`. Only `README.md` and Rust files related to an exercise in `info.toml` are allowed in the `{dir}` directory",
+ path.display()
+ )
};
for entry in read_dir(dir).with_context(|| format!("Failed to open the `{dir}` directory"))? {
@@ -154,7 +173,10 @@ fn check_unexpected_files(dir: &str, allowed_rust_files: &HashSet<PathBuf>) -> R
let path = entry.path();
if !entry.file_type().unwrap().is_file() {
- bail!("Found `{}` but expected only files. Only one level of exercise nesting is allowed", path.display());
+ bail!(
+ "Found `{}` but expected only files. Only one level of exercise nesting is allowed",
+ path.display()
+ );
}
let file_name = path.file_name().unwrap();
@@ -224,8 +246,12 @@ fn check_exercises_unsolved(
fn check_exercises(info_file: &'static InfoFile, cmd_runner: &'static CmdRunner) -> Result<()> {
match info_file.format_version.cmp(&CURRENT_FORMAT_VERSION) {
- Ordering::Less => bail!("`format_version` < {CURRENT_FORMAT_VERSION} (supported version)\nPlease migrate to the latest format version"),
- Ordering::Greater => bail!("`format_version` > {CURRENT_FORMAT_VERSION} (supported version)\nTry updating the Rustlings program"),
+ Ordering::Less => bail!(
+ "`format_version` < {CURRENT_FORMAT_VERSION} (supported version)\nPlease migrate to the latest format version"
+ ),
+ Ordering::Greater => bail!(
+ "`format_version` > {CURRENT_FORMAT_VERSION} (supported version)\nTry updating the Rustlings program"
+ ),
Ordering::Equal => (),
}
diff --git a/src/dev/new.rs b/src/dev/new.rs
index 154cd22..ba3517f 100644
--- a/src/dev/new.rs
+++ b/src/dev/new.rs
@@ -1,4 +1,4 @@
-use anyhow::{bail, Context, Result};
+use anyhow::{Context, Result, bail};
use std::{
env::set_current_dir,
fs::{self, create_dir},
@@ -6,7 +6,7 @@ use std::{
process::Command,
};
-use crate::{init::RUST_ANALYZER_TOML, CURRENT_FORMAT_VERSION};
+use crate::{CURRENT_FORMAT_VERSION, init::RUST_ANALYZER_TOML};
// Create a directory relative to the current directory and print its path.
fn create_rel_dir(dir_name: &str, current_dir: &str) -> Result<()> {
@@ -55,7 +55,9 @@ pub fn new(path: &Path, no_git: bool) -> Result<()> {
write_rel_file(
"info.toml",
&dir_path_str,
- format!("{INFO_FILE_BEFORE_FORMAT_VERSION}{CURRENT_FORMAT_VERSION}{INFO_FILE_AFTER_FORMAT_VERSION}"),
+ format!(
+ "{INFO_FILE_BEFORE_FORMAT_VERSION}{CURRENT_FORMAT_VERSION}{INFO_FILE_AFTER_FORMAT_VERSION}"
+ ),
)?;
write_rel_file("Cargo.toml", &dir_path_str, CARGO_TOML)?;
@@ -130,7 +132,7 @@ bin = []
[package]
name = "exercises"
-edition = "2021"
+edition = "2024"
# Don't publish the exercises on crates.io!
publish = false
diff --git a/src/exercise.rs b/src/exercise.rs
index 8490828..fdfbc4f 100644
--- a/src/exercise.rs
+++ b/src/exercise.rs
@@ -1,13 +1,13 @@
use anyhow::Result;
use crossterm::{
- style::{Attribute, Color, ResetColor, SetAttribute, SetForegroundColor},
QueueableCommand,
+ style::{Attribute, Color, ResetColor, SetAttribute, SetForegroundColor},
};
use std::io::{self, StdoutLock, Write};
use crate::{
cmd::CmdRunner,
- term::{self, terminal_file_link, write_ansi, CountedWrite},
+ term::{self, CountedWrite, terminal_file_link, write_ansi},
};
/// The initial capacity of the output buffer.
diff --git a/src/info_file.rs b/src/info_file.rs
index fdc8f0f..ec61f8a 100644
--- a/src/info_file.rs
+++ b/src/info_file.rs
@@ -1,4 +1,4 @@
-use anyhow::{bail, Context, Error, Result};
+use anyhow::{Context, Error, Result, bail};
use serde::Deserialize;
use std::{fs, io::ErrorKind};
diff --git a/src/init.rs b/src/init.rs
index ce49bb6..208425c 100644
--- a/src/init.rs
+++ b/src/init.rs
@@ -1,7 +1,7 @@
-use anyhow::{bail, Context, Result};
+use anyhow::{Context, Result, bail};
use crossterm::{
- style::{Attribute, Color, ResetColor, SetAttribute, SetForegroundColor},
QueueableCommand,
+ style::{Attribute, Color, ResetColor, SetAttribute, SetForegroundColor},
};
use serde::Deserialize;
use std::{
@@ -57,7 +57,9 @@ pub fn init() -> Result<()> {
if !workspace_manifest_content.contains("[workspace]\n")
&& !workspace_manifest_content.contains("workspace.")
{
- bail!("The current directory is already part of a Cargo project.\nPlease initialize Rustlings in a different directory");
+ bail!(
+ "The current directory is already part of a Cargo project.\nPlease initialize Rustlings in a different directory"
+ );
}
stdout.write_all(b"This command will create the directory `rustlings/` as a member of this Cargo workspace.\nPress ENTER to continue ")?;
@@ -75,7 +77,9 @@ pub fn init() -> Result<()> {
.stdout(Stdio::null())
.status()?;
if !status.success() {
- bail!("Failed to initialize a new Cargo workspace member.\nPlease initialize Rustlings in a different directory");
+ bail!(
+ "Failed to initialize a new Cargo workspace member.\nPlease initialize Rustlings in a different directory"
+ );
}
stdout.write_all(b"The directory `rustlings` has been added to `workspace.members` in the `Cargo.toml` file of this Cargo workspace.\n")?;
diff --git a/src/list.rs b/src/list.rs
index 9f243a1..a2eee9e 100644
--- a/src/list.rs
+++ b/src/list.rs
@@ -1,14 +1,13 @@
use anyhow::{Context, Result};
use crossterm::{
- cursor,
+ QueueableCommand, cursor,
event::{
self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEventKind, MouseEventKind,
},
terminal::{
- disable_raw_mode, enable_raw_mode, DisableLineWrap, EnableLineWrap, EnterAlternateScreen,
- LeaveAlternateScreen,
+ DisableLineWrap, EnableLineWrap, EnterAlternateScreen, LeaveAlternateScreen,
+ disable_raw_mode, enable_raw_mode,
},
- QueueableCommand,
};
use std::io::{self, StdoutLock, Write};
diff --git a/src/list/state.rs b/src/list/state.rs
index 0670fa4..ae65ec2 100644
--- a/src/list/state.rs
+++ b/src/list/state.rs
@@ -1,11 +1,11 @@
use anyhow::{Context, Result};
use crossterm::{
+ QueueableCommand,
cursor::{MoveTo, MoveToNextLine},
style::{
Attribute, Attributes, Color, ResetColor, SetAttribute, SetAttributes, SetForegroundColor,
},
terminal::{self, BeginSynchronizedUpdate, Clear, ClearType, EndSynchronizedUpdate},
- QueueableCommand,
};
use std::{
fmt::Write as _,
@@ -15,7 +15,7 @@ use std::{
use crate::{
app_state::AppState,
exercise::Exercise,
- term::{progress_bar, CountedWrite, MaxLenWriter},
+ term::{CountedWrite, MaxLenWriter, progress_bar},
};
use super::scroll_state::ScrollState;
diff --git a/src/main.rs b/src/main.rs
index eeb1883..6688e3e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,4 @@
-use anyhow::{bail, Context, Result};
+use anyhow::{Context, Result, bail};
use app_state::StateFileStatus;
use clap::{Parser, Subcommand};
use std::{
diff --git a/src/run.rs b/src/run.rs
index ac8b26a..6f4f099 100644
--- a/src/run.rs
+++ b/src/run.rs
@@ -1,7 +1,7 @@
use anyhow::Result;
use crossterm::{
- style::{Color, ResetColor, SetForegroundColor},
QueueableCommand,
+ style::{Color, ResetColor, SetForegroundColor},
};
use std::{
io::{self, Write},
@@ -10,7 +10,7 @@ use std::{
use crate::{
app_state::{AppState, ExercisesProgress},
- exercise::{solution_link_line, RunnableExercise, OUTPUT_CAPACITY},
+ exercise::{OUTPUT_CAPACITY, RunnableExercise, solution_link_line},
};
pub fn run(app_state: &mut AppState) -> Result<ExitCode> {
diff --git a/src/term.rs b/src/term.rs
index cb0a07c..1e08c84 100644
--- a/src/term.rs
+++ b/src/term.rs
@@ -1,8 +1,8 @@
use crossterm::{
+ Command, QueueableCommand,
cursor::MoveTo,
style::{Attribute, Color, ResetColor, SetAttribute, SetForegroundColor},
terminal::{Clear, ClearType},
- Command, QueueableCommand,
};
use std::{
fmt, fs,
diff --git a/src/watch/notify_event.rs b/src/watch/notify_event.rs
index 2051e54..9c05f10 100644
--- a/src/watch/notify_event.rs
+++ b/src/watch/notify_event.rs
@@ -1,18 +1,18 @@
use anyhow::{Context, Result};
use notify::{
- event::{AccessKind, AccessMode, MetadataKind, ModifyKind, RenameMode},
Event, EventKind,
+ event::{AccessKind, AccessMode, MetadataKind, ModifyKind, RenameMode},
};
use std::{
sync::{
atomic::Ordering::Relaxed,
- mpsc::{sync_channel, RecvTimeoutError, Sender, SyncSender},
+ mpsc::{RecvTimeoutError, Sender, SyncSender, sync_channel},
},
thread,
time::Duration,
};
-use super::{WatchEvent, EXERCISE_RUNNING};
+use super::{EXERCISE_RUNNING, WatchEvent};
const DEBOUNCE_DURATION: Duration = Duration::from_millis(200);
diff --git a/src/watch/state.rs b/src/watch/state.rs
index 5263bc5..2413bec 100644
--- a/src/watch/state.rs
+++ b/src/watch/state.rs
@@ -1,24 +1,25 @@
use anyhow::{Context, Result};
use crossterm::{
+ QueueableCommand,
style::{
Attribute, Attributes, Color, ResetColor, SetAttribute, SetAttributes, SetForegroundColor,
},
- terminal, QueueableCommand,
+ terminal,
};
use std::{
io::{self, Read, StdoutLock, Write},
- sync::mpsc::{sync_channel, Sender, SyncSender},
+ sync::mpsc::{Sender, SyncSender, sync_channel},
thread,
};
use crate::{
app_state::{AppState, ExercisesProgress},
clear_terminal,
- exercise::{solution_link_line, RunnableExercise, OUTPUT_CAPACITY},
+ exercise::{OUTPUT_CAPACITY, RunnableExercise, solution_link_line},
term::progress_bar,
};
-use super::{terminal_event::terminal_event_handler, InputPauseGuard, WatchEvent};
+use super::{InputPauseGuard, WatchEvent, terminal_event::terminal_event_handler};
const HEADING_ATTRIBUTES: Attributes = Attributes::none()
.with(Attribute::Bold)
diff --git a/src/watch/terminal_event.rs b/src/watch/terminal_event.rs
index 48411db..2400a3d 100644
--- a/src/watch/terminal_event.rs
+++ b/src/watch/terminal_event.rs
@@ -4,7 +4,7 @@ use std::sync::{
mpsc::{Receiver, Sender},
};
-use super::{WatchEvent, EXERCISE_RUNNING};
+use super::{EXERCISE_RUNNING, WatchEvent};
pub enum InputEvent {
Next,