some improvements to syntax highlighter

This commit is contained in:
rolux 2011-05-08 22:38:51 +02:00
parent 0b629a1b40
commit 30ebbee085
5 changed files with 76 additions and 64 deletions

View file

@ -18,10 +18,14 @@ Ox.load('UI', {
$options = Ox.Element() $options = Ox.Element()
.append( .append(
Ox.FormElementGroup({ Ox.FormElementGroup({
elements: ['showLineNumbers', 'showLinebreaks', 'showTabs', 'showWhitespace'].map(function(v, i) { elements: [
'showLineNumbers', 'showLinebreaks', 'showTabs', 'showWhitespace', 'stripComments'
].map(function(v, i) {
return Ox.Checkbox({ return Ox.Checkbox({
overlap: 'right', overlap: 'right',
title: Ox.toDashes(v).split('-').map(function(v) { return Ox.toTitleCase(v); }).join(' '), title: Ox.toDashes(v).split('-').map(function(v) {
return Ox.toTitleCase(v);
}).join(' '),
width: 160 width: 160
}).bindEvent({ }).bindEvent({
change: function(event) { change: function(event) {

View file

@ -1455,23 +1455,24 @@ SyntaxHightlighter
*/ */
.OxSyntaxHighlighter > div { .OxSyntaxHighlighter > div {
display: table-cell;
padding: 4px;
font-family: Menlo, Monaco, DejaVu Sans Mono, Bitstream Vera Sans Mono, Consolas, Lucida Console; font-family: Menlo, Monaco, DejaVu Sans Mono, Bitstream Vera Sans Mono, Consolas, Lucida Console;
//line-height: 14px; //line-height: 14px;
} }
.OxSyntaxHighlighter > .OxLineNumbers { .OxSyntaxHighlighter > .OxLineNumbers {
padding: 4px;
text-align: right; text-align: right;
-moz-user-select: none; -moz-user-select: none;
-webkit-user-select: none; -webkit-user-select: none;
} }
.OxSyntaxHighlighter > .OxSourceCode { .OxSyntaxHighlighter > .OxSourceCode {
padding: 4px; white-space: nowrap;
-moz-user-select: text; -moz-user-select: text;
-webkit-user-select: text; -webkit-user-select: text;
} }
.OxSyntaxHighlighter > .OxSourceCode .OxLinebreak { .OxSyntaxHighlighter > .OxSourceCode .OxLinebreak {
-moz-user-select: none; //-moz-user-select: none;
-webkit-user-select: none; //-webkit-user-select: none;
} }
/* /*

View file

@ -1,12 +1,20 @@
// vim: et:ts=4:sw=4:sts=4:ft=js // vim: et:ts=4:sw=4:sts=4:ft=js
/*@ /*@
Ox.SyntaxHighlighter <function> Syntax Highlighter
(options[, self]) -> <o> Syntax Highlighter
options <o> Options
offset <n|1> First line number
showLineNumbers <b|false> If true, show line numbers
showLinebreaks <b|false> If true, show linebreaks
showWhitespace <b|false> If true, show whitespace
stripComments <b|false> If true, strip comments
self <o> Shared private
@*/ @*/
Ox.SyntaxHighlighter = function(options, self) { Ox.SyntaxHighlighter = function(options, self) {
self = self || {}; self = self || {};
var that = Ox.Element({}, self) var that = Ox.Element({}, self)
.defaults({ .defaults({
height: 40, height: 40,
@ -28,35 +36,24 @@ Ox.SyntaxHighlighter = function(options, self) {
renderSource(); renderSource();
function encodeToken(source, token) {
var linebreak = '<br/>',
tab = Ox.repeat('&nbsp;', self.options.tabLength);
if (self.options.showLinebreaks) {
if (token.type == 'linebreak') {
linebreak = '\u21A9' + linebreak;
} else {
linebreak = '<span class="OxLinebreak">\u21A9</span>' + linebreak;
}
}
if (self.options.showTabs) {
tab = '<span class="OxTab">\u2192' + tab.substr(6) + '</span>';
}
return Ox.encodeHTML(source)
.replace(/ /g, '&nbsp;')
.replace(/\t/g, tab)
.replace(/\n/g, linebreak);
}
function renderSource() { function renderSource() {
var lines, source = '', tokens,
linebreak = (
self.options.showLinebreaks ?
'<span class="OxLinebreak">\u21A9</span>' : ''
) + '<br/>',
tab = (
self.options.showTabs ?
'<span class="OxTab">\u2192</span>' : ''
) + Ox.repeat('&nbsp;', self.options.tabLength - self.options.showTabs),
whitespace = self.options.showWhitespace ? '\u00B7' : '&nbsp;';
self.options.source = self.options.source self.options.source = self.options.source
.replace(/\r\n/g, '\n') .replace(/\r\n/g, '\n')
.replace(/\r/g, '\n'); .replace(/\r/g, '\n');
self.cursor = 0; tokens = Ox.tokenize(self.options.source);
self.source = ''; tokens.forEach(function(token, i) {
self.tokens = Ox.tokenize(self.options.source);
self.tokens.forEach(function(token, i) {
var classNames, var classNames,
source = self.options.source.substr(token.offset, token.length); substr = self.options.source.substr(token.offset, token.length);
if ( if (
!(self.options.stripComments && token.type == 'comment') !(self.options.stripComments && token.type == 'comment')
) { ) {
@ -68,48 +65,61 @@ Ox.SyntaxHighlighter = function(options, self) {
classNames += ' OxTrailing' classNames += ' OxTrailing'
} }
} }
self.source += '<span class="' + classNames + '">' + source += '<span class="' + classNames + '">' +
encodeToken(source, token.type) + '</span>'; Ox.encodeHTML(substr)
.replace(/ /g, whitespace)
.replace(/\t/g, tab)
.replace(/\n/g, linebreak) + '</span>';
} }
self.cursor += token.length;
function isAfterLinebreak() { function isAfterLinebreak() {
return i == 0 || return i == 0 ||
self.tokens[i - 1].type == 'linebreak'; tokens[i - 1].type == 'linebreak';
} }
function isBeforeLinebreak() { function isBeforeLinebreak() {
return i == self.tokens.length - 1 || return i == tokens.length - 1 ||
self.tokens[i + 1].type == 'linebreak'; tokens[i + 1].type == 'linebreak';
} }
function hasIrregularSpaces() { function hasIrregularSpaces() {
return source.split('').reduce(function(prev, curr) { return substr.split('').reduce(function(prev, curr) {
return prev + (curr == ' ' ? 1 : 0); return prev + (curr == ' ' ? 1 : 0);
}, 0) % self.options.tabLength; }, 0) % self.options.tabLength;
} }
}); });
self.lines = self.source.split('<br/>'); lines = source.split('<br/>');
that.empty(); that.empty();
///*
var $test = new Ox.Element()
.css({
position: 'absolute',
top: '-1000px'
})
.html(Ox.repeat('&nbsp;', self.options.lineLength))
.appendTo(that);
var width = $test.width() + 4; // add padding
$test.removeElement();
//*/
if (self.options.showLineNumbers) { if (self.options.showLineNumbers) {
self.$lineNumbers = new Ox.Element() self.$lineNumbers = new Ox.Element()
.addClass('OxLineNumbers') .addClass('OxLineNumbers')
.css({ .html(
display: 'table-cell', Ox.range(lines.length).map(function(line) {
padding: '4px', return (line + self.options.offset);
}) }).join('<br/>')
.html( )
Ox.range(self.lines.length).map(function(line) { .appendTo(that);
return (line + self.options.offset);
}).join('<br/>')
)
.appendTo(that);
} }
self.$source = new Ox.Element() self.$source = new Ox.Element()
.addClass('OxSourceCode') .addClass('OxSourceCode')
.css({ .css({
display: 'table-cell', background: '-moz-linear-gradient(left, rgb(255, 255, 255), rgb(255, 255, 255) ' +
padding: '4px' width + 'px, rgb(248, 248, 248) ' + width + 'px, rgb(248, 248, 248))'
}) })
.html(self.source) .css({
background: '-webkit-linear-gradient(left, rgb(255, 255, 255) ' +
width + 'px, rgb(192, 192, 192) ' + width + 'px, rgb(255, 255, 255) ' +
(width + 1) + 'px)'
})
.html(source)
.appendTo(that); .appendTo(that);
} }

View file

@ -421,6 +421,9 @@ SyntaxHighlighter
.OxThemeClassic .OxSourceCode .OxTab { .OxThemeClassic .OxSourceCode .OxTab {
color: rgb(192, 192, 192); color: rgb(192, 192, 192);
} }
.OxThemeClassic .OxSourceCode .OxWhitespace {
color: rgb(192, 192, 192);
}
.OxThemeClassic .OxSourceCode .OxWhitespace.OxLeading, .OxThemeClassic .OxSourceCode .OxWhitespace.OxLeading,
.OxThemeClassic .OxSourceCode .OxWhitespace.OxTrailing { .OxThemeClassic .OxSourceCode .OxWhitespace.OxTrailing {
background: rgb(255, 128, 128); background: rgb(255, 128, 128);

View file

@ -3950,11 +3950,9 @@ Ox.repeat = function(val, num) {
var ret; var ret;
if (Ox.isArray(val)) { if (Ox.isArray(val)) {
ret = []; ret = [];
if (num >= 1) { num >= 1 && Ox.loop(num, function() {
Ox.loop(num, function() { ret = Ox.merge(ret, val);
ret = Ox.merge(ret, val); });
});
}
} else { } else {
ret = num >= 1 ? new Array(num + 1).join(val.toString()) : ''; ret = num >= 1 ? new Array(num + 1).join(val.toString()) : '';
} }
@ -4463,10 +4461,6 @@ Ox.isRegExp <f> Tests if a value is a regular expression
@*/ @*/
Ox.isRegExp = function(val) { Ox.isRegExp = function(val) {
/*
>>> Ox.isRegExp(/ /)
true
*/
return val instanceof RegExp; return val instanceof RegExp;
}; };