Skip to content

Instantly share code, notes, and snippets.

@Col-E
Last active July 12, 2018 00:25
Show Gist options
  • Save Col-E/006ee9c807e3ded1881a39109fd16900 to your computer and use it in GitHub Desktop.
Save Col-E/006ee9c807e3ded1881a39109fd16900 to your computer and use it in GitHub Desktop.
Java-2-HTML converter
/**
* When the window loads, insert collapse buttons.
*/
window.onload = function() {
// Iterate code blocks:
var codeBlocks = document.getElementsByTagName("pre");
for (var i = 0; i < codeBlocks.length; i++) {
// Iterate block children to identify the sections.
// They should be the only elements with ID's in the <pre> tag.
var pre = codeBlocks[i];
var children = pre.getElementsByTagName("*");
for (var c = 0; c < children.length; c++) {
var child = children[c];
// ID span found, add collapse to it.
if (!isEmpty(child.id)){
addCollapse(pre, child.id);
c++;
}
}
}
};
/**
* containerx:
* Element that holds the container marked by the ID
* id:
* ID of collapseable content. Relative to the container, not the whole document.
*/
function addCollapse(containerx, id) {
// create buttons that collapse the content of those containers.
var container = containerx.querySelector("#" + id);
//var parent = container.parentNode;
var toggleBtn = document.createElement("div");
toggleBtn.className = "toggle-open";
// click action
toggleBtn.onclick = function () {
collapse(toggleBtn, container, id);
};
// hover to show what will be collapsed
toggleBtn.onmouseout = function () {
setHighlighted(container, true);
setHighlightedDummy(id, true);
}
toggleBtn.onmouseover = function () {
setHighlighted(container, false);
setHighlightedDummy(id, false);
}
containerx.insertBefore(toggleBtn, container);
}
/**
* container:
* Container to be marked.
* highlighted:
* If container should be highlighted, noting collapseable content.
*/
function setHighlighted(container, highlighted) {
var cls = container.className;
if(highlighted) {
container.className = container.className.replace("toggle-section", "");
} else {
container.className += " toggle-section";
}
}
/**
* id:
* ID of dummy content to be marked.
* highlighted:
* If container should be highlighted, noting collapseable content.
*/
function setHighlightedDummy(id, highlighted) {
var dcID = "dummy-cont-" + id;
var container = document.getElementById(dcID);
if (container != null) {
setHighlighted(container, highlighted);
}
}
/**
* button:
* The button that controls the visibility of the container.
* container:
* Span containing collapsable content.
* id:
* ID of the container.
*/
function collapse(button, container, id) {
// toggle button format
var btnType = button.className;
var dlID = "dummy-line-" + id;
var dcID = "dummy-cont-" + id;
if(btnType == "toggle-open") {
button.className = "toggle-closed";
// replace with dummy line
var dLine = document.createElement("span");
var dContent = document.createElement("span");
dLine.id = dlID;
dLine.className = "line";
dContent.id = dcID;
dContent.className = "comment-line toggle-section"; // selection included since mouse will be over
dContent.innerHTML = "// " + id + "... ";
container.parentNode.insertBefore(dLine, container);
container.parentNode.insertBefore(dContent, container);
} else{
button.className = "toggle-open";
// remove dummy items
document.getElementById(dlID).outerHTML = "";
document.getElementById(dcID).outerHTML = "";
}
// toggle visibility of container
if (container.style.display === "none") {
container.style.display = "inline";
} else {
container.style.display = "none";
}
}
/**
* Check if string is empty.
*/
function isEmpty(str) {
return (!str || 0 === str.length);
}
package me.coley.j2h;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.SplitPane;
import javafx.scene.control.TextArea;
import javafx.stage.Stage;
// https://mvnrepository.com/artifact/org.apache.commons/commons-text
import org.apache.commons.text.StringEscapeUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Basic java to HTML converter using regex
*
* @author Matt
*/
public class Java2Html extends Application {
//@formatter:off
private static final String[] KEYWORDS = new String[] { "abstract", "assert", "boolean", "break", "byte", "case", "catch",
"char", "class", "const", "continue", "default", "do", "double", "else", "enum", "extends", "final", "finally",
"float", "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long", "native", "new",
"package", "private", "protected", "public", "return", "short", "static", "strictfp", "super", "switch",
"synchronized", "this", "throw", "throws", "transient", "try", "void", "volatile", "while" };
//@formatter:on
private static final String KEYWORD_PATTERN = "\\b(" + String.join("|", KEYWORDS) + ")\\b";
private static final String STRING_PATTERN = "\"([^\"\\\\]|\\\\.)*\"";
private static final String CONST_HEX_PATTERN = "(0[xX][0-9a-fA-F]+)+";
private static final String CONST_VAL_PATTERN = "(\\b([\\d._]*[\\d])\\b)+|(true|false|null)";
private static final String CONST_PATTERN = CONST_HEX_PATTERN + "|" + CONST_VAL_PATTERN;
private static final String COMMENT_SINGLE_PATTERN = "//[^\n]*";
private static final String COMMENT_MULTI_SINGLE_PATTERN = "/[*](.|\\R)+?\\*/";
private static final String COMMENT_MULTI_JAVADOC_PATTERN = "/[*]{2}(.|\\R)+?\\*/";
private static final String ANNOTATION_PATTERN = "\\B(@[\\w]+)\\b";
//@formatter:off
private static final Pattern PATTERN = Pattern.compile(
"(?<KEYWORD>" + KEYWORD_PATTERN + ")" +
"|(?<STRING>" + STRING_PATTERN + ")" +
"|(?<COMMENTDOC>" + COMMENT_MULTI_JAVADOC_PATTERN + ")" +
"|(?<COMMENTMULTI>" + COMMENT_MULTI_SINGLE_PATTERN + ")" +
"|(?<COMMENTLINE>" + COMMENT_SINGLE_PATTERN + ")" +
"|(?<ANNOTATION>" + ANNOTATION_PATTERN + ")" +
"|(?<CONSTPATTERN>" + CONST_PATTERN + ")");
//@formatter:on
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
TextArea input = new TextArea();
TextArea output = new TextArea();
input.textProperty().addListener((observable, oldValue, newValue) -> {
update(output, newValue);
});
SplitPane pane = new SplitPane(input, output);
primaryStage.setScene(new Scene(pane, 900, 800));
primaryStage.setTitle("Java2Html");
primaryStage.show();
}
/**
* Set the value of the TextArea <i>(output)</i> to the HTML-decorated version of the input <i>(text)</i>.
*
* @param output
* TextArea that will host the output.
* @param text
* Input text <i>(Java code)</i>
*/
private static void update(TextArea output, String text) {
text = text.replace("\t", " ");
Matcher matcher = PATTERN.matcher(text);
StringBuilder sb = new StringBuilder();
int lastEnd = 0;
while(matcher.find()) {
//@formatter:off
String styleClass =
matcher.group("STRING") != null ? "string"
: matcher.group("KEYWORD") != null ? "keyword"
: matcher.group("COMMENTDOC") != null ? "comment-javadoc"
: matcher.group("COMMENTMULTI") != null ? "comment-multi"
: matcher.group("COMMENTLINE") != null ? "comment-line"
: matcher.group("CONSTPATTERN") != null ? "const"
: matcher.group("ANNOTATION") != null ? "annotation" : null;
//@formatter:on
int start = matcher.start();
int end = matcher.end();
// append text not matched
if(start > lastEnd) {
sb.append(StringEscapeUtils.escapeHtml4(text.substring(lastEnd, start)));
}
// append match
sb.append("<span class=\"" + styleClass + "\">" + StringEscapeUtils.escapeHtml4(text.substring(start, end)) + "</span>");
lastEnd = end;
}
sb.append(StringEscapeUtils.escapeHtml4(text.substring(lastEnd)));
StringBuilder fmt = new StringBuilder();
for(String line : sb.toString().split("\n")) {
fmt.append("<span class=\"line\"></span>" + line + "\n");
}
output.setText("<pre>" + fmt.toString() + "</pre>");
}
}
/* =========================== */
/* Code block */
/* =========================== */
/* HTML auto-gen to match this with:
https://gist.github.com/Col-E/006ee9c807e3ded1881a39109fd16900
*/
pre {
font-family: monospace;
background: rgba(0,0,0,0.04);
border: 1px solid rgba(0,0,0,0.3);
counter-reset: ln;
margin-left: 2px;
margin-right: 2px;
overflow: auto;
}
pre * {
font-family: monospace;
}
/* show line numbers */
pre .line {
display: inline-block;
}
pre .line::before {
counter-increment: ln;
content: counter(ln);
display: inline-block;
color: black;
font-weight: normal;
font-style: normal;
border-right: 1px solid rgba(200,200,200,1);
padding: 0 15;
margin: 0 10 0 0;
width: 20px;
text-align: center;
background: rgba(0,0,0,0.035);
}
/* code style for element types */
pre .keyword {
color: rgb(127, 0, 85);
font-weight: bold;
text-shadow: none;
}
pre .string {
color: rgb(47, 100, 31);
font-style: italic;
}
pre .const {
color: rgb(173, 53, 0);
}
pre .annotation {
color: rgb(120, 130, 150);
}
pre .comment-line,
pre .comment-multi {
color: rgb(0, 111, 12);
font-style: italic;
}
pre .comment-javadoc {
color: rgb(0, 100, 114);
font-style: italic;
}
/* =========================== */
/* Code block section toggle */
/* =========================== */
/* shared button style */
.toggle-open,
.toggle-closed {
cursor: pointer;
position: absolute;
display: inline-block;
margin-left: -15px;
text-align: center;
width: 13px;
background: rgba(0,0,0,0.2);
border: 1px solid rgba(0,0,0,0.3);
}
/* closed button is more blue */
.toggle-closed {
background: rgba(20,20,130,0.4);
}
/* text (+/-) for open/close button operations */
.toggle-open::before {
content: '-';
}
.toggle-closed::before {
content: '+';
}
/* dark on hover */
.toggle-open:hover,
.toggle-closed:hover {
background: rgba(0,0,0,0.34);
}
/* highlight for code belonging to a toggle-button */
.toggle-section {
background: rgba(0,0,100,0.1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment