diff --git a/ChangeLog.txt b/ChangeLog.txt
index 8e1d8524..7c3db96d 100644
--- a/ChangeLog.txt
+++ b/ChangeLog.txt
@@ -1,3 +1,8 @@
+
+* API Changes
+ - `editor.commands.commandKeyBinding` now contains direct map from keys to commands instead of grouping them by hashid
+ -
+
2014.09.21 Version 1.1.7
* Bugfixes
diff --git a/Makefile.dryice.js b/Makefile.dryice.js
index 2763da89..a6082558 100755
--- a/Makefile.dryice.js
+++ b/Makefile.dryice.js
@@ -184,7 +184,7 @@ function jsFileList(path, filter) {
filter = /_test/;
return fs.readdirSync(path).map(function(x) {
- if (x.slice(-3) == ".js" && !filter.test(x) && !/\s/.test(x))
+ if (x.slice(-3) == ".js" && !filter.test(x) && !/\s|BASE|(\b|_)dummy(\b|_)/.test(x))
return x.slice(0, -3);
}).filter(Boolean);
}
diff --git a/demo/kitchen-sink/docs/elm.elm b/demo/kitchen-sink/docs/elm.elm
new file mode 100644
index 00000000..eef70b2a
--- /dev/null
+++ b/demo/kitchen-sink/docs/elm.elm
@@ -0,0 +1,12 @@
+{- Ace {- 4 -} Elm -}
+main = lift clock (every second)
+
+clock t = collage 400 400 [ filled lightGrey (ngon 12 110)
+ , outlined (solid grey) (ngon 12 110)
+ , hand orange 100 t
+ , hand charcoal 100 (t/60)
+ , hand charcoal 60 (t/720) ]
+
+hand clr len time =
+ let angle = degrees (90 - 6 * inSeconds time)
+ in traced (solid clr) <| segment (0,0) (len * cos angle, len * sin angle)
\ No newline at end of file
diff --git a/demo/kitchen-sink/docs/sh.sh b/demo/kitchen-sink/docs/sh.sh
index b1da400d..4c5e6968 100755
--- a/demo/kitchen-sink/docs/sh.sh
+++ b/demo/kitchen-sink/docs/sh.sh
@@ -2,9 +2,9 @@
# Script to open a browser to current branch
# Repo formats:
-# ssh git@github.com:richoH/gh_pr.git
-# http https://richoH@github.com/richoH/gh_pr.git
-# git git://github.com/richoH/gh_pr.git
+# ssh git@github.com:richo/gh_pr.git
+# http https://richoH@github.com/richo/gh_pr.git
+# git git://github.com/richo/gh_pr.git
username=`git config --get github.user`
diff --git a/demo/kitchen-sink/inline_editor.js b/demo/kitchen-sink/inline_editor.js
index 0c050aed..3f814c21 100644
--- a/demo/kitchen-sink/inline_editor.js
+++ b/demo/kitchen-sink/inline_editor.js
@@ -96,9 +96,6 @@ require("ace/commands/default_commands").commands.push({
editor.keyBinding.addKeyboardHandler(kb);
inlineEditor.keyBinding.addKeyboardHandler(kb);
- editor.on("changeSession", function(e) {
- w.el.parentNode && w.el.parentNode.removeChild(w.el);
- });
inlineEditor.setTheme("ace/theme/solarized_light");
}
});
diff --git a/demo/kitchen-sink/layout.js b/demo/kitchen-sink/layout.js
index e43915bb..1332eef3 100644
--- a/demo/kitchen-sink/layout.js
+++ b/demo/kitchen-sink/layout.js
@@ -116,7 +116,6 @@ exports.singleLineEditor = function(el) {
renderer.setStyle("ace_one-line");
var editor = new Editor(renderer);
- new MultiSelect(editor);
editor.session.setUndoManager(new UndoManager());
editor.setShowPrintMargin(false);
diff --git a/lib/ace/anchor.js b/lib/ace/anchor.js
index 3431b3c4..f3a60277 100644
--- a/lib/ace/anchor.js
+++ b/lib/ace/anchor.js
@@ -36,7 +36,7 @@ var EventEmitter = require("./lib/event_emitter").EventEmitter;
/**
*
- * Defines the floating pointer in the document. Whenever text is inserted or deleted before the cursor, the position of the cursor is updated.
+ * Defines a floating pointer in the document. Whenever text is inserted or deleted before the cursor, the position of the anchor is updated.
*
* @class Anchor
**/
diff --git a/lib/ace/autocomplete.js b/lib/ace/autocomplete.js
index 78015bd4..b4bac72b 100644
--- a/lib/ace/autocomplete.js
+++ b/lib/ace/autocomplete.js
@@ -36,6 +36,7 @@ var AcePopup = require("./autocomplete/popup").AcePopup;
var util = require("./autocomplete/util");
var event = require("./lib/event");
var lang = require("./lib/lang");
+var dom = require("./lib/dom");
var snippetManager = require("./snippets").snippetManager;
var Autocomplete = function() {
@@ -52,6 +53,8 @@ var Autocomplete = function() {
this.changeTimer = lang.delayedCall(function() {
this.updateCompletions(true);
}.bind(this));
+
+ this.tooltipTimer = lang.delayedCall(this.updateDocTooltip.bind(this), 50);
};
(function() {
@@ -64,6 +67,13 @@ var Autocomplete = function() {
e.stop();
}.bind(this));
this.popup.focus = this.editor.focus.bind(this.editor);
+ this.popup.on("select", this.tooltipTimer.bind(null, null));
+ this.popup.on("changeHoverMarker", this.tooltipTimer.bind(null, null));
+ return this.popup;
+ };
+
+ this.getPopup = function() {
+ return this.popup || this.$init();
};
this.openPopup = function(editor, prefix, keepPopupPosition) {
@@ -101,6 +111,7 @@ var Autocomplete = function() {
this.editor.off("mousedown", this.mousedownListener);
this.editor.off("mousewheel", this.mousewheelListener);
this.changeTimer.cancel();
+ this.hideDocTooltip();
if (this.popup && this.popup.isOpen) {
this.gatherCompletionsId += 1;
@@ -124,12 +135,17 @@ var Autocomplete = function() {
this.detach();
};
- this.blurListener = function() {
+ this.blurListener = function(e) {
// we have to check if activeElement is a child of popup because
// on IE preventDefault doesn't stop scrollbar from being focussed
var el = document.activeElement;
- if (el != this.editor.textInput.getElement() && el.parentNode != this.popup.container)
+ var text = this.editor.textInput.getElement()
+ if (el != text && el.parentNode != this.popup.container
+ && el != this.tooltipNode && e.relatedTarget != this.tooltipNode
+ && e.relatedTarget != text
+ ) {
this.detach();
+ }
};
this.mousedownListener = function(e) {
@@ -178,6 +194,7 @@ var Autocomplete = function() {
this.detach();
};
+
this.commands = {
"Up": function(editor) { editor.completer.goTo("up"); },
"Down": function(editor) { editor.completer.goTo("down"); },
@@ -310,6 +327,74 @@ var Autocomplete = function() {
this.cancelContextMenu = function() {
this.editor.$mouseHandler.cancelContextMenu();
};
+
+ this.updateDocTooltip = function() {
+ var popup = this.popup;
+ var all = popup.data;
+ var selected = all && (all[popup.getHoveredRow()] || all[popup.getRow()]);
+ var doc = null;
+ if (!selected || !this.editor || !this.popup.isOpen)
+ return this.hideDocTooltip();
+ this.editor.completers.some(function(completer) {
+ if (completer.getDocTooltip)
+ doc = completer.getDocTooltip(selected);
+ return doc;
+ });
+ if (!doc)
+ doc = selected;
+
+ if (typeof doc == "string")
+ doc = {tooltipText: doc}
+ if (!doc || !(doc.docHTML || doc.docText))
+ return this.hideDocTooltip();
+ this.showDocTooltip(doc);
+ };
+
+ this.showDocTooltip = function(item) {
+ if (!this.tooltipNode) {
+ this.tooltipNode = dom.createElement("pre");
+ this.tooltipNode.className = "ace_tooltip ace_doc-tooltip";
+ this.tooltipNode.style.margin = 0;
+ this.tooltipNode.style.pointerEvents = "auto";
+ this.tooltipNode.tabIndex = -1;
+ this.tooltipNode.onblur = this.blurListener.bind(this);
+ }
+
+ var tooltipNode = this.tooltipNode;
+ if (item.docHTML) {
+ tooltipNode.innerHTML = item.docHTML;
+ } else if (item.docText) {
+ tooltipNode.textContent = item.docText;
+ }
+
+ if (!tooltipNode.parentNode)
+ document.body.appendChild(tooltipNode);
+ var popup = this.popup;
+ var rect = popup.container.getBoundingClientRect();
+ tooltipNode.style.top = popup.container.style.top;
+ tooltipNode.style.bottom = popup.container.style.bottom;
+
+ if (window.innerWidth - rect.right < 320) {
+ tooltipNode.style.right = window.innerWidth - rect.left + "px";
+ tooltipNode.style.left = "";
+ } else {
+ tooltipNode.style.left = (rect.right + 1) + "px";
+ tooltipNode.style.right = "";
+ }
+ // tooltipNode.style.height = rect.height + "px";
+ tooltipNode.style.display = "block";
+ };
+
+ this.hideDocTooltip = function() {
+ this.tooltipTimer.cancel();
+ if (!this.tooltipNode) return;
+ var el = this.tooltipNode;
+ if (!this.editor.isFocused() && document.activeElement == el)
+ this.editor.focus();
+ this.tooltipNode = null;
+ if (el.parentNode)
+ el.parentNode.removeChild(el);
+ };
}).call(Autocomplete.prototype);
diff --git a/lib/ace/commands/command_manager.js b/lib/ace/commands/command_manager.js
index 537942ab..df30ef9b 100644
--- a/lib/ace/commands/command_manager.js
+++ b/lib/ace/commands/command_manager.js
@@ -2,13 +2,12 @@ define(function(require, exports, module) {
"use strict";
var oop = require("../lib/oop");
-var HashHandler = require("../keyboard/hash_handler").HashHandler;
+var MultiHashHandler = require("../keyboard/hash_handler").MultiHashHandler;
var EventEmitter = require("../lib/event_emitter").EventEmitter;
/**
* @class CommandManager
*
- *
**/
/**
@@ -19,20 +18,27 @@ var EventEmitter = require("../lib/event_emitter").EventEmitter;
**/
var CommandManager = function(platform, commands) {
- HashHandler.call(this, commands, platform);
+ MultiHashHandler.call(this, commands, platform);
this.byName = this.commands;
this.setDefaultHandler("exec", function(e) {
return e.command.exec(e.editor, e.args || {});
});
};
-oop.inherits(CommandManager, HashHandler);
+oop.inherits(CommandManager, MultiHashHandler);
(function() {
oop.implement(this, EventEmitter);
this.exec = function(command, editor, args) {
+ if (Array.isArray(command)) {
+ for (var i = command.length; i--; ) {
+ if (this.exec(command[i], editor, args)) return true;
+ }
+ return false;
+ }
+
if (typeof command === "string")
command = this.commands[command];
@@ -43,10 +49,10 @@ oop.inherits(CommandManager, HashHandler);
return false;
var e = {editor: editor, command: command, args: args};
- var retvalue = this._emit("exec", e);
+ e.returnValue = this._emit("exec", e);
this._signal("afterExec", e);
- return retvalue === false ? false : true;
+ return e.returnValue === false ? false : true;
};
this.toggleRecording = function(editor) {
diff --git a/lib/ace/commands/command_manager_test.js b/lib/ace/commands/command_manager_test.js
index 76d973bb..902600be 100644
--- a/lib/ace/commands/command_manager_test.js
+++ b/lib/ace/commands/command_manager_test.js
@@ -188,7 +188,7 @@ module.exports = {
assert.equal(command, "cm2");
var command = this.cm.findKeyCommand(0, "return");
- assert.equal(command, "cm3");
+ assert.equal(command + "", ["cm4", "cm3"] + "");
}
};
diff --git a/lib/ace/edit_session/folding.js b/lib/ace/edit_session/folding.js
index 99983d5f..d5052266 100644
--- a/lib/ace/edit_session/folding.js
+++ b/lib/ace/edit_session/folding.js
@@ -289,13 +289,12 @@ function Folding() {
if (startFold && endFold == startFold)
return startFold.addSubFold(fold);
- if (
- (startFold && !startFold.range.isStart(startRow, startColumn))
- || (endFold && !endFold.range.isEnd(endRow, endColumn))
- ) {
- throw new Error("A fold can't intersect already existing fold" + fold.range + startFold.range);
- }
-
+ if (startFold && !startFold.range.isStart(startRow, startColumn))
+ this.removeFold(startFold);
+
+ if (endFold && !endFold.range.isEnd(endRow, endColumn))
+ this.removeFold(endFold);
+
// Check if there are folds in the range we create the new fold for.
var folds = this.getFoldsInRange(fold.range);
if (folds.length > 0) {
diff --git a/lib/ace/editor.js b/lib/ace/editor.js
index 587cb50d..97c4a8e6 100644
--- a/lib/ace/editor.js
+++ b/lib/ace/editor.js
@@ -115,30 +115,8 @@ var Editor = function(renderer, session) {
function last(a) {return a[a.length - 1]}
this.selections = [];
- this.commands.on("exec", function(e) {
- this.startOperation(e);
-
- var command = e.command;
- if (command.aceCommandGroup == "fileJump") {
- var prev = this.prevOp;
- if (!prev || prev.command.aceCommandGroup != "fileJump") {
- this.lastFileJumpPos = last(this.selections);
- }
- } else {
- this.lastFileJumpPos = null;
- }
- }.bind(this), true);
-
- this.commands.on("afterExec", function(e) {
- var command = e.command;
-
- if (command.aceCommandGroup == "fileJump") {
- if (this.lastFileJumpPos && !this.curOp.selectionChanged) {
- this.selection.fromJSON(this.lastFileJumpPos);
- }
- }
- this.endOperation(e);
- }.bind(this), true);
+ this.commands.on("exec", this.startOperation.bind(this), true);
+ this.commands.on("afterExec", this.endOperation.bind(this), true);
this.$opResetTimer = lang.delayedCall(this.endOperation.bind(this));
@@ -173,18 +151,16 @@ var Editor = function(renderer, session) {
scrollTop: this.renderer.scrollTop
};
- var command = this.curOp.command;
- if (command && command.scrollIntoView)
- this.$blockScrolling++;
-
- this.selections.push(this.selection.toJSON());
+ // this.selections.push(this.selection.toJSON());
};
- this.endOperation = function() {
+ this.endOperation = function(e) {
if (this.curOp) {
+ if (e && e.returnValue === false)
+ return this.curOp = null;
+
var command = this.curOp.command;
if (command && command.scrollIntoView) {
- this.$blockScrolling--;
switch (command.scrollIntoView) {
case "center":
this.renderer.scrollCursorIntoView(null, 0.5);
@@ -255,19 +231,19 @@ var Editor = function(renderer, session) {
* @param {String} keyboardHandler The new key handler
*
**/
- this.setKeyboardHandler = function(keyboardHandler) {
- if (!keyboardHandler) {
- this.keyBinding.setKeyboardHandler(null);
- } else if (typeof keyboardHandler === "string") {
+ this.setKeyboardHandler = function(keyboardHandler, cb) {
+ if (keyboardHandler && typeof keyboardHandler === "string") {
this.$keybindingId = keyboardHandler;
var _self = this;
config.loadModule(["keybinding", keyboardHandler], function(module) {
if (_self.$keybindingId == keyboardHandler)
_self.keyBinding.setKeyboardHandler(module && module.handler);
+ cb && cb();
});
} else {
this.$keybindingId = null;
this.keyBinding.setKeyboardHandler(keyboardHandler);
+ cb && cb();
}
};
@@ -662,13 +638,13 @@ var Editor = function(renderer, session) {
*
*
**/
- this.onFocus = function() {
+ this.onFocus = function(e) {
if (this.$isFocused)
return;
this.$isFocused = true;
this.renderer.showCursor();
this.renderer.visualizeFocus();
- this._emit("focus");
+ this._emit("focus", e);
};
/**
@@ -677,13 +653,13 @@ var Editor = function(renderer, session) {
*
*
**/
- this.onBlur = function() {
+ this.onBlur = function(e) {
if (!this.$isFocused)
return;
this.$isFocused = false;
this.renderer.hideCursor();
this.renderer.visualizeBlur();
- this._emit("blur");
+ this._emit("blur", e);
};
this.$cursorChange = function() {
@@ -927,9 +903,8 @@ var Editor = function(renderer, session) {
this.insert(e.text, true);
};
-
this.execCommand = function(command, args) {
- this.commands.exec(command, this, args);
+ return this.commands.exec(command, this, args);
};
/**
@@ -2541,7 +2516,9 @@ var Editor = function(renderer, session) {
rect = self.renderer.container.getBoundingClientRect();
});
var onAfterRender = this.renderer.on("afterRender", function() {
- if (shouldScroll && rect && self.isFocused()) {
+ if (shouldScroll && rect && (self.isFocused()
+ || self.searchBox && self.searchBox.isFocused())
+ ) {
var renderer = self.renderer;
var pos = renderer.$cursorLayer.$pixelPos;
var config = renderer.layerConfig;
diff --git a/lib/ace/ext/emmet.js b/lib/ace/ext/emmet.js
index e547ae4d..75eefa3f 100644
--- a/lib/ace/ext/emmet.js
+++ b/lib/ace/ext/emmet.js
@@ -34,15 +34,7 @@ var HashHandler = require("ace/keyboard/hash_handler").HashHandler;
var Editor = require("ace/editor").Editor;
var snippetManager = require("ace/snippets").snippetManager;
var Range = require("ace/range").Range;
-var emmet;
-
-Editor.prototype.indexToPosition = function(index) {
- return this.session.doc.indexToPosition(index);
-};
-
-Editor.prototype.positionToIndex = function(pos) {
- return this.session.doc.positionToIndex(pos);
-};
+var emmet, emmetPath;
/**
* Implementation of {@link IEmmetEditor} interface for Ace
@@ -72,9 +64,10 @@ AceEmmetEditor.prototype = {
getSelectionRange: function() {
// TODO should start be caret position instead?
var range = this.ace.getSelectionRange();
+ var doc = this.ace.session.doc;
return {
- start: this.ace.positionToIndex(range.start),
- end: this.ace.positionToIndex(range.end)
+ start: doc.positionToIndex(range.start),
+ end: doc.positionToIndex(range.end)
};
},
@@ -91,9 +84,10 @@ AceEmmetEditor.prototype = {
* editor.createSelection(15);
*/
createSelection: function(start, end) {
+ var doc = this.ace.session.doc;
this.ace.selection.setRange({
- start: this.ace.indexToPosition(start),
- end: this.ace.indexToPosition(end)
+ start: doc.indexToPosition(start),
+ end: doc.indexToPosition(end)
});
},
@@ -106,9 +100,10 @@ AceEmmetEditor.prototype = {
* alert(range.start + ', ' + range.end);
*/
getCurrentLineRange: function() {
- var row = this.ace.getCursorPosition().row;
- var lineLength = this.ace.session.getLine(row).length;
- var index = this.ace.positionToIndex({row: row, column: 0});
+ var ace = this.ace;
+ var row = ace.getCursorPosition().row;
+ var lineLength = ace.session.getLine(row).length;
+ var index = ace.session.doc.positionToIndex({row: row, column: 0});
return {
start: index,
end: index + lineLength
@@ -121,7 +116,7 @@ AceEmmetEditor.prototype = {
*/
getCaretPos: function(){
var pos = this.ace.getCursorPosition();
- return this.ace.positionToIndex(pos);
+ return this.ace.session.doc.positionToIndex(pos);
},
/**
@@ -129,7 +124,7 @@ AceEmmetEditor.prototype = {
* @param {Number} index Caret position
*/
setCaretPos: function(index){
- var pos = this.ace.indexToPosition(index);
+ var pos = this.ace.session.doc.indexToPosition(index);
this.ace.selection.moveToPosition(pos);
},
@@ -169,14 +164,15 @@ AceEmmetEditor.prototype = {
start = 0;
var editor = this.ace;
- var range = Range.fromPoints(editor.indexToPosition(start), editor.indexToPosition(end));
+ var doc = editor.session.doc;
+ var range = Range.fromPoints(doc.indexToPosition(start), doc.indexToPosition(end));
editor.session.remove(range);
range.end = range.start;
//editor.selection.setRange(range);
value = this.$updateTabstops(value);
- snippetManager.insertSnippet(editor, value)
+ snippetManager.insertSnippet(editor, value);
},
/**
@@ -292,7 +288,7 @@ AceEmmetEditor.prototype = {
lastZero = range.create(data.start, result);
}
- return result
+ return result;
},
escape: function(ch) {
if (ch == '$') return '\\$';
@@ -363,12 +359,17 @@ exports.runEmmetCommand = function(editor) {
}, 0);
}
+ var pos = editor.selection.lead;
+ var token = editor.session.getTokenAt(pos.row, pos.column);
+ if (token && /\btag\b/.test(token.type))
+ return false;
+
try {
var result = actions.run(this.action, editorProxy);
} catch(e) {
editor._signal("changeStatus", typeof e == "string" ? e : e.message);
console.log(e);
- result = false
+ result = false;
}
return result;
};
@@ -383,21 +384,36 @@ for (var command in keymap) {
});
}
+exports.updateCommands = function(editor, enabled) {
+ if (enabled) {
+ editor.keyBinding.addKeyboardHandler(exports.commands);
+ } else {
+ editor.keyBinding.removeKeyboardHandler(exports.commands);
+ }
+};
+
+exports.isSupportedMode = function(modeId) {
+ return modeId && /css|less|scss|sass|stylus|html|php|twig/.test(modeId);
+};
+
var onChangeMode = function(e, target) {
var editor = target;
if (!editor)
return;
- var modeId = editor.session.$modeId;
- var enabled = modeId && /css|less|scss|sass|stylus|html|php/.test(modeId);
+ var enabled = exports.isSupportedMode(editor.session.$modeId);
if (e.enableEmmet === false)
enabled = false;
- if (enabled)
- editor.keyBinding.addKeyboardHandler(exports.commands);
- else
- editor.keyBinding.removeKeyboardHandler(exports.commands);
+ if (enabled) {
+ if (typeof emmetPath == "string") {
+ require("ace/config").loadModule(emmetPath, function() {
+
+ });
+ emmetPath = null;
+ }
+ }
+ exports.updateCommands(editor, enabled);
};
-
exports.AceEmmetEditor = AceEmmetEditor;
require("ace/config").defineOptions(Editor.prototype, "editor", {
enableEmmet: {
@@ -409,7 +425,11 @@ require("ace/config").defineOptions(Editor.prototype, "editor", {
}
});
-
-exports.setCore = function(e) {emmet = e;};
+exports.setCore = function(e) {
+ if (typeof e == "string")
+ emmetPath = e;
+ else
+ emmet = e;
+};
});
diff --git a/lib/ace/ext/language_tools.js b/lib/ace/ext/language_tools.js
index d8b2a1dd..4687efd5 100644
--- a/lib/ace/ext/language_tools.js
+++ b/lib/ace/ext/language_tools.js
@@ -34,6 +34,7 @@ define(function(require, exports, module) {
var snippetManager = require("../snippets").snippetManager;
var Autocomplete = require("../autocomplete").Autocomplete;
var config = require("../config");
+var lang = require("../lib/lang");
var util = require("../autocomplete/util");
var textCompleter = require("../autocomplete/text_completer");
@@ -59,15 +60,29 @@ var snippetCompleter = {
completions.push({
caption: caption,
snippet: s.content,
- meta: s.tabTrigger && !s.name ? s.tabTrigger + "\u21E5 " : "snippet"
+ meta: s.tabTrigger && !s.name ? s.tabTrigger + "\u21E5 " : "snippet",
+ type: "snippet"
});
}
}, this);
callback(null, completions);
+ },
+ getDocTooltip: function(item) {
+ if (item.type == "snippet" && !item.docHTML) {
+ item.docHTML = [
+ "", lang.escapeHTML(item.caption), "", "
",
+ lang.escapeHTML(item.snippet)
+ ].join("");
+ }
}
};
var completers = [snippetCompleter, textCompleter, keyWordCompleter];
+// Allows default completers to be removed or replaced with a explict set of completers
+// A null argument here will result in an empty completer array, not a null attribute
+exports.setCompleters = function(val) {
+ completers = val || [];
+};
exports.addCompleter = function(completer) {
completers.push(completer);
};
@@ -80,9 +95,7 @@ exports.snippetCompleter = snippetCompleter;
var expandSnippet = {
name: "expandSnippet",
exec: function(editor) {
- var success = snippetManager.expandWithTab(editor);
- if (!success)
- editor.execCommand("indent");
+ return snippetManager.expandWithTab(editor);
},
bindKey: "Tab"
};
diff --git a/lib/ace/ext/menu_tools/get_editor_keyboard_shortcuts.js b/lib/ace/ext/menu_tools/get_editor_keyboard_shortcuts.js
index e412bfba..99e006b0 100644
--- a/lib/ace/ext/menu_tools/get_editor_keyboard_shortcuts.js
+++ b/lib/ace/ext/menu_tools/get_editor_keyboard_shortcuts.js
@@ -69,29 +69,20 @@ module.exports.getEditorKeybordShortcuts = function(editor) {
editor.keyBinding.$handlers.forEach(function(handler) {
var ckb = handler.commandKeyBinding;
for (var i in ckb) {
- var modifier = parseInt(i);
- if (modifier == -1) {
- modifier = "";
- } else if(isNaN(modifier)) {
- modifier = i;
- } else {
- modifier = "" +
- (modifier & KEY_MODS.command ? "Cmd-" : "") +
- (modifier & KEY_MODS.ctrl ? "Ctrl-" : "") +
- (modifier & KEY_MODS.alt ? "Alt-" : "") +
- (modifier & KEY_MODS.shift ? "Shift-" : "");
- }
- for (var key in ckb[i]) {
- var command = ckb[i][key]
+ var key = i.replace(/(^|-)\w/g, function(x) { return x.toUpperCase(); });
+ var commands = ckb[i];
+ if (!Array.isArray(commands))
+ commands = [commands];
+ commands.forEach(function(command) {
if (typeof command != "string")
command = command.name
if (commandMap[command]) {
- commandMap[command].key += "|" + modifier + key;
+ commandMap[command].key += "|" + key;
} else {
- commandMap[command] = {key: modifier+key, command: command};
+ commandMap[command] = {key: key, command: command};
keybindings.push(commandMap[command]);
- }
- }
+ }
+ });
}
});
return keybindings;
diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js
index 3ffac26b..3f85c5b3 100644
--- a/lib/ace/ext/modelist.js
+++ b/lib/ace/ext/modelist.js
@@ -65,8 +65,11 @@ var supportedModes = {
Diff: ["diff|patch"],
Dockerfile: ["^Dockerfile"],
Dot: ["dot"],
+ Dummy: ["dummy"],
+ DummySyntax: ["dummy"],
Eiffel: ["e"],
EJS: ["ejs"],
+ Elm: ["elm"],
Erlang: ["erl|hrl"],
Forth: ["frt|fs|ldr"],
FTL: ["ftl"],
diff --git a/lib/ace/ext/searchbox.js b/lib/ace/ext/searchbox.js
index 0369f2d0..b316aa75 100644
--- a/lib/ace/ext/searchbox.js
+++ b/lib/ace/ext/searchbox.js
@@ -281,6 +281,10 @@ var SearchBox = function(editor, range, showReplaceForm) {
this.editor.keyBinding.addKeyboardHandler(this.$closeSearchBarKb);
};
+ this.isFocused = function() {
+ var el = document.activeElement;
+ return el == this.searchInput || el == this.replaceInput;
+ }
}).call(SearchBox.prototype);
exports.SearchBox = SearchBox;
diff --git a/lib/ace/keyboard/emacs.js b/lib/ace/keyboard/emacs.js
index df14b9a1..ab4471b2 100644
--- a/lib/ace/keyboard/emacs.js
+++ b/lib/ace/keyboard/emacs.js
@@ -64,7 +64,7 @@ exports.handler.attach = function(editor) {
initialized = true;
dom.importCssString('\
.emacs-mode .ace_cursor{\
- border: 2px rgba(50,250,50,0.8) solid!important;\
+ border: 1px rgba(50,250,50,0.8) solid!important;\
-moz-box-sizing: border-box!important;\
-webkit-box-sizing: border-box!important;\
box-sizing: border-box!important;\
@@ -195,6 +195,8 @@ exports.handler.onPaste = function(e, editor) {
};
exports.handler.bindKey = function(key, command) {
+ if (typeof key == "object")
+ key = key[this.platform];
if (!key)
return;
diff --git a/lib/ace/keyboard/hash_handler.js b/lib/ace/keyboard/hash_handler.js
index cb02f170..06badccd 100644
--- a/lib/ace/keyboard/hash_handler.js
+++ b/lib/ace/keyboard/hash_handler.js
@@ -33,37 +33,25 @@ define(function(require, exports, module) {
var keyUtil = require("../lib/keys");
var useragent = require("../lib/useragent");
+var KEY_MODS = keyUtil.KEY_MODS;
function HashHandler(config, platform) {
this.platform = platform || (useragent.isMac ? "mac" : "win");
this.commands = {};
this.commandKeyBinding = {};
-
- // todo remove this after a while
- if (this.__defineGetter__ && this.__defineSetter__ && typeof console != "undefined" && console.error) {
- var warned = false;
- var warn = function() {
- if (!warned) {
- warned = true;
- console.error("commmandKeyBinding has too many m's. use commandKeyBinding");
- }
- };
- this.__defineGetter__("commmandKeyBinding", function() {
- warn();
- return this.commandKeyBinding;
- });
- this.__defineSetter__("commmandKeyBinding", function(val) {
- warn();
- return this.commandKeyBinding = val;
- });
- } else {
- this.commmandKeyBinding = this.commandKeyBinding;
- }
-
this.addCommands(config);
-};
+ this.$singleCommand = true;
+}
+
+function MultiHashHandler(config, platform) {
+ HashHandler.call(this, config, platform);
+ this.$singleCommand = false;
+}
+
+MultiHashHandler.prototype = HashHandler.prototype;
(function() {
+
this.addCommand = function(command) {
if (this.commands[command.name])
@@ -75,37 +63,76 @@ function HashHandler(config, platform) {
this._buildKeyHash(command);
};
- this.removeCommand = function(command) {
- var name = (typeof command === 'string' ? command : command.name);
+ this.removeCommand = function(command, keepCommand) {
+ var name = command && (typeof command === 'string' ? command : command.name);
command = this.commands[name];
- delete this.commands[name];
+ if (!keepCommand)
+ delete this.commands[name];
// exhaustive search is brute force but since removeCommand is
// not a performance critical operation this should be OK
var ckb = this.commandKeyBinding;
- for (var hashId in ckb) {
- for (var key in ckb[hashId]) {
- if (ckb[hashId][key] == command)
- delete ckb[hashId][key];
+ for (var keyId in ckb) {
+ var cmdGroup = ckb[keyId];
+ if (cmdGroup == command) {
+ delete ckb[keyId];
+ } else if (Array.isArray(cmdGroup)) {
+ var i = cmdGroup.indexOf(command);
+ if (i != -1) {
+ cmdGroup.splice(i, 1);
+ if (cmdGroup.length == 1)
+ ckb[keyId] = cmdGroup[0];
+ }
}
}
};
- this.bindKey = function(key, command) {
- if(!key)
+ this.bindKey = function(key, command, asDefault) {
+ if (typeof key == "object")
+ key = key[this.platform];
+ if (!key)
return;
- if (typeof command == "function") {
- this.addCommand({exec: command, bindKey: key, name: command.name || key});
- return;
- }
-
- var ckb = this.commandKeyBinding;
+ if (typeof command == "function")
+ return this.addCommand({exec: command, bindKey: key, name: command.name || key});
+
key.split("|").forEach(function(keyPart) {
- var binding = this.parseKeys(keyPart, command);
- var hashId = binding.hashId;
- (ckb[hashId] || (ckb[hashId] = {}))[binding.key] = command;
+ var chain = "";
+ if (keyPart.indexOf(" ") != -1) {
+ var parts = keyPart.split(/\s+/);
+ keyPart = parts.pop();
+ parts.forEach(function(keyPart) {
+ var binding = this.parseKeys(keyPart);
+ var id = KEY_MODS[binding.hashId] + binding.key;
+ chain += (chain ? " " : "") + id;
+ this._addCommandToBinding(chain, "chainKeys");
+ }, this);
+ chain += " ";
+ }
+ var binding = this.parseKeys(keyPart);
+ var id = KEY_MODS[binding.hashId] + binding.key;
+ this._addCommandToBinding(chain + id, command, asDefault);
}, this);
};
+
+ this._addCommandToBinding = function(keyId, command, asDefault) {
+ var ckb = this.commandKeyBinding, i;
+ if (!command) {
+ delete ckb[keyId];
+ } else if (!ckb[keyId] || this.$singleCommand) {
+ ckb[keyId] = command;
+ } else {
+ if (!Array.isArray(ckb[keyId])) {
+ ckb[keyId] = [ckb[keyId]];
+ } else if ((i = ckb[keyId].indexOf(command)) != -1) {
+ ckb[keyId].splice(i, 1);
+ }
+
+ if (asDefault || command.isDefault)
+ ckb[keyId].unshift(command);
+ else
+ ckb[keyId].push(command);
+ }
+ };
this.addCommands = function(commands) {
commands && Object.keys(commands).forEach(function(name) {
@@ -142,21 +169,12 @@ function HashHandler(config, platform) {
};
this._buildKeyHash = function(command) {
- var binding = command.bindKey;
- if (!binding)
- return;
-
- var key = typeof binding == "string" ? binding: binding[this.platform];
- this.bindKey(key, command);
+ this.bindKey(command.bindKey, command);
};
// accepts keys in the form ctrl+Enter or ctrl-Enter
// keys without modifiers or shift only
this.parseKeys = function(keys) {
- // todo support keychains
- if (keys.indexOf(" ") != -1)
- keys = keys.split(/\s+/).pop();
-
var parts = keys.toLowerCase().split(/[\-\+]([\-\+])?/).filter(function(x){return x});
var key = parts.pop();
@@ -173,7 +191,7 @@ function HashHandler(config, platform) {
var modifier = keyUtil.KEY_MODS[parts[i]];
if (modifier == null) {
if (typeof console != "undefined")
- console.error("invalid modifier " + parts[i] + " in " + keys);
+ console.error("invalid modifier " + parts[i] + " in " + keys);
return false;
}
hashId |= modifier;
@@ -182,17 +200,32 @@ function HashHandler(config, platform) {
};
this.findKeyCommand = function findKeyCommand(hashId, keyString) {
- var ckbr = this.commandKeyBinding;
- return ckbr[hashId] && ckbr[hashId][keyString];
+ var key = KEY_MODS[hashId] + keyString;
+ return this.commandKeyBinding[key];
};
this.handleKeyboard = function(data, hashId, keyString, keyCode) {
- return {
- command: this.findKeyCommand(hashId, keyString)
- };
+ var key = KEY_MODS[hashId] + keyString;
+ var command = this.commandKeyBinding[key];
+ if (data.$keyChain) {
+ data.$keyChain += " " + key;
+ command = this.commandKeyBinding[data.$keyChain] || command;
+ }
+
+ if (command) {
+ if (command == "chainKeys" || command[command.length - 1] == "chainKeys") {
+ data.$keyChain = data.$keyChain || key;
+ return {command: "null"};
+ }
+ }
+
+ if (data.$keyChain && keyCode > 0)
+ data.$keyChain = "";
+ return {command: command};
};
-}).call(HashHandler.prototype)
+}).call(HashHandler.prototype);
exports.HashHandler = HashHandler;
+exports.MultiHashHandler = MultiHashHandler;
});
diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js
index d2293024..1e6b057e 100644
--- a/lib/ace/keyboard/textinput.js
+++ b/lib/ace/keyboard/textinput.js
@@ -66,13 +66,13 @@ var TextInput = function(parentNode, host) {
// ie9 throws error if document.activeElement is accessed too soon
try { var isFocused = document.activeElement === text; } catch(e) {}
- event.addListener(text, "blur", function() {
- host.onBlur();
+ event.addListener(text, "blur", function(e) {
+ host.onBlur(e);
isFocused = false;
});
- event.addListener(text, "focus", function() {
+ event.addListener(text, "focus", function(e) {
isFocused = true;
- host.onFocus();
+ host.onFocus(e);
resetSelection();
});
this.focus = function() { text.focus(); };
diff --git a/lib/ace/lib/keys.js b/lib/ace/lib/keys.js
index e75a6e47..722c544d 100644
--- a/lib/ace/lib/keys.js
+++ b/lib/ace/lib/keys.js
@@ -145,6 +145,9 @@ var Keys = (function() {
}
})();
+ ret.KEY_MODS[0] = "";
+ ret.KEY_MODS[-1] = "input";
+
return ret;
})();
oop.mixin(exports, Keys);
diff --git a/lib/ace/line_widgets.js b/lib/ace/line_widgets.js
index 7ee76d48..4e5ae39d 100644
--- a/lib/ace/line_widgets.js
+++ b/lib/ace/line_widgets.js
@@ -45,9 +45,10 @@ function LineWidgets(session) {
this.renderWidgets = this.renderWidgets.bind(this);
this.measureWidgets = this.measureWidgets.bind(this);
this.session._changedWidgets = [];
- this.detach = this.detach.bind(this);
+ this.$onChangeEditor = this.$onChangeEditor.bind(this);
this.session.on("change", this.updateOnChange);
+ this.session.on("changeEditor", this.$onChangeEditor);
}
(function() {
@@ -73,8 +74,12 @@ function LineWidgets(session) {
return screenRows;
};
+ this.$onChangeEditor = function(e) {
+ this.attach(e.editor);
+ };
+
this.attach = function(editor) {
- if (editor.widgetManager && editor.widgetManager != this)
+ if (editor && editor.widgetManager && editor.widgetManager != this)
editor.widgetManager.detach();
if (this.editor == editor)
@@ -83,21 +88,16 @@ function LineWidgets(session) {
this.detach();
this.editor = editor;
- this.editor.on("changeSession", this.detach);
-
- editor.widgetManager = this;
-
- editor.renderer.on("beforeRender", this.measureWidgets);
- editor.renderer.on("afterRender", this.renderWidgets);
+ if (editor) {
+ editor.widgetManager = this;
+ editor.renderer.on("beforeRender", this.measureWidgets);
+ editor.renderer.on("afterRender", this.renderWidgets);
+ }
};
this.detach = function(e) {
- if (e && e.session == this.session)
- return; // sometimes attach can be called before setSession
var editor = this.editor;
if (!editor)
return;
-
- editor.off("changeSession", this.detach);
this.editor = null;
editor.widgetManager = null;
diff --git a/lib/ace/mode/_test/highlight_rules_test.js b/lib/ace/mode/_test/highlight_rules_test.js
index 57273292..647ca3c3 100644
--- a/lib/ace/mode/_test/highlight_rules_test.js
+++ b/lib/ace/mode/_test/highlight_rules_test.js
@@ -1,20 +1,66 @@
var fs = require("fs");
+var path = require("path");
if (!fs.existsSync)
- fs.existsSync = require("path").existsSync;
+ fs.existsSync = path.existsSync;
require("amd-loader");
var cwd = __dirname + "/";
+var root = path.normalize(cwd + Array(5).join("../"));
+
+function jsFileList(path, filter) {
+ if (!filter) filter = /_test/;
+ return fs.readdirSync(path).map(function(x) {
+ if (x.slice(-3) == ".js" && !filter.test(x) && !/\s/.test(x))
+ return x.slice(0, -3);
+ }).filter(Boolean);
+}
+
+function modeList() {
+ return jsFileList(cwd + "../", /_highlight_rules|_test|_worker|xml_util|_outdent|behaviour|completions/);
+}
+
+function checkModes() {
+ modeList().forEach(function(modeName) {
+ try {
+ var Mode = require("../" + modeName).Mode;
+ } catch(e) {
+ console.warn("Can't load mode :" + modeName, e);
+ return;
+ }
+ var m = new Mode();
+ if (!m.lineCommentStart && !m.blockComment)
+ console.warn("missing comment in " + modeName);
+ if (!m.$id)
+ console.warn("missing id in " + modeName);
+ var tokenizer = (new Mode).getTokenizer();
+ if (m.lineCommentStart) {
+ if (Array.isArray(m.lineCommentStart)) {
+ m.lineCommentStart.forEach(function(x) {
+ testLineComment(tokenizer, x, modeName)
+ });
+ } else {
+ testLineComment(tokenizer, m.lineCommentStart, modeName)
+ }
+ }
+ // if (m.blockComment) {
+ // var tokens = tok.getLineTokens(m.lineCommentStart, "start");
+ // if (!/comment/.test(tokens[0]))
+ // console.warn("broken lineCommentStart in " + modeName);
+ // }
+ });
+
+ function testLineComment(tokenizer, commentStart, modeName) {
+ var tokens = tokenizer.getLineTokens(commentStart + " ", "start").tokens;
+ if (!/comment/.test(tokens[0].type))
+ console.warn("broken lineCommentStart in " + modeName);
+ }
+}
function generateTestData() {
- var root = Array(5).join("../") + "/demo/kitchen-sink/docs";
- var docs = fs.readdirSync(cwd + root);
+ var docs = jsFileList(cwd + root);
var specialDocs = fs.readdirSync(cwd);
- var modes = fs.readdirSync(cwd + "../").filter(function(x){
- return !/(_highlight_rules|behaviour|worker)\.js$/.test(x) && /\.js$/.test(x);
- }).map(function(x) {
- return x.replace(/\.js$/, "");
- });
+ var modes = modeList();
console.log("Docs:", docs);
console.log("Modes:", modes);
@@ -61,7 +107,7 @@ function generateTestData() {
return tmp.join(",\n ");
});
- jsonStr = "[[\n " + data.join("\n],[\n ") + "\n]]";
+ var jsonStr = "[[\n " + data.join("\n],[\n ") + "\n]]";
fs.writeFileSync(cwd + "tokens_" + modeName + ".json", jsonStr, "utf8");
});
}
@@ -91,7 +137,7 @@ function testMode(modeName, i) {
lineData.state = lineData.shift();
var line = null;
if (typeof lineData[lineData.length - 1] == "string")
- line = lineData.pop()
+ line = lineData.pop();
lineData.forEach(function(x) {
lineData.types.push(x[0]);
lineData.values.push(x[1]);
@@ -103,14 +149,13 @@ function testMode(modeName, i) {
var values = tokens.tokens.map(function(x) {return x.value;});
var types = tokens.tokens.map(function(x) {return x.type;});
- var success = true;
var err = testEqual([
JSON.stringify(lineData.state), JSON.stringify(tokens.state),
lineData.types, types,
lineData.values, values]);
if (err) {
- console.log(line)
+ console.log(line);
throw "error";
}
@@ -150,10 +195,12 @@ function padNumber(num, digits) {
// cli
var arg = process.argv[2];
if (!arg)
- test()
+ test();
else if (/--?g(en)?/.test(arg))
generateTestData(process.argv.splice(3));
+else if (/--?c(heck)?/.test(arg))
+ checkModes(process.argv.splice(3));
else if (/\d+/.test(arg))
test(parseInt(process.argv[2],10) || 0);
else
- testMode(arg, -1)
\ No newline at end of file
+ testMode(arg, -1);
\ No newline at end of file
diff --git a/lib/ace/mode/_test/tokens_sh.json b/lib/ace/mode/_test/tokens_sh.json
index e4ab3412..53411906 100644
--- a/lib/ace/mode/_test/tokens_sh.json
+++ b/lib/ace/mode/_test/tokens_sh.json
@@ -11,13 +11,13 @@
["comment","# Repo formats:"]
],[
"start",
- ["comment","# ssh git@github.com:richoH/gh_pr.git"]
+ ["comment","# ssh git@github.com:richo/gh_pr.git"]
],[
"start",
- ["comment","# http https://richoH@github.com/richoH/gh_pr.git"]
+ ["comment","# http https://richoH@github.com/richo/gh_pr.git"]
],[
"start",
- ["comment","# git git://github.com/richoH/gh_pr.git"]
+ ["comment","# git git://github.com/richo/gh_pr.git"]
],[
"start"
],[
@@ -331,4 +331,4 @@
["keyword","fi"]
],[
"start"
-]]
\ No newline at end of file
+]]
diff --git a/lib/ace/mode/actionscript.js b/lib/ace/mode/actionscript.js
index 93297e42..7daf2941 100644
--- a/lib/ace/mode/actionscript.js
+++ b/lib/ace/mode/actionscript.js
@@ -27,10 +27,6 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
- * Contributor(s):
- *
- *
- *
* ***** END LICENSE BLOCK ***** */
/*
diff --git a/lib/ace/mode/autohotkey.js b/lib/ace/mode/autohotkey.js
index 21d3c802..d7093fd5 100644
--- a/lib/ace/mode/autohotkey.js
+++ b/lib/ace/mode/autohotkey.js
@@ -26,11 +26,6 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- *
- * Contributor(s):
- *
- *
- *
* ***** END LICENSE BLOCK ***** */
/*
@@ -53,7 +48,7 @@ var Mode = function() {
oop.inherits(Mode, TextMode);
(function() {
- this.lineCommentStart = "/\\*";
+ this.lineCommentStart = ";";
this.blockComment = {start: "/*", end: "*/"};
this.$id = "ace/mode/autohotkey";
}).call(Mode.prototype);
diff --git a/lib/ace/mode/c_cpp_highlight_rules.js b/lib/ace/mode/c_cpp_highlight_rules.js
index 008da9d5..8aad5046 100644
--- a/lib/ace/mode/c_cpp_highlight_rules.js
+++ b/lib/ace/mode/c_cpp_highlight_rules.js
@@ -50,11 +50,12 @@ var c_cppHighlightRules = function() {
// regexp must not have capturing parentheses. Use (?:) instead.
// regexps are ordered -> the first match is used
- this.$rules = {
+ this.$rules = {
"start" : [
{
token : "comment",
- regex : "\\/\\/.*$"
+ regex : "//",
+ next : "singleLineComment"
},
DocCommentHighlightRules.getStartRule("doc-start"),
{
@@ -121,14 +122,26 @@ var c_cppHighlightRules = function() {
regex : ".+"
}
],
+ "singleLineComment" : [
+ {
+ token : "comment",
+ regex : /\\$/,
+ next : "singleLineComment"
+ }, {
+ token : "comment",
+ regex : /$/,
+ next : "start"
+ }, {
+ defaultToken: "comment"
+ }
+ ],
"qqstring" : [
{
token : "string",
regex : '(?:(?:\\\\.)|(?:[^"\\\\]))*?"',
next : "start"
}, {
- token : "string",
- regex : '.+'
+ defaultToken : "string"
}
],
"qstring" : [
@@ -137,8 +150,7 @@ var c_cppHighlightRules = function() {
regex : "(?:(?:\\\\.)|(?:[^'\\\\]))*?'",
next : "start"
}, {
- token : "string",
- regex : '.+'
+ defaultToken : "string"
}
],
"directive" : [
diff --git a/lib/ace/mode/coffee_highlight_rules.js b/lib/ace/mode/coffee_highlight_rules.js
index a6d33abb..94c9476f 100644
--- a/lib/ace/mode/coffee_highlight_rules.js
+++ b/lib/ace/mode/coffee_highlight_rules.js
@@ -142,7 +142,7 @@ define(function(require, exports, module) {
}
if (val == "}" && stack.length) {
stack.shift();
- this.next = stack.shift();
+ this.next = stack.shift() || "";
if (this.next.indexOf("string") != -1)
return "paren.string";
}
diff --git a/lib/ace/mode/d.js b/lib/ace/mode/d.js
index 7c3a53c1..03c723e0 100644
--- a/lib/ace/mode/d.js
+++ b/lib/ace/mode/d.js
@@ -47,7 +47,7 @@ var Mode = function() {
oop.inherits(Mode, TextMode);
(function() {
- this.lineCommentStart = "/\\+";
+ this.lineCommentStart = "//";
this.blockComment = {start: "/*", end: "*/"};
this.$id = "ace/mode/d";
}).call(Mode.prototype);
diff --git a/lib/ace/mode/doc_comment_highlight_rules.js b/lib/ace/mode/doc_comment_highlight_rules.js
index 5262a8e8..11b4e813 100644
--- a/lib/ace/mode/doc_comment_highlight_rules.js
+++ b/lib/ace/mode/doc_comment_highlight_rules.js
@@ -35,22 +35,28 @@ var oop = require("../lib/oop");
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
var DocCommentHighlightRules = function() {
-
this.$rules = {
"start" : [ {
token : "comment.doc.tag",
regex : "@[\\w\\d_]+" // TODO: fix email addresses
- }, {
- token : "comment.doc.tag",
- regex : "\\bTODO\\b"
- }, {
- defaultToken : "comment.doc"
+ },
+ DocCommentHighlightRules.getTagRule(),
+ {
+ defaultToken : "comment.doc",
+ caseInsensitive: true
}]
};
};
oop.inherits(DocCommentHighlightRules, TextHighlightRules);
+DocCommentHighlightRules.getTagRule = function(start) {
+ return {
+ token : "comment.doc.tag.storage.type",
+ regex : "\\b(?:TODO|FIXME|XXX|HACK)\\b"
+ };
+}
+
DocCommentHighlightRules.getStartRule = function(start) {
return {
token : "comment.doc", // doc comment
diff --git a/lib/ace/mode/elm.js b/lib/ace/mode/elm.js
new file mode 100644
index 00000000..169e9b39
--- /dev/null
+++ b/lib/ace/mode/elm.js
@@ -0,0 +1,58 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * Copyright (c) 2012, Ajax.org B.V.
+ * 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 Ajax.org B.V. 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 HOLDERS AND CONTRIBUTORS "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 AJAX.ORG B.V. 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ THIS FILE WAS AUTOGENERATED BY mode.tmpl.js
+*/
+
+define(function(require, exports, module) {
+"use strict";
+
+var oop = require("../lib/oop");
+var TextMode = require("./text").Mode;
+var HighlightRules = require("./elm_highlight_rules").ElmHighlightRules;
+// TODO: pick appropriate fold mode
+var FoldMode = require("./folding/cstyle").FoldMode;
+
+var Mode = function() {
+ this.HighlightRules = HighlightRules;
+ this.foldingRules = new FoldMode();
+};
+oop.inherits(Mode, TextMode);
+
+(function() {
+ this.lineCommentStart = "--";
+ this.blockComment = {start: "{-", end: "-}"};
+ // Extra logic goes here.
+ this.$id = "ace/mode/elm";
+}).call(Mode.prototype);
+
+exports.Mode = Mode;
+});
\ No newline at end of file
diff --git a/lib/ace/mode/elm_highlight_rules.js b/lib/ace/mode/elm_highlight_rules.js
new file mode 100644
index 00000000..6b435fdf
--- /dev/null
+++ b/lib/ace/mode/elm_highlight_rules.js
@@ -0,0 +1,162 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * Copyright (c) 2012, Ajax.org B.V.
+ * 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 Ajax.org B.V. 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 HOLDERS AND CONTRIBUTORS "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 AJAX.ORG B.V. 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// TODO check with https://github.com/deadfoxygrandpa/Elm.tmLanguage
+
+define(function(require, exports, module) {
+"use strict";
+
+var oop = require("../lib/oop");
+var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
+
+var ElmHighlightRules = function() {
+ var keywordMapper = this.createKeywordMapper({
+ "keyword": "as|case|class|data|default|deriving|do|else|export|foreign|" +
+ "hiding|jsevent|if|import|in|infix|infixl|infixr|instance|let|" +
+ "module|newtype|of|open|then|type|where|_|port|\u03BB"
+ }, "identifier");
+
+ var escapeRe = /\\(\d+|['"\\&trnbvf])/;
+
+ var smallRe = /[a-z_]/.source;
+ var largeRe = /[A-Z]/.source;
+ var idRe = /[a-z_A-Z0-9\']/.source;
+
+ this.$rules = {
+ start: [{
+ token: "string.start",
+ regex: '"',
+ next: "string"
+ }, {
+ token: "string.character",
+ regex: "'(?:" + escapeRe.source + "|.)'?"
+ }, {
+ regex: /0(?:[xX][0-9A-Fa-f]+|[oO][0-7]+)|\d+(\.\d+)?([eE][-+]?\d*)?/,
+ token: "constant.numeric"
+ }, {
+ token : "keyword",
+ regex : /\.\.|\||:|=|\\|\"|->|<-|\u2192/
+ }, {
+ token : "keyword.operator",
+ regex : /[-!#$%&*+.\/<=>?@\\^|~:\u03BB\u2192]+/
+ }, {
+ token : "operator.punctuation",
+ regex : /[,;`]/
+ }, {
+ regex : largeRe + idRe + "+\\.?",
+ token : function(value) {
+ if (value[value.length - 1] == ".")
+ return "entity.name.function";
+ return "constant.language";
+ }
+ }, {
+ regex : "^" + smallRe + idRe + "+",
+ token : function(value) {
+ return "constant.language";
+ }
+ }, {
+ token : keywordMapper,
+ regex : "[\\w\\xff-\\u218e\\u2455-\\uffff]+\\b"
+ }, {
+ regex: "{-#?",
+ token: "comment.start",
+ onMatch: function(value, currentState, stack) {
+ this.next = value.length == 2 ? "blockComment" : "docComment";
+ return this.token;
+ }
+ }, {
+ token: "variable.language",
+ regex: /\[markdown\|/,
+ next: "markdown"
+ }, {
+ token: "paren.lparen",
+ regex: /[\[({]/
+ }, {
+ token: "paren.rparen",
+ regex: /[\])}]/
+ }, ],
+ markdown: [{
+ regex: /\|\]/,
+ next: "start"
+ }, {
+ defaultToken : "string"
+ }],
+ blockComment: [{
+ regex: "{-",
+ token: "comment.start",
+ push: "blockComment"
+ }, {
+ regex: "-}",
+ token: "comment.end",
+ next: "pop"
+ }, {
+ defaultToken: "comment"
+ }],
+ docComment: [{
+ regex: "{-",
+ token: "comment.start",
+ push: "docComment"
+ }, {
+ regex: "-}",
+ token: "comment.end",
+ next: "pop"
+ }, {
+ defaultToken: "doc.comment"
+ }],
+ string: [{
+ token: "constant.language.escape",
+ regex: escapeRe,
+ }, {
+ token: "text",
+ regex: /\\(\s|$)/,
+ next: "stringGap"
+ }, {
+ token: "string.end",
+ regex: '"',
+ next: "start"
+ }],
+ stringGap: [{
+ token: "text",
+ regex: /\\/,
+ next: "string"
+ }, {
+ token: "error",
+ regex: "",
+ next: "start"
+ }],
+ };
+
+ this.normalizeRules();
+};
+
+oop.inherits(ElmHighlightRules, TextHighlightRules);
+
+exports.ElmHighlightRules = ElmHighlightRules;
+});
diff --git a/lib/ace/mode/forth.js b/lib/ace/mode/forth.js
index 31e8d512..ce590576 100644
--- a/lib/ace/mode/forth.js
+++ b/lib/ace/mode/forth.js
@@ -27,10 +27,6 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
- * Contributor(s):
- *
- *
- *
* ***** END LICENSE BLOCK ***** */
/*
@@ -53,7 +49,7 @@ var Mode = function() {
oop.inherits(Mode, TextMode);
(function() {
- this.lineCommentStart = "(?<=^|\\s)\\.?\\( [^)]*\\)";
+ this.lineCommentStart = "--";
this.blockComment = {start: "/*", end: "*/"};
this.$id = "ace/mode/forth";
}).call(Mode.prototype);
diff --git a/lib/ace/mode/gitignore.js b/lib/ace/mode/gitignore.js
index fd9b04f4..fa263985 100644
--- a/lib/ace/mode/gitignore.js
+++ b/lib/ace/mode/gitignore.js
@@ -12,6 +12,7 @@ var Mode = function() {
oop.inherits(Mode, TextMode);
(function() {
+ this.lineCommentStart = "#";
this.$id = "ace/mode/gitignore";
}).call(Mode.prototype);
diff --git a/lib/ace/mode/javascript_highlight_rules.js b/lib/ace/mode/javascript_highlight_rules.js
index e81a2dce..767b8fa1 100644
--- a/lib/ace/mode/javascript_highlight_rules.js
+++ b/lib/ace/mode/javascript_highlight_rules.js
@@ -302,20 +302,24 @@ var JavaScriptHighlightRules = function(options) {
}
],
"comment_regex_allowed" : [
+ DocCommentHighlightRules.getTagRule(),
{token : "comment", regex : "\\*\\/", next : "start"},
- {defaultToken : "comment"}
+ {defaultToken : "comment", caseInsensitive: true}
],
"comment" : [
+ DocCommentHighlightRules.getTagRule(),
{token : "comment", regex : "\\*\\/", next : "no_regex"},
- {defaultToken : "comment"}
+ {defaultToken : "comment", caseInsensitive: true}
],
"line_comment_regex_allowed" : [
+ DocCommentHighlightRules.getTagRule(),
{token : "comment", regex : "$|^", next : "start"},
- {defaultToken : "comment"}
+ {defaultToken : "comment", caseInsensitive: true}
],
"line_comment" : [
+ DocCommentHighlightRules.getTagRule(),
{token : "comment", regex : "$|^", next : "no_regex"},
- {defaultToken : "comment"}
+ {defaultToken : "comment", caseInsensitive: true}
],
"qqstring" : [
{
diff --git a/lib/ace/mode/makefile.js b/lib/ace/mode/makefile.js
index 673f8927..efeca6ee 100644
--- a/lib/ace/mode/makefile.js
+++ b/lib/ace/mode/makefile.js
@@ -26,11 +26,6 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- *
- * Contributor(s):
- *
- *
- *
* ***** END LICENSE BLOCK ***** */
/*
diff --git a/lib/ace/mode/rust.js b/lib/ace/mode/rust.js
index 28485e97..a8840307 100644
--- a/lib/ace/mode/rust.js
+++ b/lib/ace/mode/rust.js
@@ -27,10 +27,6 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
- * Contributor(s):
- *
- *
- *
* ***** END LICENSE BLOCK ***** */
/*
diff --git a/lib/ace/mode/rust_highlight_rules.js b/lib/ace/mode/rust_highlight_rules.js
index acb6c92a..1a7d38a6 100644
--- a/lib/ace/mode/rust_highlight_rules.js
+++ b/lib/ace/mode/rust_highlight_rules.js
@@ -29,10 +29,6 @@
* ***** END LICENSE BLOCK ***** */
/* This file was autogenerated from https://raw.github.com/dbp/sublime-rust/master/Rust.tmLanguage (uuid: ) */
-/****************************************************************************************
- * IT MIGHT NOT BE PERFECT ...But it's a good start from an existing *.tmlanguage file. *
- * fileTypes *
- ****************************************************************************************/
define(function(require, exports, module) {
"use strict";
@@ -55,6 +51,35 @@ var RustHighlightRules = function() {
next: 'pop' },
{ include: '#rust_escaped_character' },
{ defaultToken: 'string.quoted.single.source.rust' } ] },
+ {
+ stateName: "bracketedComment",
+ onMatch : function(value, currentState, stack){
+ stack.unshift(this.next, value.length - 1, currentState);
+ return "string.quoted.raw.source.rust";
+ },
+ regex : /r#*"/,
+ next : [
+ {
+ onMatch : function(value, currentState, stack) {
+ var token = "string.quoted.raw.source.rust";
+ if (value.length >= stack[1]) {
+ if (value.length > stack[1])
+ token = "invalid";
+ stack.shift();
+ stack.shift();
+ this.next = stack.shift();
+ } else {
+ this.next = "";
+ }
+ return token;
+ },
+ regex : /"#*/,
+ next : "start"
+ }, {
+ defaultToken : "string.quoted.raw.source.rust"
+ }
+ ]
+ },
{ token: 'string.quoted.double.source.rust',
regex: '"',
push:
diff --git a/lib/ace/mode/stylus.js b/lib/ace/mode/stylus.js
index ebeb1fca..2c9c3cf8 100644
--- a/lib/ace/mode/stylus.js
+++ b/lib/ace/mode/stylus.js
@@ -51,7 +51,10 @@ var Mode = function() {
};
oop.inherits(Mode, TextMode);
-(function() {
+(function() {
+ this.lineCommentStart = "//";
+ this.blockComment = {start: "/*", end: "*/"};
+
this.$id = "ace/mode/stylus";
}).call(Mode.prototype);
diff --git a/lib/ace/mode/textile.js b/lib/ace/mode/textile.js
index d5525969..9a1ea809 100644
--- a/lib/ace/mode/textile.js
+++ b/lib/ace/mode/textile.js
@@ -43,6 +43,7 @@ var Mode = function() {
oop.inherits(Mode, TextMode);
(function() {
+ this.type = "text";
this.getNextLineIndent = function(state, line, tab) {
if (state == "intag")
return tab;
diff --git a/lib/ace/search.js b/lib/ace/search.js
index 325ce00f..c5119319 100644
--- a/lib/ace/search.js
+++ b/lib/ace/search.js
@@ -305,7 +305,7 @@ var Search = function() {
if (options.wholeWord)
needle = "\\b" + needle + "\\b";
- var modifier = options.caseSensitive ? "g" : "gi";
+ var modifier = options.caseSensitive ? "gm" : "gmi";
options.$isMultiLine = !$disableFakeMultiline && /[\n\r]/.test(needle);
if (options.$isMultiLine)
diff --git a/lib/ace/theme/cobalt.css b/lib/ace/theme/cobalt.css
index 22df0460..16568fc3 100644
--- a/lib/ace/theme/cobalt.css
+++ b/lib/ace/theme/cobalt.css
@@ -1,6 +1,6 @@
.ace-cobalt .ace_gutter {
background: #011e3a;
- color: #fff
+ color: rgb(128,145,160)
}
.ace-cobalt .ace_print-margin {
diff --git a/lib/ace/theme/idle_fingers.css b/lib/ace/theme/idle_fingers.css
index 91318b30..f507ec10 100644
--- a/lib/ace/theme/idle_fingers.css
+++ b/lib/ace/theme/idle_fingers.css
@@ -1,6 +1,6 @@
.ace-idle-fingers .ace_gutter {
background: #3b3b3b;
- color: #fff
+ color: rgb(153,153,153)
}
.ace-idle-fingers .ace_print-margin {
diff --git a/lib/ace/theme/tomorrow_night_bright.css b/lib/ace/theme/tomorrow_night_bright.css
index 183e0eaf..5c896fb9 100644
--- a/lib/ace/theme/tomorrow_night_bright.css
+++ b/lib/ace/theme/tomorrow_night_bright.css
@@ -34,12 +34,13 @@
margin: -1px 0 0 -1px;
border: 1px solid #888888
}
+
.ace-tomorrow-night-bright .ace_marker-layer .ace_highlight {
- border: 1px solid rgb(110, 119, 0);
- border-bottom: 0;
- box-shadow: inset 0 -1px rgb(110, 119, 0);
- margin: -1px 0 0 -1px;
- background: rgba(255, 235, 0, 0.1);
+ border: 1px solid rgb(110, 119, 0);
+ border-bottom: 0;
+ box-shadow: inset 0 -1px rgb(110, 119, 0);
+ margin: -1px 0 0 -1px;
+ background: rgba(255, 235, 0, 0.1)
}
.ace-tomorrow-night-bright .ace_marker-layer .ace_active-line {
@@ -132,7 +133,7 @@
}
.ace-tomorrow-night-bright .ace_c9searchresults.ace_keyword {
- color: #C2C280;
+ color: #C2C280
}
.ace-tomorrow-night-bright .ace_indent-guide {
diff --git a/lib/ace/worker/worker.js b/lib/ace/worker/worker.js
index e642a6ae..928000dd 100644
--- a/lib/ace/worker/worker.js
+++ b/lib/ace/worker/worker.js
@@ -17,7 +17,13 @@ window.window = window;
window.ace = window;
window.onerror = function(message, file, line, col, err) {
- console.error("Worker " + (err ? err.stack : message));
+ postMessage({type: "error", data: {
+ message: message,
+ file: file,
+ line: line,
+ col: col,
+ stack: err.stack
+ }});
};
window.normalizeModule = function(parentId, moduleName) {
@@ -84,15 +90,20 @@ window.define = function(id, deps, factory) {
deps = [];
id = window.require.id;
}
+
+ if (typeof factory != "function") {
+ window.require.modules[id] = {
+ exports: factory,
+ initialized: true
+ };
+ return;
+ }
if (!deps.length)
// If there is no dependencies, we inject 'require', 'exports' and
// 'module' as dependencies, to provide CommonJS compatibility.
deps = ['require', 'exports', 'module'];
- if (id.indexOf("text!") === 0)
- return;
-
var req = function(childId) {
return window.require(id, childId);
};
diff --git a/lib/ace/worker/worker_client.js b/lib/ace/worker/worker_client.js
index 430699e6..255a2cea 100644
--- a/lib/ace/worker/worker_client.js
+++ b/lib/ace/worker/worker_client.js
@@ -92,14 +92,9 @@ var WorkerClient = function(topLevelNamespaces, mod, classname, workerUrl) {
this.onMessage = function(e) {
var msg = e.data;
switch(msg.type) {
- case "log":
- window.console && console.log && console.log.apply(console, msg.data);
- break;
-
case "event":
this._signal(msg.name, {data: msg.data});
break;
-
case "call":
var callback = this.callbacks[msg.id];
if (callback) {
@@ -107,8 +102,18 @@ var WorkerClient = function(topLevelNamespaces, mod, classname, workerUrl) {
delete this.callbacks[msg.id];
}
break;
+ case "error":
+ this.reportError(msg.data);
+ break;
+ case "log":
+ window.console && console.log && console.log.apply(console, msg.data);
+ break;
}
};
+
+ this.reportError = function(err) {
+ window.console && console.error && console.error(err);
+ };
this.$normalizePath = function(path) {
return net.qualifyURL(path);
@@ -119,7 +124,8 @@ var WorkerClient = function(topLevelNamespaces, mod, classname, workerUrl) {
this.deltaQueue = null;
this.$worker.terminate();
this.$worker = null;
- this.$doc.removeEventListener("change", this.changeListener);
+ if (this.$doc)
+ this.$doc.off("change", this.changeListener);
this.$doc = null;
};
diff --git a/tool/Readme.md b/tool/Readme.md
new file mode 100644
index 00000000..28dd5166
--- /dev/null
+++ b/tool/Readme.md
@@ -0,0 +1,26 @@
+Helper Scripts for Ace
+======================
+
+To use this you need to install node.js. and run `npm install` in this directory.
+
+
+# add_mode.js
+
+ Run
+```
+node add_mode.js ModeName "extension1|extension2|^FullName"
+```
+ to create all the files needed for a new mode named `ModeName`
+ this adds stubs for:
+ `ace/mode/mode_name.js`
+ `ace/mode/mode_name_hightlight_rules.js`
+ `ace/snippets/mode_name.js`
+ `ace/demo/kitchen_sink/docs/mode_name.extension1`
+ and adds entry for the new mode to `ace/ext/modelist.js`
+
+
+# tmlanguage.js
+
+```
+node tmlanguage.js ./templates/dummy.JSON-tmLanguage
+```
\ No newline at end of file
diff --git a/tool/add_mode.js b/tool/add_mode.js
index 09b4a7e6..2f70a14a 100644
--- a/tool/add_mode.js
+++ b/tool/add_mode.js
@@ -2,100 +2,105 @@ var fs = require('fs');
var lib = require('./lib');
var path = require('path');
-var args = process.argv.slice(2);
+function main(displayName, extRe) {
+ var name = lib.snakeCase(displayName).replace(/[^\w]/g, "");
+ /** demo **/
+ var demoFileExt = extRe.split("|")[0] || name;
+ var demoFileName = demoFileExt[0] == "^" ? demoFileExt.substr(1) : name + "." + demoFileExt;
+ var demoFilePath = lib.AceRoot + "demo/kitchen-sink/docs/" + demoFileName;
+ fs.writeFileSync(demoFilePath, "TODO add a nice demo!", "utf8");
+ console.log("Created demo file at: " + path.normalize(demoFilePath));
-var displayName = args[0];
-var extRe = args[1];
-if (!displayName || ! extRe) {
- console.log("Usage: ModeName ext1|ext2");
- process.exit(1);
+ /** mode **/
+ var template = fs.readFileSync(__dirname + "/templates/mode.js", "utf8");
+ var modePath = lib.AceLib + "ace/mode/" + name + ".js";
+ var text = lib.fillTemplate(template, {
+ languageHighlightFilename: name,
+ languagename: name,
+ lineCommentStart: "TODO",
+ blockCommentStart: "TODO",
+ blockCommentEnd: "TODO"
+ });
+ fs.writeFileSync(modePath, text);
+ console.log("Created mode file at: " + path.normalize(modePath));
+
+ /** highlight rules **/
+ template = fs.readFileSync(__dirname + "/templates/highlight_rules.js", "utf8");
+ var hlPath = lib.AceLib + "ace/mode/" + name + "_highlight_rules.js";
+ template = template.replace(/\/\* THIS[\s\S]*?\*{3}\/\s*/, "");
+ text = lib.fillTemplate(template, {
+ language: name,
+ languageTokens: '{\n\
+ start: [{\n\
+ token: "string.start",\n\
+ regex: \'"\',\n\
+ next: "qstring"\n\
+ }],\n\
+ qstring: [{\n\
+ token: "escape",\n\
+ regex: /\\\\./,\n\
+ }, {\n\
+ token: "string.end",\n\
+ regex: \'"\',\n\
+ next: "start"\n\
+ }],\n\
+ }'
+ });
+ fs.writeFileSync(hlPath, text);
+ console.log("Created mode file at: " + path.normalize(hlPath));
+
+ /** snippets **/
+ template = fs.readFileSync(__dirname + "/templates/snippets.js", "utf8");
+ var snipetsPath = lib.AceLib + "ace/snippets/" + name + ".js";
+ text = lib.fillTemplate(template, {
+ languagename: name,
+ snippets: ""
+ });
+ fs.writeFileSync(snipetsPath, text);
+ console.log("Created snippets file at: " + path.normalize(snipetsPath));
+
+ /** modelist **/
+ var modelistPath = lib.AceLib + "ace/ext/modelist.js";
+ var modelist = fs.readFileSync(modelistPath, "utf8").replace(/\r\n?/g, "\n");
+ modelist = modelist.replace(/(supportedModes = {\n)([\s\S]*?)(\n^};)/m, function(_, m1, m2, m3) {
+ var langs = m2.split(/,\n/);
+ var offset = langs[0].trim().indexOf("[");
+ var padding = Array(Math.max(offset - displayName.length - 1, 0) + 1).join(" ");
+ var newLang = " " + displayName + ":" + padding + "[\"" + extRe + "\"]";
+ langs = langs.concat(newLang).map(function(x) {
+ return {
+ value: x,
+ id: x.match(/[^"':\s]+/)[0].toLowerCase()
+ };
+ });
+ langs[langs.length - 1].isNew = true;
+
+ langs = langs.filter(function(x) {
+ console.log(x.id, displayName)
+ return x.id != displayName.toLowerCase() || x.isNew;
+ });
+ langs = langs.sort(function(a, b) {
+ return a.id.localeCompare(b.id);
+ }).map(function(x) {
+ return x.value;
+ });
+
+ return m1 + langs.join(",\n") + m3;
+ });
+ fs.writeFileSync(modelistPath, modelist, "utf8");
+ console.log("Updated modelist at: " + path.normalize(modelistPath));
}
-var name = lib.snakeCase(displayName).replace(/[^\w]/g, "");
-
-/** demo **/
-var demoFileExt = extRe.split("|")[0] || name;
-var demoFileName = demoFileExt[0] == "^" ? demoFileExt.substr(1) : name + "." + demoFileExt;
-var demoFilePath = lib.AceRoot + "demo/kitchen-sink/docs/" + demoFileName;
-fs.writeFileSync(demoFilePath, "TODO add a nice demo!", "utf8");
-console.log("Created demo file at: " + path.normalize(demoFilePath));
-
-/** mode **/
-var template = fs.readFileSync(__dirname + "/templates/mode.js", "utf8");
-var modePath = lib.AceLib + "ace/mode/" + name + ".js";
-var text = lib.fillTemplate(template, {
- languageHighlightFilename: name,
- languagename: name,
- lineCommentStart: "TODO",
- blockCommentStart: "TODO",
- blockCommentEnd: "TODO"
-});
-fs.writeFileSync(modePath, text);
-console.log("Created mode file at: " + path.normalize(modePath));
-
-/** highlight rules **/
-template = fs.readFileSync(__dirname + "/templates/highlight_rules.js", "utf8");
-var hlPath = lib.AceLib + "ace/mode/" + name + "_highlight_rules.js";
-template = template.replace(/\/\* THIS[\s\S]*?\*{3}\/\s*/, "");
-text = lib.fillTemplate(template, {
- language: name,
- languageTokens: '{\n\
- start: [{\n\
- token: "string.start",\n\
- regex: \'"\',\n\
- next: "qstring"\n\
- }],\n\
- qstring: [{\n\
- token: "escape",\n\
- regex: /\\\\./,\n\
- }, {\n\
- token: "string.end",\n\
- regex: \'"\',\n\
- next: "start"\n\
- }],\n\
- }'
-});
-fs.writeFileSync(hlPath, text);
-console.log("Created mode file at: " + path.normalize(hlPath));
-
-/** snippets **/
-template = fs.readFileSync(__dirname + "/templates/snippets.js", "utf8");
-var snipetsPath = lib.AceLib + "ace/snippets/" + name + ".js";
-text = lib.fillTemplate(template, {
- languagename: name,
- snippets: ""
-});
-fs.writeFileSync(snipetsPath, text);
-console.log("Created snippets file at: " + path.normalize(snipetsPath));
-
-/** modelist **/
-var modelistPath = lib.AceLib + "ace/ext/modelist.js";
-var modelist = fs.readFileSync(modelistPath, "utf8").replace(/\r\n?/g, "\n");
-modelist = modelist.replace(/(supportedModes = {\n)([\s\S]*?)(\n^};)/m, function(_, m1, m2, m3) {
- var langs = m2.split(/,\n/);
- var offset = langs[0].trim().indexOf("[");
- var padding = Array(Math.max(offset - displayName.length - 1, 0) + 1).join(" ");
- var newLang = " " + displayName + ":" + padding + "[\"" + extRe + "\"]";
- langs = langs.concat(newLang).map(function(x) {
- return {
- value: x,
- id: x.match(/[^"':\s]+/)[0].toLowerCase()
- };
- });
- langs[langs.length - 1].isNew = true;
-
- langs = langs.filter(function(x) {
- return x.id != name || x.isNew;
- });
- langs = langs.sort(function(a, b) {
- return a.id.localeCompare(b.id);
- }).map(function(x) {
- return x.value;
- });
-
- return m1 + langs.join(",\n") + m3;
-});
-fs.writeFileSync(modelistPath, modelist, "utf8");
-console.log("Updated modelist at: " + path.normalize(modelistPath));
+if (!module.parent) {
+ var args = process.argv.slice(2);
+ var displayName = args[0];
+ var extRe = args[1];
+ if (!displayName || ! extRe) {
+ console.log("Usage: ModeName ext1|ext2");
+ process.exit(1);
+ }
+} else {
+ module.exports = main;
+}
diff --git a/tool/lib.js b/tool/lib.js
index d7c0af26..e72194d7 100644
--- a/tool/lib.js
+++ b/tool/lib.js
@@ -5,13 +5,18 @@ var url = require("url");
var https = require("https");
var http = require("http");
-exports.parsePlist = function(themeXml, callback) {
- var result = "";
- plist.parseString(themeXml, function(_, theme) {
- result = theme[0];
- callback && callback(theme[0]);
- });
- return result;
+exports.parsePlist = function(xmlOrJSON, callback) {
+ var json;
+ if (xmlOrJSON[0] == "<") {
+ plist.parseString(xmlOrJSON, function(_, result) {
+ json = result[0];
+ });
+ } else {
+ xmlOrJSON = xmlOrJSON.replace(/^\s*\/\/.*/gm, "");
+ json = JSON.parse(xmlOrJSON)
+ }
+ callback && callback(json);
+ return json;
};
exports.formatJSON = function(object, initialIndent) {
diff --git a/tool/mode_creator.js b/tool/mode_creator.js
index 3eda8c8c..6b1122cd 100644
--- a/tool/mode_creator.js
+++ b/tool/mode_creator.js
@@ -2,6 +2,11 @@ define(function(require, exports, module) {
/** creates globals intentionally to make things easily accessible from console **/
+require("ace/ext/language_tools");
+require("ace/config").setDefaultValues("editor", {
+ enableBasicAutocompletion: true,
+ enableSnippets: true
+});
var net = require("ace/lib/net");
var Range = require("ace/range").Range;
var util = require("demo/kitchen-sink/util");
@@ -79,28 +84,28 @@ document.getElementById("syncToMode").onclick = function() {
docEl.value = modelist.modesByName[modeEl.value].desc;
docEl.onchange();
run();
-}
+};
document.getElementById("perfTest").onclick = function() {
- var lines = editor2.session.doc.getAllLines()
+ var lines = editor2.session.doc.getAllLines();
if (!lines.length)
- return
+ return;
while (lines.length < 1000) {
- lines = lines.concat(lines)
+ lines = lines.concat(lines);
}
var tk = new Tokenizer(currentRules);
- var testPerf = function(lines, tk){
- var state = "start"
+ var testPerf = function(lines, tk) {
+ var state = "start";
for (var i=0, l = lines.length; i |'\w+\b[+-]?\d'))/, merge:false},
+ {include: "charTypes", merge:false},
+ {token: "charclass", regex: /\[\^?/, push: "charclass", merge:false},
+ {token: "alternation", regex: /\|/, merge:false},
+ {include: "quantifiers", merge:false},
+ {include: "groups", merge:false},
+ {include: "xGroup", merge:true}
+ ],
+ charTypes: [
+ {token: "char", regex: /\\([tvnrbfae]|[0-8]{1,3}|x[\dA-Fa-f]{2}|x7[\dA-Fa-f]{7})/, merge:false}, // todo \cx
+ {token: "charType", regex: /\.|\\[wWsSdDhH]/, merge:false},
+ {token: "charProperty", regex: /\\p{\w+}/, merge:false},
+ {token: "char", regex: /\\./, merge:false},
+ ],
+ quantifiers: [
+ {token: "quantifier", regex: /([?*+]|{\d+\b,?\d*}|{,\d+})[?+]?/, merge:false}
+ ],
+ charclass: [
+ {include: "charTypes", merge:false},
+ {token: "charclass.start", regex: /\[\^?/, push: "charclass", merge:false},
+ {token: "charclass.end", regex: /\]/, next: "pop", merge:false}
+ ],
+ groups: [
+ {token: "group", regex: /[(]([?](#|[imx\-]+:?|:|=|!|<=||<\w+>|'\w+'|))?|[)]/,
+ onMatch: function(val, state, stack) {
+ if (!stack.groupNumber)
+ stack.groupNumber = 1;
+
+ var isStart = val !== ")";
+ var t = {depth:0,type: isStart ? "group.start" : "group.end", value: val};
+ t.groupType = val[2];
+
+ if (val == "(") {
+ t.number = stack.groupNumber++;
+ t.isGroup = true
+ } else if (t.groupType == "'" || (t.groupType == "<" && val.slice(-1) == ">")) {
+ t.name = val.slice(2, -1)
+ t.isGroup = true
+ } else if (t.groupType == ":") {
+ t.isGroup = true
+ }
+
+ if (t.groupType && val.indexOf("x") != -1) {
+ var minus = val.indexOf("-");
+ if (minus == -1 || minus > val.indexOf("x"))
+ stack.xGroup = t;
+ else
+ stack.xGroup = null;
+ } else if (!isStart && stack.xGroup && stack.xGroup == stack[0]) {
+ if (stack.xGroup.value.slice(-1) == ":")
+ stack.xGroup = null;
+ }
+
+ if (isStart) {
+ if (stack.groupDepth) {
+ stack[0].hasChildren = true
+ }
+ stack.groupDepth = (stack.groupDepth||0)+1;
+ stack.unshift(t)
+ } else {
+ stack.groupDepth --;
+ t.start = stack.shift(t)
+ t.start.end = t
+ }
+ return [t]
+ }, merge:false
+ }
+ ],
+ xGroup: [
+ {token: "text", regex:/\s+/, onMatch: function(val, state, stack) {
+ return stack.xGroup ? [] : "text"
+ }, merge: true},
+ {token: "text", regex: /#/, onMatch: function(val, state, stack) {
+ if (stack.xGroup) {
+ this.next = "comment";
+ stack.unshift(state);
+ return [];
+ }
+ this.next = "";
+ return "text";
+ }, merge: true}
+ ],
+ comment: [{
+ regex: "[^\n\r]*|^", token: "", onMatch: function(val, state, stack) {
+ this.next = stack.shift();
+ return [];
+ }
+ }]
+}
+r.normalizeRules()
+var tmReTokenizer = new Tokenizer(r.getRules());
+
+function tokenize(str) {
+ return tmReTokenizer.getLineTokens(str).tokens;
+}
+
+function toStr(tokens) { return tokens.map(function(x){return x.value}).join("")}
+
+
+exports.tokenize = tokenize;
+exports.toStr = toStr;
+exports.tmReTokenizer = tmReTokenizer;
\ No newline at end of file
diff --git a/tool/regexp_tokenizer_test.js b/tool/regexp_tokenizer_test.js
new file mode 100644
index 00000000..aa09ff12
--- /dev/null
+++ b/tool/regexp_tokenizer_test.js
@@ -0,0 +1,30 @@
+require("amd-loader");
+var assert = require("assert");
+
+var tk = require("./regexp_tokenizer");
+var tokenize = tk.tokenize;
+var toStr = tk.toStr;
+
+var logTokens = function(tokens) {
+ tokens.forEach(function(x) {
+ delete x.end
+ delete x.start
+ })
+ console.log(tokens)
+}
+
+assert.equal(toStr(
+ tokenize("(?x)c + +\n\
+ # comment\n\
+ (?-x) # (?x: 1 \n\
+ (2) [ ] # a \n\
+ 3 4) c#"
+ )),
+ "(?x)c++(?-x) # (?x:1(2)[ ]34) c#"
+ )
+assert.equal(toStr(
+ tokenize("(?x)\n\
+ u # comment\n\
+ ")),
+ "(?x)u"
+ )
diff --git a/tool/templates/dummy.JSON-tmLanguage b/tool/templates/dummy.JSON-tmLanguage
new file mode 100644
index 00000000..cb58b29b
--- /dev/null
+++ b/tool/templates/dummy.JSON-tmLanguage
@@ -0,0 +1,45 @@
+// [PackageDev] target_format: plist, ext: tmLanguage
+{
+ "name": "Dummy",
+ "scopeName": "source.dummy",
+ "fileTypes": ["dummy"],
+ "patterns": [
+ {
+ "include": "#string"
+ }, {
+ "include": "#escapes"
+ }
+ ],
+ "repository": {
+ "escapes": {
+ "patterns": [
+ {
+ "match": "\\\\[nrt\\\\\\$\\\"']",
+ "name": "keyword.dummy"
+ }
+ ]
+ },
+ "string": {
+ "beginCaptures": {
+ "0": {
+ "name": "punctuation.definition.string.begin.dummy"
+ }
+ },
+ "endCaptures": {
+ "0": {
+ "name": "punctuation.definition.string.end.dummy"
+ }
+ },
+ "contentName": "meta.string-contents.quoted.double.dummy",
+ "name": "string.quoted.double.dummy",
+ "end": "'''",
+ "begin": "'''",
+ "patterns": [
+ {
+ "include": "#escapes"
+ }
+ ],
+ "comment": "This is a comment"
+ }
+ }
+}
\ No newline at end of file
diff --git a/tool/templates/highlight_rules.tmpl.js b/tool/templates/highlight_rules.js
similarity index 79%
rename from tool/templates/highlight_rules.tmpl.js
rename to tool/templates/highlight_rules.js
index 82b22c07..db8f5630 100644
--- a/tool/templates/highlight_rules.tmpl.js
+++ b/tool/templates/highlight_rules.js
@@ -28,17 +28,11 @@
*
* ***** END LICENSE BLOCK ***** */
-/* THIS FILE WAS AUTOGENERATED FROM %name% (UUID: %uuid%) */
-/****************************************************************
- * IT MIGHT NOT BE PERFECT, PARTICULARLY: *
- * IN DECIDING STATES TO TRANSITION TO, *
- * IGNORING WHITESPACE, *
- * IGNORING GROUPS WITH ?:, *
- * EXTENDING EXISTING MODES, *
- * GATHERING KEYWORDS, OR *
- * DECIDING WHEN TO USE PUSH. *
- * ...But it's a good start from an existing *.tmlanguage file. *
- ****************************************************************/
+/* This file was autogenerated from %name% (uuid: %uuid%) */
+/****************************************************************************************
+ * IT MIGHT NOT BE PERFECT ...But it's a good start from an existing *.tmlanguage file. *
+ * fileTypes *
+ ****************************************************************************************/
define(function(require, exports, module) {
"use strict";
@@ -55,6 +49,9 @@ var %language%HighlightRules = function() {
this.normalizeRules();
};
+%language%HighlightRules.metaData = %metaData%
+
+
oop.inherits(%language%HighlightRules, TextHighlightRules);
exports.%language%HighlightRules = %language%HighlightRules;
diff --git a/tool/templates/mode.js b/tool/templates/mode.js
index ff21c885..1cdabf15 100644
--- a/tool/templates/mode.js
+++ b/tool/templates/mode.js
@@ -48,8 +48,8 @@ var Mode = function() {
oop.inherits(Mode, TextMode);
(function() {
- this.lineCommentStart = "%lineCommentStart%";
- this.blockComment = {start: "%blockCommentStart%", end: "%blockCommentEnd%"};
+ // this.lineCommentStart = "%lineCommentStart%";
+ // this.blockComment = {start: "%blockCommentStart%", end: "%blockCommentEnd%"};
// Extra logic goes here.
this.$id = "ace/mode/%languageHighlightFilename%"
}).call(Mode.prototype);
diff --git a/tool/templates/theme.css b/tool/templates/theme.css
index 39bb2437..8515d0c3 100644
--- a/tool/templates/theme.css
+++ b/tool/templates/theme.css
@@ -1,8 +1,8 @@
/* THIS THEME WAS AUTOGENERATED BY Theme.tmpl.css (UUID: %uuid%) */
.%cssClass% .ace_gutter {
- background: #e8e8e8;
- color: #333;
+ background: %gutterBg%;
+ color: %gutterFg%;
}
.%cssClass% .ace_print-margin {
diff --git a/tool/tmlanguage.js b/tool/tmlanguage.js
index fc575339..d3e42141 100644
--- a/tool/tmlanguage.js
+++ b/tool/tmlanguage.js
@@ -1,8 +1,330 @@
+require("amd-loader");
+
var fs = require("fs");
var util = require("util");
var lib = require("./lib");
+var pathlib = require("path");
var parseLanguage = lib.parsePlist;
+var tk = require("./regexp_tokenizer");
+var tokenize = tk.tokenize;
+var toStr = tk.toStr;
+
+function last(array) {return array[array.length - 1]}
+
+function convertHexEscape(tokens) {
+ var inChClass = false;
+ tokens.forEach(function(t) {
+ if (t.type == "charclass")
+ inChClass = true;
+ else if (t.type == "charclass.end")
+ inChClass = false;
+ else if (t.type == "charType"){
+ if (t.value == "\\h") {
+ t.type = "text";
+ t.value = inChClass ? "\\da-fA-F" : "[\\da-fA-F]";
+ }
+ else if (t.value == "\\H") {
+ if (inChClass) {
+ console.warn("can't convert \\H in charclass");
+ return;
+ }
+ t.type = "text";
+ t.value = "[^\\da-fA-F]";
+ }
+ }
+ });
+ return tokens;
+}
+
+function convertNewLinesTo$(str) {
+ var tokens = tokenize(str);
+ for (var i = 0; i < tokens.length; i++) {
+ var t= tokens[i];
+ if (t.type == "char" && t.value == "\\n") {
+ var p = tokens[i + 1] || {};
+ if (p.type != "quantifier") {
+ t.value = "$";
+ while (p.value == "\\n" || p.type == "quantifier") {
+ p.value = "";
+ p = tokens[++i + 1] || {};
+ }
+ } else if (/\?|\*|{,|{0,/.test(p.value)) {
+ t.value = p.value = "";
+ } else
+ p.value = "";
+ }
+ }
+ return toStr(tokens).replace(/[$]+/g, "$");
+}
+
+function convertCharacterTypes(str) {
+ var tokens = tokenize(str);
+ tokens = convertHexEscape(tokens);
+
+ var warn = false;
+ tokens.forEach(function(t){
+ if (t.type == "quantifier") {
+ var val = t.value;
+ if (val.slice(-1) == "+" && val.length > 1) {
+ t.value = val.slice(0, -1);
+ warn = val;
+ }
+ }
+ });
+ if (warn)
+ console.log("converted possesive quantifier " + warn + " to *");
+ return toStr(tokens);
+}
+
+function removeInlineFlags(str, rule) {
+ var tokens = tokenize(str);
+ var caseInsensitive = false;
+ tokens.forEach(function(t, i) {
+ if (t.type == "group.start" && /[imsx]/.test(t.value)) {
+ if (/i/.test(t.value))
+ caseInsensitive = true;
+ t.value = t.value.replace(/[imsx\-]/g, "");
+ var next = tokens[i + 1];
+ if (next && next.type == "group.end") {
+ t.value = next.value = "";
+ }
+ }
+ });
+ if (caseInsensitive && rule)
+ rule.caseInsensitive = true;
+ return toStr(tokens);
+}
+
+function convertToNonCapturingGroups(str) {
+ var tokens = tokenize(str);
+ tokens.forEach(function(t, i) {
+ if (t.type == "group.start" && t.value == "(")
+ t.value += "?:";
+ });
+ return toStr(tokens);
+}
+
+function simplifyNonCapturingGroups(str) {
+ var tokens = tokenize(str);
+ var t = tokens[0];
+ if (t.type == "group.start" && t.value == "(?:"
+ && t.end == last(tokens)) {
+ t.value = t.end.value = "";
+ }
+ var i = 0;
+ function iter(f) {
+ for (i = 0; i < tokens.length; i++)
+ f(tokens[i]);
+ }
+ function iterGroup(end, f) {
+ for (var i1 = i + 1; i1 < tokens.length; i1++) {
+ var t = tokens[i1];
+ if (t == end)
+ break;
+ var index = f && f(t);
+ if (index > i1)
+ i1 = index;
+ }
+ return i1;
+ }
+
+ iter(function (t) {
+ if (t.type == "group.start" && t.value == "(?:") {
+ if (!t.end)
+ return console.error("malformed regex: " + str);
+
+ var canRemove = true;
+ var next = tokens[tokens.indexOf(t.end, i) + 1];
+ if (next && next.type == "quantifier")
+ return;
+ iterGroup(t.end, function(t) {
+ if (t.type == "alternation")
+ canRemove = false;
+ else if (t.type == "group.start" && t.end)
+ return iterGroup(t.end);
+ });
+ if (canRemove)
+ t.value = t.end.value = "";
+ }
+ });
+
+ return toStr(tokens);
+}
+
+function removeLookBehinds(str) {
+ var tokens = tokenize(str);
+ var toRemove = null;
+ tokens.forEach(function(t, i) {
+ if (!toRemove && t.type == "group.start" && / i)
+ i = i1;
+ }
+ function lst(t) {return t[t.length - 1]}
+ function iter(f) {
+ for (i = 0; i < tokens.length; i++)
+ f(tokens[i]);
+ }
+ function iterGroup(end, f) {
+ for (var i1 = i + 1; i1 < tokens.length; i1++) {
+ var t = tokens[i1];
+ if (t == end)
+ break;
+ f(t);
+ }
+ }
+ function peek() { return tokens[i + 1] || {}}
+
+ // groupify
+ iter(function(t){
+ if (t.type == "group.start") {
+ tryClose();
+ isStart = true;
+ if (!t.hasChildren || t.isSpecial)
+ skip(t);
+ } else if (t.type == "group.end") {
+ isStart = true;
+ tryClose();
+ } else if (t.type == "alternation") {
+ isStart = true;
+ tryClose();
+ } else if (t.type != "anchor" && t.type != "quantifier"){
+ tryOpen();
+ }
+ });
+ tryClose();
+
+ // remove redundand groups
+ var names = [defaultName];
+ iter(function(t){
+ if (t.type == "group.start" && !t.isSpecial) {
+ var captureName = captures[t.number];
+
+ if (!t.hasChildren) {
+ t.tokenName = captureName || lst(names);
+ skip(t);
+ } else {
+ var hasCapture = false;
+ iterGroup(t.end, function(t1) {
+ if (t1.type == "group.start" && captures[t1.number])
+ hasCapture = true;
+ });
+ if (hasCapture) {
+ t.value = "(?:";
+ if (captureName) {
+ names.push(captureName);
+ t.isTokenGroup = true;
+ }
+ } else {
+ t.tokenName = captureName || lst(names);
+ iterGroup(t.end, function(t1) {
+ if (t1.value == "(")
+ t1.value = "(?:";
+ });
+ }
+ }
+ } else if (t.type == "group.end") {
+ if (t.start.isTokenGroup)
+ names.pop();
+ }
+ });
+
+ // wrap capturing groups with quantifier
+ iter(function(t){
+ if (t.type == "group.end" && t.start.value == "(" && peek().type == "quantifier") {
+ peek().value += ")";
+ t.start.value += "(?:";
+ }
+ });
+
+ names = [];
+ tokens.forEach(function(t) {
+ if (t.value == "(" || t.value == "((?:" )
+ t.tokenName && names.push(t.tokenName);
+ });
+ return {
+ names: names,
+ regex: toStr(tokens)
+ };
+}
+
+/***** converter */
function logDebug(string, obj) {
console.log(string, obj);
@@ -13,7 +335,6 @@ function logDebug(string, obj) {
// for tracking token states
var states = {start: []};
-var stateName = "start";
function processRules(rules){
if (rules.patterns)
@@ -40,29 +361,38 @@ function processPatterns(pl) {
return pl.map(processPattern);
}
function processPattern(p) {
-
if (p.end == "(?!\\G)" && p.patterns && p.patterns.length == 1) {
var rule = processPattern(p.patterns[0]);
}
- else if (p.begin && p.end) {
- var rule = simpleRule(p.begin, p.name, p.beginCaptures || p.captures)
+ else if (p.begin != null && p.end != null) {
+ convertBeginEndBackrefs(p);
+
+ var rule = simpleRule(p.begin, p.name, p.beginCaptures || p.captures);
var next = processPatterns(p.patterns || []);
var endRule = simpleRule(p.end, p.name, p.endCaptures || p.captures);
endRule.next = "pop";
- next.push(endRule);
+ if (p.applyEndPatternLast)
+ next.push(endRule);
+ else
+ next.unshift(endRule);
if (p.name || p.contentName)
next.push({defaultToken: p.name || p.contentName});
rule.push = next;
+
+ rule = removeIncludeSelf(rule);
}
else if (p.match) {
- var rule = simpleRule(p.match, p.name, p.captures)
+ var rule = simpleRule(p.match, p.name, p.captures);
}
else if (p.include) {
var rule = {include: p.include};
}
+ else {
+ var rule = {todo: p};
+ }
if (p.comment)
rule.comment = (rule.comment || "") + p.comment;
@@ -73,106 +403,269 @@ function processPattern(p) {
}
function simpleRule(regex, name, captures) {
name = name || "text";
- var rule = {};
+ var rule = {token: "", regex: ""};
- var origRegex = regex
- regex = transformRegExp(regex, rule);
+ var origRegex = regex;
+ regex = transformRegExp(origRegex, rule);
if (captures) {
var tokenArray = [];
Object.keys(captures).forEach(function(x){
tokenArray[x] = captures[x] && captures[x].name;
});
+
if (tokenArray.length == 1) {
name = tokenArray[0];
} else {
- for (var i = 0; i < tokenArray.length; i++)
- if (!tokenArray[i])
- tokenArray[i] = name;
- name = tokenArray;
- rule.todo = "fix grouping";
+ var fixed = fixGroups(tokenArray, name, regex);
+ name = fixed.names;
+ regex = fixed.regex;
+ if (name.length == 1)
+ name = name[0];
}
}
+ if (typeof name == "string")
+ regex = convertToNonCapturingGroups(regex);
+
+ regex = simplifyNonCapturingGroups(regex);
+
try {new RegExp(regex);} catch(e) {
rule.TODO = "FIXME: regexp doesn't have js equivalent";
- rule.originalRegex = origRegex
+ rule.originalRegex = origRegex;
+
+ // lookbehinds are mostly used to force ordering
+ // regex = removeLookBehinds(regex);
}
rule.token = name;
rule.regex = regex;
return rule;
}
+function removeIncludeSelf(rule) {
+ if (!rule.push)
+ return rule;
+ var hasSelfInclude = false;
+ var escapeRule = null;
+ var complexSelfInclude = false;
+ rule.push.forEach(function(sub) {
+ if (sub.include == "$self") {
+ hasSelfInclude = true;
+ } else if (sub.defaultToken) {
+ return;
+ } else if (sub.next == "pop") {
+ escapeRule = sub;
+ } else
+ complexSelfInclude = true;
+ });
+
+ if (hasSelfInclude) {
+ console.warn("can't convert include $self");
+ return {todo: rule};
+
+ if (complexSelfInclude) {
+ console.warn("can't convert include $self");
+ rule.toDo = "include $self not fully supported";
+ return rule;
+ }
+ console.warn("include $self not fully supported");
+ delete rule.push;
+ delete escapeRule.next;
+ rule.includeSelf = true;
+ escapeRule.includeSelf = true;
+ return [rule, escapeRule];
+ }
+ return rule;
+}
// regex transformation
function removeXFlag(str) {
- if (str && str.slice(0,4) == "(?x)") {
- str = str.replace(/\\.|\[([^\]\\]|\\.)*?\]|\s+|(?:#[^\n]*)/g, function(s) {
- if (s[0] == "[")
- return s;
- if (s[0] == "\\")
- return /[#\s]/.test(s[1]) ? s[1] : s;
- return "";
- }).substr(4);
- }
- return str;
+ var tokens = tokenize(str);
+ return toStr(tokens);
}
function transformRegExp(str, rule) {
- str = removeXFlag(str);
- //str = str.replace(/\\n\$|\$\\n/g, '$');
- str = str.replace(/\\n(?!\?).?/g, '$'); // replace newlines by $ except if its postfixed by ?
- if (/\(\?[i]\:|\(?\w*i\w*\)/g.test(str)) {
- str = str.replace(/\(\?[ims\-]\:/g, "(?:"); // checkForInvariantRegex
- str = str.replace(/\(\?[imsx\-]\)/g, "");
- rule && (rule.caseInsensitive = true);
- }
+ str = convertNewLinesTo$(str);
+
+ str = removeInlineFlags(str, rule);
+
str = str.replace(/(\\[xu]){([a-fA-F\d]+)}/g, '$1$2');
+
+ str = convertCharacterTypes(str, rule);
+
+ checkForNamedCaptures(str);
+
return str;
}
//
function extractPatterns(tmRules) {
- var patterns = processRules(tmRules);
- return lib.restoreJSONComments(lib.formatJSON(patterns, " "));
-
+ return processRules(tmRules);
}
+function detectLoops(states) {
+ var data = {};
+ var keys = Object.keys(states);
+ var flattenedStates = {};
+ function addRef(item, name) {
+ if (item.refs.indexOf(name) == -1)
+ item.refs.push(name);
+ }
+ function anonStateId(name, next) {
+ var i = 0, old = name;
+ while (flattenedStates[name] || states[name]) {
+ name = old + "_" + i++;
+ }
+ // console.log(old, name)
+ return name;
+ }
+ function addState(key, rules) {
+ if (rules && !flattenedStates[key])
+ flattenedStates[key] = rules;
+ return rules || flattenedStates[key];
+ }
+
+
+ for (var i = 0; i < keys.length; i++) {
+ var key = keys[i];
+ var state = addState(key, states[key]);
+
+ var item = data[key] || (data[key] = {/* name: key, */ refs: []});
+ state.forEach(function(rule) {
+ var next = rule.push || rule.next;
+ if (next == "pop") {
+ // nothing
+ } else if (typeof next == "string") {
+ addRef(item, next);
+ } else if (next) {
+ var anonId = anonStateId(key, next);
+ addState(anonId, next);
+ if (rule.push)
+ addRef(item, anonId);
+ keys.push(anonId);
+ } else if (rule.include) {
+ addRef(item, rule.include);
+ }
+ });
+ }
+
+
+ var cycles = [];
+ function addPath(start, path) {
+ var node = data[start];
+ path.push(start);
+ if (!node || !node.refs)
+ console.log(start);
+ var i = path.indexOf(start);
+ if (i > -1 && i != path.length - 1 || start == "$self" || start == "$base") {
+ if (i != -1)
+ path = path.slice(i);
+ for (var j = 0; j < cycles.length; j++) {
+ if (cycles[j] + "" == path + "")
+ return;
+ }
+ return cycles.push(path);
+ }
+
+ if (!node || !node.refs || !node.refs.length || path.length>30)
+ return;
+ node.refs.forEach(function(x) {
+ addPath(x, path.concat());
+ });
+ }
+ addPath("start", []);
+
+ console.error(cycles.join("\n"));
+}
+
+
+function test(fileName) {
+ console.log("testing highlighter");
+ try {
+ var module = require(fileName);
+ var Mode = module[Object.keys(module)[0]];
+ var mode = new Mode();
+ mode.getTokenizer().getLineTokens("hello world");
+ } catch(e) {
+ console.log(e);
+ }
+}
+
+function guessComment(patterns) {
+ var comment = {};
+ for (var i in patterns) {
+ var state = patterns[i];
+ state.forEach(function(r) {
+ if (typeof r.token == "string") {
+ if (/\bcomment\b/.test(r.token)) {
+ comment.line = r.regex;
+ }
+ }
+ });
+ }
+
+ return comment;
+}
// cli stuff
var modeTemplate = fs.readFileSync(__dirname + "/templates/mode.js", "utf8");
var modeHighlightTemplate = fs.readFileSync(__dirname + "/templates/highlight_rules.js", "utf8");
-function convertLanguageFile(name) {
- var path = /^(\/|\w:)/.test(name) ? name : process.cwd() + "/" + name
- var tmLanguage = fs.readFileSync(path, "utf8");
- parseLanguage(tmLanguage, function(language) {
- var languageHighlightFilename = language.name.replace(/[-_]/g, "").toLowerCase();
- var languageNameSanitized = language.name.replace(/-/g, "");
+function fetchAndConvert(name) {
+ console.log("Converting " + name);
+ if (/^http/.test(name)) {
+ if (/:\/\/github.com/.test(name)) {
+ name = name.replace(/\/blob\//, "/").replace("github.com", "raw.github.com");
+ }
+ return lib.download(name, function(data) {
+ convertTmLanguage(name, data);
+ });
+ }
+ var path = /^(\/|\w:)/.test(name) ? name : process.cwd() + "/" + name;
+ var langStr = fs.readFileSync(path, "utf8");
+ convertTmLanguage(name, langStr);
+}
- var languageHighlightFile = __dirname + "/../lib/ace/mode/" + languageHighlightFilename + "_highlight_rules.js";
- var languageModeFile = __dirname + "/../lib/ace/mode/" + languageHighlightFilename + ".js";
- console.log("Converting " + name + " to " + languageHighlightFile);
+function convertTmLanguage(name, langStr) {
+ parseLanguage(langStr, function(language) {
+ var highlighterFilename = lib.snakeCase(language.name).replace(/[^\w]/g, "");
+ var languageNameSanitized = lib.camelCase(language.name).replace(/[^\w]/g, "");
+
+ require("./add_mode")(languageNameSanitized, (language.fileTypes || []).join("|"));
+
+ var highlighterFile = pathlib.normalize(lib.AceLib + "ace/mode/" + highlighterFilename + "_highlight_rules.js");
+ var modeFile = pathlib.normalize(lib.AceLib + "ace/mode/" + highlighterFilename + ".js");
if (devMode) {
console.log(util.inspect(language.patterns, false, 4));
console.log(util.inspect(language.repository, false, 4));
}
+ var patterns = extractPatterns(language);
+ detectLoops(patterns);
+
+ // var uuid = language.uuid
+ delete language.uuid;
+ delete language.patterns;
+ delete language.repository;
+
+ var comment = guessComment(patterns);
var languageMode = lib.fillTemplate(modeTemplate, {
language: languageNameSanitized,
- languageHighlightFilename: languageHighlightFilename
+ languageHighlightFilename: highlighterFilename,
+ lineCommentStart: JSON.stringify(comment.line || "//"),
+ blockCommentStart: JSON.stringify(comment.start || "/*"),
+ blockCommentEnd: JSON.stringify(comment.end || "*/")
});
- var patterns = extractPatterns(language);
-
var languageHighlightRules = lib.fillTemplate(modeHighlightTemplate, {
language: languageNameSanitized,
- languageTokens: patterns.trim(),
+ languageTokens: lib.formatJSON(patterns, " ").trim(),
uuid: language.uuid,
- name: name
+ name: name,
+ metaData: lib.formatJSON(language, " ").trim()
});
if (devMode) {
@@ -181,17 +674,23 @@ function convertLanguageFile(name) {
console.log("Not writing, 'cause we're in dev mode, baby.");
}
else {
- fs.writeFileSync(languageHighlightFile, languageHighlightRules);
- fs.writeFileSync(languageModeFile, languageMode);
+ fs.writeFileSync(highlighterFile, languageHighlightRules);
+ fs.writeFileSync(modeFile, languageMode);
+ console.log("created file " + highlighterFile);
+ test(modeFile);
}
});
}
-var args = process.argv.splice(2);
-var tmLanguageFile = args[0];
-var devMode = args[1];
-if (tmLanguageFile === undefined) {
- console.error("Please pass in a language file via the command line.");
- process.exit(1);
+if (!module.parent) {
+ var args = process.argv.splice(2);
+ var tmLanguageFile = args[0];
+ var devMode = args[1];
+ if (tmLanguageFile === undefined) {
+ console.error("Usage: node tmlanguage.js path/or/url/to/syntax.file");
+ process.exit(1);
+ }
+ fetchAndConvert(tmLanguageFile);
+} else {
+ exports.fetchAndConvert = fetchAndConvert;
}
-convertLanguageFile(tmLanguageFile);
\ No newline at end of file
diff --git a/tool/tmtheme.js b/tool/tmtheme.js
index e9e34f39..02d9542e 100755
--- a/tool/tmtheme.js
+++ b/tool/tmtheme.js
@@ -115,7 +115,7 @@ function extractStyles(theme) {
var aceScope = supportedScopes[scope];
if (aceScope) {
- colors[aceScope] = style;
+ colors[aceScope] = style;
}
else if (style) {
unsupportedScopes[scope] = (unsupportedScopes[scope] || 0) + 1;
@@ -134,25 +134,44 @@ function extractStyles(theme) {
colors.fold = foldSource.match(/\:([^;]+)/)[1];
}
}
+
+ colors.gutterBg = colors.background
+ colors.gutterFg = mix(colors.foreground, colors.background, 0.5)
if (!colors.selected_word_highlight)
colors.selected_word_highlight = "border: 1px solid " + colors.selection + ";";
colors.isDark = (luma(colors.background) < 0.5) + "";
-
+
return colors;
};
-function luma(color) {
+function mix(c1, c2, a1, a2) {
+ c1 = rgbColor(c1);
+ c2 = rgbColor(c2);
+ if (a2 === undefined)
+ a2 = 1 - a1
+ return "rgb(" + [
+ Math.round(a1*c1[0] + a2*c2[0]),
+ Math.round(a1*c1[1] + a2*c2[1]),
+ Math.round(a1*c1[2] + a2*c2[2])
+ ].join(",") + ")";
+}
+
+function rgbColor(color) {
+ if (typeof color == "object")
+ return color;
if (color[0]=="#")
- var rgb = color.match(/^#(..)(..)(..)/).slice(1).map(function(c) {
+ return color.match(/^#(..)(..)(..)/).slice(1).map(function(c) {
return parseInt(c, 16);
});
else
- var rgb = color.match(/\(([^,]+),([^,]+),([^,]+)/).slice(1).map(function(c) {
+ return color.match(/\(([^,]+),([^,]+),([^,]+)/).slice(1).map(function(c) {
return parseInt(c, 10);
});
-
+}
+function luma(color) {
+ var rgb = rgbColor(color);
return (0.21 * rgb[0] + 0.72 * rgb[1] + 0.07 * rgb[2]) / 255;
}
diff --git a/tool/tmthemes/Katzenmilch.tmTheme b/tool/tmthemes/Katzenmilch.tmTheme
new file mode 100644
index 00000000..3878ffe9
--- /dev/null
+++ b/tool/tmthemes/Katzenmilch.tmTheme
@@ -0,0 +1,399 @@
+
+
+
+
+ name
+ Katzen-Milch
+ comment
+ Those silly germans and their cat milk! Ghee wizz!
+ settings
+
+
+ settings
+
+ background
+ #f3f2f3
+ caret
+ #100011
+ foreground
+ #0f0009ff
+ invisibles
+ #000000
+ lineHighlight
+ #ffffff
+ selection
+ #6405D044
+ selectionBorder
+ #8425f0
+ bracketContentsOptions
+ underline
+ tagsForeground
+ #0f0009ff
+ tagsOptions
+ underline
+
+
+
+ name
+ Parenthesis
+ scope
+ punctuation.definition.list
+ settings
+
+ fontStyle
+
+ foreground
+ #940494
+ background
+ #4444940a
+
+
+
+ name
+ Comment
+ scope
+ comment
+ settings
+
+ fontStyle
+ italic
+ foreground
+ #404f50aa
+ background
+ #5f0fff02
+
+
+
+ name
+ String
+ scope
+ string
+ settings
+
+ foreground
+ #5a5f9b
+ background
+ #aaafdb09
+
+
+
+ name
+ Number
+ scope
+ constant.numeric
+ settings
+
+ foreground
+ #4f827bee
+ background
+ #77c2bb0f
+
+
+
+ name
+ User-defined Constant
+ scope
+ constant.character, constant.other
+ settings
+
+ foreground
+ #025f69ff
+ background
+ #7f229910
+
+
+
+ name
+ Built-in Constant
+ scope
+ constant.language
+ settings
+
+ fontStyle
+
+ foreground
+ #7D7e52
+ background
+ #bDbe820f
+
+
+
+ name
+ Storage Modifier
+ scope
+ storage.modifier
+ settings
+
+ fontStyle
+ bold
+ foreground
+ #7B5D8f
+ background
+ #9B9FfD0a
+
+
+
+ name
+ Storage
+ scope
+ storage
+ settings
+
+ fontStyle
+ bold
+ foreground
+ #7B5cbfff
+ background
+ #8B5Ddf0d
+
+
+
+ name
+ Function Name
+ scope
+ entity.name.function
+ settings
+
+ fontStyle
+
+ foreground
+ #025f49f7
+ background
+ #22ff491f
+
+
+
+ name
+ Support Function
+ scope
+ support.function
+ settings
+
+ foreground
+ #9D7e62
+ background
+ #bDbe820a
+
+
+
+ name
+ Misc Function
+ scope
+ entity.name.function.misc
+ settings
+
+ foreground
+ #939469
+ background
+ #E3E4A90a
+
+
+
+ name
+ Predicate Function
+ scope
+ entity.name.function.predicate
+ settings
+
+ foreground
+ #856F63
+ background
+ #A5DF930a
+
+
+
+ name
+ Input/Output Function
+ scope
+ entity.name.function.io
+ settings
+
+ foreground
+ #aF938C
+ background
+ #DFB3AC0a
+
+
+
+ name
+ External Symbol
+ scope
+ variable.other.external-symbol
+ settings
+
+ foreground
+ #7BaFaD
+ background
+ #BBDFDD0a
+
+
+
+ name
+ Variable
+ scope
+ variable.language, variable.other
+ settings
+
+ foreground
+ #316fcf
+ background
+ #3aafff0a
+
+
+
+ name
+ Parameter Variable
+ scope
+ variable.parameter
+ settings
+
+ fontStyle
+ italic
+ foreground
+ #33969fdd
+ background
+ #05d6f90b
+
+
+
+ name
+ Keyword
+ scope
+ keyword
+ settings
+
+ foreground
+ #674Aa8
+ background
+ #A3AAD80e
+
+
+
+ name
+ Class Name
+ scope
+ entity.name.class
+ settings
+
+ fontStyle
+ bold
+ foreground
+ #B9986F
+ background
+ #B998DF22
+
+
+
+ name
+ Structure Name
+ scope
+ entity.name.structure
+ settings
+
+ foreground
+ #22af9d
+ background
+ #B998DF0a
+
+
+
+ name
+ Type Name
+ scope
+ entity.name.type
+ settings
+
+ foreground
+ #af47a9
+ background
+ #af77a90d
+
+
+
+ name
+ Class name
+ scope
+ entity.name.class, entity.name.type.class
+ settings
+
+ foreground
+ #cc4357
+ background
+ #ffddff92
+
+
+
+ name
+ Support Class
+ scope
+ support.class
+ settings
+
+ foreground
+ #ef6aa7ff
+ background
+ #ef6aa710
+
+
+
+ name
+ Invalid
+ scope
+ invalid
+ settings
+
+ background
+ #CC1B27
+ foreground
+ #DFDFD5
+
+
+
+
+ name
+ ♦ String embedded-source
+ scope
+ string source
+ settings
+
+ fontStyle
+ italic
+ foreground
+ #13499fdd
+ background
+ #0099ff0a
+
+
+
+ name
+ Tag name
+ scope
+ entity.name.tag
+ settings
+
+ foreground
+ #3976a2
+ background
+ #49a6d20a
+
+
+
+ name
+ Tag attribute
+ scope
+ entity.other.attribute-name
+ settings
+
+ fontStyle
+
+ foreground
+ #4946c2ee
+ background
+ #4986c209
+
+
+
+
+
diff --git a/tool/tmthemes/Kuroir Theme.tmTheme b/tool/tmthemes/Kuroir Theme.tmTheme
new file mode 100644
index 00000000..36acd588
--- /dev/null
+++ b/tool/tmthemes/Kuroir Theme.tmTheme
@@ -0,0 +1,916 @@
+
+
+
+
+ author
+ Stanley Rost
+ comment
+ Kuroir
+ name
+ Kuroir Theme
+ settings
+
+
+ settings
+
+ background
+ #E8E9E8
+ caret
+ #202020
+ foreground
+ #363636
+ invisibles
+ #0000004A
+ lineHighlight
+ #CBDC2F38
+ selection
+ #F5AA0091
+
+ bracketsForeground
+ #C41717
+ bracketsOptions
+ foreground underline
+
+ bracketContentsForeground
+ #C41717
+ bracketContentsOptions
+ foreground underline background
+
+ guide
+ #8F8F8F
+ activeGuide
+ #FA2828
+
+ tagsOptions
+ stippled_underline
+
+
+
+ name
+ Comment
+ scope
+ comment
+ settings
+
+ background
+ #DCDCDC8F
+ fontStyle
+
+ foreground
+ #949494E8
+
+
+
+ name
+ Regions
+ scope
+ comment.line.region
+ settings
+
+ background
+ #E9D6DC85
+ fontStyle
+
+ foreground
+ #A54776
+
+
+
+ name
+ Line Marker
+ scope
+ comment.line.marker.php
+ settings
+
+ background
+ #E9E4BE
+ foreground
+ #668D68
+
+
+
+ name
+ Todo
+ scope
+ comment.line.todo.php
+ settings
+
+ background
+ #D9EAB8
+ fontStyle
+
+ foreground
+ #456E48
+
+
+
+ name
+ FIXME
+ scope
+ comment.line.fixme.php
+ settings
+
+ background
+ #E1D0CA
+ fontStyle
+
+ foreground
+ #880006
+
+
+
+ name
+ Constant
+ scope
+ constant
+ settings
+
+ foreground
+ #CD6839
+
+
+
+ name
+ Entity
+ scope
+ entity
+ settings
+
+ background
+ #E8E9E8
+ fontStyle
+
+ foreground
+ #8B4726
+
+
+
+ name
+ Storage
+ scope
+ storage
+ settings
+
+ fontStyle
+
+ foreground
+ #A52A2A
+
+
+
+ name
+ Keyword Control
+ scope
+ keyword.control
+ settings
+
+ foreground
+ #CD3700
+
+
+
+ name
+ Library Function
+ scope
+ support.function - variable, keyword.other.special-method.ruby
+ settings
+
+ foreground
+ #B03060
+
+
+
+ name
+ Comparison
+ scope
+ keyword.operator.comparison,keyword.operator.logical
+ settings
+
+ foreground
+ #B83126
+
+
+
+ name
+ String
+ scope
+ string
+ settings
+
+ fontStyle
+
+ foreground
+ #639300
+
+
+
+ name
+ R Interpolation
+ scope
+ string.quoted.double.ruby source.ruby.embedded.source
+ settings
+
+ foreground
+ #007E69
+
+
+
+ name
+ Support
+ scope
+ support
+ settings
+
+ fontStyle
+
+ foreground
+ #104E8B
+
+
+
+ name
+ Variable
+ scope
+ variable
+ settings
+
+ foreground
+ #009ACD
+
+
+
+ name
+ Invalid Deprecated
+ scope
+ invalid.deprecated
+ settings
+
+ background
+ #E8E9E8
+ fontStyle
+ italic underline
+ foreground
+ #FD1732
+
+
+
+ name
+ Invalid Illegal
+ scope
+ invalid.illegal
+ settings
+
+ background
+ #FF060026
+ foreground
+ #FD1224
+
+
+
+ name
+ Embedded Source (Bright)
+ scope
+ text source
+ settings
+
+ background
+ #77ADE900
+ foreground
+ #7B211A
+
+
+
+ name
+ Entity inherited-class
+ scope
+ entity.other.inherited-class
+ settings
+
+ fontStyle
+ italic
+ foreground
+ #005273
+
+
+
+ name
+ String.regexp
+ scope
+ string.regexp
+ settings
+
+ background
+ #C9D4BE
+ foreground
+ #417E00
+
+
+
+ name
+ Support.function
+ scope
+ support.function
+ settings
+
+ fontStyle
+
+ foreground
+ #005273
+
+
+
+ name
+ Support.constant
+ scope
+ support.constant
+ settings
+
+ fontStyle
+
+ foreground
+ #CF6A4C
+
+
+
+ name
+ j Entity Name Type
+ scope
+ entity.name.type
+ settings
+
+ fontStyle
+ underline
+
+
+
+ name
+ j Cast
+ scope
+ meta.cast
+ settings
+
+ fontStyle
+ italic
+ foreground
+ #676767
+
+
+
+ name
+ Doctype/XML Processing
+ scope
+ meta.sgml.html meta.doctype, meta.sgml.html meta.doctype entity, meta.sgml.html meta.doctype string, meta.xml-processing, meta.xml-processing entity, meta.xml-processing string
+ settings
+
+ foreground
+ #494949
+
+
+
+ name
+ Meta.tag.all
+ scope
+ meta.tag, meta.tag entity
+ settings
+
+ foreground
+ #005273
+
+
+
+ name
+ Meta.tag.inline
+ scope
+ source entity.name.tag, source entity.other.attribute-name, meta.tag.inline, meta.tag.inline entity
+ settings
+
+ foreground
+ #005273
+
+
+
+ name
+ Namespaces
+ scope
+ entity.name.tag.namespace, entity.other.attribute-name.namespace
+ settings
+
+ foreground
+ #B85423
+
+
+
+ name
+ css tag-name
+ scope
+ entity.name.tag.css
+ settings
+
+ foreground
+ #B83126
+
+
+
+ name
+ css:pseudo-class
+ scope
+ meta.selector.css entity.other.attribute-name.tag.pseudo-class
+ settings
+
+ foreground
+ #B12E25
+
+
+
+ name
+ css#id
+ scope
+ meta.selector.css entity.other.attribute-name.id,entity.other.attribute-name.id.css
+ settings
+
+ foreground
+ #B8002D
+
+
+
+ name
+ css.class
+ scope
+ meta.selector.css entity.other.attribute-name.class, entity.other.attribute-name.class.css
+ settings
+
+ foreground
+ #B8012D
+
+
+
+ name
+ css property-name:
+ scope
+ support.type.property-name.css, meta.property-name
+ settings
+
+ foreground
+ #005273
+
+
+
+ name
+ css @at-rule
+ scope
+ meta.preprocessor.at-rule keyword.control.at-rule
+ settings
+
+ foreground
+ #8693A5
+
+
+
+ name
+ css property-value;
+ scope
+ meta.property-value
+ settings
+
+ foreground
+ #417E00
+
+
+
+ name
+ css property-value color
+ scope
+ constant.other.color
+ settings
+
+ foreground
+ #B8860B
+
+
+
+ name
+ css !important / !default
+ scope
+ keyword.other.important,keyword.other.default
+ settings
+
+ foreground
+ #EE3A8C
+
+
+
+ name
+ css additional-constants
+ scope
+ meta.property-value support.constant.named-color.css, meta.property-value constant
+ settings
+
+ foreground
+ #417E00
+
+
+
+
+
+ name
+ css constructor.argument
+ scope
+ meta.constructor.argument.css
+ settings
+
+ foreground
+ #417E00
+
+
+
+ name
+ css constant.numeric
+ scope
+ constant.numeric
+ settings
+
+ foreground
+ #9A5925
+
+
+
+ name
+ css keyword.unit
+ scope
+ keyword.other
+ settings
+
+ foreground
+ #9F5E3D
+
+
+
+ name
+ css keyword.unit
+ scope
+ source.scss support.function.misc
+ settings
+
+ foreground
+ #1B76B0
+
+
+
+ name
+ diff.header
+ scope
+ meta.diff, meta.diff.header
+ settings
+
+ background
+ #82000E
+ fontStyle
+ italic
+ foreground
+ #F8BEBE
+
+
+
+ name
+ diff.deleted
+ scope
+ markup.deleted
+ settings
+
+ background
+ #420E09
+ foreground
+ #F8F8F8
+
+
+
+ name
+ diff.changed
+ scope
+ markup.changed
+ settings
+
+ background
+ #4A410D
+ foreground
+ #F8F8F8
+
+
+
+ name
+ diff.inserted
+ scope
+ markup.inserted
+ settings
+
+ background
+ #253B22
+ foreground
+ #F8F8F8
+
+
+
+ name
+ Markup: Italic
+ scope
+ markup.italic
+ settings
+
+ fontStyle
+ italic
+ foreground
+ #CD2626
+
+
+
+ name
+ Markup: Bold
+ scope
+ markup.bold
+ settings
+
+ fontStyle
+ bold
+ foreground
+ #8B1A1A
+
+
+
+ name
+ Markup: Underline
+ scope
+ markup.underline
+ settings
+
+ fontStyle
+ underline
+ foreground
+ #E18964
+
+
+
+ name
+ Markup: Quote
+ scope
+ markup.quote
+ settings
+
+ background
+ #FEE09C12
+ fontStyle
+ italic
+ foreground
+ #8B7765
+
+
+
+ name
+ Markup: Heading
+ scope
+ markup.heading, markup.heading entity
+ settings
+
+ background
+ #BF61330D
+ fontStyle
+
+ foreground
+ #B8012D
+
+
+
+ name
+ Markup: List
+ scope
+ markup.list
+ settings
+
+ foreground
+ #8F5B26
+
+
+
+ name
+ Markup: Raw
+ scope
+ markup.raw
+ settings
+
+ background
+ #B1B3BA08
+ fontStyle
+
+ foreground
+ #578BB3
+
+
+
+ name
+ Markup: Comment
+ scope
+ markup comment
+ settings
+
+ fontStyle
+ italic
+ foreground
+ #F67B37
+
+
+
+ name
+ Markup: Separator
+ scope
+ meta.separator
+ settings
+
+ background
+ #242424
+ foreground
+ #60A633
+
+
+
+ name
+ Markup: Other
+ scope
+ markup.other
+ settings
+
+ background
+ #B1B3BA08
+ fontStyle
+
+ foreground
+ #578BB3
+
+
+
+ name
+ Log Entry
+ scope
+ meta.line.entry.logfile, meta.line.exit.logfile
+ settings
+
+ background
+ #EEEEEE29
+
+
+
+ name
+ Log Entry Error
+ scope
+ meta.line.error.logfile
+ settings
+
+ background
+ #751012
+
+
+
+ name
+ SCSS Punctuation End Comments
+ scope
+ punctuation.definition.end
+ settings
+
+ background
+ #DCDCDC8F
+ fontStyle
+
+
+
+
+ name
+ --------------------------------
+ settings
+
+
+
+ name
+ HTML Attribute name
+ scope
+ entity.other.attribute-name.html
+ settings
+
+ foreground
+ #629F9E
+
+
+
+ name
+ JS String
+ scope
+ string.quoted.double.js, string.quoted.single.js
+ settings
+
+ foreground
+ #79A316
+
+
+
+ name
+ JS Function
+ scope
+ entity.name.function.js
+ settings
+
+ foreground
+ #488C45
+ fontStyle
+ italic
+
+
+
+ name
+ JS Embedded code general
+ scope
+ source.js.embedded.html
+ settings
+
+ foreground
+ #666
+
+
+
+ name
+ JS Storage Type
+ scope
+ storage.type.js
+ settings
+
+ foreground
+ #BB3182
+
+
+
+ name
+ JS Support Class
+ scope
+ support.class.js
+ settings
+
+ foreground
+ #338FD5
+
+
+
+ name
+ JS Control Keyword
+ scope
+ keyword.control.js, keyword.operator.js
+ settings
+
+ foreground
+ #A99904
+ fontStyle
+ italic
+
+
+
+
+ name
+ Matching Pairs
+ scope
+ entity.name.class
+ settings
+
+ background
+ #D7D7A7
+ foreground
+ #616838
+ fontStyle
+
+
+
+
+ name
+ Active Guide
+ scope
+ active_guide
+ settings
+
+ background
+ #968F96
+ fontStyle
+
+
+
+
+ name
+ Highlight Matching Word
+ scope
+ highlight_matching_word
+ settings
+
+ background
+ #CBDC2F38
+ fontStyle
+
+
+
+
+ uuid
+ 467560D0-6ACE-4409-82FD-4791420837AC
+
+