Conflicts: build/demo/kitchen-sink/mode-coldfusion-uncompressed.js build/demo/kitchen-sink/mode-css-uncompressed.js build/demo/kitchen-sink/mode-groovy-uncompressed.js build/demo/kitchen-sink/mode-html-uncompressed.js build/demo/kitchen-sink/mode-java-uncompressed.js build/demo/kitchen-sink/mode-javascript-uncompressed.js build/demo/kitchen-sink/mode-markdown-uncompressed.js build/demo/kitchen-sink/mode-php-uncompressed.js build/demo/kitchen-sink/mode-scala-uncompressed.js build/demo/kitchen-sink/mode-svg-uncompressed.js build/demo/kitchen-sink/mode-xquery-uncompressed.js build/demo/kitchen-sink/theme-cobalt-uncompressed.js build/demo/kitchen-sink/theme-dawn-uncompressed.js build/demo/kitchen-sink/theme-idle_fingers-uncompressed.js build/demo/kitchen-sink/theme-kr_theme-uncompressed.js build/demo/kitchen-sink/theme-merbivore-uncompressed.js build/demo/kitchen-sink/theme-merbivore_soft-uncompressed.js build/demo/kitchen-sink/theme-mono_industrial-uncompressed.js build/demo/kitchen-sink/theme-pastel_on_dark-uncompressed.js build/demo/kitchen-sink/theme-twilight-uncompressed.js build/demo/kitchen-sink/theme-vibrant_ink-uncompressed.js build/kitchen-sink.html build/src/mode-coldfusion-noconflict.js build/src/mode-coldfusion-uncompressed-noconflict.js build/src/mode-coldfusion-uncompressed.js build/src/mode-coldfusion.js build/src/mode-css-noconflict.js build/src/mode-css-uncompressed-noconflict.js build/src/mode-css-uncompressed.js build/src/mode-css.js build/src/mode-groovy-noconflict.js build/src/mode-groovy-uncompressed-noconflict.js build/src/mode-groovy-uncompressed.js build/src/mode-groovy.js build/src/mode-html-noconflict.js build/src/mode-html-uncompressed-noconflict.js build/src/mode-html-uncompressed.js build/src/mode-html.js build/src/mode-java-noconflict.js build/src/mode-java-uncompressed-noconflict.js build/src/mode-java-uncompressed.js build/src/mode-java.js build/src/mode-javascript-noconflict.js build/src/mode-javascript-uncompressed-noconflict.js build/src/mode-javascript-uncompressed.js build/src/mode-javascript.js build/src/mode-markdown-noconflict.js build/src/mode-markdown-uncompressed-noconflict.js build/src/mode-markdown-uncompressed.js build/src/mode-markdown.js build/src/mode-php-noconflict.js build/src/mode-php-uncompressed-noconflict.js build/src/mode-php-uncompressed.js build/src/mode-php.js build/src/mode-scala-noconflict.js build/src/mode-scala-uncompressed-noconflict.js build/src/mode-scala-uncompressed.js build/src/mode-scala.js build/src/mode-svg-noconflict.js build/src/mode-svg-uncompressed-noconflict.js build/src/mode-svg-uncompressed.js build/src/mode-svg.js build/src/mode-xquery-noconflict.js build/src/mode-xquery.js build/src/theme-clouds-noconflict.js build/src/theme-clouds.js build/src/theme-clouds_midnight-noconflict.js build/src/theme-clouds_midnight.js build/src/theme-cobalt-noconflict.js build/src/theme-cobalt-uncompressed-noconflict.js build/src/theme-cobalt-uncompressed.js build/src/theme-cobalt.js build/src/theme-dawn-noconflict.js build/src/theme-dawn-uncompressed-noconflict.js build/src/theme-dawn-uncompressed.js build/src/theme-dawn.js build/src/theme-idle_fingers-noconflict.js build/src/theme-idle_fingers-uncompressed-noconflict.js build/src/theme-idle_fingers-uncompressed.js build/src/theme-idle_fingers.js build/src/theme-kr_theme-noconflict.js build/src/theme-kr_theme-uncompressed-noconflict.js build/src/theme-kr_theme-uncompressed.js build/src/theme-kr_theme.js build/src/theme-merbivore-noconflict.js build/src/theme-merbivore-uncompressed-noconflict.js build/src/theme-merbivore-uncompressed.js build/src/theme-merbivore.js build/src/theme-merbivore_soft-noconflict.js build/src/theme-merbivore_soft-uncompressed-noconflict.js build/src/theme-merbivore_soft-uncompressed.js build/src/theme-merbivore_soft.js build/src/theme-mono_industrial-noconflict.js build/src/theme-mono_industrial-uncompressed-noconflict.js build/src/theme-mono_industrial-uncompressed.js build/src/theme-mono_industrial.js build/src/theme-monokai-noconflict.js build/src/theme-monokai.js build/src/theme-pastel_on_dark-noconflict.js build/src/theme-pastel_on_dark-uncompressed-noconflict.js build/src/theme-pastel_on_dark-uncompressed.js build/src/theme-pastel_on_dark.js build/src/theme-solarized_dark-noconflict.js build/src/theme-solarized_dark.js build/src/theme-solarized_light-noconflict.js build/src/theme-solarized_light.js build/src/theme-tomorrow-noconflict.js build/src/theme-tomorrow.js build/src/theme-tomorrow_night-noconflict.js build/src/theme-tomorrow_night.js build/src/theme-tomorrow_night_blue-noconflict.js build/src/theme-tomorrow_night_blue.js build/src/theme-tomorrow_night_bright-noconflict.js build/src/theme-tomorrow_night_bright.js build/src/theme-tomorrow_night_eighties-noconflict.js build/src/theme-tomorrow_night_eighties.js build/src/theme-twilight-noconflict.js build/src/theme-twilight-uncompressed-noconflict.js build/src/theme-twilight-uncompressed.js build/src/theme-twilight.js build/src/theme-vibrant_ink-noconflict.js build/src/theme-vibrant_ink-uncompressed-noconflict.js build/src/theme-vibrant_ink-uncompressed.js build/src/theme-vibrant_ink.js
This commit is contained in:
commit
b63d2c178b
362 changed files with 35354 additions and 17306 deletions
|
|
@ -47,12 +47,12 @@ var Editor = require("./editor").Editor;
|
|||
var EditSession = require("./edit_session").EditSession;
|
||||
var UndoManager = require("./undomanager").UndoManager;
|
||||
var Renderer = require("./virtual_renderer").VirtualRenderer;
|
||||
var MultiSelect = require("./multi_select").MultiSelect;
|
||||
|
||||
// The following require()s are for inclusion in the built ace file
|
||||
require("./worker/worker_client");
|
||||
require("./keyboard/hash_handler");
|
||||
require("./keyboard/state_handler");
|
||||
require("./lib/net");
|
||||
require("./placeholder");
|
||||
require("./config").init();
|
||||
|
||||
|
|
@ -66,6 +66,7 @@ exports.edit = function(el) {
|
|||
el.innerHTML = '';
|
||||
|
||||
var editor = new Editor(new Renderer(el, require("./theme/textmate")));
|
||||
new MultiSelect(editor);
|
||||
editor.setSession(doc);
|
||||
|
||||
var env = {};
|
||||
|
|
|
|||
|
|
@ -1,131 +1,27 @@
|
|||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var keyUtil = require("../lib/keys");
|
||||
var oop = require("../lib/oop");
|
||||
var HashHandler = require("../keyboard/hash_handler").HashHandler;
|
||||
var EventEmitter = require("../lib/event_emitter").EventEmitter;
|
||||
|
||||
var CommandManager = function(platform, commands) {
|
||||
if (typeof platform !== "string")
|
||||
throw new TypeError("'platform' argument must be either 'mac' or 'win'");
|
||||
|
||||
this.platform = platform;
|
||||
this.commands = {};
|
||||
this.commmandKeyBinding = {};
|
||||
|
||||
if (commands)
|
||||
commands.forEach(this.addCommand, this);
|
||||
this.addCommands(commands);
|
||||
|
||||
this.setDefaultHandler("exec", function(e) {
|
||||
e.command.exec(e.editor, e.args || {});
|
||||
});
|
||||
};
|
||||
|
||||
oop.inherits(CommandManager, HashHandler);
|
||||
|
||||
(function() {
|
||||
|
||||
this.addCommand = function(command) {
|
||||
if (this.commands[command.name])
|
||||
this.removeCommand(command);
|
||||
|
||||
this.commands[command.name] = command;
|
||||
|
||||
if (command.bindKey) {
|
||||
this._buildKeyHash(command);
|
||||
}
|
||||
};
|
||||
|
||||
this.removeCommand = function(command) {
|
||||
var name = (typeof command === 'string' ? command : command.name);
|
||||
command = this.commands[name];
|
||||
delete this.commands[name];
|
||||
|
||||
// exaustive search is brute force but since removeCommand is
|
||||
// not a performance critical operation this should be OK
|
||||
var ckb = this.commmandKeyBinding;
|
||||
for (var hashId in ckb) {
|
||||
for (var key in ckb[hashId]) {
|
||||
if (ckb[hashId][key] == command)
|
||||
delete ckb[hashId][key];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.addCommands = function(commands) {
|
||||
Object.keys(commands).forEach(function(name) {
|
||||
var command = commands[name];
|
||||
if (typeof command === "string")
|
||||
return this.bindKey(command, name);
|
||||
|
||||
if (typeof command === "function")
|
||||
command = { exec: command };
|
||||
|
||||
if (!command.name)
|
||||
command.name = name;
|
||||
|
||||
this.addCommand(command);
|
||||
}, this);
|
||||
};
|
||||
|
||||
this.removeCommands = function(commands) {
|
||||
Object.keys(commands).forEach(function(name) {
|
||||
this.removeCommand(commands[name]);
|
||||
}, this);
|
||||
};
|
||||
|
||||
this.bindKey = function(key, command) {
|
||||
if(!key)
|
||||
return;
|
||||
|
||||
var ckb = this.commmandKeyBinding;
|
||||
key.split("|").forEach(function(keyPart) {
|
||||
var binding = parseKeys(keyPart, command);
|
||||
var hashId = binding.hashId;
|
||||
(ckb[hashId] || (ckb[hashId] = {}))[binding.key] = command;
|
||||
});
|
||||
};
|
||||
|
||||
this.bindKeys = function(keyList) {
|
||||
Object.keys(keyList).forEach(function(key) {
|
||||
this.bindKey(key, keyList[key]);
|
||||
}, this);
|
||||
};
|
||||
|
||||
this._buildKeyHash = function(command) {
|
||||
var binding = command.bindKey;
|
||||
if (!binding)
|
||||
return;
|
||||
|
||||
var key = typeof binding == "string" ? binding: binding[this.platform];
|
||||
this.bindKey(key, command);
|
||||
}
|
||||
|
||||
function parseKeys(keys, val, ret) {
|
||||
var key;
|
||||
var hashId = 0;
|
||||
var parts = splitSafe(keys);
|
||||
|
||||
for (var i=0, l = parts.length; i < l; i++) {
|
||||
if (keyUtil.KEY_MODS[parts[i]])
|
||||
hashId = hashId | keyUtil.KEY_MODS[parts[i]];
|
||||
else
|
||||
key = parts[i] || "-"; //when empty, the splitSafe removed a '-'
|
||||
}
|
||||
|
||||
return {
|
||||
key: key,
|
||||
hashId: hashId
|
||||
}
|
||||
}
|
||||
|
||||
function splitSafe(s, separator) {
|
||||
return (s.toLowerCase()
|
||||
.trim()
|
||||
.split(new RegExp("[\\s ]*\\-[\\s ]*", "g"), 999));
|
||||
}
|
||||
|
||||
this.findKeyCommand = function findKeyCommand(hashId, textOrKey) {
|
||||
// Convert keyCode to the string representation.
|
||||
if (typeof textOrKey == "number") {
|
||||
textOrKey = keyUtil.keyCodeToString(textOrKey);
|
||||
}
|
||||
|
||||
var ckbr = this.commmandKeyBinding;
|
||||
return ckbr[hashId] && ckbr[hashId][textOrKey.toLowerCase()];
|
||||
}
|
||||
oop.implement(this, EventEmitter);
|
||||
|
||||
this.exec = function(command, editor, args) {
|
||||
if (typeof command === 'string')
|
||||
|
|
@ -137,7 +33,7 @@ var CommandManager = function(platform, commands) {
|
|||
if (editor && editor.$readOnly && !command.readOnly)
|
||||
return false;
|
||||
|
||||
command.exec(editor, args || {});
|
||||
this._emit("exec", {editor: editor, command: command, args: args});
|
||||
return true;
|
||||
};
|
||||
|
||||
|
|
@ -146,20 +42,22 @@ var CommandManager = function(platform, commands) {
|
|||
return;
|
||||
if (this.recording) {
|
||||
this.macro.pop();
|
||||
this.exec = this.normal_exec;
|
||||
this.removeEventListener("exec", this.$addCommandToMacro);
|
||||
|
||||
if (!this.macro.length)
|
||||
this.macro = this.oldMacro;
|
||||
|
||||
return this.recording = false;
|
||||
}
|
||||
if (!this.$addCommandToMacro) {
|
||||
this.$addCommandToMacro = function(e) {
|
||||
this.macro.push([e.command, e.args]);
|
||||
}.bind(this);
|
||||
}
|
||||
|
||||
this.oldMacro = this.macro;
|
||||
this.macro = [];
|
||||
this.normal_exec = this.exec;
|
||||
this.exec = function(command, editor, args) {
|
||||
this.macro.push([command, args]);
|
||||
return this.normal_exec(command, editor, args);
|
||||
};
|
||||
this.on("exec", this.$addCommandToMacro);
|
||||
return this.recording = true;
|
||||
};
|
||||
|
||||
|
|
@ -177,7 +75,7 @@ var CommandManager = function(platform, commands) {
|
|||
this.exec(x, editor);
|
||||
else
|
||||
this.exec(x[0], editor, x[1]);
|
||||
}, this)
|
||||
}, this);
|
||||
} finally {
|
||||
this.$inReplay = false;
|
||||
}
|
||||
|
|
@ -189,9 +87,9 @@ var CommandManager = function(platform, commands) {
|
|||
x[0] = x[0].name;
|
||||
if (!x[1])
|
||||
x = x[0];
|
||||
return x
|
||||
})
|
||||
}
|
||||
return x;
|
||||
});
|
||||
};
|
||||
|
||||
}).call(CommandManager.prototype);
|
||||
|
||||
|
|
|
|||
|
|
@ -127,91 +127,109 @@ exports.commands = [{
|
|||
name: "selectup",
|
||||
bindKey: bindKey("Shift-Up", "Shift-Up"),
|
||||
exec: function(editor) { editor.getSelection().selectUp(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "golineup",
|
||||
bindKey: bindKey("Up", "Up|Ctrl-P"),
|
||||
exec: function(editor, args) { editor.navigateUp(args.times); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selecttoend",
|
||||
bindKey: bindKey("Ctrl-Shift-End|Alt-Shift-Down", "Command-Shift-Down"),
|
||||
exec: function(editor) { editor.getSelection().selectFileEnd(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotoend",
|
||||
bindKey: bindKey("Ctrl-End|Ctrl-Down", "Command-End|Command-Down"),
|
||||
exec: function(editor) { editor.navigateFileEnd(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectdown",
|
||||
bindKey: bindKey("Shift-Down", "Shift-Down"),
|
||||
exec: function(editor) { editor.getSelection().selectDown(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "golinedown",
|
||||
bindKey: bindKey("Down", "Down|Ctrl-N"),
|
||||
exec: function(editor, args) { editor.navigateDown(args.times); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectwordleft",
|
||||
bindKey: bindKey("Ctrl-Shift-Left", "Option-Shift-Left"),
|
||||
exec: function(editor) { editor.getSelection().selectWordLeft(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotowordleft",
|
||||
bindKey: bindKey("Ctrl-Left", "Option-Left"),
|
||||
exec: function(editor) { editor.navigateWordLeft(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selecttolinestart",
|
||||
bindKey: bindKey("Alt-Shift-Left", "Command-Shift-Left"),
|
||||
exec: function(editor) { editor.getSelection().selectLineStart(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotolinestart",
|
||||
bindKey: bindKey("Alt-Left|Home", "Command-Left|Home|Ctrl-A"),
|
||||
exec: function(editor) { editor.navigateLineStart(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectleft",
|
||||
bindKey: bindKey("Shift-Left", "Shift-Left"),
|
||||
exec: function(editor) { editor.getSelection().selectLeft(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotoleft",
|
||||
bindKey: bindKey("Left", "Left|Ctrl-B"),
|
||||
exec: function(editor, args) { editor.navigateLeft(args.times); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectwordright",
|
||||
bindKey: bindKey("Ctrl-Shift-Right", "Option-Shift-Right"),
|
||||
exec: function(editor) { editor.getSelection().selectWordRight(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotowordright",
|
||||
bindKey: bindKey("Ctrl-Right", "Option-Right"),
|
||||
exec: function(editor) { editor.navigateWordRight(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selecttolineend",
|
||||
bindKey: bindKey("Alt-Shift-Right", "Command-Shift-Right"),
|
||||
exec: function(editor) { editor.getSelection().selectLineEnd(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotolineend",
|
||||
bindKey: bindKey("Alt-Right|End", "Command-Right|End|Ctrl-E"),
|
||||
exec: function(editor) { editor.navigateLineEnd(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectright",
|
||||
bindKey: bindKey("Shift-Right", "Shift-Right"),
|
||||
exec: function(editor) { editor.getSelection().selectRight(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotoright",
|
||||
bindKey: bindKey("Right", "Right|Ctrl-F"),
|
||||
exec: function(editor, args) { editor.navigateRight(args.times); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectpagedown",
|
||||
|
|
@ -247,11 +265,13 @@ exports.commands = [{
|
|||
name: "selectlinestart",
|
||||
bindKey: bindKey("Shift-Home", "Shift-Home"),
|
||||
exec: function(editor) { editor.getSelection().selectLineStart(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectlineend",
|
||||
bindKey: bindKey("Shift-End", "Shift-End"),
|
||||
exec: function(editor) { editor.getSelection().selectLineEnd(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "togglerecording",
|
||||
|
|
@ -267,18 +287,33 @@ exports.commands = [{
|
|||
name: "jumptomatching",
|
||||
bindKey: bindKey("Ctrl-Shift-P", "Ctrl-Shift-P"),
|
||||
exec: function(editor) { editor.jumpToMatching(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
},
|
||||
|
||||
// commands disabled in readOnly mode
|
||||
{
|
||||
name: "cut",
|
||||
exec: function(editor) {
|
||||
var range = editor.getSelectionRange();
|
||||
editor._emit("cut", range);
|
||||
|
||||
if (!editor.selection.isEmpty()) {
|
||||
editor.session.remove(range);
|
||||
editor.clearSelection();
|
||||
}
|
||||
},
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "removeline",
|
||||
bindKey: bindKey("Ctrl-D", "Command-D"),
|
||||
exec: function(editor) { editor.removeLines(); }
|
||||
exec: function(editor) { editor.removeLines(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "togglecomment",
|
||||
bindKey: bindKey("Ctrl-7", "Command-7"),
|
||||
exec: function(editor) { editor.toggleCommentLines(); }
|
||||
exec: function(editor) { editor.toggleCommentLines(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "replace",
|
||||
bindKey: bindKey("Ctrl-R", "Command-Option-F"),
|
||||
|
|
@ -330,62 +365,76 @@ exports.commands = [{
|
|||
}, {
|
||||
name: "del",
|
||||
bindKey: bindKey("Delete", "Delete|Ctrl-D"),
|
||||
exec: function(editor) { editor.remove("right"); }
|
||||
exec: function(editor) { editor.remove("right"); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "backspace",
|
||||
bindKey: bindKey(
|
||||
"Ctrl-Backspace|Command-Backspace|Option-Backspace|Shift-Backspace|Backspace",
|
||||
"Command-Backspace|Option-Backspace|Shift-Backspace|Backspace",
|
||||
"Ctrl-Backspace|Command-Backspace|Shift-Backspace|Backspace|Ctrl-H"
|
||||
),
|
||||
exec: function(editor) { editor.remove("left"); }
|
||||
exec: function(editor) { editor.remove("left"); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "removetolinestart",
|
||||
bindKey: bindKey("Alt-Backspace", "Option-Backspace"),
|
||||
exec: function(editor) { editor.removeToLineStart(); }
|
||||
bindKey: bindKey("Alt-Backspace", "Command-Backspace"),
|
||||
exec: function(editor) { editor.removeToLineStart(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "removetolineend",
|
||||
bindKey: bindKey("Alt-Delete", "Ctrl-K"),
|
||||
exec: function(editor) { editor.removeToLineEnd(); }
|
||||
exec: function(editor) { editor.removeToLineEnd(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "removewordleft",
|
||||
bindKey: bindKey("Ctrl-Backspace", "Alt-Backspace|Ctrl-Alt-Backspace"),
|
||||
exec: function(editor) { editor.removeWordLeft(); }
|
||||
exec: function(editor) { editor.removeWordLeft(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "removewordright",
|
||||
bindKey: bindKey("Ctrl-Delete", "Alt-Delete"),
|
||||
exec: function(editor) { editor.removeWordRight(); }
|
||||
exec: function(editor) { editor.removeWordRight(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "outdent",
|
||||
bindKey: bindKey("Shift-Tab", "Shift-Tab"),
|
||||
exec: function(editor) { editor.blockOutdent(); }
|
||||
exec: function(editor) { editor.blockOutdent(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "indent",
|
||||
bindKey: bindKey("Tab", "Tab"),
|
||||
exec: function(editor) { editor.indent(); }
|
||||
exec: function(editor) { editor.indent(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "insertstring",
|
||||
exec: function(editor, str) { editor.insert(str); }
|
||||
exec: function(editor, str) { editor.insert(str); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "inserttext",
|
||||
exec: function(editor, args) {
|
||||
editor.insert(lang.stringRepeat(args.text || "", args.times || 1));
|
||||
}
|
||||
},
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "splitline",
|
||||
bindKey: bindKey(null, "Ctrl-O"),
|
||||
exec: function(editor) { editor.splitLine(); }
|
||||
exec: function(editor) { editor.splitLine(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "transposeletters",
|
||||
bindKey: bindKey("Ctrl-T", "Ctrl-T"),
|
||||
exec: function(editor) { editor.transposeLetters(); }
|
||||
exec: function(editor) { editor.transposeLetters(); },
|
||||
multiSelectAction: function(editor) {editor.transposeSelections(1); }
|
||||
}, {
|
||||
name: "touppercase",
|
||||
bindKey: bindKey("Ctrl-U", "Ctrl-U"),
|
||||
exec: function(editor) { editor.toUpperCase(); }
|
||||
exec: function(editor) { editor.toUpperCase(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "tolowercase",
|
||||
bindKey: bindKey("Ctrl-Shift-U", "Ctrl-Shift-U"),
|
||||
exec: function(editor) { editor.toLowerCase(); }
|
||||
exec: function(editor) { editor.toLowerCase(); },
|
||||
multiSelectAction: "forEach"
|
||||
}];
|
||||
|
||||
});
|
||||
|
|
|
|||
100
lib/ace/commands/multi_select_commands.js
Normal file
100
lib/ace/commands/multi_select_commands.js
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Harutyun Amirjanyan <amirjanyan AT gmail DOT com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
// commands to enter multiselect mode
|
||||
exports.defaultCommands = [{
|
||||
name: "addCursorAbove",
|
||||
exec: function(editor) { editor.selectMoreLines(-1); },
|
||||
bindKey: {win: "Ctrl-Alt-Up", mac: "Ctrl-Alt-Up"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "addCursorBelow",
|
||||
exec: function(editor) { editor.selectMoreLines(1); },
|
||||
bindKey: {win: "Ctrl-Alt-Down", mac: "Ctrl-Alt-Down"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "addCursorAboveSkipCurrent",
|
||||
exec: function(editor) { editor.selectMoreLines(-1, true); },
|
||||
bindKey: {win: "Ctrl-Alt-Shift-Up", mac: "Ctrl-Alt-Shift-Up"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "addCursorBelowSkipCurrent",
|
||||
exec: function(editor) { editor.selectMoreLines(1, true); },
|
||||
bindKey: {win: "Ctrl-Alt-Shift-Down", mac: "Ctrl-Alt-Shift-Down"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "selectMoreBefore",
|
||||
exec: function(editor) { editor.selectMore(-1); },
|
||||
bindKey: {win: "Ctrl-Alt-Left", mac: "Ctrl-Alt-Left"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "selectMoreAfter",
|
||||
exec: function(editor) { editor.selectMore(1); },
|
||||
bindKey: {win: "Ctrl-Alt-Right", mac: "Ctrl-Alt-Right"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "selectNextBefore",
|
||||
exec: function(editor) { editor.selectMore(-1, true); },
|
||||
bindKey: {win: "Ctrl-Alt-Shift-Left", mac: "Ctrl-Alt-Shift-Left"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "selectNextAfter",
|
||||
exec: function(editor) { editor.selectMore(1, true); },
|
||||
bindKey: {win: "Ctrl-Alt-Shift-Right", mac: "Ctrl-Alt-Shift-Right"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "splitIntoLines",
|
||||
exec: function(editor) { editor.multiSelect.splitIntoLines(); },
|
||||
bindKey: {win: "Ctrl-Shift-L", mac: "Ctrl-Shift-L"},
|
||||
readonly: true
|
||||
}];
|
||||
|
||||
// commands active in multiselect mode
|
||||
exports.multiEditCommands = [{
|
||||
name: "singleSelection",
|
||||
bindKey: "esc",
|
||||
exec: function(editor) { editor.exitMultiSelectMode(); },
|
||||
readonly: true
|
||||
}];
|
||||
|
||||
var HashHandler = require("../keyboard/hash_handler").HashHandler;
|
||||
exports.keyboardHandler = new HashHandler(exports.multiEditCommands);
|
||||
|
||||
});
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
@import url(//fonts.googleapis.com/css?family=Droid+Sans+Mono);
|
||||
|
||||
|
||||
.ace_editor {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
|
|
@ -35,6 +34,11 @@
|
|||
height: 100%;
|
||||
width: auto;
|
||||
cursor: default;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.ace_gutter.horscroll {
|
||||
box-shadow: 0px 0px 20px rgba(0,0,0,0.4);
|
||||
}
|
||||
|
||||
.ace_gutter-cell {
|
||||
|
|
@ -158,12 +162,12 @@
|
|||
|
||||
.ace_marker-layer .ace_selection {
|
||||
position: absolute;
|
||||
z-index: 4;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.ace_marker-layer .ace_bracket {
|
||||
position: absolute;
|
||||
z-index: 5;
|
||||
z-index: 6;
|
||||
}
|
||||
|
||||
.ace_marker-layer .ace_active_line {
|
||||
|
|
@ -171,9 +175,13 @@
|
|||
z-index: 2;
|
||||
}
|
||||
|
||||
.ace_gutter .ace_gutter_active_line{
|
||||
background-color : #dcdcdc;
|
||||
}
|
||||
|
||||
.ace_marker-layer .ace_selected_word {
|
||||
position: absolute;
|
||||
z-index: 6;
|
||||
z-index: 4;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
|
|
|
|||
|
|
@ -178,6 +178,7 @@ var Document = function(text) {
|
|||
|
||||
position = this.$clipPosition(position);
|
||||
|
||||
// only detect new lines if the document has no line break yet
|
||||
if (this.getLength() <= 1)
|
||||
this.$detectNewLine(text);
|
||||
|
||||
|
|
|
|||
|
|
@ -508,6 +508,10 @@ var EditSession = function(text, mode) {
|
|||
return callback(_self.$modes[mode]);
|
||||
|
||||
_self.$modes[mode] = new module.Mode();
|
||||
_self._emit("loadmode", {
|
||||
name: mode,
|
||||
mode: _self.$modes[mode]
|
||||
});
|
||||
callback(_self.$modes[mode]);
|
||||
}
|
||||
|
||||
|
|
@ -1439,8 +1443,8 @@ var EditSession = function(text, mode) {
|
|||
}
|
||||
|
||||
this.getScreenLastRowColumn = function(screenRow) {
|
||||
//return this.screenToDocumentColumn(screenRow, Number.MAX_VALUE / 10)
|
||||
return this.documentToScreenColumn(screenRow, this.doc.getLine(screenRow).length);
|
||||
var pos = this.screenToDocumentPosition(screenRow, Number.MAX_VALUE)
|
||||
return this.documentToScreenColumn(pos.row, pos.column);
|
||||
};
|
||||
|
||||
this.getDocumentLastRowColumn = function(docRow, docColumn) {
|
||||
|
|
@ -1555,16 +1559,10 @@ var EditSession = function(text, mode) {
|
|||
|
||||
docColumn += this.$getStringScreenWidth(line, screenColumn)[1];
|
||||
|
||||
// Need to do some clamping action here.
|
||||
if (this.$useWrapMode) {
|
||||
if (docColumn >= column) {
|
||||
// We remove one character at the end such that the docColumn
|
||||
// position returned is not associated to the next row on the
|
||||
// screen.
|
||||
docColumn = column - 1;
|
||||
}
|
||||
} else {
|
||||
docColumn = Math.min(docColumn, line.length);
|
||||
// We remove one character at the end so that the docColumn
|
||||
// position returned is not associated to the next row on the screen.
|
||||
if (this.$useWrapMode && docColumn >= column) {
|
||||
docColumn = column - 1;
|
||||
}
|
||||
|
||||
if (foldLine) {
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ var Fold = exports.Fold = function(range, placeholder) {
|
|||
};
|
||||
|
||||
this.addSubFold = function(fold) {
|
||||
if (this.range.isEequal(fold))
|
||||
if (this.range.isEqual(fold))
|
||||
return this;
|
||||
|
||||
if (!this.range.containsRange(fold))
|
||||
|
|
|
|||
|
|
@ -714,7 +714,7 @@ function Folding() {
|
|||
// sometimes singleline folds can be missed by the code above
|
||||
if (!range.isMultiLine()) {
|
||||
fold = this.getFoldAt(range.start.row, range.start.column, 1);
|
||||
if (fold && range.isEequal(fold.range)) {
|
||||
if (fold && range.isEqual(fold.range)) {
|
||||
this.removeFold(fold);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ var Editor = function(renderer, session) {
|
|||
var container = renderer.getContainerElement();
|
||||
this.container = container;
|
||||
this.renderer = renderer;
|
||||
|
||||
|
||||
this.textInput = new TextInput(renderer.getTextAreaContainer(), this);
|
||||
this.keyBinding = new KeyBinding(this);
|
||||
|
||||
|
|
@ -330,21 +330,29 @@ var Editor = function(renderer, session) {
|
|||
this.$updateHighlightActiveLine = function() {
|
||||
var session = this.getSession();
|
||||
|
||||
if (session.$highlightLineMarker) {
|
||||
if (session.$highlightLineMarker)
|
||||
session.removeMarker(session.$highlightLineMarker);
|
||||
}
|
||||
session.$highlightLineMarker = null;
|
||||
if (typeof this.$lastrow == "number")
|
||||
this.renderer.removeGutterDecoration(this.$lastrow, "ace_gutter_active_line");
|
||||
|
||||
if (this.getHighlightActiveLine() && (this.getSelectionStyle() != "line" || !this.selection.isMultiLine())) {
|
||||
session.$highlightLineMarker = null;
|
||||
this.$lastrow = null;
|
||||
|
||||
if (this.getHighlightActiveLine()) {
|
||||
var cursor = this.getCursorPosition(),
|
||||
foldLine = this.session.getFoldLine(cursor.row);
|
||||
var range;
|
||||
if (foldLine) {
|
||||
range = new Range(foldLine.start.row, 0, foldLine.end.row + 1, 0);
|
||||
} else {
|
||||
range = new Range(cursor.row, 0, cursor.row+1, 0);
|
||||
|
||||
if ((this.getSelectionStyle() != "line" || !this.selection.isMultiLine())) {
|
||||
var range;
|
||||
if (foldLine) {
|
||||
range = new Range(foldLine.start.row, 0, foldLine.end.row + 1, 0);
|
||||
} else {
|
||||
range = new Range(cursor.row, 0, cursor.row+1, 0);
|
||||
}
|
||||
session.$highlightLineMarker = session.addMarker(range, "ace_active_line", "background");
|
||||
}
|
||||
session.$highlightLineMarker = session.addMarker(range, "ace_active_line", "background");
|
||||
|
||||
this.renderer.addGutterDecoration(this.$lastrow = cursor.row, "ace_gutter_active_line");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -414,16 +422,7 @@ var Editor = function(renderer, session) {
|
|||
};
|
||||
|
||||
this.onCut = function() {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
var range = this.getSelectionRange();
|
||||
this._emit("cut", range);
|
||||
|
||||
if (!this.selection.isEmpty()) {
|
||||
this.session.remove(range);
|
||||
this.clearSelection();
|
||||
}
|
||||
this.commands.exec("cut", this);
|
||||
};
|
||||
|
||||
this.insert = function(text) {
|
||||
|
|
@ -598,6 +597,14 @@ var Editor = function(renderer, session) {
|
|||
return this.$highlightSelectedWord;
|
||||
};
|
||||
|
||||
this.setAnimatedScroll = function(shouldAnimate){
|
||||
this.renderer.setAnimatedScroll(shouldAnimate);
|
||||
};
|
||||
|
||||
this.getAnimatedScroll = function(){
|
||||
return this.renderer.getAnimatedScroll();
|
||||
};
|
||||
|
||||
this.setShowInvisibles = function(showInvisibles) {
|
||||
if (this.getShowInvisibles() == showInvisibles)
|
||||
return;
|
||||
|
|
@ -652,7 +659,7 @@ var Editor = function(renderer, session) {
|
|||
this.$showFoldWidgets = show;
|
||||
this.renderer.updateFull();
|
||||
};
|
||||
|
||||
|
||||
this.getShowFoldWidgets = function() {
|
||||
return this.renderer.$gutterLayer.getShowFoldWidgets();
|
||||
};
|
||||
|
|
@ -869,7 +876,7 @@ var Editor = function(renderer, session) {
|
|||
range.start.row += linesMoved;
|
||||
range.end.row += linesMoved;
|
||||
selection.setSelectionRange(range, reverse);
|
||||
}
|
||||
}
|
||||
else {
|
||||
selection.setSelectionAnchor(rows.last+linesMoved+1, 0);
|
||||
selection.$moveSelection(function() {
|
||||
|
|
@ -1033,13 +1040,13 @@ var Editor = function(renderer, session) {
|
|||
cursor.column -= 2;
|
||||
pos = this.session.findMatchingBracket(cursor);
|
||||
}
|
||||
|
||||
|
||||
if (pos) {
|
||||
this.clearSelection();
|
||||
this.moveCursorTo(pos.row, pos.column);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.gotoLine = function(lineNumber, column) {
|
||||
this.selection.clearSelection();
|
||||
this.session.unfold({row: lineNumber - 1, column: column || 0});
|
||||
|
|
@ -1131,12 +1138,19 @@ var Editor = function(renderer, session) {
|
|||
this.$search.set(options);
|
||||
|
||||
var range = this.$search.find(this.session);
|
||||
var replaced = 0;
|
||||
if (!range)
|
||||
return;
|
||||
return replaced;
|
||||
|
||||
this.$tryReplace(range, replacement);
|
||||
if (range !== null)
|
||||
if (this.$tryReplace(range, replacement)) {
|
||||
replaced = 1;
|
||||
}
|
||||
if (range !== null) {
|
||||
this.selection.setSelectionRange(range);
|
||||
this.renderer.scrollSelectionIntoView(range.start, range.end);
|
||||
}
|
||||
|
||||
return replaced;
|
||||
};
|
||||
|
||||
this.replaceAll = function(replacement, options) {
|
||||
|
|
@ -1145,19 +1159,25 @@ var Editor = function(renderer, session) {
|
|||
}
|
||||
|
||||
var ranges = this.$search.findAll(this.session);
|
||||
var replaced = 0;
|
||||
if (!ranges.length)
|
||||
return;
|
||||
return replaced;
|
||||
|
||||
var selection = this.getSelectionRange();
|
||||
this.clearSelection();
|
||||
this.selection.moveCursorTo(0, 0);
|
||||
|
||||
this.$blockScrolling += 1;
|
||||
for (var i = ranges.length - 1; i >= 0; --i)
|
||||
this.$tryReplace(ranges[i], replacement);
|
||||
for (var i = ranges.length - 1; i >= 0; --i) {
|
||||
if(this.$tryReplace(ranges[i], replacement)) {
|
||||
replaced++;
|
||||
}
|
||||
}
|
||||
|
||||
this.selection.setSelectionRange(selection);
|
||||
this.$blockScrolling -= 1;
|
||||
|
||||
return replaced;
|
||||
};
|
||||
|
||||
this.$tryReplace = function(range, replacement) {
|
||||
|
|
@ -1209,7 +1229,23 @@ var Editor = function(renderer, session) {
|
|||
var range = this.$search.find(this.session);
|
||||
if (range) {
|
||||
this.session.unfold(range);
|
||||
this.selection.setSelectionRange(range); // this scrolls selection into view
|
||||
|
||||
this.$blockScrolling += 1;
|
||||
this.selection.setSelectionRange(range);
|
||||
this.$blockScrolling -= 1;
|
||||
|
||||
if (this.getAnimatedScroll()) {
|
||||
var cursor = this.getCursorPosition();
|
||||
if (!this.isRowFullyVisible(cursor.row))
|
||||
this.scrollToLine(cursor.row, true);
|
||||
|
||||
//@todo scroll X
|
||||
//if (!this.isColumnFullyVisible(cursor.column))
|
||||
//this.scrollToRow(cursor.column);
|
||||
}
|
||||
else {
|
||||
this.renderer.scrollSelectionIntoView(range.start, range.end);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -395,6 +395,7 @@ function setupSettingPanel(settingDiv, settingOpener, api, options) {
|
|||
svg: "SVG",
|
||||
textile: "Textile",
|
||||
groovy: "Groovy",
|
||||
liquid: "Liquid",
|
||||
Scala: "Scala"
|
||||
},
|
||||
theme: {
|
||||
|
|
|
|||
|
|
@ -41,76 +41,126 @@ define(function(require, exports, module) {
|
|||
|
||||
var keyUtil = require("../lib/keys");
|
||||
|
||||
function HashHandler(config) {
|
||||
this.setConfig(config);
|
||||
}
|
||||
function HashHandler(config, platform) {
|
||||
this.platform = platform;
|
||||
this.commands = {};
|
||||
this.commmandKeyBinding = {};
|
||||
|
||||
this.addCommands(config);
|
||||
};
|
||||
|
||||
(function() {
|
||||
function splitSafe(s, separator, limit, bLowerCase) {
|
||||
return (bLowerCase && s.toLowerCase() || s)
|
||||
.replace(/(?:^\s+|\n|\s+$)/g, "")
|
||||
.split(new RegExp("[\\s ]*" + separator + "[\\s ]*", "g"), limit || 999);
|
||||
}
|
||||
|
||||
this.addCommand = function(command) {
|
||||
if (this.commands[command.name])
|
||||
this.removeCommand(command);
|
||||
|
||||
this.commands[command.name] = command;
|
||||
|
||||
if (command.bindKey) {
|
||||
this._buildKeyHash(command);
|
||||
}
|
||||
};
|
||||
|
||||
this.removeCommand = function(command) {
|
||||
var name = (typeof command === 'string' ? command : command.name);
|
||||
command = this.commands[name];
|
||||
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.commmandKeyBinding;
|
||||
for (var hashId in ckb) {
|
||||
for (var key in ckb[hashId]) {
|
||||
if (ckb[hashId][key] == command)
|
||||
delete ckb[hashId][key];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.addCommands = function(commands) {
|
||||
commands && Object.keys(commands).forEach(function(name) {
|
||||
var command = commands[name];
|
||||
if (typeof command === "string")
|
||||
return this.bindKey(command, name);
|
||||
|
||||
if (typeof command === "function")
|
||||
command = { exec: command };
|
||||
|
||||
if (!command.name)
|
||||
command.name = name;
|
||||
|
||||
this.addCommand(command);
|
||||
}, this);
|
||||
};
|
||||
|
||||
this.removeCommands = function(commands) {
|
||||
Object.keys(commands).forEach(function(name) {
|
||||
this.removeCommand(commands[name]);
|
||||
}, this);
|
||||
};
|
||||
|
||||
this.bindKey = function(key, command) {
|
||||
if(!key)
|
||||
return;
|
||||
|
||||
var ckb = this.commmandKeyBinding;
|
||||
key.split("|").forEach(function(keyPart) {
|
||||
var binding = parseKeys(keyPart, command);
|
||||
var hashId = binding.hashId;
|
||||
(ckb[hashId] || (ckb[hashId] = {}))[binding.key] = command;
|
||||
});
|
||||
};
|
||||
|
||||
this.bindKeys = function(keyList) {
|
||||
Object.keys(keyList).forEach(function(key) {
|
||||
this.bindKey(key, keyList[key]);
|
||||
}, this);
|
||||
};
|
||||
|
||||
this._buildKeyHash = function(command) {
|
||||
var binding = command.bindKey;
|
||||
if (!binding)
|
||||
return;
|
||||
|
||||
var key = typeof binding == "string" ? binding: binding[this.platform];
|
||||
this.bindKey(key, command);
|
||||
};
|
||||
|
||||
function parseKeys(keys, val, ret) {
|
||||
var key,
|
||||
hashId = 0,
|
||||
parts = splitSafe(keys, "\\-", null, true),
|
||||
i = 0,
|
||||
l = parts.length;
|
||||
var key;
|
||||
var hashId = 0;
|
||||
var parts = splitSafe(keys.toLowerCase());
|
||||
|
||||
for (; i < l; ++i) {
|
||||
for (var i = 0, l = parts.length; i < l; i++) {
|
||||
if (keyUtil.KEY_MODS[parts[i]])
|
||||
hashId = hashId | keyUtil.KEY_MODS[parts[i]];
|
||||
else
|
||||
key = parts[i] || "-"; //when empty, the splitSafe removed a '-'
|
||||
}
|
||||
|
||||
(ret[hashId] || (ret[hashId] = {}))[key] = val;
|
||||
return ret;
|
||||
return {
|
||||
key: key,
|
||||
hashId: hashId
|
||||
};
|
||||
}
|
||||
|
||||
function objectReverse(obj, keySplit) {
|
||||
var i, j, l, key,
|
||||
ret = {};
|
||||
for (i in obj) {
|
||||
key = obj[i];
|
||||
if (keySplit && typeof key == "string") {
|
||||
key = key.split(keySplit);
|
||||
for (j = 0, l = key.length; j < l; ++j)
|
||||
parseKeys.call(this, key[j], i, ret);
|
||||
}
|
||||
else {
|
||||
parseKeys.call(this, key, i, ret);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
function splitSafe(s) {
|
||||
return (s.trim()
|
||||
.split(new RegExp("[\\s ]*\\-[\\s ]*", "g"), 999));
|
||||
}
|
||||
|
||||
this.setConfig = function(config) {
|
||||
this.$config = config;
|
||||
if (typeof this.$config.reverse == "undefined")
|
||||
this.$config.reverse = objectReverse.call(this, this.$config, "|");
|
||||
this.findKeyCommand = function findKeyCommand(hashId, keyString) {
|
||||
var ckbr = this.commmandKeyBinding;
|
||||
return ckbr[hashId] && ckbr[hashId][keyString.toLowerCase()];
|
||||
}
|
||||
|
||||
this.handleKeyboard = function(data, hashId, keyString, keyCode) {
|
||||
return {
|
||||
command: this.findKeyCommand(hashId, keyString)
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* This function is called by keyBinding.
|
||||
*/
|
||||
this.handleKeyboard = function(data, hashId, textOrKey, keyCode) {
|
||||
// Figure out if a commandKey was pressed or just some text was insert.
|
||||
if (hashId != 0 || keyCode != 0) {
|
||||
return {
|
||||
command: (this.$config.reverse[hashId] || {})[textOrKey]
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
command: "inserttext",
|
||||
args: {
|
||||
text: textOrKey
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}).call(HashHandler.prototype)
|
||||
|
||||
exports.HashHandler = HashHandler;
|
||||
|
|
|
|||
|
|
@ -47,11 +47,10 @@ var Cursor = function(parentEl) {
|
|||
this.element.className = "ace_layer ace_cursor-layer";
|
||||
parentEl.appendChild(this.element);
|
||||
|
||||
this.cursor = dom.createElement("div");
|
||||
this.cursor.className = "ace_cursor ace_hidden";
|
||||
this.element.appendChild(this.cursor);
|
||||
|
||||
this.isVisible = false;
|
||||
|
||||
this.cursors = [];
|
||||
this.cursor = this.addCursor();
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
|
@ -65,30 +64,54 @@ var Cursor = function(parentEl) {
|
|||
this.session = session;
|
||||
};
|
||||
|
||||
this.addCursor = function() {
|
||||
var el = dom.createElement("div");
|
||||
var className = "ace_cursor";
|
||||
if (!this.isVisible)
|
||||
className += " ace_hidden";
|
||||
if (this.overwrite)
|
||||
className += " ace_overwrite";
|
||||
|
||||
el.className = className;
|
||||
this.element.appendChild(el);
|
||||
this.cursors.push(el);
|
||||
return el;
|
||||
};
|
||||
|
||||
this.removeCursor = function() {
|
||||
if (this.cursors.length > 1) {
|
||||
var el = this.cursors.pop();
|
||||
el.parentNode.removeChild(el);
|
||||
return el;
|
||||
}
|
||||
};
|
||||
|
||||
this.hideCursor = function() {
|
||||
this.isVisible = false;
|
||||
dom.addCssClass(this.cursor, "ace_hidden");
|
||||
for (var i = this.cursors.length; i--; )
|
||||
dom.addCssClass(this.cursors[i], "ace_hidden");
|
||||
clearInterval(this.blinkId);
|
||||
};
|
||||
|
||||
this.showCursor = function() {
|
||||
this.isVisible = true;
|
||||
dom.removeCssClass(this.cursor, "ace_hidden");
|
||||
this.cursor.style.visibility = "visible";
|
||||
for (var i = this.cursors.length; i--; )
|
||||
dom.removeCssClass(this.cursors[i], "ace_hidden");
|
||||
|
||||
this.element.style.visibility = "";
|
||||
this.restartTimer();
|
||||
};
|
||||
|
||||
this.restartTimer = function() {
|
||||
clearInterval(this.blinkId);
|
||||
if (!this.isVisible) {
|
||||
if (!this.isVisible)
|
||||
return;
|
||||
}
|
||||
|
||||
var cursor = this.cursor;
|
||||
var element = this.element;
|
||||
this.blinkId = setInterval(function() {
|
||||
cursor.style.visibility = "hidden";
|
||||
element.style.visibility = "hidden";
|
||||
setTimeout(function() {
|
||||
cursor.style.visibility = "visible";
|
||||
element.style.visibility = "visible";
|
||||
}, 400);
|
||||
}, 1000);
|
||||
};
|
||||
|
|
@ -118,25 +141,53 @@ var Cursor = function(parentEl) {
|
|||
this.update = function(config) {
|
||||
this.config = config;
|
||||
|
||||
this.pixelPos = this.getPixelPosition(null, true);
|
||||
if (this.session.selectionMarkerCount > 1) {
|
||||
var selections = this.session.$selectionMarkers;
|
||||
var i = 0, sel, cursorIndex = 0;
|
||||
|
||||
this.cursor.style.left = this.pixelPos.left + "px";
|
||||
this.cursor.style.top = this.pixelPos.top + "px";
|
||||
this.cursor.style.width = config.characterWidth + "px";
|
||||
this.cursor.style.height = config.lineHeight + "px";
|
||||
for (var i = selections.length; i--; ) {
|
||||
sel = selections[i];
|
||||
var pixelPos = this.getPixelPosition(sel.cursor, true);
|
||||
|
||||
var overwrite = this.session.getOverwrite()
|
||||
if (overwrite != this.overwrite) {
|
||||
this.overwrite = overwrite;
|
||||
if (overwrite)
|
||||
dom.addCssClass(this.cursor, "ace_overwrite");
|
||||
else
|
||||
dom.removeCssClass(this.cursor, "ace_overwrite");
|
||||
var style = (this.cursors[cursorIndex++] || this.addCursor()).style;
|
||||
|
||||
style.left = pixelPos.left + "px";
|
||||
style.top = pixelPos.top + "px";
|
||||
style.width = config.characterWidth + "px";
|
||||
style.height = config.lineHeight + "px";
|
||||
}
|
||||
if (cursorIndex > 1)
|
||||
while (this.cursors.length > cursorIndex)
|
||||
this.removeCursor();
|
||||
} else {
|
||||
var pixelPos = this.getPixelPosition(null, true);
|
||||
var style = this.cursor.style;
|
||||
style.left = pixelPos.left + "px";
|
||||
style.top = pixelPos.top + "px";
|
||||
style.width = config.characterWidth + "px";
|
||||
style.height = config.lineHeight + "px";
|
||||
|
||||
while (this.cursors.length > 1)
|
||||
this.removeCursor();
|
||||
}
|
||||
|
||||
var overwrite = this.session.getOverwrite();
|
||||
if (overwrite != this.overwrite)
|
||||
this.$setOverite(overwrite);
|
||||
|
||||
this.restartTimer();
|
||||
};
|
||||
|
||||
this.$setOverite = function(overwrite) {
|
||||
this.overwrite = overwrite;
|
||||
for (var i = this.cursors.length; i--; ) {
|
||||
if (overwrite)
|
||||
dom.addCssClass(this.cursors[i], "ace_overwrite");
|
||||
else
|
||||
dom.removeCssClass(this.cursors[i], "ace_overwrite");
|
||||
}
|
||||
};
|
||||
|
||||
this.destroy = function() {
|
||||
clearInterval(this.blinkId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,11 +68,11 @@ var Gutter = function(parentEl) {
|
|||
this.addGutterDecoration = function(row, className){
|
||||
if (!this.$decorations[row])
|
||||
this.$decorations[row] = "";
|
||||
this.$decorations[row] += " ace_" + className;
|
||||
this.$decorations[row] += " " + className;
|
||||
};
|
||||
|
||||
this.removeGutterDecoration = function(row, className){
|
||||
this.$decorations[row] = this.$decorations[row].replace(" ace_" + className, "");
|
||||
this.$decorations[row] = this.$decorations[row].replace(" " + className, "");
|
||||
};
|
||||
|
||||
this.setBreakpoints = function(rows) {
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ var Marker = function(parentEl) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Draws a marker, which spans a range of text in a single line
|
||||
* Draws a marker, which spans a range of text on multiple lines
|
||||
*/
|
||||
this.drawTextMarker = function(stringBuilder, range, clazz, layerConfig) {
|
||||
// selection start
|
||||
|
|
@ -187,7 +187,7 @@ var Marker = function(parentEl) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Draws a marker which covers one single full line
|
||||
* Draws a marker which covers part or whole width of a single screen line
|
||||
*/
|
||||
this.drawSingleLineMarker = function(stringBuilder, range, clazz, layerConfig, extraLength, type) {
|
||||
var padding = type === "background" ? 0 : this.$padding;
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ var Text = function(parentEl) {
|
|||
lineHeight : 1
|
||||
};
|
||||
|
||||
this.$measureSizes = function() {
|
||||
this.$measureSizes = useragent.isIE || useragent.isOldGecko ? function() {
|
||||
var n = 1000;
|
||||
if (!this.$measureNode) {
|
||||
var measureNode = this.$measureNode = dom.createElement("div");
|
||||
|
|
@ -113,7 +113,7 @@ var Text = function(parentEl) {
|
|||
style.left = style.top = (-n * 40) + "px";
|
||||
|
||||
style.visibility = "hidden";
|
||||
style.position = "absolute";
|
||||
style.position = "fixed";
|
||||
style.overflow = "visible";
|
||||
style.whiteSpace = "nowrap";
|
||||
|
||||
|
|
@ -130,7 +130,6 @@ var Text = function(parentEl) {
|
|||
container = container.parentNode;
|
||||
container.appendChild(measureNode);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Size and width can be null if the editor is not visible or
|
||||
|
|
@ -150,7 +149,46 @@ var Text = function(parentEl) {
|
|||
|
||||
// Size and width can be null if the editor is not visible or
|
||||
// detached from the document
|
||||
if (size.width == 0 && size.height == 0)
|
||||
if (size.width == 0 || size.height == 0)
|
||||
return null;
|
||||
|
||||
return size;
|
||||
}
|
||||
: function() {
|
||||
if (!this.$measureNode) {
|
||||
var measureNode = this.$measureNode = dom.createElement("div");
|
||||
var style = measureNode.style;
|
||||
|
||||
style.width = style.height = "auto";
|
||||
style.left = style.top = -100 + "px";
|
||||
|
||||
style.visibility = "hidden";
|
||||
style.position = "fixed";
|
||||
style.overflow = "visible";
|
||||
style.whiteSpace = "nowrap";
|
||||
|
||||
measureNode.innerHTML = "X";
|
||||
|
||||
var container = this.element.parentNode;
|
||||
while (container && !dom.hasCssClass(container, "ace_editor"))
|
||||
container = container.parentNode;
|
||||
|
||||
if (!container)
|
||||
return this.$measureNode = null;
|
||||
|
||||
container.appendChild(measureNode);
|
||||
}
|
||||
|
||||
var rect = this.$measureNode.getBoundingClientRect();
|
||||
|
||||
var size = {
|
||||
height: rect.height,
|
||||
width: rect.width
|
||||
};
|
||||
|
||||
// Size and width can be null if the editor is not visible or
|
||||
// detached from the document
|
||||
if (size.width == 0 || size.height == 0)
|
||||
return null;
|
||||
|
||||
return size;
|
||||
|
|
@ -264,16 +302,16 @@ var Text = function(parentEl) {
|
|||
};
|
||||
|
||||
this.$renderLinesFragment = function(config, firstRow, lastRow) {
|
||||
var fragment = this.element.ownerDocument.createDocumentFragment(),
|
||||
row = firstRow,
|
||||
fold = this.session.getNextFoldLine(row),
|
||||
foldStart = fold ?fold.start.row :Infinity;
|
||||
var fragment = this.element.ownerDocument.createDocumentFragment();
|
||||
var row = firstRow;
|
||||
var foldLine = this.session.getNextFoldLine(row);
|
||||
var foldStart = foldLine ? foldLine.start.row : Infinity;
|
||||
|
||||
while (true) {
|
||||
if (row > foldStart) {
|
||||
row = fold.end.row+1;
|
||||
fold = this.session.getNextFoldLine(row, fold);
|
||||
foldStart = fold ?fold.start.row :Infinity;
|
||||
row = foldLine.end.row+1;
|
||||
foldLine = this.session.getNextFoldLine(row, foldLine);
|
||||
foldStart = foldLine ? foldLine.start.row : Infinity;
|
||||
}
|
||||
if (row > lastRow)
|
||||
break;
|
||||
|
|
@ -312,15 +350,15 @@ var Text = function(parentEl) {
|
|||
var html = [];
|
||||
var firstRow = config.firstRow, lastRow = config.lastRow;
|
||||
|
||||
var row = firstRow,
|
||||
fold = this.session.getNextFoldLine(row),
|
||||
foldStart = fold ?fold.start.row :Infinity;
|
||||
var row = firstRow;
|
||||
var foldLine = this.session.getNextFoldLine(row);
|
||||
var foldStart = foldLine ? foldLine.start.row : Infinity;
|
||||
|
||||
while (true) {
|
||||
if (row > foldStart) {
|
||||
row = fold.end.row+1;
|
||||
fold = this.session.getNextFoldLine(row, fold);
|
||||
foldStart = fold ?fold.start.row :Infinity;
|
||||
row = foldLine.end.row+1;
|
||||
foldLine = this.session.getNextFoldLine(row, foldLine);
|
||||
foldStart = foldLine ? foldLine.start.row :Infinity;
|
||||
}
|
||||
if (row > lastRow)
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -52,12 +52,12 @@ var CstyleBehaviour = function () {
|
|||
return {
|
||||
text: '{' + selected + '}',
|
||||
selection: false
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
text: '{}',
|
||||
selection: [1, 1]
|
||||
}
|
||||
};
|
||||
}
|
||||
} else if (text == '}') {
|
||||
var cursor = editor.getCursorPosition();
|
||||
|
|
@ -69,7 +69,7 @@ var CstyleBehaviour = function () {
|
|||
return {
|
||||
text: '',
|
||||
selection: [1, 1]
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
} else if (text == "\n") {
|
||||
|
|
@ -87,7 +87,7 @@ var CstyleBehaviour = function () {
|
|||
return {
|
||||
text: '\n' + indent + '\n' + next_indent,
|
||||
selection: [1, indent.length, 1, indent.length]
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -112,12 +112,12 @@ var CstyleBehaviour = function () {
|
|||
return {
|
||||
text: '(' + selected + ')',
|
||||
selection: false
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
text: '()',
|
||||
selection: [1, 1]
|
||||
}
|
||||
};
|
||||
}
|
||||
} else if (text == ')') {
|
||||
var cursor = editor.getCursorPosition();
|
||||
|
|
@ -129,7 +129,7 @@ var CstyleBehaviour = function () {
|
|||
return {
|
||||
text: '',
|
||||
selection: [1, 1]
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -148,14 +148,15 @@ var CstyleBehaviour = function () {
|
|||
});
|
||||
|
||||
this.add("string_dquotes", "insertion", function (state, action, editor, session, text) {
|
||||
if (text == '"') {
|
||||
if (text == '"' || text == "'") {
|
||||
var quote = text;
|
||||
var selection = editor.getSelectionRange();
|
||||
var selected = session.doc.getTextRange(selection);
|
||||
if (selected !== "") {
|
||||
return {
|
||||
text: '"' + selected + '"',
|
||||
text: quote + selected + quote,
|
||||
selection: false
|
||||
}
|
||||
};
|
||||
} else {
|
||||
var cursor = editor.getCursorPosition();
|
||||
var line = session.doc.getLine(cursor.row);
|
||||
|
|
@ -176,7 +177,7 @@ var CstyleBehaviour = function () {
|
|||
if (token.type == "string") {
|
||||
quotepos = -1;
|
||||
} else if (quotepos < 0) {
|
||||
quotepos = token.value.indexOf('"');
|
||||
quotepos = token.value.indexOf(quote);
|
||||
}
|
||||
if ((token.value.length + col) > selection.start.column) {
|
||||
break;
|
||||
|
|
@ -185,19 +186,19 @@ var CstyleBehaviour = function () {
|
|||
}
|
||||
|
||||
// Try and be smart about when we auto insert.
|
||||
if (!token || (quotepos < 0 && token.type !== "comment" && (token.type !== "string" || ((selection.start.column !== token.value.length+col-1) && token.value.lastIndexOf('"') === token.value.length-1)))) {
|
||||
if (!token || (quotepos < 0 && token.type !== "comment" && (token.type !== "string" || ((selection.start.column !== token.value.length+col-1) && token.value.lastIndexOf(quote) === token.value.length-1)))) {
|
||||
return {
|
||||
text: '""',
|
||||
text: quote + quote,
|
||||
selection: [1,1]
|
||||
}
|
||||
};
|
||||
} else if (token && token.type === "string") {
|
||||
// Ignore input and move right one if we're typing over the closing quote.
|
||||
var rightChar = line.substring(cursor.column, cursor.column + 1);
|
||||
if (rightChar == '"') {
|
||||
if (rightChar == quote) {
|
||||
return {
|
||||
text: '',
|
||||
selection: [1, 1]
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -206,7 +207,7 @@ var CstyleBehaviour = function () {
|
|||
|
||||
this.add("string_dquotes", "deletion", function (state, action, editor, session, range) {
|
||||
var selected = session.doc.getTextRange(range);
|
||||
if (!range.isMultiLine() && selected == '"') {
|
||||
if (!range.isMultiLine() && (selected == '"' || selected == "'")) {
|
||||
var line = session.doc.getLine(range.start.row);
|
||||
var rightChar = line.substring(range.start.column + 1, range.start.column + 2);
|
||||
if (rightChar == '"') {
|
||||
|
|
@ -216,7 +217,8 @@ var CstyleBehaviour = function () {
|
|||
}
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
oop.inherits(CstyleBehaviour, Behaviour);
|
||||
|
||||
exports.CstyleBehaviour = CstyleBehaviour;
|
||||
|
|
|
|||
|
|
@ -138,9 +138,9 @@ var ClojureHighlightRules = function() {
|
|||
token : "comment",
|
||||
regex : ";.*$"
|
||||
}, {
|
||||
token : "comment", // multi line comment
|
||||
regex : "^\=begin$",
|
||||
next : "comment"
|
||||
token : "comment", // multi line comment
|
||||
regex : "^=begin$",
|
||||
next : "comment"
|
||||
}, {
|
||||
token : "keyword", //parens
|
||||
regex : "[\\(|\\)]"
|
||||
|
|
@ -193,17 +193,17 @@ var ClojureHighlightRules = function() {
|
|||
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
|
||||
}, {
|
||||
token : "string", // symbol
|
||||
regex : "[:](?:[a-zA-Z]|\d)+"
|
||||
regex : "[:](?:[a-zA-Z]|\\d)+"
|
||||
}, {
|
||||
token : "string.regexp", //Regular Expressions
|
||||
regex : '/#"(?:\.|(\\\")|[^\""\n])*"/g'
|
||||
token : "string.regexp", //Regular Expressions
|
||||
regex : '/#"(?:\\.|(?:\\\")|[^\""\n])*"/g'
|
||||
}
|
||||
|
||||
|
||||
],
|
||||
"comment" : [
|
||||
{
|
||||
token : "comment", // closing comment
|
||||
regex : "^\=end$",
|
||||
regex : "^=end$",
|
||||
next : "start"
|
||||
}, {
|
||||
token : "comment", // comment spanning whole line
|
||||
|
|
|
|||
|
|
@ -45,31 +45,7 @@ var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
|
|||
var CssHighlightRules = function() {
|
||||
|
||||
var properties = lang.arrayToMap(
|
||||
("-moz-appearance|-moz-box-sizing|-webkit-box-sizing|-moz-outline-radius|-moz-transform|-webkit-transform|" +
|
||||
"appearance|azimuth|background-attachment|background-color|background-image|" +
|
||||
"background-origin|background-position|background-repeat|background|border-bottom-color|" +
|
||||
"border-bottom-style|border-bottom-width|border-bottom|border-collapse|" +
|
||||
"border-color|border-left-color|border-left-style|border-left-width|" +
|
||||
"border-left|border-right-color|border-right-style|border-right-width|" +
|
||||
"border-right|border-spacing|border-style|border-top-color|" +
|
||||
"border-top-style|border-top-width|border-top|border-width|border|" +
|
||||
"bottom|box-sizing|caption-side|clear|clip|color|content|counter-increment|" +
|
||||
"counter-reset|cue-after|cue-before|cue|cursor|direction|display|" +
|
||||
"elevation|empty-cells|float|font-family|font-size-adjust|font-size|" +
|
||||
"font-stretch|font-style|font-variant|font-weight|font|height|left|" +
|
||||
"letter-spacing|line-height|list-style-image|list-style-position|" +
|
||||
"list-style-type|list-style|margin-bottom|margin-left|margin-right|" +
|
||||
"margin-top|marker-offset|margin|marks|max-height|max-width|min-height|" +
|
||||
"min-width|-moz-border-radius|opacity|orphans|outline-color|outline-offset|outline-radius|" +
|
||||
"outline-style|outline-width|outline|overflow|overflow-x|overflow-y|padding-bottom|" +
|
||||
"padding-left|padding-right|padding-top|padding|page-break-after|" +
|
||||
"page-break-before|page-break-inside|page|pause-after|pause-before|" +
|
||||
"pause|pitch-range|pitch|play-during|pointer-events|position|quotes|resize|richness|right|" +
|
||||
"size|speak-header|speak-numeral|speak-punctuation|speech-rate|speak|" +
|
||||
"stress|table-layout|text-align|text-decoration|text-indent|" +
|
||||
"text-shadow|text-transform|top|transform|unicode-bidi|vertical-align|" +
|
||||
"visibility|voice-family|volume|white-space|widows|width|word-spacing|" +
|
||||
"z-index").split("|")
|
||||
("animation-fill-mode|alignment-adjust|alignment-baseline|animation-delay|animation-direction|animation-duration|animation-iteration-count|animation-name|animation-play-state|animation-timing-function|animation|appearance|azimuth|backface-visibility|background-attachment|background-break|background-clip|background-color|background-image|background-origin|background-position|background-repeat|background-size|background|baseline-shift|binding|bleed|bookmark-label|bookmark-level|bookmark-state|bookmark-target|border-bottom|border-bottom-color|border-bottom-left-radius|border-bottom-right-radius|border-bottom-style|border-bottom-width|border-collapse|border-color|border-image|border-image-outset|border-image-repeat|border-image-slice|border-image-source|border-image-width|border-left|border-left-color|border-left-style|border-left-width|border-radius|border-right|border-right-color|border-right-style|border-right-width|border-spacing|border-style|border-top|border-top-color|border-top-left-radius|border-top-right-radius|border-top-style|border-top-width|border-width|border|bottom|box-align|box-decoration-break|box-direction|box-flex-group|box-flex|box-lines|box-ordinal-group|box-orient|box-pack|box-shadow|box-sizing|break-after|break-before|break-inside|caption-side|clear|clip|color-profile|color|column-count|column-fill|column-gap|column-rule|column-rule-color|column-rule-style|column-rule-width|column-span|column-width|columns|content|counter-increment|counter-reset|crop|cue-after|cue-before|cue|cursor|direction|display|dominant-baseline|drop-initial-after-adjust|drop-initial-after-align|drop-initial-before-adjust|drop-initial-before-align|drop-initial-size|drop-initial-value|elevation|empty-cells|fit|fit-position|float-offset|float|font-family|font-size|font-size-adjust|font-stretch|font-style|font-variant|font-weight|font|grid-columns|grid-rows|hanging-punctuation|height|hyphenate-after|hyphenate-before|hyphenate-character|hyphenate-lines|hyphenate-resource|hyphens|icon|image-orientation|image-rendering|image-resolution|inline-box-align|left|letter-spacing|line-height|line-stacking-ruby|line-stacking-shift|line-stacking-strategy|line-stacking|list-style-image|list-style-position|list-style-type|list-style|margin-bottom|margin-left|margin-right|margin-top|margin|mark-after|mark-before|mark|marks|marquee-direction|marquee-play-count|marquee-speed|marquee-style|max-height|max-width|min-height|min-width|move-to|nav-down|nav-index|nav-left|nav-right|nav-up|opacity|orphans|outline-color|outline-offset|outline-style|outline-width|outline|overflow-style|overflow-x|overflow-y|overflow|padding-bottom|padding-left|padding-right|padding-top|padding|page-break-after|page-break-before|page-break-inside|page-policy|page|pause-after|pause-before|pause|perspective-origin|perspective|phonemes|pitch-range|pitch|play-during|position|presentation-level|punctuation-trim|quotes|rendering-intent|resize|rest-after|rest-before|rest|richness|right|rotation-point|rotation|ruby-align|ruby-overhang|ruby-position|ruby-span|size|speak-header|speak-numeral|speak-punctuation|speak|speech-rate|stress|string-set|table-layout|target-name|target-new|target-position|target|text-align-last|text-align|text-decoration|text-emphasis|text-height|text-indent|text-justify|text-outline|text-shadow|text-transform|text-wrap|top|transform-origin|transform-style|transform|transition-delay|transition-duration|transition-property|transition-timing-function|transition|unicode-bidi|vertical-align|visibility|voice-balance|voice-duration|voice-family|voice-pitch-range|voice-pitch|voice-rate|voice-stress|voice-volume|volume|white-space-collapse|white-space|widows|width|word-break|word-spacing|word-wrap|z-index").split("|")
|
||||
);
|
||||
|
||||
var functions = lang.arrayToMap(
|
||||
|
|
@ -77,27 +53,7 @@ var CssHighlightRules = function() {
|
|||
);
|
||||
|
||||
var constants = lang.arrayToMap(
|
||||
("absolute|all-scroll|always|armenian|auto|baseline|below|bidi-override|" +
|
||||
"block|bold|bolder|border-box|both|bottom|break-all|break-word|capitalize|center|" +
|
||||
"char|circle|cjk-ideographic|col-resize|collapse|content-box|crosshair|dashed|" +
|
||||
"decimal-leading-zero|decimal|default|disabled|disc|" +
|
||||
"distribute-all-lines|distribute-letter|distribute-space|" +
|
||||
"distribute|dotted|double|e-resize|ellipsis|fixed|georgian|groove|" +
|
||||
"hand|hebrew|help|hidden|hiragana-iroha|hiragana|horizontal|" +
|
||||
"ideograph-alpha|ideograph-numeric|ideograph-parenthesis|" +
|
||||
"ideograph-space|inactive|inherit|inline-block|inline|inset|inside|" +
|
||||
"inter-ideograph|inter-word|italic|justify|katakana-iroha|katakana|" +
|
||||
"keep-all|left|lighter|line-edge|line-through|line|list-item|loose|" +
|
||||
"lower-alpha|lower-greek|lower-latin|lower-roman|lowercase|lr-tb|ltr|" +
|
||||
"medium|middle|move|n-resize|ne-resize|newspaper|no-drop|no-repeat|" +
|
||||
"nw-resize|none|normal|not-allowed|nowrap|oblique|outset|outside|" +
|
||||
"overline|pointer|progress|relative|repeat-x|repeat-y|repeat|right|" +
|
||||
"ridge|row-resize|rtl|s-resize|scroll|se-resize|separate|small-caps|" +
|
||||
"solid|square|static|strict|super|sw-resize|table-footer-group|" +
|
||||
"table-header-group|tb-rl|text-bottom|text-top|text|thick|thin|top|" +
|
||||
"transparent|underline|upper-alpha|upper-latin|upper-roman|uppercase|" +
|
||||
"vertical-ideographic|vertical-text|visible|w-resize|wait|whitespace|" +
|
||||
"zero").split("|")
|
||||
("absolute|after-edge|after|all-scroll|all|alphabetic|always|antialiased|armenian|auto|avoid-column|avoid-page|avoid|balance|baseline|before-edge|before|below|bidi-override|block-line-height|block|bold|bolder|border-box|both|bottom|box|break-all|break-word|capitalize|caps-height|caption|center|central|char|circle|cjk-ideographic|clone|close-quote|col-resize|collapse|column|consider-shifts|contain|content-box|cover|crosshair|cubic-bezier|dashed|decimal-leading-zero|decimal|default|disabled|disc|disregard-shifts|distribute-all-lines|distribute-letter|distribute-space|distribute|dotted|double|e-resize|ease-in|ease-in-out|ease-out|ease|ellipsis|end|exclude-ruby|fill|fixed|font-size|font|georgian|glyphs|grid-height|groove|hand|hanging|hebrew|help|hidden|hiragana-iroha|hiragana|horizontal|icon|ideograph-alpha|ideograph-numeric|ideograph-parenthesis|ideograph-space|ideographic|inactive|include-ruby|inherit|initial|inline-block|inline-box|inline-line-height|inline-table|inline|inset|inside|inter-ideograph|inter-word|invert|italic|justify|katakana-iroha|katakana|keep-all|last|left|lighter|line-edge|line-through|line|linear|list-item|local|loose|lower-alpha|lower-greek|lower-latin|lower-roman|lowercase|lr-tb|ltr|mathematical|max-height|max-size|medium|menu|message-box|middle|move|n-resize|ne-resize|newspaper|no-change|no-close-quote|no-drop|no-open-quote|no-repeat|none|normal|not-allowed|nowrap|nw-resize|oblique|open-quote|outset|outside|overline|padding-box|page|pointer|pre-line|pre-wrap|pre|preserve-3d|progress|relative|repeat-x|repeat-y|repeat|replaced|reset-size|ridge|right|round|row-resize|rtl|s-resize|scroll|se-resize|separate|slice|small-caps|small-caption|solid|space|square|start|static|status-bar|step-end|step-start|steps|stretch|strict|sub|super|sw-resize|table-caption|table-cell|table-column-group|table-column|table-footer-group|table-header-group|table-row-group|table-row|table|tb-rl|text-after-edge|text-before-edge|text-bottom|text-size|text-top|text|thick|thin|top|transparent|underline|upper-alpha|upper-latin|upper-roman|uppercase|use-script|vertical-ideographic|vertical-text|visible|w-resize|wait|whitespace|z-index|zero").split("|")
|
||||
);
|
||||
|
||||
var colors = lang.arrayToMap(
|
||||
|
|
@ -115,6 +71,8 @@ var CssHighlightRules = function() {
|
|||
// regexps are ordered -> the first match is used
|
||||
|
||||
var numRe = "\\-?(?:(?:[0-9]+)|(?:[0-9]*\\.[0-9]+))";
|
||||
var pseudoElements = "(\\:+)\\b(after|before|first-letter|first-line|moz-selection|selection)\\b";
|
||||
var pseudoClasses = "(:)\\b(active|checked|disabled|empty|enabled|first-child|first-of-type|focus|hover|indeterminate|invalid|last-child|last-of-type|link|not|nth-child|nth-last-child|nth-last-of-type|nth-of-type|only-child|only-of-type|required|root|target|valid|visited)\\b";
|
||||
|
||||
var base_ruleset = [
|
||||
{
|
||||
|
|
@ -122,7 +80,7 @@ var CssHighlightRules = function() {
|
|||
merge : true,
|
||||
regex : "\\/\\*",
|
||||
next : "ruleset_comment"
|
||||
},{
|
||||
}, {
|
||||
token : "string", // single line
|
||||
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
|
||||
}, {
|
||||
|
|
@ -130,7 +88,7 @@ var CssHighlightRules = function() {
|
|||
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
|
||||
}, {
|
||||
token : ["constant.numeric", "keyword"],
|
||||
regex : "(" + numRe + ")(em|ex|px|ch|cm|mm|in|pt|pc|deg|rad|dpi|grad|ms|s|hz|khz|%)"
|
||||
regex : "(" + numRe + ")(ch|cm|deg|em|ex|fr|gd|grad|Hz|in|kHz|mm|ms|pc|pt|px|rad|rem|s|turn|vh|vm|vw|%)"
|
||||
}, {
|
||||
token : ["constant.numeric"],
|
||||
regex : "([0-9]+)"
|
||||
|
|
@ -140,6 +98,12 @@ var CssHighlightRules = function() {
|
|||
}, {
|
||||
token : "constant.numeric", // hex3 color
|
||||
regex : "#[a-f0-9]{3}"
|
||||
}, {
|
||||
token : ["punctuation", "entity.other.attribute-name.pseudo-element.css"],
|
||||
regex : pseudoElements
|
||||
}, {
|
||||
token : ["punctuation", "entity.other.attribute-name.pseudo-class.css"],
|
||||
regex : pseudoClasses
|
||||
}, {
|
||||
token : function(value) {
|
||||
if (properties.hasOwnProperty(value.toLowerCase())) {
|
||||
|
|
|
|||
|
|
@ -62,6 +62,9 @@ var HtmlHighlightRules = function() {
|
|||
merge : true,
|
||||
regex : "<\\!--",
|
||||
next : "comment"
|
||||
}, {
|
||||
token : "xml_pe",
|
||||
regex : "<\\!.*?>"
|
||||
}, {
|
||||
token : "meta.tag",
|
||||
regex : "<(?=\s*script\\b)",
|
||||
|
|
@ -77,6 +80,9 @@ var HtmlHighlightRules = function() {
|
|||
}, {
|
||||
token : "text",
|
||||
regex : "\\s+"
|
||||
}, {
|
||||
token : "constant.character.entity",
|
||||
regex : "(?:&#[0-9]+;)|(?:&#x[0-9a-fA-F]+;)|(?:&[a-zA-Z0-9_:\\.-]+;)"
|
||||
}, {
|
||||
token : "text",
|
||||
regex : "[^<]+"
|
||||
|
|
|
|||
|
|
@ -93,20 +93,20 @@ var JavaScriptHighlightRules = function() {
|
|||
);
|
||||
|
||||
// TODO: Unicode escape sequences
|
||||
var identifierRe = "[" + unicode.packages.L + "\\$_]["
|
||||
var identifierRe = "[" + unicode.packages.L + "\\$_]["
|
||||
+ unicode.packages.L
|
||||
+ unicode.packages.Mn + unicode.packages.Mc
|
||||
+ unicode.packages.Nd
|
||||
+ unicode.packages.Pc + "\\$_]*\\b";
|
||||
|
||||
|
||||
var escapedRe = "\\\\(?:x[0-9a-fA-F]{2}|" + // hex
|
||||
"u[0-9a-fA-F]{4}|" + // unicode
|
||||
"[0-2][0-7]{0,2}|" + // oct
|
||||
"3[0-6][0-7]?|" + // oct
|
||||
"37[0-7]?|" + // oct
|
||||
"37[0-7]?|" + // oct
|
||||
"[4-7][0-7]?|" + //oct
|
||||
".)";
|
||||
|
||||
|
||||
// regexp must not have capturing parentheses. Use (?:) instead.
|
||||
// regexps are ordered -> the first match is used
|
||||
|
||||
|
|
@ -114,13 +114,13 @@ var JavaScriptHighlightRules = function() {
|
|||
"start" : [
|
||||
{
|
||||
token : "comment",
|
||||
regex : "\\/\\/.*$"
|
||||
regex : /\/\/.*$/
|
||||
},
|
||||
new DocCommentHighlightRules().getStartRule("doc-start"),
|
||||
{
|
||||
token : "comment", // multi line comment
|
||||
merge : true,
|
||||
regex : "\\/\\*",
|
||||
regex : /\/\*/,
|
||||
next : "comment"
|
||||
}, {
|
||||
token : "string",
|
||||
|
|
@ -132,51 +132,121 @@ var JavaScriptHighlightRules = function() {
|
|||
next : "qqstring"
|
||||
}, {
|
||||
token : "constant.numeric", // hex
|
||||
regex : "0[xX][0-9a-fA-F]+\\b"
|
||||
regex : /0[xX][0-9a-fA-F]+\b/
|
||||
}, {
|
||||
token : "constant.numeric", // float
|
||||
regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
|
||||
regex : /[+-]?\d+(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?\b/
|
||||
}, { // match stuff like: Sound.prototype.play = function() { }
|
||||
token : ["storage.type", "punctuation.operator", "support.function", "punctuation.operator", "entity.name.function", "text", "keyword.operator", "text", "storage.type", "text", "paren.lparen", "variable.parameter", "paren.rparen"],
|
||||
regex : "(" + identifierRe + ")(\\.)(prototype)(\\.)(" + identifierRe +")(\\s*)(=)(\\s*)(function)?(\\s*)(\\()(.*?)(\\))"
|
||||
token : [
|
||||
"storage.type",
|
||||
"punctuation.operator",
|
||||
"support.function",
|
||||
"punctuation.operator",
|
||||
"entity.name.function",
|
||||
"text",
|
||||
"keyword.operator",
|
||||
"text",
|
||||
"storage.type",
|
||||
"text",
|
||||
"paren.lparen",
|
||||
"variable.parameter",
|
||||
"paren.rparen"
|
||||
],
|
||||
regex : "(" + identifierRe + ")(\\.)(prototype)(\\.)(" + identifierRe +")(\\s*)(=)(\\s*)(function)(\\s*)(\\()(.*?)(\\))"
|
||||
}, { // match stuff like: Sound.prototype.play = myfunc
|
||||
token : ["storage.type", "punctuation.operator", "support.function", "punctuation.operator", "entity.name.function", "text", "keyword.operator", "text"],
|
||||
token : [
|
||||
"storage.type",
|
||||
"punctuation.operator",
|
||||
"support.function",
|
||||
"punctuation.operator",
|
||||
"entity.name.function",
|
||||
"text",
|
||||
"keyword.operator",
|
||||
"text"
|
||||
],
|
||||
regex : "(" + identifierRe + ")(\\.)(prototype)(\\.)(" + identifierRe +")(\\s*)(=)(\\s*)"
|
||||
}, { // match stuff like: Sound.play = function() { }
|
||||
token : ["storage.type", "punctuation.operator", "entity.name.function", "text", "keyword.operator", "text", "storage.type", "text", "paren.lparen", "variable.parameter", "paren.rparen"],
|
||||
regex : "(" + identifierRe + ")(\\.)(" + identifierRe +")(\\s*)(=)(\\s*)(function)?(\\s*)(\\()(.*?)(\\))"
|
||||
token : [
|
||||
"storage.type",
|
||||
"punctuation.operator",
|
||||
"entity.name.function",
|
||||
"text",
|
||||
"keyword.operator",
|
||||
"text",
|
||||
"storage.type",
|
||||
"text",
|
||||
"paren.lparen",
|
||||
"variable.parameter",
|
||||
"paren.rparen"
|
||||
],
|
||||
regex : "(" + identifierRe + ")(\\.)(" + identifierRe +")(\\s*)(=)(\\s*)(function)(\\s*)(\\()(.*?)(\\))"
|
||||
}, { // match stuff like: play = function() { }
|
||||
token : ["entity.name.function", "text", "keyword.operator", "text", "storage.type", "text", "paren.lparen", "variable.parameter", "paren.rparen"],
|
||||
regex : "(" + identifierRe +")(\\s*)(=)(\\s*)(function)?(\\s*)(\\()(.*?)(\\))"
|
||||
token : [
|
||||
"entity.name.function",
|
||||
"text",
|
||||
"keyword.operator",
|
||||
"text",
|
||||
"storage.type",
|
||||
"text",
|
||||
"paren.lparen",
|
||||
"variable.parameter",
|
||||
"paren.rparen"
|
||||
],
|
||||
regex : "(" + identifierRe +")(\\s*)(=)(\\s*)(function)(\\s*)(\\()(.*?)(\\))"
|
||||
}, { // match regular function like: function myFunc(arg) { }
|
||||
token : ["storage.type", "text", "entity.name.function", "text", "paren.lparen", "variable.parameter", "paren.rparen"],
|
||||
token : [
|
||||
"storage.type",
|
||||
"text",
|
||||
"entity.name.function",
|
||||
"text",
|
||||
"paren.lparen",
|
||||
"variable.parameter",
|
||||
"paren.rparen"
|
||||
],
|
||||
regex : "(function)(\\s+)(" + identifierRe + ")(\\s*)(\\()(.*?)(\\))"
|
||||
}, { // match stuff like: foobar: function() { }
|
||||
token : ["entity.name.function", "text", "punctuation.operator", "text", "storage.type", "text", "paren.lparen", "variable.parameter", "paren.rparen"],
|
||||
regex : "(" + identifierRe + ")(\\s*)(:)(\\s*)(function)?(\\s*)(\\()(.*?)(\\))"
|
||||
token : [
|
||||
"entity.name.function",
|
||||
"text",
|
||||
"punctuation.operator",
|
||||
"text",
|
||||
"storage.type",
|
||||
"text",
|
||||
"paren.lparen",
|
||||
"variable.parameter",
|
||||
"paren.rparen"
|
||||
],
|
||||
regex : "(" + identifierRe + ")(\\s*)(:)(\\s*)(function)(\\s*)(\\()(.*?)(\\))"
|
||||
}, { // Attempt to match : function() { } (this is for issues with 'foo': function() { })
|
||||
token : ["text", "text", "storage.type", "text", "paren.lparen", "variable.parameter", "paren.rparen"],
|
||||
token : [
|
||||
"text",
|
||||
"text",
|
||||
"storage.type",
|
||||
"text",
|
||||
"paren.lparen",
|
||||
"variable.parameter",
|
||||
"paren.rparen"
|
||||
],
|
||||
regex : "(:)(\\s*)(function)?(\\s*)(\\()([^)]*)(\\))"
|
||||
}, {
|
||||
token : "constant.language.boolean",
|
||||
regex : "(?:true|false)\\b"
|
||||
regex : /(?:true|false)\b/
|
||||
}, {
|
||||
token : "keyword",
|
||||
regex : "(?:" + kwBeforeRe + ")\\b",
|
||||
next : "regex_allowed"
|
||||
}, {
|
||||
token : "support.function",
|
||||
regex : "\\b(?:s(?:h(?:ift|ow(?:Mod(?:elessDialog|alDialog)|Help))|croll(?:X|By(?:Pages|Lines)?|Y|To)?|t(?:op|rike)|i(?:n|zeToContent|debar|gnText)|ort|u(?:p|b(?:str(?:ing)?)?)|pli(?:ce|t)|e(?:nd|t(?:Re(?:sizable|questHeader)|M(?:i(?:nutes|lliseconds)|onth)|Seconds|Ho(?:tKeys|urs)|Year|Cursor|Time(?:out)?|Interval|ZOptions|Date|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear)|FullYear|Active)|arch)|qrt|lice|avePreferences|mall)|h(?:ome|andleEvent)|navigate|c(?:har(?:CodeAt|At)|o(?:s|n(?:cat|textual|firm)|mpile)|eil|lear(?:Timeout|Interval)?|a(?:ptureEvents|ll)|reate(?:StyleSheet|Popup|EventObject))|t(?:o(?:GMTString|S(?:tring|ource)|U(?:TCString|pperCase)|Lo(?:caleString|werCase))|est|a(?:n|int(?:Enabled)?))|i(?:s(?:NaN|Finite)|ndexOf|talics)|d(?:isableExternalCapture|ump|etachEvent)|u(?:n(?:shift|taint|escape|watch)|pdateCommands)|j(?:oin|avaEnabled)|p(?:o(?:p|w)|ush|lugins.refresh|a(?:ddings|rse(?:Int|Float)?)|r(?:int|ompt|eference))|e(?:scape|nableExternalCapture|val|lementFromPoint|x(?:p|ec(?:Script|Command)?))|valueOf|UTC|queryCommand(?:State|Indeterm|Enabled|Value)|f(?:i(?:nd|le(?:ModifiedDate|Size|CreatedDate|UpdatedDate)|xed)|o(?:nt(?:size|color)|rward)|loor|romCharCode)|watch|l(?:ink|o(?:ad|g)|astIndexOf)|a(?:sin|nchor|cos|t(?:tachEvent|ob|an(?:2)?)|pply|lert|b(?:s|ort))|r(?:ou(?:nd|teEvents)|e(?:size(?:By|To)|calc|turnValue|place|verse|l(?:oad|ease(?:Capture|Events)))|andom)|g(?:o|et(?:ResponseHeader|M(?:i(?:nutes|lliseconds)|onth)|Se(?:conds|lection)|Hours|Year|Time(?:zoneOffset)?|Da(?:y|te)|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Da(?:y|te)|FullYear)|FullYear|A(?:ttention|llResponseHeaders)))|m(?:in|ove(?:B(?:y|elow)|To(?:Absolute)?|Above)|ergeAttributes|a(?:tch|rgins|x))|b(?:toa|ig|o(?:ld|rderWidths)|link|ack))\\b(?=\\()"
|
||||
token : ["punctuation.operator", "support.function"],
|
||||
regex : /(\.)(s(?:h(?:ift|ow(?:Mod(?:elessDialog|alDialog)|Help))|croll(?:X|By(?:Pages|Lines)?|Y|To)?|t(?:opzzzz|rike)|i(?:n|zeToContent|debar|gnText)|ort|u(?:p|b(?:str(?:ing)?)?)|pli(?:ce|t)|e(?:nd|t(?:Re(?:sizable|questHeader)|M(?:i(?:nutes|lliseconds)|onth)|Seconds|Ho(?:tKeys|urs)|Year|Cursor|Time(?:out)?|Interval|ZOptions|Date|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear)|FullYear|Active)|arch)|qrt|lice|avePreferences|mall)|h(?:ome|andleEvent)|navigate|c(?:har(?:CodeAt|At)|o(?:s|n(?:cat|textual|firm)|mpile)|eil|lear(?:Timeout|Interval)?|a(?:ptureEvents|ll)|reate(?:StyleSheet|Popup|EventObject))|t(?:o(?:GMTString|S(?:tring|ource)|U(?:TCString|pperCase)|Lo(?:caleString|werCase))|est|a(?:n|int(?:Enabled)?))|i(?:s(?:NaN|Finite)|ndexOf|talics)|d(?:isableExternalCapture|ump|etachEvent)|u(?:n(?:shift|taint|escape|watch)|pdateCommands)|j(?:oin|avaEnabled)|p(?:o(?:p|w)|ush|lugins.refresh|a(?:ddings|rse(?:Int|Float)?)|r(?:int|ompt|eference))|e(?:scape|nableExternalCapture|val|lementFromPoint|x(?:p|ec(?:Script|Command)?))|valueOf|UTC|queryCommand(?:State|Indeterm|Enabled|Value)|f(?:i(?:nd|le(?:ModifiedDate|Size|CreatedDate|UpdatedDate)|xed)|o(?:nt(?:size|color)|rward)|loor|romCharCode)|watch|l(?:ink|o(?:ad|g)|astIndexOf)|a(?:sin|nchor|cos|t(?:tachEvent|ob|an(?:2)?)|pply|lert|b(?:s|ort))|r(?:ou(?:nd|teEvents)|e(?:size(?:By|To)|calc|turnValue|place|verse|l(?:oad|ease(?:Capture|Events)))|andom)|g(?:o|et(?:ResponseHeader|M(?:i(?:nutes|lliseconds)|onth)|Se(?:conds|lection)|Hours|Year|Time(?:zoneOffset)?|Da(?:y|te)|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Da(?:y|te)|FullYear)|FullYear|A(?:ttention|llResponseHeaders)))|m(?:in|ove(?:B(?:y|elow)|To(?:Absolute)?|Above)|ergeAttributes|a(?:tch|rgins|x))|b(?:toa|ig|o(?:ld|rderWidths)|link|ack))\b(?=\()/
|
||||
}, {
|
||||
token : "support.function.dom",
|
||||
regex : "\\b(?:s(?:ub(?:stringData|mit)|plitText|e(?:t(?:NamedItem|Attribute(?:Node)?)|lect))|has(?:ChildNodes|Feature)|namedItem|c(?:l(?:ick|o(?:se|neNode))|reate(?:C(?:omment|DATASection|aption)|T(?:Head|extNode|Foot)|DocumentFragment|ProcessingInstruction|E(?:ntityReference|lement)|Attribute))|tabIndex|i(?:nsert(?:Row|Before|Cell|Data)|tem)|open|delete(?:Row|C(?:ell|aption)|T(?:Head|Foot)|Data)|focus|write(?:ln)?|a(?:dd|ppend(?:Child|Data))|re(?:set|place(?:Child|Data)|move(?:NamedItem|Child|Attribute(?:Node)?)?)|get(?:NamedItem|Element(?:sBy(?:Name|TagName)|ById)|Attribute(?:Node)?)|blur)\\b(?=\\()"
|
||||
token : ["punctuation.operator", "support.function.dom"],
|
||||
regex : /(\.)(s(?:ub(?:stringData|mit)|plitText|e(?:t(?:NamedItem|Attribute(?:Node)?)|lect))|has(?:ChildNodes|Feature)|namedItem|c(?:l(?:ick|o(?:se|neNode))|reate(?:C(?:omment|DATASection|aption)|T(?:Head|extNode|Foot)|DocumentFragment|ProcessingInstruction|E(?:ntityReference|lement)|Attribute))|tabIndex|i(?:nsert(?:Row|Before|Cell|Data)|tem)|open|delete(?:Row|C(?:ell|aption)|T(?:Head|Foot)|Data)|focus|write(?:ln)?|a(?:dd|ppend(?:Child|Data))|re(?:set|place(?:Child|Data)|move(?:NamedItem|Child|Attribute(?:Node)?)?)|get(?:NamedItem|Element(?:sBy(?:Name|TagName)|ById)|Attribute(?:Node)?)|blur)\b(?=\()/
|
||||
}, {
|
||||
token : "support.function.constant",
|
||||
regex : "\\b(?:s(?:ystemLanguage|cr(?:ipts|ollbars|een(?:X|Y|Top|Left))|t(?:yle(?:Sheets)?|atus(?:Text|bar)?)|ibling(?:Below|Above)|ource|uffixes|e(?:curity(?:Policy)?|l(?:ection|f)))|h(?:istory|ost(?:name)?|as(?:h|Focus))|y|X(?:MLDocument|SLDocument)|n(?:ext|ame(?:space(?:s|URI)|Prop))|M(?:IN_VALUE|AX_VALUE)|c(?:haracterSet|o(?:n(?:structor|trollers)|okieEnabled|lorDepth|mp(?:onents|lete))|urrent|puClass|l(?:i(?:p(?:boardData)?|entInformation)|osed|asses)|alle(?:e|r)|rypto)|t(?:o(?:olbar|p)|ext(?:Transform|Indent|Decoration|Align)|ags)|SQRT(?:1_2|2)|i(?:n(?:ner(?:Height|Width)|put)|ds|gnoreCase)|zIndex|o(?:scpu|n(?:readystatechange|Line)|uter(?:Height|Width)|p(?:sProfile|ener)|ffscreenBuffering)|NEGATIVE_INFINITY|d(?:i(?:splay|alog(?:Height|Top|Width|Left|Arguments)|rectories)|e(?:scription|fault(?:Status|Ch(?:ecked|arset)|View)))|u(?:ser(?:Profile|Language|Agent)|n(?:iqueID|defined)|pdateInterval)|_content|p(?:ixelDepth|ort|ersonalbar|kcs11|l(?:ugins|atform)|a(?:thname|dding(?:Right|Bottom|Top|Left)|rent(?:Window|Layer)?|ge(?:X(?:Offset)?|Y(?:Offset)?))|r(?:o(?:to(?:col|type)|duct(?:Sub)?|mpter)|e(?:vious|fix)))|e(?:n(?:coding|abledPlugin)|x(?:ternal|pando)|mbeds)|v(?:isibility|endor(?:Sub)?|Linkcolor)|URLUnencoded|P(?:I|OSITIVE_INFINITY)|f(?:ilename|o(?:nt(?:Size|Family|Weight)|rmName)|rame(?:s|Element)|gColor)|E|whiteSpace|l(?:i(?:stStyleType|n(?:eHeight|kColor))|o(?:ca(?:tion(?:bar)?|lName)|wsrc)|e(?:ngth|ft(?:Context)?)|a(?:st(?:M(?:odified|atch)|Index|Paren)|yer(?:s|X)|nguage))|a(?:pp(?:MinorVersion|Name|Co(?:deName|re)|Version)|vail(?:Height|Top|Width|Left)|ll|r(?:ity|guments)|Linkcolor|bove)|r(?:ight(?:Context)?|e(?:sponse(?:XML|Text)|adyState))|global|x|m(?:imeTypes|ultiline|enubar|argin(?:Right|Bottom|Top|Left))|L(?:N(?:10|2)|OG(?:10E|2E))|b(?:o(?:ttom|rder(?:Width|RightWidth|BottomWidth|Style|Color|TopWidth|LeftWidth))|ufferDepth|elow|ackground(?:Color|Image)))\\b"
|
||||
token : ["punctuation.operator", "support.constant"],
|
||||
regex : /(\.)(s(?:ystemLanguage|cr(?:ipts|ollbars|een(?:X|Y|Top|Left))|t(?:yle(?:Sheets)?|atus(?:Text|bar)?)|ibling(?:Below|Above)|ource|uffixes|e(?:curity(?:Policy)?|l(?:ection|f)))|h(?:istory|ost(?:name)?|as(?:h|Focus))|y|X(?:MLDocument|SLDocument)|n(?:ext|ame(?:space(?:s|URI)|Prop))|M(?:IN_VALUE|AX_VALUE)|c(?:haracterSet|o(?:n(?:structor|trollers)|okieEnabled|lorDepth|mp(?:onents|lete))|urrent|puClass|l(?:i(?:p(?:boardData)?|entInformation)|osed|asses)|alle(?:e|r)|rypto)|t(?:o(?:olbar|p)|ext(?:Transform|Indent|Decoration|Align)|ags)|SQRT(?:1_2|2)|i(?:n(?:ner(?:Height|Width)|put)|ds|gnoreCase)|zIndex|o(?:scpu|n(?:readystatechange|Line)|uter(?:Height|Width)|p(?:sProfile|ener)|ffscreenBuffering)|NEGATIVE_INFINITY|d(?:i(?:splay|alog(?:Height|Top|Width|Left|Arguments)|rectories)|e(?:scription|fault(?:Status|Ch(?:ecked|arset)|View)))|u(?:ser(?:Profile|Language|Agent)|n(?:iqueID|defined)|pdateInterval)|_content|p(?:ixelDepth|ort|ersonalbar|kcs11|l(?:ugins|atform)|a(?:thname|dding(?:Right|Bottom|Top|Left)|rent(?:Window|Layer)?|ge(?:X(?:Offset)?|Y(?:Offset)?))|r(?:o(?:to(?:col|type)|duct(?:Sub)?|mpter)|e(?:vious|fix)))|e(?:n(?:coding|abledPlugin)|x(?:ternal|pando)|mbeds)|v(?:isibility|endor(?:Sub)?|Linkcolor)|URLUnencoded|P(?:I|OSITIVE_INFINITY)|f(?:ilename|o(?:nt(?:Size|Family|Weight)|rmName)|rame(?:s|Element)|gColor)|E|whiteSpace|l(?:i(?:stStyleType|n(?:eHeight|kColor))|o(?:ca(?:tion(?:bar)?|lName)|wsrc)|e(?:ngth|ft(?:Context)?)|a(?:st(?:M(?:odified|atch)|Index|Paren)|yer(?:s|X)|nguage))|a(?:pp(?:MinorVersion|Name|Co(?:deName|re)|Version)|vail(?:Height|Top|Width|Left)|ll|r(?:ity|guments)|Linkcolor|bove)|r(?:ight(?:Context)?|e(?:sponse(?:XML|Text)|adyState))|global|x|m(?:imeTypes|ultiline|enubar|argin(?:Right|Bottom|Top|Left))|L(?:N(?:10|2)|OG(?:10E|2E))|b(?:o(?:ttom|rder(?:Width|RightWidth|BottomWidth|Style|Color|TopWidth|LeftWidth))|ufferDepth|elow|ackground(?:Color|Image)))\b/
|
||||
}, {
|
||||
token : ["punctuation.operator", "support.function.firebug"],
|
||||
regex : "(\\.)(warn|info|log|error|time|timeEnd|assert)\\b"
|
||||
|
||||
token : ["storage.type", "punctuation.operator", "support.function.firebug"],
|
||||
regex : /(console)(\.)(warn|info|log|error|time|timeEnd|assert)\b/
|
||||
}, {
|
||||
token : function(value) {
|
||||
if (globals.hasOwnProperty(value))
|
||||
|
|
@ -199,29 +269,29 @@ var JavaScriptHighlightRules = function() {
|
|||
regex : identifierRe
|
||||
}, {
|
||||
token : "keyword.operator",
|
||||
regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)",
|
||||
regex : /!|\$|%|&|\*|\-\-|\-|\+\+|\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\|\||\?\:|\*=|%=|\+=|\-=|&=|\^=|\b(?:in|instanceof|new|delete|typeof|void)/,
|
||||
next : "regex_allowed"
|
||||
}, {
|
||||
token : "punctuation.operator",
|
||||
regex : "\\?|\\:|\\,|\\;|\\.",
|
||||
regex : /\?|\:|\,|\;|\./,
|
||||
next : "regex_allowed"
|
||||
}, {
|
||||
token : "paren.lparen",
|
||||
regex : "[[({]",
|
||||
regex : /[\[({]/,
|
||||
next : "regex_allowed"
|
||||
}, {
|
||||
token : "paren.rparen",
|
||||
regex : "[\\])}]"
|
||||
regex : /[\])}]/
|
||||
}, {
|
||||
token : "keyword.operator",
|
||||
regex : "\\/=?",
|
||||
regex : /\/=?/,
|
||||
next : "regex_allowed"
|
||||
}, {
|
||||
token: "comment",
|
||||
regex: "^#!.*$"
|
||||
regex: /^#!.*$/
|
||||
}, {
|
||||
token : "text",
|
||||
regex : "\\s+"
|
||||
regex : /\s+/
|
||||
}
|
||||
],
|
||||
// regular expressions are only allowed after certain tokens. This
|
||||
|
|
@ -246,7 +316,7 @@ var JavaScriptHighlightRules = function() {
|
|||
}, {
|
||||
// immediately return to the start mode without matching
|
||||
// anything
|
||||
token: "empty",
|
||||
token: "empty",
|
||||
regex: "",
|
||||
next: "start"
|
||||
}
|
||||
|
|
@ -258,10 +328,10 @@ var JavaScriptHighlightRules = function() {
|
|||
next: "regex"
|
||||
}, {
|
||||
// flag
|
||||
token: "string.regexp",
|
||||
token: "string.regexp",
|
||||
regex: "/\\w*",
|
||||
next: "start",
|
||||
merge: true
|
||||
merge: true
|
||||
}, {
|
||||
token: "string.regexp",
|
||||
regex: "[^\\\\/\\[]+",
|
||||
|
|
@ -273,9 +343,9 @@ var JavaScriptHighlightRules = function() {
|
|||
next: "regex_character_class",
|
||||
merge: true
|
||||
}, {
|
||||
token: "empty",
|
||||
token: "empty",
|
||||
regex: "",
|
||||
next: "start"
|
||||
next: "start"
|
||||
}
|
||||
],
|
||||
"regex_character_class": [
|
||||
|
|
@ -294,9 +364,9 @@ var JavaScriptHighlightRules = function() {
|
|||
next: "regex_character_class",
|
||||
merge: true
|
||||
}, {
|
||||
token: "empty",
|
||||
token: "empty",
|
||||
regex: "",
|
||||
next: "start"
|
||||
next: "start"
|
||||
}
|
||||
],
|
||||
"comment_regex_allowed" : [
|
||||
|
|
@ -350,7 +420,7 @@ var JavaScriptHighlightRules = function() {
|
|||
}
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
this.embedRules(DocCommentHighlightRules, "doc-",
|
||||
[ new DocCommentHighlightRules().getEndRule("start") ]);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ define(function(require, exports, module) {
|
|||
var oop = require("../lib/oop");
|
||||
var Mirror = require("../worker/mirror").Mirror;
|
||||
var lint = require("../worker/jshint").JSHINT;
|
||||
var parser = require("../narcissus/parser");
|
||||
|
||||
var JavaScriptWorker = exports.JavaScriptWorker = function(sender) {
|
||||
Mirror.call(this, sender);
|
||||
|
|
@ -56,7 +57,6 @@ oop.inherits(JavaScriptWorker, Mirror);
|
|||
value = value.replace(/^#!.*\n/, "\n");
|
||||
|
||||
// var start = new Date();
|
||||
var parser = require("../narcissus/jsparse");
|
||||
try {
|
||||
parser.parse(value);
|
||||
} catch(e) {
|
||||
|
|
|
|||
|
|
@ -59,19 +59,31 @@ module.exports = {
|
|||
}
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
"test check for syntax error": function() {
|
||||
var worker = new JavaScriptWorker(this.sender);
|
||||
worker.setValue("Juhu Kinners");
|
||||
worker.deferredUpdate.call();
|
||||
|
||||
|
||||
var error = this.sender.events[0][1];
|
||||
assert.equal(error.text, "missing ; before statement");
|
||||
assert.equal(error.type, "error");
|
||||
assert.equal(error.row, 0);
|
||||
assert.equal(error.column, null);
|
||||
},
|
||||
|
||||
|
||||
"test invalid multi line string": function() {
|
||||
var worker = new JavaScriptWorker(this.sender);
|
||||
worker.setValue('"a\n\\nn"');
|
||||
worker.deferredUpdate.call();
|
||||
|
||||
var error = this.sender.events[0][1];
|
||||
assert.equal(error.text, "Unterminated string literal");
|
||||
assert.equal(error.type, "error");
|
||||
assert.equal(error.row, 0);
|
||||
assert.equal(error.column, null);
|
||||
},
|
||||
|
||||
"test check for narcissus bug": function() {
|
||||
var worker = new JavaScriptWorker(this.sender);
|
||||
worker.setValue("if('");
|
||||
|
|
|
|||
87
lib/ace/mode/less.js
Normal file
87
lib/ace/mode/less.js
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* John Roepke <john AT justjohn DOT us>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("../lib/oop");
|
||||
var TextMode = require("./text").Mode;
|
||||
var Tokenizer = require("../tokenizer").Tokenizer;
|
||||
var LessHighlightRules = require("./less_highlight_rules").LessHighlightRules;
|
||||
var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent;
|
||||
var CStyleFoldMode = require("./folding/cstyle").FoldMode;
|
||||
|
||||
var Mode = function() {
|
||||
this.$tokenizer = new Tokenizer(new LessHighlightRules().getRules(), "i");
|
||||
this.$outdent = new MatchingBraceOutdent();
|
||||
this.foldingRules = new CStyleFoldMode();
|
||||
};
|
||||
oop.inherits(Mode, TextMode);
|
||||
|
||||
(function() {
|
||||
|
||||
this.getNextLineIndent = function(state, line, tab) {
|
||||
var indent = this.$getIndent(line);
|
||||
|
||||
// ignore braces in comments
|
||||
var tokens = this.$tokenizer.getLineTokens(line, state).tokens;
|
||||
if (tokens.length && tokens[tokens.length-1].type == "comment") {
|
||||
return indent;
|
||||
}
|
||||
|
||||
var match = line.match(/^.*\{\s*$/);
|
||||
if (match) {
|
||||
indent += tab;
|
||||
}
|
||||
|
||||
return indent;
|
||||
};
|
||||
|
||||
this.checkOutdent = function(state, line, input) {
|
||||
return this.$outdent.checkOutdent(line, input);
|
||||
};
|
||||
|
||||
this.autoOutdent = function(state, doc, row) {
|
||||
this.$outdent.autoOutdent(doc, row);
|
||||
};
|
||||
|
||||
}).call(Mode.prototype);
|
||||
|
||||
exports.Mode = Mode;
|
||||
|
||||
});
|
||||
279
lib/ace/mode/less_highlight_rules.js
Normal file
279
lib/ace/mode/less_highlight_rules.js
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* John Roepke <john AT justjohn DOT us>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("../lib/oop");
|
||||
var lang = require("../lib/lang");
|
||||
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
|
||||
|
||||
var LessHighlightRules = function() {
|
||||
|
||||
var properties = lang.arrayToMap( (function () {
|
||||
|
||||
var browserPrefix = ("-webkit-|-moz-|-o-|-ms-|-svg-|-pie-|-khtml-").split("|");
|
||||
|
||||
var prefixProperties = ("appearance|background-clip|background-inline-policy|background-origin|" +
|
||||
"background-size|binding|border-bottom-colors|border-left-colors|" +
|
||||
"border-right-colors|border-top-colors|border-end|border-end-color|" +
|
||||
"border-end-style|border-end-width|border-image|border-start|" +
|
||||
"border-start-color|border-start-style|border-start-width|box-align|" +
|
||||
"box-direction|box-flex|box-flexgroup|box-ordinal-group|box-orient|" +
|
||||
"box-pack|box-sizing|column-count|column-gap|column-width|column-rule|" +
|
||||
"column-rule-width|column-rule-style|column-rule-color|float-edge|" +
|
||||
"font-feature-settings|font-language-override|force-broken-image-icon|" +
|
||||
"image-region|margin-end|margin-start|opacity|outline|outline-color|" +
|
||||
"outline-offset|outline-radius|outline-radius-bottomleft|" +
|
||||
"outline-radius-bottomright|outline-radius-topleft|outline-radius-topright|" +
|
||||
"outline-style|outline-width|padding-end|padding-start|stack-sizing|" +
|
||||
"tab-size|text-blink|text-decoration-color|text-decoration-line|" +
|
||||
"text-decoration-style|transform|transform-origin|transition|" +
|
||||
"transition-delay|transition-duration|transition-property|" +
|
||||
"transition-timing-function|user-focus|user-input|user-modify|user-select|" +
|
||||
"window-shadow|border-radius").split("|");
|
||||
|
||||
var properties = ("azimuth|background-attachment|background-color|background-image|" +
|
||||
"background-position|background-repeat|background|border-bottom-color|" +
|
||||
"border-bottom-style|border-bottom-width|border-bottom|border-collapse|" +
|
||||
"border-color|border-left-color|border-left-style|border-left-width|" +
|
||||
"border-left|border-right-color|border-right-style|border-right-width|" +
|
||||
"border-right|border-spacing|border-style|border-top-color|" +
|
||||
"border-top-style|border-top-width|border-top|border-width|border|" +
|
||||
"bottom|box-sizing|caption-side|clear|clip|color|content|counter-increment|" +
|
||||
"counter-reset|cue-after|cue-before|cue|cursor|direction|display|" +
|
||||
"elevation|empty-cells|float|font-family|font-size-adjust|font-size|" +
|
||||
"font-stretch|font-style|font-variant|font-weight|font|height|left|" +
|
||||
"letter-spacing|line-height|list-style-image|list-style-position|" +
|
||||
"list-style-type|list-style|margin-bottom|margin-left|margin-right|" +
|
||||
"margin-top|marker-offset|margin|marks|max-height|max-width|min-height|" +
|
||||
"min-width|opacity|orphans|outline-color|" +
|
||||
"outline-style|outline-width|outline|overflow|overflow-x|overflow-y|padding-bottom|" +
|
||||
"padding-left|padding-right|padding-top|padding|page-break-after|" +
|
||||
"page-break-before|page-break-inside|page|pause-after|pause-before|" +
|
||||
"pause|pitch-range|pitch|play-during|position|quotes|richness|right|" +
|
||||
"size|speak-header|speak-numeral|speak-punctuation|speech-rate|speak|" +
|
||||
"stress|table-layout|text-align|text-decoration|text-indent|" +
|
||||
"text-shadow|text-transform|top|unicode-bidi|vertical-align|" +
|
||||
"visibility|voice-family|volume|white-space|widows|width|word-spacing|" +
|
||||
"z-index").split("|");
|
||||
|
||||
//The return array
|
||||
var ret = [];
|
||||
|
||||
//All prefixProperties will get the browserPrefix in
|
||||
//the begning by join the prefixProperties array with the value of browserPrefix
|
||||
for (var i=0, ln=browserPrefix.length; i<ln; i++) {
|
||||
Array.prototype.push.apply(
|
||||
ret,
|
||||
(( browserPrefix[i] + prefixProperties.join("|" + browserPrefix[i]) ).split("|"))
|
||||
);
|
||||
}
|
||||
|
||||
//Add also prefixProperties and properties without any browser prefix
|
||||
Array.prototype.push.apply(ret, prefixProperties);
|
||||
Array.prototype.push.apply(ret, properties);
|
||||
|
||||
return ret;
|
||||
|
||||
})() );
|
||||
|
||||
|
||||
|
||||
var functions = lang.arrayToMap(
|
||||
("hsl|hsla|rgb|rgba|url|attr|counter|counters|lighten|darken|saturate|" +
|
||||
"desaturate|fadein|fadeout|fade|spin|mix|hue|saturation|lightness|" +
|
||||
"alpha|round|ceil|floor|percentage|color|iscolor|isnumber|isstring|" +
|
||||
"iskeyword|isurl|ispixel|ispercentage|isem").split("|")
|
||||
);
|
||||
|
||||
var constants = lang.arrayToMap(
|
||||
("absolute|all-scroll|always|armenian|auto|baseline|below|bidi-override|" +
|
||||
"block|bold|bolder|border-box|both|bottom|break-all|break-word|capitalize|center|" +
|
||||
"char|circle|cjk-ideographic|col-resize|collapse|content-box|crosshair|dashed|" +
|
||||
"decimal-leading-zero|decimal|default|disabled|disc|" +
|
||||
"distribute-all-lines|distribute-letter|distribute-space|" +
|
||||
"distribute|dotted|double|e-resize|ellipsis|fixed|georgian|groove|" +
|
||||
"hand|hebrew|help|hidden|hiragana-iroha|hiragana|horizontal|" +
|
||||
"ideograph-alpha|ideograph-numeric|ideograph-parenthesis|" +
|
||||
"ideograph-space|inactive|inherit|inline-block|inline|inset|inside|" +
|
||||
"inter-ideograph|inter-word|italic|justify|katakana-iroha|katakana|" +
|
||||
"keep-all|left|lighter|line-edge|line-through|line|list-item|loose|" +
|
||||
"lower-alpha|lower-greek|lower-latin|lower-roman|lowercase|lr-tb|ltr|" +
|
||||
"medium|middle|move|n-resize|ne-resize|newspaper|no-drop|no-repeat|" +
|
||||
"nw-resize|none|normal|not-allowed|nowrap|oblique|outset|outside|" +
|
||||
"overline|pointer|progress|relative|repeat-x|repeat-y|repeat|right|" +
|
||||
"ridge|row-resize|rtl|s-resize|scroll|se-resize|separate|small-caps|" +
|
||||
"solid|square|static|strict|super|sw-resize|table-footer-group|" +
|
||||
"table-header-group|tb-rl|text-bottom|text-top|text|thick|thin|top|" +
|
||||
"transparent|underline|upper-alpha|upper-latin|upper-roman|uppercase|" +
|
||||
"vertical-ideographic|vertical-text|visible|w-resize|wait|whitespace|" +
|
||||
"zero").split("|")
|
||||
);
|
||||
|
||||
var colors = lang.arrayToMap(
|
||||
("aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|" +
|
||||
"purple|red|silver|teal|white|yellow").split("|")
|
||||
);
|
||||
|
||||
var keywords = lang.arrayToMap(
|
||||
("@mixin|@extend|@include|@import|@media|@debug|@warn|@if|@for|@each|" +
|
||||
"@while|@else|@font-face|@-webkit-keyframes|if|and|!default|module|" +
|
||||
"def|end|declare|when|not|and").split("|")
|
||||
);
|
||||
|
||||
var tags = lang.arrayToMap(
|
||||
("a|abbr|acronym|address|applet|area|article|aside|audio|b|base|basefont|bdo|" +
|
||||
"big|blockquote|body|br|button|canvas|caption|center|cite|code|col|colgroup|" +
|
||||
"command|datalist|dd|del|details|dfn|dir|div|dl|dt|em|embed|fieldset|" +
|
||||
"figcaption|figure|font|footer|form|frame|frameset|h1|h2|h3|h4|h5|h6|head|" +
|
||||
"header|hgroup|hr|html|i|iframe|img|input|ins|keygen|kbd|label|legend|li|" +
|
||||
"link|map|mark|menu|meta|meter|nav|noframes|noscript|object|ol|optgroup|" +
|
||||
"option|output|p|param|pre|progress|q|rp|rt|ruby|s|samp|script|section|select|" +
|
||||
"small|source|span|strike|strong|style|sub|summary|sup|table|tbody|td|" +
|
||||
"textarea|tfoot|th|thead|time|title|tr|tt|u|ul|var|video|wbr|xmp").split("|")
|
||||
);
|
||||
|
||||
// regexp must not have capturing parentheses. Use (?:) instead.
|
||||
// regexps are ordered -> the first match is used
|
||||
|
||||
var numRe = "\\-?(?:(?:[0-9]+)|(?:[0-9]*\\.[0-9]+))";
|
||||
|
||||
// regexp must not have capturing parentheses. Use (?:) instead.
|
||||
// regexps are ordered -> the first match is used
|
||||
|
||||
this.$rules = {
|
||||
"start" : [
|
||||
{
|
||||
token : "comment",
|
||||
regex : "\\/\\/.*$"
|
||||
},
|
||||
{
|
||||
token : "comment", // multi line comment
|
||||
merge : true,
|
||||
regex : "\\/\\*",
|
||||
next : "comment"
|
||||
}, {
|
||||
token : "string", // single line
|
||||
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
|
||||
}, {
|
||||
token : "string", // single line
|
||||
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
|
||||
}, {
|
||||
token : "constant.numeric",
|
||||
regex : numRe + "(?:em|ex|px|cm|mm|in|pt|pc|deg|rad|grad|ms|s|hz|khz|%)"
|
||||
}, {
|
||||
token : "constant.numeric", // hex6 color
|
||||
regex : "#[a-f0-9]{6}"
|
||||
}, {
|
||||
token : "constant.numeric", // hex3 color
|
||||
regex : "#[a-f0-9]{3}"
|
||||
}, {
|
||||
token : "constant.numeric",
|
||||
regex : numRe
|
||||
}, {
|
||||
token : function(value) {
|
||||
if (keywords.hasOwnProperty(value))
|
||||
return "keyword";
|
||||
else
|
||||
return "variable";
|
||||
},
|
||||
regex : "@[a-z0-9_\\-@]*\\b"
|
||||
}, {
|
||||
token : function(value) {
|
||||
if (properties.hasOwnProperty(value.toLowerCase()))
|
||||
return "support.type";
|
||||
else if (keywords.hasOwnProperty(value))
|
||||
return "keyword";
|
||||
else if (constants.hasOwnProperty(value))
|
||||
return "constant.language";
|
||||
else if (functions.hasOwnProperty(value))
|
||||
return "support.function";
|
||||
else if (colors.hasOwnProperty(value.toLowerCase()))
|
||||
return "support.constant.color";
|
||||
else if (tags.hasOwnProperty(value.toLowerCase()))
|
||||
return "variable.language";
|
||||
else
|
||||
return "text";
|
||||
},
|
||||
regex : "\\-?[@a-z_][@a-z0-9_\\-]*"
|
||||
}, {
|
||||
token: "variable.language",
|
||||
regex: "#[a-z0-9-_]+"
|
||||
}, {
|
||||
token: "variable.language",
|
||||
regex: "\\.[a-z0-9-_]+"
|
||||
}, {
|
||||
token: "variable.language",
|
||||
regex: ":[a-z0-9-_]+"
|
||||
}, {
|
||||
token: "constant",
|
||||
regex: "[a-z0-9-_]+"
|
||||
}, {
|
||||
token : "keyword.operator",
|
||||
regex : "<|>|<=|>=|==|!=|-|%|#|\\+|\\$|\\+|\\*"
|
||||
}, {
|
||||
token : "paren.lparen",
|
||||
regex : "[[({]"
|
||||
}, {
|
||||
token : "paren.rparen",
|
||||
regex : "[\\])}]"
|
||||
}, {
|
||||
token : "text",
|
||||
regex : "\\s+"
|
||||
}
|
||||
],
|
||||
"comment" : [
|
||||
{
|
||||
token : "comment", // closing comment
|
||||
regex : ".*?\\*\\/",
|
||||
next : "start"
|
||||
}, {
|
||||
token : "comment", // comment spanning whole line
|
||||
merge : true,
|
||||
regex : ".+"
|
||||
}
|
||||
]
|
||||
};
|
||||
};
|
||||
|
||||
oop.inherits(LessHighlightRules, TextHighlightRules);
|
||||
|
||||
exports.LessHighlightRules = LessHighlightRules;
|
||||
|
||||
});
|
||||
116
lib/ace/mode/liquid.js
Normal file
116
lib/ace/mode/liquid.js
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var oop = require("../lib/oop");
|
||||
var TextMode = require("./text").Mode;
|
||||
var Tokenizer = require("../tokenizer").Tokenizer;
|
||||
var LiquidHighlightRules = require("./liquid_highlight_rules").LiquidHighlightRules;
|
||||
var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent;
|
||||
var Range = require("../range").Range;
|
||||
|
||||
var Mode = function() {
|
||||
this.$tokenizer = new Tokenizer(new LiquidHighlightRules().getRules());
|
||||
this.$outdent = new MatchingBraceOutdent();
|
||||
};
|
||||
oop.inherits(Mode, TextMode);
|
||||
|
||||
(function() {
|
||||
|
||||
this.toggleCommentLines = function(state, doc, startRow, endRow) {
|
||||
var outdent = true;
|
||||
var outentedRows = [];
|
||||
var re = /^(\s*)#/;
|
||||
|
||||
for (var i=startRow; i<= endRow; i++) {
|
||||
if (!re.test(doc.getLine(i))) {
|
||||
outdent = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (outdent) {
|
||||
var deleteRange = new Range(0, 0, 0, 0);
|
||||
for (var i=startRow; i<= endRow; i++)
|
||||
{
|
||||
var line = doc.getLine(i);
|
||||
var m = line.match(re);
|
||||
deleteRange.start.row = i;
|
||||
deleteRange.end.row = i;
|
||||
deleteRange.end.column = m[0].length;
|
||||
doc.replace(deleteRange, m[1]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
doc.indentRows(startRow, endRow, "#");
|
||||
}
|
||||
};
|
||||
|
||||
this.getNextLineIndent = function(state, line, tab) {
|
||||
var indent = this.$getIndent(line);
|
||||
|
||||
var tokenizedLine = this.$tokenizer.getLineTokens(line, state);
|
||||
var tokens = tokenizedLine.tokens;
|
||||
var endState = tokenizedLine.state;
|
||||
|
||||
if (tokens.length && tokens[tokens.length-1].type == "comment") {
|
||||
return indent;
|
||||
}
|
||||
|
||||
if (state == "start") {
|
||||
var match = line.match(/^.*[\{\(\[]\s*$/);
|
||||
if (match) {
|
||||
indent += tab;
|
||||
}
|
||||
}
|
||||
|
||||
return indent;
|
||||
};
|
||||
|
||||
this.checkOutdent = function(state, line, input) {
|
||||
return this.$outdent.checkOutdent(line, input);
|
||||
};
|
||||
|
||||
this.autoOutdent = function(state, doc, row) {
|
||||
this.$outdent.autoOutdent(doc, row);
|
||||
};
|
||||
|
||||
}).call(Mode.prototype);
|
||||
|
||||
exports.Mode = Mode;
|
||||
});
|
||||
220
lib/ace/mode/liquid_highlight_rules.js
Normal file
220
lib/ace/mode/liquid_highlight_rules.js
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("../lib/oop");
|
||||
var CssHighlightRules = require("./css_highlight_rules").CssHighlightRules;
|
||||
var JavaScriptHighlightRules = require("./javascript_highlight_rules").JavaScriptHighlightRules;
|
||||
var lang = require("../lib/lang");
|
||||
var xmlUtil = require("./xml_util");
|
||||
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
|
||||
|
||||
var LiquidHighlightRules = function() {
|
||||
|
||||
// see: https://developer.mozilla.org/en/Liquid/Reference/Global_Objects
|
||||
var functions = lang.arrayToMap(
|
||||
// Standard Filters
|
||||
("date|capitalize|downcase|upcase|first|last|join|sort|map|size|escape|" +
|
||||
"escape_once|strip_html|strip_newlines|newline_to_br|replace|replace_first|" +
|
||||
"truncate|truncatewords|prepend|append|minus|plus|times|divided_by|split"
|
||||
).split("|")
|
||||
);
|
||||
|
||||
var keywords = lang.arrayToMap(
|
||||
// Standard Tags
|
||||
("capture|endcapture|case|endcase|when|comment|endcomment|" +
|
||||
"cycle|for|endfor|in|reversed|if|endif|else|elsif|include|endinclude|unless|endunless|" +
|
||||
// Commonly used tags
|
||||
"style|text|image|widget|plugin|marker|endmarker|tablerow|endtablerow").split("|")
|
||||
);
|
||||
|
||||
var builtinVariables = lang.arrayToMap(
|
||||
['forloop']
|
||||
// ("forloop\\.(length|index|index0|rindex|rindex0|first|last)|limit|offset|range" +
|
||||
// "tablerowloop\\.(length|index|index0|rindex|rindex0|first|last|col|col0|"+
|
||||
// "col_first|col_last)").split("|")
|
||||
);
|
||||
|
||||
var definitions = lang.arrayToMap(("assign").split("|"));
|
||||
|
||||
// regexp must not have capturing parentheses. Use (?:) instead.
|
||||
// regexps are ordered -> the first match is used
|
||||
|
||||
this.$rules = {
|
||||
start : [{
|
||||
token : "variable",
|
||||
regex : "{%",
|
||||
next : "liquid_start"
|
||||
}, {
|
||||
token : "variable",
|
||||
regex : "{{",
|
||||
next : "liquid_start"
|
||||
}, {
|
||||
token : "meta.tag",
|
||||
merge : true,
|
||||
regex : "<\\!\\[CDATA\\[",
|
||||
next : "cdata"
|
||||
}, {
|
||||
token : "xml_pe",
|
||||
regex : "<\\?.*?\\?>"
|
||||
}, {
|
||||
token : "comment",
|
||||
merge : true,
|
||||
regex : "<\\!--",
|
||||
next : "comment"
|
||||
}, {
|
||||
token : "meta.tag",
|
||||
regex : "<(?=\\s*script\\b)",
|
||||
next : "script"
|
||||
}, {
|
||||
token : "meta.tag",
|
||||
regex : "<(?=\\s*style\\b)",
|
||||
next : "style"
|
||||
}, {
|
||||
token : "meta.tag", // opening tag
|
||||
regex : "<\\/?",
|
||||
next : "tag"
|
||||
}, {
|
||||
token : "text",
|
||||
regex : "\\s+"
|
||||
}, {
|
||||
token : "text",
|
||||
regex : "[^<]+"
|
||||
} ],
|
||||
|
||||
cdata : [ {
|
||||
token : "text",
|
||||
regex : "\\]\\]>",
|
||||
next : "start"
|
||||
}, {
|
||||
token : "text",
|
||||
merge : true,
|
||||
regex : "\\s+"
|
||||
}, {
|
||||
token : "text",
|
||||
merge : true,
|
||||
regex : ".+"
|
||||
} ],
|
||||
|
||||
comment : [ {
|
||||
token : "comment",
|
||||
regex : ".*?-->",
|
||||
next : "start"
|
||||
}, {
|
||||
token : "comment",
|
||||
merge : true,
|
||||
regex : ".+"
|
||||
} ] ,
|
||||
|
||||
liquid_start : [{
|
||||
token: "variable",
|
||||
regex: "}}",
|
||||
next: "start"
|
||||
}, {
|
||||
token: "variable",
|
||||
regex: "%}",
|
||||
next: "start"
|
||||
}, {
|
||||
token : "string", // single line
|
||||
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
|
||||
}, {
|
||||
token : "string", // single line
|
||||
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
|
||||
}, {
|
||||
token : "constant.numeric", // hex
|
||||
regex : "0[xX][0-9a-fA-F]+\\b"
|
||||
}, {
|
||||
token : "constant.numeric", // float
|
||||
regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
|
||||
}, {
|
||||
token : "constant.language.boolean",
|
||||
regex : "(?:true|false)\\b"
|
||||
}, {
|
||||
token : function(value) {
|
||||
if (functions.hasOwnProperty(value))
|
||||
return "support.function";
|
||||
else if (keywords.hasOwnProperty(value))
|
||||
return "keyword";
|
||||
else if (builtinVariables.hasOwnProperty(value))
|
||||
return "variable.language";
|
||||
else if (definitions.hasOwnProperty(value))
|
||||
return "keyword.definition";
|
||||
else
|
||||
return "identifier";
|
||||
},
|
||||
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
|
||||
}, {
|
||||
token : "keyword.operator",
|
||||
regex : "\/|\\*|\\-|\\+|=|!=|\\?\\:"
|
||||
}, {
|
||||
token : "paren.lparen",
|
||||
regex : /[\[\({]/
|
||||
}, {
|
||||
token : "paren.rparen",
|
||||
regex : /[\])}]/
|
||||
}, {
|
||||
token : "text",
|
||||
regex : "\\s+"
|
||||
}]
|
||||
};
|
||||
|
||||
xmlUtil.tag(this.$rules, "tag", "start");
|
||||
xmlUtil.tag(this.$rules, "style", "css-start");
|
||||
xmlUtil.tag(this.$rules, "script", "js-start");
|
||||
|
||||
this.embedRules(JavaScriptHighlightRules, "js-", [{
|
||||
token: "comment",
|
||||
regex: "\\/\\/.*(?=<\\/script>)",
|
||||
next: "tag"
|
||||
}, {
|
||||
token: "meta.tag",
|
||||
regex: "<\\/(?=script)",
|
||||
next: "tag"
|
||||
}]);
|
||||
|
||||
this.embedRules(CssHighlightRules, "css-", [{
|
||||
token: "meta.tag",
|
||||
regex: "<\\/(?=style)",
|
||||
next: "tag"
|
||||
}]);
|
||||
};
|
||||
oop.inherits(LiquidHighlightRules, TextHighlightRules);
|
||||
|
||||
exports.LiquidHighlightRules = LiquidHighlightRules;
|
||||
});
|
||||
91
lib/ace/mode/liquid_highlight_rules_test.js
Normal file
91
lib/ace/mode/liquid_highlight_rules_test.js
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var LiquidMode = require("./liquid").Mode;
|
||||
var assert = require("../test/assertions");
|
||||
|
||||
module.exports = {
|
||||
|
||||
name: "Liquid Tokenizer",
|
||||
|
||||
setUp : function() {
|
||||
this.tokenizer = new LiquidMode().getTokenizer();
|
||||
},
|
||||
|
||||
"test: tokenize tags" : function() {
|
||||
var line = "for one in many";
|
||||
|
||||
var tokens = this.tokenizer.getLineTokens(line, "liquid_start").tokens;
|
||||
|
||||
assert.equal(7, tokens.length);
|
||||
assert.equal("keyword", tokens[0].type);
|
||||
assert.equal("text", tokens[1].type);
|
||||
assert.equal("identifier", tokens[2].type);
|
||||
assert.equal("text", tokens[3].type);
|
||||
assert.equal("keyword", tokens[4].type);
|
||||
assert.equal("text", tokens[5].type);
|
||||
assert.equal("identifier", tokens[6].type);
|
||||
},
|
||||
|
||||
"test: tokenize parens" : function() {
|
||||
var line = "[{( )}]";
|
||||
|
||||
var tokens = this.tokenizer.getLineTokens(line, "liquid_start").tokens;
|
||||
|
||||
assert.equal(7, tokens.length);
|
||||
assert.equal("paren.lparen", tokens[0].type);
|
||||
assert.equal("paren.lparen", tokens[1].type);
|
||||
assert.equal("paren.lparen", tokens[2].type);
|
||||
assert.equal("text", tokens[3].type);
|
||||
assert.equal("paren.rparen", tokens[4].type);
|
||||
assert.equal("paren.rparen", tokens[5].type);
|
||||
assert.equal("paren.rparen", tokens[6].type);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
|
|
@ -64,7 +64,7 @@ var MarkdownHighlightRules = function() {
|
|||
token : "empty_line",
|
||||
regex : '^$'
|
||||
}, { // code span `
|
||||
token : "support.function",
|
||||
token : ["support.function", "support.function", "support.function"],
|
||||
regex : "(`+)([^\\r]*?[^`])(\\1)"
|
||||
}, { // code block
|
||||
token : "support.function",
|
||||
|
|
@ -94,7 +94,7 @@ var MarkdownHighlightRules = function() {
|
|||
next : "blockquote"
|
||||
}, { // reference
|
||||
token : ["text", "constant", "text", "url", "string", "text"],
|
||||
regex : "^([ ]{0,3}\\[)([^\\]]+)(\\]:\\s*)([^ ]+)(\\s*(?:[\"][^\"]+[\"])?\\s*)$"
|
||||
regex : "^([ ]{0,3}\\[)([^\\]]+)(\\]:\\s*)([^ ]+)(\\s*(?:[\"][^\"]+[\"])?(\\s*))$"
|
||||
}, { // link by reference
|
||||
token : ["text", "string", "text", "constant", "text"],
|
||||
regex : "(\\[)((?:[[^\\]]*\\]|[^\\[\\]])*)(\\][ ]?(?:\\n[ ]*)?\\[)(.*?)(\\])"
|
||||
|
|
@ -120,10 +120,10 @@ var MarkdownHighlightRules = function() {
|
|||
regex : "^\\s{0,3}(?:[*+-]|\\d+\\.)\\s+",
|
||||
next : "listblock"
|
||||
}, { // strong ** __
|
||||
token : "string",
|
||||
token : ["string", "string", "string"],
|
||||
regex : "([*]{2}|[_]{2}(?=\\S))([^\\r]*?\\S[*_]*)(\\1)"
|
||||
}, { // emphasis * _
|
||||
token : "string",
|
||||
token : ["string", "string", "string"],
|
||||
regex : "([*]|[_](?=\\S))([^\\r]*?\\S[*_]*)(\\1)"
|
||||
}, { //
|
||||
token : ["text", "url", "text"],
|
||||
|
|
|
|||
|
|
@ -1046,7 +1046,7 @@ var PhpHighlightRules = function() {
|
|||
}, {
|
||||
token : "string",
|
||||
regex : '[^"]+'
|
||||
},
|
||||
}
|
||||
],
|
||||
"qstring" : [
|
||||
{
|
||||
|
|
@ -1094,7 +1094,7 @@ var PhpHighlightRules = function() {
|
|||
next : "htmltag"
|
||||
}, {
|
||||
token : "meta.tag",
|
||||
regex : ">",
|
||||
regex : ">"
|
||||
}, {
|
||||
token : 'text',
|
||||
regex : "(?:media|type|href)"
|
||||
|
|
@ -1104,7 +1104,7 @@ var PhpHighlightRules = function() {
|
|||
}, {
|
||||
token : "paren.lparen",
|
||||
regex : "\{",
|
||||
next : "cssdeclaration",
|
||||
next : "cssdeclaration"
|
||||
}, {
|
||||
token : "keyword",
|
||||
regex : "#[A-Za-z0-9\-\_\.]+"
|
||||
|
|
@ -1146,7 +1146,7 @@ var PhpHighlightRules = function() {
|
|||
regex : ";",
|
||||
next : "cssdeclaration"
|
||||
}
|
||||
],
|
||||
]
|
||||
};
|
||||
|
||||
this.embedRules(DocCommentHighlightRules, "doc-",
|
||||
|
|
|
|||
|
|
@ -59,6 +59,9 @@ var XmlHighlightRules = function() {
|
|||
merge : true,
|
||||
regex : "<\\!--",
|
||||
next : "comment"
|
||||
}, {
|
||||
token : "xml_pe",
|
||||
regex : "<\\!.*?>"
|
||||
}, {
|
||||
token : "meta.tag", // opening tag
|
||||
regex : "<\\/?",
|
||||
|
|
@ -66,6 +69,9 @@ var XmlHighlightRules = function() {
|
|||
}, {
|
||||
token : "text",
|
||||
regex : "\\s+"
|
||||
}, {
|
||||
token : "constant.character.entity",
|
||||
regex : "(?:&#[0-9]+;)|(?:&#x[0-9a-fA-F]+;)|(?:&[a-zA-Z0-9_:\\.-]+;)"
|
||||
}, {
|
||||
token : "text",
|
||||
regex : "[^<]+"
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ exports.tag = function(states, name, nextState) {
|
|||
}
|
||||
},
|
||||
merge : true,
|
||||
regex : "[-_a-zA-Z0-9:!]+",
|
||||
regex : "[-_a-zA-Z0-9:]+",
|
||||
next : name + "_embed_attribute_list"
|
||||
}, {
|
||||
token: "empty",
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ function DefaultHandlers(editor) {
|
|||
if (!editor.$mouseHandler.$clickSelection) {
|
||||
if (!dragCursor) {
|
||||
editor.moveCursorToPosition(pos);
|
||||
editor.selection.clearSelection(pos.row, pos.column);
|
||||
editor.selection.clearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -169,7 +169,6 @@ function DefaultHandlers(editor) {
|
|||
if (distance > DRAG_OFFSET) {
|
||||
state = STATE_SELECT;
|
||||
var cursor = editor.renderer.screenToTextCoordinates(mousePageX, mousePageY);
|
||||
cursor.row = Math.max(0, Math.min(cursor.row, editor.session.getLength()-1));
|
||||
onStartSelect(cursor);
|
||||
}
|
||||
else if ((time - mousedownTime) > editor.getDragDelay()) {
|
||||
|
|
@ -196,7 +195,7 @@ function DefaultHandlers(editor) {
|
|||
else {
|
||||
if (!_self.$clickSelection) {
|
||||
editor.moveCursorToPosition(pos);
|
||||
editor.selection.clearSelection(pos.row, pos.column);
|
||||
editor.selection.clearSelection();
|
||||
}
|
||||
}
|
||||
state = STATE_SELECT;
|
||||
|
|
@ -205,7 +204,6 @@ function DefaultHandlers(editor) {
|
|||
var onUpdateSelectionInterval = function() {
|
||||
var anchor;
|
||||
var cursor = editor.renderer.screenToTextCoordinates(mousePageX, mousePageY);
|
||||
cursor.row = Math.max(0, Math.min(cursor.row, editor.session.getLength()-1));
|
||||
|
||||
if (_self.$clickSelection) {
|
||||
if (_self.$clickSelection.contains(cursor.row, cursor.column)) {
|
||||
|
|
@ -231,8 +229,6 @@ function DefaultHandlers(editor) {
|
|||
|
||||
var onDragSelectionInterval = function() {
|
||||
dragCursor = editor.renderer.screenToTextCoordinates(mousePageX, mousePageY);
|
||||
dragCursor.row = Math.max(0, Math.min(dragCursor.row, editor.session.getLength() - 1));
|
||||
|
||||
editor.moveCursorToPosition(dragCursor);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ function FoldHandler(editor) {
|
|||
var position = e.getDocumentPosition();
|
||||
var session = editor.session;
|
||||
|
||||
// If the user dclicked on a fold, then expand it.
|
||||
// If the user clicked on a fold, then expand it.
|
||||
var fold = session.getFoldAt(position.row, position.column, 1);
|
||||
if (fold) {
|
||||
if (e.getAccelKey())
|
||||
|
|
|
|||
|
|
@ -90,7 +90,6 @@ var MouseEvent = exports.MouseEvent = function(domEvent, editor) {
|
|||
var pageX = event.getDocumentX(this.domEvent);
|
||||
var pageY = event.getDocumentY(this.domEvent);
|
||||
this.$pos = this.editor.renderer.screenToTextCoordinates(pageX, pageY);
|
||||
this.$pos.row = Math.max(0, Math.min(this.$pos.row, this.editor.session.getLength()-1));
|
||||
return this.$pos;
|
||||
};
|
||||
|
||||
|
|
|
|||
161
lib/ace/mouse/multi_select_handler.js
Normal file
161
lib/ace/mouse/multi_select_handler.js
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Harutyun Amirjanyan <amirjanyan AT gmail DOT com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var event = require("../lib/event");
|
||||
|
||||
|
||||
// mouse
|
||||
function isSamePoint(p1, p2) {
|
||||
return p1.row == p2.row && p1.column == p2.column;
|
||||
}
|
||||
|
||||
function onMouseDown(e) {
|
||||
var ev = e.domEvent;
|
||||
var alt = ev.altKey;
|
||||
var shift = ev.shiftKey;
|
||||
var ctrl = e.getAccelKey();
|
||||
var button = e.getButton();
|
||||
|
||||
if (!ctrl && !alt) {
|
||||
if (e.editor.inMultiSelectMode) {
|
||||
if (button == 0) {
|
||||
e.editor.exitMultiSelectMode();
|
||||
} else if (button == 2) {
|
||||
var editor = e.editor;
|
||||
var selectionEmpty = editor.selection.isEmpty();
|
||||
editor.textInput.onContextMenu({x: e.clientX, y: e.clientY}, selectionEmpty);
|
||||
event.capture(editor.container, function(){}, editor.textInput.onContextMenuClose);
|
||||
e.stop();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var editor = e.editor;
|
||||
var selection = editor.selection;
|
||||
var isMultiSelect = editor.inMultiSelectMode;
|
||||
var pos = e.getDocumentPosition();
|
||||
var cursor = selection.getCursor();
|
||||
var inSelection = e.inSelection() || (selection.isEmpty() && isSamePoint(pos, cursor));
|
||||
|
||||
|
||||
var mouseX = e.pageX, mouseY = e.pageY;
|
||||
var onMouseSelection = function(e) {
|
||||
mouseX = event.getDocumentX(e);
|
||||
mouseY = event.getDocumentY(e);
|
||||
};
|
||||
|
||||
var blockSelect = function() {
|
||||
var newCursor = editor.renderer.pixelToScreenCoordinates(mouseX, mouseY);
|
||||
var cursor = session.screenToDocumentPosition(newCursor.row, newCursor.column);
|
||||
|
||||
if (isSamePoint(screenCursor, newCursor)
|
||||
&& isSamePoint(cursor, selection.selectionLead))
|
||||
return;
|
||||
screenCursor = newCursor;
|
||||
|
||||
editor.selection.moveCursorToPosition(cursor);
|
||||
editor.selection.clearSelection();
|
||||
editor.renderer.scrollCursorIntoView();
|
||||
|
||||
editor.removeSelectionMarkers(rectSel);
|
||||
rectSel = selection.rectangularRangeBlock(screenCursor, screenAnchor);
|
||||
rectSel.forEach(editor.addSelectionMarker, editor);
|
||||
editor.updateSelectionMarkers();
|
||||
};
|
||||
|
||||
var session = editor.session;
|
||||
var screenAnchor = editor.renderer.pixelToScreenCoordinates(mouseX, mouseY);
|
||||
var screenCursor = screenAnchor;
|
||||
|
||||
|
||||
|
||||
if (ctrl && !shift && !alt && button == 0) {
|
||||
if (!isMultiSelect && inSelection)
|
||||
return; // dragging
|
||||
|
||||
if (!isMultiSelect)
|
||||
selection.addRange(selection.toOrientedRange());
|
||||
|
||||
|
||||
var oldRange = selection.rangeList.rangeAtPoint(pos);
|
||||
|
||||
event.capture(editor.container, function(){}, function() {
|
||||
var tmpSel = selection.toOrientedRange();
|
||||
|
||||
if (oldRange && tmpSel.isEmpty() && isSamePoint(oldRange.cursor, tmpSel.cursor))
|
||||
selection.substractPoint(tmpSel.cursor);
|
||||
else
|
||||
selection.addRange(tmpSel);
|
||||
});
|
||||
|
||||
} else if (!shift && alt && button == 0) {
|
||||
e.stop();
|
||||
|
||||
if (isMultiSelect && !ctrl)
|
||||
selection.toSingleRange();
|
||||
else if (!isMultiSelect && ctrl)
|
||||
selection.addRange();
|
||||
|
||||
selection.moveCursorToPosition(pos);
|
||||
selection.clearSelection();
|
||||
|
||||
var rectSel = [];
|
||||
|
||||
var onMouseSelectionEnd = function(e) {
|
||||
clearInterval(timerId);
|
||||
editor.removeSelectionMarkers(rectSel);
|
||||
for (var i = 0; i < rectSel.length; i++)
|
||||
selection.addRange(rectSel[i]);
|
||||
};
|
||||
|
||||
var onSelectionInterval = blockSelect;
|
||||
|
||||
event.capture(editor.container, onMouseSelection, onMouseSelectionEnd);
|
||||
var timerId = setInterval(function() {onSelectionInterval();}, 20);
|
||||
|
||||
return e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
exports.onMouseDown = onMouseDown;
|
||||
|
||||
});
|
||||
630
lib/ace/multi_select.js
Normal file
630
lib/ace/multi_select.js
Normal file
|
|
@ -0,0 +1,630 @@
|
|||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Harutyun Amirjanyan <amirjanyan AT gmail DOT com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var RangeList = require("./range_list").RangeList;
|
||||
var Range = require("./range").Range;
|
||||
var Selection = require("./selection").Selection;
|
||||
var onMouseDown = require("./mouse/multi_select_handler").onMouseDown;
|
||||
exports.commands = require("./commands/multi_select_commands");
|
||||
|
||||
// Todo: session.find or editor.findVolatile that returns range
|
||||
var Search = require("./search").Search;
|
||||
var search = new Search();
|
||||
|
||||
function find(session, needle, dir) {
|
||||
search.$options.wrap = true;
|
||||
search.$options.needle = needle;
|
||||
search.$options.backwards = dir == -1;
|
||||
return search.find(session);
|
||||
}
|
||||
|
||||
// extend EditSession
|
||||
var EditSession = require("./edit_session").EditSession;
|
||||
(function() {
|
||||
this.getSelectionMarkers = function() {
|
||||
return this.$selectionMarkers;
|
||||
};
|
||||
}).call(EditSession.prototype);
|
||||
|
||||
// extend Selection
|
||||
(function() {
|
||||
// list of ranges in reverse addition order
|
||||
this.ranges = null;
|
||||
|
||||
// automatically sorted list of ranges
|
||||
this.rangeList = null;
|
||||
|
||||
/**
|
||||
* Selection.addRange(Range) -> Void
|
||||
*
|
||||
* adds a range to selection entering multiselect mode if necessary
|
||||
**/
|
||||
this.addRange = function(range) {
|
||||
if (!this.inMultiSelectMode && this.rangeCount == 0) {
|
||||
var oldRange = this.toOrientedRange();
|
||||
if (!range || !range.isEqual(oldRange)) {
|
||||
this.rangeList.add(oldRange);
|
||||
this.$onAddRange(oldRange);
|
||||
}
|
||||
}
|
||||
|
||||
if (!range)
|
||||
return;
|
||||
|
||||
if (!range.cursor)
|
||||
range.cursor = range.end;
|
||||
|
||||
var removed = this.rangeList.add(range);
|
||||
|
||||
this.$onAddRange(range);
|
||||
|
||||
if (removed.length)
|
||||
this.$onRemoveRange(removed);
|
||||
|
||||
if (this.rangeCount > 0 && !this.inMultiSelectMode) {
|
||||
this._emit("multiSelect");
|
||||
this.inMultiSelectMode = true;
|
||||
this.session.$undoSelect = false;
|
||||
this.rangeList.attach(this.session);
|
||||
}
|
||||
};
|
||||
|
||||
this.toSingleRange = function(range) {
|
||||
range = range || this.ranges[0];
|
||||
var removed = this.rangeList.removeAll();
|
||||
if (removed.length)
|
||||
this.$onRemoveRange(removed);
|
||||
|
||||
range && this.fromOrientedRange(range);
|
||||
};
|
||||
|
||||
/**
|
||||
* Selection.addRange(pos) -> Range
|
||||
* pos: {row, column}
|
||||
*
|
||||
* removes range containing pos (if exists)
|
||||
**/
|
||||
this.substractPoint = function(pos) {
|
||||
var removed = this.rangeList.substractPoint(pos);
|
||||
if (removed) {
|
||||
this.$onRemoveRange(removed);
|
||||
return removed[0];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Selection.mergeOverlappingRanges() -> Void
|
||||
*
|
||||
* merges overlapping ranges ensuring consistency after changes
|
||||
**/
|
||||
this.mergeOverlappingRanges = function() {
|
||||
var removed = this.rangeList.merge();
|
||||
if (removed.length)
|
||||
this.$onRemoveRange(removed);
|
||||
else if(this.ranges[0])
|
||||
this.fromOrientedRange(this.ranges[0]);
|
||||
};
|
||||
|
||||
this.$onAddRange = function(range) {
|
||||
this.rangeCount = this.rangeList.ranges.length;
|
||||
this.ranges.unshift(range);
|
||||
this.fromOrientedRange(range);
|
||||
this._emit("addRange", {range: range});
|
||||
};
|
||||
|
||||
this.$onRemoveRange = function(removed) {
|
||||
this.rangeCount = this.rangeList.ranges.length;
|
||||
if (this.rangeCount == 1 && this.inMultiSelectMode) {
|
||||
var lastRange = this.rangeList.ranges.pop();
|
||||
removed.push(lastRange);
|
||||
this.rangeCount = 0;
|
||||
}
|
||||
|
||||
for (var i = removed.length; i--; ) {
|
||||
var index = this.ranges.indexOf(removed[i]);
|
||||
this.ranges.splice(index, 1);
|
||||
}
|
||||
|
||||
this._emit("removeRange", {ranges: removed});
|
||||
|
||||
if (this.rangeCount == 0 && this.inMultiSelectMode) {
|
||||
this.inMultiSelectMode = false;
|
||||
this._emit("singleSelect");
|
||||
this.session.$undoSelect = true;
|
||||
this.rangeList.detach(this.session);
|
||||
}
|
||||
|
||||
lastRange = lastRange || this.ranges[0];
|
||||
if (lastRange && !lastRange.isEqual(this.getRange()))
|
||||
this.fromOrientedRange(lastRange);
|
||||
};
|
||||
|
||||
// adds multicursor support to selection
|
||||
this.$initRangeList = function() {
|
||||
if (this.rangeList)
|
||||
return;
|
||||
|
||||
this.rangeList = new RangeList();
|
||||
this.ranges = [];
|
||||
this.rangeCount = 0;
|
||||
};
|
||||
|
||||
this.getAllRanges = function() {
|
||||
return this.rangeList.ranges.concat();
|
||||
};
|
||||
|
||||
this.splitIntoLines = function () {
|
||||
if (this.rangeCount > 1) {
|
||||
var ranges = this.rangeList.ranges;
|
||||
var lastRange = ranges[ranges.length - 1];
|
||||
var range = Range.fromPoints(ranges[0].start, lastRange.end);
|
||||
|
||||
this.toSingleRange();
|
||||
this.setSelectionRange(range, lastRange.cursor == lastRange.start);
|
||||
} else {
|
||||
var cursor = this.session.documentToScreenPosition(this.selectionLead);
|
||||
var anchor = this.session.documentToScreenPosition(this.selectionAnchor);
|
||||
|
||||
var rectSel = this.rectangularRangeBlock(cursor, anchor);
|
||||
rectSel.forEach(this.addRange, this);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Selection.rectangularRangeBlock(screenCursor, screenAnchor, includeEmptyLines) -> [Range]
|
||||
* gets list of ranges composing rectangular block on the screen
|
||||
* @includeEmptyLines if true includes ranges inside the block which
|
||||
* are empty becuase of the clipping
|
||||
*/
|
||||
this.rectangularRangeBlock = function(screenCursor, screenAnchor, includeEmptyLines) {
|
||||
var rectSel = [];
|
||||
|
||||
var xBackwards = screenCursor.column < screenAnchor.column;
|
||||
if (xBackwards) {
|
||||
var startColumn = screenCursor.column;
|
||||
var endColumn = screenAnchor.column;
|
||||
} else {
|
||||
var startColumn = screenAnchor.column;
|
||||
var endColumn = screenCursor.column;
|
||||
}
|
||||
|
||||
var yBackwards = screenCursor.row < screenAnchor.row;
|
||||
if (yBackwards) {
|
||||
var startRow = screenCursor.row;
|
||||
var endRow = screenAnchor.row;
|
||||
} else {
|
||||
var startRow = screenAnchor.row;
|
||||
var endRow = screenCursor.row;
|
||||
}
|
||||
|
||||
if (startColumn < 0)
|
||||
startColumn = 0;
|
||||
if (startRow < 0)
|
||||
startRow = 0;
|
||||
|
||||
if (startRow == endRow)
|
||||
includeEmptyLines = true;
|
||||
|
||||
for (var row = startRow; row <= endRow; row++) {
|
||||
var range = Range.fromPoints(
|
||||
this.session.screenToDocumentPosition(row, startColumn),
|
||||
this.session.screenToDocumentPosition(row, endColumn)
|
||||
);
|
||||
if (range.isEmpty()) {
|
||||
if (docEnd && isSamePoint(range.end, docEnd))
|
||||
break;
|
||||
var docEnd = range.end;
|
||||
}
|
||||
range.cursor = xBackwards ? range.start : range.end;
|
||||
rectSel.push(range);
|
||||
}
|
||||
|
||||
if (yBackwards)
|
||||
rectSel.reverse();
|
||||
|
||||
if (!includeEmptyLines) {
|
||||
var end = rectSel.length - 1;
|
||||
while (rectSel[end].isEmpty() && end > 0)
|
||||
end--;
|
||||
if (end > 0) {
|
||||
var start = 0;
|
||||
while (rectSel[start].isEmpty())
|
||||
start++;
|
||||
}
|
||||
for (var i = end; i >= start; i--) {
|
||||
if (rectSel[i].isEmpty())
|
||||
rectSel.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return rectSel;
|
||||
};
|
||||
}).call(Selection.prototype);
|
||||
|
||||
// extend Editor
|
||||
var Editor = require("./editor").Editor;
|
||||
(function() {
|
||||
/**
|
||||
* Editor.updateSelectionMarkers() -> Void
|
||||
*
|
||||
* updates cursor and marker layers
|
||||
**/
|
||||
this.updateSelectionMarkers = function() {
|
||||
this.renderer.updateCursor();
|
||||
this.renderer.updateBackMarkers();
|
||||
};
|
||||
|
||||
/**
|
||||
* Editor.addSelectionMarker(orientedRange) -> Range
|
||||
* - orientedRange: range with cursor
|
||||
*
|
||||
* adds selection and cursor
|
||||
**/
|
||||
this.addSelectionMarker = function(orientedRange) {
|
||||
if (!orientedRange.cursor)
|
||||
orientedRange.cursor = orientedRange.end;
|
||||
|
||||
var style = this.getSelectionStyle();
|
||||
orientedRange.marker = this.session.addMarker(orientedRange, "ace_selection", style);
|
||||
|
||||
this.session.$selectionMarkers.push(orientedRange);
|
||||
this.session.selectionMarkerCount = this.session.$selectionMarkers.length;
|
||||
return orientedRange;
|
||||
};
|
||||
|
||||
this.removeSelectionMarkers = function(ranges) {
|
||||
for (var i = ranges.length; i--; ) {
|
||||
var range = ranges[i];
|
||||
if (!range.marker)
|
||||
continue;
|
||||
this.session.removeMarker(range.marker);
|
||||
var index = this.session.$selectionMarkers.indexOf(range);
|
||||
if (index != -1)
|
||||
this.session.$selectionMarkers.splice(index, 1);
|
||||
}
|
||||
this.session.selectionMarkerCount = this.session.$selectionMarkers.length;
|
||||
};
|
||||
|
||||
this.$onAddRange = function(e) {
|
||||
this.addSelectionMarker(e.range);
|
||||
this.renderer.updateCursor();
|
||||
this.renderer.updateBackMarkers();
|
||||
};
|
||||
|
||||
this.$onRemoveRange = function(e) {
|
||||
this.removeSelectionMarkers(e.ranges);
|
||||
this.renderer.updateCursor();
|
||||
this.renderer.updateBackMarkers();
|
||||
};
|
||||
|
||||
this.$onMultiSelect = function(e) {
|
||||
if (this.inMultiSelectMode)
|
||||
return;
|
||||
this.inMultiSelectMode = true;
|
||||
|
||||
this.setStyle("multiselect");
|
||||
this.keyBinding.addKeyboardHandler(exports.commands.keyboardHandler);
|
||||
this.commands.on("exec", this.$onMultiSelectExec);
|
||||
|
||||
this.renderer.updateCursor();
|
||||
this.renderer.updateBackMarkers();
|
||||
};
|
||||
|
||||
this.$onSingleSelect = function(e) {
|
||||
if (this.session.multiSelect.inVirtualMode)
|
||||
return;
|
||||
this.inMultiSelectMode = false;
|
||||
|
||||
this.unsetStyle("multiselect");
|
||||
this.keyBinding.removeKeyboardHandler(exports.commands.keyboardHandler);
|
||||
|
||||
this.commands.removeEventListener("exec", this.$onMultiSelectExec);
|
||||
this.renderer.updateCursor();
|
||||
this.renderer.updateBackMarkers();
|
||||
};
|
||||
|
||||
this.$onMultiSelectExec = function(e) {
|
||||
var command = e.command;
|
||||
var editor = e.editor;
|
||||
if (!command.multiSelectAction) {
|
||||
command.exec(editor, e.args || {});
|
||||
editor.multiSelect.addRange(editor.multiSelect.toOrientedRange());
|
||||
editor.multiSelect.mergeOverlappingRanges();
|
||||
} else if (command.multiSelectAction == "forEach") {
|
||||
editor.forEachSelection(command, e.args);
|
||||
} else if (command.multiSelectAction == "single") {
|
||||
editor.exitMultiSelectMode();
|
||||
command.exec(editor, e.args || {});
|
||||
} else {
|
||||
command.multiSelectAction(editor, e.args || {});
|
||||
}
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
/**
|
||||
* Editor.forEachSelection(cmd, args) -> Void
|
||||
* - cmd: command to execute
|
||||
* - args: arguments to the command
|
||||
*
|
||||
* executes command for each selection range
|
||||
**/
|
||||
this.forEachSelection = function(cmd, args) {
|
||||
if (this.inVirtualSelectionMode)
|
||||
return;
|
||||
|
||||
var session = this.session;
|
||||
var selection = this.selection;
|
||||
var rangeList = selection.rangeList;
|
||||
|
||||
var reg = selection._eventRegistry;
|
||||
selection._eventRegistry = {};
|
||||
|
||||
var tmpSel = new Selection(session);
|
||||
this.inVirtualSelectionMode = true;
|
||||
for (var i = rangeList.ranges.length; i--;) {
|
||||
tmpSel.fromOrientedRange(rangeList.ranges[i]);
|
||||
this.selection = session.selection = tmpSel;
|
||||
cmd.exec(this, args || {});
|
||||
tmpSel.toOrientedRange(rangeList.ranges[i]);
|
||||
}
|
||||
tmpSel.detach();
|
||||
|
||||
this.selection = session.selection = selection;
|
||||
this.inVirtualSelectionMode = false;
|
||||
selection._eventRegistry = reg;
|
||||
selection.mergeOverlappingRanges();
|
||||
|
||||
this.onCursorChange();
|
||||
this.onSelectionChange();
|
||||
};
|
||||
|
||||
/**
|
||||
* Editor.exitMultiSelectMode() -> Void
|
||||
*
|
||||
* removes all selections except the last added one.
|
||||
**/
|
||||
this.exitMultiSelectMode = function() {
|
||||
if (this.inVirtualSelectionMode)
|
||||
return;
|
||||
this.multiSelect.toSingleRange();
|
||||
};
|
||||
|
||||
this.getCopyText = function() {
|
||||
var text = "";
|
||||
if (this.inMultiSelectMode) {
|
||||
var ranges = this.multiSelect.rangeList.ranges;
|
||||
text = [];
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
text.push(this.session.getTextRange(ranges[i]));
|
||||
}
|
||||
text = text.join(this.session.getDocument().getNewLineCharacter());
|
||||
} else if (!this.selection.isEmpty()) {
|
||||
text = this.session.getTextRange(this.getSelectionRange());
|
||||
}
|
||||
|
||||
return text;
|
||||
};
|
||||
|
||||
|
||||
// commands
|
||||
/**
|
||||
* Editor.selectMoreLines(dir, skip) -> Void
|
||||
* - dir: -1 up, 1 down
|
||||
* - skip: remove active selection range if true
|
||||
*
|
||||
* adds cursor above or bellow active cursor
|
||||
**/
|
||||
this.selectMoreLines = function(dir, skip) {
|
||||
var range = this.selection.toOrientedRange();
|
||||
var isBackwards = range.cursor == range.end;
|
||||
|
||||
var screenLead = this.session.documentToScreenPosition(range.cursor);
|
||||
if (this.selection.$desiredColumn)
|
||||
screenLead.column = this.selection.$desiredColumn;
|
||||
|
||||
var lead = this.session.screenToDocumentPosition(screenLead.row + dir, screenLead.column);
|
||||
|
||||
if (!range.isEmpty()) {
|
||||
var screenAnchor = this.session.documentToScreenPosition(isBackwards ? range.end : range.start);
|
||||
var anchor = this.session.screenToDocumentPosition(screenAnchor.row + dir, screenAnchor.column);
|
||||
} else {
|
||||
var anchor = lead;
|
||||
}
|
||||
|
||||
if (isBackwards) {
|
||||
var newRange = Range.fromPoints(lead, anchor);
|
||||
newRange.cursor = newRange.start;
|
||||
} else {
|
||||
var newRange = Range.fromPoints(anchor, lead);
|
||||
newRange.cursor = newRange.end;
|
||||
}
|
||||
|
||||
newRange.desiredColumn = screenLead.column;
|
||||
if (!this.selection.inMultiSelectMode) {
|
||||
this.selection.addRange(range);
|
||||
} else {
|
||||
if (skip)
|
||||
var toRemove = range.cursor;
|
||||
}
|
||||
|
||||
this.selection.addRange(newRange);
|
||||
if (toRemove)
|
||||
this.selection.substractPoint(toRemove);
|
||||
};
|
||||
|
||||
/**
|
||||
* Editor.transposeSelections(dir) -> Void
|
||||
* - dir: direction to rotate selections
|
||||
*
|
||||
* contents
|
||||
* empty ranges are expanded to word
|
||||
**/
|
||||
this.transposeSelections = function(dir) {
|
||||
var session = this.session;
|
||||
var sel = session.multiSelect;
|
||||
var all = sel.ranges;
|
||||
|
||||
for (var i = all.length; i--; ) {
|
||||
var range = all[i];
|
||||
if (range.isEmpty()) {
|
||||
var tmp = session.getWordRange(range.start.row, range.start.column);
|
||||
range.start.row = tmp.start.row;
|
||||
range.start.column = tmp.start.column;
|
||||
range.end.row = tmp.end.row;
|
||||
range.end.column = tmp.end.column;
|
||||
}
|
||||
}
|
||||
sel.mergeOverlappingRanges();
|
||||
|
||||
var words = [];
|
||||
for (var i = all.length; i--; ) {
|
||||
var range = all[i];
|
||||
words.unshift(session.getTextRange(range));
|
||||
}
|
||||
|
||||
if (dir < 0)
|
||||
words.unshift(words.pop());
|
||||
else
|
||||
words.push(words.shift());
|
||||
|
||||
for (var i = all.length; i--; ) {
|
||||
var range = all[i];
|
||||
var tmp = range.clone();
|
||||
session.replace(range, words[i]);
|
||||
range.start.row = tmp.start.row;
|
||||
range.start.column = tmp.start.column;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Editor.selectMore(dir, skip) -> Void
|
||||
* - dir: 1 next, -1 previous
|
||||
* - skip: remove active selection range if true
|
||||
*
|
||||
* finds next occurence of text in active selection
|
||||
* and adds it to the selections
|
||||
**/
|
||||
this.selectMore = function (dir, skip) {
|
||||
var session = this.session;
|
||||
var sel = session.multiSelect;
|
||||
|
||||
var range = sel.toOrientedRange();
|
||||
if (range.isEmpty()) {
|
||||
var range = session.getWordRange(range.start.row, range.start.column);
|
||||
range.cursor = range.end;
|
||||
this.multiSelect.addRange(range);
|
||||
}
|
||||
var needle = session.getTextRange(range);
|
||||
|
||||
var newRange = find(session, needle, dir);
|
||||
if (newRange) {
|
||||
newRange.cursor = dir == -1 ? newRange.start : newRange.end;
|
||||
this.multiSelect.addRange(newRange);
|
||||
}
|
||||
if (skip)
|
||||
this.multiSelect.substractPoint(range.cursor);
|
||||
};
|
||||
}).call(Editor.prototype);
|
||||
|
||||
|
||||
function isSamePoint(p1, p2) {
|
||||
return p1.row == p2.row && p1.column == p2.column;
|
||||
}
|
||||
|
||||
// patch
|
||||
// adds multicursor support to a session
|
||||
exports.onSessionChange = function(e) {
|
||||
var session = e.session;
|
||||
if (!session.multiSelect) {
|
||||
session.$selectionMarkers = [];
|
||||
session.selection.$initRangeList();
|
||||
session.multiSelect = session.selection;
|
||||
}
|
||||
this.multiSelect = session.multiSelect;
|
||||
|
||||
var oldSession = e.oldSession;
|
||||
if (oldSession) {
|
||||
// todo use events
|
||||
if (oldSession.multiSelect && oldSession.multiSelect.editor == this)
|
||||
oldSession.multiSelect.editor = null;
|
||||
|
||||
session.multiSelect.removeEventListener("addRange", this.$onAddRange);
|
||||
session.multiSelect.removeEventListener("removeRange", this.$onRemoveRange);
|
||||
session.multiSelect.removeEventListener("multiSelect", this.$onMultiSelect);
|
||||
session.multiSelect.removeEventListener("singleSelect", this.$onSingleSelect);
|
||||
}
|
||||
|
||||
session.multiSelect.on("addRange", this.$onAddRange);
|
||||
session.multiSelect.on("removeRange", this.$onRemoveRange);
|
||||
session.multiSelect.on("multiSelect", this.$onMultiSelect);
|
||||
session.multiSelect.on("singleSelect", this.$onSingleSelect);
|
||||
|
||||
// this.$onSelectionChange = this.onSelectionChange.bind(this);
|
||||
|
||||
if (this.inMultiSelectMode != session.selection.inMultiSelectMode) {
|
||||
if (session.selection.inMultiSelectMode)
|
||||
this.$onMultiSelect();
|
||||
else
|
||||
this.$onSingleSelect();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* MultiSelect(editor) -> Void
|
||||
*
|
||||
* adds multiple selection support to the editor
|
||||
* (note: should be called only once for each editor instance)
|
||||
**/
|
||||
function MultiSelect(editor) {
|
||||
editor.$onAddRange = editor.$onAddRange.bind(editor);
|
||||
editor.$onRemoveRange = editor.$onRemoveRange.bind(editor);
|
||||
editor.$onMultiSelect = editor.$onMultiSelect.bind(editor);
|
||||
editor.$onSingleSelect = editor.$onSingleSelect.bind(editor);
|
||||
|
||||
exports.onSessionChange.call(editor, editor);
|
||||
editor.on("changeSession", exports.onSessionChange.bind(editor));
|
||||
|
||||
editor.on("mousedown", onMouseDown);
|
||||
editor.commands.addCommands(exports.commands.defaultCommands);
|
||||
}
|
||||
|
||||
exports.MultiSelect = MultiSelect;
|
||||
|
||||
});
|
||||
146
lib/ace/multi_select_test.js
Normal file
146
lib/ace/multi_select_test.js
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Harutyun Amirjanyan <amirjanyan AT gmail DOT com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var EditSession = require("./edit_session").EditSession;
|
||||
var Editor = require("./editor").Editor;
|
||||
var MockRenderer = require("./test/mockrenderer").MockRenderer;
|
||||
var Range = require("./range").Range;
|
||||
var assert = require("./test/assertions");
|
||||
var MultiSelect = require("./multi_select").MultiSelect;
|
||||
|
||||
var editor
|
||||
var exec = function(name, times, args) {
|
||||
do {
|
||||
editor.commands.exec(name, editor, args);
|
||||
} while(times --> 1)
|
||||
};
|
||||
var testRanges = function(str) {
|
||||
assert.equal(editor.selection.getAllRanges()+"", str);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
name: "ACE multi_select.js",
|
||||
|
||||
"test: multiselect editing": function() {
|
||||
var doc = new EditSession([
|
||||
"w1.w2",
|
||||
" wtt.w",
|
||||
" wtt.w"
|
||||
]);
|
||||
editor = new Editor(new MockRenderer(), doc);
|
||||
MultiSelect(editor);
|
||||
|
||||
editor.navigateFileEnd();
|
||||
exec("selectMoreBefore", 3);
|
||||
assert.ok(editor.inMultiSelectMode);
|
||||
assert.equal(editor.selection.getAllRanges().length, 4);
|
||||
|
||||
var newLine = editor.session.getDocument().getNewLineCharacter();
|
||||
var copyText = "wwww".split("").join(newLine);
|
||||
assert.equal(editor.getCopyText(), copyText);
|
||||
exec("insertstring", 1, "a");
|
||||
exec("backspace", 2);
|
||||
assert.equal(editor.session.getValue(), "w1.w2\ntt\ntt");
|
||||
assert.equal(editor.selection.getAllRanges().length, 4);
|
||||
|
||||
exec("selectall");
|
||||
assert.ok(!editor.inMultiSelectMode);
|
||||
//assert.equal(editor.selection.getAllRanges().length, 1);
|
||||
},
|
||||
|
||||
"test: multiselect navigation": function() {
|
||||
var doc = new EditSession([
|
||||
"w1.w2",
|
||||
" wtt.w",
|
||||
" wtt.we"
|
||||
]);
|
||||
editor = new Editor(new MockRenderer(), doc);
|
||||
MultiSelect(editor);
|
||||
|
||||
editor.selectMoreLines(1);
|
||||
testRanges("Range: [0/0] -> [0/0],Range: [1/0] -> [1/0]");
|
||||
assert.ok(editor.inMultiSelectMode);
|
||||
|
||||
exec("golinedown");
|
||||
exec("gotolineend");
|
||||
testRanges("Range: [1/9] -> [1/9],Range: [2/10] -> [2/10]");
|
||||
exec("selectwordleft");
|
||||
|
||||
testRanges("Range: [1/8] -> [1/9],Range: [2/8] -> [2/10]");
|
||||
exec("golinedown", 2);
|
||||
assert.ok(!editor.inMultiSelectMode);
|
||||
},
|
||||
|
||||
"test: multiselect session change": function() {
|
||||
var doc = new EditSession([
|
||||
"w1.w2",
|
||||
" wtt.w",
|
||||
" wtt.w"
|
||||
]);
|
||||
var editor = new Editor(new MockRenderer(), doc);
|
||||
MultiSelect(editor);
|
||||
|
||||
editor.selectMoreLines(1)
|
||||
assert.equal(
|
||||
editor.selection.getAllRanges()+"",
|
||||
"Range: [0/0] -> [0/0],Range: [1/0] -> [1/0]"
|
||||
);
|
||||
assert.ok(editor.inMultiSelectMode);
|
||||
|
||||
var doc2 = new EditSession(["w1"]);
|
||||
editor.setSession(doc2);
|
||||
assert.ok(!editor.inMultiSelectMode);
|
||||
|
||||
editor.setSession(doc);
|
||||
assert.ok(editor.inMultiSelectMode);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
696
lib/ace/narcissus/definitions.js
Normal file
696
lib/ace/narcissus/definitions.js
Normal file
|
|
@ -0,0 +1,696 @@
|
|||
/* vim: set sw=4 ts=4 et tw=78: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the Narcissus JavaScript engine.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Brendan Eich <brendan@mozilla.org>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2004
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Tom Austin <taustin@ucsc.edu>
|
||||
* Brendan Eich <brendan@mozilla.org>
|
||||
* Shu-Yu Guo <shu@rfrn.org>
|
||||
* Dave Herman <dherman@mozilla.com>
|
||||
* Dimitris Vardoulakis <dimvar@ccs.neu.edu>
|
||||
* Patrick Walton <pcwalton@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
* Narcissus - JS implemented in JS.
|
||||
*
|
||||
* Well-known constants and lookup tables. Many consts are generated from the
|
||||
* tokens table via eval to minimize redundancy, so consumers must be compiled
|
||||
* separately to take advantage of the simple switch-case constant propagation
|
||||
* done by SpiderMonkey.
|
||||
*/
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var tokens = [
|
||||
// End of source.
|
||||
"END",
|
||||
|
||||
// Operators and punctuators. Some pair-wise order matters, e.g. (+, -)
|
||||
// and (UNARY_PLUS, UNARY_MINUS).
|
||||
"\n", ";",
|
||||
",",
|
||||
"=",
|
||||
"?", ":", "CONDITIONAL",
|
||||
"||",
|
||||
"&&",
|
||||
"|",
|
||||
"^",
|
||||
"&",
|
||||
"==", "!=", "===", "!==",
|
||||
"<", "<=", ">=", ">",
|
||||
"<<", ">>", ">>>",
|
||||
"+", "-",
|
||||
"*", "/", "%",
|
||||
"!", "~", "UNARY_PLUS", "UNARY_MINUS",
|
||||
"++", "--",
|
||||
".",
|
||||
"[", "]",
|
||||
"{", "}",
|
||||
"(", ")",
|
||||
|
||||
// Nonterminal tree node type codes.
|
||||
"SCRIPT", "BLOCK", "LABEL", "FOR_IN", "CALL", "NEW_WITH_ARGS", "INDEX",
|
||||
"ARRAY_INIT", "OBJECT_INIT", "PROPERTY_INIT", "GETTER", "SETTER",
|
||||
"GROUP", "LIST", "LET_BLOCK", "ARRAY_COMP", "GENERATOR", "COMP_TAIL",
|
||||
|
||||
// Contextual keywords.
|
||||
"IMPLEMENTS", "INTERFACE", "LET", "MODULE", "PACKAGE", "PRIVATE",
|
||||
"PROTECTED", "PUBLIC", "STATIC", "USE", "YIELD",
|
||||
|
||||
// Terminals.
|
||||
"IDENTIFIER", "NUMBER", "STRING", "REGEXP",
|
||||
|
||||
// Keywords.
|
||||
"break",
|
||||
"case", "catch", "const", "continue",
|
||||
"debugger", "default", "delete", "do",
|
||||
"else", "export",
|
||||
"false", "finally", "for", "function",
|
||||
"if", "import", "in", "instanceof",
|
||||
"new", "null",
|
||||
"return",
|
||||
"switch",
|
||||
"this", "throw", "true", "try", "typeof",
|
||||
"var", "void",
|
||||
"while", "with",
|
||||
];
|
||||
|
||||
var strictKeywords = {
|
||||
__proto__: null,
|
||||
"implements": true,
|
||||
"interface": true,
|
||||
"let": true,
|
||||
//"module": true,
|
||||
"package": true,
|
||||
"private": true,
|
||||
"protected": true,
|
||||
"public": true,
|
||||
"static": true,
|
||||
"use": true,
|
||||
"yield": true
|
||||
};
|
||||
|
||||
var statementStartTokens = [
|
||||
"break",
|
||||
"const", "continue",
|
||||
"debugger", "do",
|
||||
"for",
|
||||
"if",
|
||||
"let",
|
||||
"return",
|
||||
"switch",
|
||||
"throw", "try",
|
||||
"var",
|
||||
"yield",
|
||||
"while", "with",
|
||||
];
|
||||
|
||||
// Whitespace characters (see ECMA-262 7.2)
|
||||
var whitespaceChars = [
|
||||
// normal whitespace:
|
||||
"\u0009", "\u000B", "\u000C", "\u0020", "\u00A0", "\uFEFF",
|
||||
|
||||
// high-Unicode whitespace:
|
||||
"\u1680", "\u180E",
|
||||
"\u2000", "\u2001", "\u2002", "\u2003", "\u2004", "\u2005", "\u2006",
|
||||
"\u2007", "\u2008", "\u2009", "\u200A",
|
||||
"\u202F", "\u205F", "\u3000"
|
||||
];
|
||||
|
||||
var whitespace = {};
|
||||
for (var i = 0; i < whitespaceChars.length; i++) {
|
||||
whitespace[whitespaceChars[i]] = true;
|
||||
}
|
||||
|
||||
// Operator and punctuator mapping from token to tree node type name.
|
||||
// NB: because the lexer doesn't backtrack, all token prefixes must themselves
|
||||
// be valid tokens (e.g. !== is acceptable because its prefixes are the valid
|
||||
// tokens != and !).
|
||||
var opTypeNames = {
|
||||
'\n': "NEWLINE",
|
||||
';': "SEMICOLON",
|
||||
',': "COMMA",
|
||||
'?': "HOOK",
|
||||
':': "COLON",
|
||||
'||': "OR",
|
||||
'&&': "AND",
|
||||
'|': "BITWISE_OR",
|
||||
'^': "BITWISE_XOR",
|
||||
'&': "BITWISE_AND",
|
||||
'===': "STRICT_EQ",
|
||||
'==': "EQ",
|
||||
'=': "ASSIGN",
|
||||
'!==': "STRICT_NE",
|
||||
'!=': "NE",
|
||||
'<<': "LSH",
|
||||
'<=': "LE",
|
||||
'<': "LT",
|
||||
'>>>': "URSH",
|
||||
'>>': "RSH",
|
||||
'>=': "GE",
|
||||
'>': "GT",
|
||||
'++': "INCREMENT",
|
||||
'--': "DECREMENT",
|
||||
'+': "PLUS",
|
||||
'-': "MINUS",
|
||||
'*': "MUL",
|
||||
'/': "DIV",
|
||||
'%': "MOD",
|
||||
'!': "NOT",
|
||||
'~': "BITWISE_NOT",
|
||||
'.': "DOT",
|
||||
'[': "LEFT_BRACKET",
|
||||
']': "RIGHT_BRACKET",
|
||||
'{': "LEFT_CURLY",
|
||||
'}': "RIGHT_CURLY",
|
||||
'(': "LEFT_PAREN",
|
||||
')': "RIGHT_PAREN"
|
||||
};
|
||||
|
||||
// Hash of keyword identifier to tokens index. NB: we must null __proto__ to
|
||||
// avoid toString, etc. namespace pollution.
|
||||
var keywords = {__proto__: null};
|
||||
var mozillaKeywords = {__proto__: null};
|
||||
|
||||
// Define const END, etc., based on the token names. Also map name to index.
|
||||
var tokenIds = {};
|
||||
|
||||
var hostSupportsEvalConst = (function() {
|
||||
try {
|
||||
return eval("(function(s) { eval(s); return x })('const x = true;')");
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
})();
|
||||
|
||||
// Building up a string to be eval'd in different contexts.
|
||||
var consts = hostSupportsEvalConst ? "const " : "var ";
|
||||
for (var i = 0, j = tokens.length; i < j; i++) {
|
||||
if (i > 0)
|
||||
consts += ", ";
|
||||
var t = tokens[i];
|
||||
var name;
|
||||
if (/^[a-z]/.test(t)) {
|
||||
name = t.toUpperCase();
|
||||
if (name === "LET" || name === "YIELD")
|
||||
mozillaKeywords[name] = i;
|
||||
if (strictKeywords[name])
|
||||
strictKeywords[name] = i;
|
||||
keywords[t] = i;
|
||||
} else {
|
||||
name = (/^\W/.test(t) ? opTypeNames[t] : t);
|
||||
}
|
||||
consts += name + " = " + i;
|
||||
tokenIds[name] = i;
|
||||
tokens[t] = i;
|
||||
}
|
||||
consts += ";";
|
||||
|
||||
var isStatementStartCode = {__proto__: null};
|
||||
for (i = 0, j = statementStartTokens.length; i < j; i++)
|
||||
isStatementStartCode[keywords[statementStartTokens[i]]] = true;
|
||||
|
||||
// Map assignment operators to their indexes in the tokens array.
|
||||
var assignOps = ['|', '^', '&', '<<', '>>', '>>>', '+', '-', '*', '/', '%'];
|
||||
|
||||
for (i = 0, j = assignOps.length; i < j; i++) {
|
||||
t = assignOps[i];
|
||||
assignOps[t] = tokens[t];
|
||||
}
|
||||
|
||||
function defineGetter(obj, prop, fn, dontDelete, dontEnum) {
|
||||
Object.defineProperty(obj, prop,
|
||||
{ get: fn, configurable: !dontDelete, enumerable: !dontEnum });
|
||||
}
|
||||
|
||||
function defineGetterSetter(obj, prop, getter, setter, dontDelete, dontEnum) {
|
||||
Object.defineProperty(obj, prop, {
|
||||
get: getter,
|
||||
set: setter,
|
||||
configurable: !dontDelete,
|
||||
enumerable: !dontEnum
|
||||
});
|
||||
}
|
||||
|
||||
function defineMemoGetter(obj, prop, fn, dontDelete, dontEnum) {
|
||||
Object.defineProperty(obj, prop, {
|
||||
get: function() {
|
||||
var val = fn();
|
||||
defineProperty(obj, prop, val, dontDelete, true, dontEnum);
|
||||
return val;
|
||||
},
|
||||
configurable: true,
|
||||
enumerable: !dontEnum
|
||||
});
|
||||
}
|
||||
|
||||
function defineProperty(obj, prop, val, dontDelete, readOnly, dontEnum) {
|
||||
Object.defineProperty(obj, prop,
|
||||
{ value: val, writable: !readOnly, configurable: !dontDelete,
|
||||
enumerable: !dontEnum });
|
||||
}
|
||||
|
||||
// Returns true if fn is a native function. (Note: SpiderMonkey specific.)
|
||||
function isNativeCode(fn) {
|
||||
// Relies on the toString method to identify native code.
|
||||
return ((typeof fn) === "function") && fn.toString().match(/\[native code\]/);
|
||||
}
|
||||
|
||||
var Fpapply = Function.prototype.apply;
|
||||
|
||||
function apply(f, o, a) {
|
||||
return Fpapply.call(f, [o].concat(a));
|
||||
}
|
||||
|
||||
var applyNew;
|
||||
|
||||
// ES5's bind is a simpler way to implement applyNew
|
||||
if (Function.prototype.bind) {
|
||||
applyNew = function applyNew(f, a) {
|
||||
return new (f.bind.apply(f, [,].concat(Array.prototype.slice.call(a))))();
|
||||
};
|
||||
} else {
|
||||
applyNew = function applyNew(f, a) {
|
||||
switch (a.length) {
|
||||
case 0:
|
||||
return new f();
|
||||
case 1:
|
||||
return new f(a[0]);
|
||||
case 2:
|
||||
return new f(a[0], a[1]);
|
||||
case 3:
|
||||
return new f(a[0], a[1], a[2]);
|
||||
default:
|
||||
var argStr = "a[0]";
|
||||
for (var i = 1, n = a.length; i < n; i++)
|
||||
argStr += ",a[" + i + "]";
|
||||
return eval("new f(" + argStr + ")");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function getPropertyDescriptor(obj, name) {
|
||||
while (obj) {
|
||||
if (({}).hasOwnProperty.call(obj, name))
|
||||
return Object.getOwnPropertyDescriptor(obj, name);
|
||||
obj = Object.getPrototypeOf(obj);
|
||||
}
|
||||
}
|
||||
|
||||
function getPropertyNames(obj) {
|
||||
var table = Object.create(null, {});
|
||||
while (obj) {
|
||||
var names = Object.getOwnPropertyNames(obj);
|
||||
for (var i = 0, n = names.length; i < n; i++)
|
||||
table[names[i]] = true;
|
||||
obj = Object.getPrototypeOf(obj);
|
||||
}
|
||||
return Object.keys(table);
|
||||
}
|
||||
|
||||
function getOwnProperties(obj) {
|
||||
var map = {};
|
||||
for (var name in Object.getOwnPropertyNames(obj))
|
||||
map[name] = Object.getOwnPropertyDescriptor(obj, name);
|
||||
return map;
|
||||
}
|
||||
|
||||
function blacklistHandler(target, blacklist) {
|
||||
var mask = Object.create(null, {});
|
||||
var redirect = Dict.create(blacklist).mapObject(function(name) { return mask; });
|
||||
return mixinHandler(redirect, target);
|
||||
}
|
||||
|
||||
function whitelistHandler(target, whitelist) {
|
||||
var catchall = Object.create(null, {});
|
||||
var redirect = Dict.create(whitelist).mapObject(function(name) { return target; });
|
||||
return mixinHandler(redirect, catchall);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mixin proxies break the single-inheritance model of prototypes, so
|
||||
* the handler treats all properties as own-properties:
|
||||
*
|
||||
* X
|
||||
* |
|
||||
* +------------+------------+
|
||||
* | O |
|
||||
* | | |
|
||||
* | O O O |
|
||||
* | | | | |
|
||||
* | O O O O |
|
||||
* | | | | | |
|
||||
* | O O O O O |
|
||||
* | | | | | | |
|
||||
* +-(*)--(w)--(x)--(y)--(z)-+
|
||||
*/
|
||||
|
||||
function mixinHandler(redirect, catchall) {
|
||||
function targetFor(name) {
|
||||
return hasOwn(redirect, name) ? redirect[name] : catchall;
|
||||
}
|
||||
|
||||
function getMuxPropertyDescriptor(name) {
|
||||
var desc = getPropertyDescriptor(targetFor(name), name);
|
||||
if (desc)
|
||||
desc.configurable = true;
|
||||
return desc;
|
||||
}
|
||||
|
||||
function getMuxPropertyNames() {
|
||||
var names1 = Object.getOwnPropertyNames(redirect).filter(function(name) {
|
||||
return name in redirect[name];
|
||||
});
|
||||
var names2 = getPropertyNames(catchall).filter(function(name) {
|
||||
return !hasOwn(redirect, name);
|
||||
});
|
||||
return names1.concat(names2);
|
||||
}
|
||||
|
||||
function enumerateMux() {
|
||||
var result = Object.getOwnPropertyNames(redirect).filter(function(name) {
|
||||
return name in redirect[name];
|
||||
});
|
||||
for (name in catchall) {
|
||||
if (!hasOwn(redirect, name))
|
||||
result.push(name);
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
function hasMux(name) {
|
||||
return name in targetFor(name);
|
||||
}
|
||||
|
||||
return {
|
||||
getOwnPropertyDescriptor: getMuxPropertyDescriptor,
|
||||
getPropertyDescriptor: getMuxPropertyDescriptor,
|
||||
getOwnPropertyNames: getMuxPropertyNames,
|
||||
defineProperty: function(name, desc) {
|
||||
Object.defineProperty(targetFor(name), name, desc);
|
||||
},
|
||||
"delete": function(name) {
|
||||
var target = targetFor(name);
|
||||
return delete target[name];
|
||||
},
|
||||
// FIXME: ha ha ha
|
||||
fix: function() { },
|
||||
has: hasMux,
|
||||
hasOwn: hasMux,
|
||||
get: function(receiver, name) {
|
||||
var target = targetFor(name);
|
||||
return target[name];
|
||||
},
|
||||
set: function(receiver, name, val) {
|
||||
var target = targetFor(name);
|
||||
target[name] = val;
|
||||
return true;
|
||||
},
|
||||
enumerate: enumerateMux,
|
||||
keys: enumerateMux
|
||||
};
|
||||
}
|
||||
|
||||
function makePassthruHandler(obj) {
|
||||
// Handler copied from
|
||||
// http://wiki.ecmascript.org/doku.php?id=harmony:proxies&s=proxy%20object#examplea_no-op_forwarding_proxy
|
||||
return {
|
||||
getOwnPropertyDescriptor: function(name) {
|
||||
var desc = Object.getOwnPropertyDescriptor(obj, name);
|
||||
|
||||
// a trapping proxy's properties must always be configurable
|
||||
desc.configurable = true;
|
||||
return desc;
|
||||
},
|
||||
getPropertyDescriptor: function(name) {
|
||||
var desc = getPropertyDescriptor(obj, name);
|
||||
|
||||
// a trapping proxy's properties must always be configurable
|
||||
desc.configurable = true;
|
||||
return desc;
|
||||
},
|
||||
getOwnPropertyNames: function() {
|
||||
return Object.getOwnPropertyNames(obj);
|
||||
},
|
||||
defineProperty: function(name, desc) {
|
||||
Object.defineProperty(obj, name, desc);
|
||||
},
|
||||
"delete": function(name) { return delete obj[name]; },
|
||||
fix: function() {
|
||||
if (Object.isFrozen(obj)) {
|
||||
return getOwnProperties(obj);
|
||||
}
|
||||
|
||||
// As long as obj is not frozen, the proxy won't allow itself to be fixed.
|
||||
return undefined; // will cause a TypeError to be thrown
|
||||
},
|
||||
|
||||
has: function(name) { return name in obj; },
|
||||
hasOwn: function(name) { return ({}).hasOwnProperty.call(obj, name); },
|
||||
get: function(receiver, name) { return obj[name]; },
|
||||
|
||||
// bad behavior when set fails in non-strict mode
|
||||
set: function(receiver, name, val) { obj[name] = val; return true; },
|
||||
enumerate: function() {
|
||||
var result = [];
|
||||
for (name in obj) { result.push(name); };
|
||||
return result;
|
||||
},
|
||||
keys: function() { return Object.keys(obj); }
|
||||
};
|
||||
}
|
||||
|
||||
var hasOwnProperty = ({}).hasOwnProperty;
|
||||
|
||||
function hasOwn(obj, name) {
|
||||
return hasOwnProperty.call(obj, name);
|
||||
}
|
||||
|
||||
function Dict(table, size) {
|
||||
this.table = table || Object.create(null, {});
|
||||
this.size = size || 0;
|
||||
}
|
||||
|
||||
Dict.create = function(table) {
|
||||
var init = Object.create(null, {});
|
||||
var size = 0;
|
||||
var names = Object.getOwnPropertyNames(table);
|
||||
for (var i = 0, n = names.length; i < n; i++) {
|
||||
var name = names[i];
|
||||
init[name] = table[name];
|
||||
size++;
|
||||
}
|
||||
return new Dict(init, size);
|
||||
};
|
||||
|
||||
Dict.prototype = {
|
||||
has: function(x) { return hasOwnProperty.call(this.table, x); },
|
||||
set: function(x, v) {
|
||||
if (!hasOwnProperty.call(this.table, x))
|
||||
this.size++;
|
||||
this.table[x] = v;
|
||||
},
|
||||
get: function(x) { return this.table[x]; },
|
||||
getDef: function(x, thunk) {
|
||||
if (!hasOwnProperty.call(this.table, x)) {
|
||||
this.size++;
|
||||
this.table[x] = thunk();
|
||||
}
|
||||
return this.table[x];
|
||||
},
|
||||
forEach: function(f) {
|
||||
var table = this.table;
|
||||
for (var key in table)
|
||||
f.call(this, key, table[key]);
|
||||
},
|
||||
map: function(f) {
|
||||
var table1 = this.table;
|
||||
var table2 = Object.create(null, {});
|
||||
this.forEach(function(key, val) {
|
||||
table2[key] = f.call(this, val, key);
|
||||
});
|
||||
return new Dict(table2, this.size);
|
||||
},
|
||||
mapObject: function(f) {
|
||||
var table1 = this.table;
|
||||
var table2 = Object.create(null, {});
|
||||
this.forEach(function(key, val) {
|
||||
table2[key] = f.call(this, val, key);
|
||||
});
|
||||
return table2;
|
||||
},
|
||||
toObject: function() {
|
||||
return this.mapObject(function(val) { return val; });
|
||||
},
|
||||
choose: function() {
|
||||
return Object.getOwnPropertyNames(this.table)[0];
|
||||
},
|
||||
remove: function(x) {
|
||||
if (hasOwnProperty.call(this.table, x)) {
|
||||
this.size--;
|
||||
delete this.table[x];
|
||||
}
|
||||
},
|
||||
copy: function() {
|
||||
var table = Object.create(null, {});
|
||||
for (var key in this.table)
|
||||
table[key] = this.table[key];
|
||||
return new Dict(table, this.size);
|
||||
},
|
||||
keys: function() {
|
||||
return Object.keys(this.table);
|
||||
},
|
||||
toString: function() { return "[object Dict]" }
|
||||
};
|
||||
|
||||
var _WeakMap = typeof WeakMap === "function" ? WeakMap : (function() {
|
||||
// shim for ES6 WeakMap with poor asymptotics
|
||||
function WeakMap(array) {
|
||||
this.array = array || [];
|
||||
}
|
||||
|
||||
function searchMap(map, key, found, notFound) {
|
||||
var a = map.array;
|
||||
for (var i = 0, n = a.length; i < n; i++) {
|
||||
var pair = a[i];
|
||||
if (pair.key === key)
|
||||
return found(pair, i);
|
||||
}
|
||||
return notFound();
|
||||
}
|
||||
|
||||
WeakMap.prototype = {
|
||||
has: function(x) {
|
||||
return searchMap(this, x, function() { return true }, function() { return false });
|
||||
},
|
||||
set: function(x, v) {
|
||||
var a = this.array;
|
||||
searchMap(this, x,
|
||||
function(pair) { pair.value = v },
|
||||
function() { a.push({ key: x, value: v }) });
|
||||
},
|
||||
get: function(x) {
|
||||
return searchMap(this, x,
|
||||
function(pair) { return pair.value },
|
||||
function() { return null });
|
||||
},
|
||||
"delete": function(x) {
|
||||
var a = this.array;
|
||||
searchMap(this, x,
|
||||
function(pair, i) { a.splice(i, 1) },
|
||||
function() { });
|
||||
},
|
||||
toString: function() { return "[object WeakMap]" }
|
||||
};
|
||||
|
||||
return WeakMap;
|
||||
})();
|
||||
|
||||
// non-destructive stack
|
||||
function Stack(elts) {
|
||||
this.elts = elts || null;
|
||||
}
|
||||
|
||||
Stack.prototype = {
|
||||
push: function(x) {
|
||||
return new Stack({ top: x, rest: this.elts });
|
||||
},
|
||||
top: function() {
|
||||
if (!this.elts)
|
||||
throw new Error("empty stack");
|
||||
return this.elts.top;
|
||||
},
|
||||
isEmpty: function() {
|
||||
return this.top === null;
|
||||
},
|
||||
find: function(test) {
|
||||
for (var elts = this.elts; elts; elts = elts.rest) {
|
||||
if (test(elts.top))
|
||||
return elts.top;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
has: function(x) {
|
||||
return Boolean(this.find(function(elt) { return elt === x }));
|
||||
},
|
||||
forEach: function(f) {
|
||||
for (var elts = this.elts; elts; elts = elts.rest) {
|
||||
f(elts.top);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (!Array.prototype.copy) {
|
||||
defineProperty(Array.prototype, "copy",
|
||||
function() {
|
||||
var result = [];
|
||||
for (var i = 0, n = this.length; i < n; i++)
|
||||
result[i] = this[i];
|
||||
return result;
|
||||
}, false, false, true);
|
||||
}
|
||||
|
||||
if (!Array.prototype.top) {
|
||||
defineProperty(Array.prototype, "top",
|
||||
function() {
|
||||
return this.length && this[this.length-1];
|
||||
}, false, false, true);
|
||||
}
|
||||
|
||||
exports.tokens = tokens;
|
||||
exports.whitespace = whitespace;
|
||||
exports.opTypeNames = opTypeNames;
|
||||
exports.keywords = keywords;
|
||||
exports.mozillaKeywords = mozillaKeywords;
|
||||
exports.strictKeywords = strictKeywords;
|
||||
exports.isStatementStartCode = isStatementStartCode;
|
||||
exports.tokenIds = tokenIds;
|
||||
exports.consts = consts;
|
||||
exports.assignOps = assignOps;
|
||||
exports.defineGetter = defineGetter;
|
||||
exports.defineGetterSetter = defineGetterSetter;
|
||||
exports.defineMemoGetter = defineMemoGetter;
|
||||
exports.defineProperty = defineProperty;
|
||||
exports.isNativeCode = isNativeCode;
|
||||
exports.apply = apply;
|
||||
exports.applyNew = applyNew;
|
||||
exports.mixinHandler = mixinHandler;
|
||||
exports.whitelistHandler = whitelistHandler;
|
||||
exports.blacklistHandler = blacklistHandler;
|
||||
exports.makePassthruHandler = makePassthruHandler;
|
||||
exports.Dict = Dict;
|
||||
exports.WeakMap = _WeakMap;
|
||||
exports.Stack = Stack;
|
||||
|
||||
});
|
||||
|
|
@ -1,679 +0,0 @@
|
|||
/* vim: set sw=4 ts=4 et tw=78: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the Narcissus JavaScript engine.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Brendan Eich <brendan@mozilla.org>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2004
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Tom Austin <taustin@ucsc.edu>
|
||||
* Brendan Eich <brendan@mozilla.org>
|
||||
* Shu-Yu Guo <shu@rfrn.org>
|
||||
* Dave Herman <dherman@mozilla.com>
|
||||
* Dimitris Vardoulakis <dimvar@ccs.neu.edu>
|
||||
* Patrick Walton <pcwalton@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
* Narcissus - JS implemented in JS.
|
||||
*
|
||||
* Well-known constants and lookup tables. Many consts are generated from the
|
||||
* tokens table via eval to minimize redundancy, so consumers must be compiled
|
||||
* separately to take advantage of the simple switch-case constant propagation
|
||||
* done by SpiderMonkey.
|
||||
*/
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var narcissus = {
|
||||
options: {
|
||||
version: 185,
|
||||
// Global variables to hide from the interpreter
|
||||
hiddenHostGlobals: { Narcissus: true },
|
||||
// Desugar SpiderMonkey language extensions?
|
||||
desugarExtensions: false
|
||||
},
|
||||
hostSupportsEvalConst: (function() {
|
||||
try {
|
||||
return eval("(function(s) { eval(s); return x })('const x = true;')");
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
})(),
|
||||
hostGlobal: this
|
||||
};
|
||||
Narcissus = narcissus;
|
||||
|
||||
var tokens = [
|
||||
// End of source.
|
||||
"END",
|
||||
|
||||
// Operators and punctuators. Some pair-wise order matters, e.g. (+, -)
|
||||
// and (UNARY_PLUS, UNARY_MINUS).
|
||||
"\n", ";",
|
||||
",",
|
||||
"=",
|
||||
"?", ":", "CONDITIONAL",
|
||||
"||",
|
||||
"&&",
|
||||
"|",
|
||||
"^",
|
||||
"&",
|
||||
"==", "!=", "===", "!==",
|
||||
"<", "<=", ">=", ">",
|
||||
"<<", ">>", ">>>",
|
||||
"+", "-",
|
||||
"*", "/", "%",
|
||||
"!", "~", "UNARY_PLUS", "UNARY_MINUS",
|
||||
"++", "--",
|
||||
".",
|
||||
"[", "]",
|
||||
"{", "}",
|
||||
"(", ")",
|
||||
|
||||
// Nonterminal tree node type codes.
|
||||
"SCRIPT", "BLOCK", "LABEL", "FOR_IN", "CALL", "NEW_WITH_ARGS", "INDEX",
|
||||
"ARRAY_INIT", "OBJECT_INIT", "PROPERTY_INIT", "GETTER", "SETTER",
|
||||
"GROUP", "LIST", "LET_BLOCK", "ARRAY_COMP", "GENERATOR", "COMP_TAIL",
|
||||
|
||||
// Terminals.
|
||||
"IDENTIFIER", "NUMBER", "STRING", "REGEXP",
|
||||
|
||||
// Keywords.
|
||||
"break",
|
||||
"case", "catch", "const", "continue",
|
||||
"debugger", "default", "delete", "do",
|
||||
"else", "export",
|
||||
"false", "finally", "for", "function",
|
||||
"if", "import", "in", "instanceof",
|
||||
"let", "module",
|
||||
"new", "null",
|
||||
"return",
|
||||
"switch",
|
||||
"this", "throw", "true", "try", "typeof",
|
||||
"var", "void",
|
||||
"yield",
|
||||
"while", "with",
|
||||
];
|
||||
|
||||
var statementStartTokens = [
|
||||
"break",
|
||||
"const", "continue",
|
||||
"debugger", "do",
|
||||
"for",
|
||||
"if",
|
||||
"return",
|
||||
"switch",
|
||||
"throw", "try",
|
||||
"var",
|
||||
"yield",
|
||||
"while", "with",
|
||||
];
|
||||
|
||||
// Whitespace characters (see ECMA-262 7.2)
|
||||
var whitespaceChars = [
|
||||
// normal whitespace:
|
||||
"\u0009", "\u000B", "\u000C", "\u0020", "\u00A0", "\uFEFF",
|
||||
|
||||
// high-Unicode whitespace:
|
||||
"\u1680", "\u180E",
|
||||
"\u2000", "\u2001", "\u2002", "\u2003", "\u2004", "\u2005", "\u2006",
|
||||
"\u2007", "\u2008", "\u2009", "\u200A",
|
||||
"\u202F", "\u205F", "\u3000"
|
||||
];
|
||||
|
||||
var whitespace = {};
|
||||
for (var i = 0; i < whitespaceChars.length; i++) {
|
||||
whitespace[whitespaceChars[i]] = true;
|
||||
}
|
||||
|
||||
// Operator and punctuator mapping from token to tree node type name.
|
||||
// NB: because the lexer doesn't backtrack, all token prefixes must themselves
|
||||
// be valid tokens (e.g. !== is acceptable because its prefixes are the valid
|
||||
// tokens != and !).
|
||||
var opTypeNames = {
|
||||
'\n': "NEWLINE",
|
||||
';': "SEMICOLON",
|
||||
',': "COMMA",
|
||||
'?': "HOOK",
|
||||
':': "COLON",
|
||||
'||': "OR",
|
||||
'&&': "AND",
|
||||
'|': "BITWISE_OR",
|
||||
'^': "BITWISE_XOR",
|
||||
'&': "BITWISE_AND",
|
||||
'===': "STRICT_EQ",
|
||||
'==': "EQ",
|
||||
'=': "ASSIGN",
|
||||
'!==': "STRICT_NE",
|
||||
'!=': "NE",
|
||||
'<<': "LSH",
|
||||
'<=': "LE",
|
||||
'<': "LT",
|
||||
'>>>': "URSH",
|
||||
'>>': "RSH",
|
||||
'>=': "GE",
|
||||
'>': "GT",
|
||||
'++': "INCREMENT",
|
||||
'--': "DECREMENT",
|
||||
'+': "PLUS",
|
||||
'-': "MINUS",
|
||||
'*': "MUL",
|
||||
'/': "DIV",
|
||||
'%': "MOD",
|
||||
'!': "NOT",
|
||||
'~': "BITWISE_NOT",
|
||||
'.': "DOT",
|
||||
'[': "LEFT_BRACKET",
|
||||
']': "RIGHT_BRACKET",
|
||||
'{': "LEFT_CURLY",
|
||||
'}': "RIGHT_CURLY",
|
||||
'(': "LEFT_PAREN",
|
||||
')': "RIGHT_PAREN"
|
||||
};
|
||||
|
||||
// Hash of keyword identifier to tokens index. NB: we must null __proto__ to
|
||||
// avoid toString, etc. namespace pollution.
|
||||
var keywords = {__proto__: null};
|
||||
|
||||
// Define const END, etc., based on the token names. Also map name to index.
|
||||
var tokenIds = {};
|
||||
|
||||
// Building up a string to be eval'd in different contexts.
|
||||
var consts = Narcissus.hostSupportsEvalConst ? "const " : "var ";
|
||||
for (var i = 0, j = tokens.length; i < j; i++) {
|
||||
if (i > 0)
|
||||
consts += ", ";
|
||||
var t = tokens[i];
|
||||
var name;
|
||||
if (/^[a-z]/.test(t)) {
|
||||
name = t.toUpperCase();
|
||||
keywords[t] = i;
|
||||
} else {
|
||||
name = (/^\W/.test(t) ? opTypeNames[t] : t);
|
||||
}
|
||||
consts += name + " = " + i;
|
||||
tokenIds[name] = i;
|
||||
tokens[t] = i;
|
||||
}
|
||||
consts += ";";
|
||||
|
||||
var isStatementStartCode = {__proto__: null};
|
||||
for (i = 0, j = statementStartTokens.length; i < j; i++)
|
||||
isStatementStartCode[keywords[statementStartTokens[i]]] = true;
|
||||
|
||||
// Map assignment operators to their indexes in the tokens array.
|
||||
var assignOps = ['|', '^', '&', '<<', '>>', '>>>', '+', '-', '*', '/', '%'];
|
||||
|
||||
for (i = 0, j = assignOps.length; i < j; i++) {
|
||||
t = assignOps[i];
|
||||
assignOps[t] = tokens[t];
|
||||
}
|
||||
|
||||
function defineGetter(obj, prop, fn, dontDelete, dontEnum) {
|
||||
Object.defineProperty(obj, prop,
|
||||
{ get: fn, configurable: !dontDelete, enumerable: !dontEnum });
|
||||
}
|
||||
|
||||
function defineGetterSetter(obj, prop, getter, setter, dontDelete, dontEnum) {
|
||||
Object.defineProperty(obj, prop, {
|
||||
get: getter,
|
||||
set: setter,
|
||||
configurable: !dontDelete,
|
||||
enumerable: !dontEnum
|
||||
});
|
||||
}
|
||||
|
||||
function defineMemoGetter(obj, prop, fn, dontDelete, dontEnum) {
|
||||
Object.defineProperty(obj, prop, {
|
||||
get: function() {
|
||||
var val = fn();
|
||||
defineProperty(obj, prop, val, dontDelete, true, dontEnum);
|
||||
return val;
|
||||
},
|
||||
configurable: true,
|
||||
enumerable: !dontEnum
|
||||
});
|
||||
}
|
||||
|
||||
function defineProperty(obj, prop, val, dontDelete, readOnly, dontEnum) {
|
||||
Object.defineProperty(obj, prop,
|
||||
{ value: val, writable: !readOnly, configurable: !dontDelete,
|
||||
enumerable: !dontEnum });
|
||||
}
|
||||
|
||||
// Returns true if fn is a native function. (Note: SpiderMonkey specific.)
|
||||
function isNativeCode(fn) {
|
||||
// Relies on the toString method to identify native code.
|
||||
return ((typeof fn) === "function") && fn.toString().match(/\[native code\]/);
|
||||
}
|
||||
|
||||
function getPropertyDescriptor(obj, name) {
|
||||
while (obj) {
|
||||
if (({}).hasOwnProperty.call(obj, name))
|
||||
return Object.getOwnPropertyDescriptor(obj, name);
|
||||
obj = Object.getPrototypeOf(obj);
|
||||
}
|
||||
}
|
||||
|
||||
function getPropertyNames(obj) {
|
||||
var table = Object.create(null, {});
|
||||
while (obj) {
|
||||
var names = Object.getOwnPropertyNames(obj);
|
||||
for (var i = 0, n = names.length; i < n; i++)
|
||||
table[names[i]] = true;
|
||||
obj = Object.getPrototypeOf(obj);
|
||||
}
|
||||
return Object.keys(table);
|
||||
}
|
||||
|
||||
function getOwnProperties(obj) {
|
||||
var map = {};
|
||||
for (var name in Object.getOwnPropertyNames(obj))
|
||||
map[name] = Object.getOwnPropertyDescriptor(obj, name);
|
||||
return map;
|
||||
}
|
||||
|
||||
function blacklistHandler(target, blacklist) {
|
||||
var mask = Object.create(null, {});
|
||||
var redirect = StringMap.create(blacklist).mapObject(function(name) { return mask; });
|
||||
return mixinHandler(redirect, target);
|
||||
}
|
||||
|
||||
function whitelistHandler(target, whitelist) {
|
||||
var catchall = Object.create(null, {});
|
||||
var redirect = StringMap.create(whitelist).mapObject(function(name) { return target; });
|
||||
return mixinHandler(redirect, catchall);
|
||||
}
|
||||
|
||||
function mirrorHandler(target, writable) {
|
||||
var handler = makePassthruHandler(target);
|
||||
|
||||
var defineProperty = handler.defineProperty;
|
||||
handler.defineProperty = function(name, desc) {
|
||||
if (!desc.enumerable)
|
||||
throw new Error("mirror property must be enumerable");
|
||||
if (!desc.configurable)
|
||||
throw new Error("mirror property must be configurable");
|
||||
if (desc.writable !== writable)
|
||||
throw new Error("mirror property must " + (writable ? "" : "not ") + "be writable");
|
||||
defineProperty(name, desc);
|
||||
};
|
||||
|
||||
handler.fix = function() { };
|
||||
handler.getOwnPropertyDescriptor = handler.getPropertyDescriptor;
|
||||
handler.getOwnPropertyNames = getPropertyNames.bind(handler, target);
|
||||
handler.keys = handler.enumerate;
|
||||
handler["delete"] = function() { return false; };
|
||||
handler.hasOwn = handler.has;
|
||||
return handler;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mixin proxies break the single-inheritance model of prototypes, so
|
||||
* the handler treats all properties as own-properties:
|
||||
*
|
||||
* X
|
||||
* |
|
||||
* +------------+------------+
|
||||
* | O |
|
||||
* | | |
|
||||
* | O O O |
|
||||
* | | | | |
|
||||
* | O O O O |
|
||||
* | | | | | |
|
||||
* | O O O O O |
|
||||
* | | | | | | |
|
||||
* +-(*)--(w)--(x)--(y)--(z)-+
|
||||
*/
|
||||
|
||||
function mixinHandler(redirect, catchall) {
|
||||
function targetFor(name) {
|
||||
return hasOwn(redirect, name) ? redirect[name] : catchall;
|
||||
}
|
||||
|
||||
function getMuxPropertyDescriptor(name) {
|
||||
var desc = getPropertyDescriptor(targetFor(name), name);
|
||||
if (desc)
|
||||
desc.configurable = true;
|
||||
return desc;
|
||||
}
|
||||
|
||||
function getMuxPropertyNames() {
|
||||
var names1 = Object.getOwnPropertyNames(redirect).filter(function(name) {
|
||||
return name in redirect[name];
|
||||
});
|
||||
var names2 = getPropertyNames(catchall).filter(function(name) {
|
||||
return !hasOwn(redirect, name);
|
||||
});
|
||||
return names1.concat(names2);
|
||||
}
|
||||
|
||||
function enumerateMux() {
|
||||
var result = Object.getOwnPropertyNames(redirect).filter(function(name) {
|
||||
return name in redirect[name];
|
||||
});
|
||||
for (name in catchall) {
|
||||
if (!hasOwn(redirect, name))
|
||||
result.push(name);
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
function hasMux(name) {
|
||||
return name in targetFor(name);
|
||||
}
|
||||
|
||||
return {
|
||||
getOwnPropertyDescriptor: getMuxPropertyDescriptor,
|
||||
getPropertyDescriptor: getMuxPropertyDescriptor,
|
||||
getOwnPropertyNames: getMuxPropertyNames,
|
||||
defineProperty: function(name, desc) {
|
||||
Object.defineProperty(targetFor(name), name, desc);
|
||||
},
|
||||
"delete": function(name) {
|
||||
var target = targetFor(name);
|
||||
return delete target[name];
|
||||
},
|
||||
// FIXME: ha ha ha
|
||||
fix: function() { },
|
||||
has: hasMux,
|
||||
hasOwn: hasMux,
|
||||
get: function(receiver, name) {
|
||||
var target = targetFor(name);
|
||||
return target[name];
|
||||
},
|
||||
set: function(receiver, name, val) {
|
||||
var target = targetFor(name);
|
||||
target[name] = val;
|
||||
return true;
|
||||
},
|
||||
enumerate: enumerateMux,
|
||||
keys: enumerateMux
|
||||
};
|
||||
}
|
||||
|
||||
function makePassthruHandler(obj) {
|
||||
// Handler copied from
|
||||
// http://wiki.ecmascript.org/doku.php?id=harmony:proxies&s=proxy%20object#examplea_no-op_forwarding_proxy
|
||||
return {
|
||||
getOwnPropertyDescriptor: function(name) {
|
||||
var desc = Object.getOwnPropertyDescriptor(obj, name);
|
||||
|
||||
// a trapping proxy's properties must always be configurable
|
||||
desc.configurable = true;
|
||||
return desc;
|
||||
},
|
||||
getPropertyDescriptor: function(name) {
|
||||
var desc = getPropertyDescriptor(obj, name);
|
||||
|
||||
// a trapping proxy's properties must always be configurable
|
||||
desc.configurable = true;
|
||||
return desc;
|
||||
},
|
||||
getOwnPropertyNames: function() {
|
||||
return Object.getOwnPropertyNames(obj);
|
||||
},
|
||||
defineProperty: function(name, desc) {
|
||||
Object.defineProperty(obj, name, desc);
|
||||
},
|
||||
"delete": function(name) { return delete obj[name]; },
|
||||
fix: function() {
|
||||
if (Object.isFrozen(obj)) {
|
||||
return getOwnProperties(obj);
|
||||
}
|
||||
|
||||
// As long as obj is not frozen, the proxy won't allow itself to be fixed.
|
||||
return undefined; // will cause a TypeError to be thrown
|
||||
},
|
||||
|
||||
has: function(name) { return name in obj; },
|
||||
hasOwn: function(name) { return ({}).hasOwnProperty.call(obj, name); },
|
||||
get: function(receiver, name) { return obj[name]; },
|
||||
|
||||
// bad behavior when set fails in non-strict mode
|
||||
set: function(receiver, name, val) { obj[name] = val; return true; },
|
||||
enumerate: function() {
|
||||
var result = [];
|
||||
for (name in obj) { result.push(name); };
|
||||
return result;
|
||||
},
|
||||
keys: function() { return Object.keys(obj); }
|
||||
};
|
||||
}
|
||||
|
||||
var hasOwnProperty = ({}).hasOwnProperty;
|
||||
|
||||
function hasOwn(obj, name) {
|
||||
return hasOwnProperty.call(obj, name);
|
||||
}
|
||||
|
||||
function StringMap(table, size) {
|
||||
this.table = table || Object.create(null, {});
|
||||
this.size = size || 0;
|
||||
}
|
||||
|
||||
StringMap.create = function(table) {
|
||||
var init = Object.create(null, {});
|
||||
var size = 0;
|
||||
var names = Object.getOwnPropertyNames(table);
|
||||
for (var i = 0, n = names.length; i < n; i++) {
|
||||
var name = names[i];
|
||||
init[name] = table[name];
|
||||
size++;
|
||||
}
|
||||
return new StringMap(init, size);
|
||||
};
|
||||
|
||||
StringMap.prototype = {
|
||||
has: function(x) { return hasOwnProperty.call(this.table, x); },
|
||||
set: function(x, v) {
|
||||
if (!hasOwnProperty.call(this.table, x))
|
||||
this.size++;
|
||||
this.table[x] = v;
|
||||
},
|
||||
get: function(x) { return this.table[x]; },
|
||||
getDef: function(x, thunk) {
|
||||
if (!hasOwnProperty.call(this.table, x)) {
|
||||
this.size++;
|
||||
this.table[x] = thunk();
|
||||
}
|
||||
return this.table[x];
|
||||
},
|
||||
forEach: function(f) {
|
||||
var table = this.table;
|
||||
for (var key in table)
|
||||
f.call(this, key, table[key]);
|
||||
},
|
||||
map: function(f) {
|
||||
var table1 = this.table;
|
||||
var table2 = Object.create(null, {});
|
||||
this.forEach(function(key, val) {
|
||||
table2[key] = f.call(this, val, key);
|
||||
});
|
||||
return new StringMap(table2, this.size);
|
||||
},
|
||||
mapObject: function(f) {
|
||||
var table1 = this.table;
|
||||
var table2 = Object.create(null, {});
|
||||
this.forEach(function(key, val) {
|
||||
table2[key] = f.call(this, val, key);
|
||||
});
|
||||
return table2;
|
||||
},
|
||||
toObject: function() {
|
||||
return this.mapObject(function(val) { return val; });
|
||||
},
|
||||
choose: function() {
|
||||
return Object.getOwnPropertyNames(this.table)[0];
|
||||
},
|
||||
remove: function(x) {
|
||||
if (hasOwnProperty.call(this.table, x)) {
|
||||
this.size--;
|
||||
delete this.table[x];
|
||||
}
|
||||
},
|
||||
copy: function() {
|
||||
var table = Object.create(null, {});
|
||||
for (var key in this.table)
|
||||
table[key] = this.table[key];
|
||||
return new StringMap(table, this.size);
|
||||
},
|
||||
toString: function() { return "[object StringMap]" }
|
||||
};
|
||||
|
||||
// an object-key table with poor asymptotics (replace with WeakMap when possible)
|
||||
function ObjectMap(array) {
|
||||
this.array = array || [];
|
||||
}
|
||||
|
||||
function searchMap(map, key, found, notFound) {
|
||||
var a = map.array;
|
||||
for (var i = 0, n = a.length; i < n; i++) {
|
||||
var pair = a[i];
|
||||
if (pair.key === key)
|
||||
return found(pair, i);
|
||||
}
|
||||
return notFound();
|
||||
}
|
||||
|
||||
ObjectMap.prototype = {
|
||||
has: function(x) {
|
||||
return searchMap(this, x, function() { return true }, function() { return false });
|
||||
},
|
||||
set: function(x, v) {
|
||||
var a = this.array;
|
||||
searchMap(this, x,
|
||||
function(pair) { pair.value = v },
|
||||
function() { a.push({ key: x, value: v }) });
|
||||
},
|
||||
get: function(x) {
|
||||
return searchMap(this, x,
|
||||
function(pair) { return pair.value },
|
||||
function() { return null });
|
||||
},
|
||||
getDef: function(x, thunk) {
|
||||
var a = this.array;
|
||||
return searchMap(this, x,
|
||||
function(pair) { return pair.value },
|
||||
function() {
|
||||
var v = thunk();
|
||||
a.push({ key: x, value: v });
|
||||
return v;
|
||||
});
|
||||
},
|
||||
forEach: function(f) {
|
||||
var a = this.array;
|
||||
for (var i = 0, n = a.length; i < n; i++) {
|
||||
var pair = a[i];
|
||||
f.call(this, pair.key, pair.value);
|
||||
}
|
||||
},
|
||||
choose: function() {
|
||||
return this.array[0].key;
|
||||
},
|
||||
get size() {
|
||||
return this.array.length;
|
||||
},
|
||||
remove: function(x) {
|
||||
var a = this.array;
|
||||
searchMap(this, x,
|
||||
function(pair, i) { a.splice(i, 1) },
|
||||
function() { });
|
||||
},
|
||||
copy: function() {
|
||||
return new ObjectMap(this.array.map(function(pair) {
|
||||
return { key: pair.key, value: pair.value }
|
||||
}));
|
||||
},
|
||||
clear: function() {
|
||||
this.array = [];
|
||||
},
|
||||
toString: function() { return "[object ObjectMap]" }
|
||||
};
|
||||
|
||||
// non-destructive stack
|
||||
function Stack(elts) {
|
||||
this.elts = elts || null;
|
||||
}
|
||||
|
||||
Stack.prototype = {
|
||||
push: function(x) {
|
||||
return new Stack({ top: x, rest: this.elts });
|
||||
},
|
||||
top: function() {
|
||||
if (!this.elts)
|
||||
throw new Error("empty stack");
|
||||
return this.elts.top;
|
||||
},
|
||||
isEmpty: function() {
|
||||
return this.top === null;
|
||||
},
|
||||
find: function(test) {
|
||||
for (var elts = this.elts; elts; elts = elts.rest) {
|
||||
if (test(elts.top))
|
||||
return elts.top;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
has: function(x) {
|
||||
return Boolean(this.find(function(elt) { return elt === x }));
|
||||
},
|
||||
forEach: function(f) {
|
||||
for (var elts = this.elts; elts; elts = elts.rest) {
|
||||
f(elts.top);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
tokens: tokens,
|
||||
whitespace: whitespace,
|
||||
opTypeNames: opTypeNames,
|
||||
keywords: keywords,
|
||||
isStatementStartCode: isStatementStartCode,
|
||||
tokenIds: tokenIds,
|
||||
consts: consts,
|
||||
assignOps: assignOps,
|
||||
defineGetter: defineGetter,
|
||||
defineGetterSetter: defineGetterSetter,
|
||||
defineMemoGetter: defineMemoGetter,
|
||||
defineProperty: defineProperty,
|
||||
isNativeCode: isNativeCode,
|
||||
mirrorHandler: mirrorHandler,
|
||||
mixinHandler: mixinHandler,
|
||||
whitelistHandler: whitelistHandler,
|
||||
blacklistHandler: blacklistHandler,
|
||||
makePassthruHandler: makePassthruHandler,
|
||||
StringMap: StringMap,
|
||||
ObjectMap: ObjectMap,
|
||||
Stack: Stack
|
||||
};
|
||||
});
|
||||
|
|
@ -1,549 +0,0 @@
|
|||
/* vim: set sw=4 ts=4 et tw=78: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the Narcissus JavaScript engine.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Brendan Eich <brendan@mozilla.org>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2004
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Tom Austin <taustin@ucsc.edu>
|
||||
* Brendan Eich <brendan@mozilla.org>
|
||||
* Shu-Yu Guo <shu@rfrn.org>
|
||||
* Dave Herman <dherman@mozilla.com>
|
||||
* Dimitris Vardoulakis <dimvar@ccs.neu.edu>
|
||||
* Patrick Walton <pcwalton@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
* Narcissus - JS implemented in JS.
|
||||
*
|
||||
* Lexical scanner.
|
||||
*/
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var definitions = require("./jsdefs");
|
||||
|
||||
// Set constants in the local scope.
|
||||
eval(definitions.consts);
|
||||
|
||||
// Banned keywords by language version
|
||||
const blackLists = { 160: {}, 185: {}, harmony: {} };
|
||||
blackLists[160][LET] = true;
|
||||
blackLists[160][MODULE] = true;
|
||||
blackLists[160][YIELD] = true;
|
||||
blackLists[185][MODULE] = true;
|
||||
|
||||
// Build up a trie of operator tokens.
|
||||
var opTokens = {};
|
||||
for (var op in definitions.opTypeNames) {
|
||||
if (op === '\n' || op === '.')
|
||||
continue;
|
||||
|
||||
var node = opTokens;
|
||||
for (var i = 0; i < op.length; i++) {
|
||||
var ch = op[i];
|
||||
if (!(ch in node))
|
||||
node[ch] = {};
|
||||
node = node[ch];
|
||||
node.op = op;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Tokenizer :: (source, filename, line number) -> Tokenizer
|
||||
*/
|
||||
function Tokenizer(s, f, l) {
|
||||
this.cursor = 0;
|
||||
this.source = String(s);
|
||||
this.tokens = [];
|
||||
this.tokenIndex = 0;
|
||||
this.lookahead = 0;
|
||||
this.scanNewlines = false;
|
||||
this.unexpectedEOF = false;
|
||||
this.filename = f || "";
|
||||
this.lineno = l || 1;
|
||||
this.blackList = blackLists[Narcissus.options.version];
|
||||
this.blockComments = null;
|
||||
}
|
||||
|
||||
Tokenizer.prototype = {
|
||||
get done() {
|
||||
// We need to set scanOperand to true here because the first thing
|
||||
// might be a regexp.
|
||||
return this.peek(true) === END;
|
||||
},
|
||||
|
||||
get token() {
|
||||
return this.tokens[this.tokenIndex];
|
||||
},
|
||||
|
||||
match: function (tt, scanOperand) {
|
||||
return this.get(scanOperand) === tt || this.unget();
|
||||
},
|
||||
|
||||
mustMatch: function (tt) {
|
||||
if (!this.match(tt)) {
|
||||
throw this.newSyntaxError("Missing " +
|
||||
definitions.tokens[tt].toLowerCase());
|
||||
}
|
||||
return this.token;
|
||||
},
|
||||
|
||||
peek: function (scanOperand) {
|
||||
var tt, next;
|
||||
if (this.lookahead) {
|
||||
next = this.tokens[(this.tokenIndex + this.lookahead) & 3];
|
||||
tt = (this.scanNewlines && next.lineno !== this.lineno)
|
||||
? NEWLINE
|
||||
: next.type;
|
||||
} else {
|
||||
tt = this.get(scanOperand);
|
||||
this.unget();
|
||||
}
|
||||
return tt;
|
||||
},
|
||||
|
||||
peekOnSameLine: function (scanOperand) {
|
||||
this.scanNewlines = true;
|
||||
var tt = this.peek(scanOperand);
|
||||
this.scanNewlines = false;
|
||||
return tt;
|
||||
},
|
||||
|
||||
lastBlockComment: function() {
|
||||
var length = this.blockComments.length;
|
||||
return length ? this.blockComments[length - 1] : null;
|
||||
},
|
||||
|
||||
// Eat comments and whitespace.
|
||||
skip: function () {
|
||||
var input = this.source;
|
||||
this.blockComments = [];
|
||||
for (;;) {
|
||||
var ch = input[this.cursor++];
|
||||
var next = input[this.cursor];
|
||||
// handle \r, \r\n and (always preferable) \n
|
||||
if (ch === '\r') {
|
||||
// if the next character is \n, we don't care about this at all
|
||||
if (next === '\n') continue;
|
||||
|
||||
// otherwise, we want to consider this as a newline
|
||||
ch = '\n';
|
||||
}
|
||||
|
||||
if (ch === '\n' && !this.scanNewlines) {
|
||||
this.lineno++;
|
||||
} else if (ch === '/' && next === '*') {
|
||||
var commentStart = ++this.cursor;
|
||||
for (;;) {
|
||||
ch = input[this.cursor++];
|
||||
if (ch === undefined)
|
||||
throw this.newSyntaxError("Unterminated comment");
|
||||
|
||||
if (ch === '*') {
|
||||
next = input[this.cursor];
|
||||
if (next === '/') {
|
||||
var commentEnd = this.cursor - 1;
|
||||
this.cursor++;
|
||||
break;
|
||||
}
|
||||
} else if (ch === '\n') {
|
||||
this.lineno++;
|
||||
}
|
||||
}
|
||||
this.blockComments.push(input.substring(commentStart, commentEnd));
|
||||
} else if (ch === '/' && next === '/') {
|
||||
this.cursor++;
|
||||
for (;;) {
|
||||
ch = input[this.cursor++];
|
||||
next = input[this.cursor];
|
||||
if (ch === undefined)
|
||||
return;
|
||||
|
||||
if (ch === '\r') {
|
||||
// check for \r\n
|
||||
if (next !== '\n') ch = '\n';
|
||||
}
|
||||
|
||||
if (ch === '\n') {
|
||||
if (this.scanNewlines) {
|
||||
this.cursor--;
|
||||
} else {
|
||||
this.lineno++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (!(ch in definitions.whitespace)) {
|
||||
this.cursor--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Lex the exponential part of a number, if present. Return true iff an
|
||||
// exponential part was found.
|
||||
lexExponent: function() {
|
||||
var input = this.source;
|
||||
var next = input[this.cursor];
|
||||
if (next === 'e' || next === 'E') {
|
||||
this.cursor++;
|
||||
ch = input[this.cursor++];
|
||||
if (ch === '+' || ch === '-')
|
||||
ch = input[this.cursor++];
|
||||
|
||||
if (ch < '0' || ch > '9')
|
||||
throw this.newSyntaxError("Missing exponent");
|
||||
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
} while (ch >= '0' && ch <= '9');
|
||||
this.cursor--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
lexZeroNumber: function (ch) {
|
||||
var token = this.token, input = this.source;
|
||||
token.type = NUMBER;
|
||||
|
||||
ch = input[this.cursor++];
|
||||
if (ch === '.') {
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
} while (ch >= '0' && ch <= '9');
|
||||
this.cursor--;
|
||||
|
||||
this.lexExponent();
|
||||
token.value = parseFloat(token.start, this.cursor);
|
||||
} else if (ch === 'x' || ch === 'X') {
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
} while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') ||
|
||||
(ch >= 'A' && ch <= 'F'));
|
||||
this.cursor--;
|
||||
|
||||
token.value = parseInt(input.substring(token.start, this.cursor));
|
||||
} else if (ch >= '0' && ch <= '7') {
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
} while (ch >= '0' && ch <= '7');
|
||||
this.cursor--;
|
||||
|
||||
token.value = parseInt(input.substring(token.start, this.cursor));
|
||||
} else {
|
||||
this.cursor--;
|
||||
this.lexExponent(); // 0E1, &c.
|
||||
token.value = 0;
|
||||
}
|
||||
},
|
||||
|
||||
lexNumber: function (ch) {
|
||||
var token = this.token, input = this.source;
|
||||
token.type = NUMBER;
|
||||
|
||||
var floating = false;
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
if (ch === '.' && !floating) {
|
||||
floating = true;
|
||||
ch = input[this.cursor++];
|
||||
}
|
||||
} while (ch >= '0' && ch <= '9');
|
||||
|
||||
this.cursor--;
|
||||
|
||||
var exponent = this.lexExponent();
|
||||
floating = floating || exponent;
|
||||
|
||||
var str = input.substring(token.start, this.cursor);
|
||||
token.value = floating ? parseFloat(str) : parseInt(str);
|
||||
},
|
||||
|
||||
lexDot: function (ch) {
|
||||
var token = this.token, input = this.source;
|
||||
var next = input[this.cursor];
|
||||
if (next >= '0' && next <= '9') {
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
} while (ch >= '0' && ch <= '9');
|
||||
this.cursor--;
|
||||
|
||||
this.lexExponent();
|
||||
|
||||
token.type = NUMBER;
|
||||
token.value = parseFloat(token.start, this.cursor);
|
||||
} else {
|
||||
token.type = DOT;
|
||||
token.assignOp = null;
|
||||
token.value = '.';
|
||||
}
|
||||
},
|
||||
|
||||
lexString: function (ch) {
|
||||
var token = this.token, input = this.source;
|
||||
token.type = STRING;
|
||||
|
||||
var hasEscapes = false;
|
||||
var delim = ch;
|
||||
if (input.length <= this.cursor)
|
||||
throw this.newSyntaxError("Unterminated string literal");
|
||||
while ((ch = input[this.cursor++]) !== delim) {
|
||||
if (this.cursor == input.length)
|
||||
throw this.newSyntaxError("Unterminated string literal");
|
||||
if (ch === '\\') {
|
||||
hasEscapes = true;
|
||||
if (++this.cursor == input.length)
|
||||
throw this.newSyntaxError("Unterminated string literal");
|
||||
}
|
||||
}
|
||||
|
||||
token.value = hasEscapes
|
||||
? eval(input.substring(token.start, this.cursor))
|
||||
: input.substring(token.start + 1, this.cursor - 1);
|
||||
},
|
||||
|
||||
lexRegExp: function (ch) {
|
||||
var token = this.token, input = this.source;
|
||||
token.type = REGEXP;
|
||||
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
if (ch === '\\') {
|
||||
this.cursor++;
|
||||
} else if (ch === '[') {
|
||||
do {
|
||||
if (ch === undefined)
|
||||
throw this.newSyntaxError("Unterminated character class");
|
||||
|
||||
if (ch === '\\')
|
||||
this.cursor++;
|
||||
|
||||
ch = input[this.cursor++];
|
||||
} while (ch !== ']');
|
||||
} else if (ch === undefined) {
|
||||
throw this.newSyntaxError("Unterminated regex");
|
||||
}
|
||||
} while (ch !== '/');
|
||||
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
} while (ch >= 'a' && ch <= 'z');
|
||||
|
||||
this.cursor--;
|
||||
|
||||
token.value = eval(input.substring(token.start, this.cursor));
|
||||
},
|
||||
|
||||
lexOp: function (ch) {
|
||||
var token = this.token, input = this.source;
|
||||
|
||||
// A bit ugly, but it seems wasteful to write a trie lookup routine
|
||||
// for only 3 characters...
|
||||
var node = opTokens[ch];
|
||||
var next = input[this.cursor];
|
||||
if (next in node) {
|
||||
node = node[next];
|
||||
this.cursor++;
|
||||
next = input[this.cursor];
|
||||
if (next in node) {
|
||||
node = node[next];
|
||||
this.cursor++;
|
||||
next = input[this.cursor];
|
||||
}
|
||||
}
|
||||
|
||||
var op = node.op;
|
||||
if (definitions.assignOps[op] && input[this.cursor] === '=') {
|
||||
this.cursor++;
|
||||
token.type = ASSIGN;
|
||||
token.assignOp = definitions.tokenIds[definitions.opTypeNames[op]];
|
||||
op += '=';
|
||||
} else {
|
||||
token.type = definitions.tokenIds[definitions.opTypeNames[op]];
|
||||
token.assignOp = null;
|
||||
}
|
||||
|
||||
token.value = op;
|
||||
},
|
||||
|
||||
// FIXME: Unicode escape sequences
|
||||
lexIdent: function (ch) {
|
||||
var token = this.token;
|
||||
var id = ch;
|
||||
|
||||
while ((ch = this.getValidIdentifierChar(false)) !== null) {
|
||||
id += ch;
|
||||
}
|
||||
|
||||
token.type = definitions.keywords[id] || IDENTIFIER;
|
||||
if (token.type in this.blackList) {
|
||||
// banned keyword, this is an identifier
|
||||
token.type = IDENTIFIER;
|
||||
}
|
||||
token.value = id;
|
||||
},
|
||||
|
||||
/*
|
||||
* Tokenizer.get :: void -> token type
|
||||
*
|
||||
* Consume input *only* if there is no lookahead.
|
||||
* Dispatch to the appropriate lexing function depending on the input.
|
||||
*/
|
||||
get: function (scanOperand) {
|
||||
var token;
|
||||
while (this.lookahead) {
|
||||
--this.lookahead;
|
||||
this.tokenIndex = (this.tokenIndex + 1) & 3;
|
||||
token = this.tokens[this.tokenIndex];
|
||||
if (token.type !== NEWLINE || this.scanNewlines)
|
||||
return token.type;
|
||||
}
|
||||
|
||||
this.skip();
|
||||
|
||||
this.tokenIndex = (this.tokenIndex + 1) & 3;
|
||||
token = this.tokens[this.tokenIndex];
|
||||
if (!token)
|
||||
this.tokens[this.tokenIndex] = token = {};
|
||||
|
||||
var input = this.source;
|
||||
if (this.cursor >= input.length)
|
||||
return token.type = END;
|
||||
|
||||
token.start = this.cursor;
|
||||
token.lineno = this.lineno;
|
||||
|
||||
var ich = this.getValidIdentifierChar(true);
|
||||
var ch = (ich === null) ? input[this.cursor++] : null;
|
||||
if (ich !== null) {
|
||||
this.lexIdent(ich);
|
||||
} else if (scanOperand && ch === '/') {
|
||||
this.lexRegExp(ch);
|
||||
} else if (ch in opTokens) {
|
||||
this.lexOp(ch);
|
||||
} else if (ch === '.') {
|
||||
this.lexDot(ch);
|
||||
} else if (ch >= '1' && ch <= '9') {
|
||||
this.lexNumber(ch);
|
||||
} else if (ch === '0') {
|
||||
this.lexZeroNumber(ch);
|
||||
} else if (ch === '"' || ch === "'") {
|
||||
this.lexString(ch);
|
||||
} else if (this.scanNewlines && (ch === '\n' || ch === '\r')) {
|
||||
// if this was a \r, look for \r\n
|
||||
if (ch === '\r' && input[this.cursor] === '\n') this.cursor++;
|
||||
token.type = NEWLINE;
|
||||
token.value = '\n';
|
||||
this.lineno++;
|
||||
} else {
|
||||
throw this.newSyntaxError("Illegal token");
|
||||
}
|
||||
|
||||
token.end = this.cursor;
|
||||
return token.type;
|
||||
},
|
||||
|
||||
/*
|
||||
* Tokenizer.unget :: void -> undefined
|
||||
*
|
||||
* Match depends on unget returning undefined.
|
||||
*/
|
||||
unget: function () {
|
||||
if (++this.lookahead === 4) throw "PANIC: too much lookahead!";
|
||||
this.tokenIndex = (this.tokenIndex - 1) & 3;
|
||||
},
|
||||
|
||||
newSyntaxError: function (m) {
|
||||
m = (this.filename ? this.filename + ":" : "") + this.lineno + ": " + m;
|
||||
var e = new SyntaxError(m, this.filename, this.lineno);
|
||||
e.source = this.source;
|
||||
e.cursor = this.lookahead
|
||||
? this.tokens[(this.tokenIndex + this.lookahead) & 3].start
|
||||
: this.cursor;
|
||||
return e;
|
||||
},
|
||||
|
||||
/* Gets a single valid identifier char from the input stream, or null
|
||||
* if there is none.
|
||||
* Since JavaScript provides no convenient way to determine if a
|
||||
* character is in a particular Unicode category, we use
|
||||
* metacircularity to accomplish this (oh yeaaaah!) */
|
||||
getValidIdentifierChar: function(first) {
|
||||
var input = this.source;
|
||||
if (this.cursor >= input.length) return null;
|
||||
var ch = input[this.cursor];
|
||||
|
||||
// first check for \u escapes
|
||||
if (ch === '\\' && input[this.cursor+1] === 'u') {
|
||||
// get the character value
|
||||
try {
|
||||
ch = String.fromCharCode(parseInt(
|
||||
input.substring(this.cursor + 2, this.cursor + 6),
|
||||
16));
|
||||
} catch (ex) {
|
||||
return null;
|
||||
}
|
||||
this.cursor += 5;
|
||||
}
|
||||
|
||||
// check directly for ASCII
|
||||
if (ch <= "\u007F") {
|
||||
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch === '$' || ch === '_' ||
|
||||
(!first && (ch >= '0' && ch <= '9'))) {
|
||||
this.cursor++;
|
||||
return ch;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// create an object to test this in
|
||||
var x = {};
|
||||
x["x"+ch] = true;
|
||||
x[ch] = true;
|
||||
|
||||
// then use eval to determine if it's a valid character
|
||||
var valid = false;
|
||||
try {
|
||||
valid = (Function("x", "return (x." + (first?"":"x") + ch + ");")(x) === true);
|
||||
} catch (ex) {}
|
||||
if (valid) this.cursor++;
|
||||
return (valid ? ch : null);
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
module.exports = { Tokenizer: Tokenizer };
|
||||
|
||||
});
|
||||
File diff suppressed because it is too large
Load diff
598
lib/ace/narcissus/lexer.js
Normal file
598
lib/ace/narcissus/lexer.js
Normal file
|
|
@ -0,0 +1,598 @@
|
|||
/* vim: set sw=4 ts=4 et tw=78: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the Narcissus JavaScript engine.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Brendan Eich <brendan@mozilla.org>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2004
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Tom Austin <taustin@ucsc.edu>
|
||||
* Brendan Eich <brendan@mozilla.org>
|
||||
* Shu-Yu Guo <shu@rfrn.org>
|
||||
* Stephan Herhut <stephan.a.herhut@intel.com>
|
||||
* Dave Herman <dherman@mozilla.com>
|
||||
* Dimitris Vardoulakis <dimvar@ccs.neu.edu>
|
||||
* Patrick Walton <pcwalton@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
* Narcissus - JS implemented in JS.
|
||||
*
|
||||
* Lexical scanner.
|
||||
*/
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var definitions = require('./definitions');
|
||||
|
||||
// Set constants in the local scope.
|
||||
eval(definitions.consts);
|
||||
|
||||
// Build up a trie of operator tokens.
|
||||
var opTokens = {};
|
||||
for (var op in definitions.opTypeNames) {
|
||||
if (op === '\n' || op === '.')
|
||||
continue;
|
||||
|
||||
var node = opTokens;
|
||||
for (var i = 0; i < op.length; i++) {
|
||||
var ch = op[i];
|
||||
if (!(ch in node))
|
||||
node[ch] = {};
|
||||
node = node[ch];
|
||||
node.op = op;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Since JavaScript provides no convenient way to determine if a
|
||||
* character is in a particular Unicode category, we use
|
||||
* metacircularity to accomplish this (oh yeaaaah!)
|
||||
*/
|
||||
function isValidIdentifierChar(ch, first) {
|
||||
// check directly for ASCII
|
||||
if (ch <= "\u007F") {
|
||||
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch === '$' || ch === '_' ||
|
||||
(!first && (ch >= '0' && ch <= '9'))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// create an object to test this in
|
||||
var x = {};
|
||||
x["x"+ch] = true;
|
||||
x[ch] = true;
|
||||
|
||||
// then use eval to determine if it's a valid character
|
||||
var valid = false;
|
||||
try {
|
||||
valid = (Function("x", "return (x." + (first?"":"x") + ch + ");")(x) === true);
|
||||
} catch (ex) {}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
function isIdentifier(str) {
|
||||
if (typeof str !== "string")
|
||||
return false;
|
||||
|
||||
if (str.length === 0)
|
||||
return false;
|
||||
|
||||
if (!isValidIdentifierChar(str[0], true))
|
||||
return false;
|
||||
|
||||
for (var i = 1; i < str.length; i++) {
|
||||
if (!isValidIdentifierChar(str[i], false))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tokenizer :: (source, filename, line number, boolean) -> Tokenizer
|
||||
*/
|
||||
function Tokenizer(s, f, l, allowHTMLComments) {
|
||||
this.cursor = 0;
|
||||
this.source = String(s);
|
||||
this.tokens = [];
|
||||
this.tokenIndex = 0;
|
||||
this.lookahead = 0;
|
||||
this.scanNewlines = false;
|
||||
this.filename = f || "";
|
||||
this.lineno = l || 1;
|
||||
this.allowHTMLComments = allowHTMLComments;
|
||||
this.blockComments = null;
|
||||
}
|
||||
|
||||
Tokenizer.prototype = {
|
||||
get done() {
|
||||
// We need to set scanOperand to true here because the first thing
|
||||
// might be a regexp.
|
||||
return this.peek(true) === END;
|
||||
},
|
||||
|
||||
get token() {
|
||||
return this.tokens[this.tokenIndex];
|
||||
},
|
||||
|
||||
match: function (tt, scanOperand, keywordIsName) {
|
||||
return this.get(scanOperand, keywordIsName) === tt || this.unget();
|
||||
},
|
||||
|
||||
mustMatch: function (tt, keywordIsName) {
|
||||
if (!this.match(tt, false, keywordIsName)) {
|
||||
throw this.newSyntaxError("Missing " +
|
||||
definitions.tokens[tt].toLowerCase());
|
||||
}
|
||||
return this.token;
|
||||
},
|
||||
|
||||
peek: function (scanOperand) {
|
||||
var tt, next;
|
||||
if (this.lookahead) {
|
||||
next = this.tokens[(this.tokenIndex + this.lookahead) & 3];
|
||||
tt = (this.scanNewlines && next.lineno !== this.lineno)
|
||||
? NEWLINE
|
||||
: next.type;
|
||||
} else {
|
||||
tt = this.get(scanOperand);
|
||||
this.unget();
|
||||
}
|
||||
return tt;
|
||||
},
|
||||
|
||||
peekOnSameLine: function (scanOperand) {
|
||||
this.scanNewlines = true;
|
||||
var tt = this.peek(scanOperand);
|
||||
this.scanNewlines = false;
|
||||
return tt;
|
||||
},
|
||||
|
||||
lastBlockComment: function() {
|
||||
var length = this.blockComments.length;
|
||||
return length ? this.blockComments[length - 1] : null;
|
||||
},
|
||||
|
||||
// Eat comments and whitespace.
|
||||
skip: function () {
|
||||
var input = this.source;
|
||||
this.blockComments = [];
|
||||
for (;;) {
|
||||
var ch = input[this.cursor++];
|
||||
var next = input[this.cursor];
|
||||
// handle \r, \r\n and (always preferable) \n
|
||||
if (ch === '\r') {
|
||||
// if the next character is \n, we don't care about this at all
|
||||
if (next === '\n') continue;
|
||||
|
||||
// otherwise, we want to consider this as a newline
|
||||
ch = '\n';
|
||||
}
|
||||
|
||||
if (ch === '\n' && !this.scanNewlines) {
|
||||
this.lineno++;
|
||||
} else if (ch === '/' && next === '*') {
|
||||
var commentStart = ++this.cursor;
|
||||
for (;;) {
|
||||
ch = input[this.cursor++];
|
||||
if (ch === undefined)
|
||||
throw this.newSyntaxError("Unterminated comment");
|
||||
|
||||
if (ch === '*') {
|
||||
next = input[this.cursor];
|
||||
if (next === '/') {
|
||||
var commentEnd = this.cursor - 1;
|
||||
this.cursor++;
|
||||
break;
|
||||
}
|
||||
} else if (ch === '\n') {
|
||||
this.lineno++;
|
||||
}
|
||||
}
|
||||
this.blockComments.push(input.substring(commentStart, commentEnd));
|
||||
} else if ((ch === '/' && next === '/') ||
|
||||
(this.allowHTMLComments && ch === '<' && next === '!' &&
|
||||
input[this.cursor + 1] === '-' && input[this.cursor + 2] === '-' &&
|
||||
(this.cursor += 2))) {
|
||||
this.cursor++;
|
||||
for (;;) {
|
||||
ch = input[this.cursor++];
|
||||
next = input[this.cursor];
|
||||
if (ch === undefined)
|
||||
return;
|
||||
|
||||
if (ch === '\r') {
|
||||
// check for \r\n
|
||||
if (next !== '\n') ch = '\n';
|
||||
}
|
||||
|
||||
if (ch === '\n') {
|
||||
if (this.scanNewlines) {
|
||||
this.cursor--;
|
||||
} else {
|
||||
this.lineno++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (!(ch in definitions.whitespace)) {
|
||||
this.cursor--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Lex the exponential part of a number, if present. Return true iff an
|
||||
// exponential part was found.
|
||||
lexExponent: function() {
|
||||
var input = this.source;
|
||||
var next = input[this.cursor];
|
||||
if (next === 'e' || next === 'E') {
|
||||
this.cursor++;
|
||||
ch = input[this.cursor++];
|
||||
if (ch === '+' || ch === '-')
|
||||
ch = input[this.cursor++];
|
||||
|
||||
if (ch < '0' || ch > '9')
|
||||
throw this.newSyntaxError("Missing exponent");
|
||||
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
} while (ch >= '0' && ch <= '9');
|
||||
this.cursor--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
lexZeroNumber: function (ch) {
|
||||
var token = this.token, input = this.source;
|
||||
token.type = NUMBER;
|
||||
|
||||
ch = input[this.cursor++];
|
||||
if (ch === '.') {
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
} while (ch >= '0' && ch <= '9');
|
||||
this.cursor--;
|
||||
|
||||
this.lexExponent();
|
||||
token.value = parseFloat(
|
||||
input.substring(token.start, this.cursor));
|
||||
} else if (ch === 'x' || ch === 'X') {
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
} while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') ||
|
||||
(ch >= 'A' && ch <= 'F'));
|
||||
this.cursor--;
|
||||
|
||||
token.value = parseInt(input.substring(token.start, this.cursor));
|
||||
} else if (ch >= '0' && ch <= '7') {
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
} while (ch >= '0' && ch <= '7');
|
||||
this.cursor--;
|
||||
|
||||
token.value = parseInt(input.substring(token.start, this.cursor));
|
||||
} else {
|
||||
this.cursor--;
|
||||
this.lexExponent(); // 0E1, &c.
|
||||
token.value = 0;
|
||||
}
|
||||
},
|
||||
|
||||
lexNumber: function (ch) {
|
||||
var token = this.token, input = this.source;
|
||||
token.type = NUMBER;
|
||||
|
||||
var floating = false;
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
if (ch === '.' && !floating) {
|
||||
floating = true;
|
||||
ch = input[this.cursor++];
|
||||
}
|
||||
} while (ch >= '0' && ch <= '9');
|
||||
|
||||
this.cursor--;
|
||||
|
||||
var exponent = this.lexExponent();
|
||||
floating = floating || exponent;
|
||||
|
||||
var str = input.substring(token.start, this.cursor);
|
||||
token.value = floating ? parseFloat(str) : parseInt(str);
|
||||
},
|
||||
|
||||
lexDot: function (ch) {
|
||||
var token = this.token, input = this.source;
|
||||
var next = input[this.cursor];
|
||||
if (next >= '0' && next <= '9') {
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
} while (ch >= '0' && ch <= '9');
|
||||
this.cursor--;
|
||||
|
||||
this.lexExponent();
|
||||
|
||||
token.type = NUMBER;
|
||||
token.value = parseFloat(
|
||||
input.substring(token.start, this.cursor));
|
||||
} else {
|
||||
token.type = DOT;
|
||||
token.assignOp = null;
|
||||
token.value = '.';
|
||||
}
|
||||
},
|
||||
|
||||
lexString: function (ch) {
|
||||
var token = this.token, input = this.source;
|
||||
token.type = STRING;
|
||||
|
||||
var hasEscapes = false;
|
||||
var delim = ch;
|
||||
if (input.length <= this.cursor)
|
||||
throw this.newSyntaxError("Unterminated string literal");
|
||||
while ((ch = input[this.cursor++]) !== delim) {
|
||||
if (ch == '\n' || ch == '\r')
|
||||
throw this.newSyntaxError("Unterminated string literal");
|
||||
if (this.cursor == input.length)
|
||||
throw this.newSyntaxError("Unterminated string literal");
|
||||
if (ch === '\\') {
|
||||
hasEscapes = true;
|
||||
if (++this.cursor == input.length)
|
||||
throw this.newSyntaxError("Unterminated string literal");
|
||||
}
|
||||
}
|
||||
|
||||
token.value = hasEscapes
|
||||
? eval(input.substring(token.start, this.cursor))
|
||||
: input.substring(token.start + 1, this.cursor - 1);
|
||||
},
|
||||
|
||||
lexRegExp: function (ch) {
|
||||
var token = this.token, input = this.source;
|
||||
token.type = REGEXP;
|
||||
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
if (ch === '\\') {
|
||||
this.cursor++;
|
||||
} else if (ch === '[') {
|
||||
do {
|
||||
if (ch === undefined)
|
||||
throw this.newSyntaxError("Unterminated character class");
|
||||
|
||||
if (ch === '\\')
|
||||
this.cursor++;
|
||||
|
||||
ch = input[this.cursor++];
|
||||
} while (ch !== ']');
|
||||
} else if (ch === undefined) {
|
||||
throw this.newSyntaxError("Unterminated regex");
|
||||
}
|
||||
} while (ch !== '/');
|
||||
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
} while (ch >= 'a' && ch <= 'z');
|
||||
|
||||
this.cursor--;
|
||||
|
||||
token.value = eval(input.substring(token.start, this.cursor));
|
||||
},
|
||||
|
||||
lexOp: function (ch) {
|
||||
var token = this.token, input = this.source;
|
||||
|
||||
// A bit ugly, but it seems wasteful to write a trie lookup routine
|
||||
// for only 3 characters...
|
||||
var node = opTokens[ch];
|
||||
var next = input[this.cursor];
|
||||
if (next in node) {
|
||||
node = node[next];
|
||||
this.cursor++;
|
||||
next = input[this.cursor];
|
||||
if (next in node) {
|
||||
node = node[next];
|
||||
this.cursor++;
|
||||
next = input[this.cursor];
|
||||
}
|
||||
}
|
||||
|
||||
var op = node.op;
|
||||
if (definitions.assignOps[op] && input[this.cursor] === '=') {
|
||||
this.cursor++;
|
||||
token.type = ASSIGN;
|
||||
token.assignOp = definitions.tokenIds[definitions.opTypeNames[op]];
|
||||
op += '=';
|
||||
} else {
|
||||
token.type = definitions.tokenIds[definitions.opTypeNames[op]];
|
||||
token.assignOp = null;
|
||||
}
|
||||
|
||||
token.value = op;
|
||||
},
|
||||
|
||||
// FIXME: Unicode escape sequences
|
||||
lexIdent: function (ch, keywordIsName) {
|
||||
var token = this.token;
|
||||
var id = ch;
|
||||
|
||||
while ((ch = this.getValidIdentifierChar(false)) !== null) {
|
||||
id += ch;
|
||||
}
|
||||
|
||||
token.type = IDENTIFIER;
|
||||
token.value = id;
|
||||
|
||||
if (keywordIsName)
|
||||
return;
|
||||
|
||||
var kw;
|
||||
|
||||
if (this.parser.mozillaMode) {
|
||||
kw = definitions.mozillaKeywords[id];
|
||||
if (kw) {
|
||||
token.type = kw;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.parser.x.strictMode) {
|
||||
kw = definitions.strictKeywords[id];
|
||||
if (kw) {
|
||||
token.type = kw;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
kw = definitions.keywords[id];
|
||||
if (kw)
|
||||
token.type = kw;
|
||||
},
|
||||
|
||||
/*
|
||||
* Tokenizer.get :: ([boolean[, boolean]]) -> token type
|
||||
*
|
||||
* Consume input *only* if there is no lookahead.
|
||||
* Dispatch to the appropriate lexing function depending on the input.
|
||||
*/
|
||||
get: function (scanOperand, keywordIsName) {
|
||||
var token;
|
||||
while (this.lookahead) {
|
||||
--this.lookahead;
|
||||
this.tokenIndex = (this.tokenIndex + 1) & 3;
|
||||
token = this.tokens[this.tokenIndex];
|
||||
if (token.type !== NEWLINE || this.scanNewlines)
|
||||
return token.type;
|
||||
}
|
||||
|
||||
this.skip();
|
||||
|
||||
this.tokenIndex = (this.tokenIndex + 1) & 3;
|
||||
token = this.tokens[this.tokenIndex];
|
||||
if (!token)
|
||||
this.tokens[this.tokenIndex] = token = {};
|
||||
|
||||
var input = this.source;
|
||||
if (this.cursor >= input.length)
|
||||
return token.type = END;
|
||||
|
||||
token.start = this.cursor;
|
||||
token.lineno = this.lineno;
|
||||
|
||||
var ich = this.getValidIdentifierChar(true);
|
||||
var ch = (ich === null) ? input[this.cursor++] : null;
|
||||
if (ich !== null) {
|
||||
this.lexIdent(ich, keywordIsName);
|
||||
} else if (scanOperand && ch === '/') {
|
||||
this.lexRegExp(ch);
|
||||
} else if (ch in opTokens) {
|
||||
this.lexOp(ch);
|
||||
} else if (ch === '.') {
|
||||
this.lexDot(ch);
|
||||
} else if (ch >= '1' && ch <= '9') {
|
||||
this.lexNumber(ch);
|
||||
} else if (ch === '0') {
|
||||
this.lexZeroNumber(ch);
|
||||
} else if (ch === '"' || ch === "'") {
|
||||
this.lexString(ch);
|
||||
} else if (this.scanNewlines && (ch === '\n' || ch === '\r')) {
|
||||
// if this was a \r, look for \r\n
|
||||
if (ch === '\r' && input[this.cursor] === '\n') this.cursor++;
|
||||
token.type = NEWLINE;
|
||||
token.value = '\n';
|
||||
this.lineno++;
|
||||
} else {
|
||||
throw this.newSyntaxError("Illegal token");
|
||||
}
|
||||
|
||||
token.end = this.cursor;
|
||||
return token.type;
|
||||
},
|
||||
|
||||
/*
|
||||
* Tokenizer.unget :: void -> undefined
|
||||
*
|
||||
* Match depends on unget returning undefined.
|
||||
*/
|
||||
unget: function () {
|
||||
if (++this.lookahead === 4) throw "PANIC: too much lookahead!";
|
||||
this.tokenIndex = (this.tokenIndex - 1) & 3;
|
||||
},
|
||||
|
||||
newSyntaxError: function (m) {
|
||||
m = (this.filename ? this.filename + ":" : "") + this.lineno + ": " + m;
|
||||
var e = new SyntaxError(m, this.filename, this.lineno);
|
||||
e.source = this.source;
|
||||
e.cursor = this.lookahead
|
||||
? this.tokens[(this.tokenIndex + this.lookahead) & 3].start
|
||||
: this.cursor;
|
||||
return e;
|
||||
},
|
||||
|
||||
|
||||
/* Gets a single valid identifier char from the input stream, or null
|
||||
* if there is none.
|
||||
*/
|
||||
getValidIdentifierChar: function(first) {
|
||||
var input = this.source;
|
||||
if (this.cursor >= input.length) return null;
|
||||
var ch = input[this.cursor];
|
||||
|
||||
// first check for \u escapes
|
||||
if (ch === '\\' && input[this.cursor+1] === 'u') {
|
||||
// get the character value
|
||||
try {
|
||||
ch = String.fromCharCode(parseInt(
|
||||
input.substring(this.cursor + 2, this.cursor + 6),
|
||||
16));
|
||||
} catch (ex) {
|
||||
return null;
|
||||
}
|
||||
this.cursor += 5;
|
||||
}
|
||||
|
||||
var valid = isValidIdentifierChar(ch, first);
|
||||
if (valid) this.cursor++;
|
||||
return (valid ? ch : null);
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
exports.isIdentifier = isIdentifier;
|
||||
exports.Tokenizer = Tokenizer;
|
||||
|
||||
});
|
||||
61
lib/ace/narcissus/options.js
Normal file
61
lib/ace/narcissus/options.js
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/* vim: set sw=4 ts=4 et tw=78: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the Narcissus JavaScript engine.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Brendan Eich <brendan@mozilla.org>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2004
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Tom Austin <taustin@ucsc.edu>
|
||||
* Brendan Eich <brendan@mozilla.org>
|
||||
* Shu-Yu Guo <shu@rfrn.org>
|
||||
* Dave Herman <dherman@mozilla.com>
|
||||
* Dimitris Vardoulakis <dimvar@ccs.neu.edu>
|
||||
* Patrick Walton <pcwalton@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
// Global variables to hide from the interpreter
|
||||
exports.hiddenHostGlobals = { Narcissus: true };
|
||||
|
||||
// Desugar SpiderMonkey language extensions?
|
||||
exports.desugarExtensions = false;
|
||||
|
||||
// Allow HTML comments?
|
||||
exports.allowHTMLComments = false;
|
||||
|
||||
// Allow non-standard Mozilla extensions?
|
||||
exports.mozillaMode = true;
|
||||
|
||||
// Allow experimental paren-free mode?
|
||||
exports.parenFreeMode = false;
|
||||
|
||||
});
|
||||
2072
lib/ace/narcissus/parser.js
Normal file
2072
lib/ace/narcissus/parser.js
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -51,7 +51,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) {
|
|||
};
|
||||
|
||||
(function() {
|
||||
this.isEequal = function(range) {
|
||||
this.isEqual = function(range) {
|
||||
return this.start.row == range.start.row &&
|
||||
this.end.row == range.end.row &&
|
||||
this.start.column == range.start.column &&
|
||||
|
|
@ -117,6 +117,11 @@ var Range = function(startRow, startColumn, endRow, endColumn) {
|
|||
return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0;
|
||||
}
|
||||
|
||||
this.intersectsRange = function(range) {
|
||||
var cmp = this.compareRange(range);
|
||||
return (cmp == -1 || cmp == 0 || cmp == 1);
|
||||
}
|
||||
|
||||
this.isEnd = function(row, column) {
|
||||
return this.end.row == row && this.end.column == column;
|
||||
}
|
||||
|
|
@ -276,6 +281,21 @@ var Range = function(startRow, startColumn, endRow, endColumn) {
|
|||
return Range.fromPoints(start || this.start, end || this.end);
|
||||
};
|
||||
|
||||
this.fixOrientation = function() {
|
||||
if (
|
||||
this.start.row < this.end.row
|
||||
|| (this.start.row == this.end.row && this.start.column < this.end.column)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var temp = this.start;
|
||||
this.end = this.start;
|
||||
this.start = temp;
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
this.isEmpty = function() {
|
||||
return (this.start.row == this.end.row && this.start.column == this.end.column);
|
||||
};
|
||||
|
|
|
|||
231
lib/ace/range_list.js
Normal file
231
lib/ace/range_list.js
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Harutyun Amirjanyan <amirjanyan AT gmail DOT com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
|
||||
var RangeList = function() {
|
||||
this.ranges = [];
|
||||
};
|
||||
|
||||
(function() {
|
||||
this.comparePoints = function(p1, p2) {
|
||||
return p1.row - p2.row || p1.column - p2.column;
|
||||
};
|
||||
|
||||
this.pointIndex = function(pos, startIndex) {
|
||||
var list = this.ranges;
|
||||
|
||||
for (var i = startIndex || 0; i < list.length; i++) {
|
||||
var range = list[i];
|
||||
var cmp = this.comparePoints(pos, range.end);
|
||||
|
||||
if (cmp > 0)
|
||||
continue;
|
||||
if (cmp == 0)
|
||||
return i;
|
||||
cmp = this.comparePoints(pos, range.start);
|
||||
if (cmp >= 0)
|
||||
return i;
|
||||
|
||||
return -i-1;
|
||||
}
|
||||
return -i - 1;
|
||||
};
|
||||
|
||||
this.add = function(range) {
|
||||
var startIndex = this.pointIndex(range.start);
|
||||
if (startIndex < 0)
|
||||
startIndex = -startIndex - 1;
|
||||
|
||||
var endIndex = this.pointIndex(range.end, startIndex);
|
||||
|
||||
if (endIndex < 0)
|
||||
endIndex = -endIndex - 1;
|
||||
else
|
||||
endIndex++;
|
||||
|
||||
return this.ranges.splice(startIndex, endIndex - startIndex, range);
|
||||
};
|
||||
|
||||
this.addList = function(list) {
|
||||
var removed = [];
|
||||
for (var i = list.length; i--; ) {
|
||||
removed.push.call(removed, this.add(list[i]));
|
||||
}
|
||||
return removed;
|
||||
};
|
||||
|
||||
this.substractPoint = function(pos) {
|
||||
var i = this.pointIndex(pos);
|
||||
|
||||
if (i >= 0)
|
||||
return this.ranges.splice(i, 1);
|
||||
};
|
||||
|
||||
// merge overlapping ranges
|
||||
this.merge = function() {
|
||||
var removed = [];
|
||||
var list = this.ranges;
|
||||
var next = list[0], range;
|
||||
for (var i = 1; i < list.length; i++) {
|
||||
range = next;
|
||||
next = list[i];
|
||||
var cmp = this.comparePoints(range.end, next.start);
|
||||
if (cmp < 0)
|
||||
continue;
|
||||
|
||||
if (cmp == 0 && !(range.isEmpty() || next.isEmpty()))
|
||||
continue;
|
||||
|
||||
if (this.comparePoints(range.end, next.end) < 0) {
|
||||
range.end.row = next.end.row;
|
||||
range.end.column = next.end.column;
|
||||
}
|
||||
|
||||
list.splice(i, 1);
|
||||
removed.push(next);
|
||||
next = range;
|
||||
i--;
|
||||
}
|
||||
|
||||
return removed;
|
||||
};
|
||||
|
||||
this.contains = function(row, column) {
|
||||
return this.pointIndex({row: row, column: column}) >= 0;
|
||||
};
|
||||
|
||||
this.containsPoint = function(pos) {
|
||||
return this.pointIndex(pos) >= 0;
|
||||
};
|
||||
|
||||
this.rangeAtPoint = function(pos) {
|
||||
var i = this.pointIndex(pos);
|
||||
if (i >= 0)
|
||||
return this.ranges[i];
|
||||
};
|
||||
|
||||
|
||||
this.clipRows = function(startRow, endRow) {
|
||||
var list = this.ranges;
|
||||
if (list[0].start.row > endRow || list[list.length - 1].start.row < startRow)
|
||||
return [];
|
||||
|
||||
var startIndex = this.pointIndex({row: startRow, column: 0});
|
||||
if (startIndex < 0)
|
||||
startIndex = -startIndex - 1;
|
||||
var endIndex = this.pointIndex({row: endRow, column: 0}, startIndex);
|
||||
if (endIndex < 0)
|
||||
endIndex = -endIndex - 1;
|
||||
|
||||
var clipped = [];
|
||||
for (var i = startIndex; i < endIndex; i++) {
|
||||
clipped.push(list[i]);
|
||||
}
|
||||
return clipped;
|
||||
};
|
||||
|
||||
this.removeAll = function() {
|
||||
return this.ranges.splice(0, this.ranges.length);
|
||||
};
|
||||
|
||||
this.attach = function(session) {
|
||||
if (this.session)
|
||||
this.detach();
|
||||
|
||||
this.session = session;
|
||||
this.onChange = this.$onChange.bind(this);
|
||||
|
||||
this.session.on('change', this.onChange);
|
||||
};
|
||||
|
||||
this.detach = function() {
|
||||
if (!this.session)
|
||||
return;
|
||||
this.session.removeListener('change', this.onChange);
|
||||
this.session = null;
|
||||
};
|
||||
|
||||
this.$onChange = function(e) {
|
||||
var changeRange = e.data.range;
|
||||
if (e.data.action[0] == "i"){
|
||||
var start = changeRange.start;
|
||||
var end = changeRange.end;
|
||||
} else {
|
||||
var end = changeRange.start;
|
||||
var start = changeRange.end;
|
||||
}
|
||||
var startRow = start.row;
|
||||
var endRow = end.row;
|
||||
var lineDif = endRow - startRow;
|
||||
|
||||
var colDiff = -start.column + end.column;
|
||||
|
||||
var ranges = this.ranges;
|
||||
|
||||
for (var i=0, n = ranges.length; i < n; i++) {
|
||||
var r = ranges[i];
|
||||
if (r.end.row < startRow)
|
||||
continue;
|
||||
if (r.start.row > startRow)
|
||||
break;
|
||||
|
||||
if (r.start.row == startRow && r.start.column >= start.column ) {
|
||||
r.start.column += colDiff;
|
||||
r.start.row += lineDif;
|
||||
}
|
||||
if (r.end.row == startRow && r.end.column >= start.column) {
|
||||
r.end.column += colDiff;
|
||||
r.end.row += lineDif;
|
||||
}
|
||||
}
|
||||
|
||||
if (lineDif != 0 && i < n) {
|
||||
for (; i < n; i++) {
|
||||
var r = ranges[i];
|
||||
r.start.row += lineDif;
|
||||
r.end.row += lineDif;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}).call(RangeList.prototype);
|
||||
|
||||
exports.RangeList = RangeList;
|
||||
});
|
||||
170
lib/ace/range_list_test.js
Normal file
170
lib/ace/range_list_test.js
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var Range = require("./range").Range;
|
||||
var RangeList = require("./range_list").RangeList;
|
||||
var EditSession = require("./edit_session").EditSession;
|
||||
var assert = require("./test/assertions");
|
||||
|
||||
function flatten(rangeList) {
|
||||
var points = [];
|
||||
rangeList.ranges.forEach(function(r) {
|
||||
points.push(r.start.row, r.start.column, r.end.row, r.end.column)
|
||||
})
|
||||
return points;
|
||||
}
|
||||
function testRangeList(rangeList, points) {
|
||||
assert.equal("" + flatten(rangeList), "" + points);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
name: "ACE range_list.js",
|
||||
|
||||
"test: rangeList pointIndex": function() {
|
||||
var rangeList = new RangeList();
|
||||
rangeList.ranges = [
|
||||
new Range(1,2,3,4),
|
||||
new Range(4,2,5,4),
|
||||
new Range(8,8,9,9)
|
||||
];
|
||||
|
||||
assert.equal(rangeList.pointIndex({row: 0, column: 1}), -1);
|
||||
assert.equal(rangeList.pointIndex({row: 1, column: 2}), 0);
|
||||
assert.equal(rangeList.pointIndex({row: 1, column: 3}), 0);
|
||||
assert.equal(rangeList.pointIndex({row: 3, column: 4}), 0);
|
||||
assert.equal(rangeList.pointIndex({row: 4, column: 1}), -2);
|
||||
assert.equal(rangeList.pointIndex({row: 5, column: 1}), 1);
|
||||
assert.equal(rangeList.pointIndex({row: 8, column: 9}), 2);
|
||||
assert.equal(rangeList.pointIndex({row: 18, column: 9}), -4);
|
||||
},
|
||||
|
||||
"test: rangeList add": function() {
|
||||
var rangeList = new RangeList();
|
||||
rangeList.addList([
|
||||
new Range(9,0,9,1),
|
||||
new Range(1,2,3,4),
|
||||
new Range(8,8,9,9),
|
||||
new Range(4,2,5,4),
|
||||
new Range(3,20,3,24),
|
||||
new Range(6,6,7,7)
|
||||
]);
|
||||
assert.equal(rangeList.ranges.length, 5);
|
||||
|
||||
rangeList.add(new Range(1,2,3,5));
|
||||
assert.range(rangeList.ranges[0], 1,2,3,5);
|
||||
assert.equal(rangeList.ranges.length, 5);
|
||||
|
||||
rangeList.add(new Range(7,7,7,7));
|
||||
assert.range(rangeList.ranges[3], 7,7,7,7);
|
||||
rangeList.add(new Range(7,8,7,8));
|
||||
assert.range(rangeList.ranges[4], 7,8,7,8);
|
||||
},
|
||||
|
||||
"test: rangeList add empty": function() {
|
||||
var rangeList = new RangeList();
|
||||
rangeList.addList([
|
||||
new Range(7,10,7,10),
|
||||
new Range(9,10,9,10),
|
||||
new Range(8,10,8,10)
|
||||
]);
|
||||
assert.equal(rangeList.ranges.length, 3);
|
||||
|
||||
rangeList.add(new Range(9,10,9,10));
|
||||
testRangeList(rangeList, [7,10,7,10,8,10,8,10,9,10,9,10]);
|
||||
},
|
||||
|
||||
"test: rangeList merge": function() {
|
||||
var rangeList = new RangeList();
|
||||
rangeList.addList([
|
||||
new Range(1,2,3,4),
|
||||
new Range(4,2,5,4),
|
||||
new Range(6,6,7,7),
|
||||
new Range(8,8,9,9)
|
||||
]);
|
||||
var removed = [];
|
||||
|
||||
assert.equal(rangeList.ranges.length, 4);
|
||||
|
||||
rangeList.ranges[1].end.row = 7;
|
||||
removed = rangeList.merge();
|
||||
assert.equal(removed.length, 1);
|
||||
assert.range(rangeList.ranges[1], 4,2,7,7);
|
||||
assert.equal(rangeList.ranges.length, 3);
|
||||
|
||||
rangeList.ranges[0].end.row = 10;
|
||||
removed = rangeList.merge();
|
||||
assert.range(rangeList.ranges[0], 1,2,10,4);
|
||||
assert.equal(removed.length, 2);
|
||||
assert.equal(rangeList.ranges.length, 1);
|
||||
|
||||
rangeList.ranges.push(new Range(10,10,10,10));
|
||||
rangeList.ranges.push(new Range(10,10,10,10));
|
||||
removed = rangeList.merge();
|
||||
assert.equal(rangeList.ranges.length, 2);
|
||||
},
|
||||
|
||||
"test: rangeList remove": function() {
|
||||
var rangeList = new RangeList();
|
||||
var list = [
|
||||
new Range(1,2,3,4),
|
||||
new Range(4,2,5,4),
|
||||
new Range(6,6,7,7),
|
||||
new Range(8,8,9,9)
|
||||
];
|
||||
rangeList.addList(list);
|
||||
assert.equal(rangeList.ranges.length, 4);
|
||||
rangeList.substractPoint({row: 1, column: 2});
|
||||
assert.equal(rangeList.ranges.length, 3);
|
||||
rangeList.substractPoint({row: 6, column: 7});
|
||||
assert.equal(rangeList.ranges.length, 2);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
|
|
@ -83,6 +83,8 @@ var ScrollBar = function(parent) {
|
|||
this.inner.style.height = height + "px";
|
||||
};
|
||||
|
||||
// TODO: on chrome 17+ after for small zoom levels after this function
|
||||
// this.element.scrollTop != scrollTop which makes page to scroll up.
|
||||
this.setScrollTop = function(scrollTop) {
|
||||
this.element.scrollTop = scrollTop;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -59,18 +59,18 @@ var Selection = function(session) {
|
|||
this.selectionLead = this.doc.createAnchor(0, 0);
|
||||
this.selectionAnchor = this.doc.createAnchor(0, 0);
|
||||
|
||||
var _self = this;
|
||||
var self = this;
|
||||
this.selectionLead.on("change", function(e) {
|
||||
_self._emit("changeCursor");
|
||||
if (!_self.$isEmpty)
|
||||
_self._emit("changeSelection");
|
||||
if (!_self.$preventUpdateDesiredColumnOnChange && e.old.column != e.value.column)
|
||||
_self.$updateDesiredColumn();
|
||||
self._emit("changeCursor");
|
||||
if (!self.$isEmpty)
|
||||
self._emit("changeSelection");
|
||||
if (!self.$keepDesiredColumnOnChange && e.old.column != e.value.column)
|
||||
self.$desiredColumn = null;
|
||||
});
|
||||
|
||||
this.selectionAnchor.on("change", function() {
|
||||
if (!_self.$isEmpty)
|
||||
_self._emit("changeSelection");
|
||||
if (!self.$isEmpty)
|
||||
self._emit("changeSelection");
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -180,12 +180,7 @@ var Selection = function(session) {
|
|||
this.setSelectionAnchor(range.start.row, range.start.column);
|
||||
this.selectTo(range.end.row, range.end.column);
|
||||
}
|
||||
this.$updateDesiredColumn();
|
||||
};
|
||||
|
||||
this.$updateDesiredColumn = function() {
|
||||
var cursor = this.getCursor();
|
||||
this.$desiredColumn = this.session.documentToScreenColumn(cursor.row, cursor.column);
|
||||
this.$desiredColumn = null;
|
||||
};
|
||||
|
||||
this.$moveSelection = function(mover) {
|
||||
|
|
@ -392,14 +387,14 @@ var Selection = function(session) {
|
|||
this.moveCursorTo(fold.end.row, fold.end.column);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// first skip space
|
||||
if (match = this.session.nonTokenRe.exec(rightOfCursor)) {
|
||||
column += this.session.nonTokenRe.lastIndex;
|
||||
this.session.nonTokenRe.lastIndex = 0;
|
||||
rightOfCursor = line.substring(column);
|
||||
}
|
||||
|
||||
|
||||
// if at line end proceed with next line
|
||||
if (column >= line.length) {
|
||||
this.moveCursorTo(row, line.length);
|
||||
|
|
@ -408,7 +403,7 @@ var Selection = function(session) {
|
|||
this.moveCursorWordRight();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// advance to the end of the next token
|
||||
if (match = this.session.tokenRe.exec(rightOfCursor)) {
|
||||
column += this.session.tokenRe.lastIndex;
|
||||
|
|
@ -433,19 +428,19 @@ var Selection = function(session) {
|
|||
if (str == null) {
|
||||
str = this.doc.getLine(row).substring(0, column)
|
||||
}
|
||||
|
||||
|
||||
var leftOfCursor = lang.stringReverse(str);
|
||||
var match;
|
||||
this.session.nonTokenRe.lastIndex = 0;
|
||||
this.session.tokenRe.lastIndex = 0;
|
||||
|
||||
|
||||
// skip whitespace
|
||||
if (match = this.session.nonTokenRe.exec(leftOfCursor)) {
|
||||
column -= this.session.nonTokenRe.lastIndex;
|
||||
leftOfCursor = leftOfCursor.slice(this.session.nonTokenRe.lastIndex);
|
||||
this.session.nonTokenRe.lastIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
// if at begin of the line proceed in line above
|
||||
if (column <= 0) {
|
||||
this.moveCursorTo(row, 0);
|
||||
|
|
@ -470,8 +465,14 @@ var Selection = function(session) {
|
|||
this.selectionLead.column
|
||||
);
|
||||
|
||||
var screenCol = (chars === 0 && this.$desiredColumn) || screenPos.column;
|
||||
var docPos = this.session.screenToDocumentPosition(screenPos.row + rows, screenCol);
|
||||
if (chars === 0) {
|
||||
if (this.$desiredColumn)
|
||||
screenPos.column = this.$desiredColumn;
|
||||
else
|
||||
this.$desiredColumn = screenPos.column;
|
||||
}
|
||||
|
||||
var docPos = this.session.screenToDocumentPosition(screenPos.row + rows, screenPos.column);
|
||||
|
||||
// move the cursor and update the desired column
|
||||
this.moveCursorTo(docPos.row, docPos.column + chars, chars === 0);
|
||||
|
|
@ -481,7 +482,7 @@ var Selection = function(session) {
|
|||
this.moveCursorTo(position.row, position.column);
|
||||
};
|
||||
|
||||
this.moveCursorTo = function(row, column, preventUpdateDesiredColumn) {
|
||||
this.moveCursorTo = function(row, column, keepDesiredColumn) {
|
||||
// Ensure the row/column is not inside of a fold.
|
||||
var fold = this.session.getFoldAt(row, column, 1);
|
||||
if (fold) {
|
||||
|
|
@ -489,21 +490,47 @@ var Selection = function(session) {
|
|||
column = fold.start.column;
|
||||
}
|
||||
|
||||
this.$preventUpdateDesiredColumnOnChange = true;
|
||||
this.$keepDesiredColumnOnChange = true;
|
||||
this.selectionLead.setPosition(row, column);
|
||||
this.$preventUpdateDesiredColumnOnChange = false;
|
||||
this.$keepDesiredColumnOnChange = false;
|
||||
|
||||
if (!preventUpdateDesiredColumn)
|
||||
this.$updateDesiredColumn(this.selectionLead.column);
|
||||
if (!keepDesiredColumn)
|
||||
this.$desiredColumn = null;
|
||||
};
|
||||
|
||||
this.moveCursorToScreen = function(row, column, preventUpdateDesiredColumn) {
|
||||
this.moveCursorToScreen = function(row, column, keepDesiredColumn) {
|
||||
var pos = this.session.screenToDocumentPosition(row, column);
|
||||
row = pos.row;
|
||||
column = pos.column;
|
||||
this.moveCursorTo(row, column, preventUpdateDesiredColumn);
|
||||
this.moveCursorTo(pos.row, pos.column, keepDesiredColumn);
|
||||
};
|
||||
|
||||
// remove listeners from document
|
||||
this.detach = function() {
|
||||
this.selectionLead.detach();
|
||||
this.selectionAnchor.detach();
|
||||
this.session = this.doc = null;
|
||||
}
|
||||
|
||||
this.fromOrientedRange = function(range) {
|
||||
this.setSelectionRange(range, range.cursor == range.start);
|
||||
this.$desiredColumn = range.desiredColumn || this.$desiredColumn;
|
||||
}
|
||||
|
||||
this.toOrientedRange = function(range) {
|
||||
var r = this.getRange();
|
||||
if (range) {
|
||||
range.start.column = r.start.column;
|
||||
range.start.row = r.start.row;
|
||||
range.end.column = r.end.column;
|
||||
range.end.row = r.end.row;
|
||||
} else {
|
||||
range = r;
|
||||
}
|
||||
|
||||
range.cursor = this.isBackwards() ? range.start : range.end;
|
||||
range.desiredColumn = this.$desiredColumn;
|
||||
return range;
|
||||
}
|
||||
|
||||
}).call(Selection.prototype);
|
||||
|
||||
exports.Selection = Selection;
|
||||
|
|
|
|||
|
|
@ -9,96 +9,116 @@ var passed = 0
|
|||
var failed = 0
|
||||
var log = document.getElementById("log")
|
||||
|
||||
var tests = [
|
||||
require("ace/anchor_test"),
|
||||
require("ace/commands/command_manager_test"),
|
||||
require("ace/document_test"),
|
||||
require("ace/edit_session_test"),
|
||||
require("ace/editor_change_document_test"),
|
||||
require("ace/editor_highlight_selected_word_test"),
|
||||
require("ace/editor_navigation_test"),
|
||||
require("ace/editor_text_edit_test"),
|
||||
require("ace/ext/static_highlight_test"),
|
||||
require("ace/layer/text_test"),
|
||||
require("ace/lib/event_emitter_test"),
|
||||
require("ace/mode/coffee/parser_test"),
|
||||
require("ace/mode/coffee_tokenizer_test"),
|
||||
require("ace/mode/coldfusion_test"),
|
||||
require("ace/mode/css_test"),
|
||||
require("ace/mode/css_tokenizer_test"),
|
||||
require("ace/mode/css_worker"),
|
||||
require("ace/mode/html_test"),
|
||||
require("ace/mode/html_tokenizer_test"),
|
||||
require("ace/mode/javascript_test"),
|
||||
require("ace/mode/javascript_tokenizer_test"),
|
||||
require("ace/mode/javascript_worker_test"),
|
||||
require("ace/mode/python_test"),
|
||||
require("ace/mode/ruby_tokenizer_test"),
|
||||
require("ace/mode/text_test"),
|
||||
require("ace/mode/xml_test"),
|
||||
require("ace/mode/xml_tokenizer_test"),
|
||||
require("ace/mode/folding/cstyle_test"),
|
||||
require("ace/mode/folding/html_test"),
|
||||
require("ace/mode/folding/pythonic_test"),
|
||||
require("ace/mode/folding/xml_test"),
|
||||
require("ace/range_test"),
|
||||
require("ace/search_test"),
|
||||
require("ace/selection_test"),
|
||||
require("ace/token_iterator_test"),
|
||||
require("ace/virtual_renderer_test")
|
||||
]
|
||||
var testNames = [
|
||||
"ace/anchor_test",
|
||||
"ace/commands/command_manager_test",
|
||||
"ace/document_test",
|
||||
"ace/edit_session_test",
|
||||
"ace/editor_change_document_test",
|
||||
"ace/editor_highlight_selected_word_test",
|
||||
"ace/editor_navigation_test",
|
||||
"ace/editor_text_edit_test",
|
||||
"ace/ext/static_highlight_test",
|
||||
"ace/layer/text_test",
|
||||
"ace/lib/event_emitter_test",
|
||||
"ace/mode/coffee/parser_test",
|
||||
"ace/mode/coffee_highlight_rules_test",
|
||||
"ace/mode/coldfusion_test",
|
||||
"ace/mode/css_test",
|
||||
"ace/mode/css_highlight_rules_test",
|
||||
"ace/mode/css_worker",
|
||||
"ace/mode/html_test",
|
||||
"ace/mode/html_highlight_rules_test",
|
||||
"ace/mode/javascript_test",
|
||||
"ace/mode/javascript_highlight_rules_test",
|
||||
"ace/mode/javascript_worker_test",
|
||||
"ace/mode/python_test",
|
||||
"ace/mode/ruby_highlight_rules_test",
|
||||
"ace/mode/text_test",
|
||||
"ace/mode/xml_test",
|
||||
"ace/mode/xml_highlight_rules_test",
|
||||
"ace/mode/folding/cstyle_test",
|
||||
"ace/mode/folding/html_test",
|
||||
"ace/mode/folding/pythonic_test",
|
||||
"ace/mode/folding/xml_test",
|
||||
"ace/multi_select_test",
|
||||
"ace/range_test",
|
||||
"ace/range_list_test",
|
||||
"ace/search_test",
|
||||
"ace/selection_test",
|
||||
"ace/token_iterator_test",
|
||||
"ace/virtual_renderer_test"
|
||||
];
|
||||
|
||||
async.list(tests)
|
||||
.expand(function(test) {
|
||||
return AsyncTest.testcase(test)
|
||||
}, AsyncTest.TestGenerator)
|
||||
.run()
|
||||
.each(function(test, next) {
|
||||
var node = document.createElement("div");
|
||||
node.className = test.passed ? "passed" : "failed";
|
||||
var html = ["<a href='?'>all tests</a><br>"];
|
||||
for (var i in testNames) {
|
||||
var href = testNames[i];
|
||||
html.push("<a href='?", href, "'>", href.replace(/^ace\//, "") ,"</a><br>");
|
||||
}
|
||||
|
||||
var name = test.name
|
||||
if (test.suiteName)
|
||||
name = test.suiteName + ": " + test.name
|
||||
var nav = document.createElement("div");
|
||||
nav.innerHTML = html.join("");
|
||||
nav.style.cssText = "position:absolute;right:0;top:0";
|
||||
document.body.appendChild(nav);
|
||||
|
||||
var msg = "[" + test.count + "/" + test.index + "] " + name + " " + (test.passed ? "OK" : "FAIL")
|
||||
if (!test.passed) {
|
||||
if (test.err.stack)
|
||||
var err = test.err.stack
|
||||
if (location.search)
|
||||
testNames = location.search.substr(1).split(",")
|
||||
|
||||
require(testNames, function() {
|
||||
var tests = testNames.map(require);
|
||||
|
||||
async.list(tests)
|
||||
.expand(function(test) {
|
||||
return AsyncTest.testcase(test)
|
||||
}, AsyncTest.TestGenerator)
|
||||
.run()
|
||||
.each(function(test, next) {
|
||||
var node = document.createElement("div");
|
||||
node.className = test.passed ? "passed" : "failed";
|
||||
|
||||
var name = test.name
|
||||
if (test.suiteName)
|
||||
name = test.suiteName + ": " + test.name
|
||||
|
||||
var msg = "[" + test.count + "/" + test.index + "] " + name + " " + (test.passed ? "OK" : "FAIL")
|
||||
if (!test.passed) {
|
||||
if (test.err.stack)
|
||||
var err = test.err.stack
|
||||
else
|
||||
var err = test.err
|
||||
|
||||
console.error(msg);
|
||||
console.error(err);
|
||||
msg += "<pre class='error'>" + err + "</pre>";
|
||||
} else {
|
||||
console.log(msg);
|
||||
}
|
||||
|
||||
node.innerHTML = msg;
|
||||
log.appendChild(node);
|
||||
|
||||
next()
|
||||
})
|
||||
.each(function(test) {
|
||||
if (test.passed)
|
||||
passed += 1
|
||||
else
|
||||
var err = test.err
|
||||
|
||||
console.error(msg);
|
||||
console.error(err);
|
||||
msg += "<pre class='error'>" + err + "</pre>";
|
||||
} else {
|
||||
console.log(msg);
|
||||
}
|
||||
|
||||
node.innerHTML = msg;
|
||||
log.appendChild(node);
|
||||
|
||||
next()
|
||||
})
|
||||
.each(function(test) {
|
||||
if (test.passed)
|
||||
passed += 1
|
||||
else
|
||||
failed += 1
|
||||
})
|
||||
.end(function() {
|
||||
log.innerHTML += [
|
||||
"<div class='summary'>",
|
||||
"<br>",
|
||||
"Summary: <br>",
|
||||
"<br>",
|
||||
"Total number of tests: " + (passed + failed) + "<br>",
|
||||
(passed ? "Passed tests: " + passed + "<br>" : ""),
|
||||
(failed ? "Failed tests: " + failed + "<br>" : "")
|
||||
].join("")
|
||||
console.log("Total number of tests: " + (passed + failed));
|
||||
console.log("Passed tests: " + passed);
|
||||
console.log("Failed tests: " + failed);
|
||||
})
|
||||
failed += 1
|
||||
})
|
||||
.end(function() {
|
||||
log.innerHTML += [
|
||||
"<div class='summary'>",
|
||||
"<br>",
|
||||
"Summary: <br>",
|
||||
"<br>",
|
||||
"Total number of tests: " + (passed + failed) + "<br>",
|
||||
(passed ? "Passed tests: " + passed + "<br>" : ""),
|
||||
(failed ? "Failed tests: " + failed + "<br>" : "")
|
||||
].join("")
|
||||
console.log("Total number of tests: " + (passed + failed));
|
||||
console.log("Passed tests: " + passed);
|
||||
console.log("Failed tests: " + failed);
|
||||
})
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ var MockRenderer = exports.MockRenderer = function(visibleRowCount) {
|
|||
};
|
||||
|
||||
this.isMockRenderer = true;
|
||||
|
||||
|
||||
this.$gutter = {};
|
||||
};
|
||||
|
||||
|
|
@ -81,6 +81,12 @@ MockRenderer.prototype.getTextAreaContainer = function() {
|
|||
return this.container;
|
||||
};
|
||||
|
||||
MockRenderer.prototype.addGutterDecoration = function() {
|
||||
};
|
||||
|
||||
MockRenderer.prototype.removeGutterDecoration = function() {
|
||||
};
|
||||
|
||||
MockRenderer.prototype.moveTextAreaToCursor = function() {
|
||||
};
|
||||
|
||||
|
|
@ -103,7 +109,7 @@ MockRenderer.prototype.updateCursor = function() {
|
|||
|
||||
MockRenderer.prototype.scrollToX = function(scrollTop) {};
|
||||
MockRenderer.prototype.scrollToY = function(scrollLeft) {};
|
||||
|
||||
|
||||
MockRenderer.prototype.scrollToLine = function(line, center) {
|
||||
var lineHeight = { lineHeight: 16 };
|
||||
var row = 0;
|
||||
|
|
@ -117,6 +123,9 @@ MockRenderer.prototype.scrollToLine = function(line, center) {
|
|||
this.scrollToRow(row);
|
||||
};
|
||||
|
||||
MockRenderer.prototype.scrollSelectionIntoView = function() {
|
||||
};
|
||||
|
||||
MockRenderer.prototype.scrollCursorIntoView = function() {
|
||||
var cursor = this.session.getSelection().getCursor();
|
||||
if (cursor.row < this.layerConfig.firstVisibleRow) {
|
||||
|
|
@ -171,6 +180,12 @@ MockRenderer.prototype.visualizeFocus = function() {
|
|||
MockRenderer.prototype.setAnnotations = function() {
|
||||
};
|
||||
|
||||
MockRenderer.prototype.setStyle = function() {
|
||||
};
|
||||
|
||||
MockRenderer.prototype.unsetStyle = function() {
|
||||
};
|
||||
|
||||
MockRenderer.prototype.textToScreenCoordinates = function() {
|
||||
return {
|
||||
pageX: 0,
|
||||
|
|
@ -179,7 +194,7 @@ MockRenderer.prototype.textToScreenCoordinates = function() {
|
|||
};
|
||||
|
||||
MockRenderer.prototype.adjustWrapLimit = function () {
|
||||
|
||||
|
||||
};
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ exports.cssText = ".ace-chrome .ace_editor {\
|
|||
}\
|
||||
\
|
||||
.ace-chrome .ace_gutter {\
|
||||
width: 50px;\
|
||||
background: #e8e8e8;\
|
||||
color: #333;\
|
||||
overflow : hidden;\
|
||||
|
|
@ -58,10 +57,6 @@ exports.cssText = ".ace-chrome .ace_editor {\
|
|||
text-align: right;\
|
||||
}\
|
||||
\
|
||||
.ace-chrome .ace_gutter-layer .ace_gutter-cell {\
|
||||
padding-right: 6px;\
|
||||
}\
|
||||
\
|
||||
.ace-chrome .ace_print_margin {\
|
||||
width: 1px;\
|
||||
background: #e8e8e8;\
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ exports.cssText = "\
|
|||
}\
|
||||
\
|
||||
.ace-clouds .ace_cursor {\
|
||||
border-left: 2px solid #000000;\
|
||||
border-left: 1px solid #000000;\
|
||||
}\
|
||||
\
|
||||
.ace-clouds .ace_cursor.ace_overwrite {\
|
||||
border-left: 0px;\
|
||||
border-bottom: 1px solid #000000;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-clouds .ace_marker-layer .ace_selection {\
|
||||
background: #BDD5FC;\
|
||||
}\
|
||||
|
|
@ -96,7 +96,7 @@ exports.cssText = "\
|
|||
.ace-clouds .ace_marker-layer .ace_selected_word {\
|
||||
border: 1px solid #BDD5FC;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-clouds .ace_invisible {\
|
||||
color: #BFBFBF;\
|
||||
}\
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ exports.cssText = "\
|
|||
}\
|
||||
\
|
||||
.ace-clouds-midnight .ace_cursor {\
|
||||
border-left: 2px solid #7DA5DC;\
|
||||
border-left: 1px solid #7DA5DC;\
|
||||
}\
|
||||
\
|
||||
.ace-clouds-midnight .ace_cursor.ace_overwrite {\
|
||||
border-left: 0px;\
|
||||
border-bottom: 1px solid #7DA5DC;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-clouds-midnight .ace_marker-layer .ace_selection {\
|
||||
background: #000000;\
|
||||
}\
|
||||
|
|
@ -96,7 +96,7 @@ exports.cssText = "\
|
|||
.ace-clouds-midnight .ace_marker-layer .ace_selected_word {\
|
||||
border: 1px solid #000000;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-clouds-midnight .ace_invisible {\
|
||||
color: #BFBFBF;\
|
||||
}\
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ exports.cssText = "\
|
|||
}\
|
||||
\
|
||||
.ace-cobalt .ace_cursor {\
|
||||
border-left: 2px solid #FFFFFF;\
|
||||
border-left: 1px solid #FFFFFF;\
|
||||
}\
|
||||
\
|
||||
.ace-cobalt .ace_cursor.ace_overwrite {\
|
||||
border-left: 0px;\
|
||||
border-bottom: 1px solid #FFFFFF;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-cobalt .ace_marker-layer .ace_selection {\
|
||||
background: rgba(179, 101, 57, 0.75);\
|
||||
}\
|
||||
|
|
@ -96,7 +96,7 @@ exports.cssText = "\
|
|||
.ace-cobalt .ace_marker-layer .ace_selected_word {\
|
||||
border: 1px solid rgba(179, 101, 57, 0.75);\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-cobalt .ace_invisible {\
|
||||
color: rgba(255, 255, 255, 0.15);\
|
||||
}\
|
||||
|
|
@ -109,6 +109,14 @@ exports.cssText = "\
|
|||
color:#FF628C;\
|
||||
}\
|
||||
\
|
||||
.ace-cobalt .ace_constant.ace_character, {\
|
||||
color:#FF628C;\
|
||||
}\
|
||||
\
|
||||
.ace-cobalt .ace_constant.ace_character.ace_escape, {\
|
||||
color:#FF628C;\
|
||||
}\
|
||||
\
|
||||
.ace-cobalt .ace_invalid {\
|
||||
color:#F8F8F8;\
|
||||
background-color:#800F00;\
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ exports.cssText = "\
|
|||
}\
|
||||
\
|
||||
.ace-dawn .ace_cursor {\
|
||||
border-left: 2px solid #000000;\
|
||||
border-left: 1px solid #000000;\
|
||||
}\
|
||||
\
|
||||
.ace-dawn .ace_cursor.ace_overwrite {\
|
||||
border-left: 0px;\
|
||||
border-bottom: 1px solid #000000;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-dawn .ace_marker-layer .ace_selection {\
|
||||
background: rgba(39, 95, 255, 0.30);\
|
||||
}\
|
||||
|
|
@ -96,7 +96,7 @@ exports.cssText = "\
|
|||
.ace-dawn .ace_marker-layer .ace_selected_word {\
|
||||
border: 1px solid rgba(39, 95, 255, 0.30);\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-dawn .ace_invisible {\
|
||||
color: rgba(75, 75, 126, 0.50);\
|
||||
}\
|
||||
|
|
@ -109,6 +109,14 @@ exports.cssText = "\
|
|||
color:#811F24;\
|
||||
}\
|
||||
\
|
||||
.ace-dawn .ace_constant.ace_character, {\
|
||||
color:#811F24;\
|
||||
}\
|
||||
\
|
||||
.ace-dawn .ace_constant.ace_character.ace_escape, {\
|
||||
color:#811F24;\
|
||||
}\
|
||||
\
|
||||
.ace-dawn .ace_invalid.ace_illegal {\
|
||||
text-decoration:underline;\
|
||||
font-style:italic;\
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ exports.cssText = "\
|
|||
}\
|
||||
\
|
||||
.ace-idle-fingers .ace_cursor {\
|
||||
border-left: 2px solid #91FF00;\
|
||||
border-left: 1px solid #91FF00;\
|
||||
}\
|
||||
\
|
||||
.ace-idle-fingers .ace_cursor.ace_overwrite {\
|
||||
border-left: 0px;\
|
||||
border-bottom: 1px solid #91FF00;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-idle-fingers .ace_marker-layer .ace_selection {\
|
||||
background: rgba(90, 100, 126, 0.88);\
|
||||
}\
|
||||
|
|
@ -96,7 +96,7 @@ exports.cssText = "\
|
|||
.ace-idle-fingers .ace_marker-layer .ace_selected_word {\
|
||||
border: 1px solid rgba(90, 100, 126, 0.88);\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-idle-fingers .ace_invisible {\
|
||||
color: #404040;\
|
||||
}\
|
||||
|
|
@ -109,6 +109,14 @@ exports.cssText = "\
|
|||
color:#6C99BB;\
|
||||
}\
|
||||
\
|
||||
.ace-idle-fingers .ace_constant.ace_character, {\
|
||||
color:#6C99BB;\
|
||||
}\
|
||||
\
|
||||
.ace-idle-fingers .ace_constant.ace_character.ace_escape, {\
|
||||
color:#6C99BB;\
|
||||
}\
|
||||
\
|
||||
.ace-idle-fingers .ace_invalid {\
|
||||
color:#FFFFFF;\
|
||||
background-color:#FF0000;\
|
||||
|
|
@ -158,7 +166,7 @@ color:#BC9458;\
|
|||
\
|
||||
.ace-idle-fingers .ace_collab.ace_user1 {\
|
||||
color:#323232;\
|
||||
background-color:#FFF980; \
|
||||
background-color:#FFF980;\
|
||||
}";
|
||||
|
||||
var dom = require("../lib/dom");
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ exports.cssText = "\
|
|||
}\
|
||||
\
|
||||
.ace-kr-theme .ace_cursor {\
|
||||
border-left: 2px solid #FF9900;\
|
||||
border-left: 1px solid #FF9900;\
|
||||
}\
|
||||
\
|
||||
.ace-kr-theme .ace_cursor.ace_overwrite {\
|
||||
border-left: 0px;\
|
||||
border-bottom: 1px solid #FF9900;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-kr-theme .ace_marker-layer .ace_selection {\
|
||||
background: rgba(170, 0, 255, 0.45);\
|
||||
}\
|
||||
|
|
@ -96,7 +96,7 @@ exports.cssText = "\
|
|||
.ace-kr-theme .ace_marker-layer .ace_selected_word {\
|
||||
border: 1px solid rgba(170, 0, 255, 0.45);\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-kr-theme .ace_invisible {\
|
||||
color: rgba(255, 177, 111, 0.32);\
|
||||
}\
|
||||
|
|
@ -109,6 +109,14 @@ exports.cssText = "\
|
|||
color:rgba(210, 117, 24, 0.76);\
|
||||
}\
|
||||
\
|
||||
.ace-kr-theme .ace_constant.ace_character, {\
|
||||
color:rgba(210, 117, 24, 0.76);\
|
||||
}\
|
||||
\
|
||||
.ace-kr-theme .ace_constant.ace_character.ace_escape, {\
|
||||
color:rgba(210, 117, 24, 0.76);\
|
||||
}\
|
||||
\
|
||||
.ace-kr-theme .ace_invalid {\
|
||||
color:#F8F8F8;\
|
||||
background-color:#A41300;\
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ exports.cssText = "\
|
|||
}\
|
||||
\
|
||||
.ace-merbivore .ace_cursor {\
|
||||
border-left: 2px solid #FFFFFF;\
|
||||
border-left: 1px solid #FFFFFF;\
|
||||
}\
|
||||
\
|
||||
.ace-merbivore .ace_cursor.ace_overwrite {\
|
||||
border-left: 0px;\
|
||||
border-bottom: 1px solid #FFFFFF;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-merbivore .ace_marker-layer .ace_selection {\
|
||||
background: #454545;\
|
||||
}\
|
||||
|
|
@ -96,7 +96,7 @@ exports.cssText = "\
|
|||
.ace-merbivore .ace_marker-layer .ace_selected_word {\
|
||||
border: 1px solid #454545;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-merbivore .ace_invisible {\
|
||||
color: #404040;\
|
||||
}\
|
||||
|
|
@ -109,6 +109,14 @@ exports.cssText = "\
|
|||
color:#1EDAFB;\
|
||||
}\
|
||||
\
|
||||
.ace-merbivore .ace_constant.ace_character, {\
|
||||
color:#1EDAFB;\
|
||||
}\
|
||||
\
|
||||
.ace-merbivore .ace_constant.ace_character.ace_escape, {\
|
||||
color:#1EDAFB;\
|
||||
}\
|
||||
\
|
||||
.ace-merbivore .ace_constant.ace_language {\
|
||||
color:#FDC251;\
|
||||
}\
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ exports.cssText = "\
|
|||
}\
|
||||
\
|
||||
.ace-merbivore-soft .ace_cursor {\
|
||||
border-left: 2px solid #FFFFFF;\
|
||||
border-left: 1px solid #FFFFFF;\
|
||||
}\
|
||||
\
|
||||
.ace-merbivore-soft .ace_cursor.ace_overwrite {\
|
||||
border-left: 0px;\
|
||||
border-bottom: 1px solid #FFFFFF;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-merbivore-soft .ace_marker-layer .ace_selection {\
|
||||
background: #494949;\
|
||||
}\
|
||||
|
|
@ -96,7 +96,7 @@ exports.cssText = "\
|
|||
.ace-merbivore-soft .ace_marker-layer .ace_selected_word {\
|
||||
border: 1px solid #494949;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-merbivore-soft .ace_invisible {\
|
||||
color: #404040;\
|
||||
}\
|
||||
|
|
@ -109,6 +109,14 @@ exports.cssText = "\
|
|||
color:#68C1D8;\
|
||||
}\
|
||||
\
|
||||
.ace-merbivore-soft .ace_constant.ace_character, {\
|
||||
color:#68C1D8;\
|
||||
}\
|
||||
\
|
||||
.ace-merbivore-soft .ace_constant.ace_character.ace_escape, {\
|
||||
color:#68C1D8;\
|
||||
}\
|
||||
\
|
||||
.ace-merbivore-soft .ace_constant.ace_language {\
|
||||
color:#E1C582;\
|
||||
}\
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ exports.cssText = "\
|
|||
}\
|
||||
\
|
||||
.ace-mono-industrial .ace_cursor {\
|
||||
border-left: 2px solid #FFFFFF;\
|
||||
border-left: 1px solid #FFFFFF;\
|
||||
}\
|
||||
\
|
||||
.ace-mono-industrial .ace_cursor.ace_overwrite {\
|
||||
border-left: 0px;\
|
||||
border-bottom: 1px solid #FFFFFF;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-mono-industrial .ace_marker-layer .ace_selection {\
|
||||
background: rgba(145, 153, 148, 0.40);\
|
||||
}\
|
||||
|
|
@ -96,7 +96,7 @@ exports.cssText = "\
|
|||
.ace-mono-industrial .ace_marker-layer .ace_selected_word {\
|
||||
border: 1px solid rgba(145, 153, 148, 0.40);\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-mono-industrial .ace_invisible {\
|
||||
color: rgba(102, 108, 104, 0.50);\
|
||||
}\
|
||||
|
|
@ -113,6 +113,14 @@ exports.cssText = "\
|
|||
color:#E98800;\
|
||||
}\
|
||||
\
|
||||
.ace-mono-industrial .ace_constant.ace_character, {\
|
||||
color:#E98800;\
|
||||
}\
|
||||
\
|
||||
.ace-mono-industrial .ace_constant.ace_character.ace_escape, {\
|
||||
color:#E98800;\
|
||||
}\
|
||||
\
|
||||
.ace-mono-industrial .ace_constant.ace_numeric {\
|
||||
color:#E98800;\
|
||||
}\
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ exports.cssText = "\
|
|||
}\
|
||||
\
|
||||
.ace-monokai .ace_cursor {\
|
||||
border-left: 2px solid #F8F8F0;\
|
||||
border-left: 1px solid #F8F8F0;\
|
||||
}\
|
||||
\
|
||||
.ace-monokai .ace_cursor.ace_overwrite {\
|
||||
border-left: 0px;\
|
||||
border-bottom: 1px solid #F8F8F0;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-monokai .ace_marker-layer .ace_selection {\
|
||||
background: #49483E;\
|
||||
}\
|
||||
|
|
@ -96,7 +96,7 @@ exports.cssText = "\
|
|||
.ace-monokai .ace_marker-layer .ace_selected_word {\
|
||||
border: 1px solid #49483E;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-monokai .ace_invisible {\
|
||||
color: #49483E;\
|
||||
}\
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ exports.cssText = "\
|
|||
}\
|
||||
\
|
||||
.ace-pastel-on-dark .ace_cursor {\
|
||||
border-left: 2px solid #A7A7A7;\
|
||||
border-left: 1px solid #A7A7A7;\
|
||||
}\
|
||||
\
|
||||
.ace-pastel-on-dark .ace_cursor.ace_overwrite {\
|
||||
border-left: 0px;\
|
||||
border-bottom: 1px solid #A7A7A7;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-pastel-on-dark .ace_marker-layer .ace_selection {\
|
||||
background: rgba(221, 240, 255, 0.20);\
|
||||
}\
|
||||
|
|
@ -96,7 +96,7 @@ exports.cssText = "\
|
|||
.ace-pastel-on-dark .ace_marker-layer .ace_selected_word {\
|
||||
border: 1px solid rgba(221, 240, 255, 0.20);\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-pastel-on-dark .ace_invisible {\
|
||||
color: rgba(255, 255, 255, 0.25);\
|
||||
}\
|
||||
|
|
@ -113,6 +113,14 @@ exports.cssText = "\
|
|||
color:#4FB7C5;\
|
||||
}\
|
||||
\
|
||||
.ace-pastel-on-dark .ace_constant.ace_character, {\
|
||||
color:#4FB7C5;\
|
||||
}\
|
||||
\
|
||||
.ace-pastel-on-dark .ace_constant.ace_character.ace_escape, {\
|
||||
color:#4FB7C5;\
|
||||
}\
|
||||
\
|
||||
.ace-pastel-on-dark .ace_constant.ace_language {\
|
||||
color:#DE8E30;\
|
||||
}\
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ exports.cssText = "\
|
|||
}\
|
||||
\
|
||||
.ace-solarized-dark .ace_cursor {\
|
||||
border-left: 2px solid #D30102;\
|
||||
border-left: 1px solid #D30102;\
|
||||
}\
|
||||
\
|
||||
.ace-solarized-dark .ace_cursor.ace_overwrite {\
|
||||
border-left: 0px;\
|
||||
border-bottom: 1px solid #D30102;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-solarized-dark .ace_marker-layer .ace_selection {\
|
||||
background: #073642;\
|
||||
}\
|
||||
|
|
@ -96,7 +96,7 @@ exports.cssText = "\
|
|||
.ace-solarized-dark .ace_marker-layer .ace_selected_word {\
|
||||
border: 1px solid #073642;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-solarized-dark .ace_invisible {\
|
||||
color: rgba(147, 161, 161, 0.50);\
|
||||
}\
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ exports.cssText = "\
|
|||
}\
|
||||
\
|
||||
.ace-solarized-light .ace_cursor {\
|
||||
border-left: 2px solid #000000;\
|
||||
border-left: 1px solid #000000;\
|
||||
}\
|
||||
\
|
||||
.ace-solarized-light .ace_cursor.ace_overwrite {\
|
||||
border-left: 0px;\
|
||||
border-bottom: 1px solid #000000;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-solarized-light .ace_marker-layer .ace_selection {\
|
||||
background: #073642;\
|
||||
}\
|
||||
|
|
@ -96,7 +96,7 @@ exports.cssText = "\
|
|||
.ace-solarized-light .ace_marker-layer .ace_selected_word {\
|
||||
border: 1px solid #073642;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-solarized-light .ace_invisible {\
|
||||
color: rgba(147, 161, 161, 0.50);\
|
||||
}\
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ exports.cssText = ".ace-tm .ace_editor {\
|
|||
}\
|
||||
\
|
||||
.ace-tm .ace_cursor {\
|
||||
border-left: 2px solid black;\
|
||||
border-left: 1px solid black;\
|
||||
}\
|
||||
\
|
||||
.ace-tm .ace_cursor.ace_overwrite {\
|
||||
|
|
@ -84,6 +84,10 @@ exports.cssText = ".ace-tm .ace_editor {\
|
|||
color: blue;\
|
||||
}\
|
||||
\
|
||||
.ace-tm .ace_line .ace_constant {\
|
||||
color: rgb(197, 6, 11);\
|
||||
}\
|
||||
\
|
||||
.ace-tm .ace_line .ace_constant.ace_buildin {\
|
||||
color: rgb(88, 72, 246);\
|
||||
}\
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ exports.cssText = "\
|
|||
}\
|
||||
\
|
||||
.ace-tomorrow .ace_cursor {\
|
||||
border-left: 2px solid #AEAFAD;\
|
||||
border-left: 1px solid #AEAFAD;\
|
||||
}\
|
||||
\
|
||||
.ace-tomorrow .ace_cursor.ace_overwrite {\
|
||||
border-left: 0px;\
|
||||
border-bottom: 1px solid #AEAFAD;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-tomorrow .ace_marker-layer .ace_selection {\
|
||||
background: #D6D6D6;\
|
||||
}\
|
||||
|
|
@ -96,7 +96,7 @@ exports.cssText = "\
|
|||
.ace-tomorrow .ace_marker-layer .ace_selected_word {\
|
||||
border: 1px solid #D6D6D6;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-tomorrow .ace_invisible {\
|
||||
color: #D1D1D1;\
|
||||
}\
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ exports.cssText = "\
|
|||
}\
|
||||
\
|
||||
.ace-tomorrow-night .ace_cursor {\
|
||||
border-left: 2px solid #AEAFAD;\
|
||||
border-left: 1px solid #AEAFAD;\
|
||||
}\
|
||||
\
|
||||
.ace-tomorrow-night .ace_cursor.ace_overwrite {\
|
||||
border-left: 0px;\
|
||||
border-bottom: 1px solid #AEAFAD;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-tomorrow-night .ace_marker-layer .ace_selection {\
|
||||
background: #373B41;\
|
||||
}\
|
||||
|
|
@ -96,7 +96,7 @@ exports.cssText = "\
|
|||
.ace-tomorrow-night .ace_marker-layer .ace_selected_word {\
|
||||
border: 1px solid #373B41;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-tomorrow-night .ace_invisible {\
|
||||
color: #4B4E55;\
|
||||
}\
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ exports.cssText = "\
|
|||
}\
|
||||
\
|
||||
.ace-tomorrow-night-blue .ace_cursor {\
|
||||
border-left: 2px solid #FFFFFF;\
|
||||
border-left: 1px solid #FFFFFF;\
|
||||
}\
|
||||
\
|
||||
.ace-tomorrow-night-blue .ace_cursor.ace_overwrite {\
|
||||
border-left: 0px;\
|
||||
border-bottom: 1px solid #FFFFFF;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-tomorrow-night-blue .ace_marker-layer .ace_selection {\
|
||||
background: #003F8E;\
|
||||
}\
|
||||
|
|
@ -96,7 +96,7 @@ exports.cssText = "\
|
|||
.ace-tomorrow-night-blue .ace_marker-layer .ace_selected_word {\
|
||||
border: 1px solid #003F8E;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-tomorrow-night-blue .ace_invisible {\
|
||||
color: #404F7D;\
|
||||
}\
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ exports.cssText = "\
|
|||
}\
|
||||
\
|
||||
.ace-tomorrow-night-bright .ace_cursor {\
|
||||
border-left: 2px solid #9F9F9F;\
|
||||
border-left: 1px solid #9F9F9F;\
|
||||
}\
|
||||
\
|
||||
.ace-tomorrow-night-bright .ace_cursor.ace_overwrite {\
|
||||
border-left: 0px;\
|
||||
border-bottom: 1px solid #9F9F9F;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-tomorrow-night-bright .ace_marker-layer .ace_selection {\
|
||||
background: #424242;\
|
||||
}\
|
||||
|
|
@ -96,7 +96,7 @@ exports.cssText = "\
|
|||
.ace-tomorrow-night-bright .ace_marker-layer .ace_selected_word {\
|
||||
border: 1px solid #424242;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-tomorrow-night-bright .ace_invisible {\
|
||||
color: #343434;\
|
||||
}\
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ exports.cssText = "\
|
|||
}\
|
||||
\
|
||||
.ace-tomorrow-night-eighties .ace_cursor {\
|
||||
border-left: 2px solid #CCCCCC;\
|
||||
border-left: 1px solid #CCCCCC;\
|
||||
}\
|
||||
\
|
||||
.ace-tomorrow-night-eighties .ace_cursor.ace_overwrite {\
|
||||
border-left: 0px;\
|
||||
border-bottom: 1px solid #CCCCCC;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-tomorrow-night-eighties .ace_marker-layer .ace_selection {\
|
||||
background: #515151;\
|
||||
}\
|
||||
|
|
@ -96,7 +96,7 @@ exports.cssText = "\
|
|||
.ace-tomorrow-night-eighties .ace_marker-layer .ace_selected_word {\
|
||||
border: 1px solid #515151;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-tomorrow-night-eighties .ace_invisible {\
|
||||
color: #6A6A6A;\
|
||||
}\
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ exports.cssText = "\
|
|||
}\
|
||||
\
|
||||
.ace-twilight .ace_cursor {\
|
||||
border-left: 2px solid #A7A7A7;\
|
||||
border-left: 1px solid #A7A7A7;\
|
||||
}\
|
||||
\
|
||||
.ace-twilight .ace_cursor.ace_overwrite {\
|
||||
border-left: 0px;\
|
||||
border-bottom: 1px solid #A7A7A7;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-twilight .ace_marker-layer .ace_selection {\
|
||||
background: rgba(221, 240, 255, 0.20);\
|
||||
}\
|
||||
|
|
@ -96,7 +96,7 @@ exports.cssText = "\
|
|||
.ace-twilight .ace_marker-layer .ace_selected_word {\
|
||||
border: 1px solid rgba(221, 240, 255, 0.20);\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-twilight .ace_invisible {\
|
||||
color: rgba(255, 255, 255, 0.25);\
|
||||
}\
|
||||
|
|
@ -109,6 +109,14 @@ exports.cssText = "\
|
|||
color:#CF6A4C;\
|
||||
}\
|
||||
\
|
||||
.ace-twilight .ace_constant.ace_character, {\
|
||||
color:#CF6A4C;\
|
||||
}\
|
||||
\
|
||||
.ace-twilight .ace_constant.ace_character.ace_escape, {\
|
||||
color:#CF6A4C;\
|
||||
}\
|
||||
\
|
||||
.ace-twilight .ace_invalid.ace_illegal {\
|
||||
color:#F8F8F8;\
|
||||
background-color:rgba(86, 45, 86, 0.75);\
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ exports.cssText = "\
|
|||
}\
|
||||
\
|
||||
.ace-vibrant-ink .ace_cursor {\
|
||||
border-left: 2px solid #FFFFFF;\
|
||||
border-left: 1px solid #FFFFFF;\
|
||||
}\
|
||||
\
|
||||
.ace-vibrant-ink .ace_cursor.ace_overwrite {\
|
||||
border-left: 0px;\
|
||||
border-bottom: 1px solid #FFFFFF;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-vibrant-ink .ace_marker-layer .ace_selection {\
|
||||
background: #6699CC;\
|
||||
}\
|
||||
|
|
@ -96,7 +96,7 @@ exports.cssText = "\
|
|||
.ace-vibrant-ink .ace_marker-layer .ace_selected_word {\
|
||||
border: 1px solid #6699CC;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
.ace-vibrant-ink .ace_invisible {\
|
||||
color: #404040;\
|
||||
}\
|
||||
|
|
@ -109,6 +109,14 @@ exports.cssText = "\
|
|||
color:#339999;\
|
||||
}\
|
||||
\
|
||||
.ace-vibrant-ink .ace_constant.ace_character, {\
|
||||
color:#339999;\
|
||||
}\
|
||||
\
|
||||
.ace-vibrant-ink .ace_constant.ace_character.ace_escape, {\
|
||||
color:#339999;\
|
||||
}\
|
||||
\
|
||||
.ace-vibrant-ink .ace_constant.ace_numeric {\
|
||||
color:#99CC99;\
|
||||
}\
|
||||
|
|
|
|||
|
|
@ -56,17 +56,17 @@ module.exports = {
|
|||
" } // Real Tab.",
|
||||
"}"
|
||||
];
|
||||
var session = new EditSession(lines.join("\n"), new JavaScriptMode());
|
||||
var session = new EditSession(lines.join("\n"), new JavaScriptMode());
|
||||
|
||||
var iterator = new TokenIterator(session, 0, 0);
|
||||
assert.equal(iterator.getCurrentToken().value, "function");
|
||||
assert.equal(iterator.getCurrentTokenRow(), 0);
|
||||
assert.equal(iterator.getCurrentTokenColumn(), 0);
|
||||
|
||||
|
||||
iterator.stepForward();
|
||||
assert.equal(iterator.getCurrentToken().value, " ");
|
||||
assert.equal(iterator.getCurrentTokenRow(), 0);
|
||||
assert.equal(iterator.getCurrentTokenColumn(), 8);
|
||||
assert.equal(iterator.getCurrentTokenColumn(), 8);
|
||||
|
||||
var iterator = new TokenIterator(session, 0, 4);
|
||||
assert.equal(iterator.getCurrentToken().value, "function");
|
||||
|
|
@ -76,7 +76,7 @@ module.exports = {
|
|||
iterator.stepForward();
|
||||
assert.equal(iterator.getCurrentToken().value, " ");
|
||||
assert.equal(iterator.getCurrentTokenRow(), 0);
|
||||
assert.equal(iterator.getCurrentTokenColumn(), 8);
|
||||
assert.equal(iterator.getCurrentTokenColumn(), 8);
|
||||
|
||||
var iterator = new TokenIterator(session, 2, 18);
|
||||
assert.equal(iterator.getCurrentToken().value, "items");
|
||||
|
|
@ -86,8 +86,8 @@ module.exports = {
|
|||
iterator.stepForward();
|
||||
assert.equal(iterator.getCurrentToken().value, "[");
|
||||
assert.equal(iterator.getCurrentTokenRow(), 2);
|
||||
assert.equal(iterator.getCurrentTokenColumn(), 19);
|
||||
|
||||
assert.equal(iterator.getCurrentTokenColumn(), 19);
|
||||
|
||||
var iterator = new TokenIterator(session, 4, 0);
|
||||
assert.equal(iterator.getCurrentToken().value, "}");
|
||||
assert.equal(iterator.getCurrentTokenRow(), 4);
|
||||
|
|
@ -96,21 +96,21 @@ module.exports = {
|
|||
iterator.stepBackward();
|
||||
assert.equal(iterator.getCurrentToken().value, "// Real Tab.");
|
||||
assert.equal(iterator.getCurrentTokenRow(), 3);
|
||||
assert.equal(iterator.getCurrentTokenColumn(), 6);
|
||||
|
||||
assert.equal(iterator.getCurrentTokenColumn(), 6);
|
||||
|
||||
var iterator = new TokenIterator(session, 5, 0);
|
||||
assert.equal(iterator.getCurrentToken(), null);
|
||||
},
|
||||
|
||||
|
||||
"test: token iterator initialization in text document" : function() {
|
||||
var lines = [
|
||||
"Lorem ipsum dolor sit amet, consectetur adipisicing elit,",
|
||||
"Lorem ipsum dolor sit amet, consectetur adipisicing elit,",
|
||||
"sed do eiusmod tempor incididunt ut labore et dolore magna",
|
||||
"aliqua. Ut enim ad minim veniam, quis nostrud exercitation",
|
||||
"aliqua. Ut enim ad minim veniam, quis nostrud exercitation",
|
||||
"ullamco laboris nisi ut aliquip ex ea commodo consequat."
|
||||
];
|
||||
var session = new EditSession(lines.join("\n"));
|
||||
|
||||
|
||||
var iterator = new TokenIterator(session, 0, 0);
|
||||
assert.equal(iterator.getCurrentToken().value, lines[0]);
|
||||
assert.equal(iterator.getCurrentTokenRow(), 0);
|
||||
|
|
@ -125,16 +125,16 @@ module.exports = {
|
|||
assert.equal(iterator.getCurrentToken().value, lines[2]);
|
||||
assert.equal(iterator.getCurrentTokenRow(), 2);
|
||||
assert.equal(iterator.getCurrentTokenColumn(), 0);
|
||||
|
||||
|
||||
var iterator = new TokenIterator(session, 3, lines[3].length-1);
|
||||
assert.equal(iterator.getCurrentToken().value, lines[3]);
|
||||
assert.equal(iterator.getCurrentTokenRow(), 3);
|
||||
assert.equal(iterator.getCurrentTokenColumn(), 0);
|
||||
|
||||
|
||||
var iterator = new TokenIterator(session, 4, 0);
|
||||
assert.equal(iterator.getCurrentToken(), null);
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
"test: token iterator step forward in JavaScript document" : function() {
|
||||
var lines = [
|
||||
"function foo(items) {",
|
||||
|
|
@ -143,10 +143,10 @@ module.exports = {
|
|||
" } // Real Tab.",
|
||||
"}"
|
||||
];
|
||||
var session = new EditSession(lines.join("\n"), new JavaScriptMode());
|
||||
|
||||
var session = new EditSession(lines.join("\n"), new JavaScriptMode());
|
||||
|
||||
var rows = session.getTokens(0, lines.length-1);
|
||||
var tokens = [];
|
||||
var tokens = [];
|
||||
for (var i = 0; i < rows.length; i++)
|
||||
tokens = tokens.concat(rows[i].tokens);
|
||||
|
||||
|
|
@ -156,7 +156,7 @@ module.exports = {
|
|||
assert.equal(iterator.stepForward(), null);
|
||||
assert.equal(iterator.getCurrentToken(), null);
|
||||
},
|
||||
|
||||
|
||||
"test: token iterator step backward in JavaScript document" : function() {
|
||||
var lines = [
|
||||
"function foo(items) {",
|
||||
|
|
@ -165,13 +165,13 @@ module.exports = {
|
|||
" } // Real Tab.",
|
||||
"}"
|
||||
];
|
||||
var session = new EditSession(lines.join("\n"), new JavaScriptMode());
|
||||
var session = new EditSession(lines.join("\n"), new JavaScriptMode());
|
||||
|
||||
var rows = session.getTokens(0, lines.length-1);
|
||||
var tokens = [];
|
||||
var tokens = [];
|
||||
for (var i = 0; i < rows.length; i++)
|
||||
tokens = tokens.concat(rows[i].tokens);
|
||||
|
||||
|
||||
var iterator = new TokenIterator(session, 4, 0);
|
||||
for (var i = tokens.length-2; i >= 0; i--)
|
||||
assert.equal(iterator.stepBackward(), tokens[i]);
|
||||
|
|
@ -187,13 +187,13 @@ module.exports = {
|
|||
" } // Real Tab.",
|
||||
"}"
|
||||
];
|
||||
var session = new EditSession(lines.join("\n"), new JavaScriptMode());
|
||||
var session = new EditSession(lines.join("\n"), new JavaScriptMode());
|
||||
|
||||
var iterator = new TokenIterator(session, 0, 0);
|
||||
|
||||
|
||||
iterator.stepForward();
|
||||
iterator.stepForward();
|
||||
|
||||
|
||||
assert.equal(iterator.getCurrentToken().value, "foo");
|
||||
assert.equal(iterator.getCurrentTokenRow(), 0);
|
||||
assert.equal(iterator.getCurrentTokenColumn(), 9);
|
||||
|
|
@ -205,8 +205,7 @@ module.exports = {
|
|||
iterator.stepForward();
|
||||
iterator.stepForward();
|
||||
iterator.stepForward();
|
||||
iterator.stepForward();
|
||||
|
||||
|
||||
assert.equal(iterator.getCurrentToken().value, "for");
|
||||
assert.equal(iterator.getCurrentTokenRow(), 1);
|
||||
assert.equal(iterator.getCurrentTokenColumn(), 4);
|
||||
|
|
|
|||
|
|
@ -50,23 +50,30 @@ var Tokenizer = function(rules, flag) {
|
|||
var ruleRegExps = [];
|
||||
var matchTotal = 0;
|
||||
var mapping = this.matchMappings[key] = {};
|
||||
|
||||
|
||||
for ( var i = 0; i < state.length; i++) {
|
||||
|
||||
if (state[i].regex instanceof RegExp)
|
||||
state[i].regex = state[i].regex.toString().slice(1, -1);
|
||||
|
||||
// Count number of matching groups. 2 extra groups from the full match
|
||||
// And the catch-all on the end (used to force a match);
|
||||
var matchcount = new RegExp("(?:(" + state[i].regex + ")|(.))").exec("a").length - 2;
|
||||
|
||||
|
||||
// Replace any backreferences and offset appropriately.
|
||||
var adjustedregex = state[i].regex.replace(/\\([0-9]+)/g, function (match, digit) {
|
||||
return "\\" + (parseInt(digit, 10) + matchTotal + 1);
|
||||
});
|
||||
|
||||
|
||||
if (matchcount > 1 && state[i].token.length !== matchcount-1)
|
||||
throw new Error("Matching groups and length of the token array don't match in rule #" + i + " of state " + key);
|
||||
|
||||
mapping[matchTotal] = {
|
||||
rule: i,
|
||||
len: matchcount
|
||||
};
|
||||
matchTotal += matchcount;
|
||||
|
||||
|
||||
ruleRegExps.push(adjustedregex);
|
||||
}
|
||||
|
||||
|
|
@ -82,47 +89,47 @@ var Tokenizer = function(rules, flag) {
|
|||
var mapping = this.matchMappings[currentState];
|
||||
var re = this.regExps[currentState];
|
||||
re.lastIndex = 0;
|
||||
|
||||
|
||||
var match, tokens = [];
|
||||
|
||||
|
||||
var lastIndex = 0;
|
||||
|
||||
|
||||
var token = {
|
||||
type: null,
|
||||
value: ""
|
||||
};
|
||||
|
||||
|
||||
while (match = re.exec(line)) {
|
||||
var type = "text";
|
||||
var rule = null;
|
||||
var value = [match[0]];
|
||||
|
||||
for (var i = 0; i < match.length-2; i++) {
|
||||
if (match[i + 1] !== undefined) {
|
||||
rule = state[mapping[i].rule];
|
||||
|
||||
if (mapping[i].len > 1) {
|
||||
value = match.slice(i+2, i+1+mapping[i].len);
|
||||
}
|
||||
|
||||
// compute token type
|
||||
if (typeof rule.token == "function")
|
||||
type = rule.token.apply(this, value);
|
||||
else
|
||||
type = rule.token;
|
||||
if (match[i + 1] === undefined)
|
||||
continue;
|
||||
|
||||
var next = rule.next;
|
||||
if (next && next !== currentState) {
|
||||
currentState = next;
|
||||
state = this.rules[currentState];
|
||||
mapping = this.matchMappings[currentState];
|
||||
lastIndex = re.lastIndex;
|
||||
rule = state[mapping[i].rule];
|
||||
|
||||
re = this.regExps[currentState];
|
||||
re.lastIndex = lastIndex;
|
||||
}
|
||||
break;
|
||||
if (mapping[i].len > 1)
|
||||
value = match.slice(i+2, i+1+mapping[i].len);
|
||||
|
||||
// compute token type
|
||||
if (typeof rule.token == "function")
|
||||
type = rule.token.apply(this, value);
|
||||
else
|
||||
type = rule.token;
|
||||
|
||||
var next = rule.next;
|
||||
if (next && next !== currentState) {
|
||||
currentState = next;
|
||||
state = this.rules[currentState];
|
||||
mapping = this.matchMappings[currentState];
|
||||
lastIndex = re.lastIndex;
|
||||
|
||||
re = this.regExps[currentState];
|
||||
re.lastIndex = lastIndex;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (value[0]) {
|
||||
|
|
@ -131,13 +138,15 @@ var Tokenizer = function(rules, flag) {
|
|||
type = [type];
|
||||
}
|
||||
for (var i = 0; i < value.length; i++) {
|
||||
if (!value[i])
|
||||
continue;
|
||||
|
||||
if ((!rule || rule.merge || type[i] === "text") && token.type === type[i]) {
|
||||
token.value += value[i];
|
||||
} else {
|
||||
if (token.type) {
|
||||
if (token.type)
|
||||
tokens.push(token);
|
||||
}
|
||||
|
||||
|
||||
token = {
|
||||
type: type[i],
|
||||
value: value[i]
|
||||
|
|
@ -145,10 +154,10 @@ var Tokenizer = function(rules, flag) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (lastIndex == line.length)
|
||||
break;
|
||||
|
||||
|
||||
lastIndex = re.lastIndex;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,13 +60,13 @@ dom.importCssString(editorCss, "ace_editor");
|
|||
|
||||
var VirtualRenderer = function(container, theme) {
|
||||
var _self = this;
|
||||
|
||||
|
||||
this.container = container;
|
||||
|
||||
// TODO: this breaks rendering in Cloud9 with multiple ace instances
|
||||
// // Imports CSS once per DOM document ('ace_editor' serves as an identifier).
|
||||
// dom.importCssString(editorCss, "ace_editor", container.ownerDocument);
|
||||
|
||||
|
||||
dom.addCssClass(container, "ace_editor");
|
||||
|
||||
this.setTheme(theme);
|
||||
|
|
@ -84,8 +84,8 @@ var VirtualRenderer = function(container, theme) {
|
|||
this.scroller.appendChild(this.content);
|
||||
|
||||
this.$gutterLayer = new GutterLayer(this.$gutter);
|
||||
this.$gutterLayer.on("changeGutterWidth", this.onResize.bind(this, true));
|
||||
|
||||
this.$gutterLayer.on("changeGutterWidth", this.onResize.bind(this, true));
|
||||
|
||||
this.$markerBack = new MarkerLayer(this.content);
|
||||
|
||||
var textLayer = this.$textLayer = new TextLayer(this.content);
|
||||
|
|
@ -103,6 +103,8 @@ var VirtualRenderer = function(container, theme) {
|
|||
this.$horizScroll = true;
|
||||
this.$horizScrollAlwaysVisible = true;
|
||||
|
||||
this.$animatedScroll = false;
|
||||
|
||||
this.scrollBar = new ScrollBar(container);
|
||||
this.scrollBar.addEventListener("scroll", function(e) {
|
||||
_self.session.setScrollTop(e.data);
|
||||
|
|
@ -110,11 +112,18 @@ var VirtualRenderer = function(container, theme) {
|
|||
|
||||
this.scrollTop = 0;
|
||||
this.scrollLeft = 0;
|
||||
|
||||
|
||||
event.addListener(this.scroller, "scroll", function() {
|
||||
var scrollLeft = _self.scroller.scrollLeft;
|
||||
_self.scrollLeft = scrollLeft;
|
||||
_self.session.setScrollLeft(scrollLeft);
|
||||
|
||||
if (scrollLeft == 0) {
|
||||
_self.$gutter.className = "ace_gutter";
|
||||
}
|
||||
else {
|
||||
_self.$gutter.className = "ace_gutter horscroll";
|
||||
}
|
||||
});
|
||||
|
||||
this.cursorPos = {
|
||||
|
|
@ -274,6 +283,14 @@ var VirtualRenderer = function(container, theme) {
|
|||
return this.session.adjustWrapLimit(limit);
|
||||
};
|
||||
|
||||
this.setAnimatedScroll = function(shouldAnimate){
|
||||
this.$animatedScroll = shouldAnimate;
|
||||
};
|
||||
|
||||
this.getAnimatedScroll = function() {
|
||||
return this.$animatedScroll;
|
||||
};
|
||||
|
||||
this.setShowInvisibles = function(showInvisibles) {
|
||||
if (this.$textLayer.setShowInvisibles(showInvisibles))
|
||||
this.$loop.schedule(this.CHANGE_TEXT);
|
||||
|
|
@ -352,7 +369,7 @@ var VirtualRenderer = function(container, theme) {
|
|||
// this persists in IE9
|
||||
if (useragent.isIE)
|
||||
return;
|
||||
|
||||
|
||||
if (this.layerConfig.lastRow === 0)
|
||||
return;
|
||||
|
||||
|
|
@ -428,13 +445,13 @@ var VirtualRenderer = function(container, theme) {
|
|||
// horizontal scrolling
|
||||
if (changes & this.CHANGE_H_SCROLL) {
|
||||
this.scroller.scrollLeft = this.scrollLeft;
|
||||
|
||||
|
||||
// read the value after writing it since the value might get clipped
|
||||
var scrollLeft = this.scroller.scrollLeft;
|
||||
this.scrollLeft = scrollLeft;
|
||||
this.session.setScrollLeft(scrollLeft);
|
||||
}
|
||||
|
||||
|
||||
// full
|
||||
if (changes & this.CHANGE_FULL) {
|
||||
this.$textLayer.checkForSizeChanges();
|
||||
|
|
@ -647,12 +664,18 @@ var VirtualRenderer = function(container, theme) {
|
|||
this.$cursorLayer.showCursor();
|
||||
};
|
||||
|
||||
this.scrollCursorIntoView = function() {
|
||||
this.scrollSelectionIntoView = function(anchor, lead) {
|
||||
// first scroll anchor into view then scroll lead into view
|
||||
this.scrollCursorIntoView(anchor);
|
||||
this.scrollCursorIntoView(lead);
|
||||
};
|
||||
|
||||
this.scrollCursorIntoView = function(cursor) {
|
||||
// the editor is not visible
|
||||
if (this.$size.scrollerHeight === 0)
|
||||
return;
|
||||
|
||||
var pos = this.$cursorLayer.getPixelPosition();
|
||||
var pos = this.$cursorLayer.getPixelPosition(cursor);
|
||||
|
||||
var left = pos.left;
|
||||
var top = pos.top;
|
||||
|
|
@ -698,13 +721,46 @@ var VirtualRenderer = function(container, theme) {
|
|||
this.session.setScrollTop(row * this.lineHeight);
|
||||
};
|
||||
|
||||
this.STEPS = 10;
|
||||
this.$calcSteps = function(fromValue, toValue){
|
||||
var i = 0;
|
||||
var l = this.STEPS;
|
||||
var steps = [];
|
||||
|
||||
var func = function(t, x_min, dx) {
|
||||
if ((t /= .5) < 1)
|
||||
return dx / 2 * Math.pow(t, 3) + x_min;
|
||||
return dx / 2 * (Math.pow(t - 2, 3) + 2) + x_min;
|
||||
};
|
||||
|
||||
for (i = 0; i < l; ++i)
|
||||
steps.push(func(i / this.STEPS, fromValue, toValue - fromValue));
|
||||
steps.push(toValue);
|
||||
|
||||
return steps;
|
||||
};
|
||||
|
||||
this.scrollToLine = function(line, center) {
|
||||
var pos = this.$cursorLayer.getPixelPosition({row: line, column: 0});
|
||||
var offset = pos.top;
|
||||
if (center)
|
||||
offset -= this.$size.scrollerHeight / 2;
|
||||
|
||||
this.session.setScrollTop(offset);
|
||||
if (this.$animatedScroll && Math.abs(offset - this.scrollTop) < 10000) {
|
||||
var _self = this;
|
||||
var steps = _self.$calcSteps(this.scrollTop, offset);
|
||||
|
||||
clearInterval(this.$timer);
|
||||
this.$timer = setInterval(function() {
|
||||
_self.session.setScrollTop(steps.shift());
|
||||
|
||||
if (!steps.length)
|
||||
clearInterval(_self.$timer);
|
||||
}, 10);
|
||||
}
|
||||
else {
|
||||
this.session.setScrollTop(offset);
|
||||
}
|
||||
};
|
||||
|
||||
this.scrollToY = function(scrollTop) {
|
||||
|
|
@ -738,6 +794,19 @@ var VirtualRenderer = function(container, theme) {
|
|||
// todo: handle horizontal scrolling
|
||||
};
|
||||
|
||||
this.pixelToScreenCoordinates = function(pageX, pageY) {
|
||||
var canvasPos = this.scroller.getBoundingClientRect();
|
||||
|
||||
var col = Math.round(
|
||||
(pageX + this.scrollLeft - canvasPos.left - this.$padding - dom.getPageScrollLeft()) / this.characterWidth
|
||||
);
|
||||
var row = Math.floor(
|
||||
(pageY + this.scrollTop - canvasPos.top - dom.getPageScrollTop()) / this.lineHeight
|
||||
);
|
||||
|
||||
return {row: row, column: col};
|
||||
};
|
||||
|
||||
this.screenToTextCoordinates = function(pageX, pageY) {
|
||||
var canvasPos = this.scroller.getBoundingClientRect();
|
||||
|
||||
|
|
@ -808,7 +877,7 @@ var VirtualRenderer = function(container, theme) {
|
|||
this._loadTheme = function(name, callback) {
|
||||
if (!config.get("packaged"))
|
||||
return callback();
|
||||
|
||||
|
||||
var base = name.split("/").pop();
|
||||
var filename = config.get("themePath") + "/theme-" + base + config.get("suffix");
|
||||
net.loadScript(filename, callback);
|
||||
|
|
@ -820,16 +889,16 @@ var VirtualRenderer = function(container, theme) {
|
|||
this.$themeValue = theme;
|
||||
if (!theme || typeof theme == "string") {
|
||||
var moduleName = theme || "ace/theme/textmate";
|
||||
|
||||
|
||||
var module;
|
||||
try {
|
||||
module = require(moduleName);
|
||||
} catch (e) {};
|
||||
if (module)
|
||||
return afterLoad(module);
|
||||
|
||||
|
||||
_self._loadTheme(moduleName, function() {
|
||||
require([theme], function(module) {
|
||||
require([moduleName], function(module) {
|
||||
if (_self.$themeValue !== theme)
|
||||
return;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue