about summary refs log tree commit diff
diff options
context:
space:
mode:
-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>");
+}