summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md14
-rw-r--r--Cargo.lock332
-rw-r--r--Cargo.toml7
-rw-r--r--clippy.toml16
-rw-r--r--exercises/18_iterators/iterators3.rs2
-rw-r--r--exercises/README.md2
-rw-r--r--rustlings-macros/Cargo.toml2
-rw-r--r--rustlings-macros/src/lib.rs2
-rw-r--r--src/app_state.rs12
-rw-r--r--src/cargo_toml.rs9
-rw-r--r--src/dev/check.rs50
-rw-r--r--src/dev/new.rs3
-rw-r--r--src/embedded.rs2
-rw-r--r--src/exercise.rs38
-rw-r--r--src/info_file.rs4
-rw-r--r--src/init.rs38
-rw-r--r--src/list/state.rs8
-rw-r--r--src/main.rs8
-rw-r--r--src/run.rs6
-rw-r--r--src/term.rs60
-rw-r--r--src/watch/state.rs4
21 files changed, 387 insertions, 232 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c1dbb42..32d9510 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,9 +1,23 @@
## Unreleased
+## 6.5.0 (2025-08-21)
+
+### Added
+
+- Check that Clippy is installed before initialization
+
### Changed
- Upgrade to Rust edition 2024
- Raise the minimum supported Rust version to `1.87`
+- Don't follow symlinks in the file watcher
+- `dev new`: Don't add `.rustlings-state.txt` to `.gitignore`
+
+### Fixed
+
+- Fix file links in VS Code
+- Fix error printing when the progress bar is shown
+- `dev check`: Don't check formatting if there are no solution files
## 6.4.0 (2024-11-11)
diff --git a/Cargo.lock b/Cargo.lock
index 7ea1217..c743dd7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4,9 +4,9 @@ version = 4
[[package]]
name = "anstream"
-version = "0.6.18"
+version = "0.6.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
+checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192"
dependencies = [
"anstyle",
"anstyle-parse",
@@ -19,50 +19,50 @@ dependencies = [
[[package]]
name = "anstyle"
-version = "1.0.10"
+version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
+checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
[[package]]
name = "anstyle-parse"
-version = "0.2.6"
+version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
+checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
-version = "1.1.2"
+version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
+checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2"
dependencies = [
- "windows-sys",
+ "windows-sys 0.60.2",
]
[[package]]
name = "anstyle-wincon"
-version = "3.0.8"
+version = "3.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa"
+checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a"
dependencies = [
"anstyle",
"once_cell_polyfill",
- "windows-sys",
+ "windows-sys 0.60.2",
]
[[package]]
name = "anyhow"
-version = "1.0.98"
+version = "1.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
+checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
[[package]]
name = "autocfg"
-version = "1.4.0"
+version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "bitflags"
@@ -72,21 +72,21 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
-version = "2.9.1"
+version = "2.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
+checksum = "6a65b545ab31d687cff52899d4890855fec459eb6afe0da6417b8a18da87aa29"
[[package]]
name = "cfg-if"
-version = "1.0.0"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
[[package]]
name = "clap"
-version = "4.5.39"
+version = "4.5.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f"
+checksum = "1fc0e74a703892159f5ae7d3aac52c8e6c392f5ae5f359c70b5881d60aaac318"
dependencies = [
"clap_builder",
"clap_derive",
@@ -94,9 +94,9 @@ dependencies = [
[[package]]
name = "clap_builder"
-version = "4.5.39"
+version = "4.5.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51"
+checksum = "b3e7f4214277f3c7aa526a59dd3fbe306a370daee1f8b7b8c987069cd8e888a8"
dependencies = [
"anstream",
"anstyle",
@@ -106,9 +106,9 @@ dependencies = [
[[package]]
name = "clap_derive"
-version = "4.5.32"
+version = "4.5.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
+checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6"
dependencies = [
"heck",
"proc-macro2",
@@ -118,15 +118,15 @@ dependencies = [
[[package]]
name = "clap_lex"
-version = "0.7.4"
+version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
+checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
[[package]]
name = "colorchoice"
-version = "1.0.3"
+version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
+checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
[[package]]
name = "crossterm"
@@ -134,7 +134,7 @@ version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b"
dependencies = [
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
"crossterm_winapi",
"document-features",
"mio",
@@ -171,12 +171,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "errno"
-version = "0.3.12"
+version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
+checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
dependencies = [
"libc",
- "windows-sys",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -186,18 +186,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]]
-name = "filetime"
-version = "0.2.25"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586"
-dependencies = [
- "cfg-if",
- "libc",
- "libredox",
- "windows-sys",
-]
-
-[[package]]
name = "fsevent-sys"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -220,9 +208,9 @@ dependencies = [
[[package]]
name = "hashbrown"
-version = "0.15.3"
+version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
+checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
[[package]]
name = "heck"
@@ -232,9 +220,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "indexmap"
-version = "2.9.0"
+version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
+checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
dependencies = [
"equivalent",
"hashbrown",
@@ -246,7 +234,7 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3"
dependencies = [
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
"inotify-sys",
"libc",
]
@@ -294,20 +282,9 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.172"
+version = "0.2.175"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
-
-[[package]]
-name = "libredox"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
-dependencies = [
- "bitflags 2.9.1",
- "libc",
- "redox_syscall",
-]
+checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
[[package]]
name = "linux-raw-sys"
@@ -317,9 +294,9 @@ checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
[[package]]
name = "litrs"
-version = "0.4.1"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5"
+checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed"
[[package]]
name = "lock_api"
@@ -339,9 +316,9 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "memchr"
-version = "2.7.4"
+version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "mio"
@@ -351,18 +328,17 @@ checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
dependencies = [
"libc",
"log",
- "wasi 0.11.0+wasi-snapshot-preview1",
- "windows-sys",
+ "wasi 0.11.1+wasi-snapshot-preview1",
+ "windows-sys 0.59.0",
]
[[package]]
name = "notify"
-version = "8.0.0"
+version = "8.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943"
+checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3"
dependencies = [
- "bitflags 2.9.1",
- "filetime",
+ "bitflags 2.9.2",
"fsevent-sys",
"inotify",
"kqueue",
@@ -371,7 +347,7 @@ dependencies = [
"mio",
"notify-types",
"walkdir",
- "windows-sys",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -412,14 +388,14 @@ dependencies = [
"libc",
"redox_syscall",
"smallvec",
- "windows-targets",
+ "windows-targets 0.52.6",
]
[[package]]
name = "proc-macro2"
-version = "1.0.95"
+version = "1.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
+checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
dependencies = [
"unicode-ident",
]
@@ -435,30 +411,30 @@ dependencies = [
[[package]]
name = "r-efi"
-version = "5.2.0"
+version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
[[package]]
name = "redox_syscall"
-version = "0.5.12"
+version = "0.5.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af"
+checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77"
dependencies = [
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
]
[[package]]
name = "rustix"
-version = "1.0.7"
+version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
+checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
dependencies = [
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
"errno",
"libc",
"linux-raw-sys",
- "windows-sys",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -474,7 +450,7 @@ dependencies = [
"serde",
"serde_json",
"tempfile",
- "toml_edit",
+ "toml",
]
[[package]]
@@ -483,7 +459,7 @@ version = "6.4.0"
dependencies = [
"quote",
"serde",
- "toml_edit",
+ "toml",
]
[[package]]
@@ -529,9 +505,9 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.140"
+version = "1.0.143"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
+checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a"
dependencies = [
"itoa",
"memchr",
@@ -541,9 +517,9 @@ dependencies = [
[[package]]
name = "serde_spanned"
-version = "0.6.8"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
+checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83"
dependencies = [
"serde",
]
@@ -571,18 +547,18 @@ dependencies = [
[[package]]
name = "signal-hook-registry"
-version = "1.4.5"
+version = "1.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410"
+checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b"
dependencies = [
"libc",
]
[[package]]
name = "smallvec"
-version = "1.15.0"
+version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "strsim"
@@ -592,9 +568,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
-version = "2.0.101"
+version = "2.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
+checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
dependencies = [
"proc-macro2",
"quote",
@@ -603,40 +579,57 @@ dependencies = [
[[package]]
name = "tempfile"
-version = "3.20.0"
+version = "3.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
+checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e"
dependencies = [
"fastrand",
"getrandom",
"once_cell",
"rustix",
- "windows-sys",
+ "windows-sys 0.60.2",
]
[[package]]
-name = "toml_datetime"
-version = "0.6.9"
+name = "toml"
+version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3"
+checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8"
dependencies = [
+ "indexmap",
"serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_parser",
+ "toml_writer",
+ "winnow",
]
[[package]]
-name = "toml_edit"
-version = "0.22.26"
+name = "toml_datetime"
+version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e"
+checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3"
dependencies = [
- "indexmap",
"serde",
- "serde_spanned",
- "toml_datetime",
+]
+
+[[package]]
+name = "toml_parser"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10"
+dependencies = [
"winnow",
]
[[package]]
+name = "toml_writer"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64"
+
+[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -660,9 +653,9 @@ dependencies = [
[[package]]
name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
+version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasi"
@@ -691,11 +684,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
-version = "0.1.9"
+version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
+checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22"
dependencies = [
- "windows-sys",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -705,12 +698,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
+name = "windows-link"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
+
+[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
- "windows-targets",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.60.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
+dependencies = [
+ "windows-targets 0.53.3",
]
[[package]]
@@ -719,14 +727,31 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_gnullvm",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "windows_i686_gnullvm 0.52.6",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.53.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
+dependencies = [
+ "windows-link",
+ "windows_aarch64_gnullvm 0.53.0",
+ "windows_aarch64_msvc 0.53.0",
+ "windows_i686_gnu 0.53.0",
+ "windows_i686_gnullvm 0.53.0",
+ "windows_i686_msvc 0.53.0",
+ "windows_x86_64_gnu 0.53.0",
+ "windows_x86_64_gnullvm 0.53.0",
+ "windows_x86_64_msvc 0.53.0",
]
[[package]]
@@ -736,55 +761,100 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
+
+[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
+name = "windows_aarch64_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
+
+[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
+name = "windows_i686_gnu"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
+
+[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
+name = "windows_i686_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
+
+[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
+name = "windows_i686_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
+
+[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
+name = "windows_x86_64_gnu"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
+
+[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
+
+[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
+name = "windows_x86_64_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
+
+[[package]]
name = "winnow"
-version = "0.7.10"
+version = "0.7.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
-dependencies = [
- "memchr",
-]
+checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95"
[[package]]
name = "wit-bindgen-rt"
@@ -792,5 +862,5 @@ version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
dependencies = [
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
]
diff --git a/Cargo.toml b/Cargo.toml
index 27531b3..454f3b8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,5 +1,4 @@
[workspace]
-resolver = "2"
exclude = [
"tests/test_exercises",
"dev",
@@ -20,7 +19,7 @@ rust-version = "1.87"
[workspace.dependencies]
serde = { version = "1.0", features = ["derive"] }
-toml_edit = { version = "0.22", default-features = false, features = ["parse", "serde"] }
+toml = { version = "0.9", default-features = false, features = ["std", "parse", "serde"] }
[package]
name = "rustlings"
@@ -53,13 +52,13 @@ notify = "8.0"
rustlings-macros = { path = "rustlings-macros", version = "=6.4.0" }
serde_json = "1.0"
serde.workspace = true
-toml_edit.workspace = true
+toml.workspace = true
[target.'cfg(not(windows))'.dependencies]
rustix = { version = "1.0", default-features = false, features = ["std", "stdio", "termios"] }
[dev-dependencies]
-tempfile = "3.19"
+tempfile = "3.21"
[profile.release]
panic = "abort"
diff --git a/clippy.toml b/clippy.toml
index afc9253..89b0a88 100644
--- a/clippy.toml
+++ b/clippy.toml
@@ -1,15 +1,11 @@
disallowed-types = [
- # Inefficient. Use `.queue(…)` instead.
- "crossterm::style::Stylize",
- "crossterm::style::styled_content::StyledContent",
+ { path = "crossterm::style::Stylize", reason = "inefficient, use `.queue(…)` instead" },
+ { path = "crossterm::style::styled_content::StyledContent", reason = "inefficient, use `.queue(…)` instead" },
]
disallowed-methods = [
- # Inefficient. Use `.queue(…)` instead.
- "crossterm::style::style",
- # Use `thread::Builder::spawn` instead and handle the error.
- "std::thread::spawn",
- "std::thread::Scope::spawn",
- # Return `ExitCode` instead.
- "std::process::exit",
+ { path = "crossterm::style::style", reason = "inefficient, use `.queue(…)` instead" },
+ { path = "std::thread::spawn", replacement = "std::thread::Builder::spawn", reason = "handle the error" },
+ { path = "std::thread::Scope::spawn", replacement = "std::thread::Builder::spawn", reason = "handle the error" },
+ { path = "std::process::exit", replacement = "std::process::ExitCode" },
]
diff --git a/exercises/18_iterators/iterators3.rs b/exercises/18_iterators/iterators3.rs
index 6b1eca1..dce0905 100644
--- a/exercises/18_iterators/iterators3.rs
+++ b/exercises/18_iterators/iterators3.rs
@@ -39,6 +39,8 @@ mod tests {
#[test]
fn test_success() {
assert_eq!(divide(81, 9), Ok(9));
+ assert_eq!(divide(81, -1), Ok(-81));
+ assert_eq!(divide(i64::MIN, i64::MIN), Ok(1));
}
#[test]
diff --git a/exercises/README.md b/exercises/README.md
index 237f2f1..86b3591 100644
--- a/exercises/README.md
+++ b/exercises/README.md
@@ -22,6 +22,6 @@
| iterators | §13.2-4 |
| smart_pointers | §15, §16.3 |
| threads | §16.1-3 |
-| macros | §19.5 |
+| macros | §20.5 |
| clippy | §21.4 |
| conversions | n/a |
diff --git a/rustlings-macros/Cargo.toml b/rustlings-macros/Cargo.toml
index 1bf6d1b..5df648b 100644
--- a/rustlings-macros/Cargo.toml
+++ b/rustlings-macros/Cargo.toml
@@ -18,7 +18,7 @@ proc-macro = true
[dependencies]
quote = "1.0"
serde.workspace = true
-toml_edit.workspace = true
+toml.workspace = true
[lints]
workspace = true
diff --git a/rustlings-macros/src/lib.rs b/rustlings-macros/src/lib.rs
index 6c6067b..b20c6f1 100644
--- a/rustlings-macros/src/lib.rs
+++ b/rustlings-macros/src/lib.rs
@@ -16,7 +16,7 @@ struct InfoFile {
#[proc_macro]
pub fn include_files(_: TokenStream) -> TokenStream {
let info_file = include_str!("../info.toml");
- let exercises = toml_edit::de::from_str::<InfoFile>(info_file)
+ let exercises = toml::de::from_str::<InfoFile>(info_file)
.expect("Failed to parse `info.toml`")
.exercises;
diff --git a/src/app_state.rs b/src/app_state.rs
index f3f3481..d654d04 100644
--- a/src/app_state.rs
+++ b/src/app_state.rs
@@ -60,8 +60,7 @@ pub struct AppState {
file_buf: Vec<u8>,
official_exercises: bool,
cmd_runner: CmdRunner,
- // Running in VS Code.
- vs_code: bool,
+ emit_file_links: bool,
}
impl AppState {
@@ -181,7 +180,8 @@ impl AppState {
file_buf,
official_exercises: !Path::new("info.toml").exists(),
cmd_runner,
- vs_code: env::var_os("TERM_PROGRAM").is_some_and(|v| v == "vscode"),
+ // VS Code has its own file link handling
+ emit_file_links: env::var_os("TERM_PROGRAM").is_none_or(|v| v != "vscode"),
};
Ok((slf, state_file_status))
@@ -218,8 +218,8 @@ impl AppState {
}
#[inline]
- pub fn vs_code(&self) -> bool {
- self.vs_code
+ pub fn emit_file_links(&self) -> bool {
+ self.emit_file_links
}
// Write the state file.
@@ -621,7 +621,7 @@ mod tests {
file_buf: Vec::new(),
official_exercises: true,
cmd_runner: CmdRunner::build().unwrap(),
- vs_code: false,
+ emit_file_links: true,
};
let mut assert = |done: [bool; 3], expected: [Option<usize>; 3]| {
diff --git a/src/cargo_toml.rs b/src/cargo_toml.rs
index e966809..ce0dfd0 100644
--- a/src/cargo_toml.rs
+++ b/src/cargo_toml.rs
@@ -134,7 +134,14 @@ mod tests {
);
assert_eq!(
- updated_cargo_toml(&exercise_infos, "abc\nbin = [xxx]\n123", b"../").unwrap(),
+ updated_cargo_toml(
+ &exercise_infos,
+ "abc\n\
+ bin = [xxx]\n\
+ 123",
+ b"../"
+ )
+ .unwrap(),
br#"abc
bin = [
{ name = "1", path = "../exercises/1.rs" },
diff --git a/src/dev/check.rs b/src/dev/check.rs
index 9cde7f2..f711106 100644
--- a/src/dev/check.rs
+++ b/src/dev/check.rs
@@ -15,6 +15,7 @@ use crate::{
cmd::CmdRunner,
exercise::{OUTPUT_CAPACITY, RunnableExercise},
info_file::{ExerciseInfo, InfoFile},
+ term::ProgressCounter,
};
const MAX_N_EXERCISES: usize = 999;
@@ -105,13 +106,15 @@ fn check_info_file_exercises(info_file: &InfoFile) -> Result<HashSet<PathBuf>> {
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"
+ "The `main` function is missing in the file `{path}`.\n\
+ Create 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."
+ "Didn't find any `// TODO` comment in the file `{path}`.\n\
+ You need to have at least one such comment to guide the user."
);
}
@@ -217,10 +220,7 @@ fn check_exercises_unsolved(
.collect::<Result<Vec<_>, _>>()
.context("Failed to spawn a thread to check if an exercise is already solved")?;
- let n_handles = handles.len();
- write!(stdout, "Progress: 0/{n_handles}")?;
- stdout.flush()?;
- let mut handle_num = 1;
+ let mut progress_counter = ProgressCounter::new(&mut stdout, handles.len())?;
for (exercise_name, handle) in handles {
let Ok(result) = handle.join() else {
@@ -229,17 +229,17 @@ fn check_exercises_unsolved(
match result {
Ok(true) => {
- bail!("The exercise {exercise_name} is already solved.\n{SKIP_CHECK_UNSOLVED_HINT}",)
+ bail!(
+ "The exercise {exercise_name} is already solved.\n\
+ {SKIP_CHECK_UNSOLVED_HINT}",
+ )
}
Ok(false) => (),
Err(e) => return Err(e),
}
- write!(stdout, "\rProgress: {handle_num}/{n_handles}")?;
- stdout.flush()?;
- handle_num += 1;
+ progress_counter.increment()?;
}
- stdout.write_all(b"\n")?;
Ok(())
}
@@ -247,10 +247,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"
+ "`format_version` < {CURRENT_FORMAT_VERSION} (supported version)\n\
+ Please migrate to the latest format version"
),
Ordering::Greater => bail!(
- "`format_version` > {CURRENT_FORMAT_VERSION} (supported version)\nTry updating the Rustlings program"
+ "`format_version` > {CURRENT_FORMAT_VERSION} (supported version)\n\
+ Try updating the Rustlings program"
),
Ordering::Equal => (),
}
@@ -318,10 +320,7 @@ fn check_solutions(
.arg("always")
.stdin(Stdio::null());
- let n_handles = handles.len();
- write!(stdout, "Progress: 0/{n_handles}")?;
- stdout.flush()?;
- let mut handle_num = 1;
+ let mut progress_counter = ProgressCounter::new(&mut stdout, handles.len())?;
for (exercise_info, handle) in info_file.exercises.iter().zip(handles) {
let Ok(check_result) = handle.join() else {
@@ -338,7 +337,7 @@ fn check_solutions(
}
SolutionCheck::MissingOptional => (),
SolutionCheck::RunFailure { output } => {
- stdout.write_all(b"\n\n")?;
+ drop(progress_counter);
stdout.write_all(&output)?;
bail!(
"Running the solution of the exercise {} failed with the error above",
@@ -348,22 +347,21 @@ fn check_solutions(
SolutionCheck::Err(e) => return Err(e),
}
- write!(stdout, "\rProgress: {handle_num}/{n_handles}")?;
- stdout.flush()?;
- handle_num += 1;
+ progress_counter.increment()?;
}
- stdout.write_all(b"\n")?;
+ let n_solutions = sol_paths.len();
let handle = thread::Builder::new()
.spawn(move || check_unexpected_files("solutions", &sol_paths))
.context(
"Failed to spawn a thread to check for unexpected files in the solutions directory",
)?;
- if !fmt_cmd
- .status()
- .context("Failed to run `rustfmt` on all solution files")?
- .success()
+ if n_solutions > 0
+ && !fmt_cmd
+ .status()
+ .context("Failed to run `rustfmt` on all solution files")?
+ .success()
{
bail!("Some solutions aren't formatted. Run `rustfmt` on them");
}
diff --git a/src/dev/new.rs b/src/dev/new.rs
index 883b6fa..7c72a6b 100644
--- a/src/dev/new.rs
+++ b/src/dev/new.rs
@@ -78,8 +78,7 @@ pub fn new(path: &Path, no_git: bool) -> Result<()> {
Ok(())
}
-pub const GITIGNORE: &[u8] = b".rustlings-state.txt
-Cargo.lock
+pub const GITIGNORE: &[u8] = b"Cargo.lock
target/
.vscode/
!.vscode/extensions.json
diff --git a/src/embedded.rs b/src/embedded.rs
index 51a14b6..88c1fb0 100644
--- a/src/embedded.rs
+++ b/src/embedded.rs
@@ -152,7 +152,7 @@ mod tests {
#[test]
fn dirs() {
- let exercises = toml_edit::de::from_str::<InfoFile>(EMBEDDED_FILES.info_file)
+ let exercises = toml::de::from_str::<InfoFile>(EMBEDDED_FILES.info_file)
.expect("Failed to parse `info.toml`")
.exercises;
diff --git a/src/exercise.rs b/src/exercise.rs
index fdfbc4f..6f517be 100644
--- a/src/exercise.rs
+++ b/src/exercise.rs
@@ -7,22 +7,28 @@ use std::io::{self, StdoutLock, Write};
use crate::{
cmd::CmdRunner,
- term::{self, CountedWrite, terminal_file_link, write_ansi},
+ term::{self, CountedWrite, file_path, terminal_file_link, write_ansi},
};
/// The initial capacity of the output buffer.
pub const OUTPUT_CAPACITY: usize = 1 << 14;
-pub fn solution_link_line(stdout: &mut StdoutLock, solution_path: &str) -> io::Result<()> {
+pub fn solution_link_line(
+ stdout: &mut StdoutLock,
+ solution_path: &str,
+ emit_file_links: bool,
+) -> io::Result<()> {
stdout.queue(SetAttribute(Attribute::Bold))?;
stdout.write_all(b"Solution")?;
stdout.queue(ResetColor)?;
stdout.write_all(b" for comparison: ")?;
- if let Some(canonical_path) = term::canonicalize(solution_path) {
- terminal_file_link(stdout, solution_path, &canonical_path, Color::Cyan)?;
- } else {
- stdout.write_all(solution_path.as_bytes())?;
- }
+ file_path(stdout, Color::Cyan, |writer| {
+ if emit_file_links && let Some(canonical_path) = term::canonicalize(solution_path) {
+ terminal_file_link(writer, solution_path, &canonical_path)
+ } else {
+ writer.stdout().write_all(solution_path.as_bytes())
+ }
+ })?;
stdout.write_all(b"\n")
}
@@ -72,12 +78,18 @@ pub struct Exercise {
}
impl Exercise {
- pub fn terminal_file_link<'a>(&self, writer: &mut impl CountedWrite<'a>) -> io::Result<()> {
- if let Some(canonical_path) = self.canonical_path.as_deref() {
- return terminal_file_link(writer, self.path, canonical_path, Color::Blue);
- }
-
- writer.write_str(self.path)
+ pub fn terminal_file_link<'a>(
+ &self,
+ writer: &mut impl CountedWrite<'a>,
+ emit_file_links: bool,
+ ) -> io::Result<()> {
+ file_path(writer, Color::Blue, |writer| {
+ if emit_file_links && let Some(canonical_path) = self.canonical_path.as_deref() {
+ terminal_file_link(writer, self.path, canonical_path)
+ } else {
+ writer.write_str(self.path)
+ }
+ })
}
}
diff --git a/src/info_file.rs b/src/info_file.rs
index 634bece..04e5d64 100644
--- a/src/info_file.rs
+++ b/src/info_file.rs
@@ -95,11 +95,11 @@ impl InfoFile {
pub fn parse() -> Result<Self> {
// Read a local `info.toml` if it exists.
let slf = match fs::read_to_string("info.toml") {
- Ok(file_content) => toml_edit::de::from_str::<Self>(&file_content)
+ Ok(file_content) => toml::de::from_str::<Self>(&file_content)
.context("Failed to parse the `info.toml` file")?,
Err(e) => {
if e.kind() == ErrorKind::NotFound {
- return toml_edit::de::from_str(EMBEDDED_FILES.info_file)
+ return toml::de::from_str(EMBEDDED_FILES.info_file)
.context("Failed to parse the embedded `info.toml` file");
}
diff --git a/src/init.rs b/src/init.rs
index a60fba7..68011ed 100644
--- a/src/init.rs
+++ b/src/init.rs
@@ -35,7 +35,27 @@ pub fn init() -> Result<()> {
.stdin(Stdio::null())
.stderr(Stdio::null())
.output()
- .context(CARGO_LOCATE_PROJECT_ERR)?;
+ .context(
+ "Failed to run the command `cargo locate-project …`\n\
+ Did you already install Rust?\n\
+ Try running `cargo --version` to diagnose the problem.",
+ )?;
+
+ if !Command::new("cargo")
+ .arg("clippy")
+ .arg("--version")
+ .stdin(Stdio::null())
+ .stdout(Stdio::null())
+ .stderr(Stdio::null())
+ .status()
+ .context("Failed to run the command `cargo clippy --version`")?
+ .success()
+ {
+ bail!(
+ "Clippy, the official Rust linter, is missing.\n\
+ Please install it first before initializing Rustlings."
+ )
+ }
let mut stdout = io::stdout().lock();
let mut init_git = true;
@@ -58,11 +78,13 @@ pub fn init() -> Result<()> {
&& !workspace_manifest_content.contains("workspace.")
{
bail!(
- "The current directory is already part of a Cargo project.\nPlease initialize Rustlings in a different directory"
+ "The current directory is already part of a Cargo project.\n\
+ Please 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 ")?;
+ stdout.write_all(b"This command will create the directory `rustlings/` as a member of this Cargo workspace.\n\
+ Press ENTER to continue ")?;
press_enter_prompt(&mut stdout)?;
// Make sure "rustlings" is added to `workspace.members` by making
@@ -78,7 +100,8 @@ pub fn init() -> Result<()> {
.status()?;
if !status.success() {
bail!(
- "Failed to initialize a new Cargo workspace member.\nPlease initialize Rustlings in a different directory"
+ "Failed to initialize a new Cargo workspace member.\n\
+ Please initialize Rustlings in a different directory"
);
}
@@ -87,7 +110,8 @@ pub fn init() -> Result<()> {
.context("Failed to remove the temporary directory `rustlings/`")?;
init_git = false;
} else {
- stdout.write_all(b"This command will create the directory `rustlings/` which will contain the exercises.\nPress ENTER to continue ")?;
+ stdout.write_all(b"This command will create the directory `rustlings/` which will contain the exercises.\n\
+ Press ENTER to continue ")?;
press_enter_prompt(&mut stdout)?;
}
@@ -166,10 +190,6 @@ pub fn init() -> Result<()> {
Ok(())
}
-const CARGO_LOCATE_PROJECT_ERR: &str = "Failed to run the command `cargo locate-project …`
-Did you already install Rust?
-Try running `cargo --version` to diagnose the problem.";
-
const INIT_SOLUTION_FILE: &[u8] = b"fn main() {
// DON'T EDIT THIS SOLUTION FILE!
// It will be automatically filled after you finish the exercise.
diff --git a/src/list/state.rs b/src/list/state.rs
index ae65ec2..50d06be 100644
--- a/src/list/state.rs
+++ b/src/list/state.rs
@@ -186,13 +186,7 @@ impl<'a> ListState<'a> {
writer.write_ascii(&self.name_col_padding[exercise.name.len()..])?;
- // The list links aren't shown correctly in VS Code on Windows.
- // But VS Code shows its own links anyway.
- if self.app_state.vs_code() {
- writer.write_str(exercise.path)?;
- } else {
- exercise.terminal_file_link(&mut writer)?;
- }
+ exercise.terminal_file_link(&mut writer, self.app_state.emit_file_links())?;
writer.write_ascii(&self.path_col_padding[exercise.path.len()..])?;
diff --git a/src/main.rs b/src/main.rs
index bce2593..ffd2dfa 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -104,7 +104,11 @@ fn main() -> Result<ExitCode> {
clear_terminal(&mut stdout)?;
let welcome_message = welcome_message.trim_ascii();
- write!(stdout, "{welcome_message}\n\nPress ENTER to continue ")?;
+ write!(
+ stdout,
+ "{welcome_message}\n\n\
+ Press ENTER to continue "
+ )?;
press_enter_prompt(&mut stdout)?;
clear_terminal(&mut stdout)?;
// Flush to be able to show errors occurring before printing a newline to stdout.
@@ -163,7 +167,7 @@ fn main() -> Result<ExitCode> {
}
app_state
.current_exercise()
- .terminal_file_link(&mut stdout)?;
+ .terminal_file_link(&mut stdout, app_state.emit_file_links())?;
stdout.write_all(b"\n")?;
return Ok(ExitCode::FAILURE);
diff --git a/src/run.rs b/src/run.rs
index 6f4f099..b473fc2 100644
--- a/src/run.rs
+++ b/src/run.rs
@@ -27,7 +27,7 @@ pub fn run(app_state: &mut AppState) -> Result<ExitCode> {
stdout.write_all(b"Ran ")?;
app_state
.current_exercise()
- .terminal_file_link(&mut stdout)?;
+ .terminal_file_link(&mut stdout, app_state.emit_file_links())?;
stdout.write_all(b" with errors\n")?;
return Ok(ExitCode::FAILURE);
@@ -41,7 +41,7 @@ pub fn run(app_state: &mut AppState) -> Result<ExitCode> {
if let Some(solution_path) = app_state.current_solution_path()? {
stdout.write_all(b"\n")?;
- solution_link_line(&mut stdout, &solution_path)?;
+ solution_link_line(&mut stdout, &solution_path, app_state.emit_file_links())?;
stdout.write_all(b"\n")?;
}
@@ -50,7 +50,7 @@ pub fn run(app_state: &mut AppState) -> Result<ExitCode> {
stdout.write_all(b"Next exercise: ")?;
app_state
.current_exercise()
- .terminal_file_link(&mut stdout)?;
+ .terminal_file_link(&mut stdout, app_state.emit_file_links())?;
stdout.write_all(b"\n")?;
}
ExercisesProgress::AllDone => (),
diff --git a/src/term.rs b/src/term.rs
index 1e08c84..3d149b3 100644
--- a/src/term.rs
+++ b/src/term.rs
@@ -160,6 +160,37 @@ impl<'a, 'lock> CheckProgressVisualizer<'a, 'lock> {
}
}
+pub struct ProgressCounter<'a, 'lock> {
+ stdout: &'a mut StdoutLock<'lock>,
+ total: usize,
+ counter: usize,
+}
+
+impl<'a, 'lock> ProgressCounter<'a, 'lock> {
+ pub fn new(stdout: &'a mut StdoutLock<'lock>, total: usize) -> io::Result<Self> {
+ write!(stdout, "Progress: 0/{total}")?;
+ stdout.flush()?;
+
+ Ok(Self {
+ stdout,
+ total,
+ counter: 0,
+ })
+ }
+
+ pub fn increment(&mut self) -> io::Result<()> {
+ self.counter += 1;
+ write!(self.stdout, "\rProgress: {}/{}", self.counter, self.total)?;
+ self.stdout.flush()
+ }
+}
+
+impl Drop for ProgressCounter<'_, '_> {
+ fn drop(&mut self) {
+ let _ = self.stdout.write_all(b"\n\n");
+ }
+}
+
pub fn progress_bar<'a>(
writer: &mut impl CountedWrite<'a>,
progress: u16,
@@ -241,22 +272,18 @@ pub fn canonicalize(path: &str) -> Option<String> {
})
}
-pub fn terminal_file_link<'a>(
- writer: &mut impl CountedWrite<'a>,
- path: &str,
- canonical_path: &str,
+pub fn file_path<'a, W: CountedWrite<'a>>(
+ writer: &mut W,
color: Color,
+ f: impl FnOnce(&mut W) -> io::Result<()>,
) -> io::Result<()> {
writer
.stdout()
.queue(SetForegroundColor(color))?
.queue(SetAttribute(Attribute::Underlined))?;
- writer.stdout().write_all(b"\x1b]8;;file://")?;
- writer.stdout().write_all(canonical_path.as_bytes())?;
- writer.stdout().write_all(b"\x1b\\")?;
- // Only this part is visible.
- writer.write_str(path)?;
- writer.stdout().write_all(b"\x1b]8;;\x1b\\")?;
+
+ f(writer)?;
+
writer
.stdout()
.queue(SetForegroundColor(Color::Reset))?
@@ -265,6 +292,19 @@ pub fn terminal_file_link<'a>(
Ok(())
}
+pub fn terminal_file_link<'a>(
+ writer: &mut impl CountedWrite<'a>,
+ path: &str,
+ canonical_path: &str,
+) -> io::Result<()> {
+ writer.stdout().write_all(b"\x1b]8;;file://")?;
+ writer.stdout().write_all(canonical_path.as_bytes())?;
+ writer.stdout().write_all(b"\x1b\\")?;
+ // Only this part is visible.
+ writer.write_str(path)?;
+ writer.stdout().write_all(b"\x1b]8;;\x1b\\")
+}
+
pub fn write_ansi(output: &mut Vec<u8>, command: impl Command) {
struct FmtWriter<'a>(&'a mut Vec<u8>);
diff --git a/src/watch/state.rs b/src/watch/state.rs
index 2413bec..a92dd2d 100644
--- a/src/watch/state.rs
+++ b/src/watch/state.rs
@@ -233,7 +233,7 @@ impl<'a> WatchState<'a> {
stdout.write_all(b"\n")?;
if let DoneStatus::DoneWithSolution(solution_path) = &self.done_status {
- solution_link_line(stdout, solution_path)?;
+ solution_link_line(stdout, solution_path, self.app_state.emit_file_links())?;
}
stdout.write_all(
@@ -252,7 +252,7 @@ impl<'a> WatchState<'a> {
stdout.write_all(b"\nCurrent exercise: ")?;
self.app_state
.current_exercise()
- .terminal_file_link(stdout)?;
+ .terminal_file_link(stdout, self.app_state.emit_file_links())?;
stdout.write_all(b"\n\n")?;
self.show_prompt(stdout)?;