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