Skip to content

Commit 417ffba

Browse files
authored
Replace Pegdown with Commonmark (#366)
Pegdown is no longer maintained, which will cause problems when upgrading build pipeline to Java 17. Also it's nice to use an implemenntation of Markdown that is compatible with GH previews and IDE plugins -- commonmark seems to do quite well. Three differences had to be handled in this PR though: * code snippets are now delimited by backticks since indented snippets behaved differently in Pegdown and Commonmark. * Commonmark does not support typography replacements (-- to en-dash, --- to em-dash, quotes) out of the box, HTML entities can be used instead. * no support for special definition list MD extension (only used by DevGuideI18nMessages) -- rewritten to HTML tags Fixes #332
1 parent 4746df9 commit 417ffba

File tree

105 files changed

+3336
-3098
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

105 files changed

+3336
-3098
lines changed

pom.xml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,18 @@
131131
</dependency>
132132

133133
<dependency>
134-
<groupId>org.pegdown</groupId>
135-
<artifactId>pegdown</artifactId>
136-
<version>1.4.2</version>
134+
<groupId>org.commonmark</groupId>
135+
<artifactId>commonmark</artifactId>
136+
<!-- last version supporting Java 8 -->
137+
<version>0.21.0</version>
137138
</dependency>
138139

140+
<dependency>
141+
<groupId>org.commonmark</groupId>
142+
<artifactId>commonmark-ext-gfm-tables</artifactId>
143+
<!-- last version supporting Java 8 -->
144+
<version>0.21.0</version>
145+
</dependency>
139146
<dependency>
140147
<groupId>commons-io</groupId>
141148
<artifactId>commons-io</artifactId>

src/main/java/com/google/gwt/site/markdown/MDHelper.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515

1616
import java.io.File;
1717

18-
import org.pegdown.PegDownProcessor;
19-
2018
import com.google.gwt.site.markdown.fs.FileSystemTraverser;
2119
import com.google.gwt.site.markdown.fs.MDParent;
2220
import com.google.gwt.site.markdown.toc.TocCreator;
@@ -107,7 +105,7 @@ public MDHelper create() throws MDHelperException {
107105

108106
// read template TOC if parameter is provided
109107
if (templateTocFile != null) {
110-
templateToc = new PegDownProcessor().markdownToHtml(readFile(templateTocFile));
108+
templateToc = MDTranslater.markDownToHtml(readFile(templateTocFile));
111109
}
112110

113111
created = true;

src/main/java/com/google/gwt/site/markdown/MDTranslater.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,21 @@
1717
import com.google.gwt.site.markdown.fs.MDParent;
1818
import com.google.gwt.site.markdown.toc.TocCreator;
1919

20-
import org.apache.commons.io.FileUtils;
21-
import org.pegdown.Extensions;
22-
import org.pegdown.PegDownProcessor;
20+
import org.commonmark.Extension;
21+
import org.commonmark.ext.gfm.tables.TablesExtension;
22+
import org.commonmark.node.*;
23+
import org.commonmark.parser.Parser;
24+
import org.commonmark.renderer.html.HtmlRenderer;
2325

2426
import java.io.File;
2527
import java.io.IOException;
26-
import java.nio.file.FileSystem;
27-
import java.nio.file.FileSystems;
28+
import java.util.Collections;
2829
import java.util.List;
30+
import java.util.Set;
2931

3032
public class MDTranslater {
31-
private static final int PEG_DOWN_FLAGS = Extensions.SMARTYPANTS | Extensions.AUTOLINKS |
32-
Extensions.FENCED_CODE_BLOCKS | Extensions.TABLES | Extensions.DEFINITIONS;
3333
private static final String SEPARATOR = File.separator;
3434

35-
private PegDownProcessor pegDownProcessor = new PegDownProcessor(PEG_DOWN_FLAGS, Long
36-
.MAX_VALUE);
3735

3836
private final TocCreator tocCreator;
3937

@@ -63,7 +61,7 @@ private void renderTree(MDNode node, MDParent root) throws TranslaterException {
6361

6462
} else {
6563
String markDown = getNodeContent(node.getPath());
66-
String htmlMarkDown = pegDownProcessor.markdownToHtml(markDown);
64+
String htmlMarkDown = markDownToHtml(markDown);
6765

6866
String toc = tocCreator.createTocForNode(root, node);
6967

@@ -86,6 +84,15 @@ private void renderTree(MDNode node, MDParent root) throws TranslaterException {
8684

8785
}
8886

87+
protected static String markDownToHtml(String markDown) {
88+
Set<Extension> extensions = Collections.singleton(TablesExtension.create());
89+
Parser parser = Parser.builder()
90+
.extensions(extensions).build();
91+
Node document = parser.parse(markDown);
92+
HtmlRenderer renderer = HtmlRenderer.builder().extensions(extensions).build();
93+
return renderer.render(document);
94+
}
95+
8996
private String getEditUrl(String path) {
9097
// TODO you should support more than one template
9198
if (path.endsWith("markdown/index.md")) {

src/main/java/com/google/gwt/site/markdown/Util.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@
1919
import java.io.FileInputStream;
2020
import java.io.FileOutputStream;
2121
import java.io.IOException;
22+
import java.nio.charset.StandardCharsets;
2223

2324
public class Util {
2425
public static String getStringFromFile(File file) throws IOException {
2526
FileInputStream fileInputStream = null;
2627
try {
2728
fileInputStream = new FileInputStream(file);
28-
return IOUtils.toString(fileInputStream, "UTF-8");
29+
return IOUtils.toString(fileInputStream, StandardCharsets.UTF_8);
2930
} finally {
3031
IOUtils.closeQuietly(fileInputStream);
3132
}
@@ -35,7 +36,7 @@ public static void writeStringToFile(File file, String content) throws IOExcepti
3536
FileOutputStream fileOutputStream = null;
3637
try {
3738
fileOutputStream = new FileOutputStream(file);
38-
IOUtils.write(content, fileOutputStream);
39+
IOUtils.write(content, fileOutputStream, StandardCharsets.UTF_8);
3940
} finally {
4041
IOUtils.closeQuietly(fileOutputStream);
4142
}

src/main/java/com/google/gwt/site/markdown/toc/TocFromMdCreator.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,9 @@
1616
import com.google.gwt.site.markdown.fs.MDNode;
1717
import com.google.gwt.site.markdown.fs.MDParent;
1818

19+
import java.util.Arrays;
1920
import java.util.List;
2021

21-
import org.parboiled.common.StringUtils;
22-
2322
public class TocFromMdCreator implements TocCreator {
2423

2524
public String createTocForNode(MDParent root, MDNode node) {
@@ -49,17 +48,17 @@ private void render(MDNode node, StringBuffer buffer, MDNode tocNode) {
4948
}
5049

5150
// Use 4 spaces to indent <li>'s, so as we have room for indenting <ul>'s
52-
String margin = StringUtils.repeat(' ', 4 * node.getDepth());
51+
String margin = spaces(4 * node.getDepth());
5352

5453
if (node.isFolder()) {
5554
MDParent mdParent = node.asFolder();
5655

5756
if (node.getDepth() != 0) {
58-
buffer.append(margin + "<li class='folder'>");
57+
buffer.append(margin).append("<li class='folder'>");
5958
buffer.append("<a href='#'>");
6059
buffer.append(node.getDisplayName());
6160
buffer.append("</a>\n");
62-
buffer.append(margin + " <ul>\n");
61+
buffer.append(margin).append(" <ul>\n");
6362
}
6463

6564
List<MDNode> children = mdParent.getChildren();
@@ -68,8 +67,8 @@ private void render(MDNode node, StringBuffer buffer, MDNode tocNode) {
6867
}
6968

7069
if (node.getDepth() != 0) {
71-
buffer.append(margin + " </ul>\n");
72-
buffer.append(margin + "</li>\n");
70+
buffer.append(margin).append(" </ul>\n");
71+
buffer.append(margin).append("</li>\n");
7372
}
7473
} else {
7574
StringBuffer relativeUrl = new StringBuffer();
@@ -85,11 +84,19 @@ private void render(MDNode node, StringBuffer buffer, MDNode tocNode) {
8584

8685
relativeUrl.append(node.getRelativePath());
8786

88-
buffer.append(margin + "<li class='file'>");
87+
buffer.append(margin).append("<li class='file'>");
8988
// TODO escape HTML
90-
buffer.append("<a href='" + relativeUrl.toString() + "' ahref='" + absoluteUrl.toString()
91-
+ "' title='" + node.getDescription() + "'>" + node.getDisplayName() + "</a>");
89+
buffer.append("<a href='").append(relativeUrl)
90+
.append("' ahref='").append(absoluteUrl)
91+
.append("' title='").append(node.getDescription()).append("'>")
92+
.append(node.getDisplayName()).append("</a>");
9293
buffer.append("</li>\n");
9394
}
9495
}
96+
97+
private String spaces(int count) {
98+
final byte[] spaceBytes = new byte[count];
99+
Arrays.fill(spaceBytes, (byte) ' ');
100+
return new String(spaceBytes);
101+
}
95102
}

src/main/markdown/articles/dom_events_memory_leaks_and_you.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ You may ask yourself, "Why do I have to use bitfields to sink DOM events?", and
99

1010
If you're creating a widget from scratch (using DOM elements directly, as opposed to simply creating a composite widget), the setup for event handling generally looks something like this:
1111

12-
```
12+
```java
1313
class MyWidget extends Widget {
1414
public MyWidget() {
1515
setElement(DOM.createDiv());
@@ -35,7 +35,7 @@ The upshot of all this is that in some browsers, any reference cycle that involv
3535

3636
Imagine the following (raw JavaScript) example:
3737

38-
```
38+
```javascript
3939
function makeWidget() {
4040
var widget = {};
4141
widget.someVariable = "foo";
@@ -48,7 +48,7 @@ function makeWidget() {
4848

4949
Now, I'm not suggesting that you'd really build a JavaScript library quite this way, but it serves to illustrate the point. The reference cycle created here is:
5050

51-
```
51+
```text
5252
widget -> elem(native) -> closure -> widget
5353
5454
```
@@ -68,7 +68,7 @@ How do we enforce this? Each widget has a single "root" element. Whenever the wi
6868

6969
Which brings is back to that odd bitfield used in the sinkEvents() method. If you look at the implementation of [DOM.sinkEvents()](/javadoc/latest/com/google/gwt/user/client/DOM.html#sinkEvents-com.google.gwt.user.client.Element-int-), you'll see that it does something like this:
7070

71-
```
71+
```javascript
7272
elem.onclick = (bits & 0x00001) ? $wnd.__dispatchEvent : null;
7373

7474
```

src/main/markdown/articles/dynamic_host_page.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ service in the onModuleLoad() method of your EntryPoint class to check
2020
if the user is logged in. This initiates a GWT-RPC request as soon as
2121
the GWT module loads.
2222

23-
```
23+
```java
2424
public void onModuleLoad() {
2525
// loginService is a GWT-RPC service that checks if the user is logged in
2626
loginService.checkLoggedIn(new AsyncCallback<Boolean> {
@@ -41,7 +41,7 @@ Let's examine everything that happens here if the user isn't logged in:
4141
1. Your app is requested and your GWT host page (YourModule.html) is downloaded
4242
2. <var>module</var>.nocache.js is requested by the page and is downloaded
4343
3. <var>MD5</var>.cache.html is selected based on the browser and is downloaded
44-
4. Your module loads and makes a GWT-RPC call to check if the user is logged in -- since they're not, they are redirected to the login page
44+
4. Your module loads and makes a GWT-RPC call to check if the user is logged in &mdash; since they're not, they are redirected to the login page
4545
4646
That's up to **four** server requests (depending on what is cached)
4747
just to send your user to the login page. And step 3 consists of
@@ -70,7 +70,7 @@ for custom authentication schemes and the ability to vary the content of
7070
the host page based on the user. Here's an example of a simple host page
7171
written as a servlet:
7272
73-
```
73+
```java
7474
public class GwtHostingServlet extends HttpServlet {
7575
7676
@Override
@@ -99,7 +99,7 @@ The following example uses the App Engine
9999
user is logged in. Even if you're not using App Engine, you can imagine
100100
how the code would look slightly different in your servlet environment.
101101
102-
```
102+
```java
103103
// In GwtHostingServlet's doGet() method...
104104
PrintWriter writer = resp.getWriter();
105105
writer.append("<html><head>");
@@ -133,7 +133,7 @@ GWT module, then immediately making another request to get this data. A
133133
more efficient way is to write the initial data as a Javascript variable
134134
into the host page itself.
135135
136-
```
136+
```java
137137
// In GwtHostingServlet's doGet() method...
138138
writer.append("<html><head>");
139139
writer.append("<script type=\"text/javascript\" src=\"sample/sample.nocache.js\"></script>");
@@ -157,7 +157,7 @@ writer.append("</head><body>Hello, world!</body></html>");
157157

158158
Now your GWT code can access the data using JSNI, like so:
159159

160-
```
160+
```java
161161
public native String getEmail() /*-{
162162
return $wnd.info['email'];
163163
}-*/;
@@ -166,7 +166,7 @@ public native String getEmail() /*-{
166166
Alternatively, you can take advantage of GWT's
167167
[Dictionary](/javadoc/latest/com/google/gwt/i18n/client/Dictionary.html) class:
168168
169-
```
169+
```java
170170
public void onModuleLoad() {
171171
// Looks for a JS variable called "info" in the global scope
172172
Dictionary info = Dictionary.getDictionary("info");
@@ -182,7 +182,7 @@ worthwhile to consider using a templating language like JSP to make your
182182
code more readable. Here's our example as a JSP page instead of a
183183
servlet:
184184

185-
```
185+
```jsp
186186
<!-- gwt-hosting.jsp -->
187187
<html>
188188
<head>
@@ -212,7 +212,7 @@ servlet:
212212

213213
You can make this JSP page your welcome file by specifying it in your web.xml file:
214214

215-
```
215+
```xml
216216
<welcome-file-list>
217217
<welcome-file>gwt-hosting.jsp</welcome-file>
218218
</welcome-file-list>

src/main/markdown/articles/elemental.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Elemental uses Java interfaces to hide most of the generated overlay types it us
3333
can be obtained by the `Window` or `Document` interfaces. Here is a simple example to play a sound using
3434
the Web Audio API.
3535

36-
```
36+
```java
3737
package com.myapp;
3838
import elemental.client.*;
3939
import elemental.dom.*;

0 commit comments

Comments
 (0)