diff --git a/crates/typst-docs/src/html.rs b/crates/typst-docs/src/html.rs
index 8f6d1366d..0ec0ddf02 100644
--- a/crates/typst-docs/src/html.rs
+++ b/crates/typst-docs/src/html.rs
@@ -307,7 +307,7 @@ impl<'a> Handler<'a> {
return Ok(link);
}
- crate::link::resolve(link)
+ crate::link::resolve(link, self.resolver.base())
}
fn nesting(&self) -> usize {
diff --git a/crates/typst-docs/src/lib.rs b/crates/typst-docs/src/lib.rs
index f25314629..315a2ed58 100644
--- a/crates/typst-docs/src/lib.rs
+++ b/crates/typst-docs/src/lib.rs
@@ -78,14 +78,15 @@ static FONTS: Lazy<(Prehashed, Vec)> = Lazy::new(|| {
/// Build documentation pages.
pub fn provide(resolver: &dyn Resolver) -> Vec {
vec![
- markdown_page(resolver, "/docs/", "overview.md").with_route("/docs/"),
+ markdown_page(resolver, resolver.base(), "overview.md")
+ .with_route(resolver.base()),
tutorial_pages(resolver),
reference_pages(resolver),
guide_pages(resolver),
packages_page(resolver),
- markdown_page(resolver, "/docs/", "changelog.md"),
- markdown_page(resolver, "/docs/", "roadmap.md"),
- markdown_page(resolver, "/docs/", "community.md"),
+ markdown_page(resolver, resolver.base(), "changelog.md"),
+ markdown_page(resolver, resolver.base(), "roadmap.md"),
+ markdown_page(resolver, resolver.base(), "community.md"),
]
}
@@ -102,6 +103,9 @@ pub trait Resolver {
/// Determine the commits between two tags.
fn commits(&self, from: &str, to: &str) -> Vec;
+
+ /// Get the base URL for the routes and links. This must end with a slash.
+ fn base(&self) -> &str;
}
/// Create a page from a markdown file.
@@ -128,25 +132,39 @@ fn markdown_page(
/// Build the tutorial.
fn tutorial_pages(resolver: &dyn Resolver) -> PageModel {
- let mut page = markdown_page(resolver, "/docs/", "tutorial/welcome.md");
+ let mut page = markdown_page(resolver, resolver.base(), "tutorial/welcome.md");
page.children = DOCS_DIR
.get_dir("tutorial")
.unwrap()
.files()
.filter(|file| file.path() != Path::new("tutorial/welcome.md"))
- .map(|file| markdown_page(resolver, "/docs/tutorial/", file.path()))
+ .map(|file| {
+ markdown_page(resolver, &format!("{}tutorial/", resolver.base()), file.path())
+ })
.collect();
page
}
/// Build the reference.
fn reference_pages(resolver: &dyn Resolver) -> PageModel {
- let mut page = markdown_page(resolver, "/docs/", "reference/welcome.md");
+ let mut page = markdown_page(resolver, resolver.base(), "reference/welcome.md");
page.children = vec![
- markdown_page(resolver, "/docs/reference/", "reference/syntax.md")
- .with_part("Language"),
- markdown_page(resolver, "/docs/reference/", "reference/styling.md"),
- markdown_page(resolver, "/docs/reference/", "reference/scripting.md"),
+ markdown_page(
+ resolver,
+ &format!("{}reference/", resolver.base()),
+ "reference/syntax.md",
+ )
+ .with_part("Language"),
+ markdown_page(
+ resolver,
+ &format!("{}reference/", resolver.base()),
+ "reference/styling.md",
+ ),
+ markdown_page(
+ resolver,
+ &format!("{}reference/", resolver.base()),
+ "reference/scripting.md",
+ ),
category_page(resolver, FOUNDATIONS).with_part("Library"),
category_page(resolver, MODEL),
category_page(resolver, TEXT),
@@ -162,10 +180,18 @@ fn reference_pages(resolver: &dyn Resolver) -> PageModel {
/// Build the guides section.
fn guide_pages(resolver: &dyn Resolver) -> PageModel {
- let mut page = markdown_page(resolver, "/docs/", "guides/welcome.md");
+ let mut page = markdown_page(resolver, resolver.base(), "guides/welcome.md");
page.children = vec![
- markdown_page(resolver, "/docs/guides/", "guides/guide-for-latex-users.md"),
- markdown_page(resolver, "/docs/guides/", "guides/page-setup.md"),
+ markdown_page(
+ resolver,
+ &format!("{}guides/", resolver.base()),
+ "guides/guide-for-latex-users.md",
+ ),
+ markdown_page(
+ resolver,
+ &format!("{}guides/", resolver.base()),
+ "guides/page-setup.md",
+ ),
];
page
}
@@ -178,7 +204,7 @@ fn packages_page(resolver: &dyn Resolver) -> PageModel {
.contents_utf8()
.unwrap();
PageModel {
- route: "/docs/packages/".into(),
+ route: eco_format!("{}packages/", resolver.base()),
title: "Packages".into(),
description: "Packages for Typst.".into(),
part: None,
@@ -191,7 +217,7 @@ fn packages_page(resolver: &dyn Resolver) -> PageModel {
/// Create a page for a category.
#[track_caller]
fn category_page(resolver: &dyn Resolver, category: Category) -> PageModel {
- let route = eco_format!("/docs/reference/{}/", category.name());
+ let route = eco_format!("{}reference/{}/", resolver.base(), category.name());
let mut children = vec![];
let mut items = vec![];
let mut shorthands = None;
@@ -801,5 +827,9 @@ mod tests {
fn commits(&self, _: &str, _: &str) -> Vec {
vec![]
}
+
+ fn base(&self) -> &str {
+ "/"
+ }
}
}
diff --git a/crates/typst-docs/src/link.rs b/crates/typst-docs/src/link.rs
index e7e191fe6..20a4f6e4a 100644
--- a/crates/typst-docs/src/link.rs
+++ b/crates/typst-docs/src/link.rs
@@ -4,15 +4,15 @@ use typst::foundations::Func;
use crate::{get_module, GROUPS, LIBRARY};
/// Resolve an intra-doc link.
-pub fn resolve(link: &str) -> StrResult {
+pub fn resolve(link: &str, base: &str) -> StrResult {
if link.starts_with('#') || link.starts_with("http") {
return Ok(link.to_string());
}
let (head, tail) = split_link(link)?;
- let mut route = match resolve_known(head) {
- Some(route) => route.into(),
- None => resolve_definition(head)?,
+ let mut route = match resolve_known(head, base) {
+ Some(route) => route,
+ None => resolve_definition(head, base)?,
};
if !tail.is_empty() {
@@ -35,24 +35,24 @@ fn split_link(link: &str) -> StrResult<(&str, &str)> {
}
/// Resolve a `$` link head to a known destination.
-fn resolve_known(head: &str) -> Option<&'static str> {
+fn resolve_known(head: &str, base: &str) -> Option {
Some(match head {
- "$tutorial" => "/docs/tutorial",
- "$reference" => "/docs/reference",
- "$category" => "/docs/reference",
- "$syntax" => "/docs/reference/syntax",
- "$styling" => "/docs/reference/styling",
- "$scripting" => "/docs/reference/scripting",
- "$guides" => "/docs/guides",
- "$packages" => "/docs/packages",
- "$changelog" => "/docs/changelog",
- "$community" => "/docs/community",
+ "$tutorial" => format!("{base}tutorial"),
+ "$reference" => format!("{base}reference"),
+ "$category" => format!("{base}reference"),
+ "$syntax" => format!("{base}reference/syntax"),
+ "$styling" => format!("{base}reference/styling"),
+ "$scripting" => format!("{base}reference/scripting"),
+ "$guides" => format!("{base}guides"),
+ "$packages" => format!("{base}packages"),
+ "$changelog" => format!("{base}changelog"),
+ "$community" => format!("{base}community"),
_ => return None,
})
}
/// Resolve a `$` link to a global definition.
-fn resolve_definition(head: &str) -> StrResult {
+fn resolve_definition(head: &str, base: &str) -> StrResult {
let mut parts = head.trim_start_matches('$').split('.').peekable();
let mut focus = &LIBRARY.global;
let mut category = None;
@@ -76,8 +76,8 @@ fn resolve_definition(head: &str) -> StrResult {
group.category == category.name() && group.filter.iter().any(|func| func == name)
}) {
let mut route = format!(
- "/docs/reference/{}/{}/#functions-{}",
- group.category, group.name, name
+ "{}reference/{}/{}/#functions-{}",
+ base, group.category, group.name, name
);
if let Some(param) = parts.next() {
route.push('-');
@@ -86,7 +86,7 @@ fn resolve_definition(head: &str) -> StrResult {
return Ok(route);
}
- let mut route = format!("/docs/reference/{}/{name}/", category.name());
+ let mut route = format!("{}reference/{}/{name}/", base, category.name());
if let Some(next) = parts.next() {
if value.field(next).is_ok() {
route.push_str("#definitions-");