Compare commits

..

11 commits

Author SHA1 Message Date
Kacper Poneta fd8c0d2ab4
Merge 59e8f70e55 into f696d98270 2024-09-03 01:43:53 -05:00
Mo f696d98270
Merge pull request #2097 from jsejcksn/ux
style: reduce pre-formatted message line lengths to 80 columns
2024-09-02 14:20:18 +02:00
mo8it a8b13f5a82 Remove "exercises" from the end of the progress bar 2024-09-01 22:04:09 +02:00
mo8it 86fc573d7a Remove the footer separators 2024-09-01 22:02:07 +02:00
Jesse Jackson f82e47f2af style: reduce pre-formatted message line lengths to 80 columns 2024-09-01 14:48:28 -05:00
mo8it 75a38fa38b Add search to the help footer 2024-09-01 20:44:19 +02:00
mo8it ac62a3713c Fix typo 2024-09-01 20:31:16 +02:00
Mo ea52c99560
Merge pull request #2092 from wugalde19/fix-hint-example-for-primitive-types3
Fix example in 'primitive_types3' hint
2024-08-31 05:27:36 +02:00
William Ugalde Gamboa 7d4100ed8a Fix example in 'primitive_types3' hint 2024-08-30 20:27:26 -06:00
mo8it c8d1d9c51f chore: Release 2024-08-29 17:20:17 +02:00
mo8it ab2eb3442e Update changelog 2024-08-29 17:10:39 +02:00
7 changed files with 83 additions and 61 deletions

View file

@ -1,3 +1,44 @@
<a name="6.3.0"></a>
## 6.3.0 (2024-08-29)
### Added
- Add the following exercise lints:
- `forbid(unsafe_code)`: You shouldn't write unsafe code in Rustlings.
- `forbid(unstable_features)`: You don't need unstable features in Rustlings and shouldn't rely on them while learning Rust.
- `forbid(todo)`: You forgot a `todo!()`.
- `forbid(empty_loop)`: This can only happen by mistake in Rustlings.
- `deny(infinite_loop)`: No infinite loops are needed in Rustlings.
- `deny(mem_forget)`: You shouldn't leak memory while still learning Rust.
- Show a link to every exercise file in the list.
- Add scroll padding in the list.
- Break the help footer of the list into two lines when the terminal width isn't big enough.
- Enable scrolling with the mouse in the list.
- `dev check`: Show the progress of checks.
- `dev check`: Check that the length of all exercise names is lower than 32.
- `dev check`: Check if exercise contains no tests and isn't marked with `test = false`.
### Changed
- The compilation time when installing Rustlings is reduced.
- Pressing `c` in the list for "continue on" now quits the list after setting the selected exercise as the current one.
- Better highlighting of the solution file after an exercise is done.
- Don't show the output of successful tests anymore. Instead, show the pretty output for tests.
- Be explicit about `q` only quitting the list and not the whole program in the list.
- Be explicit about `r` only resetting one exercise (the selected one) in the list.
- Ignore the standard output of `git init`.
- `threads3`: Remove the queue length and improve tests.
- `errors4`: Use match instead of a comparison chain in the solution.
- `functions3`: Only take `u8` to avoid using a too high number of iterations by mistake.
- `dev check`: Always check with strict Clippy (warnings to errors) when checking the solutions.
### Fixed
- Fix the error on some systems about too many open files during the final check of all exercises.
- Fix the list when the terminal height is too low.
- Restore the terminal after an error in the list.
<a name="6.2.0"></a>
## 6.2.0 (2024-08-09)

4
Cargo.lock generated
View file

@ -482,7 +482,7 @@ dependencies = [
[[package]]
name = "rustlings"
version = "6.2.0"
version = "6.3.0"
dependencies = [
"ahash",
"anyhow",
@ -499,7 +499,7 @@ dependencies = [
[[package]]
name = "rustlings-macros"
version = "6.2.0"
version = "6.3.0"
dependencies = [
"quote",
"serde",

View file

@ -6,7 +6,7 @@ exclude = [
]
[workspace.package]
version = "6.2.0"
version = "6.3.0"
authors = [
"Mo Bitar <mo8it@proton.me>", # https://github.com/mo8it
"Liv <mokou@fastmail.com>", # https://github.com/shadows-withal
@ -52,7 +52,7 @@ clap = { version = "4.5.16", features = ["derive"] }
crossterm = { version = "0.28.1", default-features = false, features = ["windows", "events"] }
notify-debouncer-mini = { version = "0.4.1", default-features = false }
os_pipe = "1.2.1"
rustlings-macros = { path = "rustlings-macros", version = "=6.2.0" }
rustlings-macros = { path = "rustlings-macros", version = "=6.3.0" }
serde_json = "1.0.127"
serde.workspace = true
toml_edit.workspace = true

View file

@ -1,6 +1,7 @@
format_version = 1
welcome_message = """Is this your first time? Don't worry, Rustlings is made for beginners!
welcome_message = """
Is this your first time? Don't worry, Rustlings is made for beginners!
We are going to teach you a lot of things about Rust, but before we can
get started, here are some notes about how Rustlings operates:
@ -10,15 +11,16 @@ get started, here are some notes about how Rustlings operates:
and fix them!
2. Make sure to have your editor open in the `rustlings/` directory. Rustlings
will show you the path of the current exercise under the progress bar. Open
the exercise file in your editor, fix errors and save the file. Rustlings will
automatically detect the file change and rerun the exercise. If all errors are
fixed, Rustlings will ask you to move on to the next exercise.
the exercise file in your editor, fix errors and save the file. Rustlings
will automatically detect the file change and rerun the exercise. If all
errors are fixed, Rustlings will ask you to move on to the next exercise.
3. If you're stuck on an exercise, enter `h` to show a hint.
4. If an exercise doesn't make sense to you, feel free to open an issue on GitHub!
(https://github.com/rust-lang/rustlings). We look at every issue, and sometimes,
other learners do too so you can help each other out!"""
4. If an exercise doesn't make sense to you, feel free to open an issue on
GitHub! (https://github.com/rust-lang/rustlings). We look at every issue, and
sometimes, other learners do too so you can help each other out!"""
final_message = """We hope you enjoyed learning about the various aspects of Rust!
final_message = """
We hope you enjoyed learning about the various aspects of Rust!
If you noticed any issues, don't hesitate to report them on Github.
You can also contribute your own exercises to help the greater community!
@ -122,8 +124,8 @@ hint = """
We know about variables and mutability, but there is another important type of
variables available: constants.
Constants are always immutable. They are declared with the keyword `const` instead
of `let`.
Constants are always immutable. They are declared with the keyword `const`
instead of `let`.
The type of Constants must always be annotated.
@ -253,7 +255,7 @@ require you to type in 100 items (but you certainly can if you want!).
For example, you can do:
```
let array = ["Are we there yet?"; 10];
let array = ["Are we there yet?"; 100];
```
Bonus: what are some other things you could have that would return `true`
@ -319,7 +321,8 @@ hint = """
In the first function, we create an empty vector and want to push new elements
to it.
In the second function, we map the values of the input and collect them into a vector.
In the second function, we map the values of the input and collect them into
a vector.
After you've completed both functions, decide for yourself which approach you
like better.
@ -332,8 +335,8 @@ What do you think is the more commonly used pattern under Rust developers?"""
name = "move_semantics1"
dir = "06_move_semantics"
hint = """
So you've got the "cannot borrow `vec` as mutable, as it is not declared as mutable"
error on the line where we push an element to the vector, right?
So you've got the "cannot borrow `vec` as mutable, as it is not declared as
mutable" error on the line where we push an element to the vector, right?
The fix for this is going to be adding one keyword, and the addition is NOT on
the line where we push to the vector (where the error is).
@ -369,7 +372,8 @@ hint = """
Carefully reason about the range in which each mutable reference is in
scope. Does it help to update the value of `x` immediately after
the mutable reference is taken?
Read more about 'Mutable References' in the book's section 'References and Borrowing':
Read more about 'Mutable References' in the book's section 'References and
Borrowing':
https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#mutable-references."""
[[exercises]]
@ -508,7 +512,8 @@ name = "strings4"
dir = "09_strings"
test = false
hint = """
Replace `placeholder` with either `string` or `string_slice` in the `main` function.
Replace `placeholder` with either `string` or `string_slice` in the `main`
function.
Example:
`placeholder("blue");`
@ -1211,7 +1216,8 @@ hint = """
Is there an implementation of `TryFrom` in the standard library that can both do
the required integer conversion and check the range of the input?
Challenge: Can you make the `TryFrom` implementations generic over many integer types?"""
Challenge: Can you make the `TryFrom` implementations generic over many integer
types?"""
[[exercises]]
name = "as_ref_mut"

View file

@ -331,7 +331,7 @@ impl AppState {
})
}
/// Official exercises: Dump the solution file form the binary and return its path.
/// Official exercises: Dump the solution file from the binary and return its path.
/// Third-party exercises: Check if a solution file exists and return its path in that case.
pub fn current_solution_path(&self) -> Result<Option<String>> {
if cfg!(debug_assertions) {

View file

@ -43,8 +43,6 @@ pub struct ListState<'a> {
filter: Filter,
term_width: u16,
term_height: u16,
separator_line: Vec<u8>,
narrow_term: bool,
show_footer: bool,
}
@ -77,8 +75,6 @@ impl<'a> ListState<'a> {
// Set by `set_term_size`
term_width: 0,
term_height: 0,
separator_line: Vec::new(),
narrow_term: false,
show_footer: true,
};
@ -96,19 +92,11 @@ impl<'a> ListState<'a> {
return;
}
let wide_help_footer_width = 95;
// The help footer is shorter when nothing is selected.
self.narrow_term = width < wide_help_footer_width && self.scroll_state.selected().is_some();
let header_height = 1;
// 2 separator, 1 progress bar, 1-2 footer message.
let footer_height = 4 + u16::from(self.narrow_term);
// 1 progress bar, 2 footer message lines.
let footer_height = 3;
self.show_footer = height > header_height + footer_height;
if self.show_footer {
self.separator_line = "".as_bytes().repeat(width as usize);
}
self.scroll_state.set_max_n_rows_to_display(
height.saturating_sub(header_height + u16::from(self.show_footer) * footer_height)
as usize,
@ -208,9 +196,6 @@ impl<'a> ListState<'a> {
}
if self.show_footer {
stdout.write_all(&self.separator_line)?;
next_ln(stdout)?;
progress_bar(
&mut MaxLenWriter::new(stdout, self.term_width as usize),
self.app_state.n_done(),
@ -219,22 +204,15 @@ impl<'a> ListState<'a> {
)?;
next_ln(stdout)?;
stdout.write_all(&self.separator_line)?;
next_ln(stdout)?;
let mut writer = MaxLenWriter::new(stdout, self.term_width as usize);
if self.message.is_empty() {
// Help footer message
if self.scroll_state.selected().is_some() {
writer.write_str("↓/j ↑/k home/g end/G | <c>ontinue at | <r>eset exercise")?;
if self.narrow_term {
next_ln(stdout)?;
writer = MaxLenWriter::new(stdout, self.term_width as usize);
next_ln(stdout)?;
writer = MaxLenWriter::new(stdout, self.term_width as usize);
writer.write_ascii(b"filter ")?;
} else {
writer.write_ascii(b" | filter ")?;
}
writer.write_ascii(b"<s>earch | filter ")?;
} else {
// Nothing selected (and nothing shown), so only display filter and quit.
writer.write_ascii(b"filter ")?;
@ -263,17 +241,14 @@ impl<'a> ListState<'a> {
}
writer.write_ascii(b" | <q>uit list")?;
next_ln(stdout)?;
} else {
writer.stdout.queue(SetForegroundColor(Color::Magenta))?;
writer.write_str(&self.message)?;
stdout.queue(ResetColor)?;
next_ln(stdout)?;
if self.narrow_term {
next_ln(stdout)?;
}
}
next_ln(stdout)?;
}
stdout.queue(EndSynchronizedUpdate)?.flush()

View file

@ -5,7 +5,7 @@ use std::{
use crossterm::{
cursor::MoveTo,
style::{Attribute, Color, ResetColor, SetAttribute, SetForegroundColor},
style::{Attribute, Color, SetAttribute, SetForegroundColor},
terminal::{Clear, ClearType},
Command, QueueableCommand,
};
@ -93,20 +93,19 @@ pub fn progress_bar<'a>(
total: u16,
line_width: u16,
) -> io::Result<()> {
debug_assert!(total < 1000);
debug_assert!(progress <= total);
const PREFIX: &[u8] = b"Progress: [";
const PREFIX_WIDTH: u16 = PREFIX.len() as u16;
// Leaving the last char empty (_) for `total` > 99.
const POSTFIX_WIDTH: u16 = "] xxx/xx exercises_".len() as u16;
const POSTFIX_WIDTH: u16 = "] xxx/xxx".len() as u16;
const WRAPPER_WIDTH: u16 = PREFIX_WIDTH + POSTFIX_WIDTH;
const MIN_LINE_WIDTH: u16 = WRAPPER_WIDTH + 4;
if line_width < MIN_LINE_WIDTH {
writer.write_ascii(b"Progress: ")?;
// Integers are in ASCII.
writer.write_ascii(format!("{progress}/{total}").as_bytes())?;
return writer.write_ascii(b" exercises");
return writer.write_ascii(format!("{progress}/{total}").as_bytes());
}
let stdout = writer.stdout();
@ -133,8 +132,9 @@ pub fn progress_bar<'a>(
}
}
stdout.queue(ResetColor)?;
write!(stdout, "] {progress:>3}/{total} exercises")
stdout.queue(SetForegroundColor(Color::Reset))?;
write!(stdout, "] {progress:>3}/{total}")
}
pub fn clear_terminal(stdout: &mut StdoutLock) -> io::Result<()> {