
help and download »
This is my light weight code highlighter for html, javascript and css.
Lets review the script :-)
The color scheme
function highlightCode(codeblock,colorSet) {
defaultColor = "#cccccc";
defaultBackground = "#000000";
defaultFontSet = "\'Courier New\', Times, serif";
colorScheme="#C3FF00,#8CFF00,#5DFF00,#00CE29,#00CE97,#00FFF6"
if(colorSet=='blueish green'){colorScheme="#C3FF00,#8CFF00,#5DFF00,#00CE29,#00CE97,#00FFF6";}
else if(colorSet=='fire'){colorScheme="#FF006E,#FF0000,#FF6A00,#FFBF00,#FFEE00,#E9FF00,#CCFF00";}
else if(colorSet=='purple blue'){colorScheme="#00CBFF,#0094FF,#0065FF,#001DFF,#6A00FF,#9000FF,#C300FF,#FF00F2";}
else if(colorSet=='techno') {colorScheme="#00FFD4,#00FF99,#00FF3F,#8BFF6B,#BCFF6B,#BBFF00,#83C1FC,#58DBFC,#09F5F9,#00FF8C,#A5C600,#A5C600";}
else if(colorSet=='restfull') {colorScheme="#A5C600,#00C475,#00C475,#00C475,#25BC8A,#25BC8A,#25BC8A,#25BC8A,#4800FF,#6474FC,#009DFF,#A24CED,#294BE5,#317237";}
else if(colorSet=='contrast') {colorScheme="#935456,#009DFF,#A24CED,#294BE5,#317237,#935456,#009DFF,#A24CED,#294BE5,#317237,#935456";}
else if(colorSet=='gray shades') {colorScheme="#ffffff,#dddddd,#aaaaaa,#777777,#555555";}
else if(colorSet=='haxor green') {colorScheme="#1C8E31,#16AD43,#1BD352,#18F45A,#54F284,#69D389,#A1EDB8";}
else if(colorSet=='circus'){
colorScheme="#F70000,#CB00FF,#8C8AFC,#00E5FF,#00FF0C,#FAFF00,#AD7824,#E0DA86";
defaultFontSet="Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New, monospace";
}
colorScheme = colorScheme.split(',');
This sets the color scheme. You can modify the colors or expand the list. The code is shown in 'blueish green'.
Load
raw = (document.getElementById(codeblock).innerHTML).split('\n').join('<br>');
raw = raw.split(' ').join(' ');
colorArray = new Array();
for(long=0;long<raw.length;long++){
colorArray[long] = defaultColor;
}
The line breaks in the raw code are replaced with html line breaks and the tabs are replaced with double space.
The second bit sets a default color for each character.
The code is shown in "fire".
Get the words
rawArr = raw.split('');
lowercaseRaw=raw.toLowerCase();
justletters=lowercaseRaw.replace(/[^a-z0-9]/g," ");
justletters=justletters.replace(/\s+/g," ");
Here we replace everything that isn't a letter or a number with a space. Then we replace rows of spaces with single ones.
The code is shown in "purple blue".
purging the duplicates
myarray=("< > & &lt; &gt; / ' { } = ( )"+' " '+justletters).split(' ');
y = 0;
result = new Array();
myarray=myarray.sort(); // first sort the array
result[0]=myarray[0];
for(x=1;x<myarray.length;x++){
if(myarray[x]!=myarray[x-1]){ // if item is not the same as the one before
result[y]=myarray[x]; // then we add it to the output array
y++;
}
}
result=result.sort(function(a,b){return a.length - b.length});
We extend the list of words with entities that should not be highlighted partially and add some special characters that we do want to colorize.
The last line sorts the array by size.
The code is shown in "techno".
Find the strings and set their colors
if(result!=-1){
for(x=0;x<result.length;x++){
locations = findInString(result[x], lowercaseRaw);
if(locations!=-1){
for (ww = 0; ww < locations.length; ww++) {
for(zz=0;zz<result[x].length;zz++){
if(x>=colorScheme.length){
colorScheme = colorScheme.concat(colorScheme);
}
colorArray[1 * locations[ww] + zz] = colorScheme[x];
}
}
}
}
}
Now we walk though our "word" list, we retreave the locations of the results, then for each result we set the color of it's letters. We start with the small strings and work our way up to the big ones. Big matches then override the small matches.
In case we run out of colors we extend the color scheme with a duplicate of the current color scheme.
The code is shown in "restfull".
// uncolor comments //
tr = lowercaseRaw; // create temporal raw copy
comment = 0; // comment pointer
while( tr.indexOf( '//' ) != -1){ // keep going until no instances of double slash remain
comment = 1 * comment + tr.indexOf( '//' ) + 2; // increase the comment pointer to point at the next potential comment
tr = lowercaseRaw.slice( comment ) + "<"; // get the part after the potential comment
trB = lowercaseRaw.substring( 0 , comment ); // get the part before the potential comment
trB = trB.split( '\\<br>' ).join( ' ' ); // remove escaped line breaks
trB = trB.substring(trB.lastIndexOf( '>' ), trB.length); // find the beginning of the line with the potential comment
sq = trB.split( "'" ).length - 1; // count the single quotes
dq = trB.split( '"' ).length - 1; // count the double quotes
if(sq%2 == 0 && dq%2 == 0
|| sq == 1 && dq == 2 && trB.indexOf('"') < trB.indexOf("'") && trB.lastIndexOf('"') > trB.indexOf("'")
|| sq == 2 && dq == 1 && trB.indexOf("'") < trB.indexOf('"') && trB.lastIndexOf( "'" ) >trB.indexOf( '"' ) ){
semicol=tr.indexOf(';');
if( semicol == -1 || semicol > tr.indexOf( '<' ) ){
for( x = 0 ; x < tr.indexOf( '<' ); x++ ){
colorArray[ 1 * comment + x ] = defaultColor;
}
}
}
}
// uncolor comments /* foo bar */
tr=lowercaseRaw; // create temporal raw copy
comment=0; // comment pointer
while(tr.indexOf('/*')!=-1){ // keep going until no instances of slash star remain
comment=1*comment+tr.indexOf('/*')+2; // increase the comment pointer to point at the next potential comment
tr=lowercaseRaw.slice(comment)+"<"; // get the part after the potential comment
trB=lowercaseRaw.substring(0,comment); // get the part before the potential comment
trB=trB.split('\\<br>').join(' '); // remove escaped line breaks
trB=trB.substring(trB.lastIndexOf('>'),trB.length); // find the beginning of the line with the potential comment
sq=trB.split("'").length-1; // count the single quotes
dq=trB.split('"').length-1; // count the double quotes
if(sq%2==0&&dq%2==0
||sq==1&&dq==2&&trB.indexOf('"')<trB.indexOf("'")&&trB.lastIndexOf('"')>trB.indexOf("'")
||sq==2&&dq==1&&trB.indexOf("'")<trB.indexOf('"')&&trB.lastIndexOf("'")>trB.indexOf('"')){
semicol=tr.indexOf(';');
if(semicol==-1||semicol>tr.indexOf('*/')){
for(x=0;x<tr.indexOf('*/');x++){
colorArray[1*comment+x]= defaultColor;
}
}
}
}
To make them more readable we color the comments in the default color. The code is shown in "circus".
The output array pooping process
var output = '<ol start="0"><li><span style="color:'+colorArray[0]+'">';
var theOldColor = colorArray[0];
for (CharacterPointer=0;CharacterPointer<raw.length;CharacterPointer++){
theLetter=rawArr[CharacterPointer];
theColor=colorArray[CharacterPointer];
theFutureColor=colorArray[CharacterPointer*1+1];
if(theLetter=="<"){
if(lowercaseRaw.substring(CharacterPointer, (1*CharacterPointer+4))=="<br>"){
theLetter="</li><li>";
CharacterPointer=CharacterPointer*1+3;
}
}
if (theLetter==" ") {
theLetter=" <wbr>";
}
if (theColor == theOldColor && theColor == theFutureColor) {
output = output + theLetter;
} else if (theColor == theOldColor&&CharacterPointer>1) {
output = output + theLetter + '</span>';
} else if (theColor == theFutureColor) {
output = output + '</span><span style="color:' + theColor + ';">' + theLetter;
} else {
output = output + '<span style="color:' + theColor + ';">' + theLetter + '</span>';
}
theOldColor=colorArray[CharacterPointer];
}
If the color of a character is the same as the one before it there is no need to set the color. If the color of the next character is the same there is no need to close the span.
I've also made cleaver use of the wbr tag. This way we can have a kind of absolute formating without the text bursting out of the side of the monitor.
The code is shown in "contrast".
Writing it back to the page
document.getElementById(codeblock).innerHTML = '<div style="font-weight:bold;font-family:\'Courier New\', Times, serif;color:'+defaultColor+';font-size:14px;padding:4px 0px 4px 4px;background-color:'+defaultBackground+';"><ol start="0"><li>'+output+"</li></ol></div>";
We dont need that much CSS, attching a stylesheet thingy seems exessive.
The code is shown in "gray shades".
The find string inside string function
function findInString(searchFor, searchIn) {
var results = new Array();
var yy = 0;
var aa = searchIn.indexOf(searchFor);
results[0] = aa;
searchIn = searchIn.slice(aa * 1 + searchFor.length);
yy = aa * 1 + searchFor.length;
if (aa != -1) {
for (xx = 1; searchIn.indexOf(searchFor) != -1; xx++) {
yy = searchIn.indexOf(searchFor)
results[xx] = 1 * results[1 * xx - 1] + searchIn.indexOf(searchFor) + searchFor.length;
searchIn = searchIn.slice(1 * searchIn.indexOf(searchFor) + searchFor.length);
}
}
return results;
}
We give the function 2 strings, it searches for the first one inside the second one then it returns an array of locations where a match was found.
The code is shown in "haxor green". Nostalgica isn't trying to win any usability contest.
I'm sure by now you understand I've given you a really powerful tool here, use it wizely, we wouldn't want anyone to get hurt.
Pro tip
Besides from converting the script on the page you could also build the highlighter into your cms and have it do the formatting before you post things.
credits
- yalue @ #regex @ freenode : for providing a better space stripping regex.
- j201 @ ##javascript @ freenode : for his entugiasm about the array pooping terminology.
- CorbinDallas @ ##javascript @ freenode : for helping figure out how to escape & when escaping < and &gt;.
- +jwillia3 @ ##programming @ freenode : for suggesting black a background and that everything in the tag could be the same colour.
- JoeyA @ ##programming @ freenode : for reminding me of small screens.
- Raymondo @ #defocus @ freenode : for suggesting a credit section.
- Vill @ #css @ freenode : for helping with the line numbers.
- dysoco @ ##programming @ freenode : for suggesting not to colorize comments. (harder than it seems)
- Havvy @ ##javascript @ freenode : for suggesting
- named paterns (and functions)
- style sheets
- more spacing for readability
- The nice color picker seen in the color studio and in the html prefab lab is from johndyer.name.