diff --git a/README.md b/README.md index 9596e1f..8208a9d 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ it works. You need a recent version of Rust, which is most easily installed with [rustup.rs](https://rustup.rs). -In addition, you will also need [Trunk](https://trunkrs.dev/), which is a tool +In addition, you will also need [Trunk](https://trunk-rs.github.io/trunk/), which is a tool that helps to build Rust WebAssembly applications, and the WebAssembly build target for Rust. You can install it like this: diff --git a/src/components/file_tree.rs b/src/components/file_tree.rs index 0fbf1f0..a550262 100644 --- a/src/components/file_tree.rs +++ b/src/components/file_tree.rs @@ -22,8 +22,8 @@ impl Context { Route::File { old_krate: self.old_krate.clone(), old_version: self.old_version.clone(), - new_krate: self.new_krate.clone(), - new_version: self.new_version.clone(), + new_krate: self.new_krate.clone().into(), + new_version: self.new_version.clone().into(), path, } .simplify() diff --git a/src/lib.rs b/src/lib.rs index 03844de..4a376a4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,7 @@ mod cache; pub mod components; mod data; +mod maybe_parsed; mod syntax; #[cfg(test)] mod tests; @@ -15,6 +16,7 @@ mod version; pub mod views; use crate::{ + maybe_parsed::MaybeParsed, version::{VersionId, VersionNamed}, views::*, }; @@ -92,8 +94,13 @@ pub enum Route { File { old_krate: String, old_version: VersionId, - new_krate: String, - new_version: VersionId, + // Handling of `/` in wildcard fields changed in yew-router-0.20 and route + // recognizer can match this handler instead of SingleSourceFile. + // + // The following two fields are parsed optionally and then routed manually in + // Route::render method. + new_krate: MaybeParsed, + new_version: MaybeParsed, path: Utf8PathBuf, }, @@ -177,9 +184,27 @@ impl Route { new_krate, new_version, path, - } => html! { - - }, + } => { + // Route manually to keep compatibility with old links. + match (new_krate, new_version) { + (MaybeParsed::String(new_krate), MaybeParsed::Parsed(new_version)) => { + // matched /:old_krate/:old_version/:new_krate/:new_version/*path + html! { + + } + } + (MaybeParsed::Parsed(new_version), root) => { + // matched /:krate/:old_version/:new_version/:root/*path + Route::render(Route::SingleSourceFile { + krate: old_krate, + old_version, + new_version, + path: Utf8PathBuf::from(String::from(root)).join(path), + }) + } + _ => Route::render(Route::NotFound), + } + } Route::NotFound => html! { }, Route::Search { query } => html! { }, Route::RepoFile { @@ -201,8 +226,8 @@ impl Route { Route::File { old_krate, old_version, - new_krate, - new_version, + new_krate: MaybeParsed::String(new_krate), + new_version: MaybeParsed::Parsed(new_version), path, } if old_krate == new_krate => Route::SingleSourceFile { krate: old_krate, diff --git a/src/maybe_parsed.rs b/src/maybe_parsed.rs new file mode 100644 index 0000000..0b4745c --- /dev/null +++ b/src/maybe_parsed.rs @@ -0,0 +1,59 @@ +use std::{ + convert::Infallible, + fmt::{Display, Formatter, Result as FmtResult}, + str::FromStr, +}; + +use crate::version::VersionId; + +#[derive(Clone, PartialEq)] +pub enum MaybeParsed { + Parsed(T), + String(String), +} + +impl FromStr for MaybeParsed { + type Err = Infallible; + + fn from_str(input: &str) -> Result { + Ok(T::from_str(input) + .map(Self::Parsed) + .unwrap_or_else(|_| MaybeParsed::String(input.to_string()))) + } +} + +impl Display for MaybeParsed { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + match self { + Self::Parsed(i) => i.fmt(f), + Self::String(i) => i.fmt(f), + } + } +} + +impl From> for String { + fn from(value: MaybeParsed) -> Self { + match value { + MaybeParsed::Parsed(i) => i.to_string(), + MaybeParsed::String(i) => i, + } + } +} + +impl From for MaybeParsed { + fn from(value: String) -> Self { + Self::String(value) + } +} + +impl From for MaybeParsed { + fn from(value: semver::Version) -> Self { + Self::Parsed(value.into()) + } +} + +impl From for MaybeParsed { + fn from(value: VersionId) -> Self { + Self::Parsed(value) + } +} diff --git a/src/views/diff.rs b/src/views/diff.rs index 97719bc..d773e2d 100644 --- a/src/views/diff.rs +++ b/src/views/diff.rs @@ -206,7 +206,7 @@ fn SourceFetcherInner(props: &SourceFetcherProps) -> HtmlResult { move |((src_name, old), (dst_name, new)): ((String, Version), (String, Version))| { navigator.push(&Route::File { old_krate: src_name.clone(), - new_krate: dst_name.clone(), + new_krate: dst_name.clone().into(), old_version: old.clone().into(), new_version: new.clone().into(), path: path.clone().unwrap_or_default().into(), @@ -230,7 +230,7 @@ fn SourceFetcherInner(props: &SourceFetcherProps) -> HtmlResult { return Ok(html! { to={Route::File { old_krate: props.src_info.krate.id.clone(), - new_krate: props.dst_info.krate.id.clone(), + new_krate: props.dst_info.krate.id.clone().into(), old_version: props.old.version.clone().into(), new_version: props.new.version.clone().into(), path: "Cargo.toml".into(), @@ -283,7 +283,7 @@ pub fn SourceView(props: &SourceViewProps) -> Html { move |((src_name, old), (dst_name, new)): ((String, Version), (String, Version))| { navigator.push(&Route::File { old_krate: src_name.clone(), - new_krate: dst_name.clone(), + new_krate: dst_name.clone().into(), old_version: old.clone().into(), new_version: new.clone().into(), path: path.clone(),