about summary refs log tree commit diff
path: root/tools
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2021-05-01T10·53+0200
committertazjin <mail@tazj.in>2021-09-10T11·32+0000
commit5e08f9b6c642e9d60a6e4589e2e280ed1122f9e0 (patch)
treeda5fe4d9d32dae0de811372c3354e627890b1a8b /tools
parent596344faf4c7f1cca8b1a7cd1da983270b81c530 (diff)
refactor(cheddar): Support multiple shortlinks & custom link sets r/2835
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 <lukegb@tvl.fyi>
Diffstat (limited to 'tools')
-rw-r--r--tools/cheddar/src/lib.rs52
1 files changed, 42 insertions, 10 deletions
diff --git a/tools/cheddar/src/lib.rs b/tools/cheddar/src/lib.rs
index 441af1f6e9..e5d7aad1e6 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(?P<type>b|cl)/(?P<dest>\\d+)\\b").unwrap();
+    // Default shortlink set used in cheddar (i.e. TVL's shortlinks)
+    static ref TVL_LINKS: Vec<Shortlink> = 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(?P<type>b|cl)/(?P<dest>\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<Ast>>) -> Option<Callout> {
 
 // 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<R: BufRead, W: Write>(reader: &mut R, writer: &mut W) {
+pub fn format_markdown_with_shortlinks<R: BufRead, W: Write>(
+    reader: &mut R,
+    writer: &mut W,
+    shortlinks: &[Shortlink],
+) {
     let document = {
         let mut buffer = String::new();
         reader
@@ -209,7 +237,7 @@ pub fn format_markdown<R: BufRead, W: Write>(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<R: BufRead, W: Write>(reader: &mut R, writer: &mut W) {
     format_html(root, &MD_OPTS, writer).expect("Markdown rendering failed");
 }
 
+pub fn format_markdown<R: BufRead, W: Write>(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)