mirror of
https://github.com/rust-lang/rustlings.git
synced 2024-12-27 00:00:03 +03:00
Compare commits
6 commits
0432e07864
...
930a0ea73b
Author | SHA1 | Date | |
---|---|---|---|
930a0ea73b | |||
7e2f56f41a | |||
e90f5f03f3 | |||
0e090ae112 | |||
99496706c5 | |||
f146553dea |
15
Cargo.lock
generated
15
Cargo.lock
generated
|
@ -186,12 +186,6 @@ dependencies = [
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "foldhash"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fsevent-sys"
|
name = "fsevent-sys"
|
||||||
version = "4.1.0"
|
version = "4.1.0"
|
||||||
|
@ -283,9 +277,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.159"
|
version = "0.2.160"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
|
checksum = "f0b21006cd1874ae9e650973c565615676dc4a274c965bb0a73796dac838ce4f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libredox"
|
name = "libredox"
|
||||||
|
@ -410,9 +404,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.87"
|
version = "1.0.88"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a"
|
checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
@ -455,7 +449,6 @@ dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"foldhash",
|
|
||||||
"notify",
|
"notify",
|
||||||
"os_pipe",
|
"os_pipe",
|
||||||
"rustix",
|
"rustix",
|
||||||
|
|
|
@ -49,7 +49,6 @@ include = [
|
||||||
anyhow = "1.0.89"
|
anyhow = "1.0.89"
|
||||||
clap = { version = "4.5.20", features = ["derive"] }
|
clap = { version = "4.5.20", features = ["derive"] }
|
||||||
crossterm = { version = "0.28.1", default-features = false, features = ["windows", "events"] }
|
crossterm = { version = "0.28.1", default-features = false, features = ["windows", "events"] }
|
||||||
foldhash = "0.1.3"
|
|
||||||
notify = { version = "6.1.1", default-features = false, features = ["macos_fsevent"] }
|
notify = { version = "6.1.1", default-features = false, features = ["macos_fsevent"] }
|
||||||
os_pipe = "1.2.1"
|
os_pipe = "1.2.1"
|
||||||
rustlings-macros = { path = "rustlings-macros", version = "=6.3.0" }
|
rustlings-macros = { path = "rustlings-macros", version = "=6.3.0" }
|
||||||
|
|
12
README.md
12
README.md
|
@ -124,14 +124,13 @@ The list allows you to…
|
||||||
|
|
||||||
- See the status of all exercises (done or pending)
|
- See the status of all exercises (done or pending)
|
||||||
- `c`: Continue at another exercise (temporarily skip some exercises or go back to a previous one)
|
- `c`: Continue at another exercise (temporarily skip some exercises or go back to a previous one)
|
||||||
- `r`: Reset status and file of an exercise (you need to _reload/reopen_ its file in your editor afterwards)
|
- `r`: Reset status and file of the selected exercise (you need to _reload/reopen_ its file in your editor afterwards)
|
||||||
|
|
||||||
See the footer of the list for all possible keys.
|
See the footer of the list for all possible keys.
|
||||||
|
|
||||||
## Continuing On
|
## Questions?
|
||||||
|
|
||||||
Once you've completed Rustlings, put your new knowledge to good use!
|
If you need any help while doing the exercises and the builtin-hints aren't helpful, feel free to ask in the [_Q&A_ category of the discussions](https://github.com/rust-lang/rustlings/discussions/categories/q-a?discussions_q=) if your question wasn't asked yet 💡
|
||||||
Continue practicing your Rust skills by building your own projects, contributing to Rustlings, or finding other open-source projects to contribute to.
|
|
||||||
|
|
||||||
## Third-Party Exercises
|
## Third-Party Exercises
|
||||||
|
|
||||||
|
@ -144,6 +143,11 @@ Do you want to create your own set of Rustlings exercises to focus on some speci
|
||||||
Or do you want to translate the original Rustlings exercises?
|
Or do you want to translate the original Rustlings exercises?
|
||||||
Then follow the the guide about [third-party exercises](https://github.com/rust-lang/rustlings/blob/main/THIRD_PARTY_EXERCISES.md)!
|
Then follow the the guide about [third-party exercises](https://github.com/rust-lang/rustlings/blob/main/THIRD_PARTY_EXERCISES.md)!
|
||||||
|
|
||||||
|
## Continuing On
|
||||||
|
|
||||||
|
Once you've completed Rustlings, put your new knowledge to good use!
|
||||||
|
Continue practicing your Rust skills by building your own projects, contributing to Rustlings, or finding other open-source projects to contribute to.
|
||||||
|
|
||||||
## Uninstalling Rustlings
|
## Uninstalling Rustlings
|
||||||
|
|
||||||
If you want to remove Rustlings from your system, run the following command:
|
If you want to remove Rustlings from your system, run the following command:
|
||||||
|
|
|
@ -5,9 +5,6 @@ disallowed-types = [
|
||||||
]
|
]
|
||||||
|
|
||||||
disallowed-methods = [
|
disallowed-methods = [
|
||||||
# We use `foldhash` instead of the default hasher.
|
|
||||||
"std::collections::HashSet::new",
|
|
||||||
"std::collections::HashSet::with_capacity",
|
|
||||||
# Inefficient. Use `.queue(…)` instead.
|
# Inefficient. Use `.queue(…)` instead.
|
||||||
"crossterm::style::style",
|
"crossterm::style::style",
|
||||||
# Use `thread::Builder::spawn` instead and handle the error.
|
# Use `thread::Builder::spawn` instead and handle the error.
|
||||||
|
|
|
@ -17,7 +17,7 @@ struct TeamScores {
|
||||||
|
|
||||||
fn build_scores_table(results: &str) -> HashMap<&str, TeamScores> {
|
fn build_scores_table(results: &str) -> HashMap<&str, TeamScores> {
|
||||||
// The name of the team is the key and its associated struct is the value.
|
// The name of the team is the key and its associated struct is the value.
|
||||||
let mut scores = HashMap::new();
|
let mut scores = HashMap::<&str, TeamScores>::new();
|
||||||
|
|
||||||
for line in results.lines() {
|
for line in results.lines() {
|
||||||
let mut split_iterator = line.split(',');
|
let mut split_iterator = line.split(',');
|
||||||
|
|
|
@ -575,12 +575,8 @@ https://doc.rust-lang.org/book/ch08-03-hash-maps.html#only-inserting-a-value-if-
|
||||||
name = "hashmaps3"
|
name = "hashmaps3"
|
||||||
dir = "11_hashmaps"
|
dir = "11_hashmaps"
|
||||||
hint = """
|
hint = """
|
||||||
Hint 1: Use the `entry()` and `or_insert()` (or `or_insert_with()`) methods of
|
Hint 1: Use the `entry()` and `or_default()` methods of `HashMap` to insert the
|
||||||
`HashMap` to insert the default value of `TeamScores` if a team doesn't
|
default value of `TeamScores` if a team doesn't exist in the table yet.
|
||||||
exist in the table yet.
|
|
||||||
|
|
||||||
Learn more in The Book:
|
|
||||||
https://doc.rust-lang.org/book/ch08-03-hash-maps.html#only-inserting-a-value-if-the-key-has-no-value
|
|
||||||
|
|
||||||
Hint 2: If there is already an entry for a given key, the value returned by
|
Hint 2: If there is already an entry for a given key, the value returned by
|
||||||
`entry()` can be updated based on the existing value.
|
`entry()` can be updated based on the existing value.
|
||||||
|
|
|
@ -17,7 +17,7 @@ struct TeamScores {
|
||||||
|
|
||||||
fn build_scores_table(results: &str) -> HashMap<&str, TeamScores> {
|
fn build_scores_table(results: &str) -> HashMap<&str, TeamScores> {
|
||||||
// The name of the team is the key and its associated struct is the value.
|
// The name of the team is the key and its associated struct is the value.
|
||||||
let mut scores = HashMap::new();
|
let mut scores = HashMap::<&str, TeamScores>::new();
|
||||||
|
|
||||||
for line in results.lines() {
|
for line in results.lines() {
|
||||||
let mut split_iterator = line.split(',');
|
let mut split_iterator = line.split(',');
|
||||||
|
@ -28,17 +28,13 @@ fn build_scores_table(results: &str) -> HashMap<&str, TeamScores> {
|
||||||
let team_2_score: u8 = split_iterator.next().unwrap().parse().unwrap();
|
let team_2_score: u8 = split_iterator.next().unwrap().parse().unwrap();
|
||||||
|
|
||||||
// Insert the default with zeros if a team doesn't exist yet.
|
// Insert the default with zeros if a team doesn't exist yet.
|
||||||
let team_1 = scores
|
let team_1 = scores.entry(team_1_name).or_default();
|
||||||
.entry(team_1_name)
|
|
||||||
.or_insert_with(TeamScores::default);
|
|
||||||
// Update the values.
|
// Update the values.
|
||||||
team_1.goals_scored += team_1_score;
|
team_1.goals_scored += team_1_score;
|
||||||
team_1.goals_conceded += team_2_score;
|
team_1.goals_conceded += team_2_score;
|
||||||
|
|
||||||
// Similarly for the second team.
|
// Similarly for the second team.
|
||||||
let team_2 = scores
|
let team_2 = scores.entry(team_2_name).or_default();
|
||||||
.entry(team_2_name)
|
|
||||||
.or_insert_with(TeamScores::default);
|
|
||||||
team_2.goals_scored += team_2_score;
|
team_2.goals_scored += team_2_score;
|
||||||
team_2.goals_conceded += team_1_score;
|
team_2.goals_conceded += team_1_score;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use anyhow::{bail, Context, Error, Result};
|
use anyhow::{bail, Context, Error, Result};
|
||||||
use crossterm::{cursor, terminal, QueueableCommand};
|
use crossterm::{cursor, terminal, QueueableCommand};
|
||||||
use std::{
|
use std::{
|
||||||
|
collections::HashSet,
|
||||||
env,
|
env,
|
||||||
fs::{File, OpenOptions},
|
fs::{File, OpenOptions},
|
||||||
io::{Read, Seek, StdoutLock, Write},
|
io::{Read, Seek, StdoutLock, Write},
|
||||||
|
@ -16,7 +17,6 @@ use std::{
|
||||||
use crate::{
|
use crate::{
|
||||||
clear_terminal,
|
clear_terminal,
|
||||||
cmd::CmdRunner,
|
cmd::CmdRunner,
|
||||||
collections::hash_set_with_capacity,
|
|
||||||
embedded::EMBEDDED_FILES,
|
embedded::EMBEDDED_FILES,
|
||||||
exercise::{Exercise, RunnableExercise},
|
exercise::{Exercise, RunnableExercise},
|
||||||
info_file::ExerciseInfo,
|
info_file::ExerciseInfo,
|
||||||
|
@ -146,7 +146,7 @@ impl AppState {
|
||||||
break 'block StateFileStatus::NotRead;
|
break 'block StateFileStatus::NotRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut done_exercises = hash_set_with_capacity(exercises.len());
|
let mut done_exercises = HashSet::with_capacity(exercises.len());
|
||||||
|
|
||||||
for done_exercise_name in lines {
|
for done_exercise_name in lines {
|
||||||
if done_exercise_name.is_empty() {
|
if done_exercise_name.is_empty() {
|
||||||
|
|
|
@ -125,7 +125,7 @@ pub struct CargoSubcommand<'out> {
|
||||||
output: Option<&'out mut Vec<u8>>,
|
output: Option<&'out mut Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'out> CargoSubcommand<'out> {
|
impl CargoSubcommand<'_> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn args<'arg, I>(&mut self, args: I) -> &mut Self
|
pub fn args<'arg, I>(&mut self, args: I) -> &mut Self
|
||||||
where
|
where
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
use foldhash::fast::FixedState;
|
|
||||||
|
|
||||||
/// DOS attacks aren't a concern for Rustlings. Therefore, we use `foldhash` with a fixed state.
|
|
||||||
pub type HashSet<T> = std::collections::HashSet<T, FixedState>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn hash_set_with_capacity<T>(capacity: usize) -> HashSet<T> {
|
|
||||||
HashSet::with_capacity_and_hasher(capacity, FixedState::default())
|
|
||||||
}
|
|
|
@ -1,6 +1,7 @@
|
||||||
use anyhow::{anyhow, bail, Context, Error, Result};
|
use anyhow::{anyhow, bail, Context, Error, Result};
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
|
collections::HashSet,
|
||||||
fs::{self, read_dir, OpenOptions},
|
fs::{self, read_dir, OpenOptions},
|
||||||
io::{self, Read, Write},
|
io::{self, Read, Write},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
@ -11,7 +12,6 @@ use std::{
|
||||||
use crate::{
|
use crate::{
|
||||||
cargo_toml::{append_bins, bins_start_end_ind, BINS_BUFFER_CAPACITY},
|
cargo_toml::{append_bins, bins_start_end_ind, BINS_BUFFER_CAPACITY},
|
||||||
cmd::CmdRunner,
|
cmd::CmdRunner,
|
||||||
collections::{hash_set_with_capacity, HashSet},
|
|
||||||
exercise::{RunnableExercise, OUTPUT_CAPACITY},
|
exercise::{RunnableExercise, OUTPUT_CAPACITY},
|
||||||
info_file::{ExerciseInfo, InfoFile},
|
info_file::{ExerciseInfo, InfoFile},
|
||||||
CURRENT_FORMAT_VERSION,
|
CURRENT_FORMAT_VERSION,
|
||||||
|
@ -53,8 +53,8 @@ fn check_cargo_toml(
|
||||||
|
|
||||||
// Check the info of all exercises and return their paths in a set.
|
// Check the info of all exercises and return their paths in a set.
|
||||||
fn check_info_file_exercises(info_file: &InfoFile) -> Result<HashSet<PathBuf>> {
|
fn check_info_file_exercises(info_file: &InfoFile) -> Result<HashSet<PathBuf>> {
|
||||||
let mut names = hash_set_with_capacity(info_file.exercises.len());
|
let mut names = HashSet::with_capacity(info_file.exercises.len());
|
||||||
let mut paths = hash_set_with_capacity(info_file.exercises.len());
|
let mut paths = HashSet::with_capacity(info_file.exercises.len());
|
||||||
|
|
||||||
let mut file_buf = String::with_capacity(1 << 14);
|
let mut file_buf = String::with_capacity(1 << 14);
|
||||||
for exercise_info in &info_file.exercises {
|
for exercise_info in &info_file.exercises {
|
||||||
|
@ -282,7 +282,7 @@ fn check_solutions(
|
||||||
.collect::<Result<Vec<_>, _>>()
|
.collect::<Result<Vec<_>, _>>()
|
||||||
.context("Failed to spawn a thread to check a solution")?;
|
.context("Failed to spawn a thread to check a solution")?;
|
||||||
|
|
||||||
let mut sol_paths = hash_set_with_capacity(info_file.exercises.len());
|
let mut sol_paths = HashSet::with_capacity(info_file.exercises.len());
|
||||||
let mut fmt_cmd = Command::new("rustfmt");
|
let mut fmt_cmd = Command::new("rustfmt");
|
||||||
fmt_cmd
|
fmt_cmd
|
||||||
.arg("--check")
|
.arg("--check")
|
||||||
|
|
|
@ -105,6 +105,28 @@ impl<'a> ListState<'a> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn draw_exericse_name(&self, writer: &mut MaxLenWriter, exercise: &Exercise) -> io::Result<()> {
|
||||||
|
if !self.search_query.is_empty() {
|
||||||
|
if let Some((pre_highlight, highlight, post_highlight)) = exercise
|
||||||
|
.name
|
||||||
|
.find(&self.search_query)
|
||||||
|
.and_then(|ind| exercise.name.split_at_checked(ind))
|
||||||
|
.and_then(|(pre_highlight, rest)| {
|
||||||
|
rest.split_at_checked(self.search_query.len())
|
||||||
|
.map(|x| (pre_highlight, x.0, x.1))
|
||||||
|
})
|
||||||
|
{
|
||||||
|
writer.write_str(pre_highlight)?;
|
||||||
|
writer.stdout.queue(SetForegroundColor(Color::Magenta))?;
|
||||||
|
writer.write_str(highlight)?;
|
||||||
|
writer.stdout.queue(ResetColor)?;
|
||||||
|
return writer.write_str(post_highlight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.write_str(exercise.name)
|
||||||
|
}
|
||||||
|
|
||||||
fn draw_rows(
|
fn draw_rows(
|
||||||
&self,
|
&self,
|
||||||
stdout: &mut StdoutLock,
|
stdout: &mut StdoutLock,
|
||||||
|
@ -147,10 +169,10 @@ impl<'a> ListState<'a> {
|
||||||
writer.stdout.queue(SetForegroundColor(Color::Yellow))?;
|
writer.stdout.queue(SetForegroundColor(Color::Yellow))?;
|
||||||
writer.write_ascii(b"PENDING ")?;
|
writer.write_ascii(b"PENDING ")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.stdout.queue(SetForegroundColor(Color::Reset))?;
|
writer.stdout.queue(SetForegroundColor(Color::Reset))?;
|
||||||
|
|
||||||
writer.write_str(exercise.name)?;
|
self.draw_exericse_name(&mut writer, exercise)?;
|
||||||
|
|
||||||
writer.write_ascii(&self.name_col_padding[exercise.name.len()..])?;
|
writer.write_ascii(&self.name_col_padding[exercise.name.len()..])?;
|
||||||
|
|
||||||
// The list links aren't shown correctly in VS Code on Windows.
|
// The list links aren't shown correctly in VS Code on Windows.
|
||||||
|
|
|
@ -13,7 +13,6 @@ use self::{app_state::AppState, dev::DevCommands, info_file::InfoFile};
|
||||||
mod app_state;
|
mod app_state;
|
||||||
mod cargo_toml;
|
mod cargo_toml;
|
||||||
mod cmd;
|
mod cmd;
|
||||||
mod collections;
|
|
||||||
mod dev;
|
mod dev;
|
||||||
mod embedded;
|
mod embedded;
|
||||||
mod exercise;
|
mod exercise;
|
||||||
|
|
24
src/term.rs
24
src/term.rs
|
@ -11,15 +11,15 @@ use std::{
|
||||||
|
|
||||||
use crate::app_state::CheckProgress;
|
use crate::app_state::CheckProgress;
|
||||||
|
|
||||||
pub struct MaxLenWriter<'a, 'b> {
|
pub struct MaxLenWriter<'a, 'lock> {
|
||||||
pub stdout: &'a mut StdoutLock<'b>,
|
pub stdout: &'a mut StdoutLock<'lock>,
|
||||||
len: usize,
|
len: usize,
|
||||||
max_len: usize,
|
max_len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> MaxLenWriter<'a, 'b> {
|
impl<'a, 'lock> MaxLenWriter<'a, 'lock> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(stdout: &'a mut StdoutLock<'b>, max_len: usize) -> Self {
|
pub fn new(stdout: &'a mut StdoutLock<'lock>, max_len: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
stdout,
|
stdout,
|
||||||
len: 0,
|
len: 0,
|
||||||
|
@ -34,13 +34,13 @@ impl<'a, 'b> MaxLenWriter<'a, 'b> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CountedWrite<'a> {
|
pub trait CountedWrite<'lock> {
|
||||||
fn write_ascii(&mut self, ascii: &[u8]) -> io::Result<()>;
|
fn write_ascii(&mut self, ascii: &[u8]) -> io::Result<()>;
|
||||||
fn write_str(&mut self, unicode: &str) -> io::Result<()>;
|
fn write_str(&mut self, unicode: &str) -> io::Result<()>;
|
||||||
fn stdout(&mut self) -> &mut StdoutLock<'a>;
|
fn stdout(&mut self) -> &mut StdoutLock<'lock>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> CountedWrite<'b> for MaxLenWriter<'a, 'b> {
|
impl<'lock> CountedWrite<'lock> for MaxLenWriter<'_, 'lock> {
|
||||||
fn write_ascii(&mut self, ascii: &[u8]) -> io::Result<()> {
|
fn write_ascii(&mut self, ascii: &[u8]) -> io::Result<()> {
|
||||||
let n = ascii.len().min(self.max_len.saturating_sub(self.len));
|
let n = ascii.len().min(self.max_len.saturating_sub(self.len));
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
|
@ -65,7 +65,7 @@ impl<'a, 'b> CountedWrite<'b> for MaxLenWriter<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn stdout(&mut self) -> &mut StdoutLock<'b> {
|
fn stdout(&mut self) -> &mut StdoutLock<'lock> {
|
||||||
self.stdout
|
self.stdout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,17 +87,17 @@ impl<'a> CountedWrite<'a> for StdoutLock<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CheckProgressVisualizer<'a, 'b> {
|
pub struct CheckProgressVisualizer<'a, 'lock> {
|
||||||
stdout: &'a mut StdoutLock<'b>,
|
stdout: &'a mut StdoutLock<'lock>,
|
||||||
n_cols: usize,
|
n_cols: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> CheckProgressVisualizer<'a, 'b> {
|
impl<'a, 'lock> CheckProgressVisualizer<'a, 'lock> {
|
||||||
const CHECKING_COLOR: Color = Color::Blue;
|
const CHECKING_COLOR: Color = Color::Blue;
|
||||||
const DONE_COLOR: Color = Color::Green;
|
const DONE_COLOR: Color = Color::Green;
|
||||||
const PENDING_COLOR: Color = Color::Red;
|
const PENDING_COLOR: Color = Color::Red;
|
||||||
|
|
||||||
pub fn build(stdout: &'a mut StdoutLock<'b>, term_width: u16) -> io::Result<Self> {
|
pub fn build(stdout: &'a mut StdoutLock<'lock>, term_width: u16) -> io::Result<Self> {
|
||||||
clear_terminal(stdout)?;
|
clear_terminal(stdout)?;
|
||||||
stdout.write_all("Checking all exercises…\n".as_bytes())?;
|
stdout.write_all("Checking all exercises…\n".as_bytes())?;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue