diff --git a/.gitmodules b/.gitmodules
index aee8d549..6074430c 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,3 @@
-[submodule "support/node-o3-xml"]
- path = support/node-o3-xml
- url = git://github.com/ajaxorg/node-o3-xml.git
[submodule "support/cockpit"]
path = support/cockpit
url = git://github.com/ajaxorg/cockpit.git
diff --git a/demo/icons/Readme.txt b/demo/icons/Readme.txt
new file mode 100644
index 00000000..87a71c8d
--- /dev/null
+++ b/demo/icons/Readme.txt
@@ -0,0 +1 @@
+The icons in this folder are from the Eclipse project and licensed under the Eclipse public license version 1.0 (EPL).
\ No newline at end of file
diff --git a/demo/icons/epl.html b/demo/icons/epl.html
new file mode 100644
index 00000000..f57b834b
--- /dev/null
+++ b/demo/icons/epl.html
@@ -0,0 +1,260 @@
+
+
+
+
+Eclipse Public License - Version 1.0
+
+
+
+
+
+
+Eclipse Public License - v 1.0
+
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
+PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR
+DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS
+AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+a) in the case of the initial Contributor, the initial
+code and documentation distributed under this Agreement, and
+b) in the case of each subsequent Contributor:
+i) changes to the Program, and
+ii) additions to the Program;
+where such changes and/or additions to the Program
+originate from and are distributed by that particular Contributor. A
+Contribution 'originates' from a Contributor if it was added to the
+Program by such Contributor itself or anyone acting on such
+Contributor's behalf. Contributions do not include additions to the
+Program which: (i) are separate modules of software distributed in
+conjunction with the Program under their own license agreement, and (ii)
+are not derivative works of the Program.
+
+"Contributor" means any person or entity that distributes
+the Program.
+
+"Licensed Patents" mean patent claims licensable by a
+Contributor which are necessarily infringed by the use or sale of its
+Contribution alone or when combined with the Program.
+
+"Program" means the Contributions distributed in accordance
+with this Agreement.
+
+"Recipient" means anyone who receives the Program under
+this Agreement, including all Contributors.
+
+2. GRANT OF RIGHTS
+
+a) Subject to the terms of this Agreement, each
+Contributor hereby grants Recipient a non-exclusive, worldwide,
+royalty-free copyright license to reproduce, prepare derivative works
+of, publicly display, publicly perform, distribute and sublicense the
+Contribution of such Contributor, if any, and such derivative works, in
+source code and object code form.
+
+b) Subject to the terms of this Agreement, each
+Contributor hereby grants Recipient a non-exclusive, worldwide,
+royalty-free patent license under Licensed Patents to make, use, sell,
+offer to sell, import and otherwise transfer the Contribution of such
+Contributor, if any, in source code and object code form. This patent
+license shall apply to the combination of the Contribution and the
+Program if, at the time the Contribution is added by the Contributor,
+such addition of the Contribution causes such combination to be covered
+by the Licensed Patents. The patent license shall not apply to any other
+combinations which include the Contribution. No hardware per se is
+licensed hereunder.
+
+c) Recipient understands that although each Contributor
+grants the licenses to its Contributions set forth herein, no assurances
+are provided by any Contributor that the Program does not infringe the
+patent or other intellectual property rights of any other entity. Each
+Contributor disclaims any liability to Recipient for claims brought by
+any other entity based on infringement of intellectual property rights
+or otherwise. As a condition to exercising the rights and licenses
+granted hereunder, each Recipient hereby assumes sole responsibility to
+secure any other intellectual property rights needed, if any. For
+example, if a third party patent license is required to allow Recipient
+to distribute the Program, it is Recipient's responsibility to acquire
+that license before distributing the Program.
+
+d) Each Contributor represents that to its knowledge it
+has sufficient copyright rights in its Contribution, if any, to grant
+the copyright license set forth in this Agreement.
+
+3. REQUIREMENTS
+
+A Contributor may choose to distribute the Program in object code
+form under its own license agreement, provided that:
+
+a) it complies with the terms and conditions of this
+Agreement; and
+
+b) its license agreement:
+
+i) effectively disclaims on behalf of all Contributors
+all warranties and conditions, express and implied, including warranties
+or conditions of title and non-infringement, and implied warranties or
+conditions of merchantability and fitness for a particular purpose;
+
+ii) effectively excludes on behalf of all Contributors
+all liability for damages, including direct, indirect, special,
+incidental and consequential damages, such as lost profits;
+
+iii) states that any provisions which differ from this
+Agreement are offered by that Contributor alone and not by any other
+party; and
+
+iv) states that source code for the Program is available
+from such Contributor, and informs licensees how to obtain it in a
+reasonable manner on or through a medium customarily used for software
+exchange.
+
+When the Program is made available in source code form:
+
+a) it must be made available under this Agreement; and
+
+b) a copy of this Agreement must be included with each
+copy of the Program.
+
+Contributors may not remove or alter any copyright notices contained
+within the Program.
+
+Each Contributor must identify itself as the originator of its
+Contribution, if any, in a manner that reasonably allows subsequent
+Recipients to identify the originator of the Contribution.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain
+responsibilities with respect to end users, business partners and the
+like. While this license is intended to facilitate the commercial use of
+the Program, the Contributor who includes the Program in a commercial
+product offering should do so in a manner which does not create
+potential liability for other Contributors. Therefore, if a Contributor
+includes the Program in a commercial product offering, such Contributor
+("Commercial Contributor") hereby agrees to defend and
+indemnify every other Contributor ("Indemnified Contributor")
+against any losses, damages and costs (collectively "Losses")
+arising from claims, lawsuits and other legal actions brought by a third
+party against the Indemnified Contributor to the extent caused by the
+acts or omissions of such Commercial Contributor in connection with its
+distribution of the Program in a commercial product offering. The
+obligations in this section do not apply to any claims or Losses
+relating to any actual or alleged intellectual property infringement. In
+order to qualify, an Indemnified Contributor must: a) promptly notify
+the Commercial Contributor in writing of such claim, and b) allow the
+Commercial Contributor to control, and cooperate with the Commercial
+Contributor in, the defense and any related settlement negotiations. The
+Indemnified Contributor may participate in any such claim at its own
+expense.
+
+For example, a Contributor might include the Program in a commercial
+product offering, Product X. That Contributor is then a Commercial
+Contributor. If that Commercial Contributor then makes performance
+claims, or offers warranties related to Product X, those performance
+claims and warranties are such Commercial Contributor's responsibility
+alone. Under this section, the Commercial Contributor would have to
+defend claims against the other Contributors related to those
+performance claims and warranties, and if a court requires any other
+Contributor to pay any damages as a result, the Commercial Contributor
+must pay those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
+PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION,
+ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
+OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
+responsible for determining the appropriateness of using and
+distributing the Program and assumes all risks associated with its
+exercise of rights under this Agreement , including but not limited to
+the risks and costs of program errors, compliance with applicable laws,
+damage to or loss of data, programs or equipment, and unavailability or
+interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
+NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
+WITHOUT LIMITATION LOST PROFITS), 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 OR
+DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under
+applicable law, it shall not affect the validity or enforceability of
+the remainder of the terms of this Agreement, and without further action
+by the parties hereto, such provision shall be reformed to the minimum
+extent necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against any entity
+(including a cross-claim or counterclaim in a lawsuit) alleging that the
+Program itself (excluding combinations of the Program with other
+software or hardware) infringes such Recipient's patent(s), then such
+Recipient's rights granted under Section 2(b) shall terminate as of the
+date such litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it
+fails to comply with any of the material terms or conditions of this
+Agreement and does not cure such failure in a reasonable period of time
+after becoming aware of such noncompliance. If all Recipient's rights
+under this Agreement terminate, Recipient agrees to cease use and
+distribution of the Program as soon as reasonably practicable. However,
+Recipient's obligations under this Agreement and any licenses granted by
+Recipient relating to the Program shall continue and survive.
+
+Everyone is permitted to copy and distribute copies of this
+Agreement, but in order to avoid inconsistency the Agreement is
+copyrighted and may only be modified in the following manner. The
+Agreement Steward reserves the right to publish new versions (including
+revisions) of this Agreement from time to time. No one other than the
+Agreement Steward has the right to modify this Agreement. The Eclipse
+Foundation is the initial Agreement Steward. The Eclipse Foundation may
+assign the responsibility to serve as the Agreement Steward to a
+suitable separate entity. Each new version of the Agreement will be
+given a distinguishing version number. The Program (including
+Contributions) may always be distributed subject to the version of the
+Agreement under which it was received. In addition, after a new version
+of the Agreement is published, Contributor may elect to distribute the
+Program (including its Contributions) under the new version. Except as
+expressly stated in Sections 2(a) and 2(b) above, Recipient receives no
+rights or licenses to the intellectual property of any Contributor under
+this Agreement, whether expressly, by implication, estoppel or
+otherwise. All rights in the Program not expressly granted under this
+Agreement are reserved.
+
+This Agreement is governed by the laws of the State of New York and
+the intellectual property laws of the United States of America. No party
+to this Agreement will bring a legal action under this Agreement more
+than one year after the cause of action arose. Each party waives its
+rights to a jury trial in any resulting litigation.
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/icons/error_obj.gif b/demo/icons/error_obj.gif
new file mode 100644
index 00000000..0bc60689
Binary files /dev/null and b/demo/icons/error_obj.gif differ
diff --git a/demo/icons/warning_obj.gif b/demo/icons/warning_obj.gif
new file mode 100644
index 00000000..2b2e50fe
Binary files /dev/null and b/demo/icons/warning_obj.gif differ
diff --git a/demo/startup.js b/demo/startup.js
index b62e79e3..1403fd1b 100644
--- a/demo/startup.js
+++ b/demo/startup.js
@@ -58,13 +58,43 @@ exports.launch = function(env) {
var vim = require("ace/keyboard/keybinding/vim").Vim;
var emacs = require("ace/keyboard/keybinding/emacs").Emacs;
var HashHandler = require("ace/keyboard/hash_handler").HashHandler;
-
+
var docs = {};
docs.js = new EditSession(document.getElementById("jstext").innerHTML);
docs.js.setMode(new JavaScriptMode());
docs.js.setUndoManager(new UndoManager());
-
+
+ if (false && window.Worker) {
+ var worker = new WorkerClient("../..", ["ace", "pilot"], "ace/worker/mirror", "Mirror");
+ worker.call("setValue", [docs.js.getValue()]);
+
+ docs.js.getDocument().on("change", function(e) {
+ e.range = {
+ start: e.data.range.start,
+ end: e.data.range.end
+ };
+ worker.emit("change", e);
+ });
+
+ worker.on("jslint", function(results) {
+ var errors = [];
+ for (var i=0; i
-
-
-
-
- Editor
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/editor.html b/editor.html
index f1b20bf5..30e67abb 100644
--- a/editor.html
+++ b/editor.html
@@ -6,66 +6,7 @@
Editor
-
-
+
diff --git a/experiments/capture.html b/experiments/capture.html
new file mode 100644
index 00000000..9df5e3cd
--- /dev/null
+++ b/experiments/capture.html
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/experiments/cut_copy.html b/experiments/cut_copy.html
new file mode 100644
index 00000000..3299f3ad
--- /dev/null
+++ b/experiments/cut_copy.html
@@ -0,0 +1,105 @@
+
+
+
+
+
+ Text Events
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/experiments/triple_click.html b/experiments/triple_click.html
new file mode 100644
index 00000000..da953a94
--- /dev/null
+++ b/experiments/triple_click.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+ triple_click
+
+
+
+
+
+
+ Juhu Kinners
+
+
+
+
+
+
+
+
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/css/editor.css b/lib/ace/css/editor.css
index adfa1511..f59da076 100644
--- a/lib/ace/css/editor.css
+++ b/lib/ace/css/editor.css
@@ -12,6 +12,20 @@
overflow-y: hidden;
}
+.ace_content {
+ position: absolute;
+ box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+}
+
+.ace_composition {
+ position: absolute;
+ background: #555;
+ color: #DDD;
+ z-index: 4;
+}
+
.ace_gutter {
position: absolute;
overflow-x: hidden;
@@ -61,8 +75,14 @@
color: black;
}
+.ace_cjk {
+ display: inline-block;
+ text-align: center;
+}
+
.ace_cursor-layer {
cursor: text;
+ pointer-events: none;
}
.ace_cursor {
diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js
index e9e2a66a..5ae0998c 100644
--- a/lib/ace/edit_session.js
+++ b/lib/ace/edit_session.js
@@ -52,16 +52,14 @@ var EditSession = function(text, mode) {
this.selection = new Selection(this);
this.$breakpoints = [];
- this.listeners = [];
- if (mode) {
- this.setMode(mode);
- }
-
if (text instanceof Document) {
this.setDocument(text)
} else {
this.setDocument(new Document(text));
}
+
+ if (mode)
+ this.setMode(mode);
};
@@ -198,6 +196,41 @@ var EditSession = function(text, mode) {
this._dispatchEvent("changeBreakpoint", {});
};
+ this.getBreakpoints = function() {
+ return this.$breakpoints;
+ };
+
+ /**
+ * Error:
+ * {
+ * row: 12,
+ * column: 2, //can be undefined
+ * text: "Missing argument",
+ * type: "error" // or "warning" or "info"
+ * }
+ */
+ this.setAnnotations = function(annotations) {
+ this.$annotations = [];
+ for (var i=0; i len) {
- remaining -= (len + 1);
- screenColumn += len + tabSize;
- }
- else {
- screenColumn += remaining;
- break;
- }
- }
+ var line = this.getLine(row);
+
+ for (var i=0; i 0) {
+ remaining -= 1;
+ // tab
+ if (c == 9) {
+ screenColumn += tabSize;
+ }
+ // CJK characters
+ else if (
+ c >= 0x3040 && c <= 0x309F || // Hiragana
+ c >= 0x30A0 && c <= 0x30FF || // Katakana
+ c >= 0x4E00 && c <= 0x9FFF || // Single CJK ideographs
+ c >= 0xF900 && c <= 0xFAFF ||
+ c >= 0x3400 && c <= 0x4DBF
+ ) {
+ screenColumn += 2;
+ } else {
+ screenColumn += 1;
+ }
+ } else {
+ break;
+ }
+ }
return screenColumn;
};
@@ -616,23 +667,44 @@ var EditSession = function(text, mode) {
var docColumn = 0;
var remaining = screenColumn;
-
- var line = this.getLine(row).split("\t");
- for (var i=0; i= len + tabSize) {
- remaining -= (len + tabSize);
- docColumn += (len + 1);
- }
- else if (remaining > len){
- docColumn += len;
- break;
- }
- else {
- docColumn += remaining;
- break;
- }
- }
+ var line = this.getLine(row);
+
+ for(var i=0; i 0) {
+ docColumn += 1;
+ // tab
+ if (c == 9) {
+ if (remaining >= tabSize) {
+ remaining -= tabSize;
+ } else {
+ remaining = 0;
+ docColumn -= 1;
+ }
+ }
+ // CJK characters
+ else if (
+ c >= 0x3040 && c <= 0x309F || // Hiragana
+ c >= 0x30A0 && c <= 0x30FF || // Katakana
+ c >= 0x4E00 && c <= 0x9FFF || // Single CJK ideographs
+ c >= 0xF900 && c <= 0xFAFF ||
+ c >= 0x3400 && c <= 0x4DBF
+ ) {
+ if (remaining >= 2) {
+ remaining -= 2;
+ } else {
+ remaining = 0;
+ docColumn -= 1;
+ }
+ } else {
+ remaining -= 1;
+ }
+ } else {
+ break;
+ }
+ }
+
return docColumn;
};
diff --git a/lib/ace/editor.js b/lib/ace/editor.js
index 807d1d2a..efa1cb9a 100644
--- a/lib/ace/editor.js
+++ b/lib/ace/editor.js
@@ -57,7 +57,7 @@ var Editor =function(renderer, session) {
this.keyBinding = new KeyBinding(this);
var self = this;
event.addListener(container, "mousedown", function(e) {
- setTimeout(function() {self.focus();});
+ self.focus();
return event.preventDefault(e);
});
event.addListener(container, "selectstart", function(e) {
@@ -122,10 +122,12 @@ var Editor =function(renderer, session) {
if (this.session == session) return;
if (this.session) {
+ var oldSession = this.session;
this.session.removeEventListener("change", this.$onDocumentChange);
this.session.removeEventListener("changeMode", this.$onDocumentModeChange);
this.session.removeEventListener("changeTabSize", this.$onDocumentChangeTabSize);
this.session.removeEventListener("changeBreakpoint", this.$onDocumentChangeBreakpoint);
+ this.session.removeEventListener("changeAnnotation", this.$onDocumentChangeAnnotation);
var selection = this.session.getSelection();
selection.removeEventListener("changeCursor", this.$onCursorChange);
@@ -148,6 +150,9 @@ var Editor =function(renderer, session) {
this.$onDocumentChangeBreakpoint = this.onDocumentChangeBreakpoint.bind(this);
this.session.addEventListener("changeBreakpoint", this.$onDocumentChangeBreakpoint);
+
+ this.$onDocumentChangeAnnotation = this.onDocumentChangeAnnotation.bind(this);
+ this.session.addEventListener("changeAnnotation", this.$onDocumentChangeAnnotation);
this.selection = session.getSelection();
this.$desiredColumn = 0;
@@ -165,8 +170,14 @@ var Editor =function(renderer, session) {
this.onCursorChange();
this.onSelectionChange();
this.onDocumentChangeBreakpoint();
+ this.onDocumentChangeAnnotation();
this.renderer.scrollToRow(session.getScrollTopRow());
this.renderer.updateFull();
+
+ this._dispatchEvent("changeSession", {
+ session: session,
+ oldSession: oldSession
+ });
};
this.getSession = function() {
@@ -289,6 +300,10 @@ var Editor =function(renderer, session) {
this.renderer.setBreakpoints(this.session.getBreakpoints());
};
+ this.onDocumentChangeAnnotation = function() {
+ this.renderer.setAnnotations(this.session.getAnnotations());
+ };
+
this.onDocumentModeChange = function() {
var mode = this.session.getMode();
if (this.mode == mode)
diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js
index 08812a0a..459f9e0e 100644
--- a/lib/ace/keyboard/textinput.js
+++ b/lib/ace/keyboard/textinput.js
@@ -43,11 +43,34 @@ var TextInput = function(parentNode, host) {
var text = document.createElement("textarea");
var style = text.style;
- style.position = "absolute";
+ style.position = "fixed";
style.left = "-10000px";
style.top = "-10000px";
parentNode.appendChild(text);
+ // move text input over the cursor
+ // this is required for iOS and IME
+ style.left = "0px";
+ style.top = "0px";
+ style.zIndex = -1;
+ style.opacity = 0;
+ style.width = "10px";
+ style.height = "30px";
+
+ var changeCursor = function() {
+ var cursor = host.getCursorPosition();
+ var pos = host.renderer.textToScreenCoordinates(cursor.row, cursor.column);
+ var epos = parentNode.getBoundingClientRect();
+ style.left = (pos.pageX - epos.left - 6) + "px";
+ style.top = (pos.pageY - epos.top + 52) + "px";
+ };
+
+ host.addEventListener("changeSession", function(e) {
+ if (e.oldSession)
+ e.oldSession.getSelection().removeEventListener("changeCursor", changeCursor);
+ e.session.getSelection().addEventListener("changeCursor", changeCursor);
+ });
+
var PLACEHOLDER = String.fromCharCode(0);
sendText();
diff --git a/lib/ace/layer/gutter.js b/lib/ace/layer/gutter.js
index aa3e5e7c..13c85bad 100644
--- a/lib/ace/layer/gutter.js
+++ b/lib/ace/layer/gutter.js
@@ -45,6 +45,7 @@ var Gutter = function(parentEl) {
parentEl.appendChild(this.element);
this.$breakpoints = [];
+ this.$annotations = [];
this.$decorations = [];
};
@@ -57,22 +58,49 @@ var Gutter = function(parentEl) {
}
this.removeGutterDecoration = function(row, className){
- this.$decorations[row] =
- this.$decorations[row].replace(" ace_" + className, "");
- }
+ this.$decorations[row] = this.$decorations[row].replace(" ace_" + className, "");
+ };
this.setBreakpoints = function(rows) {
this.$breakpoints = rows.concat();
};
+ this.setAnnotations = function(annotations) {
+ // iterate over sparse array
+ this.$annotations = [];
+ for (var row in annotations) {
+ var rowInfo = this.$annotations[row] = {
+ text: []
+ };
+ var rowAnnotations = annotations[row];
+ for (var i=0; i", (i+1), "");
html.push("");
}
diff --git a/lib/ace/layer/text.js b/lib/ace/layer/text.js
index 8ef2ebf3..568f1db9 100644
--- a/lib/ace/layer/text.js
+++ b/lib/ace/layer/text.js
@@ -248,19 +248,26 @@ var Text = function(parentEl) {
};
this.$renderLine = function(stringBuilder, row, tokens) {
-// if (this.showInvisibles) {
-// var self = this;
-// var spaceRe = /[\v\f \u00a0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000]+/g;
-// var spaceReplace = function(space) {
-// var space = new Array(space.length+1).join(self.SPACE_CHAR);
-// return "" + space + " ";
-// };
-// }
-// else {
+ if (this.showInvisibles) {
+ var self = this;
+ var spaceRe = /( +)|([\v\f \u00a0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000])/g;
+ var spaceReplace = function(space) {
+ if (space.charCodeAt(0) == 32)
+ return new Array(space.length+1).join(" ");
+ else {
+ var space = new Array(space.length+1).join(self.SPACE_CHAR);
+ return "" + space + " ";
+ }
+
+ };
+ }
+ else {
var spaceRe = /[\v\f \u00a0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000]/g;
var spaceReplace = " ";
-// }
+ }
+ var characterWidth = this.config.characterWidth;
+
for ( var i = 0; i < tokens.length; i++) {
var token = tokens[i];
@@ -268,8 +275,11 @@ var Text = function(parentEl) {
.replace(/&/g, "&")
.replace(/" + c + ""
+ });
+
if (!this.$textToken[token.type]) {
var classes = "ace_" + token.type.replace(/\./g, " ace_");
stringBuilder.push("", output, " ");
diff --git a/lib/ace/mode/css_highlight_rules.js b/lib/ace/mode/css_highlight_rules.js
index 1dc74e15..f13c821e 100644
--- a/lib/ace/mode/css_highlight_rules.js
+++ b/lib/ace/mode/css_highlight_rules.js
@@ -44,14 +44,14 @@ var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightR
var CssHighlightRules = function() {
var properties = lang.arrayToMap(
- ("azimuth|background-attachment|background-color|background-image|" +
+ ("-moz-box-sizing|-webkit-box-sizing|azimuth|background-attachment|background-color|background-image|" +
"background-position|background-repeat|background|border-bottom-color|" +
"border-bottom-style|border-bottom-width|border-bottom|border-collapse|" +
"border-color|border-left-color|border-left-style|border-left-width|" +
"border-left|border-right-color|border-right-style|border-right-width|" +
"border-right|border-spacing|border-style|border-top-color|" +
"border-top-style|border-top-width|border-top|border-width|border|" +
- "bottom|caption-side|clear|clip|color|content|counter-increment|" +
+ "bottom|box-sizing|caption-side|clear|clip|color|content|counter-increment|" +
"counter-reset|cue-after|cue-before|cue|cursor|direction|display|" +
"elevation|empty-cells|float|font-family|font-size-adjust|font-size|" +
"font-stretch|font-style|font-variant|font-weight|font|height|left|" +
@@ -76,8 +76,8 @@ var CssHighlightRules = function() {
var constants = lang.arrayToMap(
("absolute|all-scroll|always|armenian|auto|baseline|below|bidi-override|" +
- "block|bold|bolder|both|bottom|break-all|break-word|capitalize|center|" +
- "char|circle|cjk-ideographic|col-resize|collapse|crosshair|dashed|" +
+ "block|bold|bolder|border-box|both|bottom|break-all|break-word|capitalize|center|" +
+ "char|circle|cjk-ideographic|col-resize|collapse|content-box|crosshair|dashed|" +
"decimal-leading-zero|decimal|default|disabled|disc|" +
"distribute-all-lines|distribute-letter|distribute-space|" +
"distribute|dotted|double|e-resize|ellipsis|fixed|georgian|groove|" +
diff --git a/lib/ace/mode/javascript.js b/lib/ace/mode/javascript.js
index 02f7e7ac..5aab3d37 100644
--- a/lib/ace/mode/javascript.js
+++ b/lib/ace/mode/javascript.js
@@ -43,6 +43,7 @@ var Tokenizer = require("ace/tokenizer").Tokenizer;
var JavaScriptHighlightRules = require("ace/mode/javascript_highlight_rules").JavaScriptHighlightRules;
var MatchingBraceOutdent = require("ace/mode/matching_brace_outdent").MatchingBraceOutdent;
var Range = require("ace/range").Range;
+var WorkerClient = require("ace/worker/worker_client").WorkerClient;
var Mode = function() {
this.$tokenizer = new Tokenizer(new JavaScriptHighlightRules().getRules());
@@ -120,6 +121,47 @@ oop.inherits(Mode, TextMode);
this.autoOutdent = function(state, doc, row) {
return this.$outdent.autoOutdent(doc, row);
};
+
+ this.createWorker = function(session) {
+ var doc = session.getDocument();
+ var worker = new WorkerClient("../..", ["ace", "pilot"], "ace/mode/javascript_worker", "JavaScriptWorker");
+ worker.call("setValue", [doc.getValue()]);
+
+ doc.on("change", function(e) {
+ e.range = {
+ start: e.data.range.start,
+ end: e.data.range.end
+ };
+ worker.emit("change", e);
+ });
+
+ worker.on("jslint", function(results) {
+ var errors = [];
+ for (var i=0; i.
+ * Portions created by the Initial Developer are Copyright (C) 2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Tom Austin
+ * Brendan Eich
+ * Shu-Yu Guo
+ * Dave Herman
+ * Dimitris Vardoulakis
+ * Patrick Walton
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Narcissus - JS implemented in JS.
+ *
+ * Well-known constants and lookup tables. Many consts are generated from the
+ * tokens table via eval to minimize redundancy, so consumers must be compiled
+ * separately to take advantage of the simple switch-case constant propagation
+ * done by SpiderMonkey.
+ */
+
+define(function(require, exports, module) {
+
+exports.options = {
+ version: 185,
+};
+
+(function() {
+ exports.hostGlobal = this
+})();
+
+var tokens = [
+ // End of source.
+ "END",
+
+ // Operators and punctuators. Some pair-wise order matters, e.g. (+, -)
+ // and (UNARY_PLUS, UNARY_MINUS).
+ "\n", ";",
+ ",",
+ "=",
+ "?", ":", "CONDITIONAL",
+ "||",
+ "&&",
+ "|",
+ "^",
+ "&",
+ "==", "!=", "===", "!==",
+ "<", "<=", ">=", ">",
+ "<<", ">>", ">>>",
+ "+", "-",
+ "*", "/", "%",
+ "!", "~", "UNARY_PLUS", "UNARY_MINUS",
+ "++", "--",
+ ".",
+ "[", "]",
+ "{", "}",
+ "(", ")",
+
+ // Nonterminal tree node type codes.
+ "SCRIPT", "BLOCK", "LABEL", "FOR_IN", "CALL", "NEW_WITH_ARGS", "INDEX",
+ "ARRAY_INIT", "OBJECT_INIT", "PROPERTY_INIT", "GETTER", "SETTER",
+ "GROUP", "LIST", "LET_BLOCK", "ARRAY_COMP", "GENERATOR", "COMP_TAIL",
+
+ // Terminals.
+ "IDENTIFIER", "NUMBER", "STRING", "REGEXP",
+
+ // Keywords.
+ "break",
+ "case", "catch", "const", "continue",
+ "debugger", "default", "delete", "do",
+ "else",
+ "false", "finally", "for", "function",
+ "if", "in", "instanceof",
+ "let",
+ "new", "null",
+ "return",
+ "switch",
+ "this", "throw", "true", "try", "typeof",
+ "var", "void",
+ "yield",
+ "while", "with",
+];
+
+var statementStartTokens = [
+ "break",
+ "const", "continue",
+ "debugger", "do",
+ "for",
+ "if",
+ "return",
+ "switch",
+ "throw", "try",
+ "var",
+ "yield",
+ "while", "with",
+];
+
+// Operator and punctuator mapping from token to tree node type name.
+// NB: because the lexer doesn't backtrack, all token prefixes must themselves
+// be valid tokens (e.g. !== is acceptable because its prefixes are the valid
+// tokens != and !).
+var opTypeNames = {
+ '\n': "NEWLINE",
+ ';': "SEMICOLON",
+ ',': "COMMA",
+ '?': "HOOK",
+ ':': "COLON",
+ '||': "OR",
+ '&&': "AND",
+ '|': "BITWISE_OR",
+ '^': "BITWISE_XOR",
+ '&': "BITWISE_AND",
+ '===': "STRICT_EQ",
+ '==': "EQ",
+ '=': "ASSIGN",
+ '!==': "STRICT_NE",
+ '!=': "NE",
+ '<<': "LSH",
+ '<=': "LE",
+ '<': "LT",
+ '>>>': "URSH",
+ '>>': "RSH",
+ '>=': "GE",
+ '>': "GT",
+ '++': "INCREMENT",
+ '--': "DECREMENT",
+ '+': "PLUS",
+ '-': "MINUS",
+ '*': "MUL",
+ '/': "DIV",
+ '%': "MOD",
+ '!': "NOT",
+ '~': "BITWISE_NOT",
+ '.': "DOT",
+ '[': "LEFT_BRACKET",
+ ']': "RIGHT_BRACKET",
+ '{': "LEFT_CURLY",
+ '}': "RIGHT_CURLY",
+ '(': "LEFT_PAREN",
+ ')': "RIGHT_PAREN"
+};
+
+// Hash of keyword identifier to tokens index. NB: we must null __proto__ to
+// avoid toString, etc. namespace pollution.
+var keywords = {__proto__: null};
+
+// Define const END, etc., based on the token names. Also map name to index.
+var tokenIds = {};
+
+// Building up a string to be eval'd in different contexts.
+var consts = "const ";
+for (var i = 0, j = tokens.length; i < j; i++) {
+ if (i > 0)
+ consts += ", ";
+ var t = tokens[i];
+ var name;
+ if (/^[a-z]/.test(t)) {
+ name = t.toUpperCase();
+ keywords[t] = i;
+ } else {
+ name = (/^\W/.test(t) ? opTypeNames[t] : t);
+ }
+ consts += name + " = " + i;
+ tokenIds[name] = i;
+ tokens[t] = i;
+}
+consts += ";";
+
+var isStatementStartCode = {__proto__: null};
+for (i = 0, j = statementStartTokens.length; i < j; i++)
+ isStatementStartCode[keywords[statementStartTokens[i]]] = true;
+
+// Map assignment operators to their indexes in the tokens array.
+var assignOps = ['|', '^', '&', '<<', '>>', '>>>', '+', '-', '*', '/', '%'];
+
+for (i = 0, j = assignOps.length; i < j; i++) {
+ t = assignOps[i];
+ assignOps[t] = tokens[t];
+}
+
+function defineGetter(obj, prop, fn, dontDelete, dontEnum) {
+ Object.defineProperty(obj, prop,
+ { get: fn, configurable: !dontDelete, enumerable: !dontEnum });
+}
+
+function defineProperty(obj, prop, val, dontDelete, readOnly, dontEnum) {
+ Object.defineProperty(obj, prop,
+ { value: val, writable: !readOnly, configurable: !dontDelete,
+ enumerable: !dontEnum });
+}
+
+// Returns true if fn is a native function. (Note: SpiderMonkey specific.)
+function isNativeCode(fn) {
+ // Relies on the toString method to identify native code.
+ return ((typeof fn) === "function") && fn.toString().match(/\[native code\]/);
+}
+
+function getPropertyDescriptor(obj, name) {
+ while (obj) {
+ if (({}).hasOwnProperty.call(obj, name))
+ return Object.getOwnPropertyDescriptor(obj, name);
+ obj = Object.getPrototypeOf(obj);
+ }
+}
+
+function getOwnProperties(obj) {
+ var map = {};
+ for (var name in Object.getOwnPropertyNames(obj))
+ map[name] = Object.getOwnPropertyDescriptor(obj, name);
+ return map;
+}
+
+function makePassthruHandler(obj) {
+ // Handler copied from
+ // http://wiki.ecmascript.org/doku.php?id=harmony:proxies&s=proxy%20object#examplea_no-op_forwarding_proxy
+ return {
+ getOwnPropertyDescriptor: function(name) {
+ var desc = Object.getOwnPropertyDescriptor(obj, name);
+
+ // a trapping proxy's properties must always be configurable
+ desc.configurable = true;
+ return desc;
+ },
+ getPropertyDescriptor: function(name) {
+ var desc = getPropertyDescriptor(obj, name);
+
+ // a trapping proxy's properties must always be configurable
+ desc.configurable = true;
+ return desc;
+ },
+ getOwnPropertyNames: function() {
+ return Object.getOwnPropertyNames(obj);
+ },
+ defineProperty: function(name, desc) {
+ Object.defineProperty(obj, name, desc);
+ },
+ "delete": function(name) { return delete obj[name]; },
+ fix: function() {
+ if (Object.isFrozen(obj)) {
+ return getOwnProperties(obj);
+ }
+
+ // As long as obj is not frozen, the proxy won't allow itself to be fixed.
+ return undefined; // will cause a TypeError to be thrown
+ },
+
+ has: function(name) { return name in obj; },
+ hasOwn: function(name) { return ({}).hasOwnProperty.call(obj, name); },
+ get: function(receiver, name) { return obj[name]; },
+
+ // bad behavior when set fails in non-strict mode
+ set: function(receiver, name, val) { obj[name] = val; return true; },
+ enumerate: function() {
+ var result = [];
+ for (name in obj) { result.push(name); };
+ return result;
+ },
+ keys: function() { return Object.keys(obj); }
+ };
+}
+
+// default function used when looking for a property in the global object
+function noPropFound() { return undefined; }
+
+var hasOwnProperty = ({}).hasOwnProperty;
+
+function StringMap() {
+ this.table = Object.create(null, {});
+ this.size = 0;
+}
+
+StringMap.prototype = {
+ has: function(x) { return hasOwnProperty.call(this.table, x); },
+ set: function(x, v) {
+ if (!hasOwnProperty.call(this.table, x))
+ this.size++;
+ this.table[x] = v;
+ },
+ get: function(x) { return this.table[x]; },
+ getDef: function(x, thunk) {
+ if (!hasOwnProperty.call(this.table, x)) {
+ this.size++;
+ this.table[x] = thunk();
+ }
+ return this.table[x];
+ },
+ forEach: function(f) {
+ var table = this.table;
+ for (var key in table)
+ f.call(this, key, table[key]);
+ },
+ toString: function() { return "[object StringMap]" }
+};
+
+// non-destructive stack
+function Stack(elts) {
+ this.elts = elts || null;
+}
+
+Stack.prototype = {
+ push: function(x) {
+ return new Stack({ top: x, rest: this.elts });
+ },
+ top: function() {
+ if (!this.elts)
+ throw new Error("empty stack");
+ return this.elts.top;
+ },
+ isEmpty: function() {
+ return this.top === null;
+ },
+ find: function(test) {
+ for (var elts = this.elts; elts; elts = elts.rest) {
+ if (test(elts.top))
+ return elts.top;
+ }
+ return null;
+ },
+ has: function(x) {
+ return Boolean(this.find(function(elt) { return elt === x }));
+ },
+ forEach: function(f) {
+ for (var elts = this.elts; elts; elts = elts.rest) {
+ f(elts.top);
+ }
+ }
+};
+
+exports.tokens = tokens;
+exports.opTypeNames = opTypeNames;
+exports.keywords = keywords;
+exports.isStatementStartCode = isStatementStartCode;
+exports.tokenIds = tokenIds;
+exports.consts = consts;
+exports.assignOps = assignOps;
+exports.defineGetter = defineGetter;
+exports.defineProperty = defineProperty;
+exports.isNativeCode = isNativeCode;
+exports.makePassthruHandler = makePassthruHandler;
+exports.noPropFound = noPropFound;
+exports.StringMap = StringMap;
+exports.Stack = Stack;
+
+});
\ No newline at end of file
diff --git a/lib/ace/narcissus/jslex.js b/lib/ace/narcissus/jslex.js
new file mode 100644
index 00000000..c551792f
--- /dev/null
+++ b/lib/ace/narcissus/jslex.js
@@ -0,0 +1,460 @@
+/* vim: set sw=4 ts=4 et tw=78: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Narcissus JavaScript engine.
+ *
+ * The Initial Developer of the Original Code is
+ * Brendan Eich .
+ * Portions created by the Initial Developer are Copyright (C) 2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Tom Austin
+ * Brendan Eich
+ * Shu-Yu Guo
+ * Dave Herman
+ * Dimitris Vardoulakis
+ * Patrick Walton
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Narcissus - JS implemented in JS.
+ *
+ * Lexical scanner.
+ */
+
+define(function(require, exports, module) {
+
+var definitions = require("ace/narcissus/jsdefs");
+
+// Set constants in the local scope.
+eval(definitions.consts);
+
+// Build up a trie of operator tokens.
+var opTokens = {};
+for (var op in definitions.opTypeNames) {
+ if (op === '\n' || op === '.')
+ continue;
+
+ var node = opTokens;
+ for (var i = 0; i < op.length; i++) {
+ var ch = op[i];
+ if (!(ch in node))
+ node[ch] = {};
+ node = node[ch];
+ node.op = op;
+ }
+}
+
+/*
+ * Tokenizer :: (source, filename, line number) -> Tokenizer
+ */
+function Tokenizer(s, f, l) {
+ this.cursor = 0;
+ this.source = String(s);
+ this.tokens = [];
+ this.tokenIndex = 0;
+ this.lookahead = 0;
+ this.scanNewlines = false;
+ this.unexpectedEOF = false;
+ this.filename = f || "";
+ this.lineno = l || 1;
+}
+
+Tokenizer.prototype = {
+ get done() {
+ // We need to set scanOperand to true here because the first thing
+ // might be a regexp.
+ return this.peek(true) === END;
+ },
+
+ get token() {
+ return this.tokens[this.tokenIndex];
+ },
+
+ match: function (tt, scanOperand) {
+ return this.get(scanOperand) === tt || this.unget();
+ },
+
+ mustMatch: function (tt) {
+ if (!this.match(tt)) {
+ throw this.newSyntaxError("Missing " +
+ definitions.tokens[tt].toLowerCase());
+ }
+ return this.token;
+ },
+
+ peek: function (scanOperand) {
+ var tt, next;
+ if (this.lookahead) {
+ next = this.tokens[(this.tokenIndex + this.lookahead) & 3];
+ tt = (this.scanNewlines && next.lineno !== this.lineno)
+ ? NEWLINE
+ : next.type;
+ } else {
+ tt = this.get(scanOperand);
+ this.unget();
+ }
+ return tt;
+ },
+
+ peekOnSameLine: function (scanOperand) {
+ this.scanNewlines = true;
+ var tt = this.peek(scanOperand);
+ this.scanNewlines = false;
+ return tt;
+ },
+
+ // Eat comments and whitespace.
+ skip: function () {
+ var input = this.source;
+ for (;;) {
+ var ch = input[this.cursor++];
+ var next = input[this.cursor];
+ if (ch === '\n' && !this.scanNewlines) {
+ this.lineno++;
+ } else if (ch === '/' && next === '*') {
+ this.cursor++;
+ for (;;) {
+ ch = input[this.cursor++];
+ if (ch === undefined)
+ throw this.newSyntaxError("Unterminated comment");
+
+ if (ch === '*') {
+ next = input[this.cursor];
+ if (next === '/') {
+ this.cursor++;
+ break;
+ }
+ } else if (ch === '\n') {
+ this.lineno++;
+ }
+ }
+ } else if (ch === '/' && next === '/') {
+ this.cursor++;
+ for (;;) {
+ ch = input[this.cursor++];
+ if (ch === undefined)
+ return;
+
+ if (ch === '\n') {
+ this.lineno++;
+ break;
+ }
+ }
+ } else if (ch !== ' ' && ch !== '\t') {
+ this.cursor--;
+ return;
+ }
+ }
+ },
+
+ // Lex the exponential part of a number, if present. Return true iff an
+ // exponential part was found.
+ lexExponent: function() {
+ var input = this.source;
+ var next = input[this.cursor];
+ if (next === 'e' || next === 'E') {
+ this.cursor++;
+ ch = input[this.cursor++];
+ if (ch === '+' || ch === '-')
+ ch = input[this.cursor++];
+
+ if (ch < '0' || ch > '9')
+ throw this.newSyntaxError("Missing exponent");
+
+ do {
+ ch = input[this.cursor++];
+ } while (ch >= '0' && ch <= '9');
+ this.cursor--;
+
+ return true;
+ }
+
+ return false;
+ },
+
+ lexZeroNumber: function (ch) {
+ var token = this.token, input = this.source;
+ token.type = NUMBER;
+
+ ch = input[this.cursor++];
+ if (ch === '.') {
+ do {
+ ch = input[this.cursor++];
+ } while (ch >= '0' && ch <= '9');
+ this.cursor--;
+
+ this.lexExponent();
+ token.value = parseFloat(token.start, this.cursor);
+ } else if (ch === 'x' || ch === 'X') {
+ do {
+ ch = input[this.cursor++];
+ } while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') ||
+ (ch >= 'A' && ch <= 'F'));
+ this.cursor--;
+
+ token.value = parseInt(input.substring(token.start, this.cursor));
+ } else if (ch >= '0' && ch <= '7') {
+ do {
+ ch = input[this.cursor++];
+ } while (ch >= '0' && ch <= '7');
+ this.cursor--;
+
+ token.value = parseInt(input.substring(token.start, this.cursor));
+ } else {
+ this.cursor--;
+ this.lexExponent(); // 0E1, &c.
+ token.value = 0;
+ }
+ },
+
+ lexNumber: function (ch) {
+ var token = this.token, input = this.source;
+ token.type = NUMBER;
+
+ var floating = false;
+ do {
+ ch = input[this.cursor++];
+ if (ch === '.' && !floating) {
+ floating = true;
+ ch = input[this.cursor++];
+ }
+ } while (ch >= '0' && ch <= '9');
+
+ this.cursor--;
+
+ var exponent = this.lexExponent();
+ floating = floating || exponent;
+
+ var str = input.substring(token.start, this.cursor);
+ token.value = floating ? parseFloat(str) : parseInt(str);
+ },
+
+ lexDot: function (ch) {
+ var token = this.token, input = this.source;
+ var next = input[this.cursor];
+ if (next >= '0' && next <= '9') {
+ do {
+ ch = input[this.cursor++];
+ } while (ch >= '0' && ch <= '9');
+ this.cursor--;
+
+ this.lexExponent();
+
+ token.type = NUMBER;
+ token.value = parseFloat(token.start, this.cursor);
+ } else {
+ token.type = DOT;
+ token.assignOp = null;
+ token.value = '.';
+ }
+ },
+
+ lexString: function (ch) {
+ var token = this.token, input = this.source;
+ token.type = STRING;
+
+ var hasEscapes = false;
+ var delim = ch;
+ while ((ch = input[this.cursor++]) !== delim) {
+ if (this.cursor == input.length)
+ throw this.newSyntaxError("Unterminated string literal");
+ if (ch === '\\') {
+ hasEscapes = true;
+ if (++this.cursor == input.length)
+ throw this.newSyntaxError("Unterminated string literal");
+ }
+ }
+
+ token.value = hasEscapes
+ ? eval(input.substring(token.start, this.cursor))
+ : input.substring(token.start + 1, this.cursor - 1);
+ },
+
+ lexRegExp: function (ch) {
+ var token = this.token, input = this.source;
+ token.type = REGEXP;
+
+ do {
+ ch = input[this.cursor++];
+ if (ch === '\\') {
+ this.cursor++;
+ } else if (ch === '[') {
+ do {
+ if (ch === undefined)
+ throw this.newSyntaxError("Unterminated character class");
+
+ if (ch === '\\')
+ this.cursor++;
+
+ ch = input[this.cursor++];
+ } while (ch !== ']');
+ } else if (ch === undefined) {
+ throw this.newSyntaxError("Unterminated regex");
+ }
+ } while (ch !== '/');
+
+ do {
+ ch = input[this.cursor++];
+ } while (ch >= 'a' && ch <= 'z');
+
+ this.cursor--;
+
+ token.value = eval(input.substring(token.start, this.cursor));
+ },
+
+ lexOp: function (ch) {
+ var token = this.token, input = this.source;
+
+ // A bit ugly, but it seems wasteful to write a trie lookup routine
+ // for only 3 characters...
+ var node = opTokens[ch];
+ var next = input[this.cursor];
+ if (next in node) {
+ node = node[next];
+ this.cursor++;
+ next = input[this.cursor];
+ if (next in node) {
+ node = node[next];
+ this.cursor++;
+ next = input[this.cursor];
+ }
+ }
+
+ var op = node.op;
+ if (definitions.assignOps[op] && input[this.cursor] === '=') {
+ this.cursor++;
+ token.type = ASSIGN;
+ token.assignOp = definitions.tokenIds[definitions.opTypeNames[op]];
+ op += '=';
+ } else {
+ token.type = definitions.tokenIds[definitions.opTypeNames[op]];
+ token.assignOp = null;
+ }
+
+ token.value = op;
+ },
+
+ // FIXME: Unicode escape sequences
+ // FIXME: Unicode identifiers
+ lexIdent: function (ch) {
+ var token = this.token, input = this.source;
+
+ do {
+ ch = input[this.cursor++];
+ } while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
+ (ch >= '0' && ch <= '9') || ch === '$' || ch === '_');
+
+ this.cursor--; // Put the non-word character back.
+
+ var id = input.substring(token.start, this.cursor);
+ token.type = definitions.keywords[id] || IDENTIFIER;
+ token.value = id;
+ },
+
+ /*
+ * Tokenizer.get :: void -> token type
+ *
+ * Consume input *only* if there is no lookahead.
+ * Dispatch to the appropriate lexing function depending on the input.
+ */
+ get: function (scanOperand) {
+ var token;
+ while (this.lookahead) {
+ --this.lookahead;
+ this.tokenIndex = (this.tokenIndex + 1) & 3;
+ token = this.tokens[this.tokenIndex];
+ if (token.type !== NEWLINE || this.scanNewlines)
+ return token.type;
+ }
+
+ this.skip();
+
+ this.tokenIndex = (this.tokenIndex + 1) & 3;
+ token = this.tokens[this.tokenIndex];
+ if (!token)
+ this.tokens[this.tokenIndex] = token = {};
+
+ var input = this.source;
+ if (this.cursor === input.length)
+ return token.type = END;
+
+ token.start = this.cursor;
+ token.lineno = this.lineno;
+
+ var ch = input[this.cursor++];
+ if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch === '$' || ch === '_') {
+ this.lexIdent(ch);
+ } else if (scanOperand && ch === '/') {
+ this.lexRegExp(ch);
+ } else if (ch in opTokens) {
+ this.lexOp(ch);
+ } else if (ch === '.') {
+ this.lexDot(ch);
+ } else if (ch >= '1' && ch <= '9') {
+ this.lexNumber(ch);
+ } else if (ch === '0') {
+ this.lexZeroNumber(ch);
+ } else if (ch === '"' || ch === "'") {
+ this.lexString(ch);
+ } else if (this.scanNewlines && ch === '\n') {
+ token.type = NEWLINE;
+ token.value = '\n';
+ this.lineno++;
+ } else {
+ throw this.newSyntaxError("Illegal token");
+ }
+
+ token.end = this.cursor;
+ return token.type;
+ },
+
+ /*
+ * Tokenizer.unget :: void -> undefined
+ *
+ * Match depends on unget returning undefined.
+ */
+ unget: function () {
+ if (++this.lookahead === 4) throw "PANIC: too much lookahead!";
+ this.tokenIndex = (this.tokenIndex - 1) & 3;
+ },
+
+ newSyntaxError: function (m) {
+ var e = new SyntaxError(m, this.filename, this.lineno);
+ e.source = this.source;
+ e.lineno = this.lineno;
+ e.cursor = this.lookahead
+ ? this.tokens[(this.tokenIndex + this.lookahead) & 3].start
+ : this.cursor;
+ return e;
+ },
+};
+
+exports.Tokenizer = Tokenizer;
+
+});
\ No newline at end of file
diff --git a/lib/ace/narcissus/jsparse.js b/lib/ace/narcissus/jsparse.js
new file mode 100644
index 00000000..46b85ff3
--- /dev/null
+++ b/lib/ace/narcissus/jsparse.js
@@ -0,0 +1,1432 @@
+/* -*- Mode: JS; tab-width: 4; indent-tabs-mode: nil; -*-
+ * vim: set sw=4 ts=4 et tw=78:
+ * ***** BEGIN LICENSE BLOCK *****
+ *
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Narcissus JavaScript engine.
+ *
+ * The Initial Developer of the Original Code is
+ * Brendan Eich .
+ * Portions created by the Initial Developer are Copyright (C) 2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Tom Austin
+ * Brendan Eich
+ * Shu-Yu Guo
+ * Dave Herman
+ * Dimitris Vardoulakis
+ * Patrick Walton
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Narcissus - JS implemented in JS.
+ *
+ * Parser.
+ */
+
+define(function(require, exports, module) {
+
+var lexer = require("ace/narcissus/jslex");
+var definitions = require("ace/narcissus/jsdefs");
+
+const StringMap = definitions.StringMap;
+const Stack = definitions.Stack;
+
+// Set constants in the local scope.
+eval(definitions.consts);
+
+/*
+ * pushDestructuringVarDecls :: (node, hoisting node) -> void
+ *
+ * Recursively add all destructured declarations to varDecls.
+ */
+function pushDestructuringVarDecls(n, s) {
+ for (var i in n) {
+ var sub = n[i];
+ if (sub.type === IDENTIFIER) {
+ s.varDecls.push(sub);
+ } else {
+ pushDestructuringVarDecls(sub, s);
+ }
+ }
+}
+
+// NESTING_TOP: top-level
+// NESTING_SHALLOW: nested within static forms such as { ... } or labeled statement
+// NESTING_DEEP: nested within dynamic forms such as if, loops, etc.
+const NESTING_TOP = 0, NESTING_SHALLOW = 1, NESTING_DEEP = 2;
+
+function StaticContext(parentScript, parentBlock, inFunction, inForLoopInit, nesting) {
+ this.parentScript = parentScript;
+ this.parentBlock = parentBlock;
+ this.inFunction = inFunction;
+ this.inForLoopInit = inForLoopInit;
+ this.nesting = nesting;
+ this.allLabels = new Stack();
+ this.currentLabels = new Stack();
+ this.labeledTargets = new Stack();
+ this.defaultTarget = null;
+ definitions.options.ecma3OnlyMode && (this.ecma3OnlyMode = true);
+ definitions.options.parenFreeMode && (this.parenFreeMode = true);
+}
+
+StaticContext.prototype = {
+ ecma3OnlyMode: false,
+ parenFreeMode: false,
+ // non-destructive update via prototype extension
+ update: function(ext) {
+ var desc = {};
+ for (var key in ext) {
+ desc[key] = {
+ value: ext[key],
+ writable: true,
+ enumerable: true,
+ configurable: true
+ }
+ }
+ return Object.create(this, desc);
+ },
+ pushLabel: function(label) {
+ return this.update({ currentLabels: this.currentLabels.push(label),
+ allLabels: this.allLabels.push(label) });
+ },
+ pushTarget: function(target) {
+ var isDefaultTarget = target.isLoop || target.type === SWITCH;
+
+ if (this.currentLabels.isEmpty()) {
+ return isDefaultTarget
+ ? this.update({ defaultTarget: target })
+ : this;
+ }
+
+ target.labels = new StringMap();
+ this.currentLabels.forEach(function(label) {
+ target.labels.set(label, true);
+ });
+ return this.update({ currentLabels: new Stack(),
+ labeledTargets: this.labeledTargets.push(target),
+ defaultTarget: isDefaultTarget
+ ? target
+ : this.defaultTarget });
+ },
+ nest: function(atLeast) {
+ var nesting = Math.max(this.nesting, atLeast);
+ return (nesting !== this.nesting)
+ ? this.update({ nesting: nesting })
+ : this;
+ }
+};
+
+/*
+ * Script :: (tokenizer, boolean) -> node
+ *
+ * Parses the toplevel and function bodies.
+ */
+function Script(t, inFunction) {
+ var n = new Node(t, scriptInit());
+ var x = new StaticContext(n, n, inFunction, false, NESTING_TOP);
+ Statements(t, x, n);
+ return n;
+}
+
+// We extend Array slightly with a top-of-stack method.
+definitions.defineProperty(Array.prototype, "top",
+ function() {
+ return this.length && this[this.length-1];
+ }, false, false, true);
+
+/*
+ * Node :: (tokenizer, optional init object) -> node
+ */
+function Node(t, init) {
+ var token = t.token;
+ if (token) {
+ // If init.type exists it will override token.type.
+ this.type = token.type;
+ this.value = token.value;
+ this.lineno = token.lineno;
+
+ // Start and end are file positions for error handling.
+ this.start = token.start;
+ this.end = token.end;
+ } else {
+ this.lineno = t.lineno;
+ }
+
+ // Node uses a tokenizer for debugging (getSource, filename getter).
+ this.tokenizer = t;
+ this.children = [];
+
+ for (var prop in init)
+ this[prop] = init[prop];
+}
+
+var Np = Node.prototype = {};
+Np.constructor = Node;
+Np.toSource = Object.prototype.toSource;
+
+// Always use push to add operands to an expression, to update start and end.
+Np.push = function (kid) {
+ // kid can be null e.g. [1, , 2].
+ if (kid !== null) {
+ if (kid.start < this.start)
+ this.start = kid.start;
+ if (this.end < kid.end)
+ this.end = kid.end;
+ }
+ return this.children.push(kid);
+}
+
+Node.indentLevel = 0;
+
+function tokenString(tt) {
+ var t = definitions.tokens[tt];
+ return /^\W/.test(t) ? definitions.opTypeNames[t] : t.toUpperCase();
+}
+
+Np.toString = function () {
+ var a = [];
+ for (var i in this) {
+ if (this.hasOwnProperty(i) && i !== 'type' && i !== 'target')
+ a.push({id: i, value: this[i]});
+ }
+ a.sort(function (a,b) { return (a.id < b.id) ? -1 : 1; });
+ const INDENTATION = " ";
+ var n = ++Node.indentLevel;
+ var s = "{\n" + INDENTATION.repeat(n) + "type: " + tokenString(this.type);
+ for (i = 0; i < a.length; i++)
+ s += ",\n" + INDENTATION.repeat(n) + a[i].id + ": " + a[i].value;
+ n = --Node.indentLevel;
+ s += "\n" + INDENTATION.repeat(n) + "}";
+ return s;
+}
+
+Np.getSource = function () {
+ return this.tokenizer.source.slice(this.start, this.end);
+};
+
+/*
+ * Helper init objects for common nodes.
+ */
+
+const LOOP_INIT = { isLoop: true };
+
+function blockInit() {
+ return { type: BLOCK, varDecls: [] };
+}
+
+function scriptInit() {
+ return { type: SCRIPT,
+ funDecls: [],
+ varDecls: [],
+ modDecls: [],
+ impDecls: [],
+ expDecls: [],
+ loadDeps: [],
+ hasEmptyReturn: false,
+ hasReturnWithValue: false,
+ isGenerator: false };
+}
+
+definitions.defineGetter(Np, "filename",
+ function() {
+ return this.tokenizer.filename;
+ });
+
+definitions.defineProperty(String.prototype, "repeat",
+ function(n) {
+ var s = "", t = this + s;
+ while (--n >= 0)
+ s += t;
+ return s;
+ }, false, false, true);
+
+function MaybeLeftParen(t, x) {
+ if (x.parenFreeMode)
+ return t.match(LEFT_PAREN) ? LEFT_PAREN : END;
+ return t.mustMatch(LEFT_PAREN).type;
+}
+
+function MaybeRightParen(t, p) {
+ if (p === LEFT_PAREN)
+ t.mustMatch(RIGHT_PAREN);
+}
+
+/*
+ * Statements :: (tokenizer, compiler context, node) -> void
+ *
+ * Parses a sequence of Statements.
+ */
+function Statements(t, x, n) {
+ try {
+ while (!t.done && t.peek(true) !== RIGHT_CURLY)
+ n.push(Statement(t, x));
+ } catch (e) {
+ if (t.done)
+ t.unexpectedEOF = true;
+ throw e;
+ }
+}
+
+function Block(t, x) {
+ t.mustMatch(LEFT_CURLY);
+ var n = new Node(t, blockInit());
+ Statements(t, x.update({ parentBlock: n }).pushTarget(n), n);
+ t.mustMatch(RIGHT_CURLY);
+ return n;
+}
+
+const DECLARED_FORM = 0, EXPRESSED_FORM = 1, STATEMENT_FORM = 2;
+
+/*
+ * Statement :: (tokenizer, compiler context) -> node
+ *
+ * Parses a Statement.
+ */
+function Statement(t, x) {
+ var i, label, n, n2, p, c, ss, tt = t.get(true), tt2, x2, x3;
+
+ // Cases for statements ending in a right curly return early, avoiding the
+ // common semicolon insertion magic after this switch.
+ switch (tt) {
+ case FUNCTION:
+ // DECLARED_FORM extends funDecls of x, STATEMENT_FORM doesn't.
+ return FunctionDefinition(t, x, true,
+ (x.nesting !== NESTING_TOP)
+ ? STATEMENT_FORM
+ : DECLARED_FORM);
+
+ case LEFT_CURLY:
+ n = new Node(t, blockInit());
+ Statements(t, x.update({ parentBlock: n }).pushTarget(n).nest(NESTING_SHALLOW), n);
+ t.mustMatch(RIGHT_CURLY);
+ return n;
+
+ case IF:
+ n = new Node(t);
+ n.condition = HeadExpression(t, x);
+ x2 = x.pushTarget(n).nest(NESTING_DEEP);
+ n.thenPart = Statement(t, x2);
+ n.elsePart = t.match(ELSE) ? Statement(t, x2) : null;
+ return n;
+
+ case SWITCH:
+ // This allows CASEs after a DEFAULT, which is in the standard.
+ n = new Node(t, { cases: [], defaultIndex: -1 });
+ n.discriminant = HeadExpression(t, x);
+ x2 = x.pushTarget(n).nest(NESTING_DEEP);
+ t.mustMatch(LEFT_CURLY);
+ while ((tt = t.get()) !== RIGHT_CURLY) {
+ switch (tt) {
+ case DEFAULT:
+ if (n.defaultIndex >= 0)
+ throw t.newSyntaxError("More than one switch default");
+ // FALL THROUGH
+ case CASE:
+ n2 = new Node(t);
+ if (tt === DEFAULT)
+ n.defaultIndex = n.cases.length;
+ else
+ n2.caseLabel = Expression(t, x2, COLON);
+ break;
+
+ default:
+ throw t.newSyntaxError("Invalid switch case");
+ }
+ t.mustMatch(COLON);
+ n2.statements = new Node(t, blockInit());
+ while ((tt=t.peek(true)) !== CASE && tt !== DEFAULT &&
+ tt !== RIGHT_CURLY)
+ n2.statements.push(Statement(t, x2));
+ n.cases.push(n2);
+ }
+ return n;
+
+ case FOR:
+ n = new Node(t, LOOP_INIT);
+ if (t.match(IDENTIFIER)) {
+ if (t.token.value === "each")
+ n.isEach = true;
+ else
+ t.unget();
+ }
+ if (!x.parenFreeMode)
+ t.mustMatch(LEFT_PAREN);
+ x2 = x.pushTarget(n).nest(NESTING_DEEP);
+ x3 = x.update({ inForLoopInit: true });
+ if ((tt = t.peek()) !== SEMICOLON) {
+ if (tt === VAR || tt === CONST) {
+ t.get();
+ n2 = Variables(t, x3);
+ } else if (tt === LET) {
+ t.get();
+ if (t.peek() === LEFT_PAREN) {
+ n2 = LetBlock(t, x3, false);
+ } else {
+ // Let in for head, we need to add an implicit block
+ // around the rest of the for.
+ x3.parentBlock = n;
+ n.varDecls = [];
+ n2 = Variables(t, x3);
+ }
+ } else {
+ n2 = Expression(t, x3);
+ }
+ }
+ if (n2 && t.match(IN)) {
+ n.type = FOR_IN;
+ n.object = Expression(t, x3);
+ if (n2.type === VAR || n2.type === LET) {
+ c = n2.children;
+
+ // Destructuring turns one decl into multiples, so either
+ // there must be only one destructuring or only one
+ // decl.
+ if (c.length !== 1 && n2.destructurings.length !== 1) {
+ throw new SyntaxError("Invalid for..in left-hand side",
+ t.filename, n2.lineno);
+ }
+ if (n2.destructurings.length > 0) {
+ n.iterator = n2.destructurings[0];
+ } else {
+ n.iterator = c[0];
+ }
+ n.varDecl = n2;
+ } else {
+ if (n2.type === ARRAY_INIT || n2.type === OBJECT_INIT) {
+ n2.destructuredNames = checkDestructuring(t, x3, n2);
+ }
+ n.iterator = n2;
+ }
+ } else {
+ n.setup = n2;
+ t.mustMatch(SEMICOLON);
+ if (n.isEach)
+ throw t.newSyntaxError("Invalid for each..in loop");
+ n.condition = (t.peek() === SEMICOLON)
+ ? null
+ : Expression(t, x3);
+ t.mustMatch(SEMICOLON);
+ tt2 = t.peek();
+ n.update = (x.parenFreeMode
+ ? tt2 === LEFT_CURLY || definitions.isStatementStartCode[tt2]
+ : tt2 === RIGHT_PAREN)
+ ? null
+ : Expression(t, x3);
+ }
+ if (!x.parenFreeMode)
+ t.mustMatch(RIGHT_PAREN);
+ n.body = Statement(t, x2);
+ return n;
+
+ case WHILE:
+ n = new Node(t, { isLoop: true });
+ n.condition = HeadExpression(t, x);
+ n.body = Statement(t, x.pushTarget(n).nest(NESTING_DEEP));
+ return n;
+
+ case DO:
+ n = new Node(t, { isLoop: true });
+ n.body = Statement(t, x.pushTarget(n).nest(NESTING_DEEP));
+ t.mustMatch(WHILE);
+ n.condition = HeadExpression(t, x);
+ if (!x.ecmaStrictMode) {
+ //