mirror of
https://github.com/rust-lang/rustlings.git
synced 2024-12-26 00:00:03 +03:00
Compare commits
22 commits
d807b95888
...
31b4a941cd
Author | SHA1 | Date | |
---|---|---|---|
31b4a941cd | |||
71f31d74bc | |||
72e557b3a9 | |||
3eaccbb61a | |||
b678bd8ed2 | |||
2baa140615 | |||
e760f07767 | |||
ca5d5f0a49 | |||
69b4fd49fc | |||
36f315c344 | |||
8016f5ca2d | |||
8ef2ff1257 | |||
6ce31defb6 | |||
0b3ad9141b | |||
c903db5c53 | |||
8a038b946c | |||
ed9740b72c | |||
59e8f70e55 | |||
4c8365fe88 | |||
52af0674c1 | |||
938b90e5f2 | |||
55cc8584bd |
70
Cargo.lock
generated
70
Cargo.lock
generated
|
@ -116,9 +116,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.14"
|
||||
version = "4.5.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c937d4061031a6d0c8da4b9a4f98a172fc2976dfb1c19213a9cf7d0d3c837e36"
|
||||
checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
@ -126,9 +126,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.14"
|
||||
version = "4.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85379ba512b21a328adf887e85f7742d12e96eb31f3ef077df4ffc26b506ffed"
|
||||
checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
@ -197,7 +197,7 @@ checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6"
|
|||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"crossterm_winapi",
|
||||
"mio 1.0.1",
|
||||
"mio 1.0.2",
|
||||
"parking_lot",
|
||||
"rustix",
|
||||
"signal-hook",
|
||||
|
@ -244,14 +244,14 @@ checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
|
|||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.23"
|
||||
version = "0.2.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
|
||||
checksum = "bf401df4a4e3872c4fe8151134cf483738e74b67fc934d6532c882b3d24a4550"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall 0.4.1",
|
||||
"windows-sys 0.52.0",
|
||||
"libredox",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -287,9 +287,9 @@ checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.3.0"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0"
|
||||
checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
|
@ -368,9 +368,20 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.155"
|
||||
version = "0.2.156"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||
checksum = "a5f43f184355eefb8d17fc948dbecf6c13be3c141f20d834ae842193a448c72a"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
|
@ -423,9 +434,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.0.1"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4"
|
||||
checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
|
@ -497,7 +508,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
|||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall 0.5.3",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
@ -547,15 +558,6 @@ dependencies = [
|
|||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.3"
|
||||
|
@ -633,18 +635,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.205"
|
||||
version = "1.0.208"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e33aedb1a7135da52b7c21791455563facbbcc43d0f0f66165b42c21b3dfb150"
|
||||
checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.205"
|
||||
version = "1.0.208"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "692d6f5ac90220161d6774db30c662202721e64aed9058d2c394f451261420c1"
|
||||
checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -653,9 +655,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.122"
|
||||
version = "1.0.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da"
|
||||
checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
|
@ -689,7 +691,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mio 1.0.1",
|
||||
"mio 1.0.2",
|
||||
"signal-hook",
|
||||
]
|
||||
|
||||
|
@ -744,9 +746,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.72"
|
||||
version = "2.0.74"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
|
||||
checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
20
Cargo.toml
20
Cargo.toml
|
@ -19,7 +19,7 @@ edition = "2021" # On Update: Update the edition of the `rustfmt` command that c
|
|||
rust-version = "1.80"
|
||||
|
||||
[workspace.dependencies]
|
||||
serde = { version = "1.0.205", features = ["derive"] }
|
||||
serde = { version = "1.0.208", features = ["derive"] }
|
||||
toml_edit = { version = "0.22.20", default-features = false, features = ["parse", "serde"] }
|
||||
|
||||
[package]
|
||||
|
@ -48,12 +48,12 @@ include = [
|
|||
[dependencies]
|
||||
ahash = { version = "0.8.11", default-features = false }
|
||||
anyhow = "1.0.86"
|
||||
clap = { version = "4.5.14", features = ["derive"] }
|
||||
clap = { version = "4.5.16", features = ["derive"] }
|
||||
notify-debouncer-mini = { version = "0.4.1", default-features = false }
|
||||
os_pipe = "1.2.1"
|
||||
ratatui = { version = "0.28.0", default-features = false, features = ["crossterm"] }
|
||||
rustlings-macros = { path = "rustlings-macros", version = "=6.2.0" }
|
||||
serde_json = "1.0.122"
|
||||
serde_json = "1.0.125"
|
||||
serde.workspace = true
|
||||
toml_edit.workspace = true
|
||||
|
||||
|
@ -69,6 +69,18 @@ panic = "abort"
|
|||
[package.metadata.release]
|
||||
pre-release-hook = ["./release-hook.sh"]
|
||||
|
||||
[workspace.lints.rust]
|
||||
unsafe_code = "forbid"
|
||||
unstable_features = "forbid"
|
||||
|
||||
[workspace.lints.clippy]
|
||||
empty_loop = "forbid"
|
||||
infinite_loop = "deny"
|
||||
mem_forget = "deny"
|
||||
dbg_macro = "warn"
|
||||
todo = "warn"
|
||||
# TODO: Remove after the following fix is released: https://github.com/rust-lang/rust-clippy/pull/13102
|
||||
[lints.clippy]
|
||||
needless_option_as_deref = "allow"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
@ -116,6 +116,8 @@ bin = [
|
|||
{ name = "generics1_sol", path = "../solutions/14_generics/generics1.rs" },
|
||||
{ name = "generics2", path = "../exercises/14_generics/generics2.rs" },
|
||||
{ name = "generics2_sol", path = "../solutions/14_generics/generics2.rs" },
|
||||
{ name = "generics3", path = "../exercises/14_generics/generics3.rs" },
|
||||
{ name = "generics3_sol", path = "../solutions/14_generics/generics3.rs" },
|
||||
{ name = "traits1", path = "../exercises/15_traits/traits1.rs" },
|
||||
{ name = "traits1_sol", path = "../solutions/15_traits/traits1.rs" },
|
||||
{ name = "traits2", path = "../exercises/15_traits/traits2.rs" },
|
||||
|
@ -201,3 +203,19 @@ panic = "abort"
|
|||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
[lints.rust]
|
||||
# You shouldn't write unsafe code in Rustlings
|
||||
unsafe_code = "forbid"
|
||||
# You don't need unstable features in Rustlings and shouldn't rely on them while learning Rust
|
||||
unstable_features = "forbid"
|
||||
|
||||
[lints.clippy]
|
||||
# You forgot a `todo!()`
|
||||
todo = "forbid"
|
||||
# This can only happen by mistake in Rustlings
|
||||
empty_loop = "forbid"
|
||||
# No infinite loops are needed in Rustlings
|
||||
infinite_loop = "deny"
|
||||
# You shouldn't leak memory while still learning Rust
|
||||
mem_forget = "deny"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// TODO: We sometimes encourage you to keep trying things on a given exercise,
|
||||
// TODO: We sometimes encourage you to keep trying things on a given exercise
|
||||
// even after you already figured it out. If you got everything working and feel
|
||||
// ready for the next exercise, enter `n` in the terminal.
|
||||
//
|
||||
|
@ -6,8 +6,7 @@
|
|||
// Try adding a new `println!` and check the updated output in the terminal.
|
||||
|
||||
fn main() {
|
||||
println!("Hello and");
|
||||
println!(r#" welcome to... "#);
|
||||
println!(r#" Welcome to... "#);
|
||||
println!(r#" _ _ _ "#);
|
||||
println!(r#" _ __ _ _ ___| |_| (_)_ __ __ _ ___ "#);
|
||||
println!(r#" | '__| | | / __| __| | | '_ \ / _` / __| "#);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
fn main() {
|
||||
// TODO: Add missing keyword.
|
||||
// TODO: Add the missing keyword.
|
||||
x = 5;
|
||||
|
||||
println!("x has the value {x}");
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
fn call_me(num: u32) {
|
||||
fn call_me(num: u8) {
|
||||
for i in 0..num {
|
||||
println!("Ring! Call number {}", i + 1);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// of `Option<String>`.
|
||||
fn generate_nametag_text(name: String) -> Option<String> {
|
||||
if name.is_empty() {
|
||||
// Empty names aren't allowed.
|
||||
// Empty names aren't allowed
|
||||
None
|
||||
} else {
|
||||
Some(format!("Hi! My name is {name}"))
|
||||
|
|
54
exercises/14_generics/generics3.rs
Normal file
54
exercises/14_generics/generics3.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
// generics3.rs
|
||||
// Execute `rustlings hint generics3` or use the `hint` watch subcommand for a hint.
|
||||
|
||||
// This function should take an array of `Option` elements and returns array of not None elements
|
||||
// TODO fix this function signature
|
||||
fn into_dispose_nulls(list: Vec<Option<&str>>) -> Vec<&str> {
|
||||
list.into_iter().flatten().collect()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// You can optionally experiment here.
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn store_str_on_list() {
|
||||
let names_list = vec![Some("maria"), Some("jacob"), None, Some("kacper"), None];
|
||||
let only_values = into_dispose_nulls(names_list);
|
||||
assert_eq!(only_values.len(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn store_numbers_on_list() {
|
||||
let numbers_list = vec![Some(1), Some(2), None, Some(3)];
|
||||
let only_values = into_dispose_nulls(numbers_list);
|
||||
assert_eq!(only_values.len(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn store_custom_type_on_list() {
|
||||
#[allow(dead_code)]
|
||||
struct Rectangle {
|
||||
width: i32,
|
||||
height: i32,
|
||||
}
|
||||
impl Rectangle {
|
||||
fn new(width: i32, height: i32) -> Self {
|
||||
Self { width, height }
|
||||
}
|
||||
}
|
||||
|
||||
let custom_list = vec![
|
||||
Some(Rectangle::new(1, 2)),
|
||||
None,
|
||||
None,
|
||||
Some(Rectangle::new(3, 4)),
|
||||
];
|
||||
let only_values = into_dispose_nulls(custom_list);
|
||||
assert_eq!(only_values.len(), 2);
|
||||
}
|
||||
}
|
|
@ -19,3 +19,6 @@ proc-macro = true
|
|||
quote = "1.0.36"
|
||||
serde.workspace = true
|
||||
toml_edit.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
@ -744,6 +744,17 @@ hint = """
|
|||
Related section in The Book:
|
||||
https://doc.rust-lang.org/book/ch10-01-syntax.html#in-method-definitions"""
|
||||
|
||||
[[exercises]]
|
||||
name = "generics3"
|
||||
dir = "14_generics"
|
||||
hint = """
|
||||
Vectors in Rust use generics to create dynamically-sized arrays of any type.
|
||||
The `into_dispose_nulls` function takes a vector as an argument, but only accepts vectors that store the &str type.
|
||||
To allow the function to accept vectors that store any type, you can leverage your knowledge about generics.
|
||||
If you're unsure how to proceed, please refer to the Rust Book at:
|
||||
https://doc.rust-lang.org/book/ch10-01-syntax.html#in-function-definitions.
|
||||
"""
|
||||
|
||||
# TRAITS
|
||||
|
||||
[[exercises]]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
fn call_me(num: u32) {
|
||||
fn call_me(num: u8) {
|
||||
for i in 0..num {
|
||||
println!("Ring! Call number {}", i + 1);
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ fn build_scores_table(results: &str) -> HashMap<&str, TeamScores> {
|
|||
team_1.goals_scored += team_1_score;
|
||||
team_1.goals_conceded += team_2_score;
|
||||
|
||||
// Similarely for the second team.
|
||||
// Similarly for the second team.
|
||||
let team_2 = scores
|
||||
.entry(team_2_name)
|
||||
.or_insert_with(TeamScores::default);
|
||||
|
|
53
solutions/14_generics/generics3.rs
Normal file
53
solutions/14_generics/generics3.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
// generics3.rs
|
||||
// Execute `rustlings hint generics3` or use the `hint` watch subcommand for a hint.
|
||||
|
||||
// Here we added generic type `T` to function signature
|
||||
// Now this function can be used with vector of any
|
||||
fn into_dispose_nulls<T>(list: Vec<Option<T>>) -> Vec<T> {
|
||||
list.into_iter().flatten().collect()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// You can optionally experiment here.
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn store_str_on_list() {
|
||||
let names_list = vec![Some("maria"), Some("jacob"), None, Some("kacper"), None];
|
||||
let only_values = into_dispose_nulls(names_list);
|
||||
assert_eq!(only_values.len(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn store_numbers_on_list() {
|
||||
let numbers_list = vec![Some(1), Some(2), None, Some(3)];
|
||||
let only_values = into_dispose_nulls(numbers_list);
|
||||
assert_eq!(only_values.len(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn store_custom_type_on_list() {
|
||||
struct Rectangle {
|
||||
width: i32,
|
||||
height: i32,
|
||||
}
|
||||
impl Rectangle {
|
||||
fn new(width: i32, height: i32) -> Self {
|
||||
Self { width, height }
|
||||
}
|
||||
}
|
||||
|
||||
let custom_list = vec![
|
||||
Some(Rectangle::new(1, 2)),
|
||||
None,
|
||||
None,
|
||||
Some(Rectangle::new(3, 4)),
|
||||
];
|
||||
let only_values = into_dispose_nulls(custom_list);
|
||||
assert_eq!(only_values.len(), 2);
|
||||
}
|
||||
}
|
|
@ -139,13 +139,14 @@ pub fn init() -> Result<()> {
|
|||
let _ = Command::new("git")
|
||||
.arg("init")
|
||||
.stdin(Stdio::null())
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.status();
|
||||
}
|
||||
|
||||
writeln!(
|
||||
stdout,
|
||||
"\n{}\n\n{}",
|
||||
"{}\n\n{}",
|
||||
"Initialization done ✓".green(),
|
||||
POST_INIT_MSG.bold(),
|
||||
)?;
|
||||
|
|
42
src/list.rs
42
src/list.rs
|
@ -1,14 +1,14 @@
|
|||
use anyhow::Result;
|
||||
use anyhow::{Context, Result};
|
||||
use ratatui::{
|
||||
backend::CrosstermBackend,
|
||||
crossterm::{
|
||||
event::{self, Event, KeyCode, KeyEventKind},
|
||||
event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEventKind},
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
ExecutableCommand,
|
||||
QueueableCommand,
|
||||
},
|
||||
Terminal,
|
||||
};
|
||||
use std::io;
|
||||
use std::io::{self, StdoutLock, Write};
|
||||
|
||||
use crate::app_state::AppState;
|
||||
|
||||
|
@ -16,12 +16,8 @@ use self::state::{Filter, UiState};
|
|||
|
||||
mod state;
|
||||
|
||||
pub fn list(app_state: &mut AppState) -> Result<()> {
|
||||
let mut stdout = io::stdout().lock();
|
||||
stdout.execute(EnterAlternateScreen)?;
|
||||
enable_raw_mode()?;
|
||||
|
||||
let mut terminal = Terminal::new(CrosstermBackend::new(&mut stdout))?;
|
||||
fn handle_list(app_state: &mut AppState, stdout: &mut StdoutLock) -> Result<()> {
|
||||
let mut terminal = Terminal::new(CrosstermBackend::new(stdout))?;
|
||||
terminal.clear()?;
|
||||
|
||||
let mut ui_state = UiState::new(app_state);
|
||||
|
@ -30,7 +26,7 @@ pub fn list(app_state: &mut AppState) -> Result<()> {
|
|||
terminal.try_draw(|frame| ui_state.draw(frame).map_err(io::Error::other))?;
|
||||
|
||||
let key = loop {
|
||||
match event::read()? {
|
||||
match event::read().context("Failed to read terminal event")? {
|
||||
Event::Key(key) => match key.kind {
|
||||
KeyEventKind::Press | KeyEventKind::Repeat => break key,
|
||||
KeyEventKind::Release => (),
|
||||
|
@ -85,9 +81,25 @@ pub fn list(app_state: &mut AppState) -> Result<()> {
|
|||
}
|
||||
}
|
||||
|
||||
drop(terminal);
|
||||
stdout.execute(LeaveAlternateScreen)?;
|
||||
disable_raw_mode()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn list(app_state: &mut AppState) -> Result<()> {
|
||||
let mut stdout = io::stdout().lock();
|
||||
stdout
|
||||
.queue(EnterAlternateScreen)?
|
||||
.queue(EnableMouseCapture)?
|
||||
.flush()?;
|
||||
enable_raw_mode()?;
|
||||
|
||||
let res = handle_list(app_state, &mut stdout);
|
||||
|
||||
// Restore the terminal even if we got an error.
|
||||
stdout
|
||||
.queue(LeaveAlternateScreen)?
|
||||
.queue(DisableMouseCapture)?
|
||||
.flush()?;
|
||||
disable_raw_mode()?;
|
||||
|
||||
res
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@ use anyhow::{Context, Result};
|
|||
use ratatui::{
|
||||
layout::{Constraint, Rect},
|
||||
style::{Style, Stylize},
|
||||
text::{Line, Span},
|
||||
text::{Span, Text},
|
||||
widgets::{Block, Borders, HighlightSpacing, Paragraph, Row, Table, TableState},
|
||||
Frame,
|
||||
};
|
||||
use std::fmt::Write;
|
||||
use std::{fmt::Write, mem};
|
||||
|
||||
use crate::{app_state::AppState, progress_bar::progress_bar_ratatui};
|
||||
|
||||
|
@ -162,6 +162,9 @@ impl<'a> UiState<'a> {
|
|||
|
||||
pub fn draw(&mut self, frame: &mut Frame) -> Result<()> {
|
||||
let area = frame.area();
|
||||
let narrow = area.width < 95;
|
||||
let narrow_u16 = u16::from(narrow);
|
||||
let table_height = area.height - 3 - narrow_u16;
|
||||
|
||||
frame.render_stateful_widget(
|
||||
&self.table,
|
||||
|
@ -169,7 +172,7 @@ impl<'a> UiState<'a> {
|
|||
x: 0,
|
||||
y: 0,
|
||||
width: area.width,
|
||||
height: area.height - 3,
|
||||
height: table_height,
|
||||
},
|
||||
&mut self.table_state,
|
||||
);
|
||||
|
@ -183,7 +186,7 @@ impl<'a> UiState<'a> {
|
|||
.block(Block::default().borders(Borders::BOTTOM)),
|
||||
Rect {
|
||||
x: 0,
|
||||
y: area.height - 3,
|
||||
y: table_height,
|
||||
width: area.width,
|
||||
height: 2,
|
||||
},
|
||||
|
@ -191,10 +194,19 @@ impl<'a> UiState<'a> {
|
|||
|
||||
let message = if self.message.is_empty() {
|
||||
// Help footer.
|
||||
let mut text = Text::default();
|
||||
let mut spans = Vec::with_capacity(4);
|
||||
spans.push(Span::raw(
|
||||
"↓/j ↑/k home/g end/G │ <c>ontinue at │ <r>eset │ filter ",
|
||||
"↓/j ↑/k home/g end/G │ <c>ontinue at │ <r>eset exercise │",
|
||||
));
|
||||
|
||||
if narrow {
|
||||
text.push_line(mem::take(&mut spans));
|
||||
spans.push(Span::raw("filter "));
|
||||
} else {
|
||||
spans.push(Span::raw(" filter "));
|
||||
}
|
||||
|
||||
match self.filter {
|
||||
Filter::Done => {
|
||||
spans.push("<d>one".underlined().magenta());
|
||||
|
@ -206,18 +218,20 @@ impl<'a> UiState<'a> {
|
|||
}
|
||||
Filter::None => spans.push(Span::raw("<d>one/<p>ending")),
|
||||
}
|
||||
spans.push(Span::raw(" │ <q>uit"));
|
||||
Line::from(spans)
|
||||
|
||||
spans.push(Span::raw(" │ <q>uit list"));
|
||||
text.push_line(spans);
|
||||
text
|
||||
} else {
|
||||
Line::from(self.message.as_str().light_blue())
|
||||
Text::from(self.message.as_str().light_blue())
|
||||
};
|
||||
frame.render_widget(
|
||||
message,
|
||||
Rect {
|
||||
x: 0,
|
||||
y: area.height - 1,
|
||||
y: table_height + 2,
|
||||
width: area.width,
|
||||
height: 1,
|
||||
height: 1 + narrow_u16,
|
||||
},
|
||||
);
|
||||
|
||||
|
|
Loading…
Reference in a new issue