about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2021-04-30T21·59+0200
committertazjin <mail@tazj.in>2021-05-04T15·50+0000
commita9902dadcf080991c587a69e066a8b77b7b1cb94 (patch)
treee65243722bf5bfc77e5ea72223004cc4933419a4
parent57502cfc4674a66e1967c673668bc7dea0af2ff6 (diff)
feat(cheddar): Implement highlighting of CL and bug shortlinks r/2565
Implements highlighting of shortlinks like cl/123, or b/123.

Highlighting works by replacing the input Markdown using a simple
regular expression replacement.

We also considered parsing and replacing these links in the Markdown
AST, but it would have been significantly more complex (due to arena
allocation) for little upside and no obvious performance benefit.

Change-Id: I53f03fb17491046d89d0b7f605929571c11ee9a8
Reviewed-on: https://cl.tvl.fyi/c/depot/+/3082
Tested-by: BuildkiteCI
Reviewed-by: eta <eta@theta.eu.org>
-rw-r--r--tools/cheddar/Cargo.lock1
-rw-r--r--tools/cheddar/Cargo.toml1
-rw-r--r--tools/cheddar/src/lib.rs16
-rw-r--r--tools/cheddar/src/tests.rs34
4 files changed, 51 insertions, 1 deletions
diff --git a/tools/cheddar/Cargo.lock b/tools/cheddar/Cargo.lock
index 09b9ff6e85d8..bc6af6ff4b82 100644
--- a/tools/cheddar/Cargo.lock
+++ b/tools/cheddar/Cargo.lock
@@ -196,6 +196,7 @@ dependencies = [
  "clap",
  "comrak",
  "lazy_static",
+ "regex",
  "rouille",
  "serde",
  "serde_json",
diff --git a/tools/cheddar/Cargo.toml b/tools/cheddar/Cargo.toml
index ae33197cacdc..6cc8163c730a 100644
--- a/tools/cheddar/Cargo.toml
+++ b/tools/cheddar/Cargo.toml
@@ -11,6 +11,7 @@ lazy_static = "1.4"
 rouille = "3.0"
 syntect = "4.5.0"
 serde_json = "1.0"
+regex = "1.4"
 
 [dependencies.serde]
 version = "1.0"
diff --git a/tools/cheddar/src/lib.rs b/tools/cheddar/src/lib.rs
index 5e88aaaf61f8..441af1f6e95d 100644
--- a/tools/cheddar/src/lib.rs
+++ b/tools/cheddar/src/lib.rs
@@ -5,6 +5,7 @@ use comrak::arena_tree::Node;
 use comrak::nodes::{Ast, AstNode, NodeCodeBlock, NodeHtmlBlock, NodeValue};
 use comrak::{format_html, parse_document, Arena, ComrakOptions};
 use lazy_static::lazy_static;
+use regex::Regex;
 use std::cell::RefCell;
 use std::collections::HashMap;
 use std::env;
@@ -68,6 +69,13 @@ lazy_static! {
         map.insert("rules.pl", "Prolog");
         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();
 }
 
 // HTML fragment used when rendering inline blocks in Markdown documents.
@@ -172,6 +180,12 @@ 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 format_callout_paragraph(callout: Callout) -> NodeValue {
     let class = match callout {
         Callout::Todo => "cheddar-todo",
@@ -195,7 +209,7 @@ pub fn format_markdown<R: BufRead, W: Write>(reader: &mut R, writer: &mut W) {
     };
 
     let arena = Arena::new();
-    let root = parse_document(&arena, &document, &MD_OPTS);
+    let root = parse_document(&arena, &linkify_shortlinks(&document), &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
diff --git a/tools/cheddar/src/tests.rs b/tools/cheddar/src/tests.rs
index 8b8219b22d7c..5b7b1cc52a95 100644
--- a/tools/cheddar/src/tests.rs
+++ b/tools/cheddar/src/tests.rs
@@ -61,3 +61,37 @@ toString 42
 "#,
     );
 }
+
+#[test]
+fn highlights_bug_link() {
+    expect_markdown(
+        "Please look at b/123.",
+        "<p>Please look at <a href=\"https://b.tvl.fyi/123\">b/123</a>.</p>",
+    );
+}
+
+#[test]
+fn highlights_cl_link() {
+    expect_markdown(
+        "Please look at cl/420.",
+        "<p>Please look at <a href=\"https://cl.tvl.fyi/420\">cl/420</a>.</p>",
+    );
+}
+
+#[test]
+fn highlights_multiple_shortlinks() {
+    expect_markdown(
+        "Please look at cl/420, b/123.",
+        "<p>Please look at <a href=\"https://cl.tvl.fyi/420\">cl/420</a>, <a href=\"https://b.tvl.fyi/123\">b/123</a>.</p>",
+    );
+
+    expect_markdown(
+        "b/213/cl/213 are different things",
+        "<p><a href=\"https://b.tvl.fyi/213\">b/213</a>/<a href=\"https://cl.tvl.fyi/213\">cl/213</a> are different things</p>",
+    );
+}
+
+#[test]
+fn ignores_invalid_shortlinks() {
+    expect_markdown("b/abc is not a real bug", "<p>b/abc is not a real bug</p>");
+}