diff --git a/Cargo.lock b/Cargo.lock
index 98e120c..2cad9e5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -193,6 +193,15 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+[[package]]
+name = "form_urlencoded"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+dependencies = [
+ "percent-encoding",
+]
+
[[package]]
name = "funty"
version = "1.1.0"
@@ -312,6 +321,16 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
+[[package]]
+name = "idna"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
+dependencies = [
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
[[package]]
name = "include_dir"
version = "0.7.3"
@@ -400,6 +419,7 @@ dependencies = [
"serde_json",
"tokio",
"toml",
+ "url",
"walkdir",
]
@@ -455,6 +475,12 @@ dependencies = [
"walkdir",
]
+[[package]]
+name = "percent-encoding"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+
[[package]]
name = "pin-project-lite"
version = "0.2.13"
@@ -584,6 +610,21 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
+[[package]]
+name = "tinyvec"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
[[package]]
name = "tokio"
version = "1.33.0"
@@ -630,12 +671,38 @@ dependencies = [
"winnow",
]
+[[package]]
+name = "unicode-bidi"
+version = "0.3.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416"
+
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+[[package]]
+name = "unicode-normalization"
+version = "0.1.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "url"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+]
+
[[package]]
name = "utf8parse"
version = "0.2.1"
diff --git a/Cargo.toml b/Cargo.toml
index 9b552d9..5f39eee 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -31,6 +31,7 @@ serde = { version = "1.0.189", default-features = false, features = ["std", "der
serde_json = "1.0.107"
tokio = { version = "1.30.0", default-features = false, features = ["rt", "rt-multi-thread", "fs", "io-util"] }
toml = "0.8.2"
+url = "2.5.0"
walkdir = "2.4.0"
# Optimized build for any sort of release.
diff --git a/default_environment/templates/html/regular_link.dust b/default_environment/templates/html/regular_link.dust
index 2566d30..5a0dcb7 100644
--- a/default_environment/templates/html/regular_link.dust
+++ b/default_environment/templates/html/regular_link.dust
@@ -1 +1 @@
-{#.children}{>object/}{/.children}
+{#.children}{>object/}{/.children}
diff --git a/src/context/regular_link.rs b/src/context/regular_link.rs
index 9a84f51..fc77598 100644
--- a/src/context/regular_link.rs
+++ b/src/context/regular_link.rs
@@ -11,6 +11,7 @@ use super::RenderObject;
#[serde(tag = "type")]
#[serde(rename = "regular_link")]
pub(crate) struct RenderRegularLink {
+ target: String,
raw_link: String,
children: Vec,
post_blank: organic::types::PostBlank,
@@ -25,7 +26,13 @@ render!(RenderRegularLink, IRegularLink, original, render_context, {
ret
};
+ let target = original
+ .target
+ .generate_final_target(render_context.clone())?
+ .unwrap_or_else(|| "".to_owned());
+
Ok(RenderRegularLink {
+ target,
raw_link: original.raw_link.clone(),
children,
post_blank: original.post_blank,
diff --git a/src/error/error.rs b/src/error/error.rs
index a6816ee..44064e3 100644
--- a/src/error/error.rs
+++ b/src/error/error.rs
@@ -16,6 +16,7 @@ pub(crate) enum CustomError {
DusterCompile(duster::renderer::CompileError),
DusterRender(duster::renderer::RenderError),
PathStripPrefix(std::path::StripPrefixError),
+ UrlParseError(url::ParseError),
}
impl From for CustomError {
@@ -95,3 +96,9 @@ impl From for CustomError {
CustomError::PathStripPrefix(value)
}
}
+
+impl From for CustomError {
+ fn from(value: url::ParseError) -> Self {
+ CustomError::UrlParseError(value)
+ }
+}
diff --git a/src/intermediate/regular_link.rs b/src/intermediate/regular_link.rs
index 2b2c249..faab0a7 100644
--- a/src/intermediate/regular_link.rs
+++ b/src/intermediate/regular_link.rs
@@ -1,14 +1,18 @@
use organic::types::StandardProperties;
+use url::Url;
+use super::get_web_path;
use super::macros::intermediate;
use super::IObject;
+use crate::context::RenderContext;
use crate::error::CustomError;
#[derive(Debug, Clone)]
pub(crate) struct IRegularLink {
pub(crate) raw_link: String,
pub(crate) children: Vec,
+ pub(crate) target: LinkTarget,
pub(crate) post_blank: organic::types::PostBlank,
}
@@ -25,10 +29,82 @@ intermediate!(
}
ret
};
+ let raw_link = original.get_raw_link();
+ let target = LinkTarget::from_string(&raw_link)?;
Ok(IRegularLink {
- raw_link: original.get_raw_link().into_owned(),
+ raw_link: raw_link.into_owned(),
children,
+ target,
post_blank: original.get_post_blank(),
})
}
);
+
+#[derive(Debug, Clone)]
+pub(crate) enum LinkTarget {
+ Raw(String),
+ Post {
+ post_id: Option,
+ subpath: String,
+ },
+}
+
+impl LinkTarget {
+ pub(crate) fn from_string>(input: S) -> Result {
+ fn impl_from_string(input: &str) -> Result {
+ let parsed = Url::parse(input);
+ if let Err(url::ParseError::RelativeUrlWithoutBase) = parsed {
+ // For URLs to targets.
+ // TODO: This shouldn't be raw but instead a variant for targets.
+ return Ok(LinkTarget::Raw(input.to_owned()));
+ }
+ let parsed = parsed?;
+ match parsed.scheme() {
+ "post" => {
+ let post_id = parsed.host_str().map(str::to_owned);
+ let subpath = {
+ let subpath = parsed.path();
+ if let Some(subpath) = subpath.strip_prefix('/') {
+ subpath
+ } else {
+ subpath
+ }
+ };
+ Ok(LinkTarget::Post {
+ post_id,
+ subpath: subpath.to_owned(),
+ })
+ }
+ _ => Ok(LinkTarget::Raw(input.to_owned())),
+ }
+ }
+ impl_from_string(input.as_ref())
+ }
+
+ pub(crate) fn generate_final_target(
+ &self,
+ render_context: RenderContext<'_>,
+ ) -> Result