mirror of
https://github.com/rust-lang/rustlings.git
synced 2026-06-30 00:08:45 +00:00
Merge 41f60c4e910aefc056ade7d8c7ab64713bec9f0d into 5e7a5d172106e75a50039a1846e38eca9f812bc1
This commit is contained in:
commit
e7bbfafbcd
@ -21,6 +21,7 @@ use crate::{
|
|||||||
exercise::{Exercise, RunnableExercise},
|
exercise::{Exercise, RunnableExercise},
|
||||||
info_file::ExerciseInfo,
|
info_file::ExerciseInfo,
|
||||||
term::{self, CheckProgressVisualizer},
|
term::{self, CheckProgressVisualizer},
|
||||||
|
url_replacer::UrlReplacer,
|
||||||
};
|
};
|
||||||
|
|
||||||
const STATE_FILE_NAME: &str = ".rustlings-state.txt";
|
const STATE_FILE_NAME: &str = ".rustlings-state.txt";
|
||||||
@ -68,6 +69,7 @@ impl AppState {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
exercise_infos: Vec<ExerciseInfo>,
|
exercise_infos: Vec<ExerciseInfo>,
|
||||||
final_message: &'static str,
|
final_message: &'static str,
|
||||||
|
base_url: Option<String>,
|
||||||
editor: Option<Editor>,
|
editor: Option<Editor>,
|
||||||
vs_code_term: bool,
|
vs_code_term: bool,
|
||||||
) -> Result<(Self, StateFileStatus)> {
|
) -> Result<(Self, StateFileStatus)> {
|
||||||
@ -82,10 +84,19 @@ impl AppState {
|
|||||||
format!("Failed to open or create the state file {STATE_FILE_NAME}")
|
format!("Failed to open or create the state file {STATE_FILE_NAME}")
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
// replacer for rustbook url
|
||||||
|
let url_replacer = base_url.as_ref().map(|url| UrlReplacer::new(url));
|
||||||
|
|
||||||
let dir_canonical_path = term::canonicalize("exercises");
|
let dir_canonical_path = term::canonicalize("exercises");
|
||||||
let mut exercises = exercise_infos
|
let mut exercises = exercise_infos
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|exercise_info| {
|
.map(|exercise_info| {
|
||||||
|
let hint = if let Some(replacer) = &url_replacer {
|
||||||
|
replacer.replace(exercise_info.hint.trim_ascii())
|
||||||
|
} else {
|
||||||
|
exercise_info.hint.trim_ascii().to_string()
|
||||||
|
};
|
||||||
|
|
||||||
let canonical_path = dir_canonical_path.as_deref().map(|dir_canonical_path| {
|
let canonical_path = dir_canonical_path.as_deref().map(|dir_canonical_path| {
|
||||||
let mut canonical_path;
|
let mut canonical_path;
|
||||||
if let Some(dir) = exercise_info.dir {
|
if let Some(dir) = exercise_info.dir {
|
||||||
@ -117,7 +128,7 @@ impl AppState {
|
|||||||
canonical_path,
|
canonical_path,
|
||||||
test: exercise_info.test,
|
test: exercise_info.test,
|
||||||
strict_clippy: exercise_info.strict_clippy,
|
strict_clippy: exercise_info.strict_clippy,
|
||||||
hint: exercise_info.hint.trim_ascii(),
|
hint,
|
||||||
// Updated below.
|
// Updated below.
|
||||||
done: false,
|
done: false,
|
||||||
}
|
}
|
||||||
@ -617,7 +628,7 @@ mod tests {
|
|||||||
canonical_path: None,
|
canonical_path: None,
|
||||||
test: false,
|
test: false,
|
||||||
strict_clippy: false,
|
strict_clippy: false,
|
||||||
hint: "",
|
hint: String::new(),
|
||||||
done: false,
|
done: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,6 +26,9 @@ pub struct Args {
|
|||||||
/// Only use this if Rustlings fails to detect exercise file changes
|
/// Only use this if Rustlings fails to detect exercise file changes
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
pub manual_run: bool,
|
pub manual_run: bool,
|
||||||
|
/// Replace the rustbook URL with the provided base URL.
|
||||||
|
#[arg(long)]
|
||||||
|
pub base_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
|
|||||||
@ -73,7 +73,7 @@ pub struct Exercise {
|
|||||||
pub canonical_path: Option<String>,
|
pub canonical_path: Option<String>,
|
||||||
pub test: bool,
|
pub test: bool,
|
||||||
pub strict_clippy: bool,
|
pub strict_clippy: bool,
|
||||||
pub hint: &'static str,
|
pub hint: String,
|
||||||
pub done: bool,
|
pub done: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -29,6 +29,7 @@ mod init;
|
|||||||
mod list;
|
mod list;
|
||||||
mod run;
|
mod run;
|
||||||
mod term;
|
mod term;
|
||||||
|
mod url_replacer;
|
||||||
mod watch;
|
mod watch;
|
||||||
|
|
||||||
const CURRENT_FORMAT_VERSION: u8 = 1;
|
const CURRENT_FORMAT_VERSION: u8 = 1;
|
||||||
@ -71,6 +72,7 @@ fn main() -> Result<ExitCode> {
|
|||||||
let (mut app_state, state_file_status) = AppState::new(
|
let (mut app_state, state_file_status) = AppState::new(
|
||||||
info_file.exercises,
|
info_file.exercises,
|
||||||
info_file.final_message.unwrap_or_default(),
|
info_file.final_message.unwrap_or_default(),
|
||||||
|
args.base_url,
|
||||||
editor,
|
editor,
|
||||||
vs_code_term,
|
vs_code_term,
|
||||||
)?;
|
)?;
|
||||||
|
|||||||
67
src/url_replacer.rs
Normal file
67
src/url_replacer.rs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
pub struct UrlReplacer {
|
||||||
|
base_url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
const EN_BASE_URL: &str = "https://doc.rust-lang.org/book";
|
||||||
|
|
||||||
|
impl UrlReplacer {
|
||||||
|
/// this fn will trim url end with '/'
|
||||||
|
pub fn new(base_url: &str) -> Self {
|
||||||
|
let url = if base_url.ends_with('/') {
|
||||||
|
base_url.trim_end_matches('/').to_owned()
|
||||||
|
} else {
|
||||||
|
base_url.to_owned()
|
||||||
|
};
|
||||||
|
|
||||||
|
Self { base_url: url }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// replace rustbook url
|
||||||
|
pub fn replace(&self, hint: &str) -> String {
|
||||||
|
hint.replace(EN_BASE_URL, &self.base_url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const TEST_DOMAIN: &str = "https://doc.rust-kr.org";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn non_rustbook_url() {
|
||||||
|
let replacer = UrlReplacer::new(&String::from(TEST_DOMAIN));
|
||||||
|
|
||||||
|
let hint = "\
|
||||||
|
hints (...) lines (...)
|
||||||
|
link: https://example.com/ch03-02-data-types.html";
|
||||||
|
|
||||||
|
assert_eq!(hint, replacer.replace(hint));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn replace_rustbook_url() {
|
||||||
|
let replacer = UrlReplacer::new(&String::from(TEST_DOMAIN));
|
||||||
|
|
||||||
|
let hint = "\
|
||||||
|
hints (...) lines (...)
|
||||||
|
link: https://doc.rust-lang.org/book/ch03-02-data-types.html";
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
"\
|
||||||
|
hints (...) lines (...)
|
||||||
|
link: https://doc.rust-kr.org/ch03-02-data-types.html",
|
||||||
|
replacer.replace(hint)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn trim_end_with_slash() {
|
||||||
|
let mut domain = String::from(TEST_DOMAIN);
|
||||||
|
domain.push('/');
|
||||||
|
|
||||||
|
let replacer = UrlReplacer::new(&domain);
|
||||||
|
|
||||||
|
assert_eq!(TEST_DOMAIN, replacer.base_url);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user