Add a get_url global fn

Close #67
This commit is contained in:
Vincent Prouillet 2017-05-17 19:04:26 +09:00
parent 59b4b07cb3
commit b2a63e2ada
6 changed files with 91 additions and 22 deletions

View file

@ -4,6 +4,7 @@
- Fix missing serialized data for sections
- Change the single item template context for categories/tags
- Add a `get_url` global Tera function
## 0.0.5 (2017-05-15)

18
Cargo.lock generated
View file

@ -4,7 +4,7 @@ version = "0.0.5"
dependencies = [
"base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.24.1 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.24.2 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"iron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -155,7 +155,7 @@ dependencies = [
[[package]]
name = "clap"
version = "2.24.1"
version = "2.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -163,9 +163,9 @@ dependencies = [
"bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -941,7 +941,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-segmentation"
version = "1.1.0"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -991,7 +991,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "vec_map"
version = "0.7.0"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -1084,7 +1084,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
"checksum chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "9213f7cd7c27e95c2b57c49f0e69b1ea65b27138da84a170133fd21b07659c00"
"checksum chrono 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d9123be86fd2a8f627836c235ecdf331fdd067ecf7ac05aa1a68fbcf2429f056"
"checksum clap 2.24.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7541069be0b8aec41030802abe8b5cdef0490070afaa55418adea93b1e431e0"
"checksum clap 2.24.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b8f69e518f967224e628896b54e41ff6acfb4dcfefc5076325c36525dac900f"
"checksum cmake 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "92278eb79412c8f75cfc89e707a1bb3a6490b68f7f2e78d15c774f30fe701122"
"checksum conduit-mime-types 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "95ca30253581af809925ef68c2641cc140d6183f43e12e0af4992d53768bd7b8"
"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
@ -1179,7 +1179,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "13a5906ca2b98c799f4b1ab4557b76367ebd6ae5ef14930ec841c74aed5f3764"
"checksum unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a078ebdd62c0e71a709c3d53d2af693fe09fe93fbff8344aebe289b78f9032"
"checksum unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e28fa37426fceeb5cf8f41ee273faa7c82c47dc8fba5853402841e665fcd86ff"
"checksum unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18127285758f0e2c6cf325bb3f3d138a12fee27de4f23e146cd6a179f26c2cf3"
"checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946"
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
"checksum unidecode 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2adb95ee07cd579ed18131f2d9e7a17c25a4b76022935c7f2460d2bfae89fd2"
@ -1187,7 +1187,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum unsafe-any 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b351086021ebc264aea3ab4f94d61d889d98e5e9ec2d985d993f50133537fd3a"
"checksum url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5ba8a749fb4479b043733416c244fa9d1d3af3d7c23804944651c8a448cb87e"
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
"checksum vec_map 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8cdc8b93bd0198ed872357fb2e667f7125646b1762f16d60b2c96350d361897"
"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum walkdir 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c66c0b9792f0a765345452775f3adbd28dde9d33f30d13e5dcc5ae17cf6f3780"
"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff"

View file

@ -119,6 +119,8 @@ pub fn after_content_change(site: &mut Site, path: &Path) -> Result<()> {
}
};
}
// Ensure we have our fn updated so it doesn't contain the permalinks deleted
site.register_get_url_fn();
// Deletion is something that doesn't happen all the time so we
// don't need to optimise it too much
return site.build();
@ -153,6 +155,7 @@ pub fn after_content_change(site: &mut Site, path: &Path) -> Result<()> {
return Ok(());
},
None => {
site.register_get_url_fn();
// New section, only render that one
site.populate_sections();
return site.render_section(&site.sections[path], true);
@ -163,6 +166,7 @@ pub fn after_content_change(site: &mut Site, path: &Path) -> Result<()> {
// A page was edited
match site.add_page(path, true)? {
Some(prev) => {
site.register_get_url_fn();
// Updating a page
let current = site.pages[path].clone();
// Front matter didn't change, only content did
@ -201,6 +205,7 @@ pub fn after_content_change(site: &mut Site, path: &Path) -> Result<()> {
},
None => {
site.register_get_url_fn();
// It's a new page!
site.populate_sections();
site.populate_tags_and_categories();

View file

@ -14,6 +14,7 @@ use tera::{Tera, Context};
use config::Config;
use errors::{Result, ResultExt};
use site::resolve_internal_link;
// We need to put those in a struct to impl Send and sync
@ -257,21 +258,11 @@ pub fn markdown_to_html(content: &str, permalinks: &HashMap<String, String>, ter
return Event::Html(Owned("".to_owned()));
}
if link.starts_with("./") {
// First we remove the ./ since that's gutenberg specific
let clean_link = link.replacen("./", "", 1);
// Then we remove any potential anchor
// parts[0] will be the file path and parts[1] the anchor if present
let parts = clean_link.split('#').collect::<Vec<_>>();
match permalinks.get(parts[0]) {
Some(p) => {
let url = if parts.len() > 1 {
format!("{}#{}", p, parts[1])
} else {
p.to_string()
};
match resolve_internal_link(link, permalinks) {
Ok(url) => {
return Event::Start(Tag::Link(Owned(url), title.clone()));
},
None => {
Err(_) => {
error = Some(format!("Relative link {} not found.", link).into());
return Event::Html(Owned("".to_string()));
}

View file

@ -125,10 +125,16 @@ impl Site {
self.populate_tags_and_categories();
self.tera.register_global_function("get_page", global_fns::make_get_page(&self.pages));
self.register_get_url_fn();
Ok(())
}
/// Separate fn as it can be called in the serve command
pub fn register_get_url_fn(&mut self) {
self.tera.register_global_function("get_url", global_fns::make_get_url(self.permalinks.clone()));
}
/// Add a page to the site
/// The `render` parameter is used in the serve command, when rebuilding a page.
/// If `true`, it will also render the markdown for that page
@ -545,3 +551,53 @@ impl Site {
Ok(())
}
}
/// Resolves an internal link (of the `./posts/something.md#hey` sort) to its absolute link
pub fn resolve_internal_link(link: &str, permalinks: &HashMap<String, String>) -> Result<String> {
// First we remove the ./ since that's gutenberg specific
let clean_link = link.replacen("./", "", 1);
// Then we remove any potential anchor
// parts[0] will be the file path and parts[1] the anchor if present
let parts = clean_link.split('#').collect::<Vec<_>>();
match permalinks.get(parts[0]) {
Some(p) => {
if parts.len() > 1 {
Ok(format!("{}#{}", p, parts[1]))
} else {
Ok(p.to_string())
}
},
None => bail!(format!("Relative link {} not found.", link)),
}
}
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use super::resolve_internal_link;
#[test]
fn can_resolve_valid_internal_link() {
let mut permalinks = HashMap::new();
permalinks.insert("pages/about.md".to_string(), "https://vincent.is/about".to_string());
let res = resolve_internal_link("./pages/about.md", &permalinks).unwrap();
assert_eq!(res, "https://vincent.is/about");
}
#[test]
fn can_resolve_internal_links_with_anchors() {
let mut permalinks = HashMap::new();
permalinks.insert("pages/about.md".to_string(), "https://vincent.is/about".to_string());
let res = resolve_internal_link("./pages/about.md#hello", &permalinks).unwrap();
assert_eq!(res, "https://vincent.is/about#hello");
}
#[test]
fn errors_resolve_inexistant_internal_link() {
let res = resolve_internal_link("./pages/about.md#hello", &HashMap::new());
assert!(res.is_err());
}
}

View file

@ -4,6 +4,7 @@ use std::path::{PathBuf};
use tera::{GlobalFn, Value, from_value, to_value, Result};
use content::Page;
use site::resolve_internal_link;
pub fn make_get_page(all_pages: &HashMap<PathBuf, Page>) -> GlobalFn {
@ -27,3 +28,18 @@ pub fn make_get_page(all_pages: &HashMap<PathBuf, Page>) -> GlobalFn {
}
})
}
pub fn make_get_url(permalinks: HashMap<String, String>,) -> GlobalFn {
Box::new(move |args| -> Result<Value> {
match args.get("link") {
Some(val) => match from_value::<String>(val.clone()) {
Ok(v) => match resolve_internal_link(&v, &permalinks) {
Ok(url) => Ok(to_value(url).unwrap()),
Err(_) => Err(format!("Could not resolve URL for link `{}` not found.", v).into())
},
Err(_) => Err(format!("`get_url` received link={:?} but it requires a string", val).into()),
},
None => Err("`get_url` requires a `link` argument.".into()),
}
})
}