Skip to content

Commit

Permalink
Replace remark with flexmark-java
Browse files Browse the repository at this point in the history
Signed-off-by: Fred Bricon <fbricon@gmail.com>
  • Loading branch information
fbricon committed Nov 28, 2023
1 parent def27a7 commit b8bb3a4
Show file tree
Hide file tree
Showing 17 changed files with 106 additions and 83 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/pr-verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ jobs:
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Set up JDK 8
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '8'
java-version: '11'
distribution: 'temurin'
cache: 'maven'
- name: Run Tests
Expand Down
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@
"editor.tabSize": 4,
"editor.insertSpaces": false,
"java.compile.nullAnalysis.mode": "automatic",
"java.configuration.updateBuildConfiguration": "interactive",
}
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and can be used with any editor that supports the protocol, to offer good suppor
* [Eclipse LSP4J](https://github.com/eclipse/lsp4j), the Java binding for the Language Server Protocol.
* Xerces to manage XML Schema validation, completion and hover

**LemMinX** requires a Java 11+ JVM to run.

Features
--------------

Expand Down
24 changes: 20 additions & 4 deletions org.eclipse.lemminx/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -231,14 +231,30 @@
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>com.kotcrab.remark</groupId>
<artifactId>remark</artifactId>
<version>1.0.0</version>
<groupId>com.vladsch.flexmark</groupId>
<artifactId>flexmark-html2md-converter</artifactId>
<version>0.64.8</version>
<!-- for versions >= 0.64.0, Java 11 is required -->
<exclusions>
<exclusion>
<groupId>com.vladsch.flexmark</groupId>
<artifactId>flexmark-jira-converter</artifactId>
</exclusion>
<exclusion>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.10.0</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.14.2</version>
<version>1.17.1</version>
</dependency>
<dependency>
<groupId>xml-resolver</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,6 @@ private Node nodeByOffset(final int offset) throws BadLocationException {
if (node == null) {
fail(offset);
}

if (remaining < node.offset) {
node = node.left;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ public class ConfigurationItemEdit extends ConfigurationItem {
private Object value;
private ConfigurationItemEditType editType;
private ConfigurationItemValueKind valueKind;

public ConfigurationItemEdit () {
// Need explicit no-arg constructor for deserialization
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,9 @@ private static String removeFileScheme(String fileURI, boolean removeLastSlash)
* @return the given file Uri to a File.
*/
public static File toFile(String fileUri) {
String convertedUri = fileUri.replace("file:///", "file:/"); //$NON-NLS-1$//$NON-NLS-2$
convertedUri = convertedUri.replace("file://", "file:/"); //$NON-NLS-1$//$NON-NLS-2$
return new File(URI.create(convertedUri));
//String convertedUri = fileUri.replace("file:///", "file:/"); //$NON-NLS-1$//$NON-NLS-2$
//convertedUri = convertedUri.replace("file://", "file:/"); //$NON-NLS-1$//$NON-NLS-2$
return new File(URI.create(fileUri));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,15 @@
*******************************************************************************/
package org.eclipse.lemminx.utils;

import static org.apache.commons.lang3.StringEscapeUtils.unescapeJava;
import static org.apache.commons.lang3.StringEscapeUtils.unescapeXml;
import static org.apache.commons.text.StringEscapeUtils.unescapeJava;
import static org.apache.commons.text.StringEscapeUtils.unescapeXml;

import java.lang.reflect.Field;
import java.util.logging.Logger;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import com.overzealous.remark.Options;
import com.overzealous.remark.Options.FencedCodeBlocks;
import com.overzealous.remark.Options.Tables;
import com.overzealous.remark.Remark;

import org.jsoup.safety.Cleaner;
import org.jsoup.safety.Safelist;
import com.vladsch.flexmark.html2md.converter.FlexmarkHtmlConverter;

/**
* Converts HTML content into Markdown equivalent.
Expand All @@ -33,46 +29,60 @@
*/
public class MarkdownConverter {

private static final Logger LOGGER = Logger.getLogger(MarkdownConverter.class.getName());

private static Remark remark;
private static final FlexmarkHtmlConverter CONVERTER = FlexmarkHtmlConverter.builder().build();

private MarkdownConverter(){
//no public instanciation
private MarkdownConverter() {
// no public instanciation
}

static {
Options options = new Options();
options.tables = Tables.CONVERT_TO_CODE_BLOCK;
options.hardwraps = true;
options.inlineLinks = true;
options.autoLinks = true;
options.reverseHtmlSmartPunctuation = true;
options.fencedCodeBlocks = FencedCodeBlocks.ENABLED_BACKTICK;
remark = new Remark(options);
//Stop remark from stripping file protocol in an href
try {
Field cleanerField = Remark.class.getDeclaredField("cleaner");
cleanerField.setAccessible(true);

Cleaner c = (Cleaner) cleanerField.get(remark);

Field safelistField = Cleaner.class.getDeclaredField("safelist");
safelistField.setAccessible(true);

Safelist s = (Safelist) safelistField.get(c);
public static String convert(String html) {
if (!StringUtils.isTagOutsideOfBackticks(html)) {
return unescapeXml(html); // is not html so it can be returned as-is (aside from unescaping)
}

s.addProtocols("a", "href", "file");
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
LOGGER.severe("Unable to modify jsoup to include file protocols "+ e.getMessage());
Document document = Jsoup.parse(html);
//Add missing table headers if necessary, else most Markdown renderers will crap out
document.select("table").forEach(MarkdownConverter::addMissingTableHeaders);

String markdown = CONVERTER.convert(document);
if (markdown.endsWith("\n")) {// FlexmarkHtmlConverter keeps adding an extra line
markdown = markdown.substring(0, markdown.length() - 1);
}
return unescapeJava(markdown);
}

public static String convert(String html) {
if(!StringUtils.isTagOutsideOfBackticks(html)) {
return unescapeXml(html); // is not html so it can be returned as is (aside from unescaping)
/**
* Adds a new row header if the given table doesn't have any.
* @param table the HTML table to check for a header
*/
private static void addMissingTableHeaders(Element table) {
int numCols = 0;
for (Element child : table.children()) {
if ("thead".equals(child.nodeName())) {
// Table already has a header, nothing else to do
return;
}
if ("tbody".equals(child.nodeName())) {
Elements rows = child.getElementsByTag("tr");
if (!rows.isEmpty()) {
for (Element row : rows) {
int colSize = row.getElementsByTag("td").size();
//Keep the biggest column size
if (colSize > numCols) {
numCols = colSize;
}
}
}
}
}
if (numCols > 0) {
//Create a new header row based on the number of columns already found
Element newHeader = new Element("tr");
for (int i = 0; i < numCols; i++) {
newHeader.appendChild(new Element("th"));
}
//Insert header row in 1st position in the table
table.insertChildren(0, newHeader);
}
return unescapeJava(remark.convert(html));
}

}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
[
{
"name": "com.overzealous.remark.Remark",
"fields": [{
"name": "cleaner"
}]
"name": "java.lang.Object",
"allDeclaredMethods": true
},
{
"name": "java.lang.Object",
"name": "java.lang.Enum",
"allDeclaredMethods": true
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1327,8 +1327,8 @@ public static void assertDocumentLinks(List<DocumentLink> actual, DocumentLink..
assertEquals(expected.length, actual.size());
for (int i = 0; i < expected.length; i++) {
assertEquals(expected[i].getRange(), actual.get(i).getRange(), " Range test '" + i + "' link");
assertEquals(Paths.get(expected[i].getTarget()).toUri().toString().replace("file:///", "file:/"),
actual.get(i).getTarget().replace("file:///", "file:/"), " Target test '" + i + "' link");
assertEquals(Paths.get(expected[i].getTarget()).toUri().toString(),
actual.get(i).getTarget(), " Target test '" + i + "' link");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public void webXML() throws Exception {
"'" + cachedFilePath + "' file should be downloaded in the cache.");

// Process hover with the DTD (http dtd)
String dtdFileCacheURI = cachedFilePath.toUri().toString().replace("file:///", "file:/");
String dtdFileCacheURI = cachedFilePath.toUri().toString();
String xml = "<!DOCTYPE web-app PUBLIC\n" + //
" \"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN\"\n" + //
" \"" + httpDTDUri + "\" >\n" + //
Expand Down Expand Up @@ -122,7 +122,6 @@ private static void assertHoverWithCache(String value, String expectedHoverLabel
}

private static String getDTDFileURI(String dtdURI) throws MalformedURIException {
return XMLEntityManager.expandSystemId("dtd/" + dtdURI, "src/test/resources/test.xml", true).replace("///",
"/");
return XMLEntityManager.expandSystemId("dtd/" + dtdURI, "src/test/resources/test.xml", true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,7 @@ private static void assertHover(String value, String fileURI, ContentModelSettin
}

private static String getXMLSchemaFileURI(String schemaURI) throws MalformedURIException {
return XMLEntityManager.expandSystemId("xsd/" + schemaURI, "src/test/resources/test.xml", true).replace("///",
"/");
return XMLEntityManager.expandSystemId("xsd/" + schemaURI, "src/test/resources/test.xml", true);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -375,8 +375,7 @@ private SharedSettings createSharedSettings(SchemaDocumentationType docSource, b
}

private static String getXMLSchemaFileURI(String schemaURI) throws MalformedURIException {
return XMLEntityManager.expandSystemId("xsd/" + schemaURI, "src/test/resources/test.xml", true).replace("///",
"/");
return XMLEntityManager.expandSystemId("xsd/" + schemaURI, "src/test/resources/test.xml", true);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@ private SharedSettings createSharedSettings(SchemaDocumentationType docSource, b
}

private static String getXMLSchemaFileURI(String schemaURI) throws MalformedURIException {
return XMLEntityManager.expandSystemId("xsd/" + schemaURI, "src/test/resources/test.xml", true).replace("///",
"/");
return XMLEntityManager.expandSystemId("xsd/" + schemaURI, "src/test/resources/test.xml", true);
}

private void assertHover(String xml, String expected, Range range) throws BadLocationException, MalformedURIException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,6 @@ private static void assertHover(String value, String expectedHoverLabel, Range e
}

private static String getXMLSchemaFileURI(String schemaURI) throws MalformedURIException {
return XMLEntityManager.expandSystemId("xsd/" + schemaURI, "src/test/resources/test.xml", true).replace("///",
"/");
return XMLEntityManager.expandSystemId("xsd/" + schemaURI, "src/test/resources/test.xml", true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ public class MarkdownConverterTest {
@Test
public void testHTMLConversion() {
assertEquals("This is `my code`", convert("This is <code>my code</code>"));
assertEquals("This is" + System.lineSeparator() + "**bold**", convert("This is<br><b>bold</b>"));
assertEquals("This is " + System.lineSeparator() + "**bold**", convert("This is<br><b>bold</b>"));
assertEquals("The `<project>` element is the root of the descriptor.", convert("The <code>&lt;project&gt;</code> element is the root of the descriptor."));
assertEquals("# Hey Man #", convert("<h1>Hey Man</h1>"));
assertEquals("Hey Man"+ System.lineSeparator()+"=======", convert("<h1>Hey Man</h1>"));
assertEquals("[Placeholder](https://www.xml.com)", convert("<a href=\"https://www.xml.com\">Placeholder</a>"));

String htmlList =
Expand All @@ -36,9 +36,9 @@ public void testHTMLConversion() {
" <li>Milk</li>" + System.lineSeparator() +
"</ul>";
String expectedList =
" * Coffee" + System.lineSeparator() +
" * Tea" + System.lineSeparator() +
" * Milk";
"* Coffee" + System.lineSeparator() +
"* Tea" + System.lineSeparator() +
"* Milk";
assertEquals(expectedList, convert(htmlList));
assertEquals("ONLY_THIS_TEXT", convert("<p>ONLY_THIS_TEXT</p>"));

Expand All @@ -54,10 +54,13 @@ public void testHTMLConversion() {
"line" + System.lineSeparator() +
"<code>HTML</code>" + System.lineSeparator() +
"stuff";
String multilineHTML2Expected =
String multilineHTML2Expected =
"multi" + System.lineSeparator() +
"" + System.lineSeparator() +
"line `HTML` stuff";
"" + System.lineSeparator() +
"line"+ System.lineSeparator() +
"`HTML`"+ System.lineSeparator() +
"stuff";
assertEquals(multilineHTML2Expected, convert(multilineHTML2));
}

Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<plugin>
Expand Down

0 comments on commit b8bb3a4

Please sign in to comment.