Merge "Allow navar.md to enable Markdown extensions"
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/doc/DocServlet.java b/gitiles-servlet/src/main/java/com/google/gitiles/doc/DocServlet.java
index 78d1cf8..001b3b2 100644
--- a/gitiles-servlet/src/main/java/com/google/gitiles/doc/DocServlet.java
+++ b/gitiles-servlet/src/main/java/com/google/gitiles/doc/DocServlet.java
@@ -129,8 +129,9 @@
.setRequestUri(req.getRequestURI())
.setReader(reader)
.setRootTree(root);
+ Navbar navbar = createNavbar(cfg, fmt, navmd);
res.setHeader(HttpHeaders.ETAG, curEtag);
- showDoc(req, res, view, cfg, fmt, navmd, srcmd);
+ showDoc(req, res, view, fmt, navbar, srcmd);
}
}
@@ -161,14 +162,14 @@
HttpServletRequest req,
HttpServletResponse res,
GitilesView view,
- MarkdownConfig cfg,
MarkdownToHtml.Builder fmt,
- MarkdownFile navFile,
+ Navbar navbar,
MarkdownFile srcFile)
throws IOException {
Map<String, Object> data = new HashMap<>();
- data.putAll(buildNavbar(cfg, fmt, navFile));
+ data.putAll(navbar.toSoyData());
+ MarkdownConfig cfg = navbar.getConfig();
Node doc = GitilesMarkdown.parse(cfg, srcFile.consumeContent());
data.put("pageTitle", pageTitle(doc, srcFile));
if (view.getType() != GitilesView.Type.ROOTED_DOC) {
@@ -182,7 +183,10 @@
try (OutputStream out = startRenderCompressedStreamingHtml(req, res, SOY_TEMPLATE, data)) {
Writer w = newWriter(out, res);
- fmt.setFilePath(srcFile.path).build().renderToHtml(new StreamHtmlBuilder(w), doc);
+ fmt.setConfig(cfg)
+ .setFilePath(srcFile.path)
+ .build()
+ .renderToHtml(new StreamHtmlBuilder(w), doc);
w.flush();
} catch (RuntimeIOException e) {
Throwables.throwIfInstanceOf(e.getCause(), IOException.class);
@@ -190,14 +194,15 @@
}
}
- private Map<String, Object> buildNavbar(
- MarkdownConfig cfg, MarkdownToHtml.Builder fmt, MarkdownFile navFile) {
- Navbar navbar = new Navbar();
+ private static Navbar createNavbar(
+ MarkdownConfig cfg, MarkdownToHtml.Builder fmt, @Nullable MarkdownFile navFile) {
+ Navbar navbar = new Navbar().setConfig(cfg);
if (navFile != null) {
- navbar.setFormatter(fmt.setFilePath(navFile.path).build());
- navbar.setMarkdown(cfg, navFile.consumeContent());
+ navbar
+ .setFormatter(fmt.setFilePath(navFile.path).build())
+ .setMarkdown(navFile.consumeContent());
}
- return navbar.toSoyData();
+ return navbar;
}
private static String pageTitle(Node doc, MarkdownFile srcFile) {
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownConfig.java b/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownConfig.java
index 1982e5a..b4add94 100644
--- a/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownConfig.java
+++ b/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownConfig.java
@@ -16,6 +16,7 @@
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
+import java.util.Set;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Config.SectionParser;
import org.eclipse.jgit.util.StringUtils;
@@ -85,6 +86,31 @@
}
}
+ private MarkdownConfig(MarkdownConfig p, Set<String> enable, Set<String> disable) {
+ render = p.render;
+ inputLimit = p.inputLimit;
+ imageLimit = p.imageLimit;
+ analyticsId = p.analyticsId;
+
+ autoLink = on("autolink", p.autoLink, enable, disable);
+ blockNote = on("blocknote", p.blockNote, enable, disable);
+ ghThematicBreak = on("ghthematicbreak", p.ghThematicBreak, enable, disable);
+ multiColumn = on("multicolumn", p.multiColumn, enable, disable);
+ namedAnchor = on("namedanchor", p.namedAnchor, enable, disable);
+ safeHtml = on("safehtml", p.safeHtml, enable, disable);
+ smartQuote = on("smartquote", p.smartQuote, enable, disable);
+ strikethrough = on("strikethrough", p.strikethrough, enable, disable);
+ tables = on("tables", p.tables, enable, disable);
+ toc = on("toc", p.toc, enable, disable);
+
+ allowAnyIFrame = safeHtml ? p.allowAnyIFrame : false;
+ allowIFrame = safeHtml ? p.allowIFrame : ImmutableList.of();
+ }
+
+ private static boolean on(String key, boolean val, Set<String> enable, Set<String> disable) {
+ return enable.contains(key) ? true : disable.contains(key) ? false : val;
+ }
+
boolean isIFrameAllowed(String src) {
if (allowAnyIFrame) {
return true;
@@ -96,4 +122,8 @@
}
return false;
}
+
+ MarkdownConfig copyWithExtensions(Set<String> enable, Set<String> disable) {
+ return new MarkdownConfig(this, enable, disable);
+ }
}
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/doc/Navbar.java b/gitiles-servlet/src/main/java/com/google/gitiles/doc/Navbar.java
index a4581f1..a0f05bb 100644
--- a/gitiles-servlet/src/main/java/com/google/gitiles/doc/Navbar.java
+++ b/gitiles-servlet/src/main/java/com/google/gitiles/doc/Navbar.java
@@ -14,21 +14,27 @@
package com.google.gitiles.doc;
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Splitter;
import com.google.gitiles.doc.html.HtmlBuilder;
import com.google.template.soy.shared.restricted.EscapingConventions.FilterImageDataUri;
import com.google.template.soy.shared.restricted.Sanitizers;
import java.util.HashMap;
import java.util.Map;
+import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import static java.util.stream.Collectors.toSet;
import org.commonmark.node.Heading;
import org.commonmark.node.Node;
import org.eclipse.jgit.util.RawParseUtils;
class Navbar {
- private static final Pattern REF_LINK =
- Pattern.compile("^\\[(logo|home)\\]:\\s*(.+)$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE);
+ private static final Pattern META_LINK =
+ Pattern.compile(
+ "^\\[(logo|home|extensions)\\]:\\s*(.+)$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE);
+ private MarkdownConfig cfg;
private MarkdownToHtml fmt;
private Node node;
private String siteTitle;
@@ -37,14 +43,23 @@
Navbar() {}
+ MarkdownConfig getConfig() {
+ return cfg;
+ }
+
+ Navbar setConfig(MarkdownConfig cfg) {
+ this.cfg = cfg;
+ return this;
+ }
+
Navbar setFormatter(MarkdownToHtml html) {
this.fmt = html;
return this;
}
- Navbar setMarkdown(MarkdownConfig cfg, byte[] md) {
+ Navbar setMarkdown(byte[] md) {
if (md != null && md.length > 0) {
- parse(cfg, RawParseUtils.decode(md));
+ parse(RawParseUtils.decode(md));
}
return this;
}
@@ -73,11 +88,10 @@
}
}
- private void parse(MarkdownConfig cfg, String markdown) {
+ private void parse(String markdown) {
+ extractMetadata(markdown);
node = GitilesMarkdown.parse(cfg, markdown);
-
extractSiteTitle();
- extractRefLinks(markdown);
}
private void extractSiteTitle() {
@@ -93,8 +107,8 @@
}
}
- private void extractRefLinks(String markdown) {
- Matcher m = REF_LINK.matcher(markdown);
+ private void extractMetadata(String markdown) {
+ Matcher m = META_LINK.matcher(markdown);
while (m.find()) {
String key = m.group(1).toLowerCase();
String url = m.group(2).trim();
@@ -105,7 +119,29 @@
case "home":
homeUrl = url;
break;
+ case "extensions":
+ Set<String> names = splitExtensionNames(url);
+ cfg = cfg.copyWithExtensions(enabled(names), disabled(names));
+ break;
}
}
}
+
+ private static Set<String> splitExtensionNames(String url) {
+ return Splitter.on(CharMatcher.whitespace().or(CharMatcher.is(',')))
+ .trimResults()
+ .omitEmptyStrings()
+ .splitToList(url)
+ .stream()
+ .map(String::toLowerCase)
+ .collect(toSet());
+ }
+
+ private static Set<String> enabled(Set<String> names) {
+ return names.stream().filter(n -> !n.startsWith("!")).collect(toSet());
+ }
+
+ private static Set<String> disabled(Set<String> names) {
+ return names.stream().filter(n -> n.startsWith("!")).map(n -> n.substring(1)).collect(toSet());
+ }
}
diff --git a/navbar.md b/navbar.md
index 608531c..9f8ac26 100644
--- a/navbar.md
+++ b/navbar.md
@@ -2,3 +2,5 @@
* [Markdown](/Documentation/markdown.md)
* [Configuration](/Documentation/config.md)
* [Developers](/Documentation/developer-guide.md)
+
+[extensions]: blocknote, multicolumn, namedanchor, smartquote, toc