Skip to content

Commit

Permalink
Add ability for CSS to be applied inline instead of separate in a sty…
Browse files Browse the repository at this point in the history
…le block
  • Loading branch information
Col-E committed Apr 27, 2019
1 parent 64e88ef commit f4539ad
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 35 deletions.
58 changes: 30 additions & 28 deletions src/main/java/me/coley/c2h/Code2Html.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javafx.util.Pair;
import jregex.Matcher;
import jregex.Pattern;
import me.coley.c2h.config.*;
import me.coley.c2h.config.model.*;
import me.coley.c2h.ui.RuleCell;
import me.coley.c2h.util.Regex;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.controlsfx.validation.ValidationSupport;
Expand All @@ -45,8 +45,8 @@
*/
public class Code2Html extends Application implements Callable<Void> {
// Base values
private static String css = "";
private static String js = "";
public static String BASE_CSS = "";
public static String BASE_JS = "";
// Command line options/args
@Option(names = {"-c", "--config"}, description = "Config to with languages and themes")
private File clConfig;
Expand All @@ -58,8 +58,12 @@ public class Code2Html extends Application implements Callable<Void> {
private boolean clClipboard;
@Option(names = {"-o", "--out"}, description = "The file to output converted HTML to")
private File clOutput;
@Option(names = {"-i", "--inline"}, description = "Option to make CSS inline with the HTML elements")
private boolean clInline;
@CommandLine.Parameters(index = "0", description = "The file to convert to styled HTML")
private File clInput;
// Other options
private boolean inline;
// Boolean indicating if CLI has priority over GUI
private boolean cliExecution;
// Controls
Expand All @@ -77,11 +81,10 @@ public class Code2Html extends Application implements Callable<Void> {
// Config
private ConfigHelper helper;


public static void main(String[] args) {
try {
css = IOUtils.toString(Code2Html.class.getResourceAsStream("/code.css"), UTF_8);
js = IOUtils.toString(Code2Html.class.getResourceAsStream("/code.js"), UTF_8);
BASE_CSS = IOUtils.toString(Code2Html.class.getResourceAsStream("/code.css"), UTF_8);
BASE_JS = IOUtils.toString(Code2Html.class.getResourceAsStream("/code.js"), UTF_8);
} catch(Exception e) {
e.printStackTrace();
System.err.println("Failed to load default resources: css/js");
Expand Down Expand Up @@ -134,7 +137,7 @@ public Void call() {
helper = new ConfigHelper(configuration, language, theme);
// Input reading & parsing
String text = FileUtils.readFileToString(clInput, UTF_8);
String converted = helper.convert(text);
String converted = helper.convert(text, clInline);
// Output
Platform.runLater(() -> {
if(clClipboard) {
Expand Down Expand Up @@ -195,7 +198,7 @@ public void start(Stage stage) {
txtJS.setFont(Font.font("monospace"));
txtHTML.setEditable(false);
updateCSS();
txtJS.setText(js);
txtJS.setText(BASE_JS);
txtInput.textProperty().addListener((ob, o, n) -> {
// Update HTML
updateHTML();
Expand All @@ -210,21 +213,9 @@ public void start(Stage stage) {
if(!old.equalsIgnoreCase(cur)) {
// Iterate over css tags (by matching via regex)
for(Rule rule : helper.getRules()) {
String r = "(\\.({TITLE}" + rule.getName() + ")\\s*\\{({BODY}[^}]*))\\}";
Pattern pattern = new Pattern(r);
Matcher matcher = pattern.matcher(cur);
if(!matcher.find())
return;
String body = matcher.group("BODY");
// Parse the body of the css class and update the regex-rule style map.
r = "({key}\\S+):\\s*({value}.+)(?=;)";
pattern = new Pattern(r);
matcher = pattern.matcher(body);
while(matcher.find()) {
String key = matcher.group("key");
String value = matcher.group("value");
Regex.getCssProperties(cur, "." + rule.getName()).forEach((key, value) -> {
helper.getTheme().update(rule.getName(), key, value);
}
});
}
}
// Update HTML
Expand Down Expand Up @@ -309,8 +300,17 @@ public void start(Stage stage) {
});
mnFile.getItems().addAll(miConfigLoad);
mnFile.getItems().addAll(miConfigSave);
// TODO: Swap out menu-item for checkbox
Menu mnOptions = new Menu("Options");
CheckMenuItem miOptionInline = new CheckMenuItem("Inline HTML style");
miOptionInline.selectedProperty().addListener((observable, oldValue, newValue) -> {
this.inline = newValue.booleanValue();
updateHTML();
});
mnOptions.getItems().addAll(miOptionInline);
// inline
MenuBar menuBar = new MenuBar();
menuBar.getMenus().addAll(mnFile, mnLang, mnTheme);
menuBar.getMenus().addAll(mnFile, mnLang, mnTheme, mnOptions);
// Layout
SplitPane pane = new SplitPane(txtInput, tabs);
SplitPane vert = new SplitPane(pane, browser);
Expand Down Expand Up @@ -682,7 +682,7 @@ private void updateTitle() {
* Update CSS text.
*/
private void updateCSS() {
txtCSS.setText(helper.getPatternCSS() + css);
txtCSS.setText(helper.getPatternCSS() + BASE_CSS);
}

/**
Expand All @@ -693,12 +693,14 @@ private void updateHTML() {
return;
}
String text = txtInput.getText().replace("\t", " ");
String html = helper.convert(text);
String html = helper.convert(text, inline);
String style = txtCSS.getText();
StringBuilder sbWeb = new StringBuilder();
sbWeb.append("<html><head><style>");
sbWeb.append(style);
sbWeb.append("</style></head><body>");
sbWeb.append("<html><head>");
if (!inline) {
sbWeb.append("<style>" + style + "</style>");
}
sbWeb.append("</head><body>");
sbWeb.append(html);
sbWeb.append("</body></html>");
browser.getEngine().loadContent(sbWeb.toString());
Expand Down
63 changes: 56 additions & 7 deletions src/main/java/me/coley/c2h/config/ConfigHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
import jregex.Pattern;
import lombok.Getter;
import lombok.Setter;
import me.coley.c2h.Code2Html;
import me.coley.c2h.config.model.*;
import me.coley.c2h.util.Regex;

import java.util.List;
import java.util.Map;

import static org.apache.commons.text.StringEscapeUtils.escapeHtml4;

Expand Down Expand Up @@ -67,14 +70,14 @@ public void addRule(Rule rule) {
* @param text
* Text to convert into HTML.
*
* @param inline
* @return HTML of the text with matched attributes of the {@link #language current language}.
*/
public String convert(String text) {
public String convert(String text, boolean inline) {
Matcher matcher = getPattern().matcher(text);
StringBuilder sb = new StringBuilder();
int lastEnd = 0;
while(matcher.find()) {
String styleClass = getClassFromGroup(matcher);
int start = matcher.start();
int end = matcher.end();
// append text not matched
Expand All @@ -84,17 +87,43 @@ public String convert(String text) {
}
// append match
String matched = escapeHtml4(text.substring(start, end));
sb.append("<span class=\"" + styleClass + "\">" + matched + "</span>");
if (inline) {
String styleRules = getInlineStyleFromGroup(matcher);
sb.append("<span style=\"" + styleRules + "\">" + matched + "</span>");
} else {
String styleClass = getClassFromGroup(matcher);
sb.append("<span class=\"" + styleClass + "\">" + matched + "</span>");
}
lastEnd = end;
}
// Append ending text not matched
sb.append(escapeHtml4(text.substring(lastEnd)));
// Apply line formatting to each line
StringBuilder fmt = new StringBuilder();
for(String line : sb.toString().split("\n"))
fmt.append("<span class=\"line\"></span>" + line + "\n");
// Wrap in pre tags and slap it in an HTML page
return "<pre>" + fmt.toString() + "</pre>";
if(inline) {
StringBuilder sbLineStyle = new StringBuilder();
StringBuilder sbLinePreStyle = new StringBuilder();
Regex.getCssProperties(Code2Html.BASE_CSS, "pre .line").forEach((key, value) -> {
sbLineStyle.append(key + ":" + value + ";");
});
Regex.getCssProperties(Code2Html.BASE_CSS, "pre .line::before").forEach((key, value) -> {
sbLinePreStyle.append(key + ":" + value + ";");
});
int lineNum = 1;
for(String line : sb.toString().split("\n"))
fmt.append("<span style=\"" +sbLineStyle.toString() + "\"><span style=\"" + sbLinePreStyle.toString() + "\">" + (lineNum++) + "</span></span>" + line + "\n");
// Wrap in pre tags and slap it in an HTML page
StringBuilder sbPreStyle = new StringBuilder();
Regex.getCssProperties(Code2Html.BASE_CSS, "pre").forEach((key, value) -> {
sbPreStyle.append(key + ":" + value + ";");
});
return "<pre style=\"" + sbPreStyle.toString() + "\">" + fmt.toString() + "</pre>";
} else {
for(String line : sb.toString().split("\n"))
fmt.append("<span class=\"line\"></span>" + line + "\n");
// Wrap in pre tags and slap it in an HTML page
return "<pre>" + fmt.toString() + "</pre>";
}
}

/**
Expand Down Expand Up @@ -149,4 +178,24 @@ public String getClassFromGroup(Matcher matcher) {
return rule.getName();
return null;
}

/**
* Fetch the CSS style to be used by the matched group.
*
* @param matcher
* Matcher that has found a group.
*
* @return CSS inline style.
*/
public String getInlineStyleFromGroup(Matcher matcher) {
for(Rule rule : getRules())
if(matcher.group(rule.getPatternGroupName()) != null) {
StringBuilder sbStyle = new StringBuilder();
theme.getStylesForRule(rule.getName())
.forEach(style ->
sbStyle.append(style.getKey() + ":" + style.getValue() + ";"));
return sbStyle.toString();
}
return "";
}
}
43 changes: 43 additions & 0 deletions src/main/java/me/coley/c2h/util/Regex.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package me.coley.c2h.util;

import jregex.Matcher;
import jregex.Pattern;
import org.apache.commons.text.StringEscapeUtils;

import java.util.HashMap;
import java.util.Map;

/**
* Utility for miscellaneous regex actions.
*
* @author Matt
*/
public class Regex {
/**
* @param cssText
* Text containing CSS to match.
* @param cssRule
* Rule to extract properties from.
*
* @return Map of property names to values.
*/
public static Map<String, String> getCssProperties(String cssText, String cssRule) {
Map<String, String> map = new HashMap<>();
String regex = "(({TITLE}" + cssRule + ")\\s*\\{({BODY}[^}]*))\\}";
Pattern pattern = new Pattern(regex);
Matcher matcher = pattern.matcher(cssText);
if(!matcher.find())
return map;
String body = matcher.group("BODY");
// Parse the body of the css class and update the regex-rule style map.
regex = "({key}\\S+):\\s*({value}.+)(?=;)";
pattern = new Pattern(regex);
matcher = pattern.matcher(body);
while(matcher.find()) {
String key = matcher.group("key");
String value = matcher.group("value");
map.put(key, value);
}
return map;
}
}
1 change: 1 addition & 0 deletions src/main/resources/code.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pre * { font-family: monospace; }
/* show line numbers */
pre .line { display: inline-block; }
pre .line::before {
user-select: none;
counter-increment: ln;
content: counter(ln);
display: inline-block;
Expand Down

0 comments on commit f4539ad

Please sign in to comment.