diff options
Diffstat (limited to 'docs/src/lib.rs')
| -rw-r--r-- | docs/src/lib.rs | 210 |
1 files changed, 192 insertions, 18 deletions
diff --git a/docs/src/lib.rs b/docs/src/lib.rs index fcf3610c..30501e22 100644 --- a/docs/src/lib.rs +++ b/docs/src/lib.rs @@ -54,9 +54,9 @@ static LIBRARY: Lazy<Prehashed<Library>> = Lazy::new(|| { pub fn provide(resolver: &dyn Resolver) -> Vec<PageModel> { vec![ markdown_page(resolver, "/docs/", "general/overview.md").with_route("/docs/"), - tutorial_page(resolver), - reference_page(resolver), - markdown_page(resolver, "/docs/", "general/guide-for-latex-users.md"), + tutorial_pages(resolver), + reference_pages(resolver), + guides_pages(resolver), markdown_page(resolver, "/docs/", "general/changelog.md"), markdown_page(resolver, "/docs/", "general/community.md"), ] @@ -99,6 +99,14 @@ impl PageModel { } } +/// An element in the "On This Page" outline. +#[derive(Debug, Clone, Serialize)] +pub struct OutlineItem { + id: String, + name: String, + children: Vec<Self>, +} + /// Details about the body of a documentation page. #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] @@ -113,7 +121,7 @@ pub enum BodyModel { } /// Build the tutorial. -fn tutorial_page(resolver: &dyn Resolver) -> PageModel { +fn tutorial_pages(resolver: &dyn Resolver) -> PageModel { let mut page = markdown_page(resolver, "/docs/", "tutorial/welcome.md"); page.children = SRC .get_dir("tutorial") @@ -125,8 +133,16 @@ fn tutorial_page(resolver: &dyn Resolver) -> PageModel { page } +/// Build the guides section. +fn guides_pages(resolver: &dyn Resolver) -> PageModel { + let mut page = markdown_page(resolver, "/docs/", "guides/welcome.md"); + page.children = + vec![markdown_page(resolver, "/docs/guides/", "guides/guide-for-latex-users.md")]; + page +} + /// Build the reference. -fn reference_page(resolver: &dyn Resolver) -> PageModel { +fn reference_pages(resolver: &dyn Resolver) -> PageModel { let mut page = markdown_page(resolver, "/docs/", "reference/welcome.md"); page.children = vec![ markdown_page(resolver, "/docs/reference/", "reference/syntax.md") @@ -164,6 +180,7 @@ fn markdown_page( title, description: html.description().unwrap(), part: None, + outline: html.outline(), body: BodyModel::Html(html), children: vec![], } @@ -200,6 +217,12 @@ fn category_page(resolver: &dyn Resolver, category: &str) -> PageModel { _ => &LIBRARY.global, }; + let parents: &[&str] = match category { + "math" => &[], + "calculate" => &["calc"], + _ => &[], + }; + let grouped = match category { "math" => GROUPS.as_slice(), _ => &[], @@ -222,7 +245,7 @@ fn category_page(resolver: &dyn Resolver, category: &str) -> PageModel { continue; } - let subpage = function_page(resolver, &route, func, info); + let subpage = function_page(resolver, &route, func, info, parents); items.push(CategoryItem { name: info.name.into(), route: subpage.route.clone(), @@ -235,11 +258,21 @@ fn category_page(resolver: &dyn Resolver, category: &str) -> PageModel { // Add grouped functions. for group in grouped { let mut functions = vec![]; + let mut outline = vec![OutlineItem { + id: "summary".into(), + name: "Summary".into(), + children: vec![], + }]; + for name in &group.functions { let value = focus.get(name).unwrap(); let Value::Func(func) = value else { panic!("not a function") }; let info = func.info().unwrap(); - functions.push(func_model(resolver, func, info)); + let func = func_model(resolver, func, info, &[], info.name); + let id = urlify(&func.path.join("-")); + let children = func_outline(&func, &id, false); + outline.push(OutlineItem { id, name: func.display.into(), children }); + functions.push(func); } let route = format!("{}{}/", route, group.name); @@ -249,13 +282,16 @@ fn category_page(resolver: &dyn Resolver, category: &str) -> PageModel { oneliner: oneliner(&group.description).into(), code: false, }); + children.push(PageModel { route, - title: group.title.clone(), + title: group.display.clone(), description: format!("Documentation for {} group of functions.", group.name), part: None, + outline, body: BodyModel::Funcs(FuncsModel { name: group.name.clone(), + display: group.display.clone(), details: Html::markdown(resolver, &group.description), functions, }), @@ -281,28 +317,47 @@ fn category_page(resolver: &dyn Resolver, category: &str) -> PageModel { } let name = category.to_title_case(); + let kind = match category { + "symbols" => "Modules", + _ => "Functions", + }; + PageModel { route, title: name.clone(), description: format!("Documentation for functions related to {name} in Typst."), part: None, + outline: category_outline(kind), body: BodyModel::Category(CategoryModel { name, details: Html::markdown(resolver, details(category)), - kind: match category { - "symbols" => "Modules", - _ => "Functions", - }, + kind, items, }), children, } } +/// Produce an outline for a category page. +fn category_outline(kind: &str) -> Vec<OutlineItem> { + vec![ + OutlineItem { + id: "summary".into(), + name: "Summary".into(), + children: vec![], + }, + OutlineItem { + id: urlify(kind), + name: kind.into(), + children: vec![], + }, + ] +} + /// Details about a function. #[derive(Debug, Serialize)] pub struct FuncModel { - pub name: &'static str, + pub path: Vec<&'static str>, pub display: &'static str, pub oneliner: &'static str, pub element: bool, @@ -310,12 +365,14 @@ pub struct FuncModel { pub params: Vec<ParamModel>, pub returns: Vec<&'static str>, pub methods: Vec<MethodModel>, + pub scope: Vec<Self>, } /// Details about a group of functions. #[derive(Debug, Serialize)] pub struct FuncsModel { pub name: String, + pub display: String, pub details: Html, pub functions: Vec<FuncModel>, } @@ -326,33 +383,105 @@ fn function_page( parent: &str, func: &Func, info: &FuncInfo, + parents: &[&'static str], ) -> PageModel { + let model = func_model(resolver, func, info, parents, ""); PageModel { route: format!("{parent}{}/", urlify(info.name)), title: info.display.to_string(), description: format!("Documentation for the `{}` function.", info.name), part: None, - body: BodyModel::Func(func_model(resolver, func, info)), + outline: func_outline(&model, "", true), + body: BodyModel::Func(model), children: vec![], } } /// Produce a function's model. -fn func_model(resolver: &dyn Resolver, func: &Func, info: &FuncInfo) -> FuncModel { +fn func_model( + resolver: &dyn Resolver, + func: &Func, + info: &FuncInfo, + parents: &[&'static str], + id_base: &str, +) -> FuncModel { let mut s = unscanny::Scanner::new(info.docs); let docs = s.eat_until("\n## Methods").trim(); + + let mut path = parents.to_vec(); + let mut name = info.name; + for parent in parents.iter().rev() { + name = name + .strip_prefix(parent) + .or(name.strip_prefix(parent.strip_suffix('s').unwrap_or(parent))) + .unwrap_or(name); + } + path.push(name); + + let scope = info + .scope + .iter() + .filter_map(|(_, value)| { + let Value::Func(func) = value else { return None }; + let info = func.info().unwrap(); + Some(func_model(resolver, func, info, &path, id_base)) + }) + .collect(); + FuncModel { - name: info.name, + path, display: info.display, oneliner: oneliner(docs), element: func.element().is_some(), - details: Html::markdown(resolver, docs), + details: Html::markdown_with_id_base(resolver, docs, id_base), params: info.params.iter().map(|param| param_model(resolver, param)).collect(), returns: info.returns.clone(), methods: method_models(resolver, info.docs), + scope, } } +/// Produce an outline for a function page. +fn func_outline(model: &FuncModel, base: &str, summary: bool) -> Vec<OutlineItem> { + let mut outline = vec![]; + + if summary { + outline.push(OutlineItem { + id: "summary".into(), + name: "Summary".into(), + children: vec![], + }); + } + + outline.extend(model.details.outline()); + + if !model.params.is_empty() { + let join = if base.is_empty() { "" } else { "-" }; + outline.push(OutlineItem { + id: format!("{base}{join}parameters"), + name: "Parameters".into(), + children: model + .params + .iter() + .map(|param| OutlineItem { + id: format!("{base}{join}parameters-{}", urlify(param.name)), + name: param.name.into(), + children: vec![], + }) + .collect(), + }); + } + + for func in &model.scope { + let id = urlify(&func.path.join("-")); + let children = func_outline(func, &id, false); + outline.push(OutlineItem { id, name: func.display.into(), children }) + } + + outline.extend(methods_outline(&model.methods)); + outline +} + /// Details about a function parameter. #[derive(Debug, Serialize)] pub struct ParamModel { @@ -469,6 +598,7 @@ fn types_page(resolver: &dyn Resolver, parent: &str) -> PageModel { title: model.name.to_title_case(), description: format!("Documentation for the `{}` type.", model.name), part: None, + outline: type_outline(&model), body: BodyModel::Type(model), children: vec![], }); @@ -479,6 +609,7 @@ fn types_page(resolver: &dyn Resolver, parent: &str) -> PageModel { title: "Types".into(), description: "Documentation for Typst's built-in types.".into(), part: None, + outline: category_outline("Types"), body: BodyModel::Category(CategoryModel { name: "Types".into(), details: Html::markdown(resolver, details("types")), @@ -604,6 +735,48 @@ fn method_model(resolver: &dyn Resolver, part: &'static str) -> MethodModel { } } +/// Produce an outline for a type page. +fn type_outline(model: &TypeModel) -> Vec<OutlineItem> { + let mut outline = vec![OutlineItem { + id: "summary".into(), + name: "Summary".into(), + children: vec![], + }]; + + outline.extend(methods_outline(&model.methods)); + outline +} + +/// Produce an outline for a type's method. +fn methods_outline(methods: &[MethodModel]) -> Option<OutlineItem> { + (!methods.is_empty()).then(|| OutlineItem { + id: "methods".into(), + name: "Methods".into(), + children: methods.iter().map(method_outline).collect(), + }) +} + +/// Produce an outline for a type's method. +fn method_outline(model: &MethodModel) -> OutlineItem { + OutlineItem { + id: format!("methods-{}", urlify(model.name)), + name: model.name.into(), + children: model + .params + .iter() + .map(|param| OutlineItem { + id: format!( + "methods-{}-parameters-{}", + urlify(model.name), + urlify(param.name) + ), + name: param.name.into(), + children: vec![], + }) + .collect(), + } +} + /// A collection of symbols. #[derive(Debug, Serialize)] pub struct SymbolsModel { @@ -671,6 +844,7 @@ fn symbol_page(resolver: &dyn Resolver, parent: &str, name: &str) -> PageModel { title: title.into(), description: format!("Documentation for the `{name}` module."), part: None, + outline: vec![], body: BodyModel::Symbols(SymbolsModel { name: title, details: Html::markdown(resolver, details(name)), @@ -684,7 +858,7 @@ fn symbol_page(resolver: &dyn Resolver, parent: &str, name: &str) -> PageModel { #[derive(Debug, Deserialize)] struct GroupData { name: String, - title: String, + display: String, functions: Vec<String>, description: String, } |
