mirror of
https://github.com/rust-lang/rustlings.git
synced 2024-12-26 15:26:29 +00:00
Compare commits
1 commit
cf2134455b
...
e64593ebb0
Author | SHA1 | Date | |
---|---|---|---|
|
e64593ebb0 |
5 changed files with 40 additions and 61 deletions
36
Cargo.lock
generated
36
Cargo.lock
generated
|
@ -4,9 +4,9 @@ version = 3
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.6.18"
|
version = "0.6.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
|
checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"anstyle-parse",
|
"anstyle-parse",
|
||||||
|
@ -19,9 +19,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle"
|
name = "anstyle"
|
||||||
version = "1.0.10"
|
version = "1.0.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle-parse"
|
name = "anstyle-parse"
|
||||||
|
@ -53,9 +53,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.93"
|
version = "1.0.91"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
|
checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
|
@ -170,9 +170,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "2.2.0"
|
version = "2.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4"
|
checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "filetime"
|
name = "filetime"
|
||||||
|
@ -197,9 +197,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.1"
|
version = "0.15.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3"
|
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
|
@ -286,9 +286,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.162"
|
version = "0.2.161"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398"
|
checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libredox"
|
name = "libredox"
|
||||||
|
@ -438,9 +438,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.40"
|
version = "0.38.38"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0"
|
checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"errno",
|
"errno",
|
||||||
|
@ -581,9 +581,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.87"
|
version = "2.0.85"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
|
checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -592,9 +592,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.14.0"
|
version = "3.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
|
checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"fastrand",
|
"fastrand",
|
||||||
|
|
|
@ -46,7 +46,7 @@ include = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.93"
|
anyhow = "1.0.91"
|
||||||
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"] }
|
||||||
notify = "7.0.0"
|
notify = "7.0.0"
|
||||||
|
@ -60,7 +60,7 @@ toml_edit.workspace = true
|
||||||
rustix = { version = "0.38.38", default-features = false, features = ["std", "stdio", "termios"] }
|
rustix = { version = "0.38.38", default-features = false, features = ["std", "stdio", "termios"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3.14.0"
|
tempfile = "3.13.0"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|
|
@ -11,6 +11,3 @@ cargo clippy -- --deny warnings
|
||||||
cargo fmt --all --check
|
cargo fmt --all --check
|
||||||
cargo test --workspace --all-targets
|
cargo test --workspace --all-targets
|
||||||
cargo run -- dev check --require-solutions
|
cargo run -- dev check --require-solutions
|
||||||
|
|
||||||
# MSRV
|
|
||||||
cargo +1.80 run -- dev check --require-solutions
|
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use crossterm::{
|
use crossterm::{
|
||||||
cursor::{MoveTo, MoveToNextLine},
|
cursor::{MoveTo, MoveToNextLine},
|
||||||
style::{
|
style::{Attribute, Color, ResetColor, SetAttribute, SetBackgroundColor, SetForegroundColor},
|
||||||
Attribute, Attributes, Color, ResetColor, SetAttribute, SetAttributes, SetForegroundColor,
|
|
||||||
},
|
|
||||||
terminal::{self, BeginSynchronizedUpdate, Clear, ClearType, EndSynchronizedUpdate},
|
terminal::{self, BeginSynchronizedUpdate, Clear, ClearType, EndSynchronizedUpdate},
|
||||||
QueueableCommand,
|
QueueableCommand,
|
||||||
};
|
};
|
||||||
|
@ -21,9 +19,6 @@ use crate::{
|
||||||
use super::scroll_state::ScrollState;
|
use super::scroll_state::ScrollState;
|
||||||
|
|
||||||
const COL_SPACING: usize = 2;
|
const COL_SPACING: usize = 2;
|
||||||
const SELECTED_ROW_ATTRIBUTES: Attributes = Attributes::none()
|
|
||||||
.with(Attribute::Reverse)
|
|
||||||
.with(Attribute::Bold);
|
|
||||||
|
|
||||||
fn next_ln(stdout: &mut StdoutLock) -> io::Result<()> {
|
fn next_ln(stdout: &mut StdoutLock) -> io::Result<()> {
|
||||||
stdout
|
stdout
|
||||||
|
@ -46,7 +41,6 @@ pub struct ListState<'a> {
|
||||||
app_state: &'a mut AppState,
|
app_state: &'a mut AppState,
|
||||||
scroll_state: ScrollState,
|
scroll_state: ScrollState,
|
||||||
name_col_padding: Vec<u8>,
|
name_col_padding: Vec<u8>,
|
||||||
path_col_padding: Vec<u8>,
|
|
||||||
filter: Filter,
|
filter: Filter,
|
||||||
term_width: u16,
|
term_width: u16,
|
||||||
term_height: u16,
|
term_height: u16,
|
||||||
|
@ -58,18 +52,13 @@ impl<'a> ListState<'a> {
|
||||||
stdout.queue(Clear(ClearType::All))?;
|
stdout.queue(Clear(ClearType::All))?;
|
||||||
|
|
||||||
let name_col_title_len = 4;
|
let name_col_title_len = 4;
|
||||||
let path_col_title_len = 4;
|
let name_col_width = app_state
|
||||||
let (name_col_width, path_col_width) = app_state.exercises().iter().fold(
|
.exercises()
|
||||||
(name_col_title_len, path_col_title_len),
|
.iter()
|
||||||
|(name_col_width, path_col_width), exercise| {
|
.map(|exercise| exercise.name.len())
|
||||||
(
|
.max()
|
||||||
name_col_width.max(exercise.name.len()),
|
.map_or(name_col_title_len, |max| max.max(name_col_title_len));
|
||||||
path_col_width.max(exercise.path.len()),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let name_col_padding = vec![b' '; name_col_width + COL_SPACING];
|
let name_col_padding = vec![b' '; name_col_width + COL_SPACING];
|
||||||
let path_col_padding = vec![b' '; path_col_width];
|
|
||||||
|
|
||||||
let filter = Filter::None;
|
let filter = Filter::None;
|
||||||
let n_rows_with_filter = app_state.exercises().len();
|
let n_rows_with_filter = app_state.exercises().len();
|
||||||
|
@ -84,7 +73,6 @@ impl<'a> ListState<'a> {
|
||||||
app_state,
|
app_state,
|
||||||
scroll_state,
|
scroll_state,
|
||||||
name_col_padding,
|
name_col_padding,
|
||||||
path_col_padding,
|
|
||||||
filter,
|
filter,
|
||||||
// Set by `set_term_size`
|
// Set by `set_term_size`
|
||||||
term_width: 0,
|
term_width: 0,
|
||||||
|
@ -117,7 +105,7 @@ impl<'a> ListState<'a> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_exercise_name(&self, writer: &mut MaxLenWriter, exercise: &Exercise) -> io::Result<()> {
|
fn draw_exericse_name(&self, writer: &mut MaxLenWriter, exercise: &Exercise) -> io::Result<()> {
|
||||||
if !self.search_query.is_empty() {
|
if !self.search_query.is_empty() {
|
||||||
if let Some((pre_highlight, highlight, post_highlight)) = exercise
|
if let Some((pre_highlight, highlight, post_highlight)) = exercise
|
||||||
.name
|
.name
|
||||||
|
@ -131,7 +119,7 @@ impl<'a> ListState<'a> {
|
||||||
writer.write_str(pre_highlight)?;
|
writer.write_str(pre_highlight)?;
|
||||||
writer.stdout.queue(SetForegroundColor(Color::Magenta))?;
|
writer.stdout.queue(SetForegroundColor(Color::Magenta))?;
|
||||||
writer.write_str(highlight)?;
|
writer.write_str(highlight)?;
|
||||||
writer.stdout.queue(SetForegroundColor(Color::Reset))?;
|
writer.stdout.queue(ResetColor)?;
|
||||||
return writer.write_str(post_highlight);
|
return writer.write_str(post_highlight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,12 +143,14 @@ impl<'a> ListState<'a> {
|
||||||
let mut writer = MaxLenWriter::new(stdout, self.term_width as usize);
|
let mut writer = MaxLenWriter::new(stdout, self.term_width as usize);
|
||||||
|
|
||||||
if self.scroll_state.selected() == Some(row_offset + n_displayed_rows) {
|
if self.scroll_state.selected() == Some(row_offset + n_displayed_rows) {
|
||||||
|
writer.stdout.queue(SetBackgroundColor(Color::Rgb {
|
||||||
|
r: 40,
|
||||||
|
g: 40,
|
||||||
|
b: 40,
|
||||||
|
}))?;
|
||||||
// The crab emoji has the width of two ascii chars.
|
// The crab emoji has the width of two ascii chars.
|
||||||
writer.add_to_len(2);
|
writer.add_to_len(2);
|
||||||
writer.stdout.write_all("🦀".as_bytes())?;
|
writer.stdout.write_all("🦀".as_bytes())?;
|
||||||
writer
|
|
||||||
.stdout
|
|
||||||
.queue(SetAttributes(SELECTED_ROW_ATTRIBUTES))?;
|
|
||||||
} else {
|
} else {
|
||||||
writer.write_ascii(b" ")?;
|
writer.write_ascii(b" ")?;
|
||||||
}
|
}
|
||||||
|
@ -174,15 +164,14 @@ impl<'a> ListState<'a> {
|
||||||
|
|
||||||
if exercise.done {
|
if exercise.done {
|
||||||
writer.stdout.queue(SetForegroundColor(Color::Green))?;
|
writer.stdout.queue(SetForegroundColor(Color::Green))?;
|
||||||
writer.write_ascii(b"DONE ")?;
|
writer.write_ascii(b"DONE ")?;
|
||||||
} else {
|
} else {
|
||||||
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_ascii(b" ")?;
|
|
||||||
|
|
||||||
self.draw_exercise_name(&mut writer, exercise)?;
|
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()..])?;
|
||||||
|
|
||||||
|
@ -194,8 +183,6 @@ impl<'a> ListState<'a> {
|
||||||
exercise.terminal_file_link(&mut writer)?;
|
exercise.terminal_file_link(&mut writer)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.write_ascii(&self.path_col_padding[exercise.path.len()..])?;
|
|
||||||
|
|
||||||
next_ln(stdout)?;
|
next_ln(stdout)?;
|
||||||
stdout.queue(ResetColor)?;
|
stdout.queue(ResetColor)?;
|
||||||
n_displayed_rows += 1;
|
n_displayed_rows += 1;
|
||||||
|
|
|
@ -20,10 +20,6 @@ use crate::{
|
||||||
|
|
||||||
use super::{terminal_event::terminal_event_handler, InputPauseGuard, WatchEvent};
|
use super::{terminal_event::terminal_event_handler, InputPauseGuard, WatchEvent};
|
||||||
|
|
||||||
const HEADING_ATTRIBUTES: Attributes = Attributes::none()
|
|
||||||
.with(Attribute::Bold)
|
|
||||||
.with(Attribute::Underlined);
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq)]
|
#[derive(PartialEq, Eq)]
|
||||||
enum DoneStatus {
|
enum DoneStatus {
|
||||||
DoneWithSolution(String),
|
DoneWithSolution(String),
|
||||||
|
@ -213,7 +209,9 @@ impl<'a> WatchState<'a> {
|
||||||
|
|
||||||
if self.show_hint {
|
if self.show_hint {
|
||||||
stdout
|
stdout
|
||||||
.queue(SetAttributes(HEADING_ATTRIBUTES))?
|
.queue(SetAttributes(
|
||||||
|
Attributes::from(Attribute::Bold).with(Attribute::Underlined),
|
||||||
|
))?
|
||||||
.queue(SetForegroundColor(Color::Cyan))?;
|
.queue(SetForegroundColor(Color::Cyan))?;
|
||||||
stdout.write_all(b"Hint")?;
|
stdout.write_all(b"Hint")?;
|
||||||
stdout.queue(ResetColor)?;
|
stdout.queue(ResetColor)?;
|
||||||
|
@ -269,9 +267,6 @@ impl<'a> WatchState<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_all_exercises(&mut self, stdout: &mut StdoutLock) -> Result<ExercisesProgress> {
|
pub fn check_all_exercises(&mut self, stdout: &mut StdoutLock) -> Result<ExercisesProgress> {
|
||||||
// Ignore any input until checking all exercises is done.
|
|
||||||
let _input_pause_guard = InputPauseGuard::scoped_pause();
|
|
||||||
|
|
||||||
if let Some(first_pending_exercise_ind) = self.app_state.check_all_exercises(stdout)? {
|
if let Some(first_pending_exercise_ind) = self.app_state.check_all_exercises(stdout)? {
|
||||||
// Only change exercise if the current one is done.
|
// Only change exercise if the current one is done.
|
||||||
if self.app_state.current_exercise().done {
|
if self.app_state.current_exercise().done {
|
||||||
|
|
Loading…
Reference in a new issue