Skip to content

Commit f485a31

Browse files
committed
Allow navar.md to enable Markdown extensions
A site's pages may require specific Gitiles extensions to Markdown. For example the Gitiles Markdown documentation uses its extensions to demo how those extensions are formatted. Use a named link in navbar.md as metadata to activate extensions that may have been disabled by the site's configuration, e.g.: [home]: / [logo]: /images/logo.png [extensions]: blocknote, multicolumn Change-Id: Id43e5d103bbd6b31ebfcb2565c0600d45075bc16
1 parent db394cc commit f485a31

File tree

4 files changed

+93
-20
lines changed

4 files changed

+93
-20
lines changed

gitiles-servlet/src/main/java/com/google/gitiles/doc/DocServlet.java

+16-11
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,9 @@ protected void doGetHtml(HttpServletRequest req, HttpServletResponse res) throws
129129
.setRequestUri(req.getRequestURI())
130130
.setReader(reader)
131131
.setRootTree(root);
132+
Navbar navbar = createNavbar(cfg, fmt, navmd);
132133
res.setHeader(HttpHeaders.ETAG, curEtag);
133-
showDoc(req, res, view, cfg, fmt, navmd, srcmd);
134+
showDoc(req, res, view, fmt, navbar, srcmd);
134135
}
135136
}
136137

@@ -161,14 +162,14 @@ private void showDoc(
161162
HttpServletRequest req,
162163
HttpServletResponse res,
163164
GitilesView view,
164-
MarkdownConfig cfg,
165165
MarkdownToHtml.Builder fmt,
166-
MarkdownFile navFile,
166+
Navbar navbar,
167167
MarkdownFile srcFile)
168168
throws IOException {
169169
Map<String, Object> data = new HashMap<>();
170-
data.putAll(buildNavbar(cfg, fmt, navFile));
170+
data.putAll(navbar.toSoyData());
171171

172+
MarkdownConfig cfg = navbar.getConfig();
172173
Node doc = GitilesMarkdown.parse(cfg, srcFile.consumeContent());
173174
data.put("pageTitle", pageTitle(doc, srcFile));
174175
if (view.getType() != GitilesView.Type.ROOTED_DOC) {
@@ -182,22 +183,26 @@ private void showDoc(
182183

183184
try (OutputStream out = startRenderCompressedStreamingHtml(req, res, SOY_TEMPLATE, data)) {
184185
Writer w = newWriter(out, res);
185-
fmt.setFilePath(srcFile.path).build().renderToHtml(new StreamHtmlBuilder(w), doc);
186+
fmt.setConfig(cfg)
187+
.setFilePath(srcFile.path)
188+
.build()
189+
.renderToHtml(new StreamHtmlBuilder(w), doc);
186190
w.flush();
187191
} catch (RuntimeIOException e) {
188192
Throwables.throwIfInstanceOf(e.getCause(), IOException.class);
189193
throw e;
190194
}
191195
}
192196

193-
private Map<String, Object> buildNavbar(
194-
MarkdownConfig cfg, MarkdownToHtml.Builder fmt, MarkdownFile navFile) {
195-
Navbar navbar = new Navbar();
197+
private static Navbar createNavbar(
198+
MarkdownConfig cfg, MarkdownToHtml.Builder fmt, @Nullable MarkdownFile navFile) {
199+
Navbar navbar = new Navbar().setConfig(cfg);
196200
if (navFile != null) {
197-
navbar.setFormatter(fmt.setFilePath(navFile.path).build());
198-
navbar.setMarkdown(cfg, navFile.consumeContent());
201+
navbar
202+
.setFormatter(fmt.setFilePath(navFile.path).build())
203+
.setMarkdown(navFile.consumeContent());
199204
}
200-
return navbar.toSoyData();
205+
return navbar;
201206
}
202207

203208
private static String pageTitle(Node doc, MarkdownFile srcFile) {

gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownConfig.java

+30
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import com.google.common.base.Strings;
1818
import com.google.common.collect.ImmutableList;
19+
import java.util.Set;
1920
import org.eclipse.jgit.lib.Config;
2021
import org.eclipse.jgit.lib.Config.SectionParser;
2122
import org.eclipse.jgit.util.StringUtils;
@@ -85,6 +86,31 @@ public MarkdownConfig parse(Config cfg) {
8586
}
8687
}
8788

89+
private MarkdownConfig(MarkdownConfig p, Set<String> enable, Set<String> disable) {
90+
render = p.render;
91+
inputLimit = p.inputLimit;
92+
imageLimit = p.imageLimit;
93+
analyticsId = p.analyticsId;
94+
95+
autoLink = on("autolink", p.autoLink, enable, disable);
96+
blockNote = on("blocknote", p.blockNote, enable, disable);
97+
ghThematicBreak = on("ghthematicbreak", p.ghThematicBreak, enable, disable);
98+
multiColumn = on("multicolumn", p.multiColumn, enable, disable);
99+
namedAnchor = on("namedanchor", p.namedAnchor, enable, disable);
100+
safeHtml = on("safehtml", p.safeHtml, enable, disable);
101+
smartQuote = on("smartquote", p.smartQuote, enable, disable);
102+
strikethrough = on("strikethrough", p.strikethrough, enable, disable);
103+
tables = on("tables", p.tables, enable, disable);
104+
toc = on("toc", p.toc, enable, disable);
105+
106+
allowAnyIFrame = safeHtml ? p.allowAnyIFrame : false;
107+
allowIFrame = safeHtml ? p.allowIFrame : ImmutableList.of();
108+
}
109+
110+
private static boolean on(String key, boolean val, Set<String> enable, Set<String> disable) {
111+
return enable.contains(key) ? true : disable.contains(key) ? false : val;
112+
}
113+
88114
boolean isIFrameAllowed(String src) {
89115
if (allowAnyIFrame) {
90116
return true;
@@ -96,4 +122,8 @@ boolean isIFrameAllowed(String src) {
96122
}
97123
return false;
98124
}
125+
126+
MarkdownConfig copyWithExtensions(Set<String> enable, Set<String> disable) {
127+
return new MarkdownConfig(this, enable, disable);
128+
}
99129
}

gitiles-servlet/src/main/java/com/google/gitiles/doc/Navbar.java

+45-9
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,27 @@
1414

1515
package com.google.gitiles.doc;
1616

17+
import com.google.common.base.CharMatcher;
18+
import com.google.common.base.Splitter;
1719
import com.google.gitiles.doc.html.HtmlBuilder;
1820
import com.google.template.soy.shared.restricted.EscapingConventions.FilterImageDataUri;
1921
import com.google.template.soy.shared.restricted.Sanitizers;
2022
import java.util.HashMap;
2123
import java.util.Map;
24+
import java.util.Set;
2225
import java.util.regex.Matcher;
2326
import java.util.regex.Pattern;
27+
import static java.util.stream.Collectors.toSet;
2428
import org.commonmark.node.Heading;
2529
import org.commonmark.node.Node;
2630
import org.eclipse.jgit.util.RawParseUtils;
2731

2832
class Navbar {
29-
private static final Pattern REF_LINK =
30-
Pattern.compile("^\\[(logo|home)\\]:\\s*(.+)$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE);
33+
private static final Pattern META_LINK =
34+
Pattern.compile(
35+
"^\\[(logo|home|extensions)\\]:\\s*(.+)$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE);
3136

37+
private MarkdownConfig cfg;
3238
private MarkdownToHtml fmt;
3339
private Node node;
3440
private String siteTitle;
@@ -37,14 +43,23 @@ class Navbar {
3743

3844
Navbar() {}
3945

46+
MarkdownConfig getConfig() {
47+
return cfg;
48+
}
49+
50+
Navbar setConfig(MarkdownConfig cfg) {
51+
this.cfg = cfg;
52+
return this;
53+
}
54+
4055
Navbar setFormatter(MarkdownToHtml html) {
4156
this.fmt = html;
4257
return this;
4358
}
4459

45-
Navbar setMarkdown(MarkdownConfig cfg, byte[] md) {
60+
Navbar setMarkdown(byte[] md) {
4661
if (md != null && md.length > 0) {
47-
parse(cfg, RawParseUtils.decode(md));
62+
parse(RawParseUtils.decode(md));
4863
}
4964
return this;
5065
}
@@ -73,11 +88,10 @@ private Object logo() {
7388
}
7489
}
7590

76-
private void parse(MarkdownConfig cfg, String markdown) {
91+
private void parse(String markdown) {
92+
extractMetadata(markdown);
7793
node = GitilesMarkdown.parse(cfg, markdown);
78-
7994
extractSiteTitle();
80-
extractRefLinks(markdown);
8195
}
8296

8397
private void extractSiteTitle() {
@@ -93,8 +107,8 @@ private void extractSiteTitle() {
93107
}
94108
}
95109

96-
private void extractRefLinks(String markdown) {
97-
Matcher m = REF_LINK.matcher(markdown);
110+
private void extractMetadata(String markdown) {
111+
Matcher m = META_LINK.matcher(markdown);
98112
while (m.find()) {
99113
String key = m.group(1).toLowerCase();
100114
String url = m.group(2).trim();
@@ -105,7 +119,29 @@ private void extractRefLinks(String markdown) {
105119
case "home":
106120
homeUrl = url;
107121
break;
122+
case "extensions":
123+
Set<String> names = splitExtensionNames(url);
124+
cfg = cfg.copyWithExtensions(enabled(names), disabled(names));
125+
break;
108126
}
109127
}
110128
}
129+
130+
private static Set<String> splitExtensionNames(String url) {
131+
return Splitter.on(CharMatcher.whitespace().or(CharMatcher.is(',')))
132+
.trimResults()
133+
.omitEmptyStrings()
134+
.splitToList(url)
135+
.stream()
136+
.map(String::toLowerCase)
137+
.collect(toSet());
138+
}
139+
140+
private static Set<String> enabled(Set<String> names) {
141+
return names.stream().filter(n -> !n.startsWith("!")).collect(toSet());
142+
}
143+
144+
private static Set<String> disabled(Set<String> names) {
145+
return names.stream().filter(n -> n.startsWith("!")).map(n -> n.substring(1)).collect(toSet());
146+
}
111147
}

navbar.md

+2
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@
22
* [Markdown](/Documentation/markdown.md)
33
* [Configuration](/Documentation/config.md)
44
* [Developers](/Documentation/developer-guide.md)
5+
6+
[extensions]: blocknote, multicolumn, namedanchor, smartquote, toc

0 commit comments

Comments
 (0)