Custom link callback

This commit is contained in:
Laurenz 2023-02-06 13:53:21 +01:00
parent 7d28e6499e
commit 149e2b055b
4 changed files with 28 additions and 15 deletions

View File

@ -48,6 +48,7 @@ impl Html {
let mut raw = String::new(); let mut raw = String::new();
md::html::push_html(&mut raw, iter); md::html::push_html(&mut raw, iter);
raw.truncate(raw.trim_end().len()); raw.truncate(raw.trim_end().len());
Html { md: text.into(), raw, description } Html { md: text.into(), raw, description }
} }
@ -171,19 +172,23 @@ impl<'a> Handler<'a> {
true true
} }
fn handle_image(&self, path: &str) -> String { fn handle_image(&self, link: &str) -> String {
let data = IMAGES if let Some(file) = IMAGES.get_file(link) {
.get_file(path) self.resolver.image(&link, file.contents()).into()
.unwrap_or_else(|| panic!("missing image: {path}")) } else if let Some(url) = self.resolver.link(link) {
.contents(); url
self.resolver.image(&path, data).into() } else {
panic!("missing image: {link}")
}
} }
fn handle_link(&self, link: &str) -> Option<String> { fn handle_link(&self, link: &str) -> Option<String> {
if link.starts_with(['#', 'h']) { if link.starts_with('#') || link.starts_with("http") {
return Some(link.into()); return Some(link.into());
} else if !link.starts_with('$') { }
return None;
if !link.starts_with('$') {
return self.resolver.link(link);
} }
let root = link.split('/').next()?; let root = link.split('/').next()?;
@ -196,9 +201,10 @@ impl<'a> Handler<'a> {
"$styling" => "/docs/reference/styling/", "$styling" => "/docs/reference/styling/",
"$scripting" => "/docs/reference/scripting/", "$scripting" => "/docs/reference/scripting/",
"$types" => "/docs/reference/types/", "$types" => "/docs/reference/types/",
"$community" => "/docs/community/",
"$type" => "/docs/reference/types/", "$type" => "/docs/reference/types/",
"$func" => "/docs/reference/", "$func" => "/docs/reference/",
"$changelog" => "/docs/changelog/",
"$community" => "/docs/community/",
_ => panic!("unknown link root: {root}"), _ => panic!("unknown link root: {root}"),
}; };
@ -221,6 +227,7 @@ impl<'a> Handler<'a> {
route.push_str(info.category); route.push_str(info.category);
route.push('/'); route.push('/');
route.push_str(name); route.push_str(name);
route.push('/');
if let Some(param) = param { if let Some(param) = param {
route.push_str("#parameters--"); route.push_str("#parameters--");
route.push_str(param); route.push_str(param);

View File

@ -60,6 +60,9 @@ pub fn provide(resolver: &dyn Resolver) -> Vec<PageModel> {
/// Resolve consumer dependencies. /// Resolve consumer dependencies.
pub trait Resolver { pub trait Resolver {
/// Try to resolve a link that the system cannot resolve itself.
fn link(&self, link: &str) -> Option<String>;
/// Produce an URL for an image file. /// Produce an URL for an image file.
fn image(&self, filename: &str, data: &[u8]) -> String; fn image(&self, filename: &str, data: &[u8]) -> String;
@ -294,6 +297,7 @@ fn category_page(resolver: &dyn Resolver, category: &str) -> PageModel {
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub struct FuncModel { pub struct FuncModel {
pub name: &'static str, pub name: &'static str,
pub display: &'static str,
pub oneliner: &'static str, pub oneliner: &'static str,
pub details: Html, pub details: Html,
pub showable: bool, pub showable: bool,
@ -330,6 +334,7 @@ fn function_page(
fn func_model(resolver: &dyn Resolver, func: &Func, info: &FuncInfo) -> FuncModel { fn func_model(resolver: &dyn Resolver, func: &Func, info: &FuncInfo) -> FuncModel {
FuncModel { FuncModel {
name: info.name.into(), name: info.name.into(),
display: info.display,
oneliner: oneliner(info.docs), oneliner: oneliner(info.docs),
details: Html::markdown(resolver, info.docs), details: Html::markdown(resolver, info.docs),
showable: func.select(None).is_ok() && info.category != "math", showable: func.select(None).is_ok() && info.category != "math",
@ -442,7 +447,7 @@ fn types_page(resolver: &dyn Resolver, parent: &str) -> PageModel {
let mut items = vec![]; let mut items = vec![];
for model in type_models(resolver) { for model in type_models(resolver) {
let route = format!("{route}{}/", model.name); let route = format!("{route}{}/", urlify(&model.name));
items.push(CategoryItem { items.push(CategoryItem {
name: model.name.clone(), name: model.name.clone(),
route: route.clone(), route: route.clone(),
@ -694,7 +699,7 @@ fn details(key: &str) -> &str {
} }
/// Turn a title into an URL fragment. /// Turn a title into an URL fragment.
fn urlify(title: &str) -> String { pub fn urlify(title: &str) -> String {
title title
.chars() .chars()
.map(|c| c.to_ascii_lowercase()) .map(|c| c.to_ascii_lowercase())

View File

@ -39,9 +39,9 @@ math: |
{ x in RR | x "is natural" } $ { x in RR | x "is natural" } $
``` ```
Math mode defines a wide selection of [symbols]($category/math/symbols) like Math mode makes a wide selection of [symbols]($category/math/symbols) like
`pi`, `dot`, or `RR`. Many mathematical symbols are available in different `pi`, `dot`, or `RR` available. Many mathematical symbols are available in
variants. You can select between different variants by applying different variants. You can select between different variants by applying
[modifiers]($type/symbol) to the symbol. Typst further recognizes a number of [modifiers]($type/symbol) to the symbol. Typst further recognizes a number of
shorthand sequences like `=>` that approximate a symbol. When such a shorthand shorthand sequences like `=>` that approximate a symbol. When such a shorthand
exists, the symbol's documentation lists it. exists, the symbol's documentation lists it.

View File

@ -160,6 +160,7 @@ pub struct FontInfo {
bitflags::bitflags! { bitflags::bitflags! {
/// Bitflags describing characteristics of a font. /// Bitflags describing characteristics of a font.
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(transparent)]
pub struct FontFlags: u32 { pub struct FontFlags: u32 {
/// All glyphs have the same width. /// All glyphs have the same width.
const MONOSPACE = 1 << 0; const MONOSPACE = 1 << 0;