Project
I wanted to create a syntax highlighter for Java using JavaScript, HTML and CSS. It uses regular expressions to find the parts that should be highlighted (at the moment: keywords, strings, comments, imports) and then uses HTML-tags to highlight the found parts.
Result
The website looks like this before entering some code:
Example
I've used the following java-snippet to test the code:
import java.time.LocalDate;
public class Person {
//Local variable for dateOfBirth
private LocalDate dateOfBirth;
public Person(int year, int month, int day) {
//See API also: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html
dateOfBirth = LocalDate.of(year, month, day);
//Keywords (e.g. int) are not highlighted in comments and strings
System.out.println("Hello (int)");
}
/*
* Getter
*/
public LocalDate getDateOfBirth() {
return dateOfBirth;
}
}
The result looks like this:
Background
This is my first HTML/CSS/JS-project.
Code
var keywordsColor = "#0033cc";
var controlKeywordsColor = "#009933";
var typesKeywordsColor = "#3399ff";
var stringColor = "#ff3300";
var importColor = "#0033cc";
var commentColor = "gray";
var text;
var keywords = ["abstract", "assert", "class", "const", "extends", "false", "final",
"implements", "import", "instanceof", "interface", "native", "new", "null", "package",
"private", "protected", "public", "return", "static", "strictfp", "super", "synchronized",
"System", "this", "throw", "throws", "transient", "true", "volatile"];
var controlKeywords = ["break", "case", "catch", "continue", "default", "do", "else",
"finally", "for", "goto", "if", "switch", "try", "while"];
var typesKeywords = ["boolean", "byte", "char", "double", "enum", "float", "int",
"long", "short", "String", "void"];
var otherKeywords = [];
function highlight() {
text = document.getElementById("Input").value;
highlightKeywords();
highlightStrings();
highlightImports();
highlightSingleLineComments();
highlightMultiLineComments();
addStyles();
document.getElementById("Output").value = text;
document.getElementById("outputArea").innerHTML = text;
}
function highlightKeywords() {
var i;
for (i = 0; i < keywords.length; i++) {
var x = new RegExp(keywords[i] + " ", "g");
var y = "<span style='color:" + keywordsColor + ";font-weight:bold;'>" + keywords[i] + " </span>";
text = text.replace(x, y);
}
for (i = 0; i < controlKeywords.length; i++) {
var x = new RegExp(controlKeywords[i] + " ", "g");
var y = "<span style='color:" + controlKeywordsColor + "; font-weight:bold; '>" + controlKeywords[i] + " </span>";
text = text.replace(x, y);
}
for (i = 0; i < typesKeywords.length; i++) {
var x = new RegExp(typesKeywords[i] + " ", "g");
var y = "<span style='color:" + typesKeywordsColor + "; font-weight:bold; '>" + typesKeywords[i]
+ " </span>";
text = text.replace(x, y);
}
}
function highlightStrings() {
text = text.replace(/"(.*?)"/g,
"<span id=\"str\"style='color:" + stringColor + "; font-weight:bold; '>"
+ "\"$1\"" + "</span>");
}
function highlightImports() {
text = text.replace(/import(.*?);/g,
"<span id=\"str\"style='color:" + importColor + "; font-weight:bold; '>"
+ "import$1;" + "</span>");
}
function highlightSingleLineComments() {
text = text.replace(/\/\/(.*)/g,
"<span id=\"comment\"style='color:" + commentColor + "; font-weight:bold; '>"
+ "//$1" + "</span>");
}
function highlightMultiLineComments() {
text = text.replace(/\/\*([\s\S]*?)\*\//g,
"<span id=\"comment\"style='color:" + commentColor + "; font-weight:bold; '>"
+ "/*$1*/" + "</span>");
}
function addStyles() {
text = "<!-- Code begins here -->\n<pre><code>\n"
+ "<style>#comment span {color:" + commentColor + "!important;}</style>"
+ "<style>#str span {color:" + stringColor + "!important;}</style>" + text
+ "\n</code></pre>\n<!-- Code ends here -->\n";
}
/* Navigation bar style */
.nav ul {
background: ForestGreen; /* Sets the background-color */
list-style: none; /* Removes bullet point */
overflow: hidden; /* What happens when element is too big for formatting context*/
padding: 0px; /* padding-area at all four sides of an element */
}
.nav li {
float: left; /* Move element to the left and add new element on the right side*/
border-right: 2px solid LightGray;/* Border lines on the right side of each element */
}
.nav a {
color: black; /* Font color has to be set here, because otherwise it would be a blue hyperlink */
display: inline-block; /* One box for all elements */
font-size: large; /* Sets font size to a large size */
text-decoration: none; /* Removes underline */
padding: 4px;
}
.nav a:hover {
background: AliceBlue; /* Changes background of element when user is hovering over it */
}
.nav a.active {
background: DarkGreen; /* Changes background of current element */
}
/* Other */
#code {
background: LightGray;
font: monospace;
}
.column {
float: left;
width: 50%;
}
<!DOCTYPE html>
<html>
<!-- Head -->
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<!-- Navigation bar -->
<header>
<div class="nav">
<ul>
<li><a class = "active" href="index.html">Home</a></li>
</ul>
</div>
</header>
<!-- Body -->
<body>
<h2>HTML syntax-highlighting for Java</h2>
<!-- Left column -->
<div class="column">
<!-- Input Area -->
<h4>Input:</h4>
<div style = "white-space = pre !important">
<textarea id="Input" cols="80" rows="8" wrap = "off" style = "resize: none; background: LightGray"></textarea>
</div>
<br><br>
<button type="button" onclick="highlight()">Highlight</button>
<!-- Output Area -->
<h4>Output:</h4>
<div style = "white-space = pre !important">
<textarea id="Output" cols="80" rows="8" wrap = "off" style = "resize: none; background: LightGray"></textarea>
</div>
<style>
document.getElementById("Input").style.whiteSpace = "nowrap";
document.getElementById("Output").style.whiteSpace = "nowrap";
</style>
</div>
<!-- Right Column -->
<div class="column">
<h4>Preview</h4>
<div id="outputArea" style="overflow-y:auto; overflow-x:auto; height: 690px">
</div>
</div>
</body>
<script language = "javascript" type = "text/javascript" src = "highlightSyntax.js"></script>
</html>
Questions
How can this code be improved? Did I make a major mistake in regards to the best-practices of HTML/CSS/JS?
Any suggestions are appreciated.
The follow-up question can be found here.
"\""
? Or"\\\""
? \$\endgroup\$serif (x);
,if (x) y();
andif(x) y();
. The first is a false positive, and the third a false negative. The regex\b
for word-boundaries may be more useful (/\bif\b
) than just looking for a trailing space (/if /
) \$\endgroup\$