Merge "Add IntelliJ project files to .gitignore"
diff --git a/Documentation/markdown.md b/Documentation/markdown.md
index 652d5ed..3e0f392 100644
--- a/Documentation/markdown.md
+++ b/Documentation/markdown.md
@@ -187,13 +187,6 @@
Note two tildes are required (`~~`) on either side of the struck out
section of text.
-### Smart quotes
-
-'Single' and "double" quotes in paragraph text are
-replaced with smart quotes. Apostrophes (this doc's text), ellipses
-("...") and dashes ("--" and "---") are also replaced with HTML
-entities to make the documentation appear typeset.
-
### Blockquotes
Blockquoted text can be used to stand off text obtained from
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/doc/BlockNoteExtension.java b/gitiles-servlet/src/main/java/com/google/gitiles/doc/BlockNoteExtension.java
index 7c18d60..3ae747d 100644
--- a/gitiles-servlet/src/main/java/com/google/gitiles/doc/BlockNoteExtension.java
+++ b/gitiles-servlet/src/main/java/com/google/gitiles/doc/BlockNoteExtension.java
@@ -51,10 +51,12 @@
}
private static class NoteParser extends AbstractBlockParser {
+ private final int indent;
private final BlockNote block;
private boolean done;
- NoteParser(String style) {
+ NoteParser(int indent, String style) {
+ this.indent = indent;
block = new BlockNote();
block.setClassName(style);
}
@@ -69,7 +71,7 @@
if (done) {
return BlockContinue.none();
}
- if (state.getIndent() == 0) {
+ if (state.getIndent() <= indent) {
int s = state.getNextNonSpaceIndex();
CharSequence line = state.getLine();
if ("***".contentEquals(line.subSequence(s, line.length()))) {
@@ -94,23 +96,19 @@
private static class NoteParserFactory extends AbstractBlockParserFactory {
@Override
public BlockStart tryStart(ParserState state, MatchedBlockParser matched) {
- if (state.getIndent() > 0) {
- return BlockStart.none();
- }
-
int s = state.getNextNonSpaceIndex();
CharSequence line = state.getLine();
CharSequence text = line.subSequence(s, line.length());
- if (text.length() < 4 || !"*** ".contentEquals(text.subSequence(0, 4))) {
+ if (text.length() < 3 || !"***".contentEquals(text.subSequence(0, 3))) {
return BlockStart.none();
}
- String style = text.subSequence(4, text.length()).toString().trim();
+ String style = text.subSequence(3, text.length()).toString().trim();
if (!VALID_STYLES.contains(style)) {
return BlockStart.none();
}
- return BlockStart.of(new NoteParser(style)).atIndex(line.length());
+ return BlockStart.of(new NoteParser(state.getIndent(), style)).atIndex(line.length());
}
}
}
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownToHtml.java b/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownToHtml.java
index 7a116c1..d5218e7 100644
--- a/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownToHtml.java
+++ b/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownToHtml.java
@@ -61,8 +61,6 @@
import org.eclipse.jgit.revwalk.RevTree;
import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
import javax.annotation.Nullable;
@@ -366,6 +364,11 @@
String href(String target) {
if (target.startsWith("#") || HtmlBuilder.isValidHttpUri(target)) {
return target;
+ } else if (target.startsWith("git:")) {
+ if (HtmlBuilder.isValidGitUri(target)) {
+ return target;
+ }
+ return FilterNormalizeUri.INSTANCE.getInnocuousOutput();
}
String anchor = "";
@@ -457,37 +460,9 @@
}
}
- private static final Pattern PRETTY = Pattern.compile("('|[.]{3}|-{2,3})");
-
@Override
public void visit(Text node) {
- String text = node.getLiteral();
- Matcher pretty = PRETTY.matcher(text);
- int i = 0;
- while (pretty.find()) {
- int s = pretty.start();
- if (i < s) {
- html.appendAndEscape(text.substring(i, s));
- }
- switch (pretty.group(0)) {
- case "'":
- html.entity("’");
- break;
- case "...":
- html.entity("…");
- break;
- case "--":
- html.entity("–");
- break;
- case "---":
- html.entity("—");
- break;
- }
- i = pretty.end();
- }
- if (i < text.length()) {
- html.appendAndEscape(text.substring(i));
- }
+ html.appendAndEscape(node.getLiteral());
}
@Override
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/doc/MultiColumnExtension.java b/gitiles-servlet/src/main/java/com/google/gitiles/doc/MultiColumnExtension.java
index ef53fe3..aeb3d89 100644
--- a/gitiles-servlet/src/main/java/com/google/gitiles/doc/MultiColumnExtension.java
+++ b/gitiles-servlet/src/main/java/com/google/gitiles/doc/MultiColumnExtension.java
@@ -46,7 +46,7 @@
@Override
public void extend(Parser.Builder builder) {
- builder.customBlockParserFactory(new DivParserFactory());
+ builder.customBlockParserFactory(new MultiColumnParserFactory());
}
private static class MultiColumnParser extends AbstractBlockParser {
@@ -151,7 +151,7 @@
}
}
- private static class DivParserFactory extends AbstractBlockParserFactory {
+ private static class MultiColumnParserFactory extends AbstractBlockParserFactory {
@Override
public BlockStart tryStart(ParserState state, MatchedBlockParser matched) {
if (state.getIndent() > 0) {
@@ -161,12 +161,13 @@
int s = state.getNextNonSpaceIndex();
CharSequence line = state.getLine();
CharSequence text = line.subSequence(s, line.length());
- if (text.length() >= MARKER.length()
- && MARKER.contentEquals(text.subSequence(0, MARKER.length()))) {
- String layout = text.subSequence(MARKER.length(), line.length()).toString().trim();
- return BlockStart.of(new MultiColumnParser(layout)).atIndex(line.length());
+ if (text.length() < MARKER.length()
+ || !MARKER.contentEquals(text.subSequence(0, MARKER.length()))) {
+ return BlockStart.none();
}
- return BlockStart.none();
+
+ String layout = text.subSequence(MARKER.length(), text.length()).toString().trim();
+ return BlockStart.of(new MultiColumnParser(layout)).atIndex(text.length());
}
}
}
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/doc/html/HtmlBuilder.java b/gitiles-servlet/src/main/java/com/google/gitiles/doc/html/HtmlBuilder.java
index 9639176..3239fe1 100644
--- a/gitiles-servlet/src/main/java/com/google/gitiles/doc/html/HtmlBuilder.java
+++ b/gitiles-servlet/src/main/java/com/google/gitiles/doc/html/HtmlBuilder.java
@@ -85,6 +85,17 @@
private static final FilterNormalizeUri URI = FilterNormalizeUri.INSTANCE;
private static final FilterImageDataUri IMAGE_DATA = FilterImageDataUri.INSTANCE;
+ private static final Pattern GIT_URI =
+ Pattern.compile(
+ "^"
+ +
+ // Reject paths containing /../ or ending in /..
+ "(?![^#?]*/(?:\\.|%2E){2}(?:[/?#]|\\z))"
+ +
+ // Accept git://host/path
+ "git://[^/]+/.+",
+ Pattern.CASE_INSENSITIVE);
+
public static boolean isValidCssDimension(String val) {
return val != null && val.matches("(?:[1-9][0-9]*px|100%|[1-9][0-9]?%)");
}
@@ -99,6 +110,10 @@
return IMAGE_DATA.getValueFilter().matcher(url).find();
}
+ public static boolean isValidGitUri(String val) {
+ return GIT_URI.matcher(val).find();
+ }
+
private final StringBuilder htmlBuf;
private final Appendable textBuf;
private String tag;
@@ -159,7 +174,7 @@
}
private String anchorHref(String val) {
- if (URI.getValueFilter().matcher(val).find()) {
+ if (URI.getValueFilter().matcher(val).find() || isValidGitUri(val)) {
return URI.escape(val);
}
return URI.getInnocuousOutput();
diff --git a/gitiles-servlet/src/test/java/com/google/gitiles/doc/DocServletTest.java b/gitiles-servlet/src/test/java/com/google/gitiles/doc/DocServletTest.java
index f73c331..25f3d7f 100644
--- a/gitiles-servlet/src/test/java/com/google/gitiles/doc/DocServletTest.java
+++ b/gitiles-servlet/src/test/java/com/google/gitiles/doc/DocServletTest.java
@@ -104,6 +104,20 @@
}
@Test
+ public void noteInList() throws Exception {
+ String markdown =
+ "+ one\n\n" + " ***aside\n" + " remember this\n" + " ***\n" + "\n" + "+ two\n";
+ repo.branch("master").commit().add("index.md", markdown).create();
+
+ String html = buildHtml("/repo/+/master/index.md");
+ System.out.println(html);
+ assertThat(html)
+ .contains(
+ "<ul><li><p>one</p><div class=\"aside\">remember this</div>"
+ + "</li><li><p>two</p></li></ul>");
+ }
+
+ @Test
public void relativeLink() throws Exception {
repo.branch("master").commit().add("A/B/README.md", "[c](../../C)").create();
@@ -118,4 +132,20 @@
String html = buildHtml("/repo/+doc/master/README.md");
assertThat(html).contains("<a href=\"/b/repo/+/master/x\">c</a>");
}
+
+ @Test
+ public void gitUrlLink() throws Exception {
+ repo.branch("master").commit().add("README.md", "[c](git://example.com/repo.git)").create();
+
+ String html = buildHtml("/repo/+doc/master/README.md");
+ assertThat(html).contains("<a href=\"git://example.com/repo.git\">c</a>");
+ }
+
+ @Test
+ public void invalidGitUrlLink() throws Exception {
+ repo.branch("master").commit().add("README.md", "[c](git://example.com/repo/..)").create();
+
+ String html = buildHtml("/repo/+doc/master/README.md");
+ assertThat(html).contains("<a href=\"#zSoyz\">c</a>");
+ }
}
diff --git a/gitiles-servlet/src/test/java/com/google/gitiles/doc/LinkTest.java b/gitiles-servlet/src/test/java/com/google/gitiles/doc/LinkTest.java
index fdffffc..ad9f941 100644
--- a/gitiles-servlet/src/test/java/com/google/gitiles/doc/LinkTest.java
+++ b/gitiles-servlet/src/test/java/com/google/gitiles/doc/LinkTest.java
@@ -63,6 +63,25 @@
}
@Test
+ public void gitLink() {
+ MarkdownToHtml md =
+ MarkdownToHtml.builder()
+ .setGitilesView(view)
+ .setConfig(new MarkdownConfig(config))
+ .setFilePath("index.md")
+ .build();
+ String url;
+
+ url = "git://example.com/repo.git";
+ assertThat(md.href(url)).isEqualTo(url);
+
+ assertThat(md.href("git:example.com/repo.git")).isEqualTo("#zSoyz");
+ assertThat(md.href("git://")).isEqualTo("#zSoyz");
+ assertThat(md.href("git://example.com/../root")).isEqualTo("#zSoyz");
+ assertThat(md.href("git://example.com/root/..")).isEqualTo("#zSoyz");
+ }
+
+ @Test
public void absolutePath() {
MarkdownToHtml md =
MarkdownToHtml.builder()