summaryrefslogtreecommitdiff
path: root/gstudio/static/gstudio/js/Gnowmacs/src/js/ymacs-tokenizer.js
diff options
context:
space:
mode:
Diffstat (limited to 'gstudio/static/gstudio/js/Gnowmacs/src/js/ymacs-tokenizer.js')
-rw-r--r--gstudio/static/gstudio/js/Gnowmacs/src/js/ymacs-tokenizer.js335
1 files changed, 335 insertions, 0 deletions
diff --git a/gstudio/static/gstudio/js/Gnowmacs/src/js/ymacs-tokenizer.js b/gstudio/static/gstudio/js/Gnowmacs/src/js/ymacs-tokenizer.js
new file mode 100644
index 00000000..986f6bc0
--- /dev/null
+++ b/gstudio/static/gstudio/js/Gnowmacs/src/js/ymacs-tokenizer.js
@@ -0,0 +1,335 @@
+//> This file is part of Ymacs, an Emacs-like editor for the Web
+//> http://www.ymacs.org/
+//>
+//> Copyright (c) 2009-2010, Mihai Bazon, Dynarch.com. All rights reserved.
+//>
+//> Redistribution and use in source and binary forms, with or without
+//> modification, are permitted provided that the following conditions are
+//> met:
+//>
+//> * Redistributions of source code must retain the above copyright
+//> notice, this list of conditions and the following disclaimer.
+//>
+//> * Redistributions in binary form must reproduce the above copyright
+//> notice, this list of conditions and the following disclaimer in
+//> the documentation and/or other materials provided with the
+//> distribution.
+//>
+//> * Neither the name of Dynarch.com nor the names of its contributors
+//> may be used to endorse or promote products derived from this
+//> software without specific prior written permission.
+//>
+//> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+//> EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+//> IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+//> PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE
+//> FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+//> CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+//> SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+//> INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+//> CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+//> ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+//> THE POSSIBILITY OF SUCH DAMAGE.
+
+// @require ymacs-buffer.js
+
+DEFINE_CLASS("Ymacs_Stream", null, function(D, P){
+
+ D.DEFAULT_ARGS = {
+ buffer : [ "buffer" , null ],
+ line : [ "line" , 0 ],
+ col : [ "col" , 0]
+ };
+
+ P.nextCol = function() {
+ ++this.col;
+ };
+
+ P.prevCol = function() {
+ --this.col;
+ };
+
+ P.nextLine = function() {
+ ++this.line;
+ this.col = 0;
+ };
+
+ P.prevLine = function() {
+ --this.line;
+ this.col = 0;
+ };
+
+ P.peek = function(n) {
+ if (n == null) n = 0;
+ return this.buffer.code[this.line].charAt(this.col + n);
+ };
+
+ P.get = function() {
+ var ch = this.peek();
+ this.nextCol();
+ return ch;
+ };
+
+ P.lineText = function(row) {
+ if (row == null)
+ row = this.line;
+ return this.buffer.code[row];
+ };
+
+ P.lineIndentation = function(row) {
+ return /^\s*/.exec(this.lineText(row))[0].length;
+ };
+ P.lookingAt = function(what) {
+ var line = this.buffer.code[this.line];
+ if (what instanceof RegExp) {
+ return what.exec(line.substr(this.col));
+ } else {
+ return line.substr(this.col, what.length) == what;
+ }
+ };
+
+
+ P.textBefore = function(pos) {
+ if (pos == null)
+ pos = this.buffer._rowColToPosition(this.line, this.col);
+ return this.buffer.getCode().substr(0, pos);
+ };
+
+ P.textAfter = function(pos) {
+ if (pos == null)
+ pos = this.buffer._rowColToPosition(this.line, this.col);
+ return this.buffer.getCode().substr(pos);
+ };
+
+ P.substring = function(start, end) {
+ return this.buffer.getCode().substring(start, end);
+ };
+
+ P.substr = function(start, end) {
+ return this.buffer.getCode().substr(start, end);
+ };
+
+ P.eol = function() {
+ return this.col == this.buffer.code[this.line].length;
+ };
+
+ P.eof = function() {
+ var n = this.buffer.code.length, l = this.line;
+ return l >= n || l == n - 1 && this.eol();
+ };
+
+ P.length = function() {
+ return this.buffer.code.length;
+ };
+
+ P.lineLength = function(line) {
+ if (line == null)
+ line = this.line;
+ return this.buffer.code[line].length;
+ };
+
+ P.save = function() {
+ return { buffer: this.buffer, line: this.line, col: this.col };
+ };
+
+ P.restore = function(state) {
+ this.buffer = state.buffer;
+ this.line = state.line;
+ this.col = state.col;
+ };
+
+ P.checkStop = function() {
+ if (this.eof()) throw this.EOF;
+ if (this.eol()) throw this.EOL;
+ };
+
+ P.EOL = new (function(){});
+
+ P.EOF = new (function(){});
+
+});
+
+DEFINE_CLASS("Ymacs_Tokenizer", DlEventProxy, function(D, P){
+
+ var LANGUAGES = {};
+
+ D.define = function(name, func) {
+ LANGUAGES[name.toLowerCase()] = func;
+ };
+
+ D.DEFAULT_EVENTS = [ "onFoundToken" ];
+
+ D.DEFAULT_ARGS = {
+ buffer : [ "buffer", null ],
+ type : [ "type", null ]
+ };
+
+ D.FIXARGS = function(args) {
+ if (typeof args.type == "string")
+ args.type = LANGUAGES[args.type.toLowerCase()];
+ };
+
+ D.CONSTRUCT = function() {
+ var smallest = null;
+ var timer = null;
+ this.quickUpdate = function(offset) {
+ var row = this.buffer._positionToRowCol(offset).row;
+ this.parsers.splice(row - 1, this.parsers.length + 1);
+
+ if (smallest != null) {
+ smallest = Math.min(row, smallest);
+ } else {
+ smallest = row;
+ }
+ clearTimeout(timer);
+ timer = function(){
+ this._do_quickUpdate(smallest);
+ smallest = null;
+ }.delayed(1, this);
+ };
+ this._stopQuickUpdate = function() {
+ clearTimeout(timer);
+ clearTimeout(this.timerUpdate);
+ };
+ this.reset();
+ };
+
+ P.reset = function() {
+ this.stream = new Ymacs_Stream({ buffer: this.buffer });
+ this.theParser = this.type(this.stream, this);
+ this.parsers = [];
+ this.parsers[-1] = this.theParser.copy();
+ this.timerUpdate = null;
+ this.quickUpdate(0);
+ };
+
+ P.getLanguage = function(name) {
+ return LANGUAGES[name](this.stream, this);
+ };
+
+ P.showProgress = function(p) {
+ if (p != null) {
+ p = Math.round(p / this.stream.length() * 100) + "%";
+ }
+ this.buffer.updateProgress("Syntax highlighting", p);
+ };
+
+ P._do_quickUpdate = function(row) {
+ this._stopQuickUpdate();
+ var s = this.stream, p, a = this.parsers, n;
+ s.line = row - 1;
+ while (!(p = a[s.line]))
+ s.prevLine();
+ s.nextLine();
+ p = p();
+ var iteration = 0;
+ var first = true;
+ var doit = function() {
+ this.buffer.preventUpdates();
+ n = first ? 3 : 20;
+ if (++iteration > 10)
+ this.showProgress(this.stream.line);
+ while (true) {
+ try {
+ while (true) p.next();
+ }
+ catch(ex) {
+ if (ex === s.EOL) {
+ a[s.line] = p.copy();
+ s.nextLine();
+ if (--n == 0) {
+ this.buffer.resumeUpdates();
+ this.timerUpdate = setTimeout(doit, first ? 500 : 50);
+ first = false;
+ return;
+ }
+ }
+ else if (ex === s.EOF) {
+ a[s.line] = p.copy();
+ this.buffer.resumeUpdates();
+ if (p.on_EOF)
+ p.on_EOF();
+ break;
+ }
+ else throw ex;
+ }
+ }
+ this.showProgress();
+ }.$(this);
+ doit();
+ };
+
+ P.quickInsertLine = function(row) {
+ this.parsers.splice(row, this.parsers.length + 1);
+ };
+
+ P.quickDeleteLine = function(row) {
+ this.parsers.splice(row, this.parsers.length + 1);
+ };
+
+ P.onToken = function(line, c1, c2, type) {
+ this.callHooks("onFoundToken", line, c1, c2, type);
+ };
+
+ P.getParserForLine = function(row) {
+ this._stopQuickUpdate();
+ var s = this.stream, p, a = this.parsers, n;
+ var currentLine = s.line;
+ s.line = row - 1;
+ while (!(p = a[s.line]))
+ s.prevLine();
+ s.nextLine();
+ p = p();
+ try {
+ this.buffer.preventUpdates();
+ while (true) {
+ if (s.line == row) {
+ return p;
+ }
+ try {
+ while (true) p.next();
+ } catch(ex) {
+ if (ex === s.EOL) {
+ a[s.line] = p.copy();
+ s.nextLine();
+ }
+ else if (ex === s.EOF) {
+ break;
+ }
+ else {
+ throw ex;
+ }
+ }
+ }
+ } finally {
+ this.buffer.resumeUpdates();
+ // if (currentLine < s.length()) {
+ // // resume lazy tokenizer if it was interrupted
+ // this.timerUpdate = this._do_quickUpdate.delayed(50, this, Math.min(row, currentLine));
+ // }
+ if (s.line < s.length())
+ this.timerUpdate = this._do_quickUpdate.delayed(50, this, s.line);
+ }
+ };
+
+ P.reparseAll = function() {
+ this.parsers.splice(0, this.parsers.length);
+ return this.finishParsing();
+ };
+
+ P.finishParsing = function() {
+ this.getParserForLine(this.stream.length());
+ return this.getLastParser();
+ };
+
+ P.getLastParser = function() {
+ return this.parsers.peek();
+ };
+
+ P.getIndentation = function(row, buffer) {
+ var p = this.getParserForLine(row);
+ if (p && p.indentation instanceof Function)
+ return p.indentation(buffer);
+ };
+
+});