diff --git a/experiments/worker.html b/experiments/worker.html new file mode 100644 index 00000000..f3c75bde --- /dev/null +++ b/experiments/worker.html @@ -0,0 +1,33 @@ + + + + + + worker + + + + + + + + + + diff --git a/experiments/worker.js b/experiments/worker.js new file mode 100644 index 00000000..1335f55e --- /dev/null +++ b/experiments/worker.js @@ -0,0 +1,3 @@ +onmessage = function(e) { + onmessage = new Function("e", e.data); +}; \ No newline at end of file diff --git a/lib/ace/WorkerTokenizer.js b/lib/ace/WorkerTokenizer.js new file mode 100644 index 00000000..743f9936 --- /dev/null +++ b/lib/ace/WorkerTokenizer.js @@ -0,0 +1,91 @@ +/** + * Ajax.org Code Editor (ACE) + * + * @copyright 2010, Ajax.org Services B.V. + * @license LGPLv3 + * @author Fabian Jakobs + */ +require.def("ace/WorkerTokenizer", ["ace/lib/oop", "ace/MEventEmitter"], function(oop, MEventEmitter) { + +var WorkerTokenizer = function(tokenizer) { + var workerUrl = require.nameToUrl("ace/worker", null, "_"); + this.$worker = new Worker(workerUrl); + + this.callbackId = 1; + this.callbacks = {}; + + var _self = this; + this.$worker.onerror = function(e) { + throw e; + }; + this.$worker.onmessage = function(e) { + var msg = e.data; + //console.log("rec", msg) + switch(msg.type) { + case "log": + console.log(msg.data); + break; + + case "event": + _self.$dispatchEvent(msg.name, {data: msg.data}); + break; + + case "call": + var callback = _self.callbacks[msg.id]; + if (callback) { + callback(msg.data); + delete _self.callbacks[msg.id]; + } + break; + } + }; +}; + +(function(){ + + oop.implement(this, MEventEmitter); + + this.$send = function(cmd, args) { + this.$worker.postMessage({command: cmd, args: args}); + }; + + this.$call = function(cmd, args, callback) { + var id = this.callbackId++; + this.callbacks[id] = callback; + args.push(id); + this.$send(cmd, args); + }; + + this.setTokenizer = function(tokenizer) { + this.$send("setRules", ["ace/mode/JavaScriptHighlightRules"]); + }; + + this.setLines = function(textLines) { + this.lines = textLines; + this.$send("setLines", [textLines]); + }; + + this.start = function(startRow) { + // TODO don't send all lines on each update!! + this.$send("setLines", [this.lines]); + this.$send("start", [startRow]) + }; + + this.stop = function() { + this.$send("stop", []) + }; + + this.getTokens = function(firstRow, lastRow, callback) { + this.$call("getTokens", [firstRow, lastRow], function(tokens) { + callback(tokens) + }); + }; + + this.getState = function(row, callback) { + this.$call("getState", [row], callback); + }; + +}).call(WorkerTokenizer.prototype); + +return WorkerTokenizer; +}); diff --git a/lib/ace/worker.js b/lib/ace/worker.js new file mode 100644 index 00000000..f90819f1 --- /dev/null +++ b/lib/ace/worker.js @@ -0,0 +1,163 @@ +postMessage("Juhu Kinners"); + +var console = { + log: function(msg) { + postMessage({type: "log", data: msg}); + } +}; +var window = { + console: console +}; + +var require = function(name) { + if (require.modules[name]) + return require.modules[name]; + + importScripts(require.baseUrl + "/" + name + ".js"); + return require.modules[name]; +}; + +require.def = function(name, deps, callback) { + if (!callback) { + callback = deps; + deps = []; + } + var modules = deps.map(function(dep) { + return require(dep); + }); + require.modules[name] = callback.apply(this, modules); +}; + +require.baseUrl = ".."; +require.modules = {}; + +var Tokenizer = require("ace/Tokenizer"); + +var bgtokenizer = { + running: false, + textLines: [], + lines: [], + currentLine: 0, + tokenizer: null, + + init: function() { + var self = this; + + this.$worker = function() { + if (!self.running) { return; } + + var workerStart = new Date(); + var startLine = self.currentLine; + var textLines = self.textLines; + + var processedLines = 0; + + while (self.currentLine < textLines.length) { + self.lines[self.currentLine] = self.$tokenizeRows(self.currentLine, self.currentLine)[0]; + self.currentLine++; + + // only check every 5 lines + processedLines += 1; + if ((processedLines % 5 == 0) && (new Date() - workerStart) > 40) { + self.$event("update", {first: startLine, last: self.currentLine-1}); + self.running = setTimeout(self.$worker, 0); + return; + } + } + + self.running = false; + self.$event("update", {first: startLine, last: textLines.length - 1}); + }; + }, + + setRules: function(rules) { + var Rules = require(rules); + this.tokenizer = new Tokenizer(new Rules().getRules()); + this.lines = []; + + this.start(0); + }, + + setLines: function(textLines) { + this.textLines = textLines; + this.lines = []; + + this.stop(); + }, + + start: function(startRow) { + this.currentLine = Math.min(startRow || 0, this.currentLine, + this.textLines.length); + + // remove all cached items below this line + this.lines.splice(this.currentLine, this.lines.length); + + this.stop(); + this.running = setTimeout(this.$worker, 0); + }, + + stop: function() { + if (this.running) + clearTimeout(this.running); + + this.running = false; + }, + + getTokens: function(firstRow, lastRow, callbackId) { + this.$callback(this.$tokenizeRows(firstRow, lastRow), callbackId); + }, + + getState: function(row, callbackId) { + this.$callback(this.$tokenizeRows(row, row)[0].state, callbackId); + }, + + $tokenizeRows: function(firstRow, lastRow) { + var rows = []; + + // determin start state + var state = "start"; + var doCache = false; + if (firstRow > 0 && this.lines[firstRow - 1]) { + state = this.lines[firstRow - 1].state; + doCache = true; + } + + for (var row=firstRow; row<=lastRow; row++) { + if (!this.lines[row]) { + var tokens = this.tokenizer.getLineTokens(this.textLines[row] || "", state); + var state = tokens.state; + rows.push(tokens); + + if (doCache) { + this.lines[row] = tokens; + } + } + else + rows.push(this.lines[row]); + } + return rows; + }, + + $callback: function(data, callbackId) { + postMessage({ + type: "call", + id: callbackId, + data: data + }); + }, + + $event: function(name, data) { + postMessage({ + type: "event", + name: name, + data: data + }); + } +}; + +bgtokenizer.init(); + +var onmessage = function(e) { + var msg = e.data; + bgtokenizer[msg.command].apply(bgtokenizer, msg.args); +}; \ No newline at end of file