From 5e08f9b6c642e9d60a6e4589e2e280ed1122f9e0 Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Sat, 1 May 2021 12:53:06 +0200 Subject: refactor(cheddar): Support multiple shortlinks & custom link sets This makes it possible for users of cheddar as a library to supply their own shortlinks. In practice it is unlikely anyone will do this, but the change also allows us to (relatively) easily add additional shortlinks to the set used by TVL. Note that Cheddar is primarily intended for use by TVL and the default rendering function interfaces have not changed, and will default to using TVL shortlinks. A new public function `format_markdown_with_shortlinks` has been added with which users can use an alternative set of shortlinks. This function should not be used in TVL depot code. Change-Id: I4ddab28cbcf45d07c51323b7b730b96e62922816 Reviewed-on: https://cl.tvl.fyi/c/depot/+/3083 Tested-by: BuildkiteCI Reviewed-by: lukegb --- tools/cheddar/src/lib.rs | 52 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/tools/cheddar/src/lib.rs b/tools/cheddar/src/lib.rs index 441af1f6e95d..e5d7aad1e62c 100644 --- a/tools/cheddar/src/lib.rs +++ b/tools/cheddar/src/lib.rs @@ -70,12 +70,29 @@ lazy_static! { map }; - // Supported shortlinks in Markdown files. - // - // Currently only bug links (e.g. b/123) and CL links (e.g. - // cl/345) are supported. Coincidentally these have the same - // format, which makes the initial implementation easy. - static ref SHORTLINK: Regex = Regex::new("\\b(?Pb|cl)/(?P\\d+)\\b").unwrap(); + // Default shortlink set used in cheddar (i.e. TVL's shortlinks) + static ref TVL_LINKS: Vec = vec![ + // TVL shortlinks for bugs and changelists (e.g. b/123, + // cl/123). Coincidentally these have the same format, which + // makes the initial implementation easy. + Shortlink { + pattern: Regex::new(r#"\b(?Pb|cl)/(?P\d+)\b"#).unwrap(), + replacement: "[$type/$dest](https://$type.tvl.fyi/$dest)", + } + ]; +} + +/// Structure that describes a single shortlink that should be +/// automatically highlighted. Highlighting is performed as a string +/// replacement over input Markdown. +pub struct Shortlink { + /// Short link pattern to recognise. Make sure to anchor these + /// correctly. + pub pattern: Regex, + + /// Replacement string, as per the documentation of + /// [`Regex::replace`]. + pub replacement: &'static str, } // HTML fragment used when rendering inline blocks in Markdown documents. @@ -182,8 +199,15 @@ fn has_callout<'a>(node: &Node<'a, RefCell>) -> Option { // Replace instances of known shortlinks in the input document with // Markdown syntax for a highlighted link. -fn linkify_shortlinks<'a>(input: &'a str) -> std::borrow::Cow<'a, str> { - SHORTLINK.replace_all(input, "[$type/$dest](https://$type.tvl.fyi/$dest)") +fn linkify_shortlinks(mut text: String, shortlinks: &[Shortlink]) -> String { + for link in shortlinks { + text = link + .pattern + .replace_all(&text, link.replacement) + .to_string(); + } + + return text; } fn format_callout_paragraph(callout: Callout) -> NodeValue { @@ -199,7 +223,11 @@ fn format_callout_paragraph(callout: Callout) -> NodeValue { NodeValue::HtmlBlock(block) } -pub fn format_markdown(reader: &mut R, writer: &mut W) { +pub fn format_markdown_with_shortlinks( + reader: &mut R, + writer: &mut W, + shortlinks: &[Shortlink], +) { let document = { let mut buffer = String::new(); reader @@ -209,7 +237,7 @@ pub fn format_markdown(reader: &mut R, writer: &mut W) { }; let arena = Arena::new(); - let root = parse_document(&arena, &linkify_shortlinks(&document), &MD_OPTS); + let root = parse_document(&arena, &linkify_shortlinks(document, shortlinks), &MD_OPTS); // This node must exist with a lifetime greater than that of the parsed AST // in case that callouts are encountered (otherwise insertion into the tree @@ -248,6 +276,10 @@ pub fn format_markdown(reader: &mut R, writer: &mut W) { format_html(root, &MD_OPTS, writer).expect("Markdown rendering failed"); } +pub fn format_markdown(reader: &mut R, writer: &mut W) { + format_markdown_with_shortlinks(reader, writer, &TVL_LINKS) +} + fn find_syntax_for_file(filename: &str) -> &'static SyntaxReference { (*FILENAME_OVERRIDES) .get(filename) -- cgit 1.4.1