From 30ebbee0856a08cfa0d1e2ce02fee3b505b082bb Mon Sep 17 00:00:00 2001 From: rolux Date: Sun, 8 May 2011 22:38:51 +0200 Subject: [PATCH] some improvements to syntax highlighter --- demos/syntax/js/syntax.js | 8 +- source/Ox.UI/css/Ox.UI.css | 9 +- source/Ox.UI/js/Core/Ox.SyntaxHighlighter.js | 108 ++++++++++--------- source/Ox.UI/themes/classic/css/classic.css | 3 + source/Ox.js | 12 +-- 5 files changed, 76 insertions(+), 64 deletions(-) diff --git a/demos/syntax/js/syntax.js b/demos/syntax/js/syntax.js index b9e98c4e..b13112af 100644 --- a/demos/syntax/js/syntax.js +++ b/demos/syntax/js/syntax.js @@ -18,10 +18,14 @@ Ox.load('UI', { $options = Ox.Element() .append( Ox.FormElementGroup({ - elements: ['showLineNumbers', 'showLinebreaks', 'showTabs', 'showWhitespace'].map(function(v, i) { + elements: [ + 'showLineNumbers', 'showLinebreaks', 'showTabs', 'showWhitespace', 'stripComments' + ].map(function(v, i) { return Ox.Checkbox({ 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 }).bindEvent({ change: function(event) { diff --git a/source/Ox.UI/css/Ox.UI.css b/source/Ox.UI/css/Ox.UI.css index 96d66eb5..bb090f32 100644 --- a/source/Ox.UI/css/Ox.UI.css +++ b/source/Ox.UI/css/Ox.UI.css @@ -1455,23 +1455,24 @@ SyntaxHightlighter */ .OxSyntaxHighlighter > div { + display: table-cell; + padding: 4px; font-family: Menlo, Monaco, DejaVu Sans Mono, Bitstream Vera Sans Mono, Consolas, Lucida Console; //line-height: 14px; } .OxSyntaxHighlighter > .OxLineNumbers { - padding: 4px; text-align: right; -moz-user-select: none; -webkit-user-select: none; } .OxSyntaxHighlighter > .OxSourceCode { - padding: 4px; + white-space: nowrap; -moz-user-select: text; -webkit-user-select: text; } .OxSyntaxHighlighter > .OxSourceCode .OxLinebreak { - -moz-user-select: none; - -webkit-user-select: none; + //-moz-user-select: none; + //-webkit-user-select: none; } /* diff --git a/source/Ox.UI/js/Core/Ox.SyntaxHighlighter.js b/source/Ox.UI/js/Core/Ox.SyntaxHighlighter.js index ce7b6152..fe88a7e3 100644 --- a/source/Ox.UI/js/Core/Ox.SyntaxHighlighter.js +++ b/source/Ox.UI/js/Core/Ox.SyntaxHighlighter.js @@ -1,12 +1,20 @@ // vim: et:ts=4:sw=4:sts=4:ft=js /*@ - +Ox.SyntaxHighlighter Syntax Highlighter + (options[, self]) -> Syntax Highlighter + options Options + offset First line number + showLineNumbers If true, show line numbers + showLinebreaks If true, show linebreaks + showWhitespace If true, show whitespace + stripComments If true, strip comments + self Shared private @*/ Ox.SyntaxHighlighter = function(options, self) { - self = self || {}; + self = self || {}; var that = Ox.Element({}, self) .defaults({ height: 40, @@ -28,35 +36,24 @@ Ox.SyntaxHighlighter = function(options, self) { renderSource(); - function encodeToken(source, token) { - var linebreak = '
', - tab = Ox.repeat(' ', self.options.tabLength); - if (self.options.showLinebreaks) { - if (token.type == 'linebreak') { - linebreak = '\u21A9' + linebreak; - } else { - linebreak = '\u21A9' + linebreak; - } - } - if (self.options.showTabs) { - tab = '\u2192' + tab.substr(6) + ''; - } - return Ox.encodeHTML(source) - .replace(/ /g, ' ') - .replace(/\t/g, tab) - .replace(/\n/g, linebreak); - } - function renderSource() { + var lines, source = '', tokens, + linebreak = ( + self.options.showLinebreaks ? + '\u21A9' : '' + ) + '
', + tab = ( + self.options.showTabs ? + '\u2192' : '' + ) + Ox.repeat(' ', self.options.tabLength - self.options.showTabs), + whitespace = self.options.showWhitespace ? '\u00B7' : ' '; self.options.source = self.options.source .replace(/\r\n/g, '\n') .replace(/\r/g, '\n'); - self.cursor = 0; - self.source = ''; - self.tokens = Ox.tokenize(self.options.source); - self.tokens.forEach(function(token, i) { + tokens = Ox.tokenize(self.options.source); + tokens.forEach(function(token, i) { var classNames, - source = self.options.source.substr(token.offset, token.length); + substr = self.options.source.substr(token.offset, token.length); if ( !(self.options.stripComments && token.type == 'comment') ) { @@ -68,48 +65,61 @@ Ox.SyntaxHighlighter = function(options, self) { classNames += ' OxTrailing' } } - self.source += '' + - encodeToken(source, token.type) + ''; + source += '' + + Ox.encodeHTML(substr) + .replace(/ /g, whitespace) + .replace(/\t/g, tab) + .replace(/\n/g, linebreak) + ''; } - self.cursor += token.length; function isAfterLinebreak() { return i == 0 || - self.tokens[i - 1].type == 'linebreak'; + tokens[i - 1].type == 'linebreak'; } function isBeforeLinebreak() { - return i == self.tokens.length - 1 || - self.tokens[i + 1].type == 'linebreak'; + return i == tokens.length - 1 || + tokens[i + 1].type == 'linebreak'; } function hasIrregularSpaces() { - return source.split('').reduce(function(prev, curr) { + return substr.split('').reduce(function(prev, curr) { return prev + (curr == ' ' ? 1 : 0); }, 0) % self.options.tabLength; } }); - self.lines = self.source.split('
'); - + lines = source.split('
'); that.empty(); + ///* + var $test = new Ox.Element() + .css({ + position: 'absolute', + top: '-1000px' + }) + .html(Ox.repeat(' ', self.options.lineLength)) + .appendTo(that); + var width = $test.width() + 4; // add padding + $test.removeElement(); + //*/ if (self.options.showLineNumbers) { self.$lineNumbers = new Ox.Element() - .addClass('OxLineNumbers') - .css({ - display: 'table-cell', - padding: '4px', - }) - .html( - Ox.range(self.lines.length).map(function(line) { - return (line + self.options.offset); - }).join('
') - ) - .appendTo(that); + .addClass('OxLineNumbers') + .html( + Ox.range(lines.length).map(function(line) { + return (line + self.options.offset); + }).join('
') + ) + .appendTo(that); } self.$source = new Ox.Element() .addClass('OxSourceCode') .css({ - display: 'table-cell', - padding: '4px' + background: '-moz-linear-gradient(left, rgb(255, 255, 255), rgb(255, 255, 255) ' + + 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); } diff --git a/source/Ox.UI/themes/classic/css/classic.css b/source/Ox.UI/themes/classic/css/classic.css index 58ec426d..61c0664e 100644 --- a/source/Ox.UI/themes/classic/css/classic.css +++ b/source/Ox.UI/themes/classic/css/classic.css @@ -421,6 +421,9 @@ SyntaxHighlighter .OxThemeClassic .OxSourceCode .OxTab { color: rgb(192, 192, 192); } +.OxThemeClassic .OxSourceCode .OxWhitespace { + color: rgb(192, 192, 192); +} .OxThemeClassic .OxSourceCode .OxWhitespace.OxLeading, .OxThemeClassic .OxSourceCode .OxWhitespace.OxTrailing { background: rgb(255, 128, 128); diff --git a/source/Ox.js b/source/Ox.js index 3b408792..305c6435 100644 --- a/source/Ox.js +++ b/source/Ox.js @@ -3950,11 +3950,9 @@ Ox.repeat = function(val, num) { var ret; if (Ox.isArray(val)) { ret = []; - if (num >= 1) { - Ox.loop(num, function() { - ret = Ox.merge(ret, val); - }); - } + num >= 1 && Ox.loop(num, function() { + ret = Ox.merge(ret, val); + }); } else { ret = num >= 1 ? new Array(num + 1).join(val.toString()) : ''; } @@ -4463,10 +4461,6 @@ Ox.isRegExp Tests if a value is a regular expression @*/ Ox.isRegExp = function(val) { - /* - >>> Ox.isRegExp(/ /) - true - */ return val instanceof RegExp; };