Markdown testproject

PaulMeuris

Well-Known Member
Licensed User
In this thread markdown-to-html-with-a-twist @Erel shows code that downloads a markdown string and converts that string to html and shows the result in a WebView.
He uses a parser library named markdown2 that was written in Python.
In this thread I would like to show a few alternative ways to parse a markdown text. The user interface is kept very simple. In the first textarea the markdown text is added. In the second textarea the HTML result from the parser is shown and the result is loaded in the bottom WebView.
1738899304060.png

First case using B4J and a parser subroutine.​

When you click on the parse button the parse_markdown subroutine is called and the HTML result is returned to the content variable in the btnparse_Click subroutine. The content variable is used to fill the second textarea and to load the content HTML text in the WebView.
B4X:
Dim content As String = parse_markdown
The parser subroutine contains code to change 3 headings, a horizontal rule, some font formatting (bold, italic, underline, strikethrough) and a few symbols.
It doesn’t contain code for unordered list items and blockquotes.
1738899480263.png

Second case using B4J and a java parser library.​

The btnparse_Click subroutine also contains a line of code to call a java method called “start”. Uncomment the line (and put a comment before the line of the call to the parse_markdown subroutine).
B4X:
Dim content As String = jo.RunMethod("start",Array(ta1.text))
In the start method a new object of the markdownparser class is created. The parse method from that object is then called and the result is returned.
B4X:
#if java
import markdown_parser.*;
public String start(String source) {
    markdownparser mdp = new markdownparser();
    String res = mdp.parse(source);
    return res;
}
#End If
For this to work you need to place the markdownparser.jar file in the AdditionalLibraries folder. And in the Region Project attributes you need to add:
B4X:
#AdditionalJar: markdownparser.jar
#JavaCompilerPath: 23, E:\java\jdk-23.0.1\bin\javac.exe
The java library was compiled with JDK 23.0.1 (and javafx 23). Adjust the path to your JDK installation. Download and install the JDK and javafx SDK if you don’t have it yet.
Now the unordered list items and the blockquotes are converted.
1738899677494.png

In the log panel of the B4J IDE the lines are displayed that the library sends to the system output (System.out.println).

Third case using javafx and the java parser library.​

In this case the user interface is created using SceneBuilder. The test_markdown class contains code to load the fxml file.
Java:
@Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setTitle("Test Markdown Parser");
        primaryStage.setResizable(false);
        VBox layout = FXMLLoader.load(getClass().getResource("test_markdown.fxml"));
        layout.setStyle("-fx-font-size: 16");
        Scene scene = new Scene(layout, 600,600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }
The markdownparser library is imported in the Controller class.
Java:
import markdown_parser.*;
In this class the public variables are declared that are linked to the user interface objects (a button, 2 textarea’s and a webview).
In the initialize() method of the Controller class the default text is set for the first textarea.
In the btnparseClick method the new object of the markdownparser class is created. The parse method from the new object is called and the result is used to fill the second textarea and to show the result in the webview.
Java:
    public void btnparseClick(ActionEvent e) {
        markdownparser mdp = new markdownparser();
        String res = mdp.parse(ta1.getText());
        ta2.setText(res);
        wv1.setZoom(1.5);
        WebEngine webEngine = wv1.getEngine();
        webEngine.loadContent(res);
    }
The BlueJ IDE (5.4.1) is used to compile the javafx source code and to create the markdownparser.jar file (project / Create Jar File…).
1738899976389.png
1738899998936.png

The markdown_parser package contains the markdownparser class and its methods: parse, parse_line_marks, parse_font_formatting, parse_symbols, parse_images, parse_links, …
In the parse_images method you can find an example of a markdown line to add images in the text. Copy and paste the commented line in the first textarea and adjust the path and the text. The markdown for an image is as follows: ![alt-text](url ″title-text″).
In the parse_links you can also find an example.
The library doesn’t support all the markdown characters yet. You can use the source code and add methods for the remaining markdown characters. There are different flavors of markdown marks. In this example the italic marks are non-standard backticks (``), for the underline marks 2 underscore characters (__) are used and 2 tilde characters (~~) are used for the strikethrough characters.
You can add HTML and CSS to the first textarea to do some styling like the yellow background for instance.
1738900093389.png

You can find the generated documentation of the markdownparser library in the “doc” folder.
You can find the source codes in the attachments:
markdown_test.zip
test_markdown_parser.zip
testenvironment86.zip

Feel free to experiment with the source codes once you have downloaded and installed all the components needed.
 

Attachments

  • markdown_test.zip
    180.3 KB · Views: 184
  • test_markdown_parser.zip
    5.2 KB · Views: 178
  • testenvironment86.zip
    3.9 KB · Views: 180
Last edited:

PaulMeuris

Well-Known Member
Licensed User
And what about B4A?
1738914532967.png

The markdownparser library can also be used on an Android device.
I have created a similar layout in the B4A IDE with a button, 2 EditText views and a WebView.
And again i added the jar file reference:
B4X:
    #AdditionalJar: markdownparser.jar
The jar file should be in the AdditionalLibraries folder of course.
The source code is identical to the B4J code except for the use of the EditText views.
In debug mode with JDK 19 the app runs, however in release mode it doesn't:
B4A Version: 13.00
Parsing code. (0.05s)
Java Version: 19
Building folders structure. (0.04s)
Compiling code. (0.25s)
Compiling layouts code. (0.00s)
Organizing libraries. (0.00s)
(AndroidX SDK)
Compiling resources (0.08s)
Linking resources (0.41s)
build tools: 30.0.2, android jar: android-34
Compiling generated Java code. (3.91s)
Finding libraries that need to be dexed. (0.00s)
Dex code Error
Compilation failed with an internal error.
java.lang.IllegalArgumentException: Unsupported class file major version 65
at com.android.tools.r8.A.a.a.f.<init>:)10)
at com.android.tools.r8.A.a.a.f.<init>:)2)
at com.android.tools.r8.A.a.a.f.<init>:)1)
at com.android.tools.r8.A.a.a.f.<init>:)107)
at com.android.tools.r8.graph.x0.a:)24)
at com.android.tools.r8.utils.J.a:)9)
at com.android.tools.r8.utils.G.a:)8)
at com.android.tools.r8.utils.G.get:)1)
at com.android.tools.r8.utils.H.a:)28)
at com.android.tools.r8.graph.E0.definitionFor:)16)
at com.android.tools.r8.graph.c.definitionFor:)16)
at com.android.tools.r8.t.b.x0.f:)19)
at com.android.tools.r8.ir.optimize.s0.c.a:)14)
at com.android.tools.r8.ir.conversion.O.a:)586)
at com.android.tools.r8.ir.conversion.O.a:)426)
at com.android.tools.r8.ir.conversion.O.b:)53)
at com.android.tools.r8.ir.conversion.O.a:)102)
at com.android.tools.r8.ir.conversion.O.a:)51)
at com.android.tools.r8.graph.C.b:)34)
at com.android.tools.r8.ir.conversion.O.b:)35)
at com.android.tools.r8.utils.V0.a:)32)
at com.android.tools.r8.utils.V0.a:)30)
at java.base/java.util.concurrent.ForkJoinTask$AdaptedCallable.exec(ForkJoinTask.java:1456)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:387)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1311)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1841)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1806)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
And that is because the library was compiled with JDK 23 (class version 65), so i changed the Paths Configuration:
1738916176759.png

And tried to run it again... notice the Java Version:8 didn't change... which library needs to be dexed and why? @Erel, what seems to be the problem here?
B4A Version: 13.00
Parsing code. (0.05s)
Java Version: 8
Building folders structure. (0.07s)
Compiling code. (0.24s)
Compiling layouts code. (0.04s)
Organizing libraries. (0.04s)
(AndroidX SDK)
Compiling resources (0.08s)
Linking resources (0.41s)
build tools: 30.0.2, android jar: android-34
Compiling generated Java code. (4.55s)
Finding libraries that need to be dexed. (0.01s)
Dex code Error
Compilation failed with an internal error.
java.lang.NullPointerException: Cannot invoke "String.length()" because "<parameter1>" is null
at com.android.tools.r8.graph.h0.<init>:)5)
at com.android.tools.r8.graph.Y.b:)2)
at com.android.tools.r8.graph.x0$d.b:)8)
at com.android.tools.r8.A.a.a.f.a:)721)
at com.android.tools.r8.graph.x0.a:)38)
at com.android.tools.r8.dex.a$a.a:)12)
at java.base/java.util.concurrent.ForkJoinTask$AdaptedInterruptibleCallable.compute(ForkJoinTask.java:1689)
at java.base/java.util.concurrent.ForkJoinTask$InterruptibleTask.exec(ForkJoinTask.java:1641)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:507)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1458)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:2034)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:189)
And now what? Switch back to JDK 19 and in debug mode... notice Java Version:19...
So if the dexing problem gets resolved you should be able to run the app in release mode...
You can find the source code in the attachment (testenvironment86.zip)
 

Attachments

  • testenvironment86.zip
    10.4 KB · Views: 169

PaulMeuris

Well-Known Member
Licensed User
I did a few more tests... disconnected my device... closed and opened the IDE again... opened the testenvironment86... checked the Paths Configuration was on JDK 19... selected Release mode and ran it...
1738919615222.png

And it got compiled, dexed and installed on the device!
Maybe the JDK 23 is not yet supported by B4A?
 

PaulMeuris

Well-Known Member
Licensed User
Yes, i know the library will work fine with an older JDK.
I wanted to test using the same library in different environments: B4J with java library, JavaFX with java library and B4A with java library.
I had no problem using the first 2 environments and the B4J IDE accepts the java version 23 without any problem.

1739169854387.png


But the B4A IDE doesn't like the java version 23. The IDE tries to use the old java version 8 and doesn't use the specified path.
1739170520946.png


Dex code Error
Compilation failed with an internal error.
java.lang.NullPointerException: Cannot invoke "String.length()" because "<parameter1>" is null
at com.android.tools.r8.graph.h0.<init>:)5)
at com.android.tools.r8.graph.Y.b:)2)
at com.android.tools.r8.graph.x0$d.b:)8)
at com.android.tools.r8.A.a.a.f.a:)721)
at com.android.tools.r8.graph.x0.a:)38)
at com.android.tools.r8.dex.a$a.a:)12)
at java.base/java.util.concurrent.ForkJoinTask$AdaptedInterruptibleCallable.compute(ForkJoinTask.java:1689)
at java.base/java.util.concurrent.ForkJoinTask$InterruptibleTask.exec(ForkJoinTask.java:1641)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:507)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1458)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:2034)
And when i change the JDK version in the B4A IDE to version 19 the compilation uses java version: 19 and the app gets installed.
1739171512049.png

So this works for me for now but what will happen if i use a library with specific JDK 23 components?
Can you explain the Dex code error please? What happened?
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
So this works for me for now but what will happen if i use a library with specific JDK 23 components?
It is very unlikely that you will actually need a feature that is only available in JDK 23, and it for sure won't be available on Android.

Can you explain the Dex code error please?
The dex tool, which is part of Android SDK, isn't compatible with the bytecode.
 
Top