mirror of
https://github.com/rust-lang/rustlings.git
synced 2025-01-09 20:03:24 +03:00
Compare commits
16 commits
6f04570dd0
...
d322bcfcec
Author | SHA1 | Date | |
---|---|---|---|
d322bcfcec | |||
0ac5aa7af2 | |||
f9be652b3b | |||
932f6b53a9 | |||
4d9eb35ad7 | |||
86d716cf8a | |||
87db9129bc | |||
6566c5904f | |||
aa813fbce1 | |||
d1ebbaa6f6 | |||
c07cf5bffe | |||
df448c069c | |||
25e7696565 | |||
92777c0a44 | |||
7ebc260924 | |||
f5eaa578b9 |
41
Cargo.lock
generated
41
Cargo.lock
generated
|
@ -179,7 +179,7 @@ dependencies = [
|
|||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.58",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -589,9 +589,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.79"
|
||||
version = "1.0.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
|
||||
checksum = "a56dea16b0a29e94408b9aa5e2940a4eedbd128a1ba20e8f7ae60fd3d465af0e"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
@ -607,9 +607,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ratatui"
|
||||
version = "0.26.1"
|
||||
version = "0.26.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bcb12f8fbf6c62614b0d56eb352af54f6a22410c3b079eb53ee93c7b97dd31d8"
|
||||
checksum = "a564a852040e82671dc50a37d88f3aa83bbc690dfc6844cfe7a2591620206a80"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"cassowary",
|
||||
|
@ -678,7 +678,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustlings"
|
||||
version = "6.0.0"
|
||||
version = "6.0.0-alpha.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assert_cmd",
|
||||
|
@ -696,7 +696,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustlings-macros"
|
||||
version = "6.0.0"
|
||||
version = "6.0.0-alpha.0"
|
||||
dependencies = [
|
||||
"quote",
|
||||
]
|
||||
|
@ -745,7 +745,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.58",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -795,12 +795,12 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
|||
|
||||
[[package]]
|
||||
name = "stability"
|
||||
version = "0.1.1"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebd1b177894da2a2d9120208c3386066af06a488255caabc5de8ddca22dbc3ce"
|
||||
checksum = "2ff9eaf853dec4c8802325d8b6d3dffa86cc707fd7a1a4cdbf416e13b061787a"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -834,25 +834,14 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.58",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
version = "2.0.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687"
|
||||
checksum = "4a6531ffc7b071655e4ce2e04bd464c4830bb585a61cabb96cf808f05172615a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1156,5 +1145,5 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.58",
|
||||
"syn",
|
||||
]
|
||||
|
|
14
Cargo.toml
14
Cargo.toml
|
@ -11,10 +11,11 @@ members = [
|
|||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "6.0.0"
|
||||
version = "6.0.0-alpha.0"
|
||||
authors = [
|
||||
"Liv <mokou@fastmail.com>",
|
||||
"Carol (Nichols || Goulding) <carol.nichols@gmail.com>",
|
||||
"Mo <mo8it@proton.me>",
|
||||
]
|
||||
license = "MIT"
|
||||
edition = "2021"
|
||||
|
@ -32,6 +33,13 @@ version.workspace = true
|
|||
authors.workspace = true
|
||||
license.workspace = true
|
||||
edition.workspace = true
|
||||
include = [
|
||||
"/exercises/",
|
||||
"/info.toml",
|
||||
"/LICENSE",
|
||||
"/README.md",
|
||||
"/src/",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
|
@ -39,8 +47,8 @@ clap = { version = "4.5.4", features = ["derive"] }
|
|||
crossterm = "0.27.0"
|
||||
hashbrown = "0.14.3"
|
||||
notify-debouncer-mini = "0.4.1"
|
||||
ratatui = "0.26.1"
|
||||
rustlings-macros = { path = "rustlings-macros" }
|
||||
ratatui = "0.26.2"
|
||||
rustlings-macros = { path = "rustlings-macros", version = "6.0.0-alpha.0" }
|
||||
serde.workspace = true
|
||||
toml_edit.workspace = true
|
||||
which = "6.0.1"
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
format_version = 1
|
||||
|
||||
welcome_message = """Is this your first time? Don't worry, Rustlings was made for beginners! We are
|
||||
going to teach you a lot of things about Rust, but before we can get
|
||||
started, here's a couple of notes about how Rustlings operates:
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[package]
|
||||
name = "rustlings-macros"
|
||||
description = "A macros crate intended to be only used by rustlings"
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
license.workspace = true
|
||||
|
|
25
src/dev.rs
Normal file
25
src/dev.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use anyhow::{Context, Result};
|
||||
use clap::Subcommand;
|
||||
|
||||
use crate::info_file::InfoFile;
|
||||
|
||||
mod check;
|
||||
mod init;
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum DevCommands {
|
||||
Init,
|
||||
Check,
|
||||
}
|
||||
|
||||
impl DevCommands {
|
||||
pub fn run(self, info_file: InfoFile) -> Result<()> {
|
||||
match self {
|
||||
DevCommands::Init => init::init().context(INIT_ERR),
|
||||
DevCommands::Check => check::check(info_file),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const INIT_ERR: &str = "Initialization failed.
|
||||
After resolving the issue, delete the `rustlings` directory (if it was created) and try again";
|
18
src/dev/check.rs
Normal file
18
src/dev/check.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
use std::fs;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
use crate::{info_file::InfoFile, init::cargo_toml};
|
||||
|
||||
pub fn check(info_file: InfoFile) -> Result<()> {
|
||||
// TODO: Add checks
|
||||
|
||||
// TODO: Keep dependencies!
|
||||
fs::write("Cargo.toml", cargo_toml(&info_file.exercises))
|
||||
.context("Failed to update the file `Cargo.toml`")?;
|
||||
println!("Updated `Cargo.toml`");
|
||||
|
||||
println!("\nEverything looks fine!");
|
||||
|
||||
Ok(())
|
||||
}
|
106
src/dev/init.rs
Normal file
106
src/dev/init.rs
Normal file
|
@ -0,0 +1,106 @@
|
|||
use std::fs::{self, create_dir};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
use crate::CURRENT_FORMAT_VERSION;
|
||||
|
||||
pub fn init() -> Result<()> {
|
||||
create_dir("rustlings").context("Failed to create the directory `rustlings`")?;
|
||||
|
||||
create_dir("rustlings/exercises")
|
||||
.context("Failed to create the directory `rustlings/exercises`")?;
|
||||
|
||||
create_dir("rustlings/solutions")
|
||||
.context("Failed to create the directory `rustlings/solutions`")?;
|
||||
|
||||
fs::write(
|
||||
"rustlings/info.toml",
|
||||
format!("{INFO_FILE_BEFORE_FORMAT_VERSION}{CURRENT_FORMAT_VERSION}{INFO_FILE_AFTER_FORMAT_VERSION}"),
|
||||
)
|
||||
.context("Failed to create the file `rustlings/info.toml`")?;
|
||||
|
||||
fs::write(
|
||||
"rustlings/Cargo.toml",
|
||||
format!("{CARGO_TOML_COMMENT}{}", crate::init::CARGO_TOML_PACKAGE),
|
||||
)
|
||||
.context("Failed to create the file `rustlings/Cargo.toml`")?;
|
||||
|
||||
fs::write("rustlings/.gitignore", crate::init::GITIGNORE)
|
||||
.context("Failed to create the file `rustlings/.gitignore`")?;
|
||||
|
||||
fs::write("rustlings/README.md", README)
|
||||
.context("Failed to create the file `rustlings/README.md`")?;
|
||||
|
||||
create_dir("rustlings/.vscode")
|
||||
.context("Failed to create the directory `rustlings/.vscode`")?;
|
||||
fs::write(
|
||||
"rustlings/.vscode/extensions.json",
|
||||
crate::init::VS_CODE_EXTENSIONS_JSON,
|
||||
)
|
||||
.context("Failed to create the file `rustlings/.vscode/extensions.json`")?;
|
||||
|
||||
println!("{INIT_DONE}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
const INFO_FILE_BEFORE_FORMAT_VERSION: &str =
|
||||
"# The format version is an indicator of the compatibility of third-party exercises with the
|
||||
# Rustlings program.
|
||||
# The format version is not the same as the version of the Rustlings program.
|
||||
# In case Rustlings makes an unavoidable breaking change to the expected format of third-party
|
||||
# exercises, you would need to raise this version and adapt to the new format.
|
||||
# Otherwise, the newest version of the Rustlings program won't be able to run these exercises.
|
||||
format_version = ";
|
||||
|
||||
const INFO_FILE_AFTER_FORMAT_VERSION: &str = r#"
|
||||
|
||||
# Optional multi-line message to be shown to users when just starting with the exercises.
|
||||
welcome_message = """Welcome to these third-party Rustlings exercises."""
|
||||
|
||||
# Optional multi-line message to be shown to users after finishing all exercises.
|
||||
final_message = """We hope that you found the exercises helpful :D"""
|
||||
|
||||
# Repeat this section for every exercise.
|
||||
[[exercises]]
|
||||
# Exercise name which is the exercise file name without the `.rs` extension.
|
||||
name = "???"
|
||||
|
||||
# Optional directory name to be provided if you want to organize exercises in directories.
|
||||
# If `dir` is specified, the exercise path is `exercises/DIR/NAME.rs`
|
||||
# Otherwise, the path is `exercises/NAME.rs`
|
||||
# dir = "???"
|
||||
|
||||
# The mode to run the exercise in.
|
||||
# The mode "test" (preferred) runs the exercise's tests.
|
||||
# The mode "run" only checks if the exercise compiles and runs it.
|
||||
mode = "test"
|
||||
|
||||
# A multi-line hint to be shown to users on request.
|
||||
hint = """???"""
|
||||
"#;
|
||||
|
||||
const CARGO_TOML_COMMENT: &str =
|
||||
"# You shouldn't edit this file manually! It is updated by `rustlings dev check`
|
||||
|
||||
";
|
||||
|
||||
const README: &str = "# Rustlings 🦀
|
||||
|
||||
Welcome to these third-party Rustlings exercises 😃
|
||||
|
||||
First,
|
||||
[install Rustlings using the official instructions in the README of the Rustlings project](https://github.com/rust-lang/rustlings) ✅
|
||||
|
||||
Then, open your terminal in this directory and run `rustlings` to get started with the exercises 🚀
|
||||
";
|
||||
|
||||
const INIT_DONE: &str = r#"Initialization done!
|
||||
You can start developing third-party Rustlings exercises in the `rustlings` directory :D
|
||||
|
||||
If the initialization was done in a Rust project which is a Cargo workspace, you need to add the
|
||||
path to the `rustlings` directory to the `workspace.exclude` list in the project's `Cargo.toml`
|
||||
file. For example:
|
||||
|
||||
[workspace]
|
||||
exclude = ["rustlings"]"#;
|
|
@ -39,6 +39,7 @@ impl ExerciseInfo {
|
|||
|
||||
#[derive(Deserialize)]
|
||||
pub struct InfoFile {
|
||||
pub format_version: u8,
|
||||
pub welcome_message: Option<String>,
|
||||
pub final_message: Option<String>,
|
||||
pub exercises: Vec<ExerciseInfo>,
|
||||
|
|
70
src/init.rs
70
src/init.rs
|
@ -1,14 +1,14 @@
|
|||
use anyhow::{bail, Context, Result};
|
||||
use std::{
|
||||
env::set_current_dir,
|
||||
fs::{create_dir, OpenOptions},
|
||||
io::{self, ErrorKind, Write},
|
||||
fs::{self, create_dir},
|
||||
io::ErrorKind,
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use crate::{embedded::EMBEDDED_FILES, info_file::ExerciseInfo};
|
||||
|
||||
fn create_cargo_toml(exercise_infos: &[ExerciseInfo]) -> io::Result<()> {
|
||||
pub fn cargo_toml(exercise_infos: &[ExerciseInfo]) -> Vec<u8> {
|
||||
let mut cargo_toml = Vec::with_capacity(1 << 13);
|
||||
cargo_toml.extend_from_slice(b"bin = [\n");
|
||||
for exercise_info in exercise_infos {
|
||||
|
@ -23,39 +23,10 @@ fn create_cargo_toml(exercise_infos: &[ExerciseInfo]) -> io::Result<()> {
|
|||
cargo_toml.extend_from_slice(b".rs\" },\n");
|
||||
}
|
||||
|
||||
cargo_toml.extend_from_slice(
|
||||
br#"]
|
||||
cargo_toml.extend_from_slice(b"]\n\n");
|
||||
cargo_toml.extend_from_slice(CARGO_TOML_PACKAGE.as_bytes());
|
||||
|
||||
[package]
|
||||
name = "rustlings"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
"#,
|
||||
);
|
||||
OpenOptions::new()
|
||||
.create_new(true)
|
||||
.write(true)
|
||||
.open("Cargo.toml")?
|
||||
.write_all(&cargo_toml)
|
||||
}
|
||||
|
||||
fn create_gitignore() -> io::Result<()> {
|
||||
OpenOptions::new()
|
||||
.create_new(true)
|
||||
.write(true)
|
||||
.open(".gitignore")?
|
||||
.write_all(GITIGNORE)
|
||||
}
|
||||
|
||||
fn create_vscode_dir() -> Result<()> {
|
||||
create_dir(".vscode").context("Failed to create the directory `.vscode`")?;
|
||||
OpenOptions::new()
|
||||
.create_new(true)
|
||||
.write(true)
|
||||
.open(".vscode/extensions.json")?
|
||||
.write_all(VS_CODE_EXTENSIONS_JSON)?;
|
||||
|
||||
Ok(())
|
||||
cargo_toml
|
||||
}
|
||||
|
||||
pub fn init(exercise_infos: &[ExerciseInfo]) -> Result<()> {
|
||||
|
@ -78,21 +49,33 @@ pub fn init(exercise_infos: &[ExerciseInfo]) -> Result<()> {
|
|||
.init_exercises_dir()
|
||||
.context("Failed to initialize the `rustlings/exercises` directory")?;
|
||||
|
||||
create_cargo_toml(exercise_infos)
|
||||
fs::write("Cargo.toml", cargo_toml(exercise_infos))
|
||||
.context("Failed to create the file `rustlings/Cargo.toml`")?;
|
||||
|
||||
create_gitignore().context("Failed to create the file `rustlings/.gitignore`")?;
|
||||
fs::write(".gitignore", GITIGNORE)
|
||||
.context("Failed to create the file `rustlings/.gitignore`")?;
|
||||
|
||||
create_vscode_dir().context("Failed to create the file `rustlings/.vscode/extensions.json`")?;
|
||||
create_dir(".vscode").context("Failed to create the directory `rustlings/.vscode`")?;
|
||||
fs::write(".vscode/extensions.json", VS_CODE_EXTENSIONS_JSON)
|
||||
.context("Failed to create the file `rustlings/.vscode/extensions.json`")?;
|
||||
|
||||
println!("{POST_INIT_MSG}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
const GITIGNORE: &[u8] = b"/target
|
||||
/.rustlings-state.txt
|
||||
pub const CARGO_TOML_PACKAGE: &str = r#"[package]
|
||||
name = "rustlings"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
"#;
|
||||
|
||||
pub const GITIGNORE: &[u8] = b"Cargo.lock
|
||||
.rustlings-state.txt
|
||||
target
|
||||
";
|
||||
|
||||
const VS_CODE_EXTENSIONS_JSON: &[u8] = br#"{"recommendations":["rust-lang.rust-analyzer"]}"#;
|
||||
pub const VS_CODE_EXTENSIONS_JSON: &[u8] = br#"{"recommendations":["rust-lang.rust-analyzer"]}"#;
|
||||
|
||||
const PROBABLY_IN_RUSTLINGS_DIR_ERR: &str =
|
||||
"A directory with the name `exercises` and a file with the name `Cargo.toml` already exist
|
||||
|
@ -106,3 +89,8 @@ const RUSTLINGS_DIR_ALREADY_EXISTS_ERR: &str =
|
|||
You probably already initialized Rustlings.
|
||||
Run `cd rustlings`
|
||||
Then run `rustlings` again";
|
||||
|
||||
const POST_INIT_MSG: &str = "Done initialization!
|
||||
|
||||
Run `cd rustlings` to go into the generated directory.
|
||||
Then run `rustlings` to get started.";
|
||||
|
|
48
src/main.rs
48
src/main.rs
|
@ -1,4 +1,4 @@
|
|||
use anyhow::{Context, Result};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use app_state::StateFileStatus;
|
||||
use clap::{Parser, Subcommand};
|
||||
use crossterm::{
|
||||
|
@ -12,6 +12,7 @@ use std::{
|
|||
};
|
||||
|
||||
mod app_state;
|
||||
mod dev;
|
||||
mod embedded;
|
||||
mod exercise;
|
||||
mod info_file;
|
||||
|
@ -21,14 +22,9 @@ mod progress_bar;
|
|||
mod run;
|
||||
mod watch;
|
||||
|
||||
use self::{
|
||||
app_state::AppState,
|
||||
info_file::InfoFile,
|
||||
init::init,
|
||||
list::list,
|
||||
run::run,
|
||||
watch::{watch, WatchExit},
|
||||
};
|
||||
use self::{app_state::AppState, dev::DevCommands, info_file::InfoFile, watch::WatchExit};
|
||||
|
||||
const CURRENT_FORMAT_VERSION: u8 = 1;
|
||||
|
||||
/// Rustlings is a collection of small exercises to get you used to writing and reading Rust code
|
||||
#[derive(Parser)]
|
||||
|
@ -61,6 +57,8 @@ enum Subcommands {
|
|||
/// The name of the exercise
|
||||
name: String,
|
||||
},
|
||||
#[command(subcommand)]
|
||||
Dev(DevCommands),
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
|
@ -70,10 +68,16 @@ fn main() -> Result<()> {
|
|||
|
||||
let info_file = InfoFile::parse()?;
|
||||
|
||||
if matches!(args.command, Some(Subcommands::Init)) {
|
||||
init(&info_file.exercises).context("Initialization failed")?;
|
||||
println!("{POST_INIT_MSG}");
|
||||
return Ok(());
|
||||
if info_file.format_version > CURRENT_FORMAT_VERSION {
|
||||
bail!(FORMAT_VERSION_HIGHER_ERR);
|
||||
}
|
||||
|
||||
match args.command {
|
||||
Some(Subcommands::Init) => {
|
||||
return init::init(&info_file.exercises).context("Initialization failed");
|
||||
}
|
||||
Some(Subcommands::Dev(dev_command)) => return dev_command.run(info_file),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if !Path::new("exercises").is_dir() {
|
||||
|
@ -122,22 +126,20 @@ fn main() -> Result<()> {
|
|||
};
|
||||
|
||||
loop {
|
||||
match watch(&mut app_state, notify_exercise_paths)? {
|
||||
match watch::watch(&mut app_state, notify_exercise_paths)? {
|
||||
WatchExit::Shutdown => break,
|
||||
// It is much easier to exit the watch mode, launch the list mode and then restart
|
||||
// the watch mode instead of trying to pause the watch threads and correct the
|
||||
// watch state.
|
||||
WatchExit::List => list(&mut app_state)?,
|
||||
WatchExit::List => list::list(&mut app_state)?,
|
||||
}
|
||||
}
|
||||
}
|
||||
// `Init` is handled above.
|
||||
Some(Subcommands::Init) => (),
|
||||
Some(Subcommands::Run { name }) => {
|
||||
if let Some(name) = name {
|
||||
app_state.set_current_exercise_by_name(&name)?;
|
||||
}
|
||||
run(&mut app_state)?;
|
||||
run::run(&mut app_state)?;
|
||||
}
|
||||
Some(Subcommands::Reset { name }) => {
|
||||
app_state.set_current_exercise_by_name(&name)?;
|
||||
|
@ -150,6 +152,8 @@ fn main() -> Result<()> {
|
|||
app_state.set_current_exercise_by_name(&name)?;
|
||||
println!("{}", app_state.current_exercise().hint);
|
||||
}
|
||||
// Handled in an earlier match.
|
||||
Some(Subcommands::Init | Subcommands::Dev(_)) => (),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -159,10 +163,10 @@ const CARGO_NOT_FOUND_ERR: &str = "Failed to find `cargo`.
|
|||
Did you already install Rust?
|
||||
Try running `cargo --version` to diagnose the problem.";
|
||||
|
||||
const POST_INIT_MSG: &str = "Done initialization!
|
||||
|
||||
Run `cd rustlings` to go into the generated directory.
|
||||
Then run `rustlings` to get started.";
|
||||
const FORMAT_VERSION_HIGHER_ERR: &str =
|
||||
"The format version specified in the `info.toml` file is higher than the last one supported.
|
||||
It is possible that you have an outdated version of Rustlings.
|
||||
Try to install the latest Rustlings version first.";
|
||||
|
||||
const PRE_INIT_MSG: &str = r"
|
||||
Welcome to...
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
format_version = 1
|
||||
|
||||
[[exercises]]
|
||||
name = "compFailure"
|
||||
mode = "run"
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
format_version = 1
|
||||
|
||||
[[exercises]]
|
||||
name = "pending_exercise"
|
||||
mode = "run"
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
format_version = 1
|
||||
|
||||
[[exercises]]
|
||||
name = "compSuccess"
|
||||
mode = "run"
|
||||
|
|
Loading…
Reference in a new issue