blob: d7d2d9616cf6adb245d7879bcf35a18d2fb0be6b [file] [log] [blame]
/**
* A Syntax Highlighter brush for Java properties files.
* For a description of their syntax, see the link below.
* @see "http://download.oracle.com/javase/1.5.0/docs/api/java/util/Properties.html#load(java.io.InputStream)"
* @version 1.0
* @author Alexandre DUTRA
*
*/
;(function()
{
// CommonJS
typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null;
function Brush() {
function process(match, regexInfo) {
var result = [];
var line = match[0];
//one or more lines with just a line terminator have been skipped => reset flags for multiline keys and values
//but continue processing
if(match.index > currentIndex + 1) {
multilineValue = false;
multilineKey = false;
}
//a line with whitespaces only => reset flags for multiline keys and values and stop processing
if(isBlank(line)){
multilineValue = false;
multilineKey = false;
//a comment line
} else if(!multilineValue && !multilineKey && isComment(line)){
pushResult(result, line, match.index, 'comments');
//a value spanned over multiple lines
} else if (multilineValue) {
pushResult(result, line, match.index, 'string');
multilineValue = isMultiline(line);
} else {
//a line containing at least a key, possibly key + separator + value
//can also be the continuation of a multiline key
var indexes = splitKeySepValue(line);
//separator found
if(indexes[0] != -1) {
//non empty key
if(indexes[0] > 0) {
var key = line.substring(0, indexes[0]);
pushResult(result, key, match.index, 'functions');
}
//separator
var sep = line.substring(indexes[0], indexes[1] != -1 ? indexes[1] : line.length);
pushResult(result, sep, match.index + indexes[0], 'constants');
//non empty value
if(indexes[1] != -1) {
var value = line.substring(indexes[1], line.length);
pushResult(result, value, match.index + indexes[1], 'string');
}
//check if it is the start of a multiline value
multilineValue = isMultiline(line);
multilineKey = false;
} else {
//no separator => key without value, check if it is the start of a multiline key
var key = line.substring(0, line.length);
pushResult(result, key, match.index, 'functions');
multilineValue = false;
multilineKey = isMultiline(line);
}
}
//record the current input index
currentIndex = match.index + line.length;
return result;
}
function isBlank(text) {
return text.match(/^\s*$/);
}
function isComment(text) {
return text.match(/^\s*[#!].*$/);
}
function isMultiline(text) {
return text.match(/^.*\\\s*$/g);
}
/**
* Splits the line into up to 3 parts: key, separator and value.
* Returns the indexes for the separator and the value, if they are found, or -1 otherwise.
*/
function splitKeySepValue(text) {
var indexes = [-1,-1];
var escape = false;
var INIT=-1, KEY=0, SEP=1;
var state = INIT;
var hardSepFound = false;
for(var i = 0; i < text.length; i++) {
var c = text.charAt(i);
switch(state) {
case INIT:
if(!isSoftSeparator(c)){
if(isSeparator(c)) {
state = SEP;
indexes[0] = i;
} else {
state = KEY;
}
}
break;
case KEY:
if(!escape && isSeparator(c)) {
state = SEP;
indexes[0] = i;
}
hardSepFound = isHardSeparator(c);
break;
case SEP:
if(!isSeparator(c) || (hardSepFound && isHardSeparator(c))) {
indexes[1] = i;
return indexes;
}
hardSepFound = isHardSeparator(c);
break;
}
escape = c === '\\';
}
return indexes;
}
/**
* Creates a new constructor and pushes it to the result.
* @param result
* @param text
* @param index
* @param css
*/
function pushResult(result, text, index, css){
var constructor = SyntaxHighlighter.Match;
var unicodeIndex = findUnicodeEscapeIndex(text);
while(unicodeIndex != -1) {
if(unicodeIndex > 0) {
var textBefore = text.substring(0, unicodeIndex);
result.push(new constructor(textBefore, index, css));
}
var escape = text.substr(unicodeIndex, 6);
result.push(new constructor(escape, index + unicodeIndex, 'keyword'));
text = text.substring(unicodeIndex + 6, text.length);
index = index + unicodeIndex + 6;
unicodeIndex = findUnicodeEscapeIndex(text);
}
if(text != '') {
result.push(new constructor(text, index, css));
}
}
/**
* Locates unicode escape sequences of the form "\u" + four hex digits.
* @param text
* @return the index of the escape sequence start
*/
function findUnicodeEscapeIndex(text) {
var escape = false;
var started = false;
for(var i = 0; i < text.length; i++) {
var c = text.charAt(i);
if(c === '\\'){
escape = true;
} else {
if(escape && c === 'u') {
return i - 1;
}
escape = false;
}
}
return -1;
}
function isSeparator(c) {
return c === '=' || c === ':' || c === ' ' || c === '\t';
}
function isHardSeparator(c) {
return c === '=' || c === ':';
}
function isSoftSeparator(c) {
return c === ' ' || c === '\t';
}
var multilineValue = false;
var multilineKey = false;
var currentIndex = -1;
this.regexList = [
{ regex: /^.+$/gm, func: process }
];
};
Brush.prototype = new SyntaxHighlighter.Highlighter();
Brush.aliases = ['properties'];
SyntaxHighlighter.brushes.Properties = Brush;
// CommonJS
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
})();