From fad075ad37852624519f74bef5a33f41d015e624 Mon Sep 17 00:00:00 2001 From: Dmitry Vasilev Date: Sat, 10 Sep 2022 02:48:13 +0800 Subject: [PATCH] initial --- .gitignore | 1 + README.md | 117 + ace/ace.js | 21816 ++++++++++++++++++++++++++++++++ ace/ext-searchbox.js | 8 + ace/keybinding-vim.js | 5895 +++++++++ ace/mode-javascript.js | 797 ++ docs/images/background.png | Bin 0 -> 16072 bytes docs/images/edit.gif | Bin 0 -> 25562 bytes docs/images/error.png | Bin 0 -> 30896 bytes docs/images/exec.png | Bin 0 -> 54506 bytes docs/images/follow_cursor.gif | Bin 0 -> 26109 bytes docs/images/immutable.png | Bin 0 -> 23224 bytes docs/images/inspect.gif | Bin 0 -> 21725 bytes docs/images/mutation.png | Bin 0 -> 17319 bytes docs/images/nav.gif | Bin 0 -> 55681 bytes docs/images/self-hosted.png | Bin 0 -> 238095 bytes docs/images/test.png | Bin 0 -> 224614 bytes index.html | 347 + package.json | 3 + service_worker.js | 30 + src/ast_utils.js | 167 + src/calltree.js | 782 ++ src/cmd.js | 661 + src/color.js | 214 + src/editor/calltree.js | 173 + src/editor/domutils.js | 117 + src/editor/editor.js | 469 + src/editor/eval.js | 67 + src/editor/files.js | 164 + src/editor/ui.js | 267 + src/editor/value_explorer.js | 356 + src/effects.js | 232 + src/eval.js | 1224 ++ src/feature_flags.js | 3 + src/filesystem.js | 135 + src/find_definitions.js | 304 + src/globals.js | 39 + src/index.js | 112 + src/parse_js.js | 1633 +++ src/reserved.js | 48 + src/utils.js | 95 + test/run.js | 4 + test/self_hosted_test.js | 82 + test/test.js | 1998 +++ test/utils.js | 141 + 45 files changed, 38501 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 ace/ace.js create mode 100644 ace/ext-searchbox.js create mode 100644 ace/keybinding-vim.js create mode 100644 ace/mode-javascript.js create mode 100644 docs/images/background.png create mode 100644 docs/images/edit.gif create mode 100644 docs/images/error.png create mode 100644 docs/images/exec.png create mode 100644 docs/images/follow_cursor.gif create mode 100644 docs/images/immutable.png create mode 100644 docs/images/inspect.gif create mode 100644 docs/images/mutation.png create mode 100644 docs/images/nav.gif create mode 100644 docs/images/self-hosted.png create mode 100644 docs/images/test.png create mode 100644 index.html create mode 100644 package.json create mode 100644 service_worker.js create mode 100644 src/ast_utils.js create mode 100644 src/calltree.js create mode 100644 src/cmd.js create mode 100644 src/color.js create mode 100644 src/editor/calltree.js create mode 100644 src/editor/domutils.js create mode 100644 src/editor/editor.js create mode 100644 src/editor/eval.js create mode 100644 src/editor/files.js create mode 100644 src/editor/ui.js create mode 100644 src/editor/value_explorer.js create mode 100644 src/effects.js create mode 100644 src/eval.js create mode 100644 src/feature_flags.js create mode 100644 src/filesystem.js create mode 100644 src/find_definitions.js create mode 100644 src/globals.js create mode 100644 src/index.js create mode 100644 src/parse_js.js create mode 100644 src/reserved.js create mode 100644 src/utils.js create mode 100644 test/run.js create mode 100644 test/self_hosted_test.js create mode 100644 test/test.js create mode 100644 test/utils.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..daa30a3 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +README.html diff --git a/README.md b/README.md new file mode 100644 index 0000000..270f234 --- /dev/null +++ b/README.md @@ -0,0 +1,117 @@ +# Leporello.js + +Leporello.js is live coding IDE for pure functional subset of javascript. It provides novel debugging experience + +## **[Try online](https://leporello-js.github.io/leporello-js/)** + +## Features + +- Mutating values is not allowed +![Mutating](docs/images/mutation.png) + +- All values are immutable. You create new values by applying change to old values +![Immutable](docs/images/immutable.png) + +- Functional programs are trees of expressions that map values to other values, + rather than a sequence of imperative statements which update the running + state of the program. Because data is never mutated, you can jump to any + point in execution of your program +![Navigation](docs/images/nav.gif) + +- and inspect any intermediate values +![Inspect](docs/images/inspect.gif) + +- Expressions that were evaluated have blue background. And that were not reached +have white background. +![Background](docs/images/background.png) + +- Expressions that throw errors are red +![Errors](docs/images/error.png) + +- When you put cursor inside function, the first call of this function is found +![Follow cursor](docs/images/follow_cursor.gif) + +- You can edit this function and immediately see result +![Live coding](docs/images/edit.gif) + +- Leporello is (mostly) self-hosted, i.e. built in itself +![Self-hosted](docs/images/self-hosted.png) + + +## Supported javascript subset + +Variables are declared by `const` declaration. `var` is not supported. `let` variables can be declared to be assigned later, for cases when value depends on condition. Example: +``` +let result +if (n == 0 || n == 1) { + result = n +} else { + result = fib(n - 1) + fib(n - 2) +} +``` + +Currenlty only one declaration for single `const` statement is supported (TODO). + +Any kind of loops are not supported. Use recursion or array functions instead. + +`if` / `else` can only contain blocks, not single statements (TODO). + +Functions can be declared only by arrow function syntax. `function` keyword and method definitions (like `const foo = { bar() { /* body */ } }` may be supported in future. Both concise and block body are supported. + +Classes are not supported. Some sort of immutable classes may be supported in future. `this` keyword is not currently supported. `new` operator is supported for instantiating builtin classes. + +`switch` statements will be supported in future. + +`try`, `catch` and `finally` will be supported in future. `throw` is currently supported. + +ES6 modules are suppoted. Default exports are not currently supported, only named exports. Circular module dependencies are not supported (currently they crash IDE (TODO)). Import/export aliases are not supported. Exporting `let` variables is not supported. `import.meta` is not supported. + +Generators are not supported. + +Async/await will be supported in future. + +Destructuring is mostly supported. + +Some operators are not currently supported: + - Unary negation, unary plus + - Bitwise operators + - `in`, `instanceof` + - `void` + - comma operator + +Operators that are not supported by design (not pure functional): + - increment, decrement + - `delete` + +## Hotkeys + +See built-in Help + +## Editing local files + +Editing local files is possible via [File System Access API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API). Click "Allow access to local project folder" to grant access to local directory. + + +## Run Leporello locally +To run it locally, you need to clone repo to local folder and serve it via HTTPS protocol (HTTPS is required by [File System Access API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API)). See [How to use HTTPS for local development](https://web.dev/how-to-use-local-https/) + +## Running test suite +run tests in node.js: + +``` +node test/run.js +``` + +run tests in leporello itself: +![Tests](docs/images/test.png) + +- grant local folder access +- select `test/run.js` as entrypoint + + +## Roadmap + +* Support async/await and calling impure (performing IO) functions +* Use production level JS parser, probably typescript parser (so it will be + possible to program in pure functional subset of typescript) +* Implement VSCode plugin diff --git a/ace/ace.js b/ace/ace.js new file mode 100644 index 0000000..c14c592 --- /dev/null +++ b/ace/ace.js @@ -0,0 +1,21816 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +/** + * Define a module along with a payload + * @param module a name for the payload + * @param payload a function to call with (require, exports, module) params + */ + +(function() { + +var ACE_NAMESPACE = ""; + +var global = (function() { return this; })(); +if (!global && typeof window != "undefined") global = window; // strict mode + + +if (!ACE_NAMESPACE && typeof requirejs !== "undefined") + return; + + +var define = function(module, deps, payload) { + if (typeof module !== "string") { + if (define.original) + define.original.apply(this, arguments); + else { + console.error("dropping module because define wasn\'t a string."); + console.trace(); + } + return; + } + if (arguments.length == 2) + payload = deps; + if (!define.modules[module]) { + define.payloads[module] = payload; + define.modules[module] = null; + } +}; + +define.modules = {}; +define.payloads = {}; + +/** + * Get at functionality define()ed using the function above + */ +var _require = function(parentId, module, callback) { + if (typeof module === "string") { + var payload = lookup(parentId, module); + if (payload != undefined) { + callback && callback(); + return payload; + } + } else if (Object.prototype.toString.call(module) === "[object Array]") { + var params = []; + for (var i = 0, l = module.length; i < l; ++i) { + var dep = lookup(parentId, module[i]); + if (dep == undefined && require.original) + return; + params.push(dep); + } + return callback && callback.apply(null, params) || true; + } +}; + +var require = function(module, callback) { + var packagedModule = _require("", module, callback); + if (packagedModule == undefined && require.original) + return require.original.apply(this, arguments); + return packagedModule; +}; + +var normalizeModule = function(parentId, moduleName) { + // normalize plugin requires + if (moduleName.indexOf("!") !== -1) { + var chunks = moduleName.split("!"); + return normalizeModule(parentId, chunks[0]) + "!" + normalizeModule(parentId, chunks[1]); + } + // normalize relative requires + if (moduleName.charAt(0) == ".") { + var base = parentId.split("/").slice(0, -1).join("/"); + moduleName = base + "/" + moduleName; + + while(moduleName.indexOf(".") !== -1 && previous != moduleName) { + var previous = moduleName; + moduleName = moduleName.replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, ""); + } + } + return moduleName; +}; + +/** + * Internal function to lookup moduleNames and resolve them by calling the + * definition function if needed. + */ +var lookup = function(parentId, moduleName) { + moduleName = normalizeModule(parentId, moduleName); + + var module = define.modules[moduleName]; + if (!module) { + module = define.payloads[moduleName]; + if (typeof module === 'function') { + var exports = {}; + var mod = { + id: moduleName, + uri: '', + exports: exports, + packaged: true + }; + + var req = function(module, callback) { + return _require(moduleName, module, callback); + }; + + var returnValue = module(req, exports, mod); + exports = returnValue || mod.exports; + define.modules[moduleName] = exports; + delete define.payloads[moduleName]; + } + module = define.modules[moduleName] = exports || module; + } + return module; +}; + +function exportAce(ns) { + var root = global; + if (ns) { + if (!global[ns]) + global[ns] = {}; + root = global[ns]; + } + + if (!root.define || !root.define.packaged) { + define.original = root.define; + root.define = define; + root.define.packaged = true; + } + + if (!root.require || !root.require.packaged) { + require.original = root.require; + root.require = require; + root.require.packaged = true; + } +} + +exportAce(ACE_NAMESPACE); + +})(); + +define("ace/lib/regexp",["require","exports","module"], function(require, exports, module) { +"use strict"; + + var real = { + exec: RegExp.prototype.exec, + test: RegExp.prototype.test, + match: String.prototype.match, + replace: String.prototype.replace, + split: String.prototype.split + }, + compliantExecNpcg = real.exec.call(/()??/, "")[1] === undefined, // check `exec` handling of nonparticipating capturing groups + compliantLastIndexIncrement = function () { + var x = /^/g; + real.test.call(x, ""); + return !x.lastIndex; + }(); + + if (compliantLastIndexIncrement && compliantExecNpcg) + return; + RegExp.prototype.exec = function (str) { + var match = real.exec.apply(this, arguments), + name, r2; + if ( typeof(str) == 'string' && match) { + if (!compliantExecNpcg && match.length > 1 && indexOf(match, "") > -1) { + r2 = RegExp(this.source, real.replace.call(getNativeFlags(this), "g", "")); + real.replace.call(str.slice(match.index), r2, function () { + for (var i = 1; i < arguments.length - 2; i++) { + if (arguments[i] === undefined) + match[i] = undefined; + } + }); + } + if (this._xregexp && this._xregexp.captureNames) { + for (var i = 1; i < match.length; i++) { + name = this._xregexp.captureNames[i - 1]; + if (name) + match[name] = match[i]; + } + } + if (!compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index)) + this.lastIndex--; + } + return match; + }; + if (!compliantLastIndexIncrement) { + RegExp.prototype.test = function (str) { + var match = real.exec.call(this, str); + if (match && this.global && !match[0].length && (this.lastIndex > match.index)) + this.lastIndex--; + return !!match; + }; + } + + function getNativeFlags (regex) { + return (regex.global ? "g" : "") + + (regex.ignoreCase ? "i" : "") + + (regex.multiline ? "m" : "") + + (regex.extended ? "x" : "") + // Proposed for ES4; included in AS3 + (regex.sticky ? "y" : ""); + } + + function indexOf (array, item, from) { + if (Array.prototype.indexOf) // Use the native array method if available + return array.indexOf(item, from); + for (var i = from || 0; i < array.length; i++) { + if (array[i] === item) + return i; + } + return -1; + } + +}); + +define("ace/lib/es5-shim",["require","exports","module"], function(require, exports, module) { + +function Empty() {} + +if (!Function.prototype.bind) { + Function.prototype.bind = function bind(that) { // .length is 1 + var target = this; + if (typeof target != "function") { + throw new TypeError("Function.prototype.bind called on incompatible " + target); + } + var args = slice.call(arguments, 1); // for normal call + var bound = function () { + + if (this instanceof bound) { + + var result = target.apply( + this, + args.concat(slice.call(arguments)) + ); + if (Object(result) === result) { + return result; + } + return this; + + } else { + return target.apply( + that, + args.concat(slice.call(arguments)) + ); + + } + + }; + if(target.prototype) { + Empty.prototype = target.prototype; + bound.prototype = new Empty(); + Empty.prototype = null; + } + return bound; + }; +} +var call = Function.prototype.call; +var prototypeOfArray = Array.prototype; +var prototypeOfObject = Object.prototype; +var slice = prototypeOfArray.slice; +var _toString = call.bind(prototypeOfObject.toString); +var owns = call.bind(prototypeOfObject.hasOwnProperty); +var defineGetter; +var defineSetter; +var lookupGetter; +var lookupSetter; +var supportsAccessors; +if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) { + defineGetter = call.bind(prototypeOfObject.__defineGetter__); + defineSetter = call.bind(prototypeOfObject.__defineSetter__); + lookupGetter = call.bind(prototypeOfObject.__lookupGetter__); + lookupSetter = call.bind(prototypeOfObject.__lookupSetter__); +} +if ([1,2].splice(0).length != 2) { + if(function() { // test IE < 9 to splice bug - see issue #138 + function makeArray(l) { + var a = new Array(l+2); + a[0] = a[1] = 0; + return a; + } + var array = [], lengthBefore; + + array.splice.apply(array, makeArray(20)); + array.splice.apply(array, makeArray(26)); + + lengthBefore = array.length; //46 + array.splice(5, 0, "XXX"); // add one element + + lengthBefore + 1 == array.length + + if (lengthBefore + 1 == array.length) { + return true;// has right splice implementation without bugs + } + }()) {//IE 6/7 + var array_splice = Array.prototype.splice; + Array.prototype.splice = function(start, deleteCount) { + if (!arguments.length) { + return []; + } else { + return array_splice.apply(this, [ + start === void 0 ? 0 : start, + deleteCount === void 0 ? (this.length - start) : deleteCount + ].concat(slice.call(arguments, 2))) + } + }; + } else {//IE8 + Array.prototype.splice = function(pos, removeCount){ + var length = this.length; + if (pos > 0) { + if (pos > length) + pos = length; + } else if (pos == void 0) { + pos = 0; + } else if (pos < 0) { + pos = Math.max(length + pos, 0); + } + + if (!(pos+removeCount < length)) + removeCount = length - pos; + + var removed = this.slice(pos, pos+removeCount); + var insert = slice.call(arguments, 2); + var add = insert.length; + if (pos === length) { + if (add) { + this.push.apply(this, insert); + } + } else { + var remove = Math.min(removeCount, length - pos); + var tailOldPos = pos + remove; + var tailNewPos = tailOldPos + add - remove; + var tailCount = length - tailOldPos; + var lengthAfterRemove = length - remove; + + if (tailNewPos < tailOldPos) { // case A + for (var i = 0; i < tailCount; ++i) { + this[tailNewPos+i] = this[tailOldPos+i]; + } + } else if (tailNewPos > tailOldPos) { // case B + for (i = tailCount; i--; ) { + this[tailNewPos+i] = this[tailOldPos+i]; + } + } // else, add == remove (nothing to do) + + if (add && pos === lengthAfterRemove) { + this.length = lengthAfterRemove; // truncate array + this.push.apply(this, insert); + } else { + this.length = lengthAfterRemove + add; // reserves space + for (i = 0; i < add; ++i) { + this[pos+i] = insert[i]; + } + } + } + return removed; + }; + } +} +if (!Array.isArray) { + Array.isArray = function isArray(obj) { + return _toString(obj) == "[object Array]"; + }; +} +var boxedString = Object("a"), + splitString = boxedString[0] != "a" || !(0 in boxedString); + +if (!Array.prototype.forEach) { + Array.prototype.forEach = function forEach(fun /*, thisp*/) { + var object = toObject(this), + self = splitString && _toString(this) == "[object String]" ? + this.split("") : + object, + thisp = arguments[1], + i = -1, + length = self.length >>> 0; + if (_toString(fun) != "[object Function]") { + throw new TypeError(); // TODO message + } + + while (++i < length) { + if (i in self) { + fun.call(thisp, self[i], i, object); + } + } + }; +} +if (!Array.prototype.map) { + Array.prototype.map = function map(fun /*, thisp*/) { + var object = toObject(this), + self = splitString && _toString(this) == "[object String]" ? + this.split("") : + object, + length = self.length >>> 0, + result = Array(length), + thisp = arguments[1]; + if (_toString(fun) != "[object Function]") { + throw new TypeError(fun + " is not a function"); + } + + for (var i = 0; i < length; i++) { + if (i in self) + result[i] = fun.call(thisp, self[i], i, object); + } + return result; + }; +} +if (!Array.prototype.filter) { + Array.prototype.filter = function filter(fun /*, thisp */) { + var object = toObject(this), + self = splitString && _toString(this) == "[object String]" ? + this.split("") : + object, + length = self.length >>> 0, + result = [], + value, + thisp = arguments[1]; + if (_toString(fun) != "[object Function]") { + throw new TypeError(fun + " is not a function"); + } + + for (var i = 0; i < length; i++) { + if (i in self) { + value = self[i]; + if (fun.call(thisp, value, i, object)) { + result.push(value); + } + } + } + return result; + }; +} +if (!Array.prototype.every) { + Array.prototype.every = function every(fun /*, thisp */) { + var object = toObject(this), + self = splitString && _toString(this) == "[object String]" ? + this.split("") : + object, + length = self.length >>> 0, + thisp = arguments[1]; + if (_toString(fun) != "[object Function]") { + throw new TypeError(fun + " is not a function"); + } + + for (var i = 0; i < length; i++) { + if (i in self && !fun.call(thisp, self[i], i, object)) { + return false; + } + } + return true; + }; +} +if (!Array.prototype.some) { + Array.prototype.some = function some(fun /*, thisp */) { + var object = toObject(this), + self = splitString && _toString(this) == "[object String]" ? + this.split("") : + object, + length = self.length >>> 0, + thisp = arguments[1]; + if (_toString(fun) != "[object Function]") { + throw new TypeError(fun + " is not a function"); + } + + for (var i = 0; i < length; i++) { + if (i in self && fun.call(thisp, self[i], i, object)) { + return true; + } + } + return false; + }; +} +if (!Array.prototype.reduce) { + Array.prototype.reduce = function reduce(fun /*, initial*/) { + var object = toObject(this), + self = splitString && _toString(this) == "[object String]" ? + this.split("") : + object, + length = self.length >>> 0; + if (_toString(fun) != "[object Function]") { + throw new TypeError(fun + " is not a function"); + } + if (!length && arguments.length == 1) { + throw new TypeError("reduce of empty array with no initial value"); + } + + var i = 0; + var result; + if (arguments.length >= 2) { + result = arguments[1]; + } else { + do { + if (i in self) { + result = self[i++]; + break; + } + if (++i >= length) { + throw new TypeError("reduce of empty array with no initial value"); + } + } while (true); + } + + for (; i < length; i++) { + if (i in self) { + result = fun.call(void 0, result, self[i], i, object); + } + } + + return result; + }; +} +if (!Array.prototype.reduceRight) { + Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) { + var object = toObject(this), + self = splitString && _toString(this) == "[object String]" ? + this.split("") : + object, + length = self.length >>> 0; + if (_toString(fun) != "[object Function]") { + throw new TypeError(fun + " is not a function"); + } + if (!length && arguments.length == 1) { + throw new TypeError("reduceRight of empty array with no initial value"); + } + + var result, i = length - 1; + if (arguments.length >= 2) { + result = arguments[1]; + } else { + do { + if (i in self) { + result = self[i--]; + break; + } + if (--i < 0) { + throw new TypeError("reduceRight of empty array with no initial value"); + } + } while (true); + } + + do { + if (i in this) { + result = fun.call(void 0, result, self[i], i, object); + } + } while (i--); + + return result; + }; +} +if (!Array.prototype.indexOf || ([0, 1].indexOf(1, 2) != -1)) { + Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) { + var self = splitString && _toString(this) == "[object String]" ? + this.split("") : + toObject(this), + length = self.length >>> 0; + + if (!length) { + return -1; + } + + var i = 0; + if (arguments.length > 1) { + i = toInteger(arguments[1]); + } + i = i >= 0 ? i : Math.max(0, length + i); + for (; i < length; i++) { + if (i in self && self[i] === sought) { + return i; + } + } + return -1; + }; +} +if (!Array.prototype.lastIndexOf || ([0, 1].lastIndexOf(0, -3) != -1)) { + Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) { + var self = splitString && _toString(this) == "[object String]" ? + this.split("") : + toObject(this), + length = self.length >>> 0; + + if (!length) { + return -1; + } + var i = length - 1; + if (arguments.length > 1) { + i = Math.min(i, toInteger(arguments[1])); + } + i = i >= 0 ? i : length - Math.abs(i); + for (; i >= 0; i--) { + if (i in self && sought === self[i]) { + return i; + } + } + return -1; + }; +} +if (!Object.getPrototypeOf) { + Object.getPrototypeOf = function getPrototypeOf(object) { + return object.__proto__ || ( + object.constructor ? + object.constructor.prototype : + prototypeOfObject + ); + }; +} +if (!Object.getOwnPropertyDescriptor) { + var ERR_NON_OBJECT = "Object.getOwnPropertyDescriptor called on a " + + "non-object: "; + Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) { + if ((typeof object != "object" && typeof object != "function") || object === null) + throw new TypeError(ERR_NON_OBJECT + object); + if (!owns(object, property)) + return; + + var descriptor, getter, setter; + descriptor = { enumerable: true, configurable: true }; + if (supportsAccessors) { + var prototype = object.__proto__; + object.__proto__ = prototypeOfObject; + + var getter = lookupGetter(object, property); + var setter = lookupSetter(object, property); + object.__proto__ = prototype; + + if (getter || setter) { + if (getter) descriptor.get = getter; + if (setter) descriptor.set = setter; + return descriptor; + } + } + descriptor.value = object[property]; + return descriptor; + }; +} +if (!Object.getOwnPropertyNames) { + Object.getOwnPropertyNames = function getOwnPropertyNames(object) { + return Object.keys(object); + }; +} +if (!Object.create) { + var createEmpty; + if (Object.prototype.__proto__ === null) { + createEmpty = function () { + return { "__proto__": null }; + }; + } else { + createEmpty = function () { + var empty = {}; + for (var i in empty) + empty[i] = null; + empty.constructor = + empty.hasOwnProperty = + empty.propertyIsEnumerable = + empty.isPrototypeOf = + empty.toLocaleString = + empty.toString = + empty.valueOf = + empty.__proto__ = null; + return empty; + } + } + + Object.create = function create(prototype, properties) { + var object; + if (prototype === null) { + object = createEmpty(); + } else { + if (typeof prototype != "object") + throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'"); + var Type = function () {}; + Type.prototype = prototype; + object = new Type(); + object.__proto__ = prototype; + } + if (properties !== void 0) + Object.defineProperties(object, properties); + return object; + }; +} + +function doesDefinePropertyWork(object) { + try { + Object.defineProperty(object, "sentinel", {}); + return "sentinel" in object; + } catch (exception) { + } +} +if (Object.defineProperty) { + var definePropertyWorksOnObject = doesDefinePropertyWork({}); + var definePropertyWorksOnDom = typeof document == "undefined" || + doesDefinePropertyWork(document.createElement("div")); + if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) { + var definePropertyFallback = Object.defineProperty; + } +} + +if (!Object.defineProperty || definePropertyFallback) { + var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: "; + var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: " + var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " + + "on this javascript engine"; + + Object.defineProperty = function defineProperty(object, property, descriptor) { + if ((typeof object != "object" && typeof object != "function") || object === null) + throw new TypeError(ERR_NON_OBJECT_TARGET + object); + if ((typeof descriptor != "object" && typeof descriptor != "function") || descriptor === null) + throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor); + if (definePropertyFallback) { + try { + return definePropertyFallback.call(Object, object, property, descriptor); + } catch (exception) { + } + } + if (owns(descriptor, "value")) { + + if (supportsAccessors && (lookupGetter(object, property) || + lookupSetter(object, property))) + { + var prototype = object.__proto__; + object.__proto__ = prototypeOfObject; + delete object[property]; + object[property] = descriptor.value; + object.__proto__ = prototype; + } else { + object[property] = descriptor.value; + } + } else { + if (!supportsAccessors) + throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED); + if (owns(descriptor, "get")) + defineGetter(object, property, descriptor.get); + if (owns(descriptor, "set")) + defineSetter(object, property, descriptor.set); + } + + return object; + }; +} +if (!Object.defineProperties) { + Object.defineProperties = function defineProperties(object, properties) { + for (var property in properties) { + if (owns(properties, property)) + Object.defineProperty(object, property, properties[property]); + } + return object; + }; +} +if (!Object.seal) { + Object.seal = function seal(object) { + return object; + }; +} +if (!Object.freeze) { + Object.freeze = function freeze(object) { + return object; + }; +} +try { + Object.freeze(function () {}); +} catch (exception) { + Object.freeze = (function freeze(freezeObject) { + return function freeze(object) { + if (typeof object == "function") { + return object; + } else { + return freezeObject(object); + } + }; + })(Object.freeze); +} +if (!Object.preventExtensions) { + Object.preventExtensions = function preventExtensions(object) { + return object; + }; +} +if (!Object.isSealed) { + Object.isSealed = function isSealed(object) { + return false; + }; +} +if (!Object.isFrozen) { + Object.isFrozen = function isFrozen(object) { + return false; + }; +} +if (!Object.isExtensible) { + Object.isExtensible = function isExtensible(object) { + if (Object(object) === object) { + throw new TypeError(); // TODO message + } + var name = ''; + while (owns(object, name)) { + name += '?'; + } + object[name] = true; + var returnValue = owns(object, name); + delete object[name]; + return returnValue; + }; +} +if (!Object.keys) { + var hasDontEnumBug = true, + dontEnums = [ + "toString", + "toLocaleString", + "valueOf", + "hasOwnProperty", + "isPrototypeOf", + "propertyIsEnumerable", + "constructor" + ], + dontEnumsLength = dontEnums.length; + + for (var key in {"toString": null}) { + hasDontEnumBug = false; + } + + Object.keys = function keys(object) { + + if ( + (typeof object != "object" && typeof object != "function") || + object === null + ) { + throw new TypeError("Object.keys called on a non-object"); + } + + var keys = []; + for (var name in object) { + if (owns(object, name)) { + keys.push(name); + } + } + + if (hasDontEnumBug) { + for (var i = 0, ii = dontEnumsLength; i < ii; i++) { + var dontEnum = dontEnums[i]; + if (owns(object, dontEnum)) { + keys.push(dontEnum); + } + } + } + return keys; + }; + +} +if (!Date.now) { + Date.now = function now() { + return new Date().getTime(); + }; +} +var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u2000\u2001\u2002\u2003" + + "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" + + "\u2029\uFEFF"; +if (!String.prototype.trim) { + ws = "[" + ws + "]"; + var trimBeginRegexp = new RegExp("^" + ws + ws + "*"), + trimEndRegexp = new RegExp(ws + ws + "*$"); + String.prototype.trim = function trim() { + return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, ""); + }; +} + +function toInteger(n) { + n = +n; + if (n !== n) { // isNaN + n = 0; + } else if (n !== 0 && n !== (1/0) && n !== -(1/0)) { + n = (n > 0 || -1) * Math.floor(Math.abs(n)); + } + return n; +} + +function isPrimitive(input) { + var type = typeof input; + return ( + input === null || + type === "undefined" || + type === "boolean" || + type === "number" || + type === "string" + ); +} + +function toPrimitive(input) { + var val, valueOf, toString; + if (isPrimitive(input)) { + return input; + } + valueOf = input.valueOf; + if (typeof valueOf === "function") { + val = valueOf.call(input); + if (isPrimitive(val)) { + return val; + } + } + toString = input.toString; + if (typeof toString === "function") { + val = toString.call(input); + if (isPrimitive(val)) { + return val; + } + } + throw new TypeError(); +} +var toObject = function (o) { + if (o == null) { // this matches both null and undefined + throw new TypeError("can't convert "+o+" to object"); + } + return Object(o); +}; + +}); + +define("ace/lib/fixoldbrowsers",["require","exports","module","ace/lib/regexp","ace/lib/es5-shim"], function(require, exports, module) { +"use strict"; + +require("./regexp"); +require("./es5-shim"); +if (typeof Element != "undefined" && !Element.prototype.remove) { + Object.defineProperty(Element.prototype, "remove", { + enumerable: false, + writable: true, + configurable: true, + value: function() { this.parentNode && this.parentNode.removeChild(this); } + }); +} + + +}); + +define("ace/lib/useragent",["require","exports","module"], function(require, exports, module) { +"use strict"; +exports.OS = { + LINUX: "LINUX", + MAC: "MAC", + WINDOWS: "WINDOWS" +}; +exports.getOS = function() { + if (exports.isMac) { + return exports.OS.MAC; + } else if (exports.isLinux) { + return exports.OS.LINUX; + } else { + return exports.OS.WINDOWS; + } +}; +var _navigator = typeof navigator == "object" ? navigator : {}; + +var os = (/mac|win|linux/i.exec(_navigator.platform) || ["other"])[0].toLowerCase(); +var ua = _navigator.userAgent || ""; +var appName = _navigator.appName || ""; +exports.isWin = (os == "win"); +exports.isMac = (os == "mac"); +exports.isLinux = (os == "linux"); +exports.isIE = + (appName == "Microsoft Internet Explorer" || appName.indexOf("MSAppHost") >= 0) + ? parseFloat((ua.match(/(?:MSIE |Trident\/[0-9]+[\.0-9]+;.*rv:)([0-9]+[\.0-9]+)/)||[])[1]) + : parseFloat((ua.match(/(?:Trident\/[0-9]+[\.0-9]+;.*rv:)([0-9]+[\.0-9]+)/)||[])[1]); // for ie + +exports.isOldIE = exports.isIE && exports.isIE < 9; +exports.isGecko = exports.isMozilla = ua.match(/ Gecko\/\d+/); +exports.isOpera = typeof opera == "object" && Object.prototype.toString.call(window.opera) == "[object Opera]"; +exports.isWebKit = parseFloat(ua.split("WebKit/")[1]) || undefined; + +exports.isChrome = parseFloat(ua.split(" Chrome/")[1]) || undefined; + +exports.isEdge = parseFloat(ua.split(" Edge/")[1]) || undefined; + +exports.isAIR = ua.indexOf("AdobeAIR") >= 0; + +exports.isAndroid = ua.indexOf("Android") >= 0; + +exports.isChromeOS = ua.indexOf(" CrOS ") >= 0; + +exports.isIOS = /iPad|iPhone|iPod/.test(ua) && !window.MSStream; + +if (exports.isIOS) exports.isMac = true; + +exports.isMobile = exports.isIOS || exports.isAndroid; + +}); + +define("ace/lib/dom",["require","exports","module","ace/lib/useragent"], function(require, exports, module) { +"use strict"; + +var useragent = require("./useragent"); +var XHTML_NS = "http://www.w3.org/1999/xhtml"; + +exports.buildDom = function buildDom(arr, parent, refs) { + if (typeof arr == "string" && arr) { + var txt = document.createTextNode(arr); + if (parent) + parent.appendChild(txt); + return txt; + } + + if (!Array.isArray(arr)) + return arr; + if (typeof arr[0] != "string" || !arr[0]) { + var els = []; + for (var i = 0; i < arr.length; i++) { + var ch = buildDom(arr[i], parent, refs); + ch && els.push(ch); + } + return els; + } + + var el = document.createElement(arr[0]); + var options = arr[1]; + var childIndex = 1; + if (options && typeof options == "object" && !Array.isArray(options)) + childIndex = 2; + for (var i = childIndex; i < arr.length; i++) + buildDom(arr[i], el, refs); + if (childIndex == 2) { + Object.keys(options).forEach(function(n) { + var val = options[n]; + if (n === "class") { + el.className = Array.isArray(val) ? val.join(" ") : val; + } else if (typeof val == "function" || n == "value") { + el[n] = val; + } else if (n === "ref") { + if (refs) refs[val] = el; + } else if (val != null) { + el.setAttribute(n, val); + } + }); + } + if (parent) + parent.appendChild(el); + return el; +}; + +exports.getDocumentHead = function(doc) { + if (!doc) + doc = document; + return doc.head || doc.getElementsByTagName("head")[0] || doc.documentElement; +}; + +exports.createElement = function(tag, ns) { + return document.createElementNS ? + document.createElementNS(ns || XHTML_NS, tag) : + document.createElement(tag); +}; + +exports.removeChildren = function(element) { + element.innerHTML = ""; +}; + +exports.createTextNode = function(textContent, element) { + var doc = element ? element.ownerDocument : document; + return doc.createTextNode(textContent); +}; + +exports.createFragment = function(element) { + var doc = element ? element.ownerDocument : document; + return doc.createDocumentFragment(); +}; + +exports.hasCssClass = function(el, name) { + var classes = (el.className + "").split(/\s+/g); + return classes.indexOf(name) !== -1; +}; +exports.addCssClass = function(el, name) { + if (!exports.hasCssClass(el, name)) { + el.className += " " + name; + } +}; +exports.removeCssClass = function(el, name) { + var classes = el.className.split(/\s+/g); + while (true) { + var index = classes.indexOf(name); + if (index == -1) { + break; + } + classes.splice(index, 1); + } + el.className = classes.join(" "); +}; + +exports.toggleCssClass = function(el, name) { + var classes = el.className.split(/\s+/g), add = true; + while (true) { + var index = classes.indexOf(name); + if (index == -1) { + break; + } + add = false; + classes.splice(index, 1); + } + if (add) + classes.push(name); + + el.className = classes.join(" "); + return add; +}; +exports.setCssClass = function(node, className, include) { + if (include) { + exports.addCssClass(node, className); + } else { + exports.removeCssClass(node, className); + } +}; + +exports.hasCssString = function(id, doc) { + var index = 0, sheets; + doc = doc || document; + if ((sheets = doc.querySelectorAll("style"))) { + while (index < sheets.length) + if (sheets[index++].id === id) + return true; + } +}; + +exports.importCssString = function importCssString(cssText, id, target) { + var container = target; + if (!target || !target.getRootNode) { + container = document; + } else { + container = target.getRootNode(); + if (!container || container == target) + container = document; + } + + var doc = container.ownerDocument || container; + if (id && exports.hasCssString(id, container)) + return null; + + if (id) + cssText += "\n/*# sourceURL=ace/css/" + id + " */"; + + var style = exports.createElement("style"); + style.appendChild(doc.createTextNode(cssText)); + if (id) + style.id = id; + + if (container == doc) + container = exports.getDocumentHead(doc); + container.insertBefore(style, container.firstChild); +}; + +exports.importCssStylsheet = function(uri, doc) { + exports.buildDom(["link", {rel: "stylesheet", href: uri}], exports.getDocumentHead(doc)); +}; +exports.scrollbarWidth = function(document) { + var inner = exports.createElement("ace_inner"); + inner.style.width = "100%"; + inner.style.minWidth = "0px"; + inner.style.height = "200px"; + inner.style.display = "block"; + + var outer = exports.createElement("ace_outer"); + var style = outer.style; + + style.position = "absolute"; + style.left = "-10000px"; + style.overflow = "hidden"; + style.width = "200px"; + style.minWidth = "0px"; + style.height = "150px"; + style.display = "block"; + + outer.appendChild(inner); + + var body = document.documentElement; + body.appendChild(outer); + + var noScrollbar = inner.offsetWidth; + + style.overflow = "scroll"; + var withScrollbar = inner.offsetWidth; + + if (noScrollbar == withScrollbar) { + withScrollbar = outer.clientWidth; + } + + body.removeChild(outer); + + return noScrollbar-withScrollbar; +}; + +if (typeof document == "undefined") { + exports.importCssString = function() {}; +} + +exports.computedStyle = function(element, style) { + return window.getComputedStyle(element, "") || {}; +}; + +exports.setStyle = function(styles, property, value) { + if (styles[property] !== value) { + styles[property] = value; + } +}; + +exports.HAS_CSS_ANIMATION = false; +exports.HAS_CSS_TRANSFORMS = false; +exports.HI_DPI = useragent.isWin + ? typeof window !== "undefined" && window.devicePixelRatio >= 1.5 + : true; + +if (typeof document !== "undefined") { + var div = document.createElement("div"); + if (exports.HI_DPI && div.style.transform !== undefined) + exports.HAS_CSS_TRANSFORMS = true; + if (!useragent.isEdge && typeof div.style.animationName !== "undefined") + exports.HAS_CSS_ANIMATION = true; + div = null; +} + +if (exports.HAS_CSS_TRANSFORMS) { + exports.translate = function(element, tx, ty) { + element.style.transform = "translate(" + Math.round(tx) + "px, " + Math.round(ty) +"px)"; + }; +} else { + exports.translate = function(element, tx, ty) { + element.style.top = Math.round(ty) + "px"; + element.style.left = Math.round(tx) + "px"; + }; +} + +}); + +define("ace/lib/oop",["require","exports","module"], function(require, exports, module) { +"use strict"; + +exports.inherits = function(ctor, superCtor) { + ctor.super_ = superCtor; + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); +}; + +exports.mixin = function(obj, mixin) { + for (var key in mixin) { + obj[key] = mixin[key]; + } + return obj; +}; + +exports.implement = function(proto, mixin) { + exports.mixin(proto, mixin); +}; + +}); + +define("ace/lib/keys",["require","exports","module","ace/lib/oop"], function(require, exports, module) { +"use strict"; + +var oop = require("./oop"); +var Keys = (function() { + var ret = { + MODIFIER_KEYS: { + 16: 'Shift', 17: 'Ctrl', 18: 'Alt', 224: 'Meta', + 91: 'MetaLeft', 92: 'MetaRight', 93: 'ContextMenu' + }, + + KEY_MODS: { + "ctrl": 1, "alt": 2, "option" : 2, "shift": 4, + "super": 8, "meta": 8, "command": 8, "cmd": 8 + }, + + FUNCTION_KEYS : { + 8 : "Backspace", + 9 : "Tab", + 13 : "Return", + 19 : "Pause", + 27 : "Esc", + 32 : "Space", + 33 : "PageUp", + 34 : "PageDown", + 35 : "End", + 36 : "Home", + 37 : "Left", + 38 : "Up", + 39 : "Right", + 40 : "Down", + 44 : "Print", + 45 : "Insert", + 46 : "Delete", + 96 : "Numpad0", + 97 : "Numpad1", + 98 : "Numpad2", + 99 : "Numpad3", + 100: "Numpad4", + 101: "Numpad5", + 102: "Numpad6", + 103: "Numpad7", + 104: "Numpad8", + 105: "Numpad9", + '-13': "NumpadEnter", + 112: "F1", + 113: "F2", + 114: "F3", + 115: "F4", + 116: "F5", + 117: "F6", + 118: "F7", + 119: "F8", + 120: "F9", + 121: "F10", + 122: "F11", + 123: "F12", + 144: "Numlock", + 145: "Scrolllock" + }, + + PRINTABLE_KEYS: { + 32: ' ', 48: '0', 49: '1', 50: '2', 51: '3', 52: '4', 53: '5', + 54: '6', 55: '7', 56: '8', 57: '9', 59: ';', 61: '=', 65: 'a', + 66: 'b', 67: 'c', 68: 'd', 69: 'e', 70: 'f', 71: 'g', 72: 'h', + 73: 'i', 74: 'j', 75: 'k', 76: 'l', 77: 'm', 78: 'n', 79: 'o', + 80: 'p', 81: 'q', 82: 'r', 83: 's', 84: 't', 85: 'u', 86: 'v', + 87: 'w', 88: 'x', 89: 'y', 90: 'z', 107: '+', 109: '-', 110: '.', + 186: ';', 187: '=', 188: ',', 189: '-', 190: '.', 191: '/', 192: '`', + 219: '[', 220: '\\',221: ']', 222: "'", 111: '/', 106: '*' + } + }; + var name, i; + for (i in ret.FUNCTION_KEYS) { + name = ret.FUNCTION_KEYS[i].toLowerCase(); + ret[name] = parseInt(i, 10); + } + for (i in ret.PRINTABLE_KEYS) { + name = ret.PRINTABLE_KEYS[i].toLowerCase(); + ret[name] = parseInt(i, 10); + } + oop.mixin(ret, ret.MODIFIER_KEYS); + oop.mixin(ret, ret.PRINTABLE_KEYS); + oop.mixin(ret, ret.FUNCTION_KEYS); + ret.enter = ret["return"]; + ret.escape = ret.esc; + ret.del = ret["delete"]; + ret[173] = '-'; + + (function() { + var mods = ["cmd", "ctrl", "alt", "shift"]; + for (var i = Math.pow(2, mods.length); i--;) { + ret.KEY_MODS[i] = mods.filter(function(x) { + return i & ret.KEY_MODS[x]; + }).join("-") + "-"; + } + })(); + + ret.KEY_MODS[0] = ""; + ret.KEY_MODS[-1] = "input-"; + + return ret; +})(); +oop.mixin(exports, Keys); + +exports.keyCodeToString = function(keyCode) { + var keyString = Keys[keyCode]; + if (typeof keyString != "string") + keyString = String.fromCharCode(keyCode); + return keyString.toLowerCase(); +}; + +}); + +define("ace/lib/event",["require","exports","module","ace/lib/keys","ace/lib/useragent"], function(require, exports, module) { +"use strict"; + +var keys = require("./keys"); +var useragent = require("./useragent"); + +var pressedKeys = null; +var ts = 0; + +exports.addListener = function(elem, type, callback) { + if (elem.addEventListener) { + return elem.addEventListener(type, callback, false); + } + if (elem.attachEvent) { + var wrapper = function() { + callback.call(elem, window.event); + }; + callback._wrapper = wrapper; + elem.attachEvent("on" + type, wrapper); + } +}; + +exports.removeListener = function(elem, type, callback) { + if (elem.removeEventListener) { + return elem.removeEventListener(type, callback, false); + } + if (elem.detachEvent) { + elem.detachEvent("on" + type, callback._wrapper || callback); + } +}; +exports.stopEvent = function(e) { + exports.stopPropagation(e); + exports.preventDefault(e); + return false; +}; + +exports.stopPropagation = function(e) { + if (e.stopPropagation) + e.stopPropagation(); + else + e.cancelBubble = true; +}; + +exports.preventDefault = function(e) { + if (e.preventDefault) + e.preventDefault(); + else + e.returnValue = false; +}; +exports.getButton = function(e) { + if (e.type == "dblclick") + return 0; + if (e.type == "contextmenu" || (useragent.isMac && (e.ctrlKey && !e.altKey && !e.shiftKey))) + return 2; + if (e.preventDefault) { + return e.button; + } + else { + return {1:0, 2:2, 4:1}[e.button]; + } +}; + +exports.capture = function(el, eventHandler, releaseCaptureHandler) { + function onMouseUp(e) { + eventHandler && eventHandler(e); + releaseCaptureHandler && releaseCaptureHandler(e); + + exports.removeListener(document, "mousemove", eventHandler, true); + exports.removeListener(document, "mouseup", onMouseUp, true); + exports.removeListener(document, "dragstart", onMouseUp, true); + } + + exports.addListener(document, "mousemove", eventHandler, true); + exports.addListener(document, "mouseup", onMouseUp, true); + exports.addListener(document, "dragstart", onMouseUp, true); + + return onMouseUp; +}; + +exports.addMouseWheelListener = function(el, callback) { + if ("onmousewheel" in el) { + exports.addListener(el, "mousewheel", function(e) { + var factor = 8; + if (e.wheelDeltaX !== undefined) { + e.wheelX = -e.wheelDeltaX / factor; + e.wheelY = -e.wheelDeltaY / factor; + } else { + e.wheelX = 0; + e.wheelY = -e.wheelDelta / factor; + } + callback(e); + }); + } else if ("onwheel" in el) { + exports.addListener(el, "wheel", function(e) { + var factor = 0.35; + switch (e.deltaMode) { + case e.DOM_DELTA_PIXEL: + e.wheelX = e.deltaX * factor || 0; + e.wheelY = e.deltaY * factor || 0; + break; + case e.DOM_DELTA_LINE: + case e.DOM_DELTA_PAGE: + e.wheelX = (e.deltaX || 0) * 5; + e.wheelY = (e.deltaY || 0) * 5; + break; + } + + callback(e); + }); + } else { + exports.addListener(el, "DOMMouseScroll", function(e) { + if (e.axis && e.axis == e.HORIZONTAL_AXIS) { + e.wheelX = (e.detail || 0) * 5; + e.wheelY = 0; + } else { + e.wheelX = 0; + e.wheelY = (e.detail || 0) * 5; + } + callback(e); + }); + } +}; + +exports.addMultiMouseDownListener = function(elements, timeouts, eventHandler, callbackName) { + var clicks = 0; + var startX, startY, timer; + var eventNames = { + 2: "dblclick", + 3: "tripleclick", + 4: "quadclick" + }; + + function onMousedown(e) { + if (exports.getButton(e) !== 0) { + clicks = 0; + } else if (e.detail > 1) { + clicks++; + if (clicks > 4) + clicks = 1; + } else { + clicks = 1; + } + if (useragent.isIE) { + var isNewClick = Math.abs(e.clientX - startX) > 5 || Math.abs(e.clientY - startY) > 5; + if (!timer || isNewClick) + clicks = 1; + if (timer) + clearTimeout(timer); + timer = setTimeout(function() {timer = null;}, timeouts[clicks - 1] || 600); + + if (clicks == 1) { + startX = e.clientX; + startY = e.clientY; + } + } + + e._clicks = clicks; + + eventHandler[callbackName]("mousedown", e); + + if (clicks > 4) + clicks = 0; + else if (clicks > 1) + return eventHandler[callbackName](eventNames[clicks], e); + } + function onDblclick(e) { + clicks = 2; + if (timer) + clearTimeout(timer); + timer = setTimeout(function() {timer = null;}, timeouts[clicks - 1] || 600); + eventHandler[callbackName]("mousedown", e); + eventHandler[callbackName](eventNames[clicks], e); + } + if (!Array.isArray(elements)) + elements = [elements]; + elements.forEach(function(el) { + exports.addListener(el, "mousedown", onMousedown); + if (useragent.isOldIE) + exports.addListener(el, "dblclick", onDblclick); + }); +}; + +var getModifierHash = useragent.isMac && useragent.isOpera && !("KeyboardEvent" in window) + ? function(e) { + return 0 | (e.metaKey ? 1 : 0) | (e.altKey ? 2 : 0) | (e.shiftKey ? 4 : 0) | (e.ctrlKey ? 8 : 0); + } + : function(e) { + return 0 | (e.ctrlKey ? 1 : 0) | (e.altKey ? 2 : 0) | (e.shiftKey ? 4 : 0) | (e.metaKey ? 8 : 0); + }; + +exports.getModifierString = function(e) { + return keys.KEY_MODS[getModifierHash(e)]; +}; + +function normalizeCommandKeys(callback, e, keyCode) { + var hashId = getModifierHash(e); + + if (!useragent.isMac && pressedKeys) { + if (e.getModifierState && (e.getModifierState("OS") || e.getModifierState("Win"))) + hashId |= 8; + if (pressedKeys.altGr) { + if ((3 & hashId) != 3) + pressedKeys.altGr = 0; + else + return; + } + if (keyCode === 18 || keyCode === 17) { + var location = "location" in e ? e.location : e.keyLocation; + if (keyCode === 17 && location === 1) { + if (pressedKeys[keyCode] == 1) + ts = e.timeStamp; + } else if (keyCode === 18 && hashId === 3 && location === 2) { + var dt = e.timeStamp - ts; + if (dt < 50) + pressedKeys.altGr = true; + } + } + } + + if (keyCode in keys.MODIFIER_KEYS) { + keyCode = -1; + } + + if (!hashId && keyCode === 13) { + var location = "location" in e ? e.location : e.keyLocation; + if (location === 3) { + callback(e, hashId, -keyCode); + if (e.defaultPrevented) + return; + } + } + + if (useragent.isChromeOS && hashId & 8) { + callback(e, hashId, keyCode); + if (e.defaultPrevented) + return; + else + hashId &= ~8; + } + if (!hashId && !(keyCode in keys.FUNCTION_KEYS) && !(keyCode in keys.PRINTABLE_KEYS)) { + return false; + } + + return callback(e, hashId, keyCode); +} + + +exports.addCommandKeyListener = function(el, callback) { + var addListener = exports.addListener; + if (useragent.isOldGecko || (useragent.isOpera && !("KeyboardEvent" in window))) { + var lastKeyDownKeyCode = null; + addListener(el, "keydown", function(e) { + lastKeyDownKeyCode = e.keyCode; + }); + addListener(el, "keypress", function(e) { + return normalizeCommandKeys(callback, e, lastKeyDownKeyCode); + }); + } else { + var lastDefaultPrevented = null; + + addListener(el, "keydown", function(e) { + pressedKeys[e.keyCode] = (pressedKeys[e.keyCode] || 0) + 1; + var result = normalizeCommandKeys(callback, e, e.keyCode); + lastDefaultPrevented = e.defaultPrevented; + return result; + }); + + addListener(el, "keypress", function(e) { + if (lastDefaultPrevented && (e.ctrlKey || e.altKey || e.shiftKey || e.metaKey)) { + exports.stopEvent(e); + lastDefaultPrevented = null; + } + }); + + addListener(el, "keyup", function(e) { + pressedKeys[e.keyCode] = null; + }); + + if (!pressedKeys) { + resetPressedKeys(); + addListener(window, "focus", resetPressedKeys); + } + } +}; +function resetPressedKeys() { + pressedKeys = Object.create(null); +} + +if (typeof window == "object" && window.postMessage && !useragent.isOldIE) { + var postMessageId = 1; + exports.nextTick = function(callback, win) { + win = win || window; + var messageName = "zero-timeout-message-" + (postMessageId++); + + var listener = function(e) { + if (e.data == messageName) { + exports.stopPropagation(e); + exports.removeListener(win, "message", listener); + callback(); + } + }; + + exports.addListener(win, "message", listener); + win.postMessage(messageName, "*"); + }; +} + +exports.$idleBlocked = false; +exports.onIdle = function(cb, timeout) { + return setTimeout(function handler() { + if (!exports.$idleBlocked) { + cb(); + } else { + setTimeout(handler, 100); + } + }, timeout); +}; + +exports.$idleBlockId = null; +exports.blockIdle = function(delay) { + if (exports.$idleBlockId) + clearTimeout(exports.$idleBlockId); + + exports.$idleBlocked = true; + exports.$idleBlockId = setTimeout(function() { + exports.$idleBlocked = false; + }, delay || 100); +}; + +exports.nextFrame = typeof window == "object" && (window.requestAnimationFrame + || window.mozRequestAnimationFrame + || window.webkitRequestAnimationFrame + || window.msRequestAnimationFrame + || window.oRequestAnimationFrame); + +if (exports.nextFrame) + exports.nextFrame = exports.nextFrame.bind(window); +else + exports.nextFrame = function(callback) { + setTimeout(callback, 17); + }; +}); + +define("ace/range",["require","exports","module"], function(require, exports, module) { +"use strict"; +var comparePoints = function(p1, p2) { + return p1.row - p2.row || p1.column - p2.column; +}; +var Range = function(startRow, startColumn, endRow, endColumn) { + this.start = { + row: startRow, + column: startColumn + }; + + this.end = { + row: endRow, + column: endColumn + }; +}; + +(function() { + this.isEqual = function(range) { + return this.start.row === range.start.row && + this.end.row === range.end.row && + this.start.column === range.start.column && + this.end.column === range.end.column; + }; + this.toString = function() { + return ("Range: [" + this.start.row + "/" + this.start.column + + "] -> [" + this.end.row + "/" + this.end.column + "]"); + }; + + this.contains = function(row, column) { + return this.compare(row, column) == 0; + }; + this.compareRange = function(range) { + var cmp, + end = range.end, + start = range.start; + + cmp = this.compare(end.row, end.column); + if (cmp == 1) { + cmp = this.compare(start.row, start.column); + if (cmp == 1) { + return 2; + } else if (cmp == 0) { + return 1; + } else { + return 0; + } + } else if (cmp == -1) { + return -2; + } else { + cmp = this.compare(start.row, start.column); + if (cmp == -1) { + return -1; + } else if (cmp == 1) { + return 42; + } else { + return 0; + } + } + }; + this.comparePoint = function(p) { + return this.compare(p.row, p.column); + }; + this.containsRange = function(range) { + return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0; + }; + this.intersects = 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; + }; + this.isStart = function(row, column) { + return this.start.row == row && this.start.column == column; + }; + this.setStart = function(row, column) { + if (typeof row == "object") { + this.start.column = row.column; + this.start.row = row.row; + } else { + this.start.row = row; + this.start.column = column; + } + }; + this.setEnd = function(row, column) { + if (typeof row == "object") { + this.end.column = row.column; + this.end.row = row.row; + } else { + this.end.row = row; + this.end.column = column; + } + }; + this.inside = function(row, column) { + if (this.compare(row, column) == 0) { + if (this.isEnd(row, column) || this.isStart(row, column)) { + return false; + } else { + return true; + } + } + return false; + }; + this.insideStart = function(row, column) { + if (this.compare(row, column) == 0) { + if (this.isEnd(row, column)) { + return false; + } else { + return true; + } + } + return false; + }; + this.insideEnd = function(row, column) { + if (this.compare(row, column) == 0) { + if (this.isStart(row, column)) { + return false; + } else { + return true; + } + } + return false; + }; + this.compare = function(row, column) { + if (!this.isMultiLine()) { + if (row === this.start.row) { + return column < this.start.column ? -1 : (column > this.end.column ? 1 : 0); + } + } + + if (row < this.start.row) + return -1; + + if (row > this.end.row) + return 1; + + if (this.start.row === row) + return column >= this.start.column ? 0 : -1; + + if (this.end.row === row) + return column <= this.end.column ? 0 : 1; + + return 0; + }; + this.compareStart = function(row, column) { + if (this.start.row == row && this.start.column == column) { + return -1; + } else { + return this.compare(row, column); + } + }; + this.compareEnd = function(row, column) { + if (this.end.row == row && this.end.column == column) { + return 1; + } else { + return this.compare(row, column); + } + }; + this.compareInside = function(row, column) { + if (this.end.row == row && this.end.column == column) { + return 1; + } else if (this.start.row == row && this.start.column == column) { + return -1; + } else { + return this.compare(row, column); + } + }; + this.clipRows = function(firstRow, lastRow) { + if (this.end.row > lastRow) + var end = {row: lastRow + 1, column: 0}; + else if (this.end.row < firstRow) + var end = {row: firstRow, column: 0}; + + if (this.start.row > lastRow) + var start = {row: lastRow + 1, column: 0}; + else if (this.start.row < firstRow) + var start = {row: firstRow, column: 0}; + + return Range.fromPoints(start || this.start, end || this.end); + }; + this.extend = function(row, column) { + var cmp = this.compare(row, column); + + if (cmp == 0) + return this; + else if (cmp == -1) + var start = {row: row, column: column}; + else + var end = {row: row, column: column}; + + return Range.fromPoints(start || this.start, end || this.end); + }; + + this.isEmpty = function() { + return (this.start.row === this.end.row && this.start.column === this.end.column); + }; + this.isMultiLine = function() { + return (this.start.row !== this.end.row); + }; + this.clone = function() { + return Range.fromPoints(this.start, this.end); + }; + this.collapseRows = function() { + if (this.end.column == 0) + return new Range(this.start.row, 0, Math.max(this.start.row, this.end.row-1), 0); + else + return new Range(this.start.row, 0, this.end.row, 0); + }; + this.toScreenRange = function(session) { + var screenPosStart = session.documentToScreenPosition(this.start); + var screenPosEnd = session.documentToScreenPosition(this.end); + + return new Range( + screenPosStart.row, screenPosStart.column, + screenPosEnd.row, screenPosEnd.column + ); + }; + this.moveBy = function(row, column) { + this.start.row += row; + this.start.column += column; + this.end.row += row; + this.end.column += column; + }; + +}).call(Range.prototype); +Range.fromPoints = function(start, end) { + return new Range(start.row, start.column, end.row, end.column); +}; +Range.comparePoints = comparePoints; + +Range.comparePoints = function(p1, p2) { + return p1.row - p2.row || p1.column - p2.column; +}; + + +exports.Range = Range; +}); + +define("ace/lib/lang",["require","exports","module"], function(require, exports, module) { +"use strict"; + +exports.last = function(a) { + return a[a.length - 1]; +}; + +exports.stringReverse = function(string) { + return string.split("").reverse().join(""); +}; + +exports.stringRepeat = function (string, count) { + var result = ''; + while (count > 0) { + if (count & 1) + result += string; + + if (count >>= 1) + string += string; + } + return result; +}; + +var trimBeginRegexp = /^\s\s*/; +var trimEndRegexp = /\s\s*$/; + +exports.stringTrimLeft = function (string) { + return string.replace(trimBeginRegexp, ''); +}; + +exports.stringTrimRight = function (string) { + return string.replace(trimEndRegexp, ''); +}; + +exports.copyObject = function(obj) { + var copy = {}; + for (var key in obj) { + copy[key] = obj[key]; + } + return copy; +}; + +exports.copyArray = function(array){ + var copy = []; + for (var i=0, l=array.length; i Date.now() - 50) + return true; + return $cancelT = false; + }, + cancel: function() { + $cancelT = Date.now(); + } +}; + +}); + +define("ace/keyboard/textinput",["require","exports","module","ace/lib/event","ace/lib/useragent","ace/lib/dom","ace/lib/lang","ace/clipboard","ace/lib/keys"], function(require, exports, module) { +"use strict"; + +var event = require("../lib/event"); +var useragent = require("../lib/useragent"); +var dom = require("../lib/dom"); +var lang = require("../lib/lang"); +var clipboard = require("../clipboard"); +var BROKEN_SETDATA = useragent.isChrome < 18; +var USE_IE_MIME_TYPE = useragent.isIE; +var HAS_FOCUS_ARGS = useragent.isChrome > 63; +var MAX_LINE_LENGTH = 400; + +var KEYS = require("../lib/keys"); +var MODS = KEYS.KEY_MODS; +var isIOS = useragent.isIOS; +var valueResetRegex = isIOS ? /\s/ : /\n/; + +var TextInput = function(parentNode, host) { + var text = dom.createElement("textarea"); + text.className = "ace_text-input"; + + text.setAttribute("wrap", "off"); + text.setAttribute("autocorrect", "off"); + text.setAttribute("autocapitalize", "off"); + text.setAttribute("spellcheck", false); + + text.style.opacity = "0"; + parentNode.insertBefore(text, parentNode.firstChild); + + var copied = false; + var pasted = false; + var inComposition = false; + var sendingText = false; + var tempStyle = ''; + + if (!useragent.isMobile) + text.style.fontSize = "1px"; + + var commandMode = false; + var ignoreFocusEvents = false; + + var lastValue = ""; + var lastSelectionStart = 0; + var lastSelectionEnd = 0; + var lastRestoreEnd = 0; + try { var isFocused = document.activeElement === text; } catch(e) {} + + event.addListener(text, "blur", function(e) { + if (ignoreFocusEvents) return; + host.onBlur(e); + isFocused = false; + }); + event.addListener(text, "focus", function(e) { + if (ignoreFocusEvents) return; + isFocused = true; + if (useragent.isEdge) { + try { + if (!document.hasFocus()) + return; + } catch(e) {} + } + host.onFocus(e); + if (useragent.isEdge) + setTimeout(resetSelection); + else + resetSelection(); + }); + this.$focusScroll = false; + this.focus = function() { + if (tempStyle || HAS_FOCUS_ARGS || this.$focusScroll == "browser") + return text.focus({ preventScroll: true }); + + var top = text.style.top; + text.style.position = "fixed"; + text.style.top = "0px"; + try { + var isTransformed = text.getBoundingClientRect().top != 0; + } catch(e) { + return; + } + var ancestors = []; + if (isTransformed) { + var t = text.parentElement; + while (t && t.nodeType == 1) { + ancestors.push(t); + t.setAttribute("ace_nocontext", true); + if (!t.parentElement && t.getRootNode) + t = t.getRootNode().host; + else + t = t.parentElement; + } + } + text.focus({ preventScroll: true }); + if (isTransformed) { + ancestors.forEach(function(p) { + p.removeAttribute("ace_nocontext"); + }); + } + setTimeout(function() { + text.style.position = ""; + if (text.style.top == "0px") + text.style.top = top; + }, 0); + }; + this.blur = function() { + text.blur(); + }; + this.isFocused = function() { + return isFocused; + }; + + host.on("beforeEndOperation", function() { + if (host.curOp && host.curOp.command.name == "insertstring") + return; + if (inComposition) { + lastValue = text.value = ""; + onCompositionEnd(); + } + resetSelection(); + }); + + var resetSelection = isIOS + ? function(value) { + if (!isFocused || (copied && !value) || sendingText) return; + if (!value) + value = ""; + var newValue = "\n ab" + value + "cde fg\n"; + if (newValue != text.value) + text.value = lastValue = newValue; + + var selectionStart = 4; + var selectionEnd = 4 + (value.length || (host.selection.isEmpty() ? 0 : 1)); + + if (lastSelectionStart != selectionStart || lastSelectionEnd != selectionEnd) { + text.setSelectionRange(selectionStart, selectionEnd); + } + lastSelectionStart = selectionStart; + lastSelectionEnd = selectionEnd; + } + : function() { + if (inComposition || sendingText) + return; + if (!isFocused && !afterContextMenu) + return; + inComposition = true; + + var selection = host.selection; + var range = selection.getRange(); + var row = selection.cursor.row; + var selectionStart = range.start.column; + var selectionEnd = range.end.column; + var line = host.session.getLine(row); + + if (range.start.row != row) { + var prevLine = host.session.getLine(row - 1); + selectionStart = range.start.row < row - 1 ? 0 : selectionStart; + selectionEnd += prevLine.length + 1; + line = prevLine + "\n" + line; + } + else if (range.end.row != row) { + var nextLine = host.session.getLine(row + 1); + selectionEnd = range.end.row > row + 1 ? nextLine.length : selectionEnd; + selectionEnd += line.length + 1; + line = line + "\n" + nextLine; + } + + if (line.length > MAX_LINE_LENGTH) { + if (selectionStart < MAX_LINE_LENGTH && selectionEnd < MAX_LINE_LENGTH) { + line = line.slice(0, MAX_LINE_LENGTH); + } else { + line = "\n"; + selectionStart = 0; + selectionEnd = 1; + } + } + + var newValue = line + "\n\n"; + if (newValue != lastValue) { + text.value = lastValue = newValue; + lastSelectionStart = lastSelectionEnd = newValue.length; + } + if (afterContextMenu) { + lastSelectionStart = text.selectionStart; + lastSelectionEnd = text.selectionEnd; + } + if ( + lastSelectionEnd != selectionEnd + || lastSelectionStart != selectionStart + || text.selectionEnd != lastSelectionEnd // on ie edge selectionEnd changes silently after the initialization + ) { + try { + text.setSelectionRange(selectionStart, selectionEnd); + lastSelectionStart = selectionStart; + lastSelectionEnd = selectionEnd; + } catch(e){} + } + inComposition = false; + }; + + if (isFocused) + host.onFocus(); + + + var isAllSelected = function(text) { + return text.selectionStart === 0 && text.selectionEnd >= lastValue.length + && text.value === lastValue && lastValue + && text.selectionEnd !== lastSelectionEnd; + }; + + var onSelect = function(e) { + if (inComposition) + return; + if (copied) { + copied = false; + } else if (isAllSelected(text)) { + host.selectAll(); + resetSelection(); + } + }; + + var inputHandler = null; + this.setInputHandler = function(cb) {inputHandler = cb;}; + this.getInputHandler = function() {return inputHandler;}; + var afterContextMenu = false; + + var sendText = function(value, fromInput) { + if (afterContextMenu) + afterContextMenu = false; + if (pasted) { + resetSelection(); + if (value) + host.onPaste(value); + pasted = false; + return ""; + } else { + var selectionStart = text.selectionStart; + var selectionEnd = text.selectionEnd; + + var extendLeft = lastSelectionStart; + var extendRight = lastValue.length - lastSelectionEnd; + + var inserted = value; + var restoreStart = value.length - selectionStart; + var restoreEnd = value.length - selectionEnd; + + var i = 0; + while (extendLeft > 0 && lastValue[i] == value[i]) { + i++; + extendLeft--; + } + inserted = inserted.slice(i); + i = 1; + while (extendRight > 0 && lastValue.length - i > lastSelectionStart - 1 && lastValue[lastValue.length - i] == value[value.length - i]) { + i++; + extendRight--; + } + restoreStart -= i-1; + restoreEnd -= i-1; + var endIndex = inserted.length - i + 1; + if (endIndex < 0) { + extendLeft = -endIndex; + endIndex = 0; + } + inserted = inserted.slice(0, endIndex); + if (!fromInput && !inserted && !restoreStart && !extendLeft && !extendRight && !restoreEnd) + return ""; + sendingText = true; + if (inserted && !extendLeft && !extendRight && !restoreStart && !restoreEnd || commandMode) { + host.onTextInput(inserted); + } else { + host.onTextInput(inserted, { + extendLeft: extendLeft, + extendRight: extendRight, + restoreStart: restoreStart, + restoreEnd: restoreEnd + }); + } + sendingText = false; + + lastValue = value; + lastSelectionStart = selectionStart; + lastSelectionEnd = selectionEnd; + lastRestoreEnd = restoreEnd; + return inserted; + } + }; + var onInput = function(e) { + if (inComposition) + return onCompositionUpdate(); + if (e && e.inputType) { + if (e.inputType == "historyUndo") return host.execCommand("undo"); + if (e.inputType == "historyRedo") return host.execCommand("redo"); + } + var data = text.value; + var inserted = sendText(data, true); + if (data.length > MAX_LINE_LENGTH + 100 || valueResetRegex.test(inserted)) + resetSelection(); + }; + + var handleClipboardData = function(e, data, forceIEMime) { + var clipboardData = e.clipboardData || window.clipboardData; + if (!clipboardData || BROKEN_SETDATA) + return; + var mime = USE_IE_MIME_TYPE || forceIEMime ? "Text" : "text/plain"; + try { + if (data) { + return clipboardData.setData(mime, data) !== false; + } else { + return clipboardData.getData(mime); + } + } catch(e) { + if (!forceIEMime) + return handleClipboardData(e, data, true); + } + }; + + var doCopy = function(e, isCut) { + var data = host.getCopyText(); + if (!data) + return event.preventDefault(e); + + if (handleClipboardData(e, data)) { + if (isIOS) { + resetSelection(data); + copied = data; + setTimeout(function () { + copied = false; + }, 10); + } + isCut ? host.onCut() : host.onCopy(); + event.preventDefault(e); + } else { + copied = true; + text.value = data; + text.select(); + setTimeout(function(){ + copied = false; + resetSelection(); + isCut ? host.onCut() : host.onCopy(); + }); + } + }; + + var onCut = function(e) { + doCopy(e, true); + }; + + var onCopy = function(e) { + doCopy(e, false); + }; + + var onPaste = function(e) { + var data = handleClipboardData(e); + if (clipboard.pasteCancelled()) + return; + if (typeof data == "string") { + if (data) + host.onPaste(data, e); + if (useragent.isIE) + setTimeout(resetSelection); + event.preventDefault(e); + } + else { + text.value = ""; + pasted = true; + } + }; + + event.addCommandKeyListener(text, host.onCommandKey.bind(host)); + + event.addListener(text, "select", onSelect); + event.addListener(text, "input", onInput); + + event.addListener(text, "cut", onCut); + event.addListener(text, "copy", onCopy); + event.addListener(text, "paste", onPaste); + if (!('oncut' in text) || !('oncopy' in text) || !('onpaste' in text)) { + event.addListener(parentNode, "keydown", function(e) { + if ((useragent.isMac && !e.metaKey) || !e.ctrlKey) + return; + + switch (e.keyCode) { + case 67: + onCopy(e); + break; + case 86: + onPaste(e); + break; + case 88: + onCut(e); + break; + } + }); + } + var onCompositionStart = function(e) { + if (inComposition || !host.onCompositionStart || host.$readOnly) + return; + + inComposition = {}; + + if (commandMode) + return; + + setTimeout(onCompositionUpdate, 0); + host.on("mousedown", cancelComposition); + + var range = host.getSelectionRange(); + range.end.row = range.start.row; + range.end.column = range.start.column; + inComposition.markerRange = range; + inComposition.selectionStart = lastSelectionStart; + host.onCompositionStart(inComposition); + + if (inComposition.useTextareaForIME) { + text.value = ""; + lastValue = ""; + lastSelectionStart = 0; + lastSelectionEnd = 0; + } + else { + if (text.msGetInputContext) + inComposition.context = text.msGetInputContext(); + if (text.getInputContext) + inComposition.context = text.getInputContext(); + } + }; + + var onCompositionUpdate = function() { + if (!inComposition || !host.onCompositionUpdate || host.$readOnly) + return; + if (commandMode) + return cancelComposition(); + + if (inComposition.useTextareaForIME) { + host.onCompositionUpdate(text.value); + } + else { + var data = text.value; + sendText(data); + if (inComposition.markerRange) { + if (inComposition.context) { + inComposition.markerRange.start.column = inComposition.selectionStart + = inComposition.context.compositionStartOffset; + } + inComposition.markerRange.end.column = inComposition.markerRange.start.column + + lastSelectionEnd - inComposition.selectionStart + lastRestoreEnd; + } + } + }; + + var onCompositionEnd = function(e) { + if (!host.onCompositionEnd || host.$readOnly) return; + inComposition = false; + host.onCompositionEnd(); + host.off("mousedown", cancelComposition); + if (e) onInput(); + }; + + + function cancelComposition() { + ignoreFocusEvents = true; + text.blur(); + text.focus(); + ignoreFocusEvents = false; + } + + var syncComposition = lang.delayedCall(onCompositionUpdate, 50).schedule.bind(null, null); + + function onKeyup(e) { + if (e.keyCode == 27 && text.value.length < text.selectionStart) { + if (!inComposition) + lastValue = text.value; + lastSelectionStart = lastSelectionEnd = -1; + resetSelection(); + } + syncComposition(); + } + + event.addListener(text, "compositionstart", onCompositionStart); + event.addListener(text, "compositionupdate", onCompositionUpdate); + event.addListener(text, "keyup", onKeyup); + event.addListener(text, "keydown", syncComposition); + event.addListener(text, "compositionend", onCompositionEnd); + + this.getElement = function() { + return text; + }; + this.setCommandMode = function(value) { + commandMode = value; + text.readOnly = false; + }; + + this.setReadOnly = function(readOnly) { + if (!commandMode) + text.readOnly = readOnly; + }; + + this.setCopyWithEmptySelection = function(value) { + }; + + this.onContextMenu = function(e) { + afterContextMenu = true; + resetSelection(); + host._emit("nativecontextmenu", {target: host, domEvent: e}); + this.moveToMouse(e, true); + }; + + this.moveToMouse = function(e, bringToFront) { + if (!tempStyle) + tempStyle = text.style.cssText; + text.style.cssText = (bringToFront ? "z-index:100000;" : "") + + (useragent.isIE ? "opacity:0.1;" : "") + + "text-indent: -" + (lastSelectionStart + lastSelectionEnd) * host.renderer.characterWidth * 0.5 + "px;"; + + var rect = host.container.getBoundingClientRect(); + var style = dom.computedStyle(host.container); + var top = rect.top + (parseInt(style.borderTopWidth) || 0); + var left = rect.left + (parseInt(rect.borderLeftWidth) || 0); + var maxTop = rect.bottom - top - text.clientHeight -2; + var move = function(e) { + dom.translate(text, e.clientX - left - 2, Math.min(e.clientY - top - 2, maxTop)); + }; + move(e); + + if (e.type != "mousedown") + return; + + host.renderer.$isMousePressed = true; + + clearTimeout(closeTimeout); + if (useragent.isWin) + event.capture(host.container, move, onContextMenuClose); + }; + + this.onContextMenuClose = onContextMenuClose; + var closeTimeout; + function onContextMenuClose() { + clearTimeout(closeTimeout); + closeTimeout = setTimeout(function () { + if (tempStyle) { + text.style.cssText = tempStyle; + tempStyle = ''; + } + host.renderer.$isMousePressed = false; + if (host.renderer.$keepTextAreaAtCursor) + host.renderer.$moveTextAreaToCursor(); + }, 0); + } + + var onContextMenu = function(e) { + host.textInput.onContextMenu(e); + onContextMenuClose(); + }; + event.addListener(text, "mouseup", onContextMenu); + event.addListener(text, "mousedown", function(e) { + e.preventDefault(); + onContextMenuClose(); + }); + event.addListener(host.renderer.scroller, "contextmenu", onContextMenu); + event.addListener(text, "contextmenu", onContextMenu); + + if (isIOS) + addIosSelectionHandler(parentNode, host, text); + + function addIosSelectionHandler(parentNode, host, text) { + var typingResetTimeout = null; + var typing = false; + + text.addEventListener("keydown", function (e) { + if (typingResetTimeout) clearTimeout(typingResetTimeout); + typing = true; + }, true); + + text.addEventListener("keyup", function (e) { + typingResetTimeout = setTimeout(function () { + typing = false; + }, 100); + }, true); + var detectArrowKeys = function(e) { + if (document.activeElement !== text) return; + if (typing || inComposition || host.$mouseHandler.isMousePressed) return; + + if (copied) { + return; + } + var selectionStart = text.selectionStart; + var selectionEnd = text.selectionEnd; + + var key = null; + var modifier = 0; + if (selectionStart == 0) { + key = KEYS.up; + } else if (selectionStart == 1) { + key = KEYS.home; + } else if (selectionEnd > lastSelectionEnd && lastValue[selectionEnd] == "\n") { + key = KEYS.end; + } else if (selectionStart < lastSelectionStart && lastValue[selectionStart - 1] == " ") { + key = KEYS.left; + modifier = MODS.option; + } else if ( + selectionStart < lastSelectionStart + || ( + selectionStart == lastSelectionStart + && lastSelectionEnd != lastSelectionStart + && selectionStart == selectionEnd + ) + ) { + key = KEYS.left; + } else if (selectionEnd > lastSelectionEnd && lastValue.slice(0, selectionEnd).split("\n").length > 2) { + key = KEYS.down; + } else if (selectionEnd > lastSelectionEnd && lastValue[selectionEnd - 1] == " ") { + key = KEYS.right; + modifier = MODS.option; + } else if ( + selectionEnd > lastSelectionEnd + || ( + selectionEnd == lastSelectionEnd + && lastSelectionEnd != lastSelectionStart + && selectionStart == selectionEnd + ) + ) { + key = KEYS.right; + } + + if (selectionStart !== selectionEnd) + modifier |= MODS.shift; + + if (key) { + var result = host.onCommandKey({}, modifier, key); + if (!result && host.commands) { + key = KEYS.keyCodeToString(key); + var command = host.commands.findKeyCommand(modifier, key); + if (command) + host.execCommand(command); + } + lastSelectionStart = selectionStart; + lastSelectionEnd = selectionEnd; + resetSelection(""); + } + }; + document.addEventListener("selectionchange", detectArrowKeys); + host.on("destroy", function() { + document.removeEventListener("selectionchange", detectArrowKeys); + }); + } + +}; + +exports.TextInput = TextInput; +}); + +define("ace/mouse/default_handlers",["require","exports","module","ace/lib/useragent"], function(require, exports, module) { +"use strict"; + +var useragent = require("../lib/useragent"); + +var DRAG_OFFSET = 0; // pixels +var SCROLL_COOLDOWN_T = 550; // milliseconds + +function DefaultHandlers(mouseHandler) { + mouseHandler.$clickSelection = null; + + var editor = mouseHandler.editor; + editor.setDefaultHandler("mousedown", this.onMouseDown.bind(mouseHandler)); + editor.setDefaultHandler("dblclick", this.onDoubleClick.bind(mouseHandler)); + editor.setDefaultHandler("tripleclick", this.onTripleClick.bind(mouseHandler)); + editor.setDefaultHandler("quadclick", this.onQuadClick.bind(mouseHandler)); + editor.setDefaultHandler("mousewheel", this.onMouseWheel.bind(mouseHandler)); + + var exports = ["select", "startSelect", "selectEnd", "selectAllEnd", "selectByWordsEnd", + "selectByLinesEnd", "dragWait", "dragWaitEnd", "focusWait"]; + + exports.forEach(function(x) { + mouseHandler[x] = this[x]; + }, this); + + mouseHandler.selectByLines = this.extendSelectionBy.bind(mouseHandler, "getLineRange"); + mouseHandler.selectByWords = this.extendSelectionBy.bind(mouseHandler, "getWordRange"); +} + +(function() { + + this.onMouseDown = function(ev) { + var inSelection = ev.inSelection(); + var pos = ev.getDocumentPosition(); + this.mousedownEvent = ev; + var editor = this.editor; + + var button = ev.getButton(); + if (button !== 0) { + var selectionRange = editor.getSelectionRange(); + var selectionEmpty = selectionRange.isEmpty(); + if (selectionEmpty || button == 1) + editor.selection.moveToPosition(pos); + if (button == 2) { + editor.textInput.onContextMenu(ev.domEvent); + if (!useragent.isMozilla) + ev.preventDefault(); + } + return; + } + + this.mousedownEvent.time = Date.now(); + if (inSelection && !editor.isFocused()) { + editor.focus(); + if (this.$focusTimeout && !this.$clickSelection && !editor.inMultiSelectMode) { + this.setState("focusWait"); + this.captureMouse(ev); + return; + } + } + + this.captureMouse(ev); + this.startSelect(pos, ev.domEvent._clicks > 1); + return ev.preventDefault(); + }; + + this.startSelect = function(pos, waitForClickSelection) { + pos = pos || this.editor.renderer.screenToTextCoordinates(this.x, this.y); + var editor = this.editor; + if (!this.mousedownEvent) return; + if (this.mousedownEvent.getShiftKey()) + editor.selection.selectToPosition(pos); + else if (!waitForClickSelection) + editor.selection.moveToPosition(pos); + if (!waitForClickSelection) + this.select(); + if (editor.renderer.scroller.setCapture) { + editor.renderer.scroller.setCapture(); + } + editor.setStyle("ace_selecting"); + this.setState("select"); + }; + + this.select = function() { + var anchor, editor = this.editor; + var cursor = editor.renderer.screenToTextCoordinates(this.x, this.y); + if (this.$clickSelection) { + var cmp = this.$clickSelection.comparePoint(cursor); + + if (cmp == -1) { + anchor = this.$clickSelection.end; + } else if (cmp == 1) { + anchor = this.$clickSelection.start; + } else { + var orientedRange = calcRangeOrientation(this.$clickSelection, cursor); + cursor = orientedRange.cursor; + anchor = orientedRange.anchor; + } + editor.selection.setSelectionAnchor(anchor.row, anchor.column); + } + editor.selection.selectToPosition(cursor); + editor.renderer.scrollCursorIntoView(); + }; + + this.extendSelectionBy = function(unitName) { + var anchor, editor = this.editor; + var cursor = editor.renderer.screenToTextCoordinates(this.x, this.y); + var range = editor.selection[unitName](cursor.row, cursor.column); + if (this.$clickSelection) { + var cmpStart = this.$clickSelection.comparePoint(range.start); + var cmpEnd = this.$clickSelection.comparePoint(range.end); + + if (cmpStart == -1 && cmpEnd <= 0) { + anchor = this.$clickSelection.end; + if (range.end.row != cursor.row || range.end.column != cursor.column) + cursor = range.start; + } else if (cmpEnd == 1 && cmpStart >= 0) { + anchor = this.$clickSelection.start; + if (range.start.row != cursor.row || range.start.column != cursor.column) + cursor = range.end; + } else if (cmpStart == -1 && cmpEnd == 1) { + cursor = range.end; + anchor = range.start; + } else { + var orientedRange = calcRangeOrientation(this.$clickSelection, cursor); + cursor = orientedRange.cursor; + anchor = orientedRange.anchor; + } + editor.selection.setSelectionAnchor(anchor.row, anchor.column); + } + editor.selection.selectToPosition(cursor); + editor.renderer.scrollCursorIntoView(); + }; + + this.selectEnd = + this.selectAllEnd = + this.selectByWordsEnd = + this.selectByLinesEnd = function() { + this.$clickSelection = null; + this.editor.unsetStyle("ace_selecting"); + if (this.editor.renderer.scroller.releaseCapture) { + this.editor.renderer.scroller.releaseCapture(); + } + }; + + this.focusWait = function() { + var distance = calcDistance(this.mousedownEvent.x, this.mousedownEvent.y, this.x, this.y); + var time = Date.now(); + + if (distance > DRAG_OFFSET || time - this.mousedownEvent.time > this.$focusTimeout) + this.startSelect(this.mousedownEvent.getDocumentPosition()); + }; + + this.onDoubleClick = function(ev) { + var pos = ev.getDocumentPosition(); + var editor = this.editor; + var session = editor.session; + + var range = session.getBracketRange(pos); + if (range) { + if (range.isEmpty()) { + range.start.column--; + range.end.column++; + } + this.setState("select"); + } else { + range = editor.selection.getWordRange(pos.row, pos.column); + this.setState("selectByWords"); + } + this.$clickSelection = range; + this.select(); + }; + + this.onTripleClick = function(ev) { + var pos = ev.getDocumentPosition(); + var editor = this.editor; + + this.setState("selectByLines"); + var range = editor.getSelectionRange(); + if (range.isMultiLine() && range.contains(pos.row, pos.column)) { + this.$clickSelection = editor.selection.getLineRange(range.start.row); + this.$clickSelection.end = editor.selection.getLineRange(range.end.row).end; + } else { + this.$clickSelection = editor.selection.getLineRange(pos.row); + } + this.select(); + }; + + this.onQuadClick = function(ev) { + var editor = this.editor; + + editor.selectAll(); + this.$clickSelection = editor.getSelectionRange(); + this.setState("selectAll"); + }; + + this.onMouseWheel = function(ev) { + if (ev.getAccelKey()) + return; + if (ev.getShiftKey() && ev.wheelY && !ev.wheelX) { + ev.wheelX = ev.wheelY; + ev.wheelY = 0; + } + + var editor = this.editor; + + if (!this.$lastScroll) + this.$lastScroll = { t: 0, vx: 0, vy: 0, allowed: 0 }; + + var prevScroll = this.$lastScroll; + var t = ev.domEvent.timeStamp; + var dt = t - prevScroll.t; + var vx = dt ? ev.wheelX / dt : prevScroll.vx; + var vy = dt ? ev.wheelY / dt : prevScroll.vy; + if (dt < SCROLL_COOLDOWN_T) { + vx = (vx + prevScroll.vx) / 2; + vy = (vy + prevScroll.vy) / 2; + } + + var direction = Math.abs(vx / vy); + + var canScroll = false; + if (direction >= 1 && editor.renderer.isScrollableBy(ev.wheelX * ev.speed, 0)) + canScroll = true; + if (direction <= 1 && editor.renderer.isScrollableBy(0, ev.wheelY * ev.speed)) + canScroll = true; + + if (canScroll) { + prevScroll.allowed = t; + } else if (t - prevScroll.allowed < SCROLL_COOLDOWN_T) { + var isSlower = Math.abs(vx) <= 1.5 * Math.abs(prevScroll.vx) + && Math.abs(vy) <= 1.5 * Math.abs(prevScroll.vy); + if (isSlower) { + canScroll = true; + prevScroll.allowed = t; + } + else { + prevScroll.allowed = 0; + } + } + + prevScroll.t = t; + prevScroll.vx = vx; + prevScroll.vy = vy; + + if (canScroll) { + editor.renderer.scrollBy(ev.wheelX * ev.speed, ev.wheelY * ev.speed); + return ev.stop(); + } + }; + +}).call(DefaultHandlers.prototype); + +exports.DefaultHandlers = DefaultHandlers; + +function calcDistance(ax, ay, bx, by) { + return Math.sqrt(Math.pow(bx - ax, 2) + Math.pow(by - ay, 2)); +} + +function calcRangeOrientation(range, cursor) { + if (range.start.row == range.end.row) + var cmp = 2 * cursor.column - range.start.column - range.end.column; + else if (range.start.row == range.end.row - 1 && !range.start.column && !range.end.column) + var cmp = cursor.column - 4; + else + var cmp = 2 * cursor.row - range.start.row - range.end.row; + + if (cmp < 0) + return {cursor: range.start, anchor: range.end}; + else + return {cursor: range.end, anchor: range.start}; +} + +}); + +define("ace/tooltip",["require","exports","module","ace/lib/oop","ace/lib/dom"], function(require, exports, module) { +"use strict"; + +var oop = require("./lib/oop"); +var dom = require("./lib/dom"); +function Tooltip (parentNode) { + this.isOpen = false; + this.$element = null; + this.$parentNode = parentNode; +} + +(function() { + this.$init = function() { + this.$element = dom.createElement("div"); + this.$element.className = "ace_tooltip"; + this.$element.style.display = "none"; + this.$parentNode.appendChild(this.$element); + return this.$element; + }; + this.getElement = function() { + return this.$element || this.$init(); + }; + this.setText = function(text) { + this.getElement().textContent = text; + }; + this.setHtml = function(html) { + this.getElement().innerHTML = html; + }; + this.setPosition = function(x, y) { + this.getElement().style.left = x + "px"; + this.getElement().style.top = y + "px"; + }; + this.setClassName = function(className) { + dom.addCssClass(this.getElement(), className); + }; + this.show = function(text, x, y) { + if (text != null) + this.setText(text); + if (x != null && y != null) + this.setPosition(x, y); + if (!this.isOpen) { + this.getElement().style.display = "block"; + this.isOpen = true; + } + }; + + this.hide = function() { + if (this.isOpen) { + this.getElement().style.display = "none"; + this.isOpen = false; + } + }; + this.getHeight = function() { + return this.getElement().offsetHeight; + }; + this.getWidth = function() { + return this.getElement().offsetWidth; + }; + + this.destroy = function() { + this.isOpen = false; + if (this.$element && this.$element.parentNode) { + this.$element.parentNode.removeChild(this.$element); + } + }; + +}).call(Tooltip.prototype); + +exports.Tooltip = Tooltip; +}); + +define("ace/mouse/default_gutter_handler",["require","exports","module","ace/lib/dom","ace/lib/oop","ace/lib/event","ace/tooltip"], function(require, exports, module) { +"use strict"; +var dom = require("../lib/dom"); +var oop = require("../lib/oop"); +var event = require("../lib/event"); +var Tooltip = require("../tooltip").Tooltip; + +function GutterHandler(mouseHandler) { + var editor = mouseHandler.editor; + var gutter = editor.renderer.$gutterLayer; + var tooltip = new GutterTooltip(editor.container); + + mouseHandler.editor.setDefaultHandler("guttermousedown", function(e) { + if (!editor.isFocused() || e.getButton() != 0) + return; + var gutterRegion = gutter.getRegion(e); + + if (gutterRegion == "foldWidgets") + return; + + var row = e.getDocumentPosition().row; + var selection = editor.session.selection; + + if (e.getShiftKey()) + selection.selectTo(row, 0); + else { + if (e.domEvent.detail == 2) { + editor.selectAll(); + return e.preventDefault(); + } + mouseHandler.$clickSelection = editor.selection.getLineRange(row); + } + mouseHandler.setState("selectByLines"); + mouseHandler.captureMouse(e); + return e.preventDefault(); + }); + + + var tooltipTimeout, mouseEvent, tooltipAnnotation; + + function showTooltip() { + var row = mouseEvent.getDocumentPosition().row; + var annotation = gutter.$annotations[row]; + if (!annotation) + return hideTooltip(); + + var maxRow = editor.session.getLength(); + if (row == maxRow) { + var screenRow = editor.renderer.pixelToScreenCoordinates(0, mouseEvent.y).row; + var pos = mouseEvent.$pos; + if (screenRow > editor.session.documentToScreenRow(pos.row, pos.column)) + return hideTooltip(); + } + + if (tooltipAnnotation == annotation) + return; + tooltipAnnotation = annotation.text.join("
"); + + tooltip.setHtml(tooltipAnnotation); + tooltip.show(); + editor._signal("showGutterTooltip", tooltip); + editor.on("mousewheel", hideTooltip); + + if (mouseHandler.$tooltipFollowsMouse) { + moveTooltip(mouseEvent); + } else { + var gutterElement = mouseEvent.domEvent.target; + var rect = gutterElement.getBoundingClientRect(); + var style = tooltip.getElement().style; + style.left = rect.right + "px"; + style.top = rect.bottom + "px"; + } + } + + function hideTooltip() { + if (tooltipTimeout) + tooltipTimeout = clearTimeout(tooltipTimeout); + if (tooltipAnnotation) { + tooltip.hide(); + tooltipAnnotation = null; + editor._signal("hideGutterTooltip", tooltip); + editor.removeEventListener("mousewheel", hideTooltip); + } + } + + function moveTooltip(e) { + tooltip.setPosition(e.x, e.y); + } + + mouseHandler.editor.setDefaultHandler("guttermousemove", function(e) { + var target = e.domEvent.target || e.domEvent.srcElement; + if (dom.hasCssClass(target, "ace_fold-widget")) + return hideTooltip(); + + if (tooltipAnnotation && mouseHandler.$tooltipFollowsMouse) + moveTooltip(e); + + mouseEvent = e; + if (tooltipTimeout) + return; + tooltipTimeout = setTimeout(function() { + tooltipTimeout = null; + if (mouseEvent && !mouseHandler.isMousePressed) + showTooltip(); + else + hideTooltip(); + }, 50); + }); + + event.addListener(editor.renderer.$gutter, "mouseout", function(e) { + mouseEvent = null; + if (!tooltipAnnotation || tooltipTimeout) + return; + + tooltipTimeout = setTimeout(function() { + tooltipTimeout = null; + hideTooltip(); + }, 50); + }); + + editor.on("changeSession", hideTooltip); +} + +function GutterTooltip(parentNode) { + Tooltip.call(this, parentNode); +} + +oop.inherits(GutterTooltip, Tooltip); + +(function(){ + this.setPosition = function(x, y) { + var windowWidth = window.innerWidth || document.documentElement.clientWidth; + var windowHeight = window.innerHeight || document.documentElement.clientHeight; + var width = this.getWidth(); + var height = this.getHeight(); + x += 15; + y += 15; + if (x + width > windowWidth) { + x -= (x + width) - windowWidth; + } + if (y + height > windowHeight) { + y -= 20 + height; + } + Tooltip.prototype.setPosition.call(this, x, y); + }; + +}).call(GutterTooltip.prototype); + + + +exports.GutterHandler = GutterHandler; + +}); + +define("ace/mouse/mouse_event",["require","exports","module","ace/lib/event","ace/lib/useragent"], function(require, exports, module) { +"use strict"; + +var event = require("../lib/event"); +var useragent = require("../lib/useragent"); +var MouseEvent = exports.MouseEvent = function(domEvent, editor) { + this.domEvent = domEvent; + this.editor = editor; + + this.x = this.clientX = domEvent.clientX; + this.y = this.clientY = domEvent.clientY; + + this.$pos = null; + this.$inSelection = null; + + this.propagationStopped = false; + this.defaultPrevented = false; +}; + +(function() { + + this.stopPropagation = function() { + event.stopPropagation(this.domEvent); + this.propagationStopped = true; + }; + + this.preventDefault = function() { + event.preventDefault(this.domEvent); + this.defaultPrevented = true; + }; + + this.stop = function() { + this.stopPropagation(); + this.preventDefault(); + }; + this.getDocumentPosition = function() { + if (this.$pos) + return this.$pos; + + this.$pos = this.editor.renderer.screenToTextCoordinates(this.clientX, this.clientY); + return this.$pos; + }; + this.inSelection = function() { + if (this.$inSelection !== null) + return this.$inSelection; + + var editor = this.editor; + + + var selectionRange = editor.getSelectionRange(); + if (selectionRange.isEmpty()) + this.$inSelection = false; + else { + var pos = this.getDocumentPosition(); + this.$inSelection = selectionRange.contains(pos.row, pos.column); + } + + return this.$inSelection; + }; + this.getButton = function() { + return event.getButton(this.domEvent); + }; + this.getShiftKey = function() { + return this.domEvent.shiftKey; + }; + + this.getAccelKey = useragent.isMac + ? function() { return this.domEvent.metaKey; } + : function() { return this.domEvent.ctrlKey; }; + +}).call(MouseEvent.prototype); + +}); + +define("ace/mouse/dragdrop_handler",["require","exports","module","ace/lib/dom","ace/lib/event","ace/lib/useragent"], function(require, exports, module) { +"use strict"; + +var dom = require("../lib/dom"); +var event = require("../lib/event"); +var useragent = require("../lib/useragent"); + +var AUTOSCROLL_DELAY = 200; +var SCROLL_CURSOR_DELAY = 200; +var SCROLL_CURSOR_HYSTERESIS = 5; + +function DragdropHandler(mouseHandler) { + + var editor = mouseHandler.editor; + + var blankImage = dom.createElement("img"); + blankImage.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; + if (useragent.isOpera) + blankImage.style.cssText = "width:1px;height:1px;position:fixed;top:0;left:0;z-index:2147483647;opacity:0;"; + + var exports = ["dragWait", "dragWaitEnd", "startDrag", "dragReadyEnd", "onMouseDrag"]; + + exports.forEach(function(x) { + mouseHandler[x] = this[x]; + }, this); + editor.addEventListener("mousedown", this.onMouseDown.bind(mouseHandler)); + + + var mouseTarget = editor.container; + var dragSelectionMarker, x, y; + var timerId, range; + var dragCursor, counter = 0; + var dragOperation; + var isInternal; + var autoScrollStartTime; + var cursorMovedTime; + var cursorPointOnCaretMoved; + + this.onDragStart = function(e) { + if (this.cancelDrag || !mouseTarget.draggable) { + var self = this; + setTimeout(function(){ + self.startSelect(); + self.captureMouse(e); + }, 0); + return e.preventDefault(); + } + range = editor.getSelectionRange(); + + var dataTransfer = e.dataTransfer; + dataTransfer.effectAllowed = editor.getReadOnly() ? "copy" : "copyMove"; + if (useragent.isOpera) { + editor.container.appendChild(blankImage); + blankImage.scrollTop = 0; + } + dataTransfer.setDragImage && dataTransfer.setDragImage(blankImage, 0, 0); + if (useragent.isOpera) { + editor.container.removeChild(blankImage); + } + dataTransfer.clearData(); + dataTransfer.setData("Text", editor.session.getTextRange()); + + isInternal = true; + this.setState("drag"); + }; + + this.onDragEnd = function(e) { + mouseTarget.draggable = false; + isInternal = false; + this.setState(null); + if (!editor.getReadOnly()) { + var dropEffect = e.dataTransfer.dropEffect; + if (!dragOperation && dropEffect == "move") + editor.session.remove(editor.getSelectionRange()); + editor.$resetCursorStyle(); + } + this.editor.unsetStyle("ace_dragging"); + this.editor.renderer.setCursorStyle(""); + }; + + this.onDragEnter = function(e) { + if (editor.getReadOnly() || !canAccept(e.dataTransfer)) + return; + x = e.clientX; + y = e.clientY; + if (!dragSelectionMarker) + addDragMarker(); + counter++; + e.dataTransfer.dropEffect = dragOperation = getDropEffect(e); + return event.preventDefault(e); + }; + + this.onDragOver = function(e) { + if (editor.getReadOnly() || !canAccept(e.dataTransfer)) + return; + x = e.clientX; + y = e.clientY; + if (!dragSelectionMarker) { + addDragMarker(); + counter++; + } + if (onMouseMoveTimer !== null) + onMouseMoveTimer = null; + + e.dataTransfer.dropEffect = dragOperation = getDropEffect(e); + return event.preventDefault(e); + }; + + this.onDragLeave = function(e) { + counter--; + if (counter <= 0 && dragSelectionMarker) { + clearDragMarker(); + dragOperation = null; + return event.preventDefault(e); + } + }; + + this.onDrop = function(e) { + if (!dragCursor) + return; + var dataTransfer = e.dataTransfer; + if (isInternal) { + switch (dragOperation) { + case "move": + if (range.contains(dragCursor.row, dragCursor.column)) { + range = { + start: dragCursor, + end: dragCursor + }; + } else { + range = editor.moveText(range, dragCursor); + } + break; + case "copy": + range = editor.moveText(range, dragCursor, true); + break; + } + } else { + var dropData = dataTransfer.getData('Text'); + range = { + start: dragCursor, + end: editor.session.insert(dragCursor, dropData) + }; + editor.focus(); + dragOperation = null; + } + clearDragMarker(); + return event.preventDefault(e); + }; + + event.addListener(mouseTarget, "dragstart", this.onDragStart.bind(mouseHandler)); + event.addListener(mouseTarget, "dragend", this.onDragEnd.bind(mouseHandler)); + event.addListener(mouseTarget, "dragenter", this.onDragEnter.bind(mouseHandler)); + event.addListener(mouseTarget, "dragover", this.onDragOver.bind(mouseHandler)); + event.addListener(mouseTarget, "dragleave", this.onDragLeave.bind(mouseHandler)); + event.addListener(mouseTarget, "drop", this.onDrop.bind(mouseHandler)); + + function scrollCursorIntoView(cursor, prevCursor) { + var now = Date.now(); + var vMovement = !prevCursor || cursor.row != prevCursor.row; + var hMovement = !prevCursor || cursor.column != prevCursor.column; + if (!cursorMovedTime || vMovement || hMovement) { + editor.moveCursorToPosition(cursor); + cursorMovedTime = now; + cursorPointOnCaretMoved = {x: x, y: y}; + } else { + var distance = calcDistance(cursorPointOnCaretMoved.x, cursorPointOnCaretMoved.y, x, y); + if (distance > SCROLL_CURSOR_HYSTERESIS) { + cursorMovedTime = null; + } else if (now - cursorMovedTime >= SCROLL_CURSOR_DELAY) { + editor.renderer.scrollCursorIntoView(); + cursorMovedTime = null; + } + } + } + + function autoScroll(cursor, prevCursor) { + var now = Date.now(); + var lineHeight = editor.renderer.layerConfig.lineHeight; + var characterWidth = editor.renderer.layerConfig.characterWidth; + var editorRect = editor.renderer.scroller.getBoundingClientRect(); + var offsets = { + x: { + left: x - editorRect.left, + right: editorRect.right - x + }, + y: { + top: y - editorRect.top, + bottom: editorRect.bottom - y + } + }; + var nearestXOffset = Math.min(offsets.x.left, offsets.x.right); + var nearestYOffset = Math.min(offsets.y.top, offsets.y.bottom); + var scrollCursor = {row: cursor.row, column: cursor.column}; + if (nearestXOffset / characterWidth <= 2) { + scrollCursor.column += (offsets.x.left < offsets.x.right ? -3 : +2); + } + if (nearestYOffset / lineHeight <= 1) { + scrollCursor.row += (offsets.y.top < offsets.y.bottom ? -1 : +1); + } + var vScroll = cursor.row != scrollCursor.row; + var hScroll = cursor.column != scrollCursor.column; + var vMovement = !prevCursor || cursor.row != prevCursor.row; + if (vScroll || (hScroll && !vMovement)) { + if (!autoScrollStartTime) + autoScrollStartTime = now; + else if (now - autoScrollStartTime >= AUTOSCROLL_DELAY) + editor.renderer.scrollCursorIntoView(scrollCursor); + } else { + autoScrollStartTime = null; + } + } + + function onDragInterval() { + var prevCursor = dragCursor; + dragCursor = editor.renderer.screenToTextCoordinates(x, y); + scrollCursorIntoView(dragCursor, prevCursor); + autoScroll(dragCursor, prevCursor); + } + + function addDragMarker() { + range = editor.selection.toOrientedRange(); + dragSelectionMarker = editor.session.addMarker(range, "ace_selection", editor.getSelectionStyle()); + editor.clearSelection(); + if (editor.isFocused()) + editor.renderer.$cursorLayer.setBlinking(false); + clearInterval(timerId); + onDragInterval(); + timerId = setInterval(onDragInterval, 20); + counter = 0; + event.addListener(document, "mousemove", onMouseMove); + } + + function clearDragMarker() { + clearInterval(timerId); + editor.session.removeMarker(dragSelectionMarker); + dragSelectionMarker = null; + editor.selection.fromOrientedRange(range); + if (editor.isFocused() && !isInternal) + editor.$resetCursorStyle(); + range = null; + dragCursor = null; + counter = 0; + autoScrollStartTime = null; + cursorMovedTime = null; + event.removeListener(document, "mousemove", onMouseMove); + } + var onMouseMoveTimer = null; + function onMouseMove() { + if (onMouseMoveTimer == null) { + onMouseMoveTimer = setTimeout(function() { + if (onMouseMoveTimer != null && dragSelectionMarker) + clearDragMarker(); + }, 20); + } + } + + function canAccept(dataTransfer) { + var types = dataTransfer.types; + return !types || Array.prototype.some.call(types, function(type) { + return type == 'text/plain' || type == 'Text'; + }); + } + + function getDropEffect(e) { + var copyAllowed = ['copy', 'copymove', 'all', 'uninitialized']; + var moveAllowed = ['move', 'copymove', 'linkmove', 'all', 'uninitialized']; + + var copyModifierState = useragent.isMac ? e.altKey : e.ctrlKey; + var effectAllowed = "uninitialized"; + try { + effectAllowed = e.dataTransfer.effectAllowed.toLowerCase(); + } catch (e) {} + var dropEffect = "none"; + + if (copyModifierState && copyAllowed.indexOf(effectAllowed) >= 0) + dropEffect = "copy"; + else if (moveAllowed.indexOf(effectAllowed) >= 0) + dropEffect = "move"; + else if (copyAllowed.indexOf(effectAllowed) >= 0) + dropEffect = "copy"; + + return dropEffect; + } +} + +(function() { + + this.dragWait = function() { + var interval = Date.now() - this.mousedownEvent.time; + if (interval > this.editor.getDragDelay()) + this.startDrag(); + }; + + this.dragWaitEnd = function() { + var target = this.editor.container; + target.draggable = false; + this.startSelect(this.mousedownEvent.getDocumentPosition()); + this.selectEnd(); + }; + + this.dragReadyEnd = function(e) { + this.editor.$resetCursorStyle(); + this.editor.unsetStyle("ace_dragging"); + this.editor.renderer.setCursorStyle(""); + this.dragWaitEnd(); + }; + + this.startDrag = function(){ + this.cancelDrag = false; + var editor = this.editor; + var target = editor.container; + target.draggable = true; + editor.renderer.$cursorLayer.setBlinking(false); + editor.setStyle("ace_dragging"); + var cursorStyle = useragent.isWin ? "default" : "move"; + editor.renderer.setCursorStyle(cursorStyle); + this.setState("dragReady"); + }; + + this.onMouseDrag = function(e) { + var target = this.editor.container; + if (useragent.isIE && this.state == "dragReady") { + var distance = calcDistance(this.mousedownEvent.x, this.mousedownEvent.y, this.x, this.y); + if (distance > 3) + target.dragDrop(); + } + if (this.state === "dragWait") { + var distance = calcDistance(this.mousedownEvent.x, this.mousedownEvent.y, this.x, this.y); + if (distance > 0) { + target.draggable = false; + this.startSelect(this.mousedownEvent.getDocumentPosition()); + } + } + }; + + this.onMouseDown = function(e) { + if (!this.$dragEnabled) + return; + this.mousedownEvent = e; + var editor = this.editor; + + var inSelection = e.inSelection(); + var button = e.getButton(); + var clickCount = e.domEvent.detail || 1; + if (clickCount === 1 && button === 0 && inSelection) { + if (e.editor.inMultiSelectMode && (e.getAccelKey() || e.getShiftKey())) + return; + this.mousedownEvent.time = Date.now(); + var eventTarget = e.domEvent.target || e.domEvent.srcElement; + if ("unselectable" in eventTarget) + eventTarget.unselectable = "on"; + if (editor.getDragDelay()) { + if (useragent.isWebKit) { + this.cancelDrag = true; + var mouseTarget = editor.container; + mouseTarget.draggable = true; + } + this.setState("dragWait"); + } else { + this.startDrag(); + } + this.captureMouse(e, this.onMouseDrag.bind(this)); + e.defaultPrevented = true; + } + }; + +}).call(DragdropHandler.prototype); + + +function calcDistance(ax, ay, bx, by) { + return Math.sqrt(Math.pow(bx - ax, 2) + Math.pow(by - ay, 2)); +} + +exports.DragdropHandler = DragdropHandler; + +}); + +define("ace/mouse/touch_handler",["require","exports","module","ace/mouse/mouse_event","ace/lib/dom"], function(require, exports, module) { +"use strict"; + +var MouseEvent = require("./mouse_event").MouseEvent; +var dom = require("../lib/dom"); + +exports.addTouchListeners = function(el, editor) { + var mode = "scroll"; + var startX; + var startY; + var touchStartT; + var lastT; + var longTouchTimer; + var animationTimer; + var animationSteps = 0; + var pos; + var clickCount = 0; + var vX = 0; + var vY = 0; + var pressed; + var contextMenu; + + function createContextMenu() { + var clipboard = window.navigator && window.navigator.clipboard; + var isOpen = false; + var updateMenu = function() { + var selected = editor.getCopyText(); + var hasUndo = editor.session.getUndoManager().hasUndo(); + contextMenu.replaceChild( + dom.buildDom(isOpen ? ["span", + !selected && ["span", { class: "ace_mobile-button", action: "selectall" }, "Select All"], + selected && ["span", { class: "ace_mobile-button", action: "copy" }, "Copy"], + selected && ["span", { class: "ace_mobile-button", action: "cut" }, "Cut"], + clipboard && ["span", { class: "ace_mobile-button", action: "paste" }, "Paste"], + hasUndo && ["span", { class: "ace_mobile-button", action: "undo" }, "Undo"], + ["span", { class: "ace_mobile-button", action: "find" }, "Find"], + ["span", { class: "ace_mobile-button", action: "openCommandPallete" }, "Pallete"] + ] : ["span"]), + contextMenu.firstChild + ); + }; + var handleClick = function(e) { + var action = e.target.getAttribute("action"); + + if (action == "more" || !isOpen) { + isOpen = !isOpen; + return updateMenu(); + } + if (action == "paste") { + clipboard.readText().then(function (text) { + editor.execCommand(action, text); + }); + } + else if (action) { + if (action == "cut" || action == "copy") { + if (clipboard) + clipboard.writeText(editor.getCopyText()); + else + document.execCommand("copy"); + } + editor.execCommand(action); + } + contextMenu.firstChild.style.display = "none"; + isOpen = false; + if (action != "openCommandPallete") + editor.focus(); + }; + contextMenu = dom.buildDom(["div", + { + class: "ace_mobile-menu", + ontouchstart: function(e) { + mode = "menu"; + e.stopPropagation(); + e.preventDefault(); + editor.textInput.focus(); + }, + ontouchend: function(e) { + e.stopPropagation(); + e.preventDefault(); + handleClick(e); + }, + onclick: handleClick + }, + ["span"], + ["span", { class: "ace_mobile-button", action: "more" }, "..."] + ], editor.container); + } + function showContextMenu() { + if (!contextMenu) createContextMenu(); + var cursor = editor.selection.cursor; + var pagePos = editor.renderer.textToScreenCoordinates(cursor.row, cursor.column); + var rect = editor.container.getBoundingClientRect(); + contextMenu.style.top = pagePos.pageY - rect.top - 3 + "px"; + contextMenu.style.right = "10px"; + contextMenu.style.display = ""; + contextMenu.firstChild.style.display = "none"; + editor.on("input", hideContextMenu); + } + function hideContextMenu(e) { + if (contextMenu) + contextMenu.style.display = "none"; + editor.off("input", hideContextMenu); + } + + function handleLongTap() { + longTouchTimer = null; + clearTimeout(longTouchTimer); + var range = editor.selection.getRange(); + var inSelection = range.contains(pos.row, pos.column); + if (range.isEmpty() || !inSelection) { + editor.selection.moveToPosition(pos); + editor.selection.selectWord(); + } + mode = "wait"; + showContextMenu(); + } + function switchToSelectionMode() { + longTouchTimer = null; + clearTimeout(longTouchTimer); + editor.selection.moveToPosition(pos); + var range = clickCount >= 2 + ? editor.selection.getLineRange(pos.row) + : editor.session.getBracketRange(pos); + if (range && !range.isEmpty()) { + editor.selection.setRange(range); + } else { + editor.selection.selectWord(); + } + mode = "wait"; + } + el.addEventListener("contextmenu", function(e) { + if (!pressed) return; + var textarea = editor.textInput.getElement(); + textarea.focus(); + }); + el.addEventListener("touchstart", function (e) { + var touches = e.touches; + if (longTouchTimer || touches.length > 1) { + clearTimeout(longTouchTimer); + longTouchTimer = null; + touchStartT = -1; + mode = "zoom"; + return; + } + + pressed = editor.$mouseHandler.isMousePressed = true; + var h = editor.renderer.layerConfig.lineHeight; + var w = editor.renderer.layerConfig.lineHeight; + var t = e.timeStamp; + lastT = t; + var touchObj = touches[0]; + var x = touchObj.clientX; + var y = touchObj.clientY; + if (Math.abs(startX - x) + Math.abs(startY - y) > h) + touchStartT = -1; + + startX = e.clientX = x; + startY = e.clientY = y; + vX = vY = 0; + + var ev = new MouseEvent(e, editor); + pos = ev.getDocumentPosition(); + + if (t - touchStartT < 500 && touches.length == 1 && !animationSteps) { + clickCount++; + e.preventDefault(); + e.button = 0; + switchToSelectionMode(); + } else { + clickCount = 0; + var cursor = editor.selection.cursor; + var anchor = editor.selection.isEmpty() ? cursor : editor.selection.anchor; + + var cursorPos = editor.renderer.$cursorLayer.getPixelPosition(cursor, true); + var anchorPos = editor.renderer.$cursorLayer.getPixelPosition(anchor, true); + var rect = editor.renderer.scroller.getBoundingClientRect(); + var weightedDistance = function(x, y) { + x = x / w; + y = y / h - 0.75; + return x * x + y * y; + }; + + if (e.clientX < rect.left) { + mode = "zoom"; + return; + } + + var diff1 = weightedDistance( + e.clientX - rect.left - cursorPos.left, + e.clientY - rect.top - cursorPos.top + ); + var diff2 = weightedDistance( + e.clientX - rect.left - anchorPos.left, + e.clientY - rect.top - anchorPos.top + ); + if (diff1 < 3.5 && diff2 < 3.5) + mode = diff1 > diff2 ? "cursor" : "anchor"; + + if (diff2 < 3.5) + mode = "anchor"; + else if (diff1 < 3.5) + mode = "cursor"; + else + mode = "scroll"; + longTouchTimer = setTimeout(handleLongTap, 450); + } + touchStartT = t; + }); + + el.addEventListener("touchend", function (e) { + pressed = editor.$mouseHandler.isMousePressed = false; + if (animationTimer) clearInterval(animationTimer); + if (mode == "zoom") { + mode = ""; + animationSteps = 0; + } else if (longTouchTimer) { + editor.selection.moveToPosition(pos); + animationSteps = 0; + showContextMenu(); + } else if (mode == "scroll") { + animate(); + e.preventDefault(); + hideContextMenu(); + } else { + showContextMenu(); + } + clearTimeout(longTouchTimer); + longTouchTimer = null; + }); + el.addEventListener("touchmove", function (e) { + if (longTouchTimer) { + clearTimeout(longTouchTimer); + longTouchTimer = null; + } + var touches = e.touches; + if (touches.length > 1 || mode == "zoom") return; + + var touchObj = touches[0]; + + var wheelX = startX - touchObj.clientX; + var wheelY = startY - touchObj.clientY; + + if (mode == "wait") { + if (wheelX * wheelX + wheelY * wheelY > 4) + mode = "cursor"; + else + return e.preventDefault(); + } + + startX = touchObj.clientX; + startY = touchObj.clientY; + + e.clientX = touchObj.clientX; + e.clientY = touchObj.clientY; + + var t = e.timeStamp; + var dt = t - lastT; + lastT = t; + if (mode == "scroll") { + var mouseEvent = new MouseEvent(e, editor); + mouseEvent.speed = 1; + mouseEvent.wheelX = wheelX; + mouseEvent.wheelY = wheelY; + if (10 * Math.abs(wheelX) < Math.abs(wheelY)) wheelX = 0; + if (10 * Math.abs(wheelY) < Math.abs(wheelX)) wheelY = 0; + if (dt != 0) { + vX = wheelX / dt; + vY = wheelY / dt; + } + editor._emit("mousewheel", mouseEvent); + if (!mouseEvent.propagationStopped) { + vX = vY = 0; + } + } + else { + var ev = new MouseEvent(e, editor); + var pos = ev.getDocumentPosition(); + if (mode == "cursor") + editor.selection.moveCursorToPosition(pos); + else if (mode == "anchor") + editor.selection.setSelectionAnchor(pos.row, pos.column); + editor.renderer.scrollCursorIntoView(pos); + e.preventDefault(); + } + }); + + function animate() { + animationSteps += 60; + animationTimer = setInterval(function() { + if (animationSteps-- <= 0) { + clearInterval(animationTimer); + animationTimer = null; + } + if (Math.abs(vX) < 0.01) vX = 0; + if (Math.abs(vY) < 0.01) vY = 0; + if (animationSteps < 20) vX = 0.9 * vX; + if (animationSteps < 20) vY = 0.9 * vY; + var oldScrollTop = editor.session.getScrollTop(); + editor.renderer.scrollBy(10 * vX, 10 * vY); + if (oldScrollTop == editor.session.getScrollTop()) + animationSteps = 0; + }, 10); + } +}; + +}); + +define("ace/lib/net",["require","exports","module","ace/lib/dom"], function(require, exports, module) { +"use strict"; +var dom = require("./dom"); + +exports.get = function (url, callback) { + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, true); + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + callback(xhr.responseText); + } + }; + xhr.send(null); +}; + +exports.loadScript = function(path, callback) { + var head = dom.getDocumentHead(); + var s = document.createElement('script'); + + s.src = path; + head.appendChild(s); + + s.onload = s.onreadystatechange = function(_, isAbort) { + if (isAbort || !s.readyState || s.readyState == "loaded" || s.readyState == "complete") { + s = s.onload = s.onreadystatechange = null; + if (!isAbort) + callback(); + } + }; +}; +exports.qualifyURL = function(url) { + var a = document.createElement('a'); + a.href = url; + return a.href; +}; + +}); + +define("ace/lib/event_emitter",["require","exports","module"], function(require, exports, module) { +"use strict"; + +var EventEmitter = {}; +var stopPropagation = function() { this.propagationStopped = true; }; +var preventDefault = function() { this.defaultPrevented = true; }; + +EventEmitter._emit = +EventEmitter._dispatchEvent = function(eventName, e) { + this._eventRegistry || (this._eventRegistry = {}); + this._defaultHandlers || (this._defaultHandlers = {}); + + var listeners = this._eventRegistry[eventName] || []; + var defaultHandler = this._defaultHandlers[eventName]; + if (!listeners.length && !defaultHandler) + return; + + if (typeof e != "object" || !e) + e = {}; + + if (!e.type) + e.type = eventName; + if (!e.stopPropagation) + e.stopPropagation = stopPropagation; + if (!e.preventDefault) + e.preventDefault = preventDefault; + + listeners = listeners.slice(); + for (var i=0; i 1) + base = parts[parts.length - 2]; + var path = options[component + "Path"]; + if (path == null) { + path = options.basePath; + } else if (sep == "/") { + component = sep = ""; + } + if (path && path.slice(-1) != "/") + path += "/"; + return path + component + sep + base + this.get("suffix"); +}; + +exports.setModuleUrl = function(name, subst) { + return options.$moduleUrls[name] = subst; +}; + +exports.$loading = {}; +exports.loadModule = function(moduleName, onLoad) { + var module, moduleType; + if (Array.isArray(moduleName)) { + moduleType = moduleName[0]; + moduleName = moduleName[1]; + } + + try { + module = require(moduleName); + } catch (e) {} + if (module && !exports.$loading[moduleName]) + return onLoad && onLoad(module); + + if (!exports.$loading[moduleName]) + exports.$loading[moduleName] = []; + + exports.$loading[moduleName].push(onLoad); + + if (exports.$loading[moduleName].length > 1) + return; + + var afterLoad = function() { + require([moduleName], function(module) { + exports._emit("load.module", {name: moduleName, module: module}); + var listeners = exports.$loading[moduleName]; + exports.$loading[moduleName] = null; + listeners.forEach(function(onLoad) { + onLoad && onLoad(module); + }); + }); + }; + + if (!exports.get("packaged")) + return afterLoad(); + + net.loadScript(exports.moduleUrl(moduleName, moduleType), afterLoad); + reportErrorIfPathIsNotConfigured(); +}; + +var reportErrorIfPathIsNotConfigured = function() { + if ( + !options.basePath && !options.workerPath + && !options.modePath && !options.themePath + && !Object.keys(options.$moduleUrls).length + ) { + console.error( + "Unable to infer path to ace from script src,", + "use ace.config.set('basePath', 'path') to enable dynamic loading of modes and themes", + "or with webpack use ace/webpack-resolver" + ); + reportErrorIfPathIsNotConfigured = function() {}; + } +}; +init(true);function init(packaged) { + + if (!global || !global.document) + return; + + options.packaged = packaged || require.packaged || module.packaged || (global.define && define.packaged); + + var scriptOptions = {}; + var scriptUrl = ""; + var currentScript = (document.currentScript || document._currentScript ); // native or polyfill + var currentDocument = currentScript && currentScript.ownerDocument || document; + + var scripts = currentDocument.getElementsByTagName("script"); + for (var i=0; i 0){ + if (action == 0x10){ + for(i = condPos; i < ix; i++){ + levels[i] = 1; + } + condPos = -1; + } else { + condPos = -1; + } + } + cond = impTab[newState][6]; + if (cond){ + if(condPos == -1){ + condPos = ix; + } + }else{ + if (condPos > -1){ + for(i = condPos; i < ix; i++){ + levels[i] = newLevel; + } + condPos = -1; + } + } + if (charTypes[ix] == B){ + levels[ix] = 0; + } + hiLevel |= newLevel; + } + if (hasUBAT_S){ + for(i = 0; i < len; i++){ + if(charTypes[i] == S){ + levels[i] = dir; + for(var j = i - 1; j >= 0; j--){ + if(charTypes[j] == WS){ + levels[j] = dir; + }else{ + break; + } + } + } + } + } +} + +function _invertLevel(lev, levels, _array) { + if (hiLevel < lev){ + return; + } + if (lev == 1 && dir == RTL && !hasUBAT_B){ + _array.reverse(); + return; + } + var len = _array.length, start = 0, end, lo, hi, tmp; + while(start < len){ + if (levels[start] >= lev){ + end = start + 1; + while(end < len && levels[end] >= lev){ + end++; + } + for(lo = start, hi = end - 1 ; lo < hi; lo++, hi--){ + tmp = _array[lo]; + _array[lo] = _array[hi]; + _array[hi] = tmp; + } + start = end; + } + start++; + } +} + +function _getCharClass(chars, types, classes, ix) { + var cType = types[ix], wType, nType, len, i; + switch(cType){ + case L: + case R: + lastArabic = false; + case ON: + case AN: + return cType; + case EN: + return lastArabic ? AN : EN; + case AL: + lastArabic = true; + hasUBAT_AL = true; + return R; + case WS: + return ON; + case CS: + if (ix < 1 || (ix + 1) >= types.length || + ((wType = classes[ix - 1]) != EN && wType != AN) || + ((nType = types[ix + 1]) != EN && nType != AN)){ + return ON; + } + if (lastArabic){nType = AN;} + return nType == wType ? nType : ON; + case ES: + wType = ix > 0 ? classes[ix - 1] : B; + if (wType == EN && (ix + 1) < types.length && types[ix + 1] == EN){ + return EN; + } + return ON; + case ET: + if (ix > 0 && classes[ix - 1] == EN){ + return EN; + } + if (lastArabic){ + return ON; + } + i = ix + 1; + len = types.length; + while (i < len && types[i] == ET){ + i++; + } + if (i < len && types[i] == EN){ + return EN; + } + return ON; + case NSM: + len = types.length; + i = ix + 1; + while (i < len && types[i] == NSM){ + i++; + } + if (i < len){ + var c = chars[ix], rtlCandidate = (c >= 0x0591 && c <= 0x08FF) || c == 0xFB1E; + + wType = types[i]; + if (rtlCandidate && (wType == R || wType == AL)){ + return R; + } + } + + if (ix < 1 || (wType = types[ix - 1]) == B){ + return ON; + } + return classes[ix - 1]; + case B: + lastArabic = false; + hasUBAT_B = true; + return dir; + case S: + hasUBAT_S = true; + return ON; + case LRE: + case RLE: + case LRO: + case RLO: + case PDF: + lastArabic = false; + case BN: + return ON; + } +} + +function _getCharacterType( ch ) { + var uc = ch.charCodeAt(0), hi = uc >> 8; + + if (hi == 0) { + return ((uc > 0x00BF) ? L : UnicodeTBL00[uc]); + } else if (hi == 5) { + return (/[\u0591-\u05f4]/.test(ch) ? R : L); + } else if (hi == 6) { + if (/[\u0610-\u061a\u064b-\u065f\u06d6-\u06e4\u06e7-\u06ed]/.test(ch)) + return NSM; + else if (/[\u0660-\u0669\u066b-\u066c]/.test(ch)) + return AN; + else if (uc == 0x066A) + return ET; + else if (/[\u06f0-\u06f9]/.test(ch)) + return EN; + else + return AL; + } else if (hi == 0x20 && uc <= 0x205F) { + return UnicodeTBL20[uc & 0xFF]; + } else if (hi == 0xFE) { + return (uc >= 0xFE70 ? AL : ON); + } + return ON; +} + +function _isArabicDiacritics( ch ) { + return (ch >= '\u064b' && ch <= '\u0655'); +} +exports.L = L; +exports.R = R; +exports.EN = EN; +exports.ON_R = 3; +exports.AN = 4; +exports.R_H = 5; +exports.B = 6; +exports.RLE = 7; + +exports.DOT = "\xB7"; +exports.doBidiReorder = function(text, textCharTypes, isRtl) { + if (text.length < 2) + return {}; + + var chars = text.split(""), logicalFromVisual = new Array(chars.length), + bidiLevels = new Array(chars.length), levels = []; + + dir = isRtl ? RTL : LTR; + + _computeLevels(chars, levels, chars.length, textCharTypes); + + for (var i = 0; i < logicalFromVisual.length; logicalFromVisual[i] = i, i++); + + _invertLevel(2, levels, logicalFromVisual); + _invertLevel(1, levels, logicalFromVisual); + + for (var i = 0; i < logicalFromVisual.length - 1; i++) { //fix levels to reflect character width + if (textCharTypes[i] === AN) { + levels[i] = exports.AN; + } else if (levels[i] === R && ((textCharTypes[i] > AL && textCharTypes[i] < LRE) + || textCharTypes[i] === ON || textCharTypes[i] === BN)) { + levels[i] = exports.ON_R; + } else if ((i > 0 && chars[i - 1] === '\u0644') && /\u0622|\u0623|\u0625|\u0627/.test(chars[i])) { + levels[i - 1] = levels[i] = exports.R_H; + i++; + } + } + if (chars[chars.length - 1] === exports.DOT) + levels[chars.length - 1] = exports.B; + + if (chars[0] === '\u202B') + levels[0] = exports.RLE; + + for (var i = 0; i < logicalFromVisual.length; i++) { + bidiLevels[i] = levels[logicalFromVisual[i]]; + } + + return {'logicalFromVisual': logicalFromVisual, 'bidiLevels': bidiLevels}; +}; +exports.hasBidiCharacters = function(text, textCharTypes){ + var ret = false; + for (var i = 0; i < text.length; i++){ + textCharTypes[i] = _getCharacterType(text.charAt(i)); + if (!ret && (textCharTypes[i] == R || textCharTypes[i] == AL || textCharTypes[i] == AN)) + ret = true; + } + return ret; +}; +exports.getVisualFromLogicalIdx = function(logIdx, rowMap) { + for (var i = 0; i < rowMap.logicalFromVisual.length; i++) { + if (rowMap.logicalFromVisual[i] == logIdx) + return i; + } + return 0; +}; + +}); + +define("ace/bidihandler",["require","exports","module","ace/lib/bidiutil","ace/lib/lang"], function(require, exports, module) { +"use strict"; + +var bidiUtil = require("./lib/bidiutil"); +var lang = require("./lib/lang"); +var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac\u202B]/; +var BidiHandler = function(session) { + this.session = session; + this.bidiMap = {}; + this.currentRow = null; + this.bidiUtil = bidiUtil; + this.charWidths = []; + this.EOL = "\xAC"; + this.showInvisibles = true; + this.isRtlDir = false; + this.$isRtl = false; + this.line = ""; + this.wrapIndent = 0; + this.EOF = "\xB6"; + this.RLE = "\u202B"; + this.contentWidth = 0; + this.fontMetrics = null; + this.rtlLineOffset = 0; + this.wrapOffset = 0; + this.isMoveLeftOperation = false; + this.seenBidi = bidiRE.test(session.getValue()); +}; + +(function() { + this.isBidiRow = function(screenRow, docRow, splitIndex) { + if (!this.seenBidi) + return false; + if (screenRow !== this.currentRow) { + this.currentRow = screenRow; + this.updateRowLine(docRow, splitIndex); + this.updateBidiMap(); + } + return this.bidiMap.bidiLevels; + }; + + this.onChange = function(delta) { + if (!this.seenBidi) { + if (delta.action == "insert" && bidiRE.test(delta.lines.join("\n"))) { + this.seenBidi = true; + this.currentRow = null; + } + } + else { + this.currentRow = null; + } + }; + + this.getDocumentRow = function() { + var docRow = 0; + var rowCache = this.session.$screenRowCache; + if (rowCache.length) { + var index = this.session.$getRowCacheIndex(rowCache, this.currentRow); + if (index >= 0) + docRow = this.session.$docRowCache[index]; + } + + return docRow; + }; + + this.getSplitIndex = function() { + var splitIndex = 0; + var rowCache = this.session.$screenRowCache; + if (rowCache.length) { + var currentIndex, prevIndex = this.session.$getRowCacheIndex(rowCache, this.currentRow); + while (this.currentRow - splitIndex > 0) { + currentIndex = this.session.$getRowCacheIndex(rowCache, this.currentRow - splitIndex - 1); + if (currentIndex !== prevIndex) + break; + + prevIndex = currentIndex; + splitIndex++; + } + } else { + splitIndex = this.currentRow; + } + + return splitIndex; + }; + + this.updateRowLine = function(docRow, splitIndex) { + if (docRow === undefined) + docRow = this.getDocumentRow(); + + var isLastRow = (docRow === this.session.getLength() - 1), + endOfLine = isLastRow ? this.EOF : this.EOL; + + this.wrapIndent = 0; + this.line = this.session.getLine(docRow); + this.isRtlDir = this.$isRtl || this.line.charAt(0) === this.RLE; + if (this.session.$useWrapMode) { + var splits = this.session.$wrapData[docRow]; + if (splits) { + if (splitIndex === undefined) + splitIndex = this.getSplitIndex(); + + if(splitIndex > 0 && splits.length) { + this.wrapIndent = splits.indent; + this.wrapOffset = this.wrapIndent * this.charWidths[bidiUtil.L]; + this.line = (splitIndex < splits.length) ? + this.line.substring(splits[splitIndex - 1], splits[splitIndex]) : + this.line.substring(splits[splits.length - 1]); + } else { + this.line = this.line.substring(0, splits[splitIndex]); + } + } + if (splitIndex == splits.length) + this.line += (this.showInvisibles) ? endOfLine : bidiUtil.DOT; + } else { + this.line += this.showInvisibles ? endOfLine : bidiUtil.DOT; + } + var session = this.session, shift = 0, size; + this.line = this.line.replace(/\t|[\u1100-\u2029, \u202F-\uFFE6]/g, function(ch, i){ + if (ch === '\t' || session.isFullWidth(ch.charCodeAt(0))) { + size = (ch === '\t') ? session.getScreenTabSize(i + shift) : 2; + shift += size - 1; + return lang.stringRepeat(bidiUtil.DOT, size); + } + return ch; + }); + + if (this.isRtlDir) { + this.fontMetrics.$main.textContent = (this.line.charAt(this.line.length - 1) == bidiUtil.DOT) ? this.line.substr(0, this.line.length - 1) : this.line; + this.rtlLineOffset = this.contentWidth - this.fontMetrics.$main.getBoundingClientRect().width; + } + }; + + this.updateBidiMap = function() { + var textCharTypes = []; + if (bidiUtil.hasBidiCharacters(this.line, textCharTypes) || this.isRtlDir) { + this.bidiMap = bidiUtil.doBidiReorder(this.line, textCharTypes, this.isRtlDir); + } else { + this.bidiMap = {}; + } + }; + this.markAsDirty = function() { + this.currentRow = null; + }; + this.updateCharacterWidths = function(fontMetrics) { + if (this.characterWidth === fontMetrics.$characterSize.width) + return; + + this.fontMetrics = fontMetrics; + var characterWidth = this.characterWidth = fontMetrics.$characterSize.width; + var bidiCharWidth = fontMetrics.$measureCharWidth("\u05d4"); + + this.charWidths[bidiUtil.L] = this.charWidths[bidiUtil.EN] = this.charWidths[bidiUtil.ON_R] = characterWidth; + this.charWidths[bidiUtil.R] = this.charWidths[bidiUtil.AN] = bidiCharWidth; + this.charWidths[bidiUtil.R_H] = bidiCharWidth * 0.45; + this.charWidths[bidiUtil.B] = this.charWidths[bidiUtil.RLE] = 0; + + this.currentRow = null; + }; + + this.setShowInvisibles = function(showInvisibles) { + this.showInvisibles = showInvisibles; + this.currentRow = null; + }; + + this.setEolChar = function(eolChar) { + this.EOL = eolChar; + }; + + this.setContentWidth = function(width) { + this.contentWidth = width; + }; + + this.isRtlLine = function(row) { + if (this.$isRtl) return true; + if (row != undefined) + return (this.session.getLine(row).charAt(0) == this.RLE); + else + return this.isRtlDir; + }; + + this.setRtlDirection = function(editor, isRtlDir) { + var cursor = editor.getCursorPosition(); + for (var row = editor.selection.getSelectionAnchor().row; row <= cursor.row; row++) { + if (!isRtlDir && editor.session.getLine(row).charAt(0) === editor.session.$bidiHandler.RLE) + editor.session.doc.removeInLine(row, 0, 1); + else if (isRtlDir && editor.session.getLine(row).charAt(0) !== editor.session.$bidiHandler.RLE) + editor.session.doc.insert({column: 0, row: row}, editor.session.$bidiHandler.RLE); + } + }; + this.getPosLeft = function(col) { + col -= this.wrapIndent; + var leftBoundary = (this.line.charAt(0) === this.RLE) ? 1 : 0; + var logicalIdx = (col > leftBoundary) ? (this.session.getOverwrite() ? col : col - 1) : leftBoundary; + var visualIdx = bidiUtil.getVisualFromLogicalIdx(logicalIdx, this.bidiMap), + levels = this.bidiMap.bidiLevels, left = 0; + + if (!this.session.getOverwrite() && col <= leftBoundary && levels[visualIdx] % 2 !== 0) + visualIdx++; + + for (var i = 0; i < visualIdx; i++) { + left += this.charWidths[levels[i]]; + } + + if (!this.session.getOverwrite() && (col > leftBoundary) && (levels[visualIdx] % 2 === 0)) + left += this.charWidths[levels[visualIdx]]; + + if (this.wrapIndent) + left += this.isRtlDir ? (-1 * this.wrapOffset) : this.wrapOffset; + + if (this.isRtlDir) + left += this.rtlLineOffset; + + return left; + }; + this.getSelections = function(startCol, endCol) { + var map = this.bidiMap, levels = map.bidiLevels, level, selections = [], offset = 0, + selColMin = Math.min(startCol, endCol) - this.wrapIndent, selColMax = Math.max(startCol, endCol) - this.wrapIndent, + isSelected = false, isSelectedPrev = false, selectionStart = 0; + + if (this.wrapIndent) + offset += this.isRtlDir ? (-1 * this.wrapOffset) : this.wrapOffset; + + for (var logIdx, visIdx = 0; visIdx < levels.length; visIdx++) { + logIdx = map.logicalFromVisual[visIdx]; + level = levels[visIdx]; + isSelected = (logIdx >= selColMin) && (logIdx < selColMax); + if (isSelected && !isSelectedPrev) { + selectionStart = offset; + } else if (!isSelected && isSelectedPrev) { + selections.push({left: selectionStart, width: offset - selectionStart}); + } + offset += this.charWidths[level]; + isSelectedPrev = isSelected; + } + + if (isSelected && (visIdx === levels.length)) { + selections.push({left: selectionStart, width: offset - selectionStart}); + } + + if(this.isRtlDir) { + for (var i = 0; i < selections.length; i++) { + selections[i].left += this.rtlLineOffset; + } + } + return selections; + }; + this.offsetToCol = function(posX) { + if(this.isRtlDir) + posX -= this.rtlLineOffset; + + var logicalIdx = 0, posX = Math.max(posX, 0), + offset = 0, visualIdx = 0, levels = this.bidiMap.bidiLevels, + charWidth = this.charWidths[levels[visualIdx]]; + + if (this.wrapIndent) + posX -= this.isRtlDir ? (-1 * this.wrapOffset) : this.wrapOffset; + + while(posX > offset + charWidth/2) { + offset += charWidth; + if(visualIdx === levels.length - 1) { + charWidth = 0; + break; + } + charWidth = this.charWidths[levels[++visualIdx]]; + } + + if (visualIdx > 0 && (levels[visualIdx - 1] % 2 !== 0) && (levels[visualIdx] % 2 === 0)){ + if(posX < offset) + visualIdx--; + logicalIdx = this.bidiMap.logicalFromVisual[visualIdx]; + + } else if (visualIdx > 0 && (levels[visualIdx - 1] % 2 === 0) && (levels[visualIdx] % 2 !== 0)){ + logicalIdx = 1 + ((posX > offset) ? this.bidiMap.logicalFromVisual[visualIdx] + : this.bidiMap.logicalFromVisual[visualIdx - 1]); + + } else if ((this.isRtlDir && visualIdx === levels.length - 1 && charWidth === 0 && (levels[visualIdx - 1] % 2 === 0)) + || (!this.isRtlDir && visualIdx === 0 && (levels[visualIdx] % 2 !== 0))){ + logicalIdx = 1 + this.bidiMap.logicalFromVisual[visualIdx]; + } else { + if (visualIdx > 0 && (levels[visualIdx - 1] % 2 !== 0) && charWidth !== 0) + visualIdx--; + logicalIdx = this.bidiMap.logicalFromVisual[visualIdx]; + } + + if (logicalIdx === 0 && this.isRtlDir) + logicalIdx++; + + return (logicalIdx + this.wrapIndent); + }; + +}).call(BidiHandler.prototype); + +exports.BidiHandler = BidiHandler; +}); + +define("ace/selection",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/lib/event_emitter","ace/range"], function(require, exports, module) { +"use strict"; + +var oop = require("./lib/oop"); +var lang = require("./lib/lang"); +var EventEmitter = require("./lib/event_emitter").EventEmitter; +var Range = require("./range").Range; +var Selection = function(session) { + this.session = session; + this.doc = session.getDocument(); + + this.clearSelection(); + this.cursor = this.lead = this.doc.createAnchor(0, 0); + this.anchor = this.doc.createAnchor(0, 0); + this.$silent = false; + + var self = this; + this.cursor.on("change", function(e) { + self.$cursorChanged = true; + if (!self.$silent) + self._emit("changeCursor"); + if (!self.$isEmpty && !self.$silent) + self._emit("changeSelection"); + if (!self.$keepDesiredColumnOnChange && e.old.column != e.value.column) + self.$desiredColumn = null; + }); + + this.anchor.on("change", function() { + self.$anchorChanged = true; + if (!self.$isEmpty && !self.$silent) + self._emit("changeSelection"); + }); +}; + +(function() { + + oop.implement(this, EventEmitter); + this.isEmpty = function() { + return this.$isEmpty || ( + this.anchor.row == this.lead.row && + this.anchor.column == this.lead.column + ); + }; + this.isMultiLine = function() { + return !this.$isEmpty && this.anchor.row != this.cursor.row; + }; + this.getCursor = function() { + return this.lead.getPosition(); + }; + this.setSelectionAnchor = function(row, column) { + this.$isEmpty = false; + this.anchor.setPosition(row, column); + }; + this.getAnchor = + this.getSelectionAnchor = function() { + if (this.$isEmpty) + return this.getSelectionLead(); + + return this.anchor.getPosition(); + }; + this.getSelectionLead = function() { + return this.lead.getPosition(); + }; + this.isBackwards = function() { + var anchor = this.anchor; + var lead = this.lead; + return (anchor.row > lead.row || (anchor.row == lead.row && anchor.column > lead.column)); + }; + this.getRange = function() { + var anchor = this.anchor; + var lead = this.lead; + + if (this.$isEmpty) + return Range.fromPoints(lead, lead); + + return this.isBackwards() + ? Range.fromPoints(lead, anchor) + : Range.fromPoints(anchor, lead); + }; + this.clearSelection = function() { + if (!this.$isEmpty) { + this.$isEmpty = true; + this._emit("changeSelection"); + } + }; + this.selectAll = function() { + this.$setSelection(0, 0, Number.MAX_VALUE, Number.MAX_VALUE); + }; + this.setRange = + this.setSelectionRange = function(range, reverse) { + var start = reverse ? range.end : range.start; + var end = reverse ? range.start : range.end; + this.$setSelection(start.row, start.column, end.row, end.column); + }; + + this.$setSelection = function(anchorRow, anchorColumn, cursorRow, cursorColumn) { + var wasEmpty = this.$isEmpty; + var wasMultiselect = this.inMultiSelectMode; + this.$silent = true; + this.$cursorChanged = this.$anchorChanged = false; + this.anchor.setPosition(anchorRow, anchorColumn); + this.cursor.setPosition(cursorRow, cursorColumn); + this.$isEmpty = !Range.comparePoints(this.anchor, this.cursor); + this.$silent = false; + if (this.$cursorChanged) + this._emit("changeCursor"); + if (this.$cursorChanged || this.$anchorChanged || wasEmpty != this.$isEmpty || wasMultiselect) + this._emit("changeSelection"); + }; + + this.$moveSelection = function(mover) { + var lead = this.lead; + if (this.$isEmpty) + this.setSelectionAnchor(lead.row, lead.column); + + mover.call(this); + }; + this.selectTo = function(row, column) { + this.$moveSelection(function() { + this.moveCursorTo(row, column); + }); + }; + this.selectToPosition = function(pos) { + this.$moveSelection(function() { + this.moveCursorToPosition(pos); + }); + }; + this.moveTo = function(row, column) { + this.clearSelection(); + this.moveCursorTo(row, column); + }; + this.moveToPosition = function(pos) { + this.clearSelection(); + this.moveCursorToPosition(pos); + }; + this.selectUp = function() { + this.$moveSelection(this.moveCursorUp); + }; + this.selectDown = function() { + this.$moveSelection(this.moveCursorDown); + }; + this.selectRight = function() { + this.$moveSelection(this.moveCursorRight); + }; + this.selectLeft = function() { + this.$moveSelection(this.moveCursorLeft); + }; + this.selectLineStart = function() { + this.$moveSelection(this.moveCursorLineStart); + }; + this.selectLineEnd = function() { + this.$moveSelection(this.moveCursorLineEnd); + }; + this.selectFileEnd = function() { + this.$moveSelection(this.moveCursorFileEnd); + }; + this.selectFileStart = function() { + this.$moveSelection(this.moveCursorFileStart); + }; + this.selectWordRight = function() { + this.$moveSelection(this.moveCursorWordRight); + }; + this.selectWordLeft = function() { + this.$moveSelection(this.moveCursorWordLeft); + }; + this.getWordRange = function(row, column) { + if (typeof column == "undefined") { + var cursor = row || this.lead; + row = cursor.row; + column = cursor.column; + } + return this.session.getWordRange(row, column); + }; + this.selectWord = function() { + this.setSelectionRange(this.getWordRange()); + }; + this.selectAWord = function() { + var cursor = this.getCursor(); + var range = this.session.getAWordRange(cursor.row, cursor.column); + this.setSelectionRange(range); + }; + + this.getLineRange = function(row, excludeLastChar) { + var rowStart = typeof row == "number" ? row : this.lead.row; + var rowEnd; + + var foldLine = this.session.getFoldLine(rowStart); + if (foldLine) { + rowStart = foldLine.start.row; + rowEnd = foldLine.end.row; + } else { + rowEnd = rowStart; + } + if (excludeLastChar === true) + return new Range(rowStart, 0, rowEnd, this.session.getLine(rowEnd).length); + else + return new Range(rowStart, 0, rowEnd + 1, 0); + }; + this.selectLine = function() { + this.setSelectionRange(this.getLineRange()); + }; + this.moveCursorUp = function() { + this.moveCursorBy(-1, 0); + }; + this.moveCursorDown = function() { + this.moveCursorBy(1, 0); + }; + this.wouldMoveIntoSoftTab = function(cursor, tabSize, direction) { + var start = cursor.column; + var end = cursor.column + tabSize; + + if (direction < 0) { + start = cursor.column - tabSize; + end = cursor.column; + } + return this.session.isTabStop(cursor) && this.doc.getLine(cursor.row).slice(start, end).split(" ").length-1 == tabSize; + }; + this.moveCursorLeft = function() { + var cursor = this.lead.getPosition(), + fold; + + if (fold = this.session.getFoldAt(cursor.row, cursor.column, -1)) { + this.moveCursorTo(fold.start.row, fold.start.column); + } else if (cursor.column === 0) { + if (cursor.row > 0) { + this.moveCursorTo(cursor.row - 1, this.doc.getLine(cursor.row - 1).length); + } + } + else { + var tabSize = this.session.getTabSize(); + if (this.wouldMoveIntoSoftTab(cursor, tabSize, -1) && !this.session.getNavigateWithinSoftTabs()) { + this.moveCursorBy(0, -tabSize); + } else { + this.moveCursorBy(0, -1); + } + } + }; + this.moveCursorRight = function() { + var cursor = this.lead.getPosition(), + fold; + if (fold = this.session.getFoldAt(cursor.row, cursor.column, 1)) { + this.moveCursorTo(fold.end.row, fold.end.column); + } + else if (this.lead.column == this.doc.getLine(this.lead.row).length) { + if (this.lead.row < this.doc.getLength() - 1) { + this.moveCursorTo(this.lead.row + 1, 0); + } + } + else { + var tabSize = this.session.getTabSize(); + var cursor = this.lead; + if (this.wouldMoveIntoSoftTab(cursor, tabSize, 1) && !this.session.getNavigateWithinSoftTabs()) { + this.moveCursorBy(0, tabSize); + } else { + this.moveCursorBy(0, 1); + } + } + }; + this.moveCursorLineStart = function() { + var row = this.lead.row; + var column = this.lead.column; + var screenRow = this.session.documentToScreenRow(row, column); + var firstColumnPosition = this.session.screenToDocumentPosition(screenRow, 0); + var beforeCursor = this.session.getDisplayLine( + row, null, firstColumnPosition.row, + firstColumnPosition.column + ); + + var leadingSpace = beforeCursor.match(/^\s*/); + if (leadingSpace[0].length != column && !this.session.$useEmacsStyleLineStart) + firstColumnPosition.column += leadingSpace[0].length; + this.moveCursorToPosition(firstColumnPosition); + }; + this.moveCursorLineEnd = function() { + var lead = this.lead; + var lineEnd = this.session.getDocumentLastRowColumnPosition(lead.row, lead.column); + if (this.lead.column == lineEnd.column) { + var line = this.session.getLine(lineEnd.row); + if (lineEnd.column == line.length) { + var textEnd = line.search(/\s+$/); + if (textEnd > 0) + lineEnd.column = textEnd; + } + } + + this.moveCursorTo(lineEnd.row, lineEnd.column); + }; + this.moveCursorFileEnd = function() { + var row = this.doc.getLength() - 1; + var column = this.doc.getLine(row).length; + this.moveCursorTo(row, column); + }; + this.moveCursorFileStart = function() { + this.moveCursorTo(0, 0); + }; + this.moveCursorLongWordRight = function() { + var row = this.lead.row; + var column = this.lead.column; + var line = this.doc.getLine(row); + var rightOfCursor = line.substring(column); + + this.session.nonTokenRe.lastIndex = 0; + this.session.tokenRe.lastIndex = 0; + var fold = this.session.getFoldAt(row, column, 1); + if (fold) { + this.moveCursorTo(fold.end.row, fold.end.column); + return; + } + if (this.session.nonTokenRe.exec(rightOfCursor)) { + column += this.session.nonTokenRe.lastIndex; + this.session.nonTokenRe.lastIndex = 0; + rightOfCursor = line.substring(column); + } + if (column >= line.length) { + this.moveCursorTo(row, line.length); + this.moveCursorRight(); + if (row < this.doc.getLength() - 1) + this.moveCursorWordRight(); + return; + } + if (this.session.tokenRe.exec(rightOfCursor)) { + column += this.session.tokenRe.lastIndex; + this.session.tokenRe.lastIndex = 0; + } + + this.moveCursorTo(row, column); + }; + this.moveCursorLongWordLeft = function() { + var row = this.lead.row; + var column = this.lead.column; + var fold; + if (fold = this.session.getFoldAt(row, column, -1)) { + this.moveCursorTo(fold.start.row, fold.start.column); + return; + } + + var str = this.session.getFoldStringAt(row, column, -1); + if (str == null) { + str = this.doc.getLine(row).substring(0, column); + } + + var leftOfCursor = lang.stringReverse(str); + this.session.nonTokenRe.lastIndex = 0; + this.session.tokenRe.lastIndex = 0; + if (this.session.nonTokenRe.exec(leftOfCursor)) { + column -= this.session.nonTokenRe.lastIndex; + leftOfCursor = leftOfCursor.slice(this.session.nonTokenRe.lastIndex); + this.session.nonTokenRe.lastIndex = 0; + } + if (column <= 0) { + this.moveCursorTo(row, 0); + this.moveCursorLeft(); + if (row > 0) + this.moveCursorWordLeft(); + return; + } + if (this.session.tokenRe.exec(leftOfCursor)) { + column -= this.session.tokenRe.lastIndex; + this.session.tokenRe.lastIndex = 0; + } + + this.moveCursorTo(row, column); + }; + + this.$shortWordEndIndex = function(rightOfCursor) { + var index = 0, ch; + var whitespaceRe = /\s/; + var tokenRe = this.session.tokenRe; + + tokenRe.lastIndex = 0; + if (this.session.tokenRe.exec(rightOfCursor)) { + index = this.session.tokenRe.lastIndex; + } else { + while ((ch = rightOfCursor[index]) && whitespaceRe.test(ch)) + index ++; + + if (index < 1) { + tokenRe.lastIndex = 0; + while ((ch = rightOfCursor[index]) && !tokenRe.test(ch)) { + tokenRe.lastIndex = 0; + index ++; + if (whitespaceRe.test(ch)) { + if (index > 2) { + index--; + break; + } else { + while ((ch = rightOfCursor[index]) && whitespaceRe.test(ch)) + index ++; + if (index > 2) + break; + } + } + } + } + } + tokenRe.lastIndex = 0; + + return index; + }; + + this.moveCursorShortWordRight = function() { + var row = this.lead.row; + var column = this.lead.column; + var line = this.doc.getLine(row); + var rightOfCursor = line.substring(column); + + var fold = this.session.getFoldAt(row, column, 1); + if (fold) + return this.moveCursorTo(fold.end.row, fold.end.column); + + if (column == line.length) { + var l = this.doc.getLength(); + do { + row++; + rightOfCursor = this.doc.getLine(row); + } while (row < l && /^\s*$/.test(rightOfCursor)); + + if (!/^\s+/.test(rightOfCursor)) + rightOfCursor = ""; + column = 0; + } + + var index = this.$shortWordEndIndex(rightOfCursor); + + this.moveCursorTo(row, column + index); + }; + + this.moveCursorShortWordLeft = function() { + var row = this.lead.row; + var column = this.lead.column; + + var fold; + if (fold = this.session.getFoldAt(row, column, -1)) + return this.moveCursorTo(fold.start.row, fold.start.column); + + var line = this.session.getLine(row).substring(0, column); + if (column === 0) { + do { + row--; + line = this.doc.getLine(row); + } while (row > 0 && /^\s*$/.test(line)); + + column = line.length; + if (!/\s+$/.test(line)) + line = ""; + } + + var leftOfCursor = lang.stringReverse(line); + var index = this.$shortWordEndIndex(leftOfCursor); + + return this.moveCursorTo(row, column - index); + }; + + this.moveCursorWordRight = function() { + if (this.session.$selectLongWords) + this.moveCursorLongWordRight(); + else + this.moveCursorShortWordRight(); + }; + + this.moveCursorWordLeft = function() { + if (this.session.$selectLongWords) + this.moveCursorLongWordLeft(); + else + this.moveCursorShortWordLeft(); + }; + this.moveCursorBy = function(rows, chars) { + var screenPos = this.session.documentToScreenPosition( + this.lead.row, + this.lead.column + ); + + var offsetX; + + if (chars === 0) { + if (rows !== 0) { + if (this.session.$bidiHandler.isBidiRow(screenPos.row, this.lead.row)) { + offsetX = this.session.$bidiHandler.getPosLeft(screenPos.column); + screenPos.column = Math.round(offsetX / this.session.$bidiHandler.charWidths[0]); + } else { + offsetX = screenPos.column * this.session.$bidiHandler.charWidths[0]; + } + } + + if (this.$desiredColumn) + screenPos.column = this.$desiredColumn; + else + this.$desiredColumn = screenPos.column; + } + + var docPos = this.session.screenToDocumentPosition(screenPos.row + rows, screenPos.column, offsetX); + + if (rows !== 0 && chars === 0 && docPos.row === this.lead.row && docPos.column === this.lead.column) { + if (this.session.lineWidgets && this.session.lineWidgets[docPos.row]) { + if (docPos.row > 0 || rows > 0) + docPos.row++; + } + } + this.moveCursorTo(docPos.row, docPos.column + chars, chars === 0); + }; + this.moveCursorToPosition = function(position) { + this.moveCursorTo(position.row, position.column); + }; + this.moveCursorTo = function(row, column, keepDesiredColumn) { + var fold = this.session.getFoldAt(row, column, 1); + if (fold) { + row = fold.start.row; + column = fold.start.column; + } + + this.$keepDesiredColumnOnChange = true; + var line = this.session.getLine(row); + if (/[\uDC00-\uDFFF]/.test(line.charAt(column)) && line.charAt(column - 1)) { + if (this.lead.row == row && this.lead.column == column + 1) + column = column - 1; + else + column = column + 1; + } + this.lead.setPosition(row, column); + this.$keepDesiredColumnOnChange = false; + + if (!keepDesiredColumn) + this.$desiredColumn = null; + }; + this.moveCursorToScreen = function(row, column, keepDesiredColumn) { + var pos = this.session.screenToDocumentPosition(row, column); + this.moveCursorTo(pos.row, pos.column, keepDesiredColumn); + }; + this.detach = function() { + this.lead.detach(); + this.anchor.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; + }; + this.getRangeOfMovements = function(func) { + var start = this.getCursor(); + try { + func(this); + var end = this.getCursor(); + return Range.fromPoints(start, end); + } catch(e) { + return Range.fromPoints(start, start); + } finally { + this.moveCursorToPosition(start); + } + }; + + this.toJSON = function() { + if (this.rangeCount) { + var data = this.ranges.map(function(r) { + var r1 = r.clone(); + r1.isBackwards = r.cursor == r.start; + return r1; + }); + } else { + var data = this.getRange(); + data.isBackwards = this.isBackwards(); + } + return data; + }; + + this.fromJSON = function(data) { + if (data.start == undefined) { + if (this.rangeList && data.length > 1) { + this.toSingleRange(data[0]); + for (var i = data.length; i--; ) { + var r = Range.fromPoints(data[i].start, data[i].end); + if (data[i].isBackwards) + r.cursor = r.start; + this.addRange(r, true); + } + return; + } else { + data = data[0]; + } + } + if (this.rangeList) + this.toSingleRange(data); + this.setSelectionRange(data, data.isBackwards); + }; + + this.isEqual = function(data) { + if ((data.length || this.rangeCount) && data.length != this.rangeCount) + return false; + if (!data.length || !this.ranges) + return this.getRange().isEqual(data); + + for (var i = this.ranges.length; i--; ) { + if (!this.ranges[i].isEqual(data[i])) + return false; + } + return true; + }; + +}).call(Selection.prototype); + +exports.Selection = Selection; +}); + +define("ace/tokenizer",["require","exports","module","ace/config"], function(require, exports, module) { +"use strict"; + +var config = require("./config"); +var MAX_TOKEN_COUNT = 2000; +var Tokenizer = function(rules) { + this.states = rules; + + this.regExps = {}; + this.matchMappings = {}; + for (var key in this.states) { + var state = this.states[key]; + var ruleRegExps = []; + var matchTotal = 0; + var mapping = this.matchMappings[key] = {defaultToken: "text"}; + var flag = "g"; + + var splitterRurles = []; + for (var i = 0; i < state.length; i++) { + var rule = state[i]; + if (rule.defaultToken) + mapping.defaultToken = rule.defaultToken; + if (rule.caseInsensitive) + flag = "gi"; + if (rule.regex == null) + continue; + + if (rule.regex instanceof RegExp) + rule.regex = rule.regex.toString().slice(1, -1); + var adjustedregex = rule.regex; + var matchcount = new RegExp("(?:(" + adjustedregex + ")|(.))").exec("a").length - 2; + if (Array.isArray(rule.token)) { + if (rule.token.length == 1 || matchcount == 1) { + rule.token = rule.token[0]; + } else if (matchcount - 1 != rule.token.length) { + this.reportError("number of classes and regexp groups doesn't match", { + rule: rule, + groupCount: matchcount - 1 + }); + rule.token = rule.token[0]; + } else { + rule.tokenArray = rule.token; + rule.token = null; + rule.onMatch = this.$arrayTokens; + } + } else if (typeof rule.token == "function" && !rule.onMatch) { + if (matchcount > 1) + rule.onMatch = this.$applyToken; + else + rule.onMatch = rule.token; + } + + if (matchcount > 1) { + if (/\\\d/.test(rule.regex)) { + adjustedregex = rule.regex.replace(/\\([0-9]+)/g, function(match, digit) { + return "\\" + (parseInt(digit, 10) + matchTotal + 1); + }); + } else { + matchcount = 1; + adjustedregex = this.removeCapturingGroups(rule.regex); + } + if (!rule.splitRegex && typeof rule.token != "string") + splitterRurles.push(rule); // flag will be known only at the very end + } + + mapping[matchTotal] = i; + matchTotal += matchcount; + + ruleRegExps.push(adjustedregex); + if (!rule.onMatch) + rule.onMatch = null; + } + + if (!ruleRegExps.length) { + mapping[0] = 0; + ruleRegExps.push("$"); + } + + splitterRurles.forEach(function(rule) { + rule.splitRegex = this.createSplitterRegexp(rule.regex, flag); + }, this); + + this.regExps[key] = new RegExp("(" + ruleRegExps.join(")|(") + ")|($)", flag); + } +}; + +(function() { + this.$setMaxTokenCount = function(m) { + MAX_TOKEN_COUNT = m | 0; + }; + + this.$applyToken = function(str) { + var values = this.splitRegex.exec(str).slice(1); + var types = this.token.apply(this, values); + if (typeof types === "string") + return [{type: types, value: str}]; + + var tokens = []; + for (var i = 0, l = types.length; i < l; i++) { + if (values[i]) + tokens[tokens.length] = { + type: types[i], + value: values[i] + }; + } + return tokens; + }; + + this.$arrayTokens = function(str) { + if (!str) + return []; + var values = this.splitRegex.exec(str); + if (!values) + return "text"; + var tokens = []; + var types = this.tokenArray; + for (var i = 0, l = types.length; i < l; i++) { + if (values[i + 1]) + tokens[tokens.length] = { + type: types[i], + value: values[i + 1] + }; + } + return tokens; + }; + + this.removeCapturingGroups = function(src) { + var r = src.replace( + /\\.|\[(?:\\.|[^\\\]])*|\(\?[:=!]|(\()/g, + function(x, y) {return y ? "(?:" : x;} + ); + return r; + }; + + this.createSplitterRegexp = function(src, flag) { + if (src.indexOf("(?=") != -1) { + var stack = 0; + var inChClass = false; + var lastCapture = {}; + src.replace(/(\\.)|(\((?:\?[=!])?)|(\))|([\[\]])/g, function( + m, esc, parenOpen, parenClose, square, index + ) { + if (inChClass) { + inChClass = square != "]"; + } else if (square) { + inChClass = true; + } else if (parenClose) { + if (stack == lastCapture.stack) { + lastCapture.end = index+1; + lastCapture.stack = -1; + } + stack--; + } else if (parenOpen) { + stack++; + if (parenOpen.length != 1) { + lastCapture.stack = stack; + lastCapture.start = index; + } + } + return m; + }); + + if (lastCapture.end != null && /^\)*$/.test(src.substr(lastCapture.end))) + src = src.substring(0, lastCapture.start) + src.substr(lastCapture.end); + } + if (src.charAt(0) != "^") src = "^" + src; + if (src.charAt(src.length - 1) != "$") src += "$"; + + return new RegExp(src, (flag||"").replace("g", "")); + }; + this.getLineTokens = function(line, startState) { + if (startState && typeof startState != "string") { + var stack = startState.slice(0); + startState = stack[0]; + if (startState === "#tmp") { + stack.shift(); + startState = stack.shift(); + } + } else + var stack = []; + + var currentState = startState || "start"; + var state = this.states[currentState]; + if (!state) { + currentState = "start"; + state = this.states[currentState]; + } + var mapping = this.matchMappings[currentState]; + var re = this.regExps[currentState]; + re.lastIndex = 0; + + var match, tokens = []; + var lastIndex = 0; + var matchAttempts = 0; + + var token = {type: null, value: ""}; + + while (match = re.exec(line)) { + var type = mapping.defaultToken; + var rule = null; + var value = match[0]; + var index = re.lastIndex; + + if (index - value.length > lastIndex) { + var skipped = line.substring(lastIndex, index - value.length); + if (token.type == type) { + token.value += skipped; + } else { + if (token.type) + tokens.push(token); + token = {type: type, value: skipped}; + } + } + + for (var i = 0; i < match.length-2; i++) { + if (match[i + 1] === undefined) + continue; + + rule = state[mapping[i]]; + + if (rule.onMatch) + type = rule.onMatch(value, currentState, stack, line); + else + type = rule.token; + + if (rule.next) { + if (typeof rule.next == "string") { + currentState = rule.next; + } else { + currentState = rule.next(currentState, stack); + } + + state = this.states[currentState]; + if (!state) { + this.reportError("state doesn't exist", currentState); + currentState = "start"; + state = this.states[currentState]; + } + mapping = this.matchMappings[currentState]; + lastIndex = index; + re = this.regExps[currentState]; + re.lastIndex = index; + } + if (rule.consumeLineEnd) + lastIndex = index; + break; + } + + if (value) { + if (typeof type === "string") { + if ((!rule || rule.merge !== false) && token.type === type) { + token.value += value; + } else { + if (token.type) + tokens.push(token); + token = {type: type, value: value}; + } + } else if (type) { + if (token.type) + tokens.push(token); + token = {type: null, value: ""}; + for (var i = 0; i < type.length; i++) + tokens.push(type[i]); + } + } + + if (lastIndex == line.length) + break; + + lastIndex = index; + + if (matchAttempts++ > MAX_TOKEN_COUNT) { + if (matchAttempts > 2 * line.length) { + this.reportError("infinite loop with in ace tokenizer", { + startState: startState, + line: line + }); + } + while (lastIndex < line.length) { + if (token.type) + tokens.push(token); + token = { + value: line.substring(lastIndex, lastIndex += 500), + type: "overflow" + }; + } + currentState = "start"; + stack = []; + break; + } + } + + if (token.type) + tokens.push(token); + + if (stack.length > 1) { + if (stack[0] !== currentState) + stack.unshift("#tmp", currentState); + } + return { + tokens : tokens, + state : stack.length ? stack : currentState + }; + }; + + this.reportError = config.reportError; + +}).call(Tokenizer.prototype); + +exports.Tokenizer = Tokenizer; +}); + +define("ace/mode/text_highlight_rules",["require","exports","module","ace/lib/lang"], function(require, exports, module) { +"use strict"; + +var lang = require("../lib/lang"); + +var TextHighlightRules = function() { + + this.$rules = { + "start" : [{ + token : "empty_line", + regex : '^$' + }, { + defaultToken : "text" + }] + }; +}; + +(function() { + + this.addRules = function(rules, prefix) { + if (!prefix) { + for (var key in rules) + this.$rules[key] = rules[key]; + return; + } + for (var key in rules) { + var state = rules[key]; + for (var i = 0; i < state.length; i++) { + var rule = state[i]; + if (rule.next || rule.onMatch) { + if (typeof rule.next == "string") { + if (rule.next.indexOf(prefix) !== 0) + rule.next = prefix + rule.next; + } + if (rule.nextState && rule.nextState.indexOf(prefix) !== 0) + rule.nextState = prefix + rule.nextState; + } + } + this.$rules[prefix + key] = state; + } + }; + + this.getRules = function() { + return this.$rules; + }; + + this.embedRules = function (HighlightRules, prefix, escapeRules, states, append) { + var embedRules = typeof HighlightRules == "function" + ? new HighlightRules().getRules() + : HighlightRules; + if (states) { + for (var i = 0; i < states.length; i++) + states[i] = prefix + states[i]; + } else { + states = []; + for (var key in embedRules) + states.push(prefix + key); + } + + this.addRules(embedRules, prefix); + + if (escapeRules) { + var addRules = Array.prototype[append ? "push" : "unshift"]; + for (var i = 0; i < states.length; i++) + addRules.apply(this.$rules[states[i]], lang.deepCopy(escapeRules)); + } + + if (!this.$embeds) + this.$embeds = []; + this.$embeds.push(prefix); + }; + + this.getEmbeds = function() { + return this.$embeds; + }; + + var pushState = function(currentState, stack) { + if (currentState != "start" || stack.length) + stack.unshift(this.nextState, currentState); + return this.nextState; + }; + var popState = function(currentState, stack) { + stack.shift(); + return stack.shift() || "start"; + }; + + this.normalizeRules = function() { + var id = 0; + var rules = this.$rules; + function processState(key) { + var state = rules[key]; + state.processed = true; + for (var i = 0; i < state.length; i++) { + var rule = state[i]; + var toInsert = null; + if (Array.isArray(rule)) { + toInsert = rule; + rule = {}; + } + if (!rule.regex && rule.start) { + rule.regex = rule.start; + if (!rule.next) + rule.next = []; + rule.next.push({ + defaultToken: rule.token + }, { + token: rule.token + ".end", + regex: rule.end || rule.start, + next: "pop" + }); + rule.token = rule.token + ".start"; + rule.push = true; + } + var next = rule.next || rule.push; + if (next && Array.isArray(next)) { + var stateName = rule.stateName; + if (!stateName) { + stateName = rule.token; + if (typeof stateName != "string") + stateName = stateName[0] || ""; + if (rules[stateName]) + stateName += id++; + } + rules[stateName] = next; + rule.next = stateName; + processState(stateName); + } else if (next == "pop") { + rule.next = popState; + } + + if (rule.push) { + rule.nextState = rule.next || rule.push; + rule.next = pushState; + delete rule.push; + } + + if (rule.rules) { + for (var r in rule.rules) { + if (rules[r]) { + if (rules[r].push) + rules[r].push.apply(rules[r], rule.rules[r]); + } else { + rules[r] = rule.rules[r]; + } + } + } + var includeName = typeof rule == "string" ? rule : rule.include; + if (includeName) { + if (Array.isArray(includeName)) + toInsert = includeName.map(function(x) { return rules[x]; }); + else + toInsert = rules[includeName]; + } + + if (toInsert) { + var args = [i, 1].concat(toInsert); + if (rule.noEscape) + args = args.filter(function(x) {return !x.next;}); + state.splice.apply(state, args); + i--; + } + + if (rule.keywordMap) { + rule.token = this.createKeywordMapper( + rule.keywordMap, rule.defaultToken || "text", rule.caseInsensitive + ); + delete rule.defaultToken; + } + } + } + Object.keys(rules).forEach(processState, this); + }; + + this.createKeywordMapper = function(map, defaultToken, ignoreCase, splitChar) { + var keywords = Object.create(null); + Object.keys(map).forEach(function(className) { + var a = map[className]; + if (ignoreCase) + a = a.toLowerCase(); + var list = a.split(splitChar || "|"); + for (var i = list.length; i--; ) + keywords[list[i]] = className; + }); + if (Object.getPrototypeOf(keywords)) { + keywords.__proto__ = null; + } + this.$keywordList = Object.keys(keywords); + map = null; + return ignoreCase + ? function(value) {return keywords[value.toLowerCase()] || defaultToken; } + : function(value) {return keywords[value] || defaultToken; }; + }; + + this.getKeywords = function() { + return this.$keywords; + }; + +}).call(TextHighlightRules.prototype); + +exports.TextHighlightRules = TextHighlightRules; +}); + +define("ace/mode/behaviour",["require","exports","module"], function(require, exports, module) { +"use strict"; + +var Behaviour = function() { + this.$behaviours = {}; +}; + +(function () { + + this.add = function (name, action, callback) { + switch (undefined) { + case this.$behaviours: + this.$behaviours = {}; + case this.$behaviours[name]: + this.$behaviours[name] = {}; + } + this.$behaviours[name][action] = callback; + }; + + this.addBehaviours = function (behaviours) { + for (var key in behaviours) { + for (var action in behaviours[key]) { + this.add(key, action, behaviours[key][action]); + } + } + }; + + this.remove = function (name) { + if (this.$behaviours && this.$behaviours[name]) { + delete this.$behaviours[name]; + } + }; + + this.inherit = function (mode, filter) { + if (typeof mode === "function") { + var behaviours = new mode().getBehaviours(filter); + } else { + var behaviours = mode.getBehaviours(filter); + } + this.addBehaviours(behaviours); + }; + + this.getBehaviours = function (filter) { + if (!filter) { + return this.$behaviours; + } else { + var ret = {}; + for (var i = 0; i < filter.length; i++) { + if (this.$behaviours[filter[i]]) { + ret[filter[i]] = this.$behaviours[filter[i]]; + } + } + return ret; + } + }; + +}).call(Behaviour.prototype); + +exports.Behaviour = Behaviour; +}); + +define("ace/token_iterator",["require","exports","module","ace/range"], function(require, exports, module) { +"use strict"; + +var Range = require("./range").Range; +var TokenIterator = function(session, initialRow, initialColumn) { + this.$session = session; + this.$row = initialRow; + this.$rowTokens = session.getTokens(initialRow); + + var token = session.getTokenAt(initialRow, initialColumn); + this.$tokenIndex = token ? token.index : -1; +}; + +(function() { + this.stepBackward = function() { + this.$tokenIndex -= 1; + + while (this.$tokenIndex < 0) { + this.$row -= 1; + if (this.$row < 0) { + this.$row = 0; + return null; + } + + this.$rowTokens = this.$session.getTokens(this.$row); + this.$tokenIndex = this.$rowTokens.length - 1; + } + + return this.$rowTokens[this.$tokenIndex]; + }; + this.stepForward = function() { + this.$tokenIndex += 1; + var rowCount; + while (this.$tokenIndex >= this.$rowTokens.length) { + this.$row += 1; + if (!rowCount) + rowCount = this.$session.getLength(); + if (this.$row >= rowCount) { + this.$row = rowCount - 1; + return null; + } + + this.$rowTokens = this.$session.getTokens(this.$row); + this.$tokenIndex = 0; + } + + return this.$rowTokens[this.$tokenIndex]; + }; + this.getCurrentToken = function () { + return this.$rowTokens[this.$tokenIndex]; + }; + this.getCurrentTokenRow = function () { + return this.$row; + }; + this.getCurrentTokenColumn = function() { + var rowTokens = this.$rowTokens; + var tokenIndex = this.$tokenIndex; + var column = rowTokens[tokenIndex].start; + if (column !== undefined) + return column; + + column = 0; + while (tokenIndex > 0) { + tokenIndex -= 1; + column += rowTokens[tokenIndex].value.length; + } + + return column; + }; + this.getCurrentTokenPosition = function() { + return {row: this.$row, column: this.getCurrentTokenColumn()}; + }; + this.getCurrentTokenRange = function() { + var token = this.$rowTokens[this.$tokenIndex]; + var column = this.getCurrentTokenColumn(); + return new Range(this.$row, column, this.$row, column + token.value.length); + }; + +}).call(TokenIterator.prototype); + +exports.TokenIterator = TokenIterator; +}); + +define("ace/mode/behaviour/cstyle",["require","exports","module","ace/lib/oop","ace/mode/behaviour","ace/token_iterator","ace/lib/lang"], function(require, exports, module) { +"use strict"; + +var oop = require("../../lib/oop"); +var Behaviour = require("../behaviour").Behaviour; +var TokenIterator = require("../../token_iterator").TokenIterator; +var lang = require("../../lib/lang"); + +var SAFE_INSERT_IN_TOKENS = + ["text", "paren.rparen", "rparen", "paren", "punctuation.operator"]; +var SAFE_INSERT_BEFORE_TOKENS = + ["text", "paren.rparen", "rparen", "paren", "punctuation.operator", "comment"]; + +var context; +var contextCache = {}; +var defaultQuotes = {'"' : '"', "'" : "'"}; + +var initContext = function(editor) { + var id = -1; + if (editor.multiSelect) { + id = editor.selection.index; + if (contextCache.rangeCount != editor.multiSelect.rangeCount) + contextCache = {rangeCount: editor.multiSelect.rangeCount}; + } + if (contextCache[id]) + return context = contextCache[id]; + context = contextCache[id] = { + autoInsertedBrackets: 0, + autoInsertedRow: -1, + autoInsertedLineEnd: "", + maybeInsertedBrackets: 0, + maybeInsertedRow: -1, + maybeInsertedLineStart: "", + maybeInsertedLineEnd: "" + }; +}; + +var getWrapped = function(selection, selected, opening, closing) { + var rowDiff = selection.end.row - selection.start.row; + return { + text: opening + selected + closing, + selection: [ + 0, + selection.start.column + 1, + rowDiff, + selection.end.column + (rowDiff ? 0 : 1) + ] + }; +}; + +var CstyleBehaviour = function(options) { + this.add("braces", "insertion", function(state, action, editor, session, text) { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + if (text == '{') { + initContext(editor); + var selection = editor.getSelectionRange(); + var selected = session.doc.getTextRange(selection); + if (selected !== "" && selected !== "{" && editor.getWrapBehavioursEnabled()) { + return getWrapped(selection, selected, '{', '}'); + } else if (CstyleBehaviour.isSaneInsertion(editor, session)) { + if (/[\]\}\)]/.test(line[cursor.column]) || editor.inMultiSelectMode || options && options.braces) { + CstyleBehaviour.recordAutoInsert(editor, session, "}"); + return { + text: '{}', + selection: [1, 1] + }; + } else { + CstyleBehaviour.recordMaybeInsert(editor, session, "{"); + return { + text: '{', + selection: [1, 1] + }; + } + } + } else if (text == '}') { + initContext(editor); + var rightChar = line.substring(cursor.column, cursor.column + 1); + if (rightChar == '}') { + var matching = session.$findOpeningBracket('}', {column: cursor.column + 1, row: cursor.row}); + if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) { + CstyleBehaviour.popAutoInsertedClosing(); + return { + text: '', + selection: [1, 1] + }; + } + } + } else if (text == "\n" || text == "\r\n") { + initContext(editor); + var closing = ""; + if (CstyleBehaviour.isMaybeInsertedClosing(cursor, line)) { + closing = lang.stringRepeat("}", context.maybeInsertedBrackets); + CstyleBehaviour.clearMaybeInsertedClosing(); + } + var rightChar = line.substring(cursor.column, cursor.column + 1); + if (rightChar === '}') { + var openBracePos = session.findMatchingBracket({row: cursor.row, column: cursor.column+1}, '}'); + if (!openBracePos) + return null; + var next_indent = this.$getIndent(session.getLine(openBracePos.row)); + } else if (closing) { + var next_indent = this.$getIndent(line); + } else { + CstyleBehaviour.clearMaybeInsertedClosing(); + return; + } + var indent = next_indent + session.getTabString(); + + return { + text: '\n' + indent + '\n' + next_indent + closing, + selection: [1, indent.length, 1, indent.length] + }; + } else { + CstyleBehaviour.clearMaybeInsertedClosing(); + } + }); + + this.add("braces", "deletion", function(state, action, editor, session, range) { + var selected = session.doc.getTextRange(range); + if (!range.isMultiLine() && selected == '{') { + initContext(editor); + var line = session.doc.getLine(range.start.row); + var rightChar = line.substring(range.end.column, range.end.column + 1); + if (rightChar == '}') { + range.end.column++; + return range; + } else { + context.maybeInsertedBrackets--; + } + } + }); + + this.add("parens", "insertion", function(state, action, editor, session, text) { + if (text == '(') { + initContext(editor); + var selection = editor.getSelectionRange(); + var selected = session.doc.getTextRange(selection); + if (selected !== "" && editor.getWrapBehavioursEnabled()) { + return getWrapped(selection, selected, '(', ')'); + } else if (CstyleBehaviour.isSaneInsertion(editor, session)) { + CstyleBehaviour.recordAutoInsert(editor, session, ")"); + return { + text: '()', + selection: [1, 1] + }; + } + } else if (text == ')') { + initContext(editor); + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + var rightChar = line.substring(cursor.column, cursor.column + 1); + if (rightChar == ')') { + var matching = session.$findOpeningBracket(')', {column: cursor.column + 1, row: cursor.row}); + if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) { + CstyleBehaviour.popAutoInsertedClosing(); + return { + text: '', + selection: [1, 1] + }; + } + } + } + }); + + this.add("parens", "deletion", function(state, action, editor, session, range) { + var selected = session.doc.getTextRange(range); + if (!range.isMultiLine() && selected == '(') { + initContext(editor); + var line = session.doc.getLine(range.start.row); + var rightChar = line.substring(range.start.column + 1, range.start.column + 2); + if (rightChar == ')') { + range.end.column++; + return range; + } + } + }); + + this.add("brackets", "insertion", function(state, action, editor, session, text) { + if (text == '[') { + initContext(editor); + var selection = editor.getSelectionRange(); + var selected = session.doc.getTextRange(selection); + if (selected !== "" && editor.getWrapBehavioursEnabled()) { + return getWrapped(selection, selected, '[', ']'); + } else if (CstyleBehaviour.isSaneInsertion(editor, session)) { + CstyleBehaviour.recordAutoInsert(editor, session, "]"); + return { + text: '[]', + selection: [1, 1] + }; + } + } else if (text == ']') { + initContext(editor); + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + var rightChar = line.substring(cursor.column, cursor.column + 1); + if (rightChar == ']') { + var matching = session.$findOpeningBracket(']', {column: cursor.column + 1, row: cursor.row}); + if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) { + CstyleBehaviour.popAutoInsertedClosing(); + return { + text: '', + selection: [1, 1] + }; + } + } + } + }); + + this.add("brackets", "deletion", function(state, action, editor, session, range) { + var selected = session.doc.getTextRange(range); + if (!range.isMultiLine() && selected == '[') { + initContext(editor); + var line = session.doc.getLine(range.start.row); + var rightChar = line.substring(range.start.column + 1, range.start.column + 2); + if (rightChar == ']') { + range.end.column++; + return range; + } + } + }); + + this.add("string_dquotes", "insertion", function(state, action, editor, session, text) { + var quotes = session.$mode.$quotes || defaultQuotes; + if (text.length == 1 && quotes[text]) { + if (this.lineCommentStart && this.lineCommentStart.indexOf(text) != -1) + return; + initContext(editor); + var quote = text; + var selection = editor.getSelectionRange(); + var selected = session.doc.getTextRange(selection); + if (selected !== "" && (selected.length != 1 || !quotes[selected]) && editor.getWrapBehavioursEnabled()) { + return getWrapped(selection, selected, quote, quote); + } else if (!selected) { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + var leftChar = line.substring(cursor.column-1, cursor.column); + var rightChar = line.substring(cursor.column, cursor.column + 1); + + var token = session.getTokenAt(cursor.row, cursor.column); + var rightToken = session.getTokenAt(cursor.row, cursor.column + 1); + if (leftChar == "\\" && token && /escape/.test(token.type)) + return null; + + var stringBefore = token && /string|escape/.test(token.type); + var stringAfter = !rightToken || /string|escape/.test(rightToken.type); + + var pair; + if (rightChar == quote) { + pair = stringBefore !== stringAfter; + if (pair && /string\.end/.test(rightToken.type)) + pair = false; + } else { + if (stringBefore && !stringAfter) + return null; // wrap string with different quote + if (stringBefore && stringAfter) + return null; // do not pair quotes inside strings + var wordRe = session.$mode.tokenRe; + wordRe.lastIndex = 0; + var isWordBefore = wordRe.test(leftChar); + wordRe.lastIndex = 0; + var isWordAfter = wordRe.test(leftChar); + if (isWordBefore || isWordAfter) + return null; // before or after alphanumeric + if (rightChar && !/[\s;,.})\]\\]/.test(rightChar)) + return null; // there is rightChar and it isn't closing + var charBefore = line[cursor.column - 2]; + if (leftChar == quote && (charBefore == quote || wordRe.test(charBefore))) + return null; + pair = true; + } + return { + text: pair ? quote + quote : "", + selection: [1,1] + }; + } + } + }); + + this.add("string_dquotes", "deletion", function(state, action, editor, session, range) { + var quotes = session.$mode.$quotes || defaultQuotes; + + var selected = session.doc.getTextRange(range); + if (!range.isMultiLine() && quotes.hasOwnProperty(selected)) { + initContext(editor); + var line = session.doc.getLine(range.start.row); + var rightChar = line.substring(range.start.column + 1, range.start.column + 2); + if (rightChar == selected) { + range.end.column++; + return range; + } + } + }); + +}; + + +CstyleBehaviour.isSaneInsertion = function(editor, session) { + var cursor = editor.getCursorPosition(); + var iterator = new TokenIterator(session, cursor.row, cursor.column); + if (!this.$matchTokenType(iterator.getCurrentToken() || "text", SAFE_INSERT_IN_TOKENS)) { + if (/[)}\]]/.test(editor.session.getLine(cursor.row)[cursor.column])) + return true; + var iterator2 = new TokenIterator(session, cursor.row, cursor.column + 1); + if (!this.$matchTokenType(iterator2.getCurrentToken() || "text", SAFE_INSERT_IN_TOKENS)) + return false; + } + iterator.stepForward(); + return iterator.getCurrentTokenRow() !== cursor.row || + this.$matchTokenType(iterator.getCurrentToken() || "text", SAFE_INSERT_BEFORE_TOKENS); +}; + +CstyleBehaviour.$matchTokenType = function(token, types) { + return types.indexOf(token.type || token) > -1; +}; + +CstyleBehaviour.recordAutoInsert = function(editor, session, bracket) { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + if (!this.isAutoInsertedClosing(cursor, line, context.autoInsertedLineEnd[0])) + context.autoInsertedBrackets = 0; + context.autoInsertedRow = cursor.row; + context.autoInsertedLineEnd = bracket + line.substr(cursor.column); + context.autoInsertedBrackets++; +}; + +CstyleBehaviour.recordMaybeInsert = function(editor, session, bracket) { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + if (!this.isMaybeInsertedClosing(cursor, line)) + context.maybeInsertedBrackets = 0; + context.maybeInsertedRow = cursor.row; + context.maybeInsertedLineStart = line.substr(0, cursor.column) + bracket; + context.maybeInsertedLineEnd = line.substr(cursor.column); + context.maybeInsertedBrackets++; +}; + +CstyleBehaviour.isAutoInsertedClosing = function(cursor, line, bracket) { + return context.autoInsertedBrackets > 0 && + cursor.row === context.autoInsertedRow && + bracket === context.autoInsertedLineEnd[0] && + line.substr(cursor.column) === context.autoInsertedLineEnd; +}; + +CstyleBehaviour.isMaybeInsertedClosing = function(cursor, line) { + return context.maybeInsertedBrackets > 0 && + cursor.row === context.maybeInsertedRow && + line.substr(cursor.column) === context.maybeInsertedLineEnd && + line.substr(0, cursor.column) == context.maybeInsertedLineStart; +}; + +CstyleBehaviour.popAutoInsertedClosing = function() { + context.autoInsertedLineEnd = context.autoInsertedLineEnd.substr(1); + context.autoInsertedBrackets--; +}; + +CstyleBehaviour.clearMaybeInsertedClosing = function() { + if (context) { + context.maybeInsertedBrackets = 0; + context.maybeInsertedRow = -1; + } +}; + + + +oop.inherits(CstyleBehaviour, Behaviour); + +exports.CstyleBehaviour = CstyleBehaviour; +}); + +define("ace/unicode",["require","exports","module"], function(require, exports, module) { +"use strict"; +var wordChars = [48,9,8,25,5,0,2,25,48,0,11,0,5,0,6,22,2,30,2,457,5,11,15,4,8,0,2,0,18,116,2,1,3,3,9,0,2,2,2,0,2,19,2,82,2,138,2,4,3,155,12,37,3,0,8,38,10,44,2,0,2,1,2,1,2,0,9,26,6,2,30,10,7,61,2,9,5,101,2,7,3,9,2,18,3,0,17,58,3,100,15,53,5,0,6,45,211,57,3,18,2,5,3,11,3,9,2,1,7,6,2,2,2,7,3,1,3,21,2,6,2,0,4,3,3,8,3,1,3,3,9,0,5,1,2,4,3,11,16,2,2,5,5,1,3,21,2,6,2,1,2,1,2,1,3,0,2,4,5,1,3,2,4,0,8,3,2,0,8,15,12,2,2,8,2,2,2,21,2,6,2,1,2,4,3,9,2,2,2,2,3,0,16,3,3,9,18,2,2,7,3,1,3,21,2,6,2,1,2,4,3,8,3,1,3,2,9,1,5,1,2,4,3,9,2,0,17,1,2,5,4,2,2,3,4,1,2,0,2,1,4,1,4,2,4,11,5,4,4,2,2,3,3,0,7,0,15,9,18,2,2,7,2,2,2,22,2,9,2,4,4,7,2,2,2,3,8,1,2,1,7,3,3,9,19,1,2,7,2,2,2,22,2,9,2,4,3,8,2,2,2,3,8,1,8,0,2,3,3,9,19,1,2,7,2,2,2,22,2,15,4,7,2,2,2,3,10,0,9,3,3,9,11,5,3,1,2,17,4,23,2,8,2,0,3,6,4,0,5,5,2,0,2,7,19,1,14,57,6,14,2,9,40,1,2,0,3,1,2,0,3,0,7,3,2,6,2,2,2,0,2,0,3,1,2,12,2,2,3,4,2,0,2,5,3,9,3,1,35,0,24,1,7,9,12,0,2,0,2,0,5,9,2,35,5,19,2,5,5,7,2,35,10,0,58,73,7,77,3,37,11,42,2,0,4,328,2,3,3,6,2,0,2,3,3,40,2,3,3,32,2,3,3,6,2,0,2,3,3,14,2,56,2,3,3,66,5,0,33,15,17,84,13,619,3,16,2,25,6,74,22,12,2,6,12,20,12,19,13,12,2,2,2,1,13,51,3,29,4,0,5,1,3,9,34,2,3,9,7,87,9,42,6,69,11,28,4,11,5,11,11,39,3,4,12,43,5,25,7,10,38,27,5,62,2,28,3,10,7,9,14,0,89,75,5,9,18,8,13,42,4,11,71,55,9,9,4,48,83,2,2,30,14,230,23,280,3,5,3,37,3,5,3,7,2,0,2,0,2,0,2,30,3,52,2,6,2,0,4,2,2,6,4,3,3,5,5,12,6,2,2,6,67,1,20,0,29,0,14,0,17,4,60,12,5,0,4,11,18,0,5,0,3,9,2,0,4,4,7,0,2,0,2,0,2,3,2,10,3,3,6,4,5,0,53,1,2684,46,2,46,2,132,7,6,15,37,11,53,10,0,17,22,10,6,2,6,2,6,2,6,2,6,2,6,2,6,2,6,2,31,48,0,470,1,36,5,2,4,6,1,5,85,3,1,3,2,2,89,2,3,6,40,4,93,18,23,57,15,513,6581,75,20939,53,1164,68,45,3,268,4,27,21,31,3,13,13,1,2,24,9,69,11,1,38,8,3,102,3,1,111,44,25,51,13,68,12,9,7,23,4,0,5,45,3,35,13,28,4,64,15,10,39,54,10,13,3,9,7,22,4,1,5,66,25,2,227,42,2,1,3,9,7,11171,13,22,5,48,8453,301,3,61,3,105,39,6,13,4,6,11,2,12,2,4,2,0,2,1,2,1,2,107,34,362,19,63,3,53,41,11,5,15,17,6,13,1,25,2,33,4,2,134,20,9,8,25,5,0,2,25,12,88,4,5,3,5,3,5,3,2]; + +var code = 0; +var str = []; +for (var i = 0; i < wordChars.length; i += 2) { + str.push(code += wordChars[i]); + if (wordChars[i + 1]) + str.push(45, code += wordChars[i + 1]); +} + +exports.wordChars = String.fromCharCode.apply(null, str); + +}); + +define("ace/mode/text",["require","exports","module","ace/config","ace/tokenizer","ace/mode/text_highlight_rules","ace/mode/behaviour/cstyle","ace/unicode","ace/lib/lang","ace/token_iterator","ace/range"], function(require, exports, module) { +"use strict"; +var config = require("../config"); + +var Tokenizer = require("../tokenizer").Tokenizer; +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; +var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour; +var unicode = require("../unicode"); +var lang = require("../lib/lang"); +var TokenIterator = require("../token_iterator").TokenIterator; +var Range = require("../range").Range; + +var Mode = function() { + this.HighlightRules = TextHighlightRules; +}; + +(function() { + this.$defaultBehaviour = new CstyleBehaviour(); + + this.tokenRe = new RegExp("^[" + unicode.wordChars + "\\$_]+", "g"); + + this.nonTokenRe = new RegExp("^(?:[^" + unicode.wordChars + "\\$_]|\\s])+", "g"); + + this.getTokenizer = function() { + if (!this.$tokenizer) { + this.$highlightRules = this.$highlightRules || new this.HighlightRules(this.$highlightRuleConfig); + this.$tokenizer = new Tokenizer(this.$highlightRules.getRules()); + } + return this.$tokenizer; + }; + + this.lineCommentStart = ""; + this.blockComment = ""; + + this.toggleCommentLines = function(state, session, startRow, endRow) { + var doc = session.doc; + + var ignoreBlankLines = true; + var shouldRemove = true; + var minIndent = Infinity; + var tabSize = session.getTabSize(); + var insertAtTabStop = false; + + if (!this.lineCommentStart) { + if (!this.blockComment) + return false; + var lineCommentStart = this.blockComment.start; + var lineCommentEnd = this.blockComment.end; + var regexpStart = new RegExp("^(\\s*)(?:" + lang.escapeRegExp(lineCommentStart) + ")"); + var regexpEnd = new RegExp("(?:" + lang.escapeRegExp(lineCommentEnd) + ")\\s*$"); + + var comment = function(line, i) { + if (testRemove(line, i)) + return; + if (!ignoreBlankLines || /\S/.test(line)) { + doc.insertInLine({row: i, column: line.length}, lineCommentEnd); + doc.insertInLine({row: i, column: minIndent}, lineCommentStart); + } + }; + + var uncomment = function(line, i) { + var m; + if (m = line.match(regexpEnd)) + doc.removeInLine(i, line.length - m[0].length, line.length); + if (m = line.match(regexpStart)) + doc.removeInLine(i, m[1].length, m[0].length); + }; + + var testRemove = function(line, row) { + if (regexpStart.test(line)) + return true; + var tokens = session.getTokens(row); + for (var i = 0; i < tokens.length; i++) { + if (tokens[i].type === "comment") + return true; + } + }; + } else { + if (Array.isArray(this.lineCommentStart)) { + var regexpStart = this.lineCommentStart.map(lang.escapeRegExp).join("|"); + var lineCommentStart = this.lineCommentStart[0]; + } else { + var regexpStart = lang.escapeRegExp(this.lineCommentStart); + var lineCommentStart = this.lineCommentStart; + } + regexpStart = new RegExp("^(\\s*)(?:" + regexpStart + ") ?"); + + insertAtTabStop = session.getUseSoftTabs(); + + var uncomment = function(line, i) { + var m = line.match(regexpStart); + if (!m) return; + var start = m[1].length, end = m[0].length; + if (!shouldInsertSpace(line, start, end) && m[0][end - 1] == " ") + end--; + doc.removeInLine(i, start, end); + }; + var commentWithSpace = lineCommentStart + " "; + var comment = function(line, i) { + if (!ignoreBlankLines || /\S/.test(line)) { + if (shouldInsertSpace(line, minIndent, minIndent)) + doc.insertInLine({row: i, column: minIndent}, commentWithSpace); + else + doc.insertInLine({row: i, column: minIndent}, lineCommentStart); + } + }; + var testRemove = function(line, i) { + return regexpStart.test(line); + }; + + var shouldInsertSpace = function(line, before, after) { + var spaces = 0; + while (before-- && line.charAt(before) == " ") + spaces++; + if (spaces % tabSize != 0) + return false; + var spaces = 0; + while (line.charAt(after++) == " ") + spaces++; + if (tabSize > 2) + return spaces % tabSize != tabSize - 1; + else + return spaces % tabSize == 0; + }; + } + + function iter(fun) { + for (var i = startRow; i <= endRow; i++) + fun(doc.getLine(i), i); + } + + + var minEmptyLength = Infinity; + iter(function(line, i) { + var indent = line.search(/\S/); + if (indent !== -1) { + if (indent < minIndent) + minIndent = indent; + if (shouldRemove && !testRemove(line, i)) + shouldRemove = false; + } else if (minEmptyLength > line.length) { + minEmptyLength = line.length; + } + }); + + if (minIndent == Infinity) { + minIndent = minEmptyLength; + ignoreBlankLines = false; + shouldRemove = false; + } + + if (insertAtTabStop && minIndent % tabSize != 0) + minIndent = Math.floor(minIndent / tabSize) * tabSize; + + iter(shouldRemove ? uncomment : comment); + }; + + this.toggleBlockComment = function(state, session, range, cursor) { + var comment = this.blockComment; + if (!comment) + return; + if (!comment.start && comment[0]) + comment = comment[0]; + + var iterator = new TokenIterator(session, cursor.row, cursor.column); + var token = iterator.getCurrentToken(); + + var sel = session.selection; + var initialRange = session.selection.toOrientedRange(); + var startRow, colDiff; + + if (token && /comment/.test(token.type)) { + var startRange, endRange; + while (token && /comment/.test(token.type)) { + var i = token.value.indexOf(comment.start); + if (i != -1) { + var row = iterator.getCurrentTokenRow(); + var column = iterator.getCurrentTokenColumn() + i; + startRange = new Range(row, column, row, column + comment.start.length); + break; + } + token = iterator.stepBackward(); + } + + var iterator = new TokenIterator(session, cursor.row, cursor.column); + var token = iterator.getCurrentToken(); + while (token && /comment/.test(token.type)) { + var i = token.value.indexOf(comment.end); + if (i != -1) { + var row = iterator.getCurrentTokenRow(); + var column = iterator.getCurrentTokenColumn() + i; + endRange = new Range(row, column, row, column + comment.end.length); + break; + } + token = iterator.stepForward(); + } + if (endRange) + session.remove(endRange); + if (startRange) { + session.remove(startRange); + startRow = startRange.start.row; + colDiff = -comment.start.length; + } + } else { + colDiff = comment.start.length; + startRow = range.start.row; + session.insert(range.end, comment.end); + session.insert(range.start, comment.start); + } + if (initialRange.start.row == startRow) + initialRange.start.column += colDiff; + if (initialRange.end.row == startRow) + initialRange.end.column += colDiff; + session.selection.fromOrientedRange(initialRange); + }; + + this.getNextLineIndent = function(state, line, tab) { + return this.$getIndent(line); + }; + + this.checkOutdent = function(state, line, input) { + return false; + }; + + this.autoOutdent = function(state, doc, row) { + }; + + this.$getIndent = function(line) { + return line.match(/^\s*/)[0]; + }; + + this.createWorker = function(session) { + return null; + }; + + this.createModeDelegates = function (mapping) { + this.$embeds = []; + this.$modes = {}; + for (var i in mapping) { + if (mapping[i]) { + var Mode = mapping[i]; + var id = Mode.prototype.$id; + var mode = config.$modes[id]; + if (!mode) + config.$modes[id] = mode = new Mode(); + if (!config.$modes[i]) + config.$modes[i] = mode; + this.$embeds.push(i); + this.$modes[i] = mode; + } + } + + var delegations = ["toggleBlockComment", "toggleCommentLines", "getNextLineIndent", + "checkOutdent", "autoOutdent", "transformAction", "getCompletions"]; + + for (var i = 0; i < delegations.length; i++) { + (function(scope) { + var functionName = delegations[i]; + var defaultHandler = scope[functionName]; + scope[delegations[i]] = function() { + return this.$delegator(functionName, arguments, defaultHandler); + }; + }(this)); + } + }; + + this.$delegator = function(method, args, defaultHandler) { + var state = args[0] || "start"; + if (typeof state != "string") { + if (Array.isArray(state[2])) { + var language = state[2][state[2].length - 1]; + var mode = this.$modes[language]; + if (mode) + return mode[method].apply(mode, [state[1]].concat([].slice.call(args, 1))); + } + state = state[0] || "start"; + } + + for (var i = 0; i < this.$embeds.length; i++) { + if (!this.$modes[this.$embeds[i]]) continue; + + var split = state.split(this.$embeds[i]); + if (!split[0] && split[1]) { + args[0] = split[1]; + var mode = this.$modes[this.$embeds[i]]; + return mode[method].apply(mode, args); + } + } + var ret = defaultHandler.apply(this, args); + return defaultHandler ? ret : undefined; + }; + + this.transformAction = function(state, action, editor, session, param) { + if (this.$behaviour) { + var behaviours = this.$behaviour.getBehaviours(); + for (var key in behaviours) { + if (behaviours[key][action]) { + var ret = behaviours[key][action].apply(this, arguments); + if (ret) { + return ret; + } + } + } + } + }; + + this.getKeywords = function(append) { + if (!this.completionKeywords) { + var rules = this.$tokenizer.rules; + var completionKeywords = []; + for (var rule in rules) { + var ruleItr = rules[rule]; + for (var r = 0, l = ruleItr.length; r < l; r++) { + if (typeof ruleItr[r].token === "string") { + if (/keyword|support|storage/.test(ruleItr[r].token)) + completionKeywords.push(ruleItr[r].regex); + } + else if (typeof ruleItr[r].token === "object") { + for (var a = 0, aLength = ruleItr[r].token.length; a < aLength; a++) { + if (/keyword|support|storage/.test(ruleItr[r].token[a])) { + var rule = ruleItr[r].regex.match(/\(.+?\)/g)[a]; + completionKeywords.push(rule.substr(1, rule.length - 2)); + } + } + } + } + } + this.completionKeywords = completionKeywords; + } + if (!append) + return this.$keywordList; + return completionKeywords.concat(this.$keywordList || []); + }; + + this.$createKeywordList = function() { + if (!this.$highlightRules) + this.getTokenizer(); + return this.$keywordList = this.$highlightRules.$keywordList || []; + }; + + this.getCompletions = function(state, session, pos, prefix) { + var keywords = this.$keywordList || this.$createKeywordList(); + return keywords.map(function(word) { + return { + name: word, + value: word, + score: 0, + meta: "keyword" + }; + }); + }; + + this.$id = "ace/mode/text"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); + +define("ace/apply_delta",["require","exports","module"], function(require, exports, module) { +"use strict"; + +function throwDeltaError(delta, errorText){ + console.log("Invalid Delta:", delta); + throw "Invalid Delta: " + errorText; +} + +function positionInDocument(docLines, position) { + return position.row >= 0 && position.row < docLines.length && + position.column >= 0 && position.column <= docLines[position.row].length; +} + +function validateDelta(docLines, delta) { + if (delta.action != "insert" && delta.action != "remove") + throwDeltaError(delta, "delta.action must be 'insert' or 'remove'"); + if (!(delta.lines instanceof Array)) + throwDeltaError(delta, "delta.lines must be an Array"); + if (!delta.start || !delta.end) + throwDeltaError(delta, "delta.start/end must be an present"); + var start = delta.start; + if (!positionInDocument(docLines, delta.start)) + throwDeltaError(delta, "delta.start must be contained in document"); + var end = delta.end; + if (delta.action == "remove" && !positionInDocument(docLines, end)) + throwDeltaError(delta, "delta.end must contained in document for 'remove' actions"); + var numRangeRows = end.row - start.row; + var numRangeLastLineChars = (end.column - (numRangeRows == 0 ? start.column : 0)); + if (numRangeRows != delta.lines.length - 1 || delta.lines[numRangeRows].length != numRangeLastLineChars) + throwDeltaError(delta, "delta.range must match delta lines"); +} + +exports.applyDelta = function(docLines, delta, doNotValidate) { + + var row = delta.start.row; + var startColumn = delta.start.column; + var line = docLines[row] || ""; + switch (delta.action) { + case "insert": + var lines = delta.lines; + if (lines.length === 1) { + docLines[row] = line.substring(0, startColumn) + delta.lines[0] + line.substring(startColumn); + } else { + var args = [row, 1].concat(delta.lines); + docLines.splice.apply(docLines, args); + docLines[row] = line.substring(0, startColumn) + docLines[row]; + docLines[row + delta.lines.length - 1] += line.substring(startColumn); + } + break; + case "remove": + var endColumn = delta.end.column; + var endRow = delta.end.row; + if (row === endRow) { + docLines[row] = line.substring(0, startColumn) + line.substring(endColumn); + } else { + docLines.splice( + row, endRow - row + 1, + line.substring(0, startColumn) + docLines[endRow].substring(endColumn) + ); + } + break; + } +}; +}); + +define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"], function(require, exports, module) { +"use strict"; + +var oop = require("./lib/oop"); +var EventEmitter = require("./lib/event_emitter").EventEmitter; + +var Anchor = exports.Anchor = function(doc, row, column) { + this.$onChange = this.onChange.bind(this); + this.attach(doc); + + if (typeof column == "undefined") + this.setPosition(row.row, row.column); + else + this.setPosition(row, column); +}; + +(function() { + + oop.implement(this, EventEmitter); + this.getPosition = function() { + return this.$clipPositionToDocument(this.row, this.column); + }; + this.getDocument = function() { + return this.document; + }; + this.$insertRight = false; + this.onChange = function(delta) { + if (delta.start.row == delta.end.row && delta.start.row != this.row) + return; + + if (delta.start.row > this.row) + return; + + var point = $getTransformedPoint(delta, {row: this.row, column: this.column}, this.$insertRight); + this.setPosition(point.row, point.column, true); + }; + + function $pointsInOrder(point1, point2, equalPointsInOrder) { + var bColIsAfter = equalPointsInOrder ? point1.column <= point2.column : point1.column < point2.column; + return (point1.row < point2.row) || (point1.row == point2.row && bColIsAfter); + } + + function $getTransformedPoint(delta, point, moveIfEqual) { + var deltaIsInsert = delta.action == "insert"; + var deltaRowShift = (deltaIsInsert ? 1 : -1) * (delta.end.row - delta.start.row); + var deltaColShift = (deltaIsInsert ? 1 : -1) * (delta.end.column - delta.start.column); + var deltaStart = delta.start; + var deltaEnd = deltaIsInsert ? deltaStart : delta.end; // Collapse insert range. + if ($pointsInOrder(point, deltaStart, moveIfEqual)) { + return { + row: point.row, + column: point.column + }; + } + if ($pointsInOrder(deltaEnd, point, !moveIfEqual)) { + return { + row: point.row + deltaRowShift, + column: point.column + (point.row == deltaEnd.row ? deltaColShift : 0) + }; + } + + return { + row: deltaStart.row, + column: deltaStart.column + }; + } + this.setPosition = function(row, column, noClip) { + var pos; + if (noClip) { + pos = { + row: row, + column: column + }; + } else { + pos = this.$clipPositionToDocument(row, column); + } + + if (this.row == pos.row && this.column == pos.column) + return; + + var old = { + row: this.row, + column: this.column + }; + + this.row = pos.row; + this.column = pos.column; + this._signal("change", { + old: old, + value: pos + }); + }; + this.detach = function() { + this.document.removeEventListener("change", this.$onChange); + }; + this.attach = function(doc) { + this.document = doc || this.document; + this.document.on("change", this.$onChange); + }; + this.$clipPositionToDocument = function(row, column) { + var pos = {}; + + if (row >= this.document.getLength()) { + pos.row = Math.max(0, this.document.getLength() - 1); + pos.column = this.document.getLine(pos.row).length; + } + else if (row < 0) { + pos.row = 0; + pos.column = 0; + } + else { + pos.row = row; + pos.column = Math.min(this.document.getLine(pos.row).length, Math.max(0, column)); + } + + if (column < 0) + pos.column = 0; + + return pos; + }; + +}).call(Anchor.prototype); + +}); + +define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"], function(require, exports, module) { +"use strict"; + +var oop = require("./lib/oop"); +var applyDelta = require("./apply_delta").applyDelta; +var EventEmitter = require("./lib/event_emitter").EventEmitter; +var Range = require("./range").Range; +var Anchor = require("./anchor").Anchor; + +var Document = function(textOrLines) { + this.$lines = [""]; + if (textOrLines.length === 0) { + this.$lines = [""]; + } else if (Array.isArray(textOrLines)) { + this.insertMergedLines({row: 0, column: 0}, textOrLines); + } else { + this.insert({row: 0, column:0}, textOrLines); + } +}; + +(function() { + + oop.implement(this, EventEmitter); + this.setValue = function(text) { + var len = this.getLength() - 1; + this.remove(new Range(0, 0, len, this.getLine(len).length)); + this.insert({row: 0, column: 0}, text); + }; + this.getValue = function() { + return this.getAllLines().join(this.getNewLineCharacter()); + }; + this.createAnchor = function(row, column) { + return new Anchor(this, row, column); + }; + if ("aaa".split(/a/).length === 0) { + this.$split = function(text) { + return text.replace(/\r\n|\r/g, "\n").split("\n"); + }; + } else { + this.$split = function(text) { + return text.split(/\r\n|\r|\n/); + }; + } + + + this.$detectNewLine = function(text) { + var match = text.match(/^.*?(\r\n|\r|\n)/m); + this.$autoNewLine = match ? match[1] : "\n"; + this._signal("changeNewLineMode"); + }; + this.getNewLineCharacter = function() { + switch (this.$newLineMode) { + case "windows": + return "\r\n"; + case "unix": + return "\n"; + default: + return this.$autoNewLine || "\n"; + } + }; + + this.$autoNewLine = ""; + this.$newLineMode = "auto"; + this.setNewLineMode = function(newLineMode) { + if (this.$newLineMode === newLineMode) + return; + + this.$newLineMode = newLineMode; + this._signal("changeNewLineMode"); + }; + this.getNewLineMode = function() { + return this.$newLineMode; + }; + this.isNewLine = function(text) { + return (text == "\r\n" || text == "\r" || text == "\n"); + }; + this.getLine = function(row) { + return this.$lines[row] || ""; + }; + this.getLines = function(firstRow, lastRow) { + return this.$lines.slice(firstRow, lastRow + 1); + }; + this.getAllLines = function() { + return this.getLines(0, this.getLength()); + }; + this.getLength = function() { + return this.$lines.length; + }; + this.getTextRange = function(range) { + return this.getLinesForRange(range).join(this.getNewLineCharacter()); + }; + this.getLinesForRange = function(range) { + var lines; + if (range.start.row === range.end.row) { + lines = [this.getLine(range.start.row).substring(range.start.column, range.end.column)]; + } else { + lines = this.getLines(range.start.row, range.end.row); + lines[0] = (lines[0] || "").substring(range.start.column); + var l = lines.length - 1; + if (range.end.row - range.start.row == l) + lines[l] = lines[l].substring(0, range.end.column); + } + return lines; + }; + this.insertLines = function(row, lines) { + console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."); + return this.insertFullLines(row, lines); + }; + this.removeLines = function(firstRow, lastRow) { + console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead."); + return this.removeFullLines(firstRow, lastRow); + }; + this.insertNewLine = function(position) { + console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead."); + return this.insertMergedLines(position, ["", ""]); + }; + this.insert = function(position, text) { + if (this.getLength() <= 1) + this.$detectNewLine(text); + + return this.insertMergedLines(position, this.$split(text)); + }; + this.insertInLine = function(position, text) { + var start = this.clippedPos(position.row, position.column); + var end = this.pos(position.row, position.column + text.length); + + this.applyDelta({ + start: start, + end: end, + action: "insert", + lines: [text] + }, true); + + return this.clonePos(end); + }; + + this.clippedPos = function(row, column) { + var length = this.getLength(); + if (row === undefined) { + row = length; + } else if (row < 0) { + row = 0; + } else if (row >= length) { + row = length - 1; + column = undefined; + } + var line = this.getLine(row); + if (column == undefined) + column = line.length; + column = Math.min(Math.max(column, 0), line.length); + return {row: row, column: column}; + }; + + this.clonePos = function(pos) { + return {row: pos.row, column: pos.column}; + }; + + this.pos = function(row, column) { + return {row: row, column: column}; + }; + + this.$clipPosition = function(position) { + var length = this.getLength(); + if (position.row >= length) { + position.row = Math.max(0, length - 1); + position.column = this.getLine(length - 1).length; + } else { + position.row = Math.max(0, position.row); + position.column = Math.min(Math.max(position.column, 0), this.getLine(position.row).length); + } + return position; + }; + this.insertFullLines = function(row, lines) { + row = Math.min(Math.max(row, 0), this.getLength()); + var column = 0; + if (row < this.getLength()) { + lines = lines.concat([""]); + column = 0; + } else { + lines = [""].concat(lines); + row--; + column = this.$lines[row].length; + } + this.insertMergedLines({row: row, column: column}, lines); + }; + this.insertMergedLines = function(position, lines) { + var start = this.clippedPos(position.row, position.column); + var end = { + row: start.row + lines.length - 1, + column: (lines.length == 1 ? start.column : 0) + lines[lines.length - 1].length + }; + + this.applyDelta({ + start: start, + end: end, + action: "insert", + lines: lines + }); + + return this.clonePos(end); + }; + this.remove = function(range) { + var start = this.clippedPos(range.start.row, range.start.column); + var end = this.clippedPos(range.end.row, range.end.column); + this.applyDelta({ + start: start, + end: end, + action: "remove", + lines: this.getLinesForRange({start: start, end: end}) + }); + return this.clonePos(start); + }; + this.removeInLine = function(row, startColumn, endColumn) { + var start = this.clippedPos(row, startColumn); + var end = this.clippedPos(row, endColumn); + + this.applyDelta({ + start: start, + end: end, + action: "remove", + lines: this.getLinesForRange({start: start, end: end}) + }, true); + + return this.clonePos(start); + }; + this.removeFullLines = function(firstRow, lastRow) { + firstRow = Math.min(Math.max(0, firstRow), this.getLength() - 1); + lastRow = Math.min(Math.max(0, lastRow ), this.getLength() - 1); + var deleteFirstNewLine = lastRow == this.getLength() - 1 && firstRow > 0; + var deleteLastNewLine = lastRow < this.getLength() - 1; + var startRow = ( deleteFirstNewLine ? firstRow - 1 : firstRow ); + var startCol = ( deleteFirstNewLine ? this.getLine(startRow).length : 0 ); + var endRow = ( deleteLastNewLine ? lastRow + 1 : lastRow ); + var endCol = ( deleteLastNewLine ? 0 : this.getLine(endRow).length ); + var range = new Range(startRow, startCol, endRow, endCol); + var deletedLines = this.$lines.slice(firstRow, lastRow + 1); + + this.applyDelta({ + start: range.start, + end: range.end, + action: "remove", + lines: this.getLinesForRange(range) + }); + return deletedLines; + }; + this.removeNewLine = function(row) { + if (row < this.getLength() - 1 && row >= 0) { + this.applyDelta({ + start: this.pos(row, this.getLine(row).length), + end: this.pos(row + 1, 0), + action: "remove", + lines: ["", ""] + }); + } + }; + this.replace = function(range, text) { + if (!(range instanceof Range)) + range = Range.fromPoints(range.start, range.end); + if (text.length === 0 && range.isEmpty()) + return range.start; + if (text == this.getTextRange(range)) + return range.end; + + this.remove(range); + var end; + if (text) { + end = this.insert(range.start, text); + } + else { + end = range.start; + } + + return end; + }; + this.applyDeltas = function(deltas) { + for (var i=0; i=0; i--) { + this.revertDelta(deltas[i]); + } + }; + this.applyDelta = function(delta, doNotValidate) { + var isInsert = delta.action == "insert"; + if (isInsert ? delta.lines.length <= 1 && !delta.lines[0] + : !Range.comparePoints(delta.start, delta.end)) { + return; + } + + if (isInsert && delta.lines.length > 20000) { + this.$splitAndapplyLargeDelta(delta, 20000); + } + else { + applyDelta(this.$lines, delta, doNotValidate); + this._signal("change", delta); + } + }; + + this.$splitAndapplyLargeDelta = function(delta, MAX) { + var lines = delta.lines; + var l = lines.length - MAX + 1; + var row = delta.start.row; + var column = delta.start.column; + for (var from = 0, to = 0; from < l; from = to) { + to += MAX - 1; + var chunk = lines.slice(from, to); + chunk.push(""); + this.applyDelta({ + start: this.pos(row + from, column), + end: this.pos(row + to, column = 0), + action: delta.action, + lines: chunk + }, true); + } + delta.lines = lines.slice(from); + delta.start.row = row + from; + delta.start.column = column; + this.applyDelta(delta, true); + }; + this.revertDelta = function(delta) { + this.applyDelta({ + start: this.clonePos(delta.start), + end: this.clonePos(delta.end), + action: (delta.action == "insert" ? "remove" : "insert"), + lines: delta.lines.slice() + }); + }; + this.indexToPosition = function(index, startRow) { + var lines = this.$lines || this.getAllLines(); + var newlineLength = this.getNewLineCharacter().length; + for (var i = startRow || 0, l = lines.length; i < l; i++) { + index -= lines[i].length + newlineLength; + if (index < 0) + return {row: i, column: index + lines[i].length + newlineLength}; + } + return {row: l-1, column: index + lines[l-1].length + newlineLength}; + }; + this.positionToIndex = function(pos, startRow) { + var lines = this.$lines || this.getAllLines(); + var newlineLength = this.getNewLineCharacter().length; + var index = 0; + var row = Math.min(pos.row, lines.length); + for (var i = startRow || 0; i < row; ++i) + index += lines[i].length + newlineLength; + + return index + pos.column; + }; + +}).call(Document.prototype); + +exports.Document = Document; +}); + +define("ace/background_tokenizer",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"], function(require, exports, module) { +"use strict"; + +var oop = require("./lib/oop"); +var EventEmitter = require("./lib/event_emitter").EventEmitter; + +var BackgroundTokenizer = function(tokenizer, editor) { + this.running = false; + this.lines = []; + this.states = []; + this.currentLine = 0; + this.tokenizer = tokenizer; + + var self = this; + + this.$worker = function() { + if (!self.running) { return; } + + var workerStart = new Date(); + var currentLine = self.currentLine; + var endLine = -1; + var doc = self.doc; + + var startLine = currentLine; + while (self.lines[currentLine]) + currentLine++; + + var len = doc.getLength(); + var processedLines = 0; + self.running = false; + while (currentLine < len) { + self.$tokenizeRow(currentLine); + endLine = currentLine; + do { + currentLine++; + } while (self.lines[currentLine]); + processedLines ++; + if ((processedLines % 5 === 0) && (new Date() - workerStart) > 20) { + self.running = setTimeout(self.$worker, 20); + break; + } + } + self.currentLine = currentLine; + + if (endLine == -1) + endLine = currentLine; + + if (startLine <= endLine) + self.fireUpdateEvent(startLine, endLine); + }; +}; + +(function(){ + + oop.implement(this, EventEmitter); + this.setTokenizer = function(tokenizer) { + this.tokenizer = tokenizer; + this.lines = []; + this.states = []; + + this.start(0); + }; + this.setDocument = function(doc) { + this.doc = doc; + this.lines = []; + this.states = []; + + this.stop(); + }; + this.fireUpdateEvent = function(firstRow, lastRow) { + var data = { + first: firstRow, + last: lastRow + }; + this._signal("update", {data: data}); + }; + this.start = function(startRow) { + this.currentLine = Math.min(startRow || 0, this.currentLine, this.doc.getLength()); + this.lines.splice(this.currentLine, this.lines.length); + this.states.splice(this.currentLine, this.states.length); + + this.stop(); + this.running = setTimeout(this.$worker, 700); + }; + + this.scheduleStart = function() { + if (!this.running) + this.running = setTimeout(this.$worker, 700); + }; + + this.$updateOnChange = function(delta) { + var startRow = delta.start.row; + var len = delta.end.row - startRow; + + if (len === 0) { + this.lines[startRow] = null; + } else if (delta.action == "remove") { + this.lines.splice(startRow, len + 1, null); + this.states.splice(startRow, len + 1, null); + } else { + var args = Array(len + 1); + args.unshift(startRow, 1); + this.lines.splice.apply(this.lines, args); + this.states.splice.apply(this.states, args); + } + + this.currentLine = Math.min(startRow, this.currentLine, this.doc.getLength()); + + this.stop(); + }; + this.stop = function() { + if (this.running) + clearTimeout(this.running); + this.running = false; + }; + this.getTokens = function(row) { + return this.lines[row] || this.$tokenizeRow(row); + }; + this.getState = function(row) { + if (this.currentLine == row) + this.$tokenizeRow(row); + return this.states[row] || "start"; + }; + + this.$tokenizeRow = function(row) { + var line = this.doc.getLine(row); + var state = this.states[row - 1]; + + var data = this.tokenizer.getLineTokens(line, state, row); + + if (this.states[row] + "" !== data.state + "") { + this.states[row] = data.state; + this.lines[row + 1] = null; + if (this.currentLine > row + 1) + this.currentLine = row + 1; + } else if (this.currentLine == row) { + this.currentLine = row + 1; + } + + return this.lines[row] = data.tokens; + }; + +}).call(BackgroundTokenizer.prototype); + +exports.BackgroundTokenizer = BackgroundTokenizer; +}); + +define("ace/search_highlight",["require","exports","module","ace/lib/lang","ace/lib/oop","ace/range"], function(require, exports, module) { +"use strict"; + +var lang = require("./lib/lang"); +var oop = require("./lib/oop"); +var Range = require("./range").Range; + +var SearchHighlight = function(regExp, clazz, type) { + this.setRegexp(regExp); + this.clazz = clazz; + this.type = type || "text"; +}; + +(function() { + this.MAX_RANGES = 500; + + this.setRegexp = function(regExp) { + if (this.regExp+"" == regExp+"") + return; + this.regExp = regExp; + this.cache = []; + }; + + this.update = function(html, markerLayer, session, config) { + if (!this.regExp) + return; + var start = config.firstRow, end = config.lastRow; + + for (var i = start; i <= end; i++) { + var ranges = this.cache[i]; + if (ranges == null) { + ranges = lang.getMatchOffsets(session.getLine(i), this.regExp); + if (ranges.length > this.MAX_RANGES) + ranges = ranges.slice(0, this.MAX_RANGES); + ranges = ranges.map(function(match) { + return new Range(i, match.offset, i, match.offset + match.length); + }); + this.cache[i] = ranges.length ? ranges : ""; + } + + for (var j = ranges.length; j --; ) { + markerLayer.drawSingleLineMarker( + html, ranges[j].toScreenRange(session), this.clazz, config); + } + } + }; + +}).call(SearchHighlight.prototype); + +exports.SearchHighlight = SearchHighlight; +}); + +define("ace/edit_session/fold_line",["require","exports","module","ace/range"], function(require, exports, module) { +"use strict"; + +var Range = require("../range").Range; +function FoldLine(foldData, folds) { + this.foldData = foldData; + if (Array.isArray(folds)) { + this.folds = folds; + } else { + folds = this.folds = [ folds ]; + } + + var last = folds[folds.length - 1]; + this.range = new Range(folds[0].start.row, folds[0].start.column, + last.end.row, last.end.column); + this.start = this.range.start; + this.end = this.range.end; + + this.folds.forEach(function(fold) { + fold.setFoldLine(this); + }, this); +} + +(function() { + this.shiftRow = function(shift) { + this.start.row += shift; + this.end.row += shift; + this.folds.forEach(function(fold) { + fold.start.row += shift; + fold.end.row += shift; + }); + }; + + this.addFold = function(fold) { + if (fold.sameRow) { + if (fold.start.row < this.startRow || fold.endRow > this.endRow) { + throw new Error("Can't add a fold to this FoldLine as it has no connection"); + } + this.folds.push(fold); + this.folds.sort(function(a, b) { + return -a.range.compareEnd(b.start.row, b.start.column); + }); + if (this.range.compareEnd(fold.start.row, fold.start.column) > 0) { + this.end.row = fold.end.row; + this.end.column = fold.end.column; + } else if (this.range.compareStart(fold.end.row, fold.end.column) < 0) { + this.start.row = fold.start.row; + this.start.column = fold.start.column; + } + } else if (fold.start.row == this.end.row) { + this.folds.push(fold); + this.end.row = fold.end.row; + this.end.column = fold.end.column; + } else if (fold.end.row == this.start.row) { + this.folds.unshift(fold); + this.start.row = fold.start.row; + this.start.column = fold.start.column; + } else { + throw new Error("Trying to add fold to FoldRow that doesn't have a matching row"); + } + fold.foldLine = this; + }; + + this.containsRow = function(row) { + return row >= this.start.row && row <= this.end.row; + }; + + this.walk = function(callback, endRow, endColumn) { + var lastEnd = 0, + folds = this.folds, + fold, + cmp, stop, isNewRow = true; + + if (endRow == null) { + endRow = this.end.row; + endColumn = this.end.column; + } + + for (var i = 0; i < folds.length; i++) { + fold = folds[i]; + + cmp = fold.range.compareStart(endRow, endColumn); + if (cmp == -1) { + callback(null, endRow, endColumn, lastEnd, isNewRow); + return; + } + + stop = callback(null, fold.start.row, fold.start.column, lastEnd, isNewRow); + stop = !stop && callback(fold.placeholder, fold.start.row, fold.start.column, lastEnd); + if (stop || cmp === 0) { + return; + } + isNewRow = !fold.sameRow; + lastEnd = fold.end.column; + } + callback(null, endRow, endColumn, lastEnd, isNewRow); + }; + + this.getNextFoldTo = function(row, column) { + var fold, cmp; + for (var i = 0; i < this.folds.length; i++) { + fold = this.folds[i]; + cmp = fold.range.compareEnd(row, column); + if (cmp == -1) { + return { + fold: fold, + kind: "after" + }; + } else if (cmp === 0) { + return { + fold: fold, + kind: "inside" + }; + } + } + return null; + }; + + this.addRemoveChars = function(row, column, len) { + var ret = this.getNextFoldTo(row, column), + fold, folds; + if (ret) { + fold = ret.fold; + if (ret.kind == "inside" + && fold.start.column != column + && fold.start.row != row) + { + window.console && window.console.log(row, column, fold); + } else if (fold.start.row == row) { + folds = this.folds; + var i = folds.indexOf(fold); + if (i === 0) { + this.start.column += len; + } + for (i; i < folds.length; i++) { + fold = folds[i]; + fold.start.column += len; + if (!fold.sameRow) { + return; + } + fold.end.column += len; + } + this.end.column += len; + } + } + }; + + this.split = function(row, column) { + var pos = this.getNextFoldTo(row, column); + + if (!pos || pos.kind == "inside") + return null; + + var fold = pos.fold; + var folds = this.folds; + var foldData = this.foldData; + + var i = folds.indexOf(fold); + var foldBefore = folds[i - 1]; + this.end.row = foldBefore.end.row; + this.end.column = foldBefore.end.column; + folds = folds.splice(i, folds.length - i); + + var newFoldLine = new FoldLine(foldData, folds); + foldData.splice(foldData.indexOf(this) + 1, 0, newFoldLine); + return newFoldLine; + }; + + this.merge = function(foldLineNext) { + var folds = foldLineNext.folds; + for (var i = 0; i < folds.length; i++) { + this.addFold(folds[i]); + } + var foldData = this.foldData; + foldData.splice(foldData.indexOf(foldLineNext), 1); + }; + + this.toString = function() { + var ret = [this.range.toString() + ": [" ]; + + this.folds.forEach(function(fold) { + ret.push(" " + fold.toString()); + }); + ret.push("]"); + return ret.join("\n"); + }; + + this.idxToPosition = function(idx) { + var lastFoldEndColumn = 0; + + for (var i = 0; i < this.folds.length; i++) { + var fold = this.folds[i]; + + idx -= fold.start.column - lastFoldEndColumn; + if (idx < 0) { + return { + row: fold.start.row, + column: fold.start.column + idx + }; + } + + idx -= fold.placeholder.length; + if (idx < 0) { + return fold.start; + } + + lastFoldEndColumn = fold.end.column; + } + + return { + row: this.end.row, + column: this.end.column + idx + }; + }; +}).call(FoldLine.prototype); + +exports.FoldLine = FoldLine; +}); + +define("ace/range_list",["require","exports","module","ace/range"], function(require, exports, module) { +"use strict"; +var Range = require("./range").Range; +var comparePoints = Range.comparePoints; + +var RangeList = function() { + this.ranges = []; + this.$bias = 1; +}; + +(function() { + this.comparePoints = comparePoints; + + this.pointIndex = function(pos, excludeEdges, startIndex) { + var list = this.ranges; + + for (var i = startIndex || 0; i < list.length; i++) { + var range = list[i]; + var cmpEnd = comparePoints(pos, range.end); + if (cmpEnd > 0) + continue; + var cmpStart = comparePoints(pos, range.start); + if (cmpEnd === 0) + return excludeEdges && cmpStart !== 0 ? -i-2 : i; + if (cmpStart > 0 || (cmpStart === 0 && !excludeEdges)) + return i; + + return -i-1; + } + return -i - 1; + }; + + this.add = function(range) { + var excludeEdges = !range.isEmpty(); + var startIndex = this.pointIndex(range.start, excludeEdges); + if (startIndex < 0) + startIndex = -startIndex - 1; + + var endIndex = this.pointIndex(range.end, excludeEdges, 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.apply(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); + }; + this.merge = function() { + var removed = []; + var list = this.ranges; + + list = list.sort(function(a, b) { + return comparePoints(a.start, b.start); + }); + + var next = list[0], range; + for (var i = 1; i < list.length; i++) { + range = next; + next = list[i]; + var cmp = comparePoints(range.end, next.start); + if (cmp < 0) + continue; + + if (cmp == 0 && !range.isEmpty() && !next.isEmpty()) + continue; + + if (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--; + } + + this.ranges = list; + + 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(delta) { + var start = delta.start; + var end = delta.end; + var startRow = start.row; + var endRow = end.row; + var ranges = this.ranges; + for (var i = 0, n = ranges.length; i < n; i++) { + var r = ranges[i]; + if (r.end.row >= startRow) + break; + } + + if (delta.action == "insert") { + var lineDif = endRow - startRow; + var colDiff = -start.column + end.column; + for (; i < n; i++) { + var r = ranges[i]; + if (r.start.row > startRow) + break; + + if (r.start.row == startRow && r.start.column >= start.column) { + if (r.start.column == start.column && this.$bias <= 0) { + } else { + r.start.column += colDiff; + r.start.row += lineDif; + } + } + if (r.end.row == startRow && r.end.column >= start.column) { + if (r.end.column == start.column && this.$bias < 0) { + continue; + } + if (r.end.column == start.column && colDiff > 0 && i < n - 1) { + if (r.end.column > r.start.column && r.end.column == ranges[i+1].start.column) + r.end.column -= colDiff; + } + r.end.column += colDiff; + r.end.row += lineDif; + } + } + } else { + var lineDif = startRow - endRow; + var colDiff = start.column - end.column; + for (; i < n; i++) { + var r = ranges[i]; + + if (r.start.row > endRow) + break; + + if (r.end.row < endRow + && ( + startRow < r.end.row + || startRow == r.end.row && start.column < r.end.column + ) + ) { + r.end.row = startRow; + r.end.column = start.column; + } + else if (r.end.row == endRow) { + if (r.end.column <= end.column) { + if (lineDif || r.end.column > start.column) { + r.end.column = start.column; + r.end.row = start.row; + } + } + else { + r.end.column += colDiff; + r.end.row += lineDif; + } + } + else if (r.end.row > endRow) { + r.end.row += lineDif; + } + + if (r.start.row < endRow + && ( + startRow < r.start.row + || startRow == r.start.row && start.column < r.start.column + ) + ) { + r.start.row = startRow; + r.start.column = start.column; + } + else if (r.start.row == endRow) { + if (r.start.column <= end.column) { + if (lineDif || r.start.column > start.column) { + r.start.column = start.column; + r.start.row = start.row; + } + } + else { + r.start.column += colDiff; + r.start.row += lineDif; + } + } + else if (r.start.row > endRow) { + r.start.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; +}); + +define("ace/edit_session/fold",["require","exports","module","ace/range_list","ace/lib/oop"], function(require, exports, module) { +"use strict"; + +var RangeList = require("../range_list").RangeList; +var oop = require("../lib/oop"); +var Fold = exports.Fold = function(range, placeholder) { + this.foldLine = null; + this.placeholder = placeholder; + this.range = range; + this.start = range.start; + this.end = range.end; + + this.sameRow = range.start.row == range.end.row; + this.subFolds = this.ranges = []; +}; + +oop.inherits(Fold, RangeList); + +(function() { + + this.toString = function() { + return '"' + this.placeholder + '" ' + this.range.toString(); + }; + + this.setFoldLine = function(foldLine) { + this.foldLine = foldLine; + this.subFolds.forEach(function(fold) { + fold.setFoldLine(foldLine); + }); + }; + + this.clone = function() { + var range = this.range.clone(); + var fold = new Fold(range, this.placeholder); + this.subFolds.forEach(function(subFold) { + fold.subFolds.push(subFold.clone()); + }); + fold.collapseChildren = this.collapseChildren; + return fold; + }; + + this.addSubFold = function(fold) { + if (this.range.isEqual(fold)) + return; + consumeRange(fold, this.start); + + var row = fold.start.row, column = fold.start.column; + for (var i = 0, cmp = -1; i < this.subFolds.length; i++) { + cmp = this.subFolds[i].range.compare(row, column); + if (cmp != 1) + break; + } + var afterStart = this.subFolds[i]; + var firstConsumed = 0; + + if (cmp == 0) { + if (afterStart.range.containsRange(fold)) + return afterStart.addSubFold(fold); + else + firstConsumed = 1; + } + var row = fold.range.end.row, column = fold.range.end.column; + for (var j = i, cmp = -1; j < this.subFolds.length; j++) { + cmp = this.subFolds[j].range.compare(row, column); + if (cmp != 1) + break; + } + if (cmp == 0) j++; + var consumedFolds = this.subFolds.splice(i, j - i, fold); + var last = cmp == 0 ? consumedFolds.length - 1 : consumedFolds.length; + for (var k = firstConsumed; k < last; k++) { + fold.addSubFold(consumedFolds[k]); + } + fold.setFoldLine(this.foldLine); + + return fold; + }; + + this.restoreRange = function(range) { + return restoreRange(range, this.start); + }; + +}).call(Fold.prototype); + +function consumePoint(point, anchor) { + point.row -= anchor.row; + if (point.row == 0) + point.column -= anchor.column; +} +function consumeRange(range, anchor) { + consumePoint(range.start, anchor); + consumePoint(range.end, anchor); +} +function restorePoint(point, anchor) { + if (point.row == 0) + point.column += anchor.column; + point.row += anchor.row; +} +function restoreRange(range, anchor) { + restorePoint(range.start, anchor); + restorePoint(range.end, anchor); +} + +}); + +define("ace/edit_session/folding",["require","exports","module","ace/range","ace/edit_session/fold_line","ace/edit_session/fold","ace/token_iterator"], function(require, exports, module) { +"use strict"; + +var Range = require("../range").Range; +var FoldLine = require("./fold_line").FoldLine; +var Fold = require("./fold").Fold; +var TokenIterator = require("../token_iterator").TokenIterator; + +function Folding() { + this.getFoldAt = function(row, column, side) { + var foldLine = this.getFoldLine(row); + if (!foldLine) + return null; + + var folds = foldLine.folds; + for (var i = 0; i < folds.length; i++) { + var range = folds[i].range; + if (range.contains(row, column)) { + if (side == 1 && range.isEnd(row, column) && !range.isEmpty()) { + continue; + } else if (side == -1 && range.isStart(row, column) && !range.isEmpty()) { + continue; + } + return folds[i]; + } + } + }; + this.getFoldsInRange = function(range) { + var start = range.start; + var end = range.end; + var foldLines = this.$foldData; + var foundFolds = []; + + start.column += 1; + end.column -= 1; + + for (var i = 0; i < foldLines.length; i++) { + var cmp = foldLines[i].range.compareRange(range); + if (cmp == 2) { + continue; + } + else if (cmp == -2) { + break; + } + + var folds = foldLines[i].folds; + for (var j = 0; j < folds.length; j++) { + var fold = folds[j]; + cmp = fold.range.compareRange(range); + if (cmp == -2) { + break; + } else if (cmp == 2) { + continue; + } else + if (cmp == 42) { + break; + } + foundFolds.push(fold); + } + } + start.column -= 1; + end.column += 1; + + return foundFolds; + }; + + this.getFoldsInRangeList = function(ranges) { + if (Array.isArray(ranges)) { + var folds = []; + ranges.forEach(function(range) { + folds = folds.concat(this.getFoldsInRange(range)); + }, this); + } else { + var folds = this.getFoldsInRange(ranges); + } + return folds; + }; + this.getAllFolds = function() { + var folds = []; + var foldLines = this.$foldData; + + for (var i = 0; i < foldLines.length; i++) + for (var j = 0; j < foldLines[i].folds.length; j++) + folds.push(foldLines[i].folds[j]); + + return folds; + }; + this.getFoldStringAt = function(row, column, trim, foldLine) { + foldLine = foldLine || this.getFoldLine(row); + if (!foldLine) + return null; + + var lastFold = { + end: { column: 0 } + }; + var str, fold; + for (var i = 0; i < foldLine.folds.length; i++) { + fold = foldLine.folds[i]; + var cmp = fold.range.compareEnd(row, column); + if (cmp == -1) { + str = this + .getLine(fold.start.row) + .substring(lastFold.end.column, fold.start.column); + break; + } + else if (cmp === 0) { + return null; + } + lastFold = fold; + } + if (!str) + str = this.getLine(fold.start.row).substring(lastFold.end.column); + + if (trim == -1) + return str.substring(0, column - lastFold.end.column); + else if (trim == 1) + return str.substring(column - lastFold.end.column); + else + return str; + }; + + this.getFoldLine = function(docRow, startFoldLine) { + var foldData = this.$foldData; + var i = 0; + if (startFoldLine) + i = foldData.indexOf(startFoldLine); + if (i == -1) + i = 0; + for (i; i < foldData.length; i++) { + var foldLine = foldData[i]; + if (foldLine.start.row <= docRow && foldLine.end.row >= docRow) { + return foldLine; + } else if (foldLine.end.row > docRow) { + return null; + } + } + return null; + }; + this.getNextFoldLine = function(docRow, startFoldLine) { + var foldData = this.$foldData; + var i = 0; + if (startFoldLine) + i = foldData.indexOf(startFoldLine); + if (i == -1) + i = 0; + for (i; i < foldData.length; i++) { + var foldLine = foldData[i]; + if (foldLine.end.row >= docRow) { + return foldLine; + } + } + return null; + }; + + this.getFoldedRowCount = function(first, last) { + var foldData = this.$foldData, rowCount = last-first+1; + for (var i = 0; i < foldData.length; i++) { + var foldLine = foldData[i], + end = foldLine.end.row, + start = foldLine.start.row; + if (end >= last) { + if (start < last) { + if (start >= first) + rowCount -= last-start; + else + rowCount = 0; // in one fold + } + break; + } else if (end >= first){ + if (start >= first) // fold inside range + rowCount -= end-start; + else + rowCount -= end-first+1; + } + } + return rowCount; + }; + + this.$addFoldLine = function(foldLine) { + this.$foldData.push(foldLine); + this.$foldData.sort(function(a, b) { + return a.start.row - b.start.row; + }); + return foldLine; + }; + this.addFold = function(placeholder, range) { + var foldData = this.$foldData; + var added = false; + var fold; + + if (placeholder instanceof Fold) + fold = placeholder; + else { + fold = new Fold(range, placeholder); + fold.collapseChildren = range.collapseChildren; + } + this.$clipRangeToDocument(fold.range); + + var startRow = fold.start.row; + var startColumn = fold.start.column; + var endRow = fold.end.row; + var endColumn = fold.end.column; + + var startFold = this.getFoldAt(startRow, startColumn, 1); + var endFold = this.getFoldAt(endRow, endColumn, -1); + if (startFold && endFold == startFold) + return startFold.addSubFold(fold); + + if (startFold && !startFold.range.isStart(startRow, startColumn)) + this.removeFold(startFold); + + if (endFold && !endFold.range.isEnd(endRow, endColumn)) + this.removeFold(endFold); + var folds = this.getFoldsInRange(fold.range); + if (folds.length > 0) { + this.removeFolds(folds); + folds.forEach(function(subFold) { + fold.addSubFold(subFold); + }); + } + + for (var i = 0; i < foldData.length; i++) { + var foldLine = foldData[i]; + if (endRow == foldLine.start.row) { + foldLine.addFold(fold); + added = true; + break; + } else if (startRow == foldLine.end.row) { + foldLine.addFold(fold); + added = true; + if (!fold.sameRow) { + var foldLineNext = foldData[i + 1]; + if (foldLineNext && foldLineNext.start.row == endRow) { + foldLine.merge(foldLineNext); + break; + } + } + break; + } else if (endRow <= foldLine.start.row) { + break; + } + } + + if (!added) + foldLine = this.$addFoldLine(new FoldLine(this.$foldData, fold)); + + if (this.$useWrapMode) + this.$updateWrapData(foldLine.start.row, foldLine.start.row); + else + this.$updateRowLengthCache(foldLine.start.row, foldLine.start.row); + this.$modified = true; + this._signal("changeFold", { data: fold, action: "add" }); + + return fold; + }; + + this.addFolds = function(folds) { + folds.forEach(function(fold) { + this.addFold(fold); + }, this); + }; + + this.removeFold = function(fold) { + var foldLine = fold.foldLine; + var startRow = foldLine.start.row; + var endRow = foldLine.end.row; + + var foldLines = this.$foldData; + var folds = foldLine.folds; + if (folds.length == 1) { + foldLines.splice(foldLines.indexOf(foldLine), 1); + } else + if (foldLine.range.isEnd(fold.end.row, fold.end.column)) { + folds.pop(); + foldLine.end.row = folds[folds.length - 1].end.row; + foldLine.end.column = folds[folds.length - 1].end.column; + } else + if (foldLine.range.isStart(fold.start.row, fold.start.column)) { + folds.shift(); + foldLine.start.row = folds[0].start.row; + foldLine.start.column = folds[0].start.column; + } else + if (fold.sameRow) { + folds.splice(folds.indexOf(fold), 1); + } else + { + var newFoldLine = foldLine.split(fold.start.row, fold.start.column); + folds = newFoldLine.folds; + folds.shift(); + newFoldLine.start.row = folds[0].start.row; + newFoldLine.start.column = folds[0].start.column; + } + + if (!this.$updating) { + if (this.$useWrapMode) + this.$updateWrapData(startRow, endRow); + else + this.$updateRowLengthCache(startRow, endRow); + } + this.$modified = true; + this._signal("changeFold", { data: fold, action: "remove" }); + }; + + this.removeFolds = function(folds) { + var cloneFolds = []; + for (var i = 0; i < folds.length; i++) { + cloneFolds.push(folds[i]); + } + + cloneFolds.forEach(function(fold) { + this.removeFold(fold); + }, this); + this.$modified = true; + }; + + this.expandFold = function(fold) { + this.removeFold(fold); + fold.subFolds.forEach(function(subFold) { + fold.restoreRange(subFold); + this.addFold(subFold); + }, this); + if (fold.collapseChildren > 0) { + this.foldAll(fold.start.row+1, fold.end.row, fold.collapseChildren-1); + } + fold.subFolds = []; + }; + + this.expandFolds = function(folds) { + folds.forEach(function(fold) { + this.expandFold(fold); + }, this); + }; + + this.unfold = function(location, expandInner) { + var range, folds; + if (location == null) { + range = new Range(0, 0, this.getLength(), 0); + expandInner = true; + } else if (typeof location == "number") + range = new Range(location, 0, location, this.getLine(location).length); + else if ("row" in location) + range = Range.fromPoints(location, location); + else + range = location; + + folds = this.getFoldsInRangeList(range); + if (expandInner) { + this.removeFolds(folds); + } else { + var subFolds = folds; + while (subFolds.length) { + this.expandFolds(subFolds); + subFolds = this.getFoldsInRangeList(range); + } + } + if (folds.length) + return folds; + }; + this.isRowFolded = function(docRow, startFoldRow) { + return !!this.getFoldLine(docRow, startFoldRow); + }; + + this.getRowFoldEnd = function(docRow, startFoldRow) { + var foldLine = this.getFoldLine(docRow, startFoldRow); + return foldLine ? foldLine.end.row : docRow; + }; + + this.getRowFoldStart = function(docRow, startFoldRow) { + var foldLine = this.getFoldLine(docRow, startFoldRow); + return foldLine ? foldLine.start.row : docRow; + }; + + this.getFoldDisplayLine = function(foldLine, endRow, endColumn, startRow, startColumn) { + if (startRow == null) + startRow = foldLine.start.row; + if (startColumn == null) + startColumn = 0; + if (endRow == null) + endRow = foldLine.end.row; + if (endColumn == null) + endColumn = this.getLine(endRow).length; + var doc = this.doc; + var textLine = ""; + + foldLine.walk(function(placeholder, row, column, lastColumn) { + if (row < startRow) + return; + if (row == startRow) { + if (column < startColumn) + return; + lastColumn = Math.max(startColumn, lastColumn); + } + + if (placeholder != null) { + textLine += placeholder; + } else { + textLine += doc.getLine(row).substring(lastColumn, column); + } + }, endRow, endColumn); + return textLine; + }; + + this.getDisplayLine = function(row, endColumn, startRow, startColumn) { + var foldLine = this.getFoldLine(row); + + if (!foldLine) { + var line; + line = this.doc.getLine(row); + return line.substring(startColumn || 0, endColumn || line.length); + } else { + return this.getFoldDisplayLine( + foldLine, row, endColumn, startRow, startColumn); + } + }; + + this.$cloneFoldData = function() { + var fd = []; + fd = this.$foldData.map(function(foldLine) { + var folds = foldLine.folds.map(function(fold) { + return fold.clone(); + }); + return new FoldLine(fd, folds); + }); + + return fd; + }; + + this.toggleFold = function(tryToUnfold) { + var selection = this.selection; + var range = selection.getRange(); + var fold; + var bracketPos; + + if (range.isEmpty()) { + var cursor = range.start; + fold = this.getFoldAt(cursor.row, cursor.column); + + if (fold) { + this.expandFold(fold); + return; + } else if (bracketPos = this.findMatchingBracket(cursor)) { + if (range.comparePoint(bracketPos) == 1) { + range.end = bracketPos; + } else { + range.start = bracketPos; + range.start.column++; + range.end.column--; + } + } else if (bracketPos = this.findMatchingBracket({row: cursor.row, column: cursor.column + 1})) { + if (range.comparePoint(bracketPos) == 1) + range.end = bracketPos; + else + range.start = bracketPos; + + range.start.column++; + } else { + range = this.getCommentFoldRange(cursor.row, cursor.column) || range; + } + } else { + var folds = this.getFoldsInRange(range); + if (tryToUnfold && folds.length) { + this.expandFolds(folds); + return; + } else if (folds.length == 1 ) { + fold = folds[0]; + } + } + + if (!fold) + fold = this.getFoldAt(range.start.row, range.start.column); + + if (fold && fold.range.toString() == range.toString()) { + this.expandFold(fold); + return; + } + + var placeholder = "..."; + if (!range.isMultiLine()) { + placeholder = this.getTextRange(range); + if (placeholder.length < 4) + return; + placeholder = placeholder.trim().substring(0, 2) + ".."; + } + + this.addFold(placeholder, range); + }; + + this.getCommentFoldRange = function(row, column, dir) { + var iterator = new TokenIterator(this, row, column); + var token = iterator.getCurrentToken(); + var type = token.type; + if (token && /^comment|string/.test(type)) { + type = type.match(/comment|string/)[0]; + if (type == "comment") + type += "|doc-start"; + var re = new RegExp(type); + var range = new Range(); + if (dir != 1) { + do { + token = iterator.stepBackward(); + } while (token && re.test(token.type)); + iterator.stepForward(); + } + + range.start.row = iterator.getCurrentTokenRow(); + range.start.column = iterator.getCurrentTokenColumn() + 2; + + iterator = new TokenIterator(this, row, column); + + if (dir != -1) { + var lastRow = -1; + do { + token = iterator.stepForward(); + if (lastRow == -1) { + var state = this.getState(iterator.$row); + if (!re.test(state)) + lastRow = iterator.$row; + } else if (iterator.$row > lastRow) { + break; + } + } while (token && re.test(token.type)); + token = iterator.stepBackward(); + } else + token = iterator.getCurrentToken(); + + range.end.row = iterator.getCurrentTokenRow(); + range.end.column = iterator.getCurrentTokenColumn() + token.value.length - 2; + return range; + } + }; + + this.foldAll = function(startRow, endRow, depth) { + if (depth == undefined) + depth = 100000; // JSON.stringify doesn't hanle Infinity + var foldWidgets = this.foldWidgets; + if (!foldWidgets) + return; // mode doesn't support folding + endRow = endRow || this.getLength(); + startRow = startRow || 0; + for (var row = startRow; row < endRow; row++) { + if (foldWidgets[row] == null) + foldWidgets[row] = this.getFoldWidget(row); + if (foldWidgets[row] != "start") + continue; + + var range = this.getFoldWidgetRange(row); + if (range && range.isMultiLine() + && range.end.row <= endRow + && range.start.row >= startRow + ) { + row = range.end.row; + try { + var fold = this.addFold("...", range); + if (fold) + fold.collapseChildren = depth; + } catch(e) {} + } + } + }; + this.$foldStyles = { + "manual": 1, + "markbegin": 1, + "markbeginend": 1 + }; + this.$foldStyle = "markbegin"; + this.setFoldStyle = function(style) { + if (!this.$foldStyles[style]) + throw new Error("invalid fold style: " + style + "[" + Object.keys(this.$foldStyles).join(", ") + "]"); + + if (this.$foldStyle == style) + return; + + this.$foldStyle = style; + + if (style == "manual") + this.unfold(); + var mode = this.$foldMode; + this.$setFolding(null); + this.$setFolding(mode); + }; + + this.$setFolding = function(foldMode) { + if (this.$foldMode == foldMode) + return; + + this.$foldMode = foldMode; + + this.off('change', this.$updateFoldWidgets); + this.off('tokenizerUpdate', this.$tokenizerUpdateFoldWidgets); + this._signal("changeAnnotation"); + + if (!foldMode || this.$foldStyle == "manual") { + this.foldWidgets = null; + return; + } + + this.foldWidgets = []; + this.getFoldWidget = foldMode.getFoldWidget.bind(foldMode, this, this.$foldStyle); + this.getFoldWidgetRange = foldMode.getFoldWidgetRange.bind(foldMode, this, this.$foldStyle); + + this.$updateFoldWidgets = this.updateFoldWidgets.bind(this); + this.$tokenizerUpdateFoldWidgets = this.tokenizerUpdateFoldWidgets.bind(this); + this.on('change', this.$updateFoldWidgets); + this.on('tokenizerUpdate', this.$tokenizerUpdateFoldWidgets); + }; + + this.getParentFoldRangeData = function (row, ignoreCurrent) { + var fw = this.foldWidgets; + if (!fw || (ignoreCurrent && fw[row])) + return {}; + + var i = row - 1, firstRange; + while (i >= 0) { + var c = fw[i]; + if (c == null) + c = fw[i] = this.getFoldWidget(i); + + if (c == "start") { + var range = this.getFoldWidgetRange(i); + if (!firstRange) + firstRange = range; + if (range && range.end.row >= row) + break; + } + i--; + } + + return { + range: i !== -1 && range, + firstRange: firstRange + }; + }; + + this.onFoldWidgetClick = function(row, e) { + e = e.domEvent; + var options = { + children: e.shiftKey, + all: e.ctrlKey || e.metaKey, + siblings: e.altKey + }; + + var range = this.$toggleFoldWidget(row, options); + if (!range) { + var el = (e.target || e.srcElement); + if (el && /ace_fold-widget/.test(el.className)) + el.className += " ace_invalid"; + } + }; + + this.$toggleFoldWidget = function(row, options) { + if (!this.getFoldWidget) + return; + var type = this.getFoldWidget(row); + var line = this.getLine(row); + + var dir = type === "end" ? -1 : 1; + var fold = this.getFoldAt(row, dir === -1 ? 0 : line.length, dir); + + if (fold) { + if (options.children || options.all) + this.removeFold(fold); + else + this.expandFold(fold); + return fold; + } + + var range = this.getFoldWidgetRange(row, true); + if (range && !range.isMultiLine()) { + fold = this.getFoldAt(range.start.row, range.start.column, 1); + if (fold && range.isEqual(fold.range)) { + this.removeFold(fold); + return fold; + } + } + + if (options.siblings) { + var data = this.getParentFoldRangeData(row); + if (data.range) { + var startRow = data.range.start.row + 1; + var endRow = data.range.end.row; + } + this.foldAll(startRow, endRow, options.all ? 10000 : 0); + } else if (options.children) { + endRow = range ? range.end.row : this.getLength(); + this.foldAll(row + 1, endRow, options.all ? 10000 : 0); + } else if (range) { + if (options.all) + range.collapseChildren = 10000; + this.addFold("...", range); + } + + return range; + }; + + + + this.toggleFoldWidget = function(toggleParent) { + var row = this.selection.getCursor().row; + row = this.getRowFoldStart(row); + var range = this.$toggleFoldWidget(row, {}); + + if (range) + return; + var data = this.getParentFoldRangeData(row, true); + range = data.range || data.firstRange; + + if (range) { + row = range.start.row; + var fold = this.getFoldAt(row, this.getLine(row).length, 1); + + if (fold) { + this.removeFold(fold); + } else { + this.addFold("...", range); + } + } + }; + + this.updateFoldWidgets = function(delta) { + var firstRow = delta.start.row; + var len = delta.end.row - firstRow; + + if (len === 0) { + this.foldWidgets[firstRow] = null; + } else if (delta.action == 'remove') { + this.foldWidgets.splice(firstRow, len + 1, null); + } else { + var args = Array(len + 1); + args.unshift(firstRow, 1); + this.foldWidgets.splice.apply(this.foldWidgets, args); + } + }; + this.tokenizerUpdateFoldWidgets = function(e) { + var rows = e.data; + if (rows.first != rows.last) { + if (this.foldWidgets.length > rows.first) + this.foldWidgets.splice(rows.first, this.foldWidgets.length); + } + }; +} + +exports.Folding = Folding; + +}); + +define("ace/edit_session/bracket_match",["require","exports","module","ace/token_iterator","ace/range"], function(require, exports, module) { +"use strict"; + +var TokenIterator = require("../token_iterator").TokenIterator; +var Range = require("../range").Range; + + +function BracketMatch() { + + this.findMatchingBracket = function(position, chr) { + if (position.column == 0) return null; + + var charBeforeCursor = chr || this.getLine(position.row).charAt(position.column-1); + if (charBeforeCursor == "") return null; + + var match = charBeforeCursor.match(/([\(\[\{])|([\)\]\}])/); + if (!match) + return null; + + if (match[1]) + return this.$findClosingBracket(match[1], position); + else + return this.$findOpeningBracket(match[2], position); + }; + + this.getBracketRange = function(pos) { + var line = this.getLine(pos.row); + var before = true, range; + + var chr = line.charAt(pos.column-1); + var match = chr && chr.match(/([\(\[\{])|([\)\]\}])/); + if (!match) { + chr = line.charAt(pos.column); + pos = {row: pos.row, column: pos.column + 1}; + match = chr && chr.match(/([\(\[\{])|([\)\]\}])/); + before = false; + } + if (!match) + return null; + + if (match[1]) { + var bracketPos = this.$findClosingBracket(match[1], pos); + if (!bracketPos) + return null; + range = Range.fromPoints(pos, bracketPos); + if (!before) { + range.end.column++; + range.start.column--; + } + range.cursor = range.end; + } else { + var bracketPos = this.$findOpeningBracket(match[2], pos); + if (!bracketPos) + return null; + range = Range.fromPoints(bracketPos, pos); + if (!before) { + range.start.column++; + range.end.column--; + } + range.cursor = range.start; + } + + return range; + }; + + this.$brackets = { + ")": "(", + "(": ")", + "]": "[", + "[": "]", + "{": "}", + "}": "{", + "<": ">", + ">": "<" + }; + + this.$findOpeningBracket = function(bracket, position, typeRe) { + var openBracket = this.$brackets[bracket]; + var depth = 1; + + var iterator = new TokenIterator(this, position.row, position.column); + var token = iterator.getCurrentToken(); + if (!token) + token = iterator.stepForward(); + if (!token) + return; + + if (!typeRe){ + typeRe = new RegExp( + "(\\.?" + + token.type.replace(".", "\\.").replace("rparen", ".paren") + .replace(/\b(?:end)\b/, "(?:start|begin|end)") + + ")+" + ); + } + var valueIndex = position.column - iterator.getCurrentTokenColumn() - 2; + var value = token.value; + + while (true) { + + while (valueIndex >= 0) { + var chr = value.charAt(valueIndex); + if (chr == openBracket) { + depth -= 1; + if (depth == 0) { + return {row: iterator.getCurrentTokenRow(), + column: valueIndex + iterator.getCurrentTokenColumn()}; + } + } + else if (chr == bracket) { + depth += 1; + } + valueIndex -= 1; + } + do { + token = iterator.stepBackward(); + } while (token && !typeRe.test(token.type)); + + if (token == null) + break; + + value = token.value; + valueIndex = value.length - 1; + } + + return null; + }; + + this.$findClosingBracket = function(bracket, position, typeRe) { + var closingBracket = this.$brackets[bracket]; + var depth = 1; + + var iterator = new TokenIterator(this, position.row, position.column); + var token = iterator.getCurrentToken(); + if (!token) + token = iterator.stepForward(); + if (!token) + return; + + if (!typeRe){ + typeRe = new RegExp( + "(\\.?" + + token.type.replace(".", "\\.").replace("lparen", ".paren") + .replace(/\b(?:start|begin)\b/, "(?:start|begin|end)") + + ")+" + ); + } + var valueIndex = position.column - iterator.getCurrentTokenColumn(); + + while (true) { + + var value = token.value; + var valueLength = value.length; + while (valueIndex < valueLength) { + var chr = value.charAt(valueIndex); + if (chr == closingBracket) { + depth -= 1; + if (depth == 0) { + return {row: iterator.getCurrentTokenRow(), + column: valueIndex + iterator.getCurrentTokenColumn()}; + } + } + else if (chr == bracket) { + depth += 1; + } + valueIndex += 1; + } + do { + token = iterator.stepForward(); + } while (token && !typeRe.test(token.type)); + + if (token == null) + break; + + valueIndex = 0; + } + + return null; + }; +} +exports.BracketMatch = BracketMatch; + +}); + +define("ace/edit_session",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/bidihandler","ace/config","ace/lib/event_emitter","ace/selection","ace/mode/text","ace/range","ace/document","ace/background_tokenizer","ace/search_highlight","ace/edit_session/folding","ace/edit_session/bracket_match"], function(require, exports, module) { +"use strict"; + +var oop = require("./lib/oop"); +var lang = require("./lib/lang"); +var BidiHandler = require("./bidihandler").BidiHandler; +var config = require("./config"); +var EventEmitter = require("./lib/event_emitter").EventEmitter; +var Selection = require("./selection").Selection; +var TextMode = require("./mode/text").Mode; +var Range = require("./range").Range; +var Document = require("./document").Document; +var BackgroundTokenizer = require("./background_tokenizer").BackgroundTokenizer; +var SearchHighlight = require("./search_highlight").SearchHighlight; + +var EditSession = function(text, mode) { + this.$breakpoints = []; + this.$decorations = []; + this.$frontMarkers = {}; + this.$backMarkers = {}; + this.$markerId = 1; + this.$undoSelect = true; + + this.$foldData = []; + this.id = "session" + (++EditSession.$uid); + this.$foldData.toString = function() { + return this.join("\n"); + }; + this.on("changeFold", this.onChangeFold.bind(this)); + this.$onChange = this.onChange.bind(this); + + if (typeof text != "object" || !text.getLine) + text = new Document(text); + + this.setDocument(text); + this.selection = new Selection(this); + this.$bidiHandler = new BidiHandler(this); + + config.resetOptions(this); + this.setMode(mode); + config._signal("session", this); +}; + + +EditSession.$uid = 0; + +(function() { + + oop.implement(this, EventEmitter); + this.setDocument = function(doc) { + if (this.doc) + this.doc.removeListener("change", this.$onChange); + + this.doc = doc; + doc.on("change", this.$onChange); + + if (this.bgTokenizer) + this.bgTokenizer.setDocument(this.getDocument()); + + this.resetCaches(); + }; + this.getDocument = function() { + return this.doc; + }; + this.$resetRowCache = function(docRow) { + if (!docRow) { + this.$docRowCache = []; + this.$screenRowCache = []; + return; + } + var l = this.$docRowCache.length; + var i = this.$getRowCacheIndex(this.$docRowCache, docRow) + 1; + if (l > i) { + this.$docRowCache.splice(i, l); + this.$screenRowCache.splice(i, l); + } + }; + + this.$getRowCacheIndex = function(cacheArray, val) { + var low = 0; + var hi = cacheArray.length - 1; + + while (low <= hi) { + var mid = (low + hi) >> 1; + var c = cacheArray[mid]; + + if (val > c) + low = mid + 1; + else if (val < c) + hi = mid - 1; + else + return mid; + } + + return low -1; + }; + + this.resetCaches = function() { + this.$modified = true; + this.$wrapData = []; + this.$rowLengthCache = []; + this.$resetRowCache(0); + if (this.bgTokenizer) + this.bgTokenizer.start(0); + }; + + this.onChangeFold = function(e) { + var fold = e.data; + this.$resetRowCache(fold.start.row); + }; + + this.onChange = function(delta) { + this.$modified = true; + this.$bidiHandler.onChange(delta); + this.$resetRowCache(delta.start.row); + + var removedFolds = this.$updateInternalDataOnChange(delta); + if (!this.$fromUndo && this.$undoManager) { + if (removedFolds && removedFolds.length) { + this.$undoManager.add({ + action: "removeFolds", + folds: removedFolds + }, this.mergeUndoDeltas); + this.mergeUndoDeltas = true; + } + this.$undoManager.add(delta, this.mergeUndoDeltas); + this.mergeUndoDeltas = true; + + this.$informUndoManager.schedule(); + } + + this.bgTokenizer && this.bgTokenizer.$updateOnChange(delta); + this._signal("change", delta); + }; + this.setValue = function(text) { + this.doc.setValue(text); + this.selection.moveTo(0, 0); + + this.$resetRowCache(0); + this.setUndoManager(this.$undoManager); + this.getUndoManager().reset(); + }; + this.getValue = + this.toString = function() { + return this.doc.getValue(); + }; + this.getSelection = function() { + return this.selection; + }; + this.getState = function(row) { + return this.bgTokenizer.getState(row); + }; + this.getTokens = function(row) { + return this.bgTokenizer.getTokens(row); + }; + this.getTokenAt = function(row, column) { + var tokens = this.bgTokenizer.getTokens(row); + var token, c = 0; + if (column == null) { + var i = tokens.length - 1; + c = this.getLine(row).length; + } else { + for (var i = 0; i < tokens.length; i++) { + c += tokens[i].value.length; + if (c >= column) + break; + } + } + token = tokens[i]; + if (!token) + return null; + token.index = i; + token.start = c - token.value.length; + return token; + }; + this.setUndoManager = function(undoManager) { + this.$undoManager = undoManager; + + if (this.$informUndoManager) + this.$informUndoManager.cancel(); + + if (undoManager) { + var self = this; + undoManager.addSession(this); + this.$syncInformUndoManager = function() { + self.$informUndoManager.cancel(); + self.mergeUndoDeltas = false; + }; + this.$informUndoManager = lang.delayedCall(this.$syncInformUndoManager); + } else { + this.$syncInformUndoManager = function() {}; + } + }; + this.markUndoGroup = function() { + if (this.$syncInformUndoManager) + this.$syncInformUndoManager(); + }; + + this.$defaultUndoManager = { + undo: function() {}, + redo: function() {}, + hasUndo: function() {}, + hasRedo: function() {}, + reset: function() {}, + add: function() {}, + addSelection: function() {}, + startNewGroup: function() {}, + addSession: function() {} + }; + this.getUndoManager = function() { + return this.$undoManager || this.$defaultUndoManager; + }; + this.getTabString = function() { + if (this.getUseSoftTabs()) { + return lang.stringRepeat(" ", this.getTabSize()); + } else { + return "\t"; + } + }; + this.setUseSoftTabs = function(val) { + this.setOption("useSoftTabs", val); + }; + this.getUseSoftTabs = function() { + return this.$useSoftTabs && !this.$mode.$indentWithTabs; + }; + this.setTabSize = function(tabSize) { + this.setOption("tabSize", tabSize); + }; + this.getTabSize = function() { + return this.$tabSize; + }; + this.isTabStop = function(position) { + return this.$useSoftTabs && (position.column % this.$tabSize === 0); + }; + this.setNavigateWithinSoftTabs = function (navigateWithinSoftTabs) { + this.setOption("navigateWithinSoftTabs", navigateWithinSoftTabs); + }; + this.getNavigateWithinSoftTabs = function() { + return this.$navigateWithinSoftTabs; + }; + + this.$overwrite = false; + this.setOverwrite = function(overwrite) { + this.setOption("overwrite", overwrite); + }; + this.getOverwrite = function() { + return this.$overwrite; + }; + this.toggleOverwrite = function() { + this.setOverwrite(!this.$overwrite); + }; + this.addGutterDecoration = function(row, className) { + if (!this.$decorations[row]) + this.$decorations[row] = ""; + this.$decorations[row] += " " + className; + this._signal("changeBreakpoint", {}); + }; + this.removeGutterDecoration = function(row, className) { + this.$decorations[row] = (this.$decorations[row] || "").replace(" " + className, ""); + this._signal("changeBreakpoint", {}); + }; + this.getBreakpoints = function() { + return this.$breakpoints; + }; + this.setBreakpoints = function(rows) { + this.$breakpoints = []; + for (var i=0; i 0) + inToken = !!line.charAt(column - 1).match(this.tokenRe); + + if (!inToken) + inToken = !!line.charAt(column).match(this.tokenRe); + + if (inToken) + var re = this.tokenRe; + else if (/^\s+$/.test(line.slice(column-1, column+1))) + var re = /\s/; + else + var re = this.nonTokenRe; + + var start = column; + if (start > 0) { + do { + start--; + } + while (start >= 0 && line.charAt(start).match(re)); + start++; + } + + var end = column; + while (end < line.length && line.charAt(end).match(re)) { + end++; + } + + return new Range(row, start, row, end); + }; + this.getAWordRange = function(row, column) { + var wordRange = this.getWordRange(row, column); + var line = this.getLine(wordRange.end.row); + + while (line.charAt(wordRange.end.column).match(/[ \t]/)) { + wordRange.end.column += 1; + } + return wordRange; + }; + this.setNewLineMode = function(newLineMode) { + this.doc.setNewLineMode(newLineMode); + }; + this.getNewLineMode = function() { + return this.doc.getNewLineMode(); + }; + this.setUseWorker = function(useWorker) { this.setOption("useWorker", useWorker); }; + this.getUseWorker = function() { return this.$useWorker; }; + this.onReloadTokenizer = function(e) { + var rows = e.data; + this.bgTokenizer.start(rows.first); + this._signal("tokenizerUpdate", e); + }; + + this.$modes = config.$modes; + this.$mode = null; + this.$modeId = null; + this.setMode = function(mode, cb) { + if (mode && typeof mode === "object") { + if (mode.getTokenizer) + return this.$onChangeMode(mode); + var options = mode; + var path = options.path; + } else { + path = mode || "ace/mode/text"; + } + if (!this.$modes["ace/mode/text"]) + this.$modes["ace/mode/text"] = new TextMode(); + + if (this.$modes[path] && !options) { + this.$onChangeMode(this.$modes[path]); + cb && cb(); + return; + } + this.$modeId = path; + config.loadModule(["mode", path], function(m) { + if (this.$modeId !== path) + return cb && cb(); + if (this.$modes[path] && !options) { + this.$onChangeMode(this.$modes[path]); + } else if (m && m.Mode) { + m = new m.Mode(options); + if (!options) { + this.$modes[path] = m; + m.$id = path; + } + this.$onChangeMode(m); + } + cb && cb(); + }.bind(this)); + if (!this.$mode) + this.$onChangeMode(this.$modes["ace/mode/text"], true); + }; + + this.$onChangeMode = function(mode, $isPlaceholder) { + if (!$isPlaceholder) + this.$modeId = mode.$id; + if (this.$mode === mode) + return; + + this.$mode = mode; + + this.$stopWorker(); + + if (this.$useWorker) + this.$startWorker(); + + var tokenizer = mode.getTokenizer(); + + if(tokenizer.addEventListener !== undefined) { + var onReloadTokenizer = this.onReloadTokenizer.bind(this); + tokenizer.addEventListener("update", onReloadTokenizer); + } + + if (!this.bgTokenizer) { + this.bgTokenizer = new BackgroundTokenizer(tokenizer); + var _self = this; + this.bgTokenizer.addEventListener("update", function(e) { + _self._signal("tokenizerUpdate", e); + }); + } else { + this.bgTokenizer.setTokenizer(tokenizer); + } + + this.bgTokenizer.setDocument(this.getDocument()); + + this.tokenRe = mode.tokenRe; + this.nonTokenRe = mode.nonTokenRe; + + + if (!$isPlaceholder) { + if (mode.attachToSession) + mode.attachToSession(this); + this.$options.wrapMethod.set.call(this, this.$wrapMethod); + this.$setFolding(mode.foldingRules); + this.bgTokenizer.start(0); + this._emit("changeMode"); + } + }; + + this.$stopWorker = function() { + if (this.$worker) { + this.$worker.terminate(); + this.$worker = null; + } + }; + + this.$startWorker = function() { + try { + this.$worker = this.$mode.createWorker(this); + } catch (e) { + config.warn("Could not load worker", e); + this.$worker = null; + } + }; + this.getMode = function() { + return this.$mode; + }; + + this.$scrollTop = 0; + this.setScrollTop = function(scrollTop) { + if (this.$scrollTop === scrollTop || isNaN(scrollTop)) + return; + + this.$scrollTop = scrollTop; + this._signal("changeScrollTop", scrollTop); + }; + this.getScrollTop = function() { + return this.$scrollTop; + }; + + this.$scrollLeft = 0; + this.setScrollLeft = function(scrollLeft) { + if (this.$scrollLeft === scrollLeft || isNaN(scrollLeft)) + return; + + this.$scrollLeft = scrollLeft; + this._signal("changeScrollLeft", scrollLeft); + }; + this.getScrollLeft = function() { + return this.$scrollLeft; + }; + this.getScreenWidth = function() { + this.$computeWidth(); + if (this.lineWidgets) + return Math.max(this.getLineWidgetMaxWidth(), this.screenWidth); + return this.screenWidth; + }; + + this.getLineWidgetMaxWidth = function() { + if (this.lineWidgetsWidth != null) return this.lineWidgetsWidth; + var width = 0; + this.lineWidgets.forEach(function(w) { + if (w && w.screenWidth > width) + width = w.screenWidth; + }); + return this.lineWidgetWidth = width; + }; + + this.$computeWidth = function(force) { + if (this.$modified || force) { + this.$modified = false; + + if (this.$useWrapMode) + return this.screenWidth = this.$wrapLimit; + + var lines = this.doc.getAllLines(); + var cache = this.$rowLengthCache; + var longestScreenLine = 0; + var foldIndex = 0; + var foldLine = this.$foldData[foldIndex]; + var foldStart = foldLine ? foldLine.start.row : Infinity; + var len = lines.length; + + for (var i = 0; i < len; i++) { + if (i > foldStart) { + i = foldLine.end.row + 1; + if (i >= len) + break; + foldLine = this.$foldData[foldIndex++]; + foldStart = foldLine ? foldLine.start.row : Infinity; + } + + if (cache[i] == null) + cache[i] = this.$getStringScreenWidth(lines[i])[0]; + + if (cache[i] > longestScreenLine) + longestScreenLine = cache[i]; + } + this.screenWidth = longestScreenLine; + } + }; + this.getLine = function(row) { + return this.doc.getLine(row); + }; + this.getLines = function(firstRow, lastRow) { + return this.doc.getLines(firstRow, lastRow); + }; + this.getLength = function() { + return this.doc.getLength(); + }; + this.getTextRange = function(range) { + return this.doc.getTextRange(range || this.selection.getRange()); + }; + this.insert = function(position, text) { + return this.doc.insert(position, text); + }; + this.remove = function(range) { + return this.doc.remove(range); + }; + this.removeFullLines = function(firstRow, lastRow){ + return this.doc.removeFullLines(firstRow, lastRow); + }; + this.undoChanges = function(deltas, dontSelect) { + if (!deltas.length) + return; + + this.$fromUndo = true; + for (var i = deltas.length - 1; i != -1; i--) { + var delta = deltas[i]; + if (delta.action == "insert" || delta.action == "remove") { + this.doc.revertDelta(delta); + } else if (delta.folds) { + this.addFolds(delta.folds); + } + } + if (!dontSelect && this.$undoSelect) { + if (deltas.selectionBefore) + this.selection.fromJSON(deltas.selectionBefore); + else + this.selection.setRange(this.$getUndoSelection(deltas, true)); + } + this.$fromUndo = false; + }; + this.redoChanges = function(deltas, dontSelect) { + if (!deltas.length) + return; + + this.$fromUndo = true; + for (var i = 0; i < deltas.length; i++) { + var delta = deltas[i]; + if (delta.action == "insert" || delta.action == "remove") { + this.doc.applyDelta(delta); + } + } + + if (!dontSelect && this.$undoSelect) { + if (deltas.selectionAfter) + this.selection.fromJSON(deltas.selectionAfter); + else + this.selection.setRange(this.$getUndoSelection(deltas, false)); + } + this.$fromUndo = false; + }; + this.setUndoSelect = function(enable) { + this.$undoSelect = enable; + }; + + this.$getUndoSelection = function(deltas, isUndo) { + function isInsert(delta) { + return isUndo ? delta.action !== "insert" : delta.action === "insert"; + } + + var range, point; + var lastDeltaIsInsert; + + for (var i = 0; i < deltas.length; i++) { + var delta = deltas[i]; + if (!delta.start) continue; // skip folds + if (!range) { + if (isInsert(delta)) { + range = Range.fromPoints(delta.start, delta.end); + lastDeltaIsInsert = true; + } else { + range = Range.fromPoints(delta.start, delta.start); + lastDeltaIsInsert = false; + } + continue; + } + + if (isInsert(delta)) { + point = delta.start; + if (range.compare(point.row, point.column) == -1) { + range.setStart(point); + } + point = delta.end; + if (range.compare(point.row, point.column) == 1) { + range.setEnd(point); + } + lastDeltaIsInsert = true; + } else { + point = delta.start; + if (range.compare(point.row, point.column) == -1) { + range = Range.fromPoints(delta.start, delta.start); + } + lastDeltaIsInsert = false; + } + } + return range; + }; + this.replace = function(range, text) { + return this.doc.replace(range, text); + }; + this.moveText = function(fromRange, toPosition, copy) { + var text = this.getTextRange(fromRange); + var folds = this.getFoldsInRange(fromRange); + + var toRange = Range.fromPoints(toPosition, toPosition); + if (!copy) { + this.remove(fromRange); + var rowDiff = fromRange.start.row - fromRange.end.row; + var collDiff = rowDiff ? -fromRange.end.column : fromRange.start.column - fromRange.end.column; + if (collDiff) { + if (toRange.start.row == fromRange.end.row && toRange.start.column > fromRange.end.column) + toRange.start.column += collDiff; + if (toRange.end.row == fromRange.end.row && toRange.end.column > fromRange.end.column) + toRange.end.column += collDiff; + } + if (rowDiff && toRange.start.row >= fromRange.end.row) { + toRange.start.row += rowDiff; + toRange.end.row += rowDiff; + } + } + + toRange.end = this.insert(toRange.start, text); + if (folds.length) { + var oldStart = fromRange.start; + var newStart = toRange.start; + var rowDiff = newStart.row - oldStart.row; + var collDiff = newStart.column - oldStart.column; + this.addFolds(folds.map(function(x) { + x = x.clone(); + if (x.start.row == oldStart.row) + x.start.column += collDiff; + if (x.end.row == oldStart.row) + x.end.column += collDiff; + x.start.row += rowDiff; + x.end.row += rowDiff; + return x; + })); + } + + return toRange; + }; + this.indentRows = function(startRow, endRow, indentString) { + indentString = indentString.replace(/\t/g, this.getTabString()); + for (var row=startRow; row<=endRow; row++) + this.doc.insertInLine({row: row, column: 0}, indentString); + }; + this.outdentRows = function (range) { + var rowRange = range.collapseRows(); + var deleteRange = new Range(0, 0, 0, 0); + var size = this.getTabSize(); + + for (var i = rowRange.start.row; i <= rowRange.end.row; ++i) { + var line = this.getLine(i); + + deleteRange.start.row = i; + deleteRange.end.row = i; + for (var j = 0; j < size; ++j) + if (line.charAt(j) != ' ') + break; + if (j < size && line.charAt(j) == '\t') { + deleteRange.start.column = j; + deleteRange.end.column = j + 1; + } else { + deleteRange.start.column = 0; + deleteRange.end.column = j; + } + this.remove(deleteRange); + } + }; + + this.$moveLines = function(firstRow, lastRow, dir) { + firstRow = this.getRowFoldStart(firstRow); + lastRow = this.getRowFoldEnd(lastRow); + if (dir < 0) { + var row = this.getRowFoldStart(firstRow + dir); + if (row < 0) return 0; + var diff = row-firstRow; + } else if (dir > 0) { + var row = this.getRowFoldEnd(lastRow + dir); + if (row > this.doc.getLength()-1) return 0; + var diff = row-lastRow; + } else { + firstRow = this.$clipRowToDocument(firstRow); + lastRow = this.$clipRowToDocument(lastRow); + var diff = lastRow - firstRow + 1; + } + + var range = new Range(firstRow, 0, lastRow, Number.MAX_VALUE); + var folds = this.getFoldsInRange(range).map(function(x){ + x = x.clone(); + x.start.row += diff; + x.end.row += diff; + return x; + }); + + var lines = dir == 0 + ? this.doc.getLines(firstRow, lastRow) + : this.doc.removeFullLines(firstRow, lastRow); + this.doc.insertFullLines(firstRow+diff, lines); + folds.length && this.addFolds(folds); + return diff; + }; + this.moveLinesUp = function(firstRow, lastRow) { + return this.$moveLines(firstRow, lastRow, -1); + }; + this.moveLinesDown = function(firstRow, lastRow) { + return this.$moveLines(firstRow, lastRow, 1); + }; + this.duplicateLines = function(firstRow, lastRow) { + return this.$moveLines(firstRow, lastRow, 0); + }; + + + this.$clipRowToDocument = function(row) { + return Math.max(0, Math.min(row, this.doc.getLength()-1)); + }; + + this.$clipColumnToRow = function(row, column) { + if (column < 0) + return 0; + return Math.min(this.doc.getLine(row).length, column); + }; + + + this.$clipPositionToDocument = function(row, column) { + column = Math.max(0, column); + + if (row < 0) { + row = 0; + column = 0; + } else { + var len = this.doc.getLength(); + if (row >= len) { + row = len - 1; + column = this.doc.getLine(len-1).length; + } else { + column = Math.min(this.doc.getLine(row).length, column); + } + } + + return { + row: row, + column: column + }; + }; + + this.$clipRangeToDocument = function(range) { + if (range.start.row < 0) { + range.start.row = 0; + range.start.column = 0; + } else { + range.start.column = this.$clipColumnToRow( + range.start.row, + range.start.column + ); + } + + var len = this.doc.getLength() - 1; + if (range.end.row > len) { + range.end.row = len; + range.end.column = this.doc.getLine(len).length; + } else { + range.end.column = this.$clipColumnToRow( + range.end.row, + range.end.column + ); + } + return range; + }; + this.$wrapLimit = 80; + this.$useWrapMode = false; + this.$wrapLimitRange = { + min : null, + max : null + }; + this.setUseWrapMode = function(useWrapMode) { + if (useWrapMode != this.$useWrapMode) { + this.$useWrapMode = useWrapMode; + this.$modified = true; + this.$resetRowCache(0); + if (useWrapMode) { + var len = this.getLength(); + this.$wrapData = Array(len); + this.$updateWrapData(0, len - 1); + } + + this._signal("changeWrapMode"); + } + }; + this.getUseWrapMode = function() { + return this.$useWrapMode; + }; + this.setWrapLimitRange = function(min, max) { + if (this.$wrapLimitRange.min !== min || this.$wrapLimitRange.max !== max) { + this.$wrapLimitRange = { min: min, max: max }; + this.$modified = true; + this.$bidiHandler.markAsDirty(); + if (this.$useWrapMode) + this._signal("changeWrapMode"); + } + }; + this.adjustWrapLimit = function(desiredLimit, $printMargin) { + var limits = this.$wrapLimitRange; + if (limits.max < 0) + limits = {min: $printMargin, max: $printMargin}; + var wrapLimit = this.$constrainWrapLimit(desiredLimit, limits.min, limits.max); + if (wrapLimit != this.$wrapLimit && wrapLimit > 1) { + this.$wrapLimit = wrapLimit; + this.$modified = true; + if (this.$useWrapMode) { + this.$updateWrapData(0, this.getLength() - 1); + this.$resetRowCache(0); + this._signal("changeWrapLimit"); + } + return true; + } + return false; + }; + + this.$constrainWrapLimit = function(wrapLimit, min, max) { + if (min) + wrapLimit = Math.max(min, wrapLimit); + + if (max) + wrapLimit = Math.min(max, wrapLimit); + + return wrapLimit; + }; + this.getWrapLimit = function() { + return this.$wrapLimit; + }; + this.setWrapLimit = function (limit) { + this.setWrapLimitRange(limit, limit); + }; + this.getWrapLimitRange = function() { + return { + min : this.$wrapLimitRange.min, + max : this.$wrapLimitRange.max + }; + }; + + this.$updateInternalDataOnChange = function(delta) { + var useWrapMode = this.$useWrapMode; + var action = delta.action; + var start = delta.start; + var end = delta.end; + var firstRow = start.row; + var lastRow = end.row; + var len = lastRow - firstRow; + var removedFolds = null; + + this.$updating = true; + if (len != 0) { + if (action === "remove") { + this[useWrapMode ? "$wrapData" : "$rowLengthCache"].splice(firstRow, len); + + var foldLines = this.$foldData; + removedFolds = this.getFoldsInRange(delta); + this.removeFolds(removedFolds); + + var foldLine = this.getFoldLine(end.row); + var idx = 0; + if (foldLine) { + foldLine.addRemoveChars(end.row, end.column, start.column - end.column); + foldLine.shiftRow(-len); + + var foldLineBefore = this.getFoldLine(firstRow); + if (foldLineBefore && foldLineBefore !== foldLine) { + foldLineBefore.merge(foldLine); + foldLine = foldLineBefore; + } + idx = foldLines.indexOf(foldLine) + 1; + } + + for (idx; idx < foldLines.length; idx++) { + var foldLine = foldLines[idx]; + if (foldLine.start.row >= end.row) { + foldLine.shiftRow(-len); + } + } + + lastRow = firstRow; + } else { + var args = Array(len); + args.unshift(firstRow, 0); + var arr = useWrapMode ? this.$wrapData : this.$rowLengthCache; + arr.splice.apply(arr, args); + var foldLines = this.$foldData; + var foldLine = this.getFoldLine(firstRow); + var idx = 0; + if (foldLine) { + var cmp = foldLine.range.compareInside(start.row, start.column); + if (cmp == 0) { + foldLine = foldLine.split(start.row, start.column); + if (foldLine) { + foldLine.shiftRow(len); + foldLine.addRemoveChars(lastRow, 0, end.column - start.column); + } + } else + if (cmp == -1) { + foldLine.addRemoveChars(firstRow, 0, end.column - start.column); + foldLine.shiftRow(len); + } + idx = foldLines.indexOf(foldLine) + 1; + } + + for (idx; idx < foldLines.length; idx++) { + var foldLine = foldLines[idx]; + if (foldLine.start.row >= firstRow) { + foldLine.shiftRow(len); + } + } + } + } else { + len = Math.abs(delta.start.column - delta.end.column); + if (action === "remove") { + removedFolds = this.getFoldsInRange(delta); + this.removeFolds(removedFolds); + + len = -len; + } + var foldLine = this.getFoldLine(firstRow); + if (foldLine) { + foldLine.addRemoveChars(firstRow, start.column, len); + } + } + + if (useWrapMode && this.$wrapData.length != this.doc.getLength()) { + console.error("doc.getLength() and $wrapData.length have to be the same!"); + } + this.$updating = false; + + if (useWrapMode) + this.$updateWrapData(firstRow, lastRow); + else + this.$updateRowLengthCache(firstRow, lastRow); + + return removedFolds; + }; + + this.$updateRowLengthCache = function(firstRow, lastRow, b) { + this.$rowLengthCache[firstRow] = null; + this.$rowLengthCache[lastRow] = null; + }; + + this.$updateWrapData = function(firstRow, lastRow) { + var lines = this.doc.getAllLines(); + var tabSize = this.getTabSize(); + var wrapData = this.$wrapData; + var wrapLimit = this.$wrapLimit; + var tokens; + var foldLine; + + var row = firstRow; + lastRow = Math.min(lastRow, lines.length - 1); + while (row <= lastRow) { + foldLine = this.getFoldLine(row, foldLine); + if (!foldLine) { + tokens = this.$getDisplayTokens(lines[row]); + wrapData[row] = this.$computeWrapSplits(tokens, wrapLimit, tabSize); + row ++; + } else { + tokens = []; + foldLine.walk(function(placeholder, row, column, lastColumn) { + var walkTokens; + if (placeholder != null) { + walkTokens = this.$getDisplayTokens( + placeholder, tokens.length); + walkTokens[0] = PLACEHOLDER_START; + for (var i = 1; i < walkTokens.length; i++) { + walkTokens[i] = PLACEHOLDER_BODY; + } + } else { + walkTokens = this.$getDisplayTokens( + lines[row].substring(lastColumn, column), + tokens.length); + } + tokens = tokens.concat(walkTokens); + }.bind(this), + foldLine.end.row, + lines[foldLine.end.row].length + 1 + ); + + wrapData[foldLine.start.row] = this.$computeWrapSplits(tokens, wrapLimit, tabSize); + row = foldLine.end.row + 1; + } + } + }; + var CHAR = 1, + CHAR_EXT = 2, + PLACEHOLDER_START = 3, + PLACEHOLDER_BODY = 4, + PUNCTUATION = 9, + SPACE = 10, + TAB = 11, + TAB_SPACE = 12; + + + this.$computeWrapSplits = function(tokens, wrapLimit, tabSize) { + if (tokens.length == 0) { + return []; + } + + var splits = []; + var displayLength = tokens.length; + var lastSplit = 0, lastDocSplit = 0; + + var isCode = this.$wrapAsCode; + + var indentedSoftWrap = this.$indentedSoftWrap; + var maxIndent = wrapLimit <= Math.max(2 * tabSize, 8) + || indentedSoftWrap === false ? 0 : Math.floor(wrapLimit / 2); + + function getWrapIndent() { + var indentation = 0; + if (maxIndent === 0) + return indentation; + if (indentedSoftWrap) { + for (var i = 0; i < tokens.length; i++) { + var token = tokens[i]; + if (token == SPACE) + indentation += 1; + else if (token == TAB) + indentation += tabSize; + else if (token == TAB_SPACE) + continue; + else + break; + } + } + if (isCode && indentedSoftWrap !== false) + indentation += tabSize; + return Math.min(indentation, maxIndent); + } + function addSplit(screenPos) { + var len = screenPos - lastSplit; + for (var i = lastSplit; i < screenPos; i++) { + var ch = tokens[i]; + if (ch === 12 || ch === 2) len -= 1; + } + + if (!splits.length) { + indent = getWrapIndent(); + splits.indent = indent; + } + lastDocSplit += len; + splits.push(lastDocSplit); + lastSplit = screenPos; + } + var indent = 0; + while (displayLength - lastSplit > wrapLimit - indent) { + var split = lastSplit + wrapLimit - indent; + if (tokens[split - 1] >= SPACE && tokens[split] >= SPACE) { + addSplit(split); + continue; + } + if (tokens[split] == PLACEHOLDER_START || tokens[split] == PLACEHOLDER_BODY) { + for (split; split != lastSplit - 1; split--) { + if (tokens[split] == PLACEHOLDER_START) { + break; + } + } + if (split > lastSplit) { + addSplit(split); + continue; + } + split = lastSplit + wrapLimit; + for (split; split < tokens.length; split++) { + if (tokens[split] != PLACEHOLDER_BODY) { + break; + } + } + if (split == tokens.length) { + break; // Breaks the while-loop. + } + addSplit(split); + continue; + } + var minSplit = Math.max(split - (wrapLimit -(wrapLimit>>2)), lastSplit - 1); + while (split > minSplit && tokens[split] < PLACEHOLDER_START) { + split --; + } + if (isCode) { + while (split > minSplit && tokens[split] < PLACEHOLDER_START) { + split --; + } + while (split > minSplit && tokens[split] == PUNCTUATION) { + split --; + } + } else { + while (split > minSplit && tokens[split] < SPACE) { + split --; + } + } + if (split > minSplit) { + addSplit(++split); + continue; + } + split = lastSplit + wrapLimit; + if (tokens[split] == CHAR_EXT) + split--; + addSplit(split - indent); + } + return splits; + }; + this.$getDisplayTokens = function(str, offset) { + var arr = []; + var tabSize; + offset = offset || 0; + + for (var i = 0; i < str.length; i++) { + var c = str.charCodeAt(i); + if (c == 9) { + tabSize = this.getScreenTabSize(arr.length + offset); + arr.push(TAB); + for (var n = 1; n < tabSize; n++) { + arr.push(TAB_SPACE); + } + } + else if (c == 32) { + arr.push(SPACE); + } else if((c > 39 && c < 48) || (c > 57 && c < 64)) { + arr.push(PUNCTUATION); + } + else if (c >= 0x1100 && isFullWidth(c)) { + arr.push(CHAR, CHAR_EXT); + } else { + arr.push(CHAR); + } + } + return arr; + }; + this.$getStringScreenWidth = function(str, maxScreenColumn, screenColumn) { + if (maxScreenColumn == 0) + return [0, 0]; + if (maxScreenColumn == null) + maxScreenColumn = Infinity; + screenColumn = screenColumn || 0; + + var c, column; + for (column = 0; column < str.length; column++) { + c = str.charCodeAt(column); + if (c == 9) { + screenColumn += this.getScreenTabSize(screenColumn); + } + else if (c >= 0x1100 && isFullWidth(c)) { + screenColumn += 2; + } else { + screenColumn += 1; + } + if (screenColumn > maxScreenColumn) { + break; + } + } + + return [screenColumn, column]; + }; + + this.lineWidgets = null; + this.getRowLength = function(row) { + if (this.lineWidgets) + var h = this.lineWidgets[row] && this.lineWidgets[row].rowCount || 0; + else + h = 0; + if (!this.$useWrapMode || !this.$wrapData[row]) { + return 1 + h; + } else { + return this.$wrapData[row].length + 1 + h; + } + }; + this.getRowLineCount = function(row) { + if (!this.$useWrapMode || !this.$wrapData[row]) { + return 1; + } else { + return this.$wrapData[row].length + 1; + } + }; + + this.getRowWrapIndent = function(screenRow) { + if (this.$useWrapMode) { + var pos = this.screenToDocumentPosition(screenRow, Number.MAX_VALUE); + var splits = this.$wrapData[pos.row]; + return splits.length && splits[0] < pos.column ? splits.indent : 0; + } else { + return 0; + } + }; + this.getScreenLastRowColumn = function(screenRow) { + var pos = this.screenToDocumentPosition(screenRow, Number.MAX_VALUE); + return this.documentToScreenColumn(pos.row, pos.column); + }; + this.getDocumentLastRowColumn = function(docRow, docColumn) { + var screenRow = this.documentToScreenRow(docRow, docColumn); + return this.getScreenLastRowColumn(screenRow); + }; + this.getDocumentLastRowColumnPosition = function(docRow, docColumn) { + var screenRow = this.documentToScreenRow(docRow, docColumn); + return this.screenToDocumentPosition(screenRow, Number.MAX_VALUE / 10); + }; + this.getRowSplitData = function(row) { + if (!this.$useWrapMode) { + return undefined; + } else { + return this.$wrapData[row]; + } + }; + this.getScreenTabSize = function(screenColumn) { + return this.$tabSize - (screenColumn % this.$tabSize | 0); + }; + + + this.screenToDocumentRow = function(screenRow, screenColumn) { + return this.screenToDocumentPosition(screenRow, screenColumn).row; + }; + + + this.screenToDocumentColumn = function(screenRow, screenColumn) { + return this.screenToDocumentPosition(screenRow, screenColumn).column; + }; + this.screenToDocumentPosition = function(screenRow, screenColumn, offsetX) { + if (screenRow < 0) + return {row: 0, column: 0}; + + var line; + var docRow = 0; + var docColumn = 0; + var column; + var row = 0; + var rowLength = 0; + + var rowCache = this.$screenRowCache; + var i = this.$getRowCacheIndex(rowCache, screenRow); + var l = rowCache.length; + if (l && i >= 0) { + var row = rowCache[i]; + var docRow = this.$docRowCache[i]; + var doCache = screenRow > rowCache[l - 1]; + } else { + var doCache = !l; + } + + var maxRow = this.getLength() - 1; + var foldLine = this.getNextFoldLine(docRow); + var foldStart = foldLine ? foldLine.start.row : Infinity; + + while (row <= screenRow) { + rowLength = this.getRowLength(docRow); + if (row + rowLength > screenRow || docRow >= maxRow) { + break; + } else { + row += rowLength; + docRow++; + if (docRow > foldStart) { + docRow = foldLine.end.row+1; + foldLine = this.getNextFoldLine(docRow, foldLine); + foldStart = foldLine ? foldLine.start.row : Infinity; + } + } + + if (doCache) { + this.$docRowCache.push(docRow); + this.$screenRowCache.push(row); + } + } + + if (foldLine && foldLine.start.row <= docRow) { + line = this.getFoldDisplayLine(foldLine); + docRow = foldLine.start.row; + } else if (row + rowLength <= screenRow || docRow > maxRow) { + return { + row: maxRow, + column: this.getLine(maxRow).length + }; + } else { + line = this.getLine(docRow); + foldLine = null; + } + var wrapIndent = 0, splitIndex = Math.floor(screenRow - row); + if (this.$useWrapMode) { + var splits = this.$wrapData[docRow]; + if (splits) { + column = splits[splitIndex]; + if(splitIndex > 0 && splits.length) { + wrapIndent = splits.indent; + docColumn = splits[splitIndex - 1] || splits[splits.length - 1]; + line = line.substring(docColumn); + } + } + } + + if (offsetX !== undefined && this.$bidiHandler.isBidiRow(row + splitIndex, docRow, splitIndex)) + screenColumn = this.$bidiHandler.offsetToCol(offsetX); + + docColumn += this.$getStringScreenWidth(line, screenColumn - wrapIndent)[1]; + if (this.$useWrapMode && docColumn >= column) + docColumn = column - 1; + + if (foldLine) + return foldLine.idxToPosition(docColumn); + + return {row: docRow, column: docColumn}; + }; + this.documentToScreenPosition = function(docRow, docColumn) { + if (typeof docColumn === "undefined") + var pos = this.$clipPositionToDocument(docRow.row, docRow.column); + else + pos = this.$clipPositionToDocument(docRow, docColumn); + + docRow = pos.row; + docColumn = pos.column; + + var screenRow = 0; + var foldStartRow = null; + var fold = null; + fold = this.getFoldAt(docRow, docColumn, 1); + if (fold) { + docRow = fold.start.row; + docColumn = fold.start.column; + } + + var rowEnd, row = 0; + + + var rowCache = this.$docRowCache; + var i = this.$getRowCacheIndex(rowCache, docRow); + var l = rowCache.length; + if (l && i >= 0) { + var row = rowCache[i]; + var screenRow = this.$screenRowCache[i]; + var doCache = docRow > rowCache[l - 1]; + } else { + var doCache = !l; + } + + var foldLine = this.getNextFoldLine(row); + var foldStart = foldLine ?foldLine.start.row :Infinity; + + while (row < docRow) { + if (row >= foldStart) { + rowEnd = foldLine.end.row + 1; + if (rowEnd > docRow) + break; + foldLine = this.getNextFoldLine(rowEnd, foldLine); + foldStart = foldLine ?foldLine.start.row :Infinity; + } + else { + rowEnd = row + 1; + } + + screenRow += this.getRowLength(row); + row = rowEnd; + + if (doCache) { + this.$docRowCache.push(row); + this.$screenRowCache.push(screenRow); + } + } + var textLine = ""; + if (foldLine && row >= foldStart) { + textLine = this.getFoldDisplayLine(foldLine, docRow, docColumn); + foldStartRow = foldLine.start.row; + } else { + textLine = this.getLine(docRow).substring(0, docColumn); + foldStartRow = docRow; + } + var wrapIndent = 0; + if (this.$useWrapMode) { + var wrapRow = this.$wrapData[foldStartRow]; + if (wrapRow) { + var screenRowOffset = 0; + while (textLine.length >= wrapRow[screenRowOffset]) { + screenRow ++; + screenRowOffset++; + } + textLine = textLine.substring( + wrapRow[screenRowOffset - 1] || 0, textLine.length + ); + wrapIndent = screenRowOffset > 0 ? wrapRow.indent : 0; + } + } + + return { + row: screenRow, + column: wrapIndent + this.$getStringScreenWidth(textLine)[0] + }; + }; + this.documentToScreenColumn = function(row, docColumn) { + return this.documentToScreenPosition(row, docColumn).column; + }; + this.documentToScreenRow = function(docRow, docColumn) { + return this.documentToScreenPosition(docRow, docColumn).row; + }; + this.getScreenLength = function() { + var screenRows = 0; + var fold = null; + if (!this.$useWrapMode) { + screenRows = this.getLength(); + var foldData = this.$foldData; + for (var i = 0; i < foldData.length; i++) { + fold = foldData[i]; + screenRows -= fold.end.row - fold.start.row; + } + } else { + var lastRow = this.$wrapData.length; + var row = 0, i = 0; + var fold = this.$foldData[i++]; + var foldStart = fold ? fold.start.row :Infinity; + + while (row < lastRow) { + var splits = this.$wrapData[row]; + screenRows += splits ? splits.length + 1 : 1; + row ++; + if (row > foldStart) { + row = fold.end.row+1; + fold = this.$foldData[i++]; + foldStart = fold ?fold.start.row :Infinity; + } + } + } + if (this.lineWidgets) + screenRows += this.$getWidgetScreenLength(); + + return screenRows; + }; + this.$setFontMetrics = function(fm) { + if (!this.$enableVarChar) return; + this.$getStringScreenWidth = function(str, maxScreenColumn, screenColumn) { + if (maxScreenColumn === 0) + return [0, 0]; + if (!maxScreenColumn) + maxScreenColumn = Infinity; + screenColumn = screenColumn || 0; + + var c, column; + for (column = 0; column < str.length; column++) { + c = str.charAt(column); + if (c === "\t") { + screenColumn += this.getScreenTabSize(screenColumn); + } else { + screenColumn += fm.getCharacterWidth(c); + } + if (screenColumn > maxScreenColumn) { + break; + } + } + + return [screenColumn, column]; + }; + }; + + this.destroy = function() { + if (this.bgTokenizer) { + this.bgTokenizer.setDocument(null); + this.bgTokenizer = null; + } + this.$stopWorker(); + }; + + this.isFullWidth = isFullWidth; + function isFullWidth(c) { + if (c < 0x1100) + return false; + return c >= 0x1100 && c <= 0x115F || + c >= 0x11A3 && c <= 0x11A7 || + c >= 0x11FA && c <= 0x11FF || + c >= 0x2329 && c <= 0x232A || + c >= 0x2E80 && c <= 0x2E99 || + c >= 0x2E9B && c <= 0x2EF3 || + c >= 0x2F00 && c <= 0x2FD5 || + c >= 0x2FF0 && c <= 0x2FFB || + c >= 0x3000 && c <= 0x303E || + c >= 0x3041 && c <= 0x3096 || + c >= 0x3099 && c <= 0x30FF || + c >= 0x3105 && c <= 0x312D || + c >= 0x3131 && c <= 0x318E || + c >= 0x3190 && c <= 0x31BA || + c >= 0x31C0 && c <= 0x31E3 || + c >= 0x31F0 && c <= 0x321E || + c >= 0x3220 && c <= 0x3247 || + c >= 0x3250 && c <= 0x32FE || + c >= 0x3300 && c <= 0x4DBF || + c >= 0x4E00 && c <= 0xA48C || + c >= 0xA490 && c <= 0xA4C6 || + c >= 0xA960 && c <= 0xA97C || + c >= 0xAC00 && c <= 0xD7A3 || + c >= 0xD7B0 && c <= 0xD7C6 || + c >= 0xD7CB && c <= 0xD7FB || + c >= 0xF900 && c <= 0xFAFF || + c >= 0xFE10 && c <= 0xFE19 || + c >= 0xFE30 && c <= 0xFE52 || + c >= 0xFE54 && c <= 0xFE66 || + c >= 0xFE68 && c <= 0xFE6B || + c >= 0xFF01 && c <= 0xFF60 || + c >= 0xFFE0 && c <= 0xFFE6; + } + +}).call(EditSession.prototype); + +require("./edit_session/folding").Folding.call(EditSession.prototype); +require("./edit_session/bracket_match").BracketMatch.call(EditSession.prototype); + + +config.defineOptions(EditSession.prototype, "session", { + wrap: { + set: function(value) { + if (!value || value == "off") + value = false; + else if (value == "free") + value = true; + else if (value == "printMargin") + value = -1; + else if (typeof value == "string") + value = parseInt(value, 10) || false; + + if (this.$wrap == value) + return; + this.$wrap = value; + if (!value) { + this.setUseWrapMode(false); + } else { + var col = typeof value == "number" ? value : null; + this.setWrapLimitRange(col, col); + this.setUseWrapMode(true); + } + }, + get: function() { + if (this.getUseWrapMode()) { + if (this.$wrap == -1) + return "printMargin"; + if (!this.getWrapLimitRange().min) + return "free"; + return this.$wrap; + } + return "off"; + }, + handlesSet: true + }, + wrapMethod: { + set: function(val) { + val = val == "auto" + ? this.$mode.type != "text" + : val != "text"; + if (val != this.$wrapAsCode) { + this.$wrapAsCode = val; + if (this.$useWrapMode) { + this.$useWrapMode = false; + this.setUseWrapMode(true); + } + } + }, + initialValue: "auto" + }, + indentedSoftWrap: { + set: function() { + if (this.$useWrapMode) { + this.$useWrapMode = false; + this.setUseWrapMode(true); + } + }, + initialValue: true + }, + firstLineNumber: { + set: function() {this._signal("changeBreakpoint");}, + initialValue: 1 + }, + useWorker: { + set: function(useWorker) { + this.$useWorker = useWorker; + + this.$stopWorker(); + if (useWorker) + this.$startWorker(); + }, + initialValue: true + }, + useSoftTabs: {initialValue: true}, + tabSize: { + set: function(tabSize) { + tabSize = parseInt(tabSize); + if (tabSize > 0 && this.$tabSize !== tabSize) { + this.$modified = true; + this.$rowLengthCache = []; + this.$tabSize = tabSize; + this._signal("changeTabSize"); + } + }, + initialValue: 4, + handlesSet: true + }, + navigateWithinSoftTabs: {initialValue: false}, + foldStyle: { + set: function(val) {this.setFoldStyle(val);}, + handlesSet: true + }, + overwrite: { + set: function(val) {this._signal("changeOverwrite");}, + initialValue: false + }, + newLineMode: { + set: function(val) {this.doc.setNewLineMode(val);}, + get: function() {return this.doc.getNewLineMode();}, + handlesSet: true + }, + mode: { + set: function(val) { this.setMode(val); }, + get: function() { return this.$modeId; }, + handlesSet: true + } +}); + +exports.EditSession = EditSession; +}); + +define("ace/search",["require","exports","module","ace/lib/lang","ace/lib/oop","ace/range"], function(require, exports, module) { +"use strict"; + +var lang = require("./lib/lang"); +var oop = require("./lib/oop"); +var Range = require("./range").Range; + +var Search = function() { + this.$options = {}; +}; + +(function() { + this.set = function(options) { + oop.mixin(this.$options, options); + return this; + }; + this.getOptions = function() { + return lang.copyObject(this.$options); + }; + this.setOptions = function(options) { + this.$options = options; + }; + this.find = function(session) { + var options = this.$options; + var iterator = this.$matchIterator(session, options); + if (!iterator) + return false; + + var firstRange = null; + iterator.forEach(function(sr, sc, er, ec) { + firstRange = new Range(sr, sc, er, ec); + if (sc == ec && options.start && options.start.start + && options.skipCurrent != false && firstRange.isEqual(options.start) + ) { + firstRange = null; + return false; + } + + return true; + }); + + return firstRange; + }; + this.findAll = function(session) { + var options = this.$options; + if (!options.needle) + return []; + this.$assembleRegExp(options); + + var range = options.range; + var lines = range + ? session.getLines(range.start.row, range.end.row) + : session.doc.getAllLines(); + + var ranges = []; + var re = options.re; + if (options.$isMultiLine) { + var len = re.length; + var maxRow = lines.length - len; + var prevRange; + outer: for (var row = re.offset || 0; row <= maxRow; row++) { + for (var j = 0; j < len; j++) + if (lines[row + j].search(re[j]) == -1) + continue outer; + + var startLine = lines[row]; + var line = lines[row + len - 1]; + var startIndex = startLine.length - startLine.match(re[0])[0].length; + var endIndex = line.match(re[len - 1])[0].length; + + if (prevRange && prevRange.end.row === row && + prevRange.end.column > startIndex + ) { + continue; + } + ranges.push(prevRange = new Range( + row, startIndex, row + len - 1, endIndex + )); + if (len > 2) + row = row + len - 2; + } + } else { + for (var i = 0; i < lines.length; i++) { + var matches = lang.getMatchOffsets(lines[i], re); + for (var j = 0; j < matches.length; j++) { + var match = matches[j]; + ranges.push(new Range(i, match.offset, i, match.offset + match.length)); + } + } + } + + if (range) { + var startColumn = range.start.column; + var endColumn = range.start.column; + var i = 0, j = ranges.length - 1; + while (i < j && ranges[i].start.column < startColumn && ranges[i].start.row == range.start.row) + i++; + + while (i < j && ranges[j].end.column > endColumn && ranges[j].end.row == range.end.row) + j--; + + ranges = ranges.slice(i, j + 1); + for (i = 0, j = ranges.length; i < j; i++) { + ranges[i].start.row += range.start.row; + ranges[i].end.row += range.start.row; + } + } + + return ranges; + }; + this.replace = function(input, replacement) { + var options = this.$options; + + var re = this.$assembleRegExp(options); + if (options.$isMultiLine) + return replacement; + + if (!re) + return; + + var match = re.exec(input); + if (!match || match[0].length != input.length) + return null; + + replacement = input.replace(re, replacement); + if (options.preserveCase) { + replacement = replacement.split(""); + for (var i = Math.min(input.length, input.length); i--; ) { + var ch = input[i]; + if (ch && ch.toLowerCase() != ch) + replacement[i] = replacement[i].toUpperCase(); + else + replacement[i] = replacement[i].toLowerCase(); + } + replacement = replacement.join(""); + } + + return replacement; + }; + + this.$assembleRegExp = function(options, $disableFakeMultiline) { + if (options.needle instanceof RegExp) + return options.re = options.needle; + + var needle = options.needle; + + if (!options.needle) + return options.re = false; + + if (!options.regExp) + needle = lang.escapeRegExp(needle); + + if (options.wholeWord) + needle = addWordBoundary(needle, options); + + var modifier = options.caseSensitive ? "gm" : "gmi"; + + options.$isMultiLine = !$disableFakeMultiline && /[\n\r]/.test(needle); + if (options.$isMultiLine) + return options.re = this.$assembleMultilineRegExp(needle, modifier); + + try { + var re = new RegExp(needle, modifier); + } catch(e) { + re = false; + } + return options.re = re; + }; + + this.$assembleMultilineRegExp = function(needle, modifier) { + var parts = needle.replace(/\r\n|\r|\n/g, "$\n^").split("\n"); + var re = []; + for (var i = 0; i < parts.length; i++) try { + re.push(new RegExp(parts[i], modifier)); + } catch(e) { + return false; + } + return re; + }; + + this.$matchIterator = function(session, options) { + var re = this.$assembleRegExp(options); + if (!re) + return false; + var backwards = options.backwards == true; + var skipCurrent = options.skipCurrent != false; + + var range = options.range; + var start = options.start; + if (!start) + start = range ? range[backwards ? "end" : "start"] : session.selection.getRange(); + + if (start.start) + start = start[skipCurrent != backwards ? "end" : "start"]; + + var firstRow = range ? range.start.row : 0; + var lastRow = range ? range.end.row : session.getLength() - 1; + + if (backwards) { + var forEach = function(callback) { + var row = start.row; + if (forEachInLine(row, start.column, callback)) + return; + for (row--; row >= firstRow; row--) + if (forEachInLine(row, Number.MAX_VALUE, callback)) + return; + if (options.wrap == false) + return; + for (row = lastRow, firstRow = start.row; row >= firstRow; row--) + if (forEachInLine(row, Number.MAX_VALUE, callback)) + return; + }; + } + else { + var forEach = function(callback) { + var row = start.row; + if (forEachInLine(row, start.column, callback)) + return; + for (row = row + 1; row <= lastRow; row++) + if (forEachInLine(row, 0, callback)) + return; + if (options.wrap == false) + return; + for (row = firstRow, lastRow = start.row; row <= lastRow; row++) + if (forEachInLine(row, 0, callback)) + return; + }; + } + + if (options.$isMultiLine) { + var len = re.length; + var forEachInLine = function(row, offset, callback) { + var startRow = backwards ? row - len + 1 : row; + if (startRow < 0) return; + var line = session.getLine(startRow); + var startIndex = line.search(re[0]); + if (!backwards && startIndex < offset || startIndex === -1) return; + for (var i = 1; i < len; i++) { + line = session.getLine(startRow + i); + if (line.search(re[i]) == -1) + return; + } + var endIndex = line.match(re[len - 1])[0].length; + if (backwards && endIndex > offset) return; + if (callback(startRow, startIndex, startRow + len - 1, endIndex)) + return true; + }; + } + else if (backwards) { + var forEachInLine = function(row, endIndex, callback) { + var line = session.getLine(row); + var matches = []; + var m, last = 0; + re.lastIndex = 0; + while((m = re.exec(line))) { + var length = m[0].length; + last = m.index; + if (!length) { + if (last >= line.length) break; + re.lastIndex = last += 1; + } + if (m.index + length > endIndex) + break; + matches.push(m.index, length); + } + for (var i = matches.length - 1; i >= 0; i -= 2) { + var column = matches[i - 1]; + var length = matches[i]; + if (callback(row, column, row, column + length)) + return true; + } + }; + } + else { + var forEachInLine = function(row, startIndex, callback) { + var line = session.getLine(row); + var last; + var m; + re.lastIndex = startIndex; + while((m = re.exec(line))) { + var length = m[0].length; + last = m.index; + if (callback(row, last, row,last + length)) + return true; + if (!length) { + re.lastIndex = last += 1; + if (last >= line.length) return false; + } + } + }; + } + return {forEach: forEach}; + }; + +}).call(Search.prototype); + +function addWordBoundary(needle, options) { + function wordBoundary(c) { + if (/\w/.test(c) || options.regExp) return "\\b"; + return ""; + } + return wordBoundary(needle[0]) + needle + + wordBoundary(needle[needle.length - 1]); +} + +exports.Search = Search; +}); + +define("ace/keyboard/hash_handler",["require","exports","module","ace/lib/keys","ace/lib/useragent"], function(require, exports, module) { +"use strict"; + +var keyUtil = require("../lib/keys"); +var useragent = require("../lib/useragent"); +var KEY_MODS = keyUtil.KEY_MODS; + +function HashHandler(config, platform) { + this.platform = platform || (useragent.isMac ? "mac" : "win"); + this.commands = {}; + this.commandKeyBinding = {}; + this.addCommands(config); + this.$singleCommand = true; +} + +function MultiHashHandler(config, platform) { + HashHandler.call(this, config, platform); + this.$singleCommand = false; +} + +MultiHashHandler.prototype = HashHandler.prototype; + +(function() { + + + this.addCommand = function(command) { + if (this.commands[command.name]) + this.removeCommand(command); + + this.commands[command.name] = command; + + if (command.bindKey) + this._buildKeyHash(command); + }; + + this.removeCommand = function(command, keepCommand) { + var name = command && (typeof command === 'string' ? command : command.name); + command = this.commands[name]; + if (!keepCommand) + delete this.commands[name]; + var ckb = this.commandKeyBinding; + for (var keyId in ckb) { + var cmdGroup = ckb[keyId]; + if (cmdGroup == command) { + delete ckb[keyId]; + } else if (Array.isArray(cmdGroup)) { + var i = cmdGroup.indexOf(command); + if (i != -1) { + cmdGroup.splice(i, 1); + if (cmdGroup.length == 1) + ckb[keyId] = cmdGroup[0]; + } + } + } + }; + + this.bindKey = function(key, command, position) { + if (typeof key == "object" && key) { + if (position == undefined) + position = key.position; + key = key[this.platform]; + } + if (!key) + return; + if (typeof command == "function") + return this.addCommand({exec: command, bindKey: key, name: command.name || key}); + + key.split("|").forEach(function(keyPart) { + var chain = ""; + if (keyPart.indexOf(" ") != -1) { + var parts = keyPart.split(/\s+/); + keyPart = parts.pop(); + parts.forEach(function(keyPart) { + var binding = this.parseKeys(keyPart); + var id = KEY_MODS[binding.hashId] + binding.key; + chain += (chain ? " " : "") + id; + this._addCommandToBinding(chain, "chainKeys"); + }, this); + chain += " "; + } + var binding = this.parseKeys(keyPart); + var id = KEY_MODS[binding.hashId] + binding.key; + this._addCommandToBinding(chain + id, command, position); + }, this); + }; + + function getPosition(command) { + return typeof command == "object" && command.bindKey + && command.bindKey.position + || (command.isDefault ? -100 : 0); + } + this._addCommandToBinding = function(keyId, command, position) { + var ckb = this.commandKeyBinding, i; + if (!command) { + delete ckb[keyId]; + } else if (!ckb[keyId] || this.$singleCommand) { + ckb[keyId] = command; + } else { + if (!Array.isArray(ckb[keyId])) { + ckb[keyId] = [ckb[keyId]]; + } else if ((i = ckb[keyId].indexOf(command)) != -1) { + ckb[keyId].splice(i, 1); + } + + if (typeof position != "number") { + position = getPosition(command); + } + + var commands = ckb[keyId]; + for (i = 0; i < commands.length; i++) { + var other = commands[i]; + var otherPos = getPosition(other); + if (otherPos > position) + break; + } + commands.splice(i, 0, command); + } + }; + + this.addCommands = function(commands) { + commands && Object.keys(commands).forEach(function(name) { + var command = commands[name]; + if (!command) + return; + + if (typeof command === "string") + return this.bindKey(command, name); + + if (typeof command === "function") + command = { exec: command }; + + if (typeof command !== "object") + return; + + 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.bindKeys = function(keyList) { + Object.keys(keyList).forEach(function(key) { + this.bindKey(key, keyList[key]); + }, this); + }; + + this._buildKeyHash = function(command) { + this.bindKey(command.bindKey, command); + }; + this.parseKeys = function(keys) { + var parts = keys.toLowerCase().split(/[\-\+]([\-\+])?/).filter(function(x){return x;}); + var key = parts.pop(); + + var keyCode = keyUtil[key]; + if (keyUtil.FUNCTION_KEYS[keyCode]) + key = keyUtil.FUNCTION_KEYS[keyCode].toLowerCase(); + else if (!parts.length) + return {key: key, hashId: -1}; + else if (parts.length == 1 && parts[0] == "shift") + return {key: key.toUpperCase(), hashId: -1}; + + var hashId = 0; + for (var i = parts.length; i--;) { + var modifier = keyUtil.KEY_MODS[parts[i]]; + if (modifier == null) { + if (typeof console != "undefined") + console.error("invalid modifier " + parts[i] + " in " + keys); + return false; + } + hashId |= modifier; + } + return {key: key, hashId: hashId}; + }; + + this.findKeyCommand = function findKeyCommand(hashId, keyString) { + var key = KEY_MODS[hashId] + keyString; + return this.commandKeyBinding[key]; + }; + + this.handleKeyboard = function(data, hashId, keyString, keyCode) { + if (keyCode < 0) return; + var key = KEY_MODS[hashId] + keyString; + var command = this.commandKeyBinding[key]; + if (data.$keyChain) { + data.$keyChain += " " + key; + command = this.commandKeyBinding[data.$keyChain] || command; + } + + if (command) { + if (command == "chainKeys" || command[command.length - 1] == "chainKeys") { + data.$keyChain = data.$keyChain || key; + return {command: "null"}; + } + } + + if (data.$keyChain) { + if ((!hashId || hashId == 4) && keyString.length == 1) + data.$keyChain = data.$keyChain.slice(0, -key.length - 1); // wait for input + else if (hashId == -1 || keyCode > 0) + data.$keyChain = ""; // reset keyChain + } + return {command: command}; + }; + + this.getStatusText = function(editor, data) { + return data.$keyChain || ""; + }; + +}).call(HashHandler.prototype); + +exports.HashHandler = HashHandler; +exports.MultiHashHandler = MultiHashHandler; +}); + +define("ace/commands/command_manager",["require","exports","module","ace/lib/oop","ace/keyboard/hash_handler","ace/lib/event_emitter"], function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var MultiHashHandler = require("../keyboard/hash_handler").MultiHashHandler; +var EventEmitter = require("../lib/event_emitter").EventEmitter; + +var CommandManager = function(platform, commands) { + MultiHashHandler.call(this, commands, platform); + this.byName = this.commands; + this.setDefaultHandler("exec", function(e) { + return e.command.exec(e.editor, e.args || {}); + }); +}; + +oop.inherits(CommandManager, MultiHashHandler); + +(function() { + + oop.implement(this, EventEmitter); + + this.exec = function(command, editor, args) { + if (Array.isArray(command)) { + for (var i = command.length; i--; ) { + if (this.exec(command[i], editor, args)) return true; + } + return false; + } + + if (typeof command === "string") + command = this.commands[command]; + + if (!command) + return false; + + if (editor && editor.$readOnly && !command.readOnly) + return false; + + if (this.$checkCommandState != false && command.isAvailable && !command.isAvailable(editor)) + return false; + + var e = {editor: editor, command: command, args: args}; + e.returnValue = this._emit("exec", e); + this._signal("afterExec", e); + + return e.returnValue === false ? false : true; + }; + + this.toggleRecording = function(editor) { + if (this.$inReplay) + return; + + editor && editor._emit("changeStatus"); + if (this.recording) { + this.macro.pop(); + 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.on("exec", this.$addCommandToMacro); + return this.recording = true; + }; + + this.replay = function(editor) { + if (this.$inReplay || !this.macro) + return; + + if (this.recording) + return this.toggleRecording(editor); + + try { + this.$inReplay = true; + this.macro.forEach(function(x) { + if (typeof x == "string") + this.exec(x, editor); + else + this.exec(x[0], editor, x[1]); + }, this); + } finally { + this.$inReplay = false; + } + }; + + this.trimMacro = function(m) { + return m.map(function(x){ + if (typeof x[0] != "string") + x[0] = x[0].name; + if (!x[1]) + x = x[0]; + return x; + }); + }; + +}).call(CommandManager.prototype); + +exports.CommandManager = CommandManager; + +}); + +define("ace/commands/default_commands",["require","exports","module","ace/lib/lang","ace/config","ace/range"], function(require, exports, module) { +"use strict"; + +var lang = require("../lib/lang"); +var config = require("../config"); +var Range = require("../range").Range; + +function bindKey(win, mac) { + return {win: win, mac: mac}; +} +exports.commands = [{ + name: "showSettingsMenu", + bindKey: bindKey("Ctrl-,", "Command-,"), + exec: function(editor) { + config.loadModule("ace/ext/settings_menu", function(module) { + module.init(editor); + editor.showSettingsMenu(); + }); + }, + readOnly: true +}, { + name: "goToNextError", + bindKey: bindKey("Alt-E", "F4"), + exec: function(editor) { + config.loadModule("./ext/error_marker", function(module) { + module.showErrorMarker(editor, 1); + }); + }, + scrollIntoView: "animate", + readOnly: true +}, { + name: "goToPreviousError", + bindKey: bindKey("Alt-Shift-E", "Shift-F4"), + exec: function(editor) { + config.loadModule("./ext/error_marker", function(module) { + module.showErrorMarker(editor, -1); + }); + }, + scrollIntoView: "animate", + readOnly: true +}, { + name: "selectall", + description: "Select all", + bindKey: bindKey("Ctrl-A", "Command-A"), + exec: function(editor) { editor.selectAll(); }, + readOnly: true +}, { + name: "centerselection", + description: "Center selection", + bindKey: bindKey(null, "Ctrl-L"), + exec: function(editor) { editor.centerSelection(); }, + readOnly: true +}, { + name: "gotoline", + description: "Go to line...", + bindKey: bindKey("Ctrl-L", "Command-L"), + exec: function(editor, line) { + if (typeof line === "number" && !isNaN(line)) + editor.gotoLine(line); + editor.prompt({ $type: "gotoLine" }); + }, + readOnly: true +}, { + name: "fold", + bindKey: bindKey("Alt-L|Ctrl-F1", "Command-Alt-L|Command-F1"), + exec: function(editor) { editor.session.toggleFold(false); }, + multiSelectAction: "forEach", + scrollIntoView: "center", + readOnly: true +}, { + name: "unfold", + bindKey: bindKey("Alt-Shift-L|Ctrl-Shift-F1", "Command-Alt-Shift-L|Command-Shift-F1"), + exec: function(editor) { editor.session.toggleFold(true); }, + multiSelectAction: "forEach", + scrollIntoView: "center", + readOnly: true +}, { + name: "toggleFoldWidget", + bindKey: bindKey("F2", "F2"), + exec: function(editor) { editor.session.toggleFoldWidget(); }, + multiSelectAction: "forEach", + scrollIntoView: "center", + readOnly: true +}, { + name: "toggleParentFoldWidget", + bindKey: bindKey("Alt-F2", "Alt-F2"), + exec: function(editor) { editor.session.toggleFoldWidget(true); }, + multiSelectAction: "forEach", + scrollIntoView: "center", + readOnly: true +}, { + name: "foldall", + description: "Fold all", + bindKey: bindKey(null, "Ctrl-Command-Option-0"), + exec: function(editor) { editor.session.foldAll(); }, + scrollIntoView: "center", + readOnly: true +}, { + name: "foldOther", + description: "Fold other", + bindKey: bindKey("Alt-0", "Command-Option-0"), + exec: function(editor) { + editor.session.foldAll(); + editor.session.unfold(editor.selection.getAllRanges()); + }, + scrollIntoView: "center", + readOnly: true +}, { + name: "unfoldall", + description: "Unfold all", + bindKey: bindKey("Alt-Shift-0", "Command-Option-Shift-0"), + exec: function(editor) { editor.session.unfold(); }, + scrollIntoView: "center", + readOnly: true +}, { + name: "findnext", + description: "Find next", + bindKey: bindKey("Ctrl-K", "Command-G"), + exec: function(editor) { editor.findNext(); }, + multiSelectAction: "forEach", + scrollIntoView: "center", + readOnly: true +}, { + name: "findprevious", + description: "Find previous", + bindKey: bindKey("Ctrl-Shift-K", "Command-Shift-G"), + exec: function(editor) { editor.findPrevious(); }, + multiSelectAction: "forEach", + scrollIntoView: "center", + readOnly: true +}, { + name: "selectOrFindNext", + description: "Select or find next", + bindKey: bindKey("Alt-K", "Ctrl-G"), + exec: function(editor) { + if (editor.selection.isEmpty()) + editor.selection.selectWord(); + else + editor.findNext(); + }, + readOnly: true +}, { + name: "selectOrFindPrevious", + description: "Select or find previous", + bindKey: bindKey("Alt-Shift-K", "Ctrl-Shift-G"), + exec: function(editor) { + if (editor.selection.isEmpty()) + editor.selection.selectWord(); + else + editor.findPrevious(); + }, + readOnly: true +}, { + name: "find", + description: "Find", + bindKey: bindKey("Ctrl-F", "Command-F"), + exec: function(editor) { + config.loadModule("ace/ext/searchbox", function(e) {e.Search(editor);}); + }, + readOnly: true +}, { + name: "overwrite", + description: "Overwrite", + bindKey: "Insert", + exec: function(editor) { editor.toggleOverwrite(); }, + readOnly: true +}, { + name: "selecttostart", + description: "Select to start", + bindKey: bindKey("Ctrl-Shift-Home", "Command-Shift-Home|Command-Shift-Up"), + exec: function(editor) { editor.getSelection().selectFileStart(); }, + multiSelectAction: "forEach", + readOnly: true, + scrollIntoView: "animate", + aceCommandGroup: "fileJump" +}, { + name: "gotostart", + description: "Go to start", + bindKey: bindKey("Ctrl-Home", "Command-Home|Command-Up"), + exec: function(editor) { editor.navigateFileStart(); }, + multiSelectAction: "forEach", + readOnly: true, + scrollIntoView: "animate", + aceCommandGroup: "fileJump" +}, { + name: "selectup", + description: "Select up", + bindKey: bindKey("Shift-Up", "Shift-Up|Ctrl-Shift-P"), + exec: function(editor) { editor.getSelection().selectUp(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "golineup", + description: "Go line up", + bindKey: bindKey("Up", "Up|Ctrl-P"), + exec: function(editor, args) { editor.navigateUp(args.times); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "selecttoend", + description: "Select to end", + bindKey: bindKey("Ctrl-Shift-End", "Command-Shift-End|Command-Shift-Down"), + exec: function(editor) { editor.getSelection().selectFileEnd(); }, + multiSelectAction: "forEach", + readOnly: true, + scrollIntoView: "animate", + aceCommandGroup: "fileJump" +}, { + name: "gotoend", + description: "Go to end", + bindKey: bindKey("Ctrl-End", "Command-End|Command-Down"), + exec: function(editor) { editor.navigateFileEnd(); }, + multiSelectAction: "forEach", + readOnly: true, + scrollIntoView: "animate", + aceCommandGroup: "fileJump" +}, { + name: "selectdown", + description: "Select down", + bindKey: bindKey("Shift-Down", "Shift-Down|Ctrl-Shift-N"), + exec: function(editor) { editor.getSelection().selectDown(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "golinedown", + description: "Go line down", + bindKey: bindKey("Down", "Down|Ctrl-N"), + exec: function(editor, args) { editor.navigateDown(args.times); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "selectwordleft", + description: "Select word left", + bindKey: bindKey("Ctrl-Shift-Left", "Option-Shift-Left"), + exec: function(editor) { editor.getSelection().selectWordLeft(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "gotowordleft", + description: "Go to word left", + bindKey: bindKey("Ctrl-Left", "Option-Left"), + exec: function(editor) { editor.navigateWordLeft(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "selecttolinestart", + description: "Select to line start", + bindKey: bindKey("Alt-Shift-Left", "Command-Shift-Left|Ctrl-Shift-A"), + exec: function(editor) { editor.getSelection().selectLineStart(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "gotolinestart", + description: "Go to line start", + bindKey: bindKey("Alt-Left|Home", "Command-Left|Home|Ctrl-A"), + exec: function(editor) { editor.navigateLineStart(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "selectleft", + description: "Select left", + bindKey: bindKey("Shift-Left", "Shift-Left|Ctrl-Shift-B"), + exec: function(editor) { editor.getSelection().selectLeft(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "gotoleft", + description: "Go to left", + bindKey: bindKey("Left", "Left|Ctrl-B"), + exec: function(editor, args) { editor.navigateLeft(args.times); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "selectwordright", + description: "Select word right", + bindKey: bindKey("Ctrl-Shift-Right", "Option-Shift-Right"), + exec: function(editor) { editor.getSelection().selectWordRight(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "gotowordright", + description: "Go to word right", + bindKey: bindKey("Ctrl-Right", "Option-Right"), + exec: function(editor) { editor.navigateWordRight(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "selecttolineend", + description: "Select to line end", + bindKey: bindKey("Alt-Shift-Right", "Command-Shift-Right|Shift-End|Ctrl-Shift-E"), + exec: function(editor) { editor.getSelection().selectLineEnd(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "gotolineend", + description: "Go to line end", + bindKey: bindKey("Alt-Right|End", "Command-Right|End|Ctrl-E"), + exec: function(editor) { editor.navigateLineEnd(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "selectright", + description: "Select right", + bindKey: bindKey("Shift-Right", "Shift-Right"), + exec: function(editor) { editor.getSelection().selectRight(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "gotoright", + description: "Go to right", + bindKey: bindKey("Right", "Right|Ctrl-F"), + exec: function(editor, args) { editor.navigateRight(args.times); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "selectpagedown", + description: "Select page down", + bindKey: "Shift-PageDown", + exec: function(editor) { editor.selectPageDown(); }, + readOnly: true +}, { + name: "pagedown", + description: "Page down", + bindKey: bindKey(null, "Option-PageDown"), + exec: function(editor) { editor.scrollPageDown(); }, + readOnly: true +}, { + name: "gotopagedown", + description: "Go to page down", + bindKey: bindKey("PageDown", "PageDown|Ctrl-V"), + exec: function(editor) { editor.gotoPageDown(); }, + readOnly: true +}, { + name: "selectpageup", + description: "Select page up", + bindKey: "Shift-PageUp", + exec: function(editor) { editor.selectPageUp(); }, + readOnly: true +}, { + name: "pageup", + description: "Page up", + bindKey: bindKey(null, "Option-PageUp"), + exec: function(editor) { editor.scrollPageUp(); }, + readOnly: true +}, { + name: "gotopageup", + description: "Go to page up", + bindKey: "PageUp", + exec: function(editor) { editor.gotoPageUp(); }, + readOnly: true +}, { + name: "scrollup", + description: "Scroll up", + bindKey: bindKey("Ctrl-Up", null), + exec: function(e) { e.renderer.scrollBy(0, -2 * e.renderer.layerConfig.lineHeight); }, + readOnly: true +}, { + name: "scrolldown", + description: "Scroll down", + bindKey: bindKey("Ctrl-Down", null), + exec: function(e) { e.renderer.scrollBy(0, 2 * e.renderer.layerConfig.lineHeight); }, + readOnly: true +}, { + name: "selectlinestart", + description: "Select line start", + bindKey: "Shift-Home", + exec: function(editor) { editor.getSelection().selectLineStart(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "selectlineend", + description: "Select line end", + bindKey: "Shift-End", + exec: function(editor) { editor.getSelection().selectLineEnd(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "togglerecording", + description: "Toggle recording", + bindKey: bindKey("Ctrl-Alt-E", "Command-Option-E"), + exec: function(editor) { editor.commands.toggleRecording(editor); }, + readOnly: true +}, { + name: "replaymacro", + description: "Replay macro", + bindKey: bindKey("Ctrl-Shift-E", "Command-Shift-E"), + exec: function(editor) { editor.commands.replay(editor); }, + readOnly: true +}, { + name: "jumptomatching", + description: "Jump to matching", + bindKey: bindKey("Ctrl-\\|Ctrl-P", "Command-\\"), + exec: function(editor) { editor.jumpToMatching(); }, + multiSelectAction: "forEach", + scrollIntoView: "animate", + readOnly: true +}, { + name: "selecttomatching", + description: "Select to matching", + bindKey: bindKey("Ctrl-Shift-\\|Ctrl-Shift-P", "Command-Shift-\\"), + exec: function(editor) { editor.jumpToMatching(true); }, + multiSelectAction: "forEach", + scrollIntoView: "animate", + readOnly: true +}, { + name: "expandToMatching", + description: "Expand to matching", + bindKey: bindKey("Ctrl-Shift-M", "Ctrl-Shift-M"), + exec: function(editor) { editor.jumpToMatching(true, true); }, + multiSelectAction: "forEach", + scrollIntoView: "animate", + readOnly: true +}, { + name: "passKeysToBrowser", + description: "Pass keys to browser", + bindKey: bindKey(null, null), + exec: function() {}, + passEvent: true, + readOnly: true +}, { + name: "copy", + description: "Copy", + exec: function(editor) { + }, + readOnly: true +}, +{ + name: "cut", + description: "Cut", + exec: function(editor) { + var cutLine = editor.$copyWithEmptySelection && editor.selection.isEmpty(); + var range = cutLine ? editor.selection.getLineRange() : editor.selection.getRange(); + editor._emit("cut", range); + + if (!range.isEmpty()) + editor.session.remove(range); + editor.clearSelection(); + }, + scrollIntoView: "cursor", + multiSelectAction: "forEach" +}, { + name: "paste", + description: "Paste", + exec: function(editor, args) { + editor.$handlePaste(args); + }, + scrollIntoView: "cursor" +}, { + name: "removeline", + description: "Remove line", + bindKey: bindKey("Ctrl-D", "Command-D"), + exec: function(editor) { editor.removeLines(); }, + scrollIntoView: "cursor", + multiSelectAction: "forEachLine" +}, { + name: "duplicateSelection", + description: "Duplicate selection", + bindKey: bindKey("Ctrl-Shift-D", "Command-Shift-D"), + exec: function(editor) { editor.duplicateSelection(); }, + scrollIntoView: "cursor", + multiSelectAction: "forEach" +}, { + name: "sortlines", + description: "Sort lines", + bindKey: bindKey("Ctrl-Alt-S", "Command-Alt-S"), + exec: function(editor) { editor.sortLines(); }, + scrollIntoView: "selection", + multiSelectAction: "forEachLine" +}, { + name: "togglecomment", + description: "Toggle comment", + bindKey: bindKey("Ctrl-/", "Command-/"), + exec: function(editor) { editor.toggleCommentLines(); }, + multiSelectAction: "forEachLine", + scrollIntoView: "selectionPart" +}, { + name: "toggleBlockComment", + description: "Toggle block comment", + bindKey: bindKey("Ctrl-Shift-/", "Command-Shift-/"), + exec: function(editor) { editor.toggleBlockComment(); }, + multiSelectAction: "forEach", + scrollIntoView: "selectionPart" +}, { + name: "modifyNumberUp", + description: "Modify number up", + bindKey: bindKey("Ctrl-Shift-Up", "Alt-Shift-Up"), + exec: function(editor) { editor.modifyNumber(1); }, + scrollIntoView: "cursor", + multiSelectAction: "forEach" +}, { + name: "modifyNumberDown", + description: "Modify number down", + bindKey: bindKey("Ctrl-Shift-Down", "Alt-Shift-Down"), + exec: function(editor) { editor.modifyNumber(-1); }, + scrollIntoView: "cursor", + multiSelectAction: "forEach" +}, { + name: "replace", + description: "Replace", + bindKey: bindKey("Ctrl-H", "Command-Option-F"), + exec: function(editor) { + config.loadModule("ace/ext/searchbox", function(e) {e.Search(editor, true);}); + } +}, { + name: "undo", + description: "Undo", + bindKey: bindKey("Ctrl-Z", "Command-Z"), + exec: function(editor) { editor.undo(); } +}, { + name: "redo", + description: "Redo", + bindKey: bindKey("Ctrl-Shift-Z|Ctrl-Y", "Command-Shift-Z|Command-Y"), + exec: function(editor) { editor.redo(); } +}, { + name: "copylinesup", + description: "Copy lines up", + bindKey: bindKey("Alt-Shift-Up", "Command-Option-Up"), + exec: function(editor) { editor.copyLinesUp(); }, + scrollIntoView: "cursor" +}, { + name: "movelinesup", + description: "Move lines up", + bindKey: bindKey("Alt-Up", "Option-Up"), + exec: function(editor) { editor.moveLinesUp(); }, + scrollIntoView: "cursor" +}, { + name: "copylinesdown", + description: "Copy lines down", + bindKey: bindKey("Alt-Shift-Down", "Command-Option-Down"), + exec: function(editor) { editor.copyLinesDown(); }, + scrollIntoView: "cursor" +}, { + name: "movelinesdown", + description: "Move lines down", + bindKey: bindKey("Alt-Down", "Option-Down"), + exec: function(editor) { editor.moveLinesDown(); }, + scrollIntoView: "cursor" +}, { + name: "del", + description: "Delete", + bindKey: bindKey("Delete", "Delete|Ctrl-D|Shift-Delete"), + exec: function(editor) { editor.remove("right"); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "backspace", + description: "Backspace", + bindKey: bindKey( + "Shift-Backspace|Backspace", + "Ctrl-Backspace|Shift-Backspace|Backspace|Ctrl-H" + ), + exec: function(editor) { editor.remove("left"); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "cut_or_delete", + description: "Cut or delete", + bindKey: bindKey("Shift-Delete", null), + exec: function(editor) { + if (editor.selection.isEmpty()) { + editor.remove("left"); + } else { + return false; + } + }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "removetolinestart", + description: "Remove to line start", + bindKey: bindKey("Alt-Backspace", "Command-Backspace"), + exec: function(editor) { editor.removeToLineStart(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "removetolineend", + description: "Remove to line end", + bindKey: bindKey("Alt-Delete", "Ctrl-K|Command-Delete"), + exec: function(editor) { editor.removeToLineEnd(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "removetolinestarthard", + description: "Remove to line start hard", + bindKey: bindKey("Ctrl-Shift-Backspace", null), + exec: function(editor) { + var range = editor.selection.getRange(); + range.start.column = 0; + editor.session.remove(range); + }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "removetolineendhard", + description: "Remove to line end hard", + bindKey: bindKey("Ctrl-Shift-Delete", null), + exec: function(editor) { + var range = editor.selection.getRange(); + range.end.column = Number.MAX_VALUE; + editor.session.remove(range); + }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "removewordleft", + description: "Remove word left", + bindKey: bindKey("Ctrl-Backspace", "Alt-Backspace|Ctrl-Alt-Backspace"), + exec: function(editor) { editor.removeWordLeft(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "removewordright", + description: "Remove word right", + bindKey: bindKey("Ctrl-Delete", "Alt-Delete"), + exec: function(editor) { editor.removeWordRight(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "outdent", + description: "Outdent", + bindKey: bindKey("Shift-Tab", "Shift-Tab"), + exec: function(editor) { editor.blockOutdent(); }, + multiSelectAction: "forEach", + scrollIntoView: "selectionPart" +}, { + name: "indent", + description: "Indent", + bindKey: bindKey("Tab", "Tab"), + exec: function(editor) { editor.indent(); }, + multiSelectAction: "forEach", + scrollIntoView: "selectionPart" +}, { + name: "blockoutdent", + description: "Block outdent", + bindKey: bindKey("Ctrl-[", "Ctrl-["), + exec: function(editor) { editor.blockOutdent(); }, + multiSelectAction: "forEachLine", + scrollIntoView: "selectionPart" +}, { + name: "blockindent", + description: "Block indent", + bindKey: bindKey("Ctrl-]", "Ctrl-]"), + exec: function(editor) { editor.blockIndent(); }, + multiSelectAction: "forEachLine", + scrollIntoView: "selectionPart" +}, { + name: "insertstring", + description: "Insert string", + exec: function(editor, str) { editor.insert(str); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "inserttext", + description: "Insert text", + exec: function(editor, args) { + editor.insert(lang.stringRepeat(args.text || "", args.times || 1)); + }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "splitline", + description: "Split line", + bindKey: bindKey(null, "Ctrl-O"), + exec: function(editor) { editor.splitLine(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "transposeletters", + description: "Transpose letters", + bindKey: bindKey("Alt-Shift-X", "Ctrl-T"), + exec: function(editor) { editor.transposeLetters(); }, + multiSelectAction: function(editor) {editor.transposeSelections(1); }, + scrollIntoView: "cursor" +}, { + name: "touppercase", + description: "To uppercase", + bindKey: bindKey("Ctrl-U", "Ctrl-U"), + exec: function(editor) { editor.toUpperCase(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "tolowercase", + description: "To lowercase", + bindKey: bindKey("Ctrl-Shift-U", "Ctrl-Shift-U"), + exec: function(editor) { editor.toLowerCase(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "expandtoline", + description: "Expand to line", + bindKey: bindKey("Ctrl-Shift-L", "Command-Shift-L"), + exec: function(editor) { + var range = editor.selection.getRange(); + + range.start.column = range.end.column = 0; + range.end.row++; + editor.selection.setRange(range, false); + }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "joinlines", + description: "Join lines", + bindKey: bindKey(null, null), + exec: function(editor) { + var isBackwards = editor.selection.isBackwards(); + var selectionStart = isBackwards ? editor.selection.getSelectionLead() : editor.selection.getSelectionAnchor(); + var selectionEnd = isBackwards ? editor.selection.getSelectionAnchor() : editor.selection.getSelectionLead(); + var firstLineEndCol = editor.session.doc.getLine(selectionStart.row).length; + var selectedText = editor.session.doc.getTextRange(editor.selection.getRange()); + var selectedCount = selectedText.replace(/\n\s*/, " ").length; + var insertLine = editor.session.doc.getLine(selectionStart.row); + + for (var i = selectionStart.row + 1; i <= selectionEnd.row + 1; i++) { + var curLine = lang.stringTrimLeft(lang.stringTrimRight(editor.session.doc.getLine(i))); + if (curLine.length !== 0) { + curLine = " " + curLine; + } + insertLine += curLine; + } + + if (selectionEnd.row + 1 < (editor.session.doc.getLength() - 1)) { + insertLine += editor.session.doc.getNewLineCharacter(); + } + + editor.clearSelection(); + editor.session.doc.replace(new Range(selectionStart.row, 0, selectionEnd.row + 2, 0), insertLine); + + if (selectedCount > 0) { + editor.selection.moveCursorTo(selectionStart.row, selectionStart.column); + editor.selection.selectTo(selectionStart.row, selectionStart.column + selectedCount); + } else { + firstLineEndCol = editor.session.doc.getLine(selectionStart.row).length > firstLineEndCol ? (firstLineEndCol + 1) : firstLineEndCol; + editor.selection.moveCursorTo(selectionStart.row, firstLineEndCol); + } + }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "invertSelection", + description: "Invert selection", + bindKey: bindKey(null, null), + exec: function(editor) { + var endRow = editor.session.doc.getLength() - 1; + var endCol = editor.session.doc.getLine(endRow).length; + var ranges = editor.selection.rangeList.ranges; + var newRanges = []; + if (ranges.length < 1) { + ranges = [editor.selection.getRange()]; + } + + for (var i = 0; i < ranges.length; i++) { + if (i == (ranges.length - 1)) { + if (!(ranges[i].end.row === endRow && ranges[i].end.column === endCol)) { + newRanges.push(new Range(ranges[i].end.row, ranges[i].end.column, endRow, endCol)); + } + } + + if (i === 0) { + if (!(ranges[i].start.row === 0 && ranges[i].start.column === 0)) { + newRanges.push(new Range(0, 0, ranges[i].start.row, ranges[i].start.column)); + } + } else { + newRanges.push(new Range(ranges[i-1].end.row, ranges[i-1].end.column, ranges[i].start.row, ranges[i].start.column)); + } + } + + editor.exitMultiSelectMode(); + editor.clearSelection(); + + for(var i = 0; i < newRanges.length; i++) { + editor.selection.addRange(newRanges[i], false); + } + }, + readOnly: true, + scrollIntoView: "none" +}, { + name: "openCommandPallete", + description: "Open command pallete", + bindKey: bindKey("F1", "F1"), + exec: function(editor) { + editor.prompt({ $type: "commands" }); + }, + readOnly: true +}, { + name: "modeSelect", + description: "Change language mode...", + bindKey: bindKey(null, null), + exec: function(editor) { + editor.prompt({ $type: "modes" }); + }, + readOnly: true +}]; + +}); + +define("ace/editor",["require","exports","module","ace/lib/fixoldbrowsers","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/lib/useragent","ace/keyboard/textinput","ace/mouse/mouse_handler","ace/mouse/fold_handler","ace/keyboard/keybinding","ace/edit_session","ace/search","ace/range","ace/lib/event_emitter","ace/commands/command_manager","ace/commands/default_commands","ace/config","ace/token_iterator","ace/clipboard"], function(require, exports, module) { +"use strict"; + +require("./lib/fixoldbrowsers"); + +var oop = require("./lib/oop"); +var dom = require("./lib/dom"); +var lang = require("./lib/lang"); +var useragent = require("./lib/useragent"); +var TextInput = require("./keyboard/textinput").TextInput; +var MouseHandler = require("./mouse/mouse_handler").MouseHandler; +var FoldHandler = require("./mouse/fold_handler").FoldHandler; +var KeyBinding = require("./keyboard/keybinding").KeyBinding; +var EditSession = require("./edit_session").EditSession; +var Search = require("./search").Search; +var Range = require("./range").Range; +var EventEmitter = require("./lib/event_emitter").EventEmitter; +var CommandManager = require("./commands/command_manager").CommandManager; +var defaultCommands = require("./commands/default_commands").commands; +var config = require("./config"); +var TokenIterator = require("./token_iterator").TokenIterator; + +var clipboard = require("./clipboard"); +var Editor = function(renderer, session, options) { + var container = renderer.getContainerElement(); + this.container = container; + this.renderer = renderer; + this.id = "editor" + (++Editor.$uid); + + this.commands = new CommandManager(useragent.isMac ? "mac" : "win", defaultCommands); + if (typeof document == "object") { + this.textInput = new TextInput(renderer.getTextAreaContainer(), this); + this.renderer.textarea = this.textInput.getElement(); + this.$mouseHandler = new MouseHandler(this); + new FoldHandler(this); + } + + this.keyBinding = new KeyBinding(this); + + this.$search = new Search().set({ + wrap: true + }); + + this.$historyTracker = this.$historyTracker.bind(this); + this.commands.on("exec", this.$historyTracker); + + this.$initOperationListeners(); + + this._$emitInputEvent = lang.delayedCall(function() { + this._signal("input", {}); + if (this.session && this.session.bgTokenizer) + this.session.bgTokenizer.scheduleStart(); + }.bind(this)); + + this.on("change", function(_, _self) { + _self._$emitInputEvent.schedule(31); + }); + + this.setSession(session || options && options.session || new EditSession("")); + config.resetOptions(this); + if (options) + this.setOptions(options); + config._signal("editor", this); +}; + +Editor.$uid = 0; + +(function(){ + + oop.implement(this, EventEmitter); + + this.$initOperationListeners = function() { + this.commands.on("exec", this.startOperation.bind(this), true); + this.commands.on("afterExec", this.endOperation.bind(this), true); + + this.$opResetTimer = lang.delayedCall(this.endOperation.bind(this, true)); + this.on("change", function() { + if (!this.curOp) { + this.startOperation(); + this.curOp.selectionBefore = this.$lastSel; + } + this.curOp.docChanged = true; + }.bind(this), true); + + this.on("changeSelection", function() { + if (!this.curOp) { + this.startOperation(); + this.curOp.selectionBefore = this.$lastSel; + } + this.curOp.selectionChanged = true; + }.bind(this), true); + }; + + this.curOp = null; + this.prevOp = {}; + this.startOperation = function(commandEvent) { + if (this.curOp) { + if (!commandEvent || this.curOp.command) + return; + this.prevOp = this.curOp; + } + if (!commandEvent) { + this.previousCommand = null; + commandEvent = {}; + } + + this.$opResetTimer.schedule(); + this.curOp = this.session.curOp = { + command: commandEvent.command || {}, + args: commandEvent.args, + scrollTop: this.renderer.scrollTop + }; + this.curOp.selectionBefore = this.selection.toJSON(); + }; + + this.endOperation = function(e) { + if (this.curOp) { + if (e && e.returnValue === false) + return (this.curOp = null); + if (e == true && this.curOp.command && this.curOp.command.name == "mouse") + return; + this._signal("beforeEndOperation"); + if (!this.curOp) return; + var command = this.curOp.command; + var scrollIntoView = command && command.scrollIntoView; + if (scrollIntoView) { + switch (scrollIntoView) { + case "center-animate": + scrollIntoView = "animate"; + case "center": + this.renderer.scrollCursorIntoView(null, 0.5); + break; + case "animate": + case "cursor": + this.renderer.scrollCursorIntoView(); + break; + case "selectionPart": + var range = this.selection.getRange(); + var config = this.renderer.layerConfig; + if (range.start.row >= config.lastRow || range.end.row <= config.firstRow) { + this.renderer.scrollSelectionIntoView(this.selection.anchor, this.selection.lead); + } + break; + default: + break; + } + if (scrollIntoView == "animate") + this.renderer.animateScrolling(this.curOp.scrollTop); + } + var sel = this.selection.toJSON(); + this.curOp.selectionAfter = sel; + this.$lastSel = this.selection.toJSON(); + this.session.getUndoManager().addSelection(sel); + this.prevOp = this.curOp; + this.curOp = null; + } + }; + this.$mergeableCommands = ["backspace", "del", "insertstring"]; + this.$historyTracker = function(e) { + if (!this.$mergeUndoDeltas) + return; + + var prev = this.prevOp; + var mergeableCommands = this.$mergeableCommands; + var shouldMerge = prev.command && (e.command.name == prev.command.name); + if (e.command.name == "insertstring") { + var text = e.args; + if (this.mergeNextCommand === undefined) + this.mergeNextCommand = true; + + shouldMerge = shouldMerge + && this.mergeNextCommand // previous command allows to coalesce with + && (!/\s/.test(text) || /\s/.test(prev.args)); // previous insertion was of same type + + this.mergeNextCommand = true; + } else { + shouldMerge = shouldMerge + && mergeableCommands.indexOf(e.command.name) !== -1; // the command is mergeable + } + + if ( + this.$mergeUndoDeltas != "always" + && Date.now() - this.sequenceStartTime > 2000 + ) { + shouldMerge = false; // the sequence is too long + } + + if (shouldMerge) + this.session.mergeUndoDeltas = true; + else if (mergeableCommands.indexOf(e.command.name) !== -1) + this.sequenceStartTime = Date.now(); + }; + this.setKeyboardHandler = function(keyboardHandler, cb) { + if (keyboardHandler && typeof keyboardHandler === "string" && keyboardHandler != "ace") { + this.$keybindingId = keyboardHandler; + var _self = this; + config.loadModule(["keybinding", keyboardHandler], function(module) { + if (_self.$keybindingId == keyboardHandler) + _self.keyBinding.setKeyboardHandler(module && module.handler); + cb && cb(); + }); + } else { + this.$keybindingId = null; + this.keyBinding.setKeyboardHandler(keyboardHandler); + cb && cb(); + } + }; + this.getKeyboardHandler = function() { + return this.keyBinding.getKeyboardHandler(); + }; + this.setSession = function(session) { + if (this.session == session) + return; + if (this.curOp) this.endOperation(); + this.curOp = {}; + + var oldSession = this.session; + if (oldSession) { + this.session.off("change", this.$onDocumentChange); + this.session.off("changeMode", this.$onChangeMode); + this.session.off("tokenizerUpdate", this.$onTokenizerUpdate); + this.session.off("changeTabSize", this.$onChangeTabSize); + this.session.off("changeWrapLimit", this.$onChangeWrapLimit); + this.session.off("changeWrapMode", this.$onChangeWrapMode); + this.session.off("changeFold", this.$onChangeFold); + this.session.off("changeFrontMarker", this.$onChangeFrontMarker); + this.session.off("changeBackMarker", this.$onChangeBackMarker); + this.session.off("changeBreakpoint", this.$onChangeBreakpoint); + this.session.off("changeAnnotation", this.$onChangeAnnotation); + this.session.off("changeOverwrite", this.$onCursorChange); + this.session.off("changeScrollTop", this.$onScrollTopChange); + this.session.off("changeScrollLeft", this.$onScrollLeftChange); + + var selection = this.session.getSelection(); + selection.off("changeCursor", this.$onCursorChange); + selection.off("changeSelection", this.$onSelectionChange); + } + + this.session = session; + if (session) { + this.$onDocumentChange = this.onDocumentChange.bind(this); + session.on("change", this.$onDocumentChange); + this.renderer.setSession(session); + + this.$onChangeMode = this.onChangeMode.bind(this); + session.on("changeMode", this.$onChangeMode); + + this.$onTokenizerUpdate = this.onTokenizerUpdate.bind(this); + session.on("tokenizerUpdate", this.$onTokenizerUpdate); + + this.$onChangeTabSize = this.renderer.onChangeTabSize.bind(this.renderer); + session.on("changeTabSize", this.$onChangeTabSize); + + this.$onChangeWrapLimit = this.onChangeWrapLimit.bind(this); + session.on("changeWrapLimit", this.$onChangeWrapLimit); + + this.$onChangeWrapMode = this.onChangeWrapMode.bind(this); + session.on("changeWrapMode", this.$onChangeWrapMode); + + this.$onChangeFold = this.onChangeFold.bind(this); + session.on("changeFold", this.$onChangeFold); + + this.$onChangeFrontMarker = this.onChangeFrontMarker.bind(this); + this.session.on("changeFrontMarker", this.$onChangeFrontMarker); + + this.$onChangeBackMarker = this.onChangeBackMarker.bind(this); + this.session.on("changeBackMarker", this.$onChangeBackMarker); + + this.$onChangeBreakpoint = this.onChangeBreakpoint.bind(this); + this.session.on("changeBreakpoint", this.$onChangeBreakpoint); + + this.$onChangeAnnotation = this.onChangeAnnotation.bind(this); + this.session.on("changeAnnotation", this.$onChangeAnnotation); + + this.$onCursorChange = this.onCursorChange.bind(this); + this.session.on("changeOverwrite", this.$onCursorChange); + + this.$onScrollTopChange = this.onScrollTopChange.bind(this); + this.session.on("changeScrollTop", this.$onScrollTopChange); + + this.$onScrollLeftChange = this.onScrollLeftChange.bind(this); + this.session.on("changeScrollLeft", this.$onScrollLeftChange); + + this.selection = session.getSelection(); + this.selection.on("changeCursor", this.$onCursorChange); + + this.$onSelectionChange = this.onSelectionChange.bind(this); + this.selection.on("changeSelection", this.$onSelectionChange); + + this.onChangeMode(); + + this.onCursorChange(); + + this.onScrollTopChange(); + this.onScrollLeftChange(); + this.onSelectionChange(); + this.onChangeFrontMarker(); + this.onChangeBackMarker(); + this.onChangeBreakpoint(); + this.onChangeAnnotation(); + this.session.getUseWrapMode() && this.renderer.adjustWrapLimit(); + this.renderer.updateFull(); + } else { + this.selection = null; + this.renderer.setSession(session); + } + + this._signal("changeSession", { + session: session, + oldSession: oldSession + }); + + this.curOp = null; + + oldSession && oldSession._signal("changeEditor", {oldEditor: this}); + session && session._signal("changeEditor", {editor: this}); + + if (session && session.bgTokenizer) + session.bgTokenizer.scheduleStart(); + }; + this.getSession = function() { + return this.session; + }; + this.setValue = function(val, cursorPos) { + this.session.doc.setValue(val); + + if (!cursorPos) + this.selectAll(); + else if (cursorPos == 1) + this.navigateFileEnd(); + else if (cursorPos == -1) + this.navigateFileStart(); + + return val; + }; + this.getValue = function() { + return this.session.getValue(); + }; + this.getSelection = function() { + return this.selection; + }; + this.resize = function(force) { + this.renderer.onResize(force); + }; + this.setTheme = function(theme, cb) { + this.renderer.setTheme(theme, cb); + }; + this.getTheme = function() { + return this.renderer.getTheme(); + }; + this.setStyle = function(style) { + this.renderer.setStyle(style); + }; + this.unsetStyle = function(style) { + this.renderer.unsetStyle(style); + }; + this.getFontSize = function () { + return this.getOption("fontSize") || + dom.computedStyle(this.container).fontSize; + }; + this.setFontSize = function(size) { + this.setOption("fontSize", size); + }; + + this.$highlightBrackets = function() { + if (this.session.$bracketHighlight) { + this.session.removeMarker(this.session.$bracketHighlight); + this.session.$bracketHighlight = null; + } + + if (this.$highlightPending) { + return; + } + var self = this; + this.$highlightPending = true; + setTimeout(function() { + self.$highlightPending = false; + var session = self.session; + if (!session || !session.bgTokenizer) return; + var pos = session.findMatchingBracket(self.getCursorPosition()); + if (pos) { + var range = new Range(pos.row, pos.column, pos.row, pos.column + 1); + } else if (session.$mode.getMatching) { + var range = session.$mode.getMatching(self.session); + } + if (range) + session.$bracketHighlight = session.addMarker(range, "ace_bracket", "text"); + }, 50); + }; + this.$highlightTags = function() { + if (this.$highlightTagPending) + return; + var self = this; + this.$highlightTagPending = true; + setTimeout(function() { + self.$highlightTagPending = false; + + var session = self.session; + if (!session || !session.bgTokenizer) return; + + var pos = self.getCursorPosition(); + var iterator = new TokenIterator(self.session, pos.row, pos.column); + var token = iterator.getCurrentToken(); + + if (!token || !/\b(?:tag-open|tag-name)/.test(token.type)) { + session.removeMarker(session.$tagHighlight); + session.$tagHighlight = null; + return; + } + + if (token.type.indexOf("tag-open") != -1) { + token = iterator.stepForward(); + if (!token) + return; + } + + var tag = token.value; + var depth = 0; + var prevToken = iterator.stepBackward(); + + if (prevToken.value == '<'){ + do { + prevToken = token; + token = iterator.stepForward(); + + if (token && token.value === tag && token.type.indexOf('tag-name') !== -1) { + if (prevToken.value === '<'){ + depth++; + } else if (prevToken.value === '= 0); + } else { + do { + token = prevToken; + prevToken = iterator.stepBackward(); + + if (token && token.value === tag && token.type.indexOf('tag-name') !== -1) { + if (prevToken.value === '<') { + depth++; + } else if (prevToken.value === ' 1)) + highlight = false; + } + + if (session.$highlightLineMarker && !highlight) { + session.removeMarker(session.$highlightLineMarker.id); + session.$highlightLineMarker = null; + } else if (!session.$highlightLineMarker && highlight) { + var range = new Range(highlight.row, highlight.column, highlight.row, Infinity); + range.id = session.addMarker(range, "ace_active-line", "screenLine"); + session.$highlightLineMarker = range; + } else if (highlight) { + session.$highlightLineMarker.start.row = highlight.row; + session.$highlightLineMarker.end.row = highlight.row; + session.$highlightLineMarker.start.column = highlight.column; + session._signal("changeBackMarker"); + } + }; + + this.onSelectionChange = function(e) { + var session = this.session; + + if (session.$selectionMarker) { + session.removeMarker(session.$selectionMarker); + } + session.$selectionMarker = null; + + if (!this.selection.isEmpty()) { + var range = this.selection.getRange(); + var style = this.getSelectionStyle(); + session.$selectionMarker = session.addMarker(range, "ace_selection", style); + } else { + this.$updateHighlightActiveLine(); + } + + var re = this.$highlightSelectedWord && this.$getSelectionHighLightRegexp(); + this.session.highlight(re); + + this._signal("changeSelection"); + }; + + this.$getSelectionHighLightRegexp = function() { + var session = this.session; + + var selection = this.getSelectionRange(); + if (selection.isEmpty() || selection.isMultiLine()) + return; + + var startColumn = selection.start.column; + var endColumn = selection.end.column; + var line = session.getLine(selection.start.row); + + var needle = line.substring(startColumn, endColumn); + if (needle.length > 5000 || !/[\w\d]/.test(needle)) + return; + + var re = this.$search.$assembleRegExp({ + wholeWord: true, + caseSensitive: true, + needle: needle + }); + + var wordWithBoundary = line.substring(startColumn - 1, endColumn + 1); + if (!re.test(wordWithBoundary)) + return; + + return re; + }; + + + this.onChangeFrontMarker = function() { + this.renderer.updateFrontMarkers(); + }; + + this.onChangeBackMarker = function() { + this.renderer.updateBackMarkers(); + }; + + + this.onChangeBreakpoint = function() { + this.renderer.updateBreakpoints(); + }; + + this.onChangeAnnotation = function() { + this.renderer.setAnnotations(this.session.getAnnotations()); + }; + + + this.onChangeMode = function(e) { + this.renderer.updateText(); + this._emit("changeMode", e); + }; + + + this.onChangeWrapLimit = function() { + this.renderer.updateFull(); + }; + + this.onChangeWrapMode = function() { + this.renderer.onResize(true); + }; + + + this.onChangeFold = function() { + this.$updateHighlightActiveLine(); + this.renderer.updateFull(); + }; + this.getSelectedText = function() { + return this.session.getTextRange(this.getSelectionRange()); + }; + this.getCopyText = function() { + var text = this.getSelectedText(); + var nl = this.session.doc.getNewLineCharacter(); + var copyLine= false; + if (!text && this.$copyWithEmptySelection) { + copyLine = true; + var ranges = this.selection.getAllRanges(); + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i]; + if (i && ranges[i - 1].start.row == range.start.row) + continue; + text += this.session.getLine(range.start.row) + nl; + } + } + var e = {text: text}; + this._signal("copy", e); + clipboard.lineMode = copyLine ? e.text : ""; + return e.text; + }; + this.onCopy = function() { + this.commands.exec("copy", this); + }; + this.onCut = function() { + this.commands.exec("cut", this); + }; + this.onPaste = function(text, event) { + var e = {text: text, event: event}; + this.commands.exec("paste", this, e); + }; + + this.$handlePaste = function(e) { + if (typeof e == "string") + e = {text: e}; + this._signal("paste", e); + var text = e.text; + + var lineMode = text == clipboard.lineMode; + var session = this.session; + if (!this.inMultiSelectMode || this.inVirtualSelectionMode) { + if (lineMode) + session.insert({ row: this.selection.lead.row, column: 0 }, text); + else + this.insert(text); + } else if (lineMode) { + this.selection.rangeList.ranges.forEach(function(range) { + session.insert({ row: range.start.row, column: 0 }, text); + }); + } else { + var lines = text.split(/\r\n|\r|\n/); + var ranges = this.selection.rangeList.ranges; + + var isFullLine = lines.length == 2 && (!lines[0] || !lines[1]); + if (lines.length != ranges.length || isFullLine) + return this.commands.exec("insertstring", this, text); + + for (var i = ranges.length; i--;) { + var range = ranges[i]; + if (!range.isEmpty()) + session.remove(range); + + session.insert(range.start, lines[i]); + } + } + }; + + this.execCommand = function(command, args) { + return this.commands.exec(command, this, args); + }; + this.insert = function(text, pasted) { + var session = this.session; + var mode = session.getMode(); + var cursor = this.getCursorPosition(); + + if (this.getBehavioursEnabled() && !pasted) { + var transform = mode.transformAction(session.getState(cursor.row), 'insertion', this, session, text); + if (transform) { + if (text !== transform.text) { + if (!this.inVirtualSelectionMode) { + this.session.mergeUndoDeltas = false; + this.mergeNextCommand = false; + } + } + text = transform.text; + + } + } + + if (text == "\t") + text = this.session.getTabString(); + if (!this.selection.isEmpty()) { + var range = this.getSelectionRange(); + cursor = this.session.remove(range); + this.clearSelection(); + } + else if (this.session.getOverwrite() && text.indexOf("\n") == -1) { + var range = new Range.fromPoints(cursor, cursor); + range.end.column += text.length; + this.session.remove(range); + } + + if (text == "\n" || text == "\r\n") { + var line = session.getLine(cursor.row); + if (cursor.column > line.search(/\S|$/)) { + var d = line.substr(cursor.column).search(/\S|$/); + session.doc.removeInLine(cursor.row, cursor.column, cursor.column + d); + } + } + this.clearSelection(); + + var start = cursor.column; + var lineState = session.getState(cursor.row); + var line = session.getLine(cursor.row); + var shouldOutdent = mode.checkOutdent(lineState, line, text); + session.insert(cursor, text); + + if (transform && transform.selection) { + if (transform.selection.length == 2) { // Transform relative to the current column + this.selection.setSelectionRange( + new Range(cursor.row, start + transform.selection[0], + cursor.row, start + transform.selection[1])); + } else { // Transform relative to the current row. + this.selection.setSelectionRange( + new Range(cursor.row + transform.selection[0], + transform.selection[1], + cursor.row + transform.selection[2], + transform.selection[3])); + } + } + + if (session.getDocument().isNewLine(text)) { + var lineIndent = mode.getNextLineIndent(lineState, line.slice(0, cursor.column), session.getTabString()); + + session.insert({row: cursor.row+1, column: 0}, lineIndent); + } + if (shouldOutdent) + mode.autoOutdent(lineState, session, cursor.row); + }; + + this.onTextInput = function(text, composition) { + if (!composition) + return this.keyBinding.onTextInput(text); + + this.startOperation({command: { name: "insertstring" }}); + var applyComposition = this.applyComposition.bind(this, text, composition); + if (this.selection.rangeCount) + this.forEachSelection(applyComposition); + else + applyComposition(); + this.endOperation(); + }; + + this.applyComposition = function(text, composition) { + if (composition.extendLeft || composition.extendRight) { + var r = this.selection.getRange(); + r.start.column -= composition.extendLeft; + r.end.column += composition.extendRight; + this.selection.setRange(r); + if (!text && !r.isEmpty()) + this.remove(); + } + if (text || !this.selection.isEmpty()) + this.insert(text, true); + if (composition.restoreStart || composition.restoreEnd) { + var r = this.selection.getRange(); + r.start.column -= composition.restoreStart; + r.end.column -= composition.restoreEnd; + this.selection.setRange(r); + } + }; + + this.onCommandKey = function(e, hashId, keyCode) { + return this.keyBinding.onCommandKey(e, hashId, keyCode); + }; + this.setOverwrite = function(overwrite) { + this.session.setOverwrite(overwrite); + }; + this.getOverwrite = function() { + return this.session.getOverwrite(); + }; + this.toggleOverwrite = function() { + this.session.toggleOverwrite(); + }; + this.setScrollSpeed = function(speed) { + this.setOption("scrollSpeed", speed); + }; + this.getScrollSpeed = function() { + return this.getOption("scrollSpeed"); + }; + this.setDragDelay = function(dragDelay) { + this.setOption("dragDelay", dragDelay); + }; + this.getDragDelay = function() { + return this.getOption("dragDelay"); + }; + this.setSelectionStyle = function(val) { + this.setOption("selectionStyle", val); + }; + this.getSelectionStyle = function() { + return this.getOption("selectionStyle"); + }; + this.setHighlightActiveLine = function(shouldHighlight) { + this.setOption("highlightActiveLine", shouldHighlight); + }; + this.getHighlightActiveLine = function() { + return this.getOption("highlightActiveLine"); + }; + this.setHighlightGutterLine = function(shouldHighlight) { + this.setOption("highlightGutterLine", shouldHighlight); + }; + + this.getHighlightGutterLine = function() { + return this.getOption("highlightGutterLine"); + }; + this.setHighlightSelectedWord = function(shouldHighlight) { + this.setOption("highlightSelectedWord", shouldHighlight); + }; + this.getHighlightSelectedWord = function() { + return this.$highlightSelectedWord; + }; + + this.setAnimatedScroll = function(shouldAnimate){ + this.renderer.setAnimatedScroll(shouldAnimate); + }; + + this.getAnimatedScroll = function(){ + return this.renderer.getAnimatedScroll(); + }; + this.setShowInvisibles = function(showInvisibles) { + this.renderer.setShowInvisibles(showInvisibles); + }; + this.getShowInvisibles = function() { + return this.renderer.getShowInvisibles(); + }; + + this.setDisplayIndentGuides = function(display) { + this.renderer.setDisplayIndentGuides(display); + }; + + this.getDisplayIndentGuides = function() { + return this.renderer.getDisplayIndentGuides(); + }; + this.setShowPrintMargin = function(showPrintMargin) { + this.renderer.setShowPrintMargin(showPrintMargin); + }; + this.getShowPrintMargin = function() { + return this.renderer.getShowPrintMargin(); + }; + this.setPrintMarginColumn = function(showPrintMargin) { + this.renderer.setPrintMarginColumn(showPrintMargin); + }; + this.getPrintMarginColumn = function() { + return this.renderer.getPrintMarginColumn(); + }; + this.setReadOnly = function(readOnly) { + this.setOption("readOnly", readOnly); + }; + this.getReadOnly = function() { + return this.getOption("readOnly"); + }; + this.setBehavioursEnabled = function (enabled) { + this.setOption("behavioursEnabled", enabled); + }; + this.getBehavioursEnabled = function () { + return this.getOption("behavioursEnabled"); + }; + this.setWrapBehavioursEnabled = function (enabled) { + this.setOption("wrapBehavioursEnabled", enabled); + }; + this.getWrapBehavioursEnabled = function () { + return this.getOption("wrapBehavioursEnabled"); + }; + this.setShowFoldWidgets = function(show) { + this.setOption("showFoldWidgets", show); + + }; + this.getShowFoldWidgets = function() { + return this.getOption("showFoldWidgets"); + }; + + this.setFadeFoldWidgets = function(fade) { + this.setOption("fadeFoldWidgets", fade); + }; + + this.getFadeFoldWidgets = function() { + return this.getOption("fadeFoldWidgets"); + }; + this.remove = function(dir) { + if (this.selection.isEmpty()){ + if (dir == "left") + this.selection.selectLeft(); + else + this.selection.selectRight(); + } + + var range = this.getSelectionRange(); + if (this.getBehavioursEnabled()) { + var session = this.session; + var state = session.getState(range.start.row); + var new_range = session.getMode().transformAction(state, 'deletion', this, session, range); + + if (range.end.column === 0) { + var text = session.getTextRange(range); + if (text[text.length - 1] == "\n") { + var line = session.getLine(range.end.row); + if (/^\s+$/.test(line)) { + range.end.column = line.length; + } + } + } + if (new_range) + range = new_range; + } + + this.session.remove(range); + this.clearSelection(); + }; + this.removeWordRight = function() { + if (this.selection.isEmpty()) + this.selection.selectWordRight(); + + this.session.remove(this.getSelectionRange()); + this.clearSelection(); + }; + this.removeWordLeft = function() { + if (this.selection.isEmpty()) + this.selection.selectWordLeft(); + + this.session.remove(this.getSelectionRange()); + this.clearSelection(); + }; + this.removeToLineStart = function() { + if (this.selection.isEmpty()) + this.selection.selectLineStart(); + if (this.selection.isEmpty()) + this.selection.selectLeft(); + this.session.remove(this.getSelectionRange()); + this.clearSelection(); + }; + this.removeToLineEnd = function() { + if (this.selection.isEmpty()) + this.selection.selectLineEnd(); + + var range = this.getSelectionRange(); + if (range.start.column == range.end.column && range.start.row == range.end.row) { + range.end.column = 0; + range.end.row++; + } + + this.session.remove(range); + this.clearSelection(); + }; + this.splitLine = function() { + if (!this.selection.isEmpty()) { + this.session.remove(this.getSelectionRange()); + this.clearSelection(); + } + + var cursor = this.getCursorPosition(); + this.insert("\n"); + this.moveCursorToPosition(cursor); + }; + this.transposeLetters = function() { + if (!this.selection.isEmpty()) { + return; + } + + var cursor = this.getCursorPosition(); + var column = cursor.column; + if (column === 0) + return; + + var line = this.session.getLine(cursor.row); + var swap, range; + if (column < line.length) { + swap = line.charAt(column) + line.charAt(column-1); + range = new Range(cursor.row, column-1, cursor.row, column+1); + } + else { + swap = line.charAt(column-1) + line.charAt(column-2); + range = new Range(cursor.row, column-2, cursor.row, column); + } + this.session.replace(range, swap); + this.session.selection.moveToPosition(range.end); + }; + this.toLowerCase = function() { + var originalRange = this.getSelectionRange(); + if (this.selection.isEmpty()) { + this.selection.selectWord(); + } + + var range = this.getSelectionRange(); + var text = this.session.getTextRange(range); + this.session.replace(range, text.toLowerCase()); + this.selection.setSelectionRange(originalRange); + }; + this.toUpperCase = function() { + var originalRange = this.getSelectionRange(); + if (this.selection.isEmpty()) { + this.selection.selectWord(); + } + + var range = this.getSelectionRange(); + var text = this.session.getTextRange(range); + this.session.replace(range, text.toUpperCase()); + this.selection.setSelectionRange(originalRange); + }; + this.indent = function() { + var session = this.session; + var range = this.getSelectionRange(); + + if (range.start.row < range.end.row) { + var rows = this.$getSelectedRows(); + session.indentRows(rows.first, rows.last, "\t"); + return; + } else if (range.start.column < range.end.column) { + var text = session.getTextRange(range); + if (!/^\s+$/.test(text)) { + var rows = this.$getSelectedRows(); + session.indentRows(rows.first, rows.last, "\t"); + return; + } + } + + var line = session.getLine(range.start.row); + var position = range.start; + var size = session.getTabSize(); + var column = session.documentToScreenColumn(position.row, position.column); + + if (this.session.getUseSoftTabs()) { + var count = (size - column % size); + var indentString = lang.stringRepeat(" ", count); + } else { + var count = column % size; + while (line[range.start.column - 1] == " " && count) { + range.start.column--; + count--; + } + this.selection.setSelectionRange(range); + indentString = "\t"; + } + return this.insert(indentString); + }; + this.blockIndent = function() { + var rows = this.$getSelectedRows(); + this.session.indentRows(rows.first, rows.last, "\t"); + }; + this.blockOutdent = function() { + var selection = this.session.getSelection(); + this.session.outdentRows(selection.getRange()); + }; + this.sortLines = function() { + var rows = this.$getSelectedRows(); + var session = this.session; + + var lines = []; + for (var i = rows.first; i <= rows.last; i++) + lines.push(session.getLine(i)); + + lines.sort(function(a, b) { + if (a.toLowerCase() < b.toLowerCase()) return -1; + if (a.toLowerCase() > b.toLowerCase()) return 1; + return 0; + }); + + var deleteRange = new Range(0, 0, 0, 0); + for (var i = rows.first; i <= rows.last; i++) { + var line = session.getLine(i); + deleteRange.start.row = i; + deleteRange.end.row = i; + deleteRange.end.column = line.length; + session.replace(deleteRange, lines[i-rows.first]); + } + }; + this.toggleCommentLines = function() { + var state = this.session.getState(this.getCursorPosition().row); + var rows = this.$getSelectedRows(); + this.session.getMode().toggleCommentLines(state, this.session, rows.first, rows.last); + }; + + this.toggleBlockComment = function() { + var cursor = this.getCursorPosition(); + var state = this.session.getState(cursor.row); + var range = this.getSelectionRange(); + this.session.getMode().toggleBlockComment(state, this.session, range, cursor); + }; + this.getNumberAt = function(row, column) { + var _numberRx = /[\-]?[0-9]+(?:\.[0-9]+)?/g; + _numberRx.lastIndex = 0; + + var s = this.session.getLine(row); + while (_numberRx.lastIndex < column) { + var m = _numberRx.exec(s); + if(m.index <= column && m.index+m[0].length >= column){ + var number = { + value: m[0], + start: m.index, + end: m.index+m[0].length + }; + return number; + } + } + return null; + }; + this.modifyNumber = function(amount) { + var row = this.selection.getCursor().row; + var column = this.selection.getCursor().column; + var charRange = new Range(row, column-1, row, column); + + var c = this.session.getTextRange(charRange); + if (!isNaN(parseFloat(c)) && isFinite(c)) { + var nr = this.getNumberAt(row, column); + if (nr) { + var fp = nr.value.indexOf(".") >= 0 ? nr.start + nr.value.indexOf(".") + 1 : nr.end; + var decimals = nr.start + nr.value.length - fp; + + var t = parseFloat(nr.value); + t *= Math.pow(10, decimals); + + + if(fp !== nr.end && column < fp){ + amount *= Math.pow(10, nr.end - column - 1); + } else { + amount *= Math.pow(10, nr.end - column); + } + + t += amount; + t /= Math.pow(10, decimals); + var nnr = t.toFixed(decimals); + var replaceRange = new Range(row, nr.start, row, nr.end); + this.session.replace(replaceRange, nnr); + this.moveCursorTo(row, Math.max(nr.start +1, column + nnr.length - nr.value.length)); + + } + } else { + this.toggleWord(); + } + }; + + this.$toggleWordPairs = [ + ["first", "last"], + ["true", "false"], + ["yes", "no"], + ["width", "height"], + ["top", "bottom"], + ["right", "left"], + ["on", "off"], + ["x", "y"], + ["get", "set"], + ["max", "min"], + ["horizontal", "vertical"], + ["show", "hide"], + ["add", "remove"], + ["up", "down"], + ["before", "after"], + ["even", "odd"], + ["in", "out"], + ["inside", "outside"], + ["next", "previous"], + ["increase", "decrease"], + ["attach", "detach"], + ["&&", "||"], + ["==", "!="] + ]; + + this.toggleWord = function () { + var row = this.selection.getCursor().row; + var column = this.selection.getCursor().column; + this.selection.selectWord(); + var currentState = this.getSelectedText(); + var currWordStart = this.selection.getWordRange().start.column; + var wordParts = currentState.replace(/([a-z]+|[A-Z]+)(?=[A-Z_]|$)/g, '$1 ').split(/\s/); + var delta = column - currWordStart - 1; + if (delta < 0) delta = 0; + var curLength = 0, itLength = 0; + var that = this; + if (currentState.match(/[A-Za-z0-9_]+/)) { + wordParts.forEach(function (item, i) { + itLength = curLength + item.length; + if (delta >= curLength && delta <= itLength) { + currentState = item; + that.selection.clearSelection(); + that.moveCursorTo(row, curLength + currWordStart); + that.selection.selectTo(row, itLength + currWordStart); + } + curLength = itLength; + }); + } + + var wordPairs = this.$toggleWordPairs; + var reg; + for (var i = 0; i < wordPairs.length; i++) { + var item = wordPairs[i]; + for (var j = 0; j <= 1; j++) { + var negate = +!j; + var firstCondition = currentState.match(new RegExp('^\\s?_?(' + lang.escapeRegExp(item[j]) + ')\\s?$', 'i')); + if (firstCondition) { + var secondCondition = currentState.match(new RegExp('([_]|^|\\s)(' + lang.escapeRegExp(firstCondition[1]) + ')($|\\s)', 'g')); + if (secondCondition) { + reg = currentState.replace(new RegExp(lang.escapeRegExp(item[j]), 'i'), function (result) { + var res = item[negate]; + if (result.toUpperCase() == result) { + res = res.toUpperCase(); + } else if (result.charAt(0).toUpperCase() == result.charAt(0)) { + res = res.substr(0, 0) + item[negate].charAt(0).toUpperCase() + res.substr(1); + } + return res; + }); + this.insert(reg); + reg = ""; + } + } + } + } + }; + this.removeLines = function() { + var rows = this.$getSelectedRows(); + this.session.removeFullLines(rows.first, rows.last); + this.clearSelection(); + }; + + this.duplicateSelection = function() { + var sel = this.selection; + var doc = this.session; + var range = sel.getRange(); + var reverse = sel.isBackwards(); + if (range.isEmpty()) { + var row = range.start.row; + doc.duplicateLines(row, row); + } else { + var point = reverse ? range.start : range.end; + var endPoint = doc.insert(point, doc.getTextRange(range), false); + range.start = point; + range.end = endPoint; + + sel.setSelectionRange(range, reverse); + } + }; + this.moveLinesDown = function() { + this.$moveLines(1, false); + }; + this.moveLinesUp = function() { + this.$moveLines(-1, false); + }; + this.moveText = function(range, toPosition, copy) { + return this.session.moveText(range, toPosition, copy); + }; + this.copyLinesUp = function() { + this.$moveLines(-1, true); + }; + this.copyLinesDown = function() { + this.$moveLines(1, true); + }; + this.$moveLines = function(dir, copy) { + var rows, moved; + var selection = this.selection; + if (!selection.inMultiSelectMode || this.inVirtualSelectionMode) { + var range = selection.toOrientedRange(); + rows = this.$getSelectedRows(range); + moved = this.session.$moveLines(rows.first, rows.last, copy ? 0 : dir); + if (copy && dir == -1) moved = 0; + range.moveBy(moved, 0); + selection.fromOrientedRange(range); + } else { + var ranges = selection.rangeList.ranges; + selection.rangeList.detach(this.session); + this.inVirtualSelectionMode = true; + + var diff = 0; + var totalDiff = 0; + var l = ranges.length; + for (var i = 0; i < l; i++) { + var rangeIndex = i; + ranges[i].moveBy(diff, 0); + rows = this.$getSelectedRows(ranges[i]); + var first = rows.first; + var last = rows.last; + while (++i < l) { + if (totalDiff) ranges[i].moveBy(totalDiff, 0); + var subRows = this.$getSelectedRows(ranges[i]); + if (copy && subRows.first != last) + break; + else if (!copy && subRows.first > last + 1) + break; + last = subRows.last; + } + i--; + diff = this.session.$moveLines(first, last, copy ? 0 : dir); + if (copy && dir == -1) rangeIndex = i + 1; + while (rangeIndex <= i) { + ranges[rangeIndex].moveBy(diff, 0); + rangeIndex++; + } + if (!copy) diff = 0; + totalDiff += diff; + } + + selection.fromOrientedRange(selection.ranges[0]); + selection.rangeList.attach(this.session); + this.inVirtualSelectionMode = false; + } + }; + this.$getSelectedRows = function(range) { + range = (range || this.getSelectionRange()).collapseRows(); + + return { + first: this.session.getRowFoldStart(range.start.row), + last: this.session.getRowFoldEnd(range.end.row) + }; + }; + + this.onCompositionStart = function(compositionState) { + this.renderer.showComposition(compositionState); + }; + + this.onCompositionUpdate = function(text) { + this.renderer.setCompositionText(text); + }; + + this.onCompositionEnd = function() { + this.renderer.hideComposition(); + }; + this.getFirstVisibleRow = function() { + return this.renderer.getFirstVisibleRow(); + }; + this.getLastVisibleRow = function() { + return this.renderer.getLastVisibleRow(); + }; + this.isRowVisible = function(row) { + return (row >= this.getFirstVisibleRow() && row <= this.getLastVisibleRow()); + }; + this.isRowFullyVisible = function(row) { + return (row >= this.renderer.getFirstFullyVisibleRow() && row <= this.renderer.getLastFullyVisibleRow()); + }; + this.$getVisibleRowCount = function() { + return this.renderer.getScrollBottomRow() - this.renderer.getScrollTopRow() + 1; + }; + + this.$moveByPage = function(dir, select) { + var renderer = this.renderer; + var config = this.renderer.layerConfig; + var rows = dir * Math.floor(config.height / config.lineHeight); + + if (select === true) { + this.selection.$moveSelection(function(){ + this.moveCursorBy(rows, 0); + }); + } else if (select === false) { + this.selection.moveCursorBy(rows, 0); + this.selection.clearSelection(); + } + + var scrollTop = renderer.scrollTop; + + renderer.scrollBy(0, rows * config.lineHeight); + if (select != null) + renderer.scrollCursorIntoView(null, 0.5); + + renderer.animateScrolling(scrollTop); + }; + this.selectPageDown = function() { + this.$moveByPage(1, true); + }; + this.selectPageUp = function() { + this.$moveByPage(-1, true); + }; + this.gotoPageDown = function() { + this.$moveByPage(1, false); + }; + this.gotoPageUp = function() { + this.$moveByPage(-1, false); + }; + this.scrollPageDown = function() { + this.$moveByPage(1); + }; + this.scrollPageUp = function() { + this.$moveByPage(-1); + }; + this.scrollToRow = function(row) { + this.renderer.scrollToRow(row); + }; + this.scrollToLine = function(line, center, animate, callback) { + this.renderer.scrollToLine(line, center, animate, callback); + }; + this.centerSelection = function() { + var range = this.getSelectionRange(); + var pos = { + row: Math.floor(range.start.row + (range.end.row - range.start.row) / 2), + column: Math.floor(range.start.column + (range.end.column - range.start.column) / 2) + }; + this.renderer.alignCursor(pos, 0.5); + }; + this.getCursorPosition = function() { + return this.selection.getCursor(); + }; + this.getCursorPositionScreen = function() { + return this.session.documentToScreenPosition(this.getCursorPosition()); + }; + this.getSelectionRange = function() { + return this.selection.getRange(); + }; + this.selectAll = function() { + this.selection.selectAll(); + }; + this.clearSelection = function() { + this.selection.clearSelection(); + }; + this.moveCursorTo = function(row, column) { + this.selection.moveCursorTo(row, column); + }; + this.moveCursorToPosition = function(pos) { + this.selection.moveCursorToPosition(pos); + }; + this.jumpToMatching = function(select, expand) { + var cursor = this.getCursorPosition(); + var iterator = new TokenIterator(this.session, cursor.row, cursor.column); + var prevToken = iterator.getCurrentToken(); + var token = prevToken || iterator.stepForward(); + + if (!token) return; + var matchType; + var found = false; + var depth = {}; + var i = cursor.column - token.start; + var bracketType; + var brackets = { + ")": "(", + "(": "(", + "]": "[", + "[": "[", + "{": "{", + "}": "{" + }; + + do { + if (token.value.match(/[{}()\[\]]/g)) { + for (; i < token.value.length && !found; i++) { + if (!brackets[token.value[i]]) { + continue; + } + + bracketType = brackets[token.value[i]] + '.' + token.type.replace("rparen", "lparen"); + + if (isNaN(depth[bracketType])) { + depth[bracketType] = 0; + } + + switch (token.value[i]) { + case '(': + case '[': + case '{': + depth[bracketType]++; + break; + case ')': + case ']': + case '}': + depth[bracketType]--; + + if (depth[bracketType] === -1) { + matchType = 'bracket'; + found = true; + } + break; + } + } + } + else if (token.type.indexOf('tag-name') !== -1) { + if (isNaN(depth[token.value])) { + depth[token.value] = 0; + } + + if (prevToken.value === '<') { + depth[token.value]++; + } + else if (prevToken.value === '= 0; --i) { + if(this.$tryReplace(ranges[i], replacement)) { + replaced++; + } + } + + this.selection.setSelectionRange(selection); + + return replaced; + }; + + this.$tryReplace = function(range, replacement) { + var input = this.session.getTextRange(range); + replacement = this.$search.replace(input, replacement); + if (replacement !== null) { + range.end = this.session.replace(range, replacement); + return range; + } else { + return null; + } + }; + this.getLastSearchOptions = function() { + return this.$search.getOptions(); + }; + this.find = function(needle, options, animate) { + if (!options) + options = {}; + + if (typeof needle == "string" || needle instanceof RegExp) + options.needle = needle; + else if (typeof needle == "object") + oop.mixin(options, needle); + + var range = this.selection.getRange(); + if (options.needle == null) { + needle = this.session.getTextRange(range) + || this.$search.$options.needle; + if (!needle) { + range = this.session.getWordRange(range.start.row, range.start.column); + needle = this.session.getTextRange(range); + } + this.$search.set({needle: needle}); + } + + this.$search.set(options); + if (!options.start) + this.$search.set({start: range}); + + var newRange = this.$search.find(this.session); + if (options.preventScroll) + return newRange; + if (newRange) { + this.revealRange(newRange, animate); + return newRange; + } + if (options.backwards) + range.start = range.end; + else + range.end = range.start; + this.selection.setRange(range); + }; + this.findNext = function(options, animate) { + this.find({skipCurrent: true, backwards: false}, options, animate); + }; + this.findPrevious = function(options, animate) { + this.find(options, {skipCurrent: true, backwards: true}, animate); + }; + + this.revealRange = function(range, animate) { + this.session.unfold(range); + this.selection.setSelectionRange(range); + + var scrollTop = this.renderer.scrollTop; + this.renderer.scrollSelectionIntoView(range.start, range.end, 0.5); + if (animate !== false) + this.renderer.animateScrolling(scrollTop); + }; + this.undo = function() { + this.session.getUndoManager().undo(this.session); + this.renderer.scrollCursorIntoView(null, 0.5); + }; + this.redo = function() { + this.session.getUndoManager().redo(this.session); + this.renderer.scrollCursorIntoView(null, 0.5); + }; + this.destroy = function() { + this.renderer.destroy(); + this._signal("destroy", this); + if (this.session) { + this.session.destroy(); + } + }; + this.setAutoScrollEditorIntoView = function(enable) { + if (!enable) + return; + var rect; + var self = this; + var shouldScroll = false; + if (!this.$scrollAnchor) + this.$scrollAnchor = document.createElement("div"); + var scrollAnchor = this.$scrollAnchor; + scrollAnchor.style.cssText = "position:absolute"; + this.container.insertBefore(scrollAnchor, this.container.firstChild); + var onChangeSelection = this.on("changeSelection", function() { + shouldScroll = true; + }); + var onBeforeRender = this.renderer.on("beforeRender", function() { + if (shouldScroll) + rect = self.renderer.container.getBoundingClientRect(); + }); + var onAfterRender = this.renderer.on("afterRender", function() { + if (shouldScroll && rect && (self.isFocused() + || self.searchBox && self.searchBox.isFocused()) + ) { + var renderer = self.renderer; + var pos = renderer.$cursorLayer.$pixelPos; + var config = renderer.layerConfig; + var top = pos.top - config.offset; + if (pos.top >= 0 && top + rect.top < 0) { + shouldScroll = true; + } else if (pos.top < config.height && + pos.top + rect.top + config.lineHeight > window.innerHeight) { + shouldScroll = false; + } else { + shouldScroll = null; + } + if (shouldScroll != null) { + scrollAnchor.style.top = top + "px"; + scrollAnchor.style.left = pos.left + "px"; + scrollAnchor.style.height = config.lineHeight + "px"; + scrollAnchor.scrollIntoView(shouldScroll); + } + shouldScroll = rect = null; + } + }); + this.setAutoScrollEditorIntoView = function(enable) { + if (enable) + return; + delete this.setAutoScrollEditorIntoView; + this.off("changeSelection", onChangeSelection); + this.renderer.off("afterRender", onAfterRender); + this.renderer.off("beforeRender", onBeforeRender); + }; + }; + + + this.$resetCursorStyle = function() { + var style = this.$cursorStyle || "ace"; + var cursorLayer = this.renderer.$cursorLayer; + if (!cursorLayer) + return; + cursorLayer.setSmoothBlinking(/smooth/.test(style)); + cursorLayer.isBlinking = !this.$readOnly && style != "wide"; + dom.setCssClass(cursorLayer.element, "ace_slim-cursors", /slim/.test(style)); + }; + this.prompt = function(message, options, callback) { + var editor = this; + config.loadModule("./ext/prompt", function (module) { + module.prompt(editor, message, options, callback); + }); + }; + +}).call(Editor.prototype); + + + +config.defineOptions(Editor.prototype, "editor", { + selectionStyle: { + set: function(style) { + this.onSelectionChange(); + this._signal("changeSelectionStyle", {data: style}); + }, + initialValue: "line" + }, + highlightActiveLine: { + set: function() {this.$updateHighlightActiveLine();}, + initialValue: true + }, + highlightSelectedWord: { + set: function(shouldHighlight) {this.$onSelectionChange();}, + initialValue: true + }, + readOnly: { + set: function(readOnly) { + this.textInput.setReadOnly(readOnly); + this.$resetCursorStyle(); + }, + initialValue: false + }, + copyWithEmptySelection: { + set: function(value) { + this.textInput.setCopyWithEmptySelection(value); + }, + initialValue: false + }, + cursorStyle: { + set: function(val) { this.$resetCursorStyle(); }, + values: ["ace", "slim", "smooth", "wide"], + initialValue: "ace" + }, + mergeUndoDeltas: { + values: [false, true, "always"], + initialValue: true + }, + behavioursEnabled: {initialValue: true}, + wrapBehavioursEnabled: {initialValue: true}, + autoScrollEditorIntoView: { + set: function(val) {this.setAutoScrollEditorIntoView(val);} + }, + keyboardHandler: { + set: function(val) { this.setKeyboardHandler(val); }, + get: function() { return this.$keybindingId; }, + handlesSet: true + }, + value: { + set: function(val) { this.session.setValue(val); }, + get: function() { return this.getValue(); }, + handlesSet: true, + hidden: true + }, + session: { + set: function(val) { this.setSession(val); }, + get: function() { return this.session; }, + handlesSet: true, + hidden: true + }, + + showLineNumbers: { + set: function(show) { + this.renderer.$gutterLayer.setShowLineNumbers(show); + this.renderer.$loop.schedule(this.renderer.CHANGE_GUTTER); + if (show && this.$relativeLineNumbers) + relativeNumberRenderer.attach(this); + else + relativeNumberRenderer.detach(this); + }, + initialValue: true + }, + relativeLineNumbers: { + set: function(value) { + if (this.$showLineNumbers && value) + relativeNumberRenderer.attach(this); + else + relativeNumberRenderer.detach(this); + } + }, + placeholder: { + set: function(message) { + if (!this.$updatePlaceholder) { + this.$updatePlaceholder = function() { + var value = this.renderer.$composition || this.getValue(); + if (value && this.renderer.placeholderNode) { + this.renderer.off("afterRender", this.$updatePlaceholder); + dom.removeCssClass(this.container, "ace_hasPlaceholder"); + this.renderer.placeholderNode.remove(); + this.renderer.placeholderNode = null; + } else if (!value && !this.renderer.placeholderNode) { + this.renderer.on("afterRender", this.$updatePlaceholder); + dom.addCssClass(this.container, "ace_hasPlaceholder"); + var el = dom.createElement("div"); + el.className = "ace_placeholder"; + el.textContent = this.$placeholder || ""; + this.renderer.placeholderNode = el; + this.renderer.content.appendChild(this.renderer.placeholderNode); + } + }.bind(this); + this.on("input", this.$updatePlaceholder); + } + this.$updatePlaceholder(); + } + }, + + hScrollBarAlwaysVisible: "renderer", + vScrollBarAlwaysVisible: "renderer", + highlightGutterLine: "renderer", + animatedScroll: "renderer", + showInvisibles: "renderer", + showPrintMargin: "renderer", + printMarginColumn: "renderer", + printMargin: "renderer", + fadeFoldWidgets: "renderer", + showFoldWidgets: "renderer", + displayIndentGuides: "renderer", + showGutter: "renderer", + fontSize: "renderer", + fontFamily: "renderer", + maxLines: "renderer", + minLines: "renderer", + scrollPastEnd: "renderer", + fixedWidthGutter: "renderer", + theme: "renderer", + hasCssTransforms: "renderer", + maxPixelHeight: "renderer", + useTextareaForIME: "renderer", + + scrollSpeed: "$mouseHandler", + dragDelay: "$mouseHandler", + dragEnabled: "$mouseHandler", + focusTimeout: "$mouseHandler", + tooltipFollowsMouse: "$mouseHandler", + + firstLineNumber: "session", + overwrite: "session", + newLineMode: "session", + useWorker: "session", + useSoftTabs: "session", + navigateWithinSoftTabs: "session", + tabSize: "session", + wrap: "session", + indentedSoftWrap: "session", + foldStyle: "session", + mode: "session" +}); + + +var relativeNumberRenderer = { + getText: function(session, row) { + return (Math.abs(session.selection.lead.row - row) || (row + 1 + (row < 9 ? "\xb7" : ""))) + ""; + }, + getWidth: function(session, lastLineNumber, config) { + return Math.max( + lastLineNumber.toString().length, + (config.lastRow + 1).toString().length, + 2 + ) * config.characterWidth; + }, + update: function(e, editor) { + editor.renderer.$loop.schedule(editor.renderer.CHANGE_GUTTER); + }, + attach: function(editor) { + editor.renderer.$gutterLayer.$renderer = this; + editor.on("changeSelection", this.update); + this.update(null, editor); + }, + detach: function(editor) { + if (editor.renderer.$gutterLayer.$renderer == this) + editor.renderer.$gutterLayer.$renderer = null; + editor.off("changeSelection", this.update); + this.update(null, editor); + } +}; + +exports.Editor = Editor; +}); + +define("ace/undomanager",["require","exports","module","ace/range"], function(require, exports, module) { +"use strict"; +var UndoManager = function() { + this.$maxRev = 0; + this.$fromUndo = false; + this.reset(); +}; + +(function() { + + this.addSession = function(session) { + this.$session = session; + }; + this.add = function(delta, allowMerge, session) { + if (this.$fromUndo) return; + if (delta == this.$lastDelta) return; + if (allowMerge === false || !this.lastDeltas) { + this.lastDeltas = []; + this.$undoStack.push(this.lastDeltas); + delta.id = this.$rev = ++this.$maxRev; + } + if (delta.action == "remove" || delta.action == "insert") + this.$lastDelta = delta; + this.lastDeltas.push(delta); + }; + + this.addSelection = function(selection, rev) { + this.selections.push({ + value: selection, + rev: rev || this.$rev + }); + }; + + this.startNewGroup = function() { + this.lastDeltas = null; + return this.$rev; + }; + + this.markIgnored = function(from, to) { + if (to == null) to = this.$rev + 1; + var stack = this.$undoStack; + for (var i = stack.length; i--;) { + var delta = stack[i][0]; + if (delta.id <= from) + break; + if (delta.id < to) + delta.ignore = true; + } + this.lastDeltas = null; + }; + + this.getSelection = function(rev, after) { + var stack = this.selections; + for (var i = stack.length; i--;) { + var selection = stack[i]; + if (selection.rev < rev) { + if (after) + selection = stack[i + 1]; + return selection; + } + } + }; + + this.getRevision = function() { + return this.$rev; + }; + + this.getDeltas = function(from, to) { + if (to == null) to = this.$rev + 1; + var stack = this.$undoStack; + var end = null, start = 0; + for (var i = stack.length; i--;) { + var delta = stack[i][0]; + if (delta.id < to && !end) + end = i+1; + if (delta.id <= from) { + start = i + 1; + break; + } + } + return stack.slice(start, end); + }; + + this.getChangedRanges = function(from, to) { + if (to == null) to = this.$rev + 1; + + }; + + this.getChangedLines = function(from, to) { + if (to == null) to = this.$rev + 1; + + }; + this.undo = function(session, dontSelect) { + this.lastDeltas = null; + var stack = this.$undoStack; + + if (!rearrangeUndoStack(stack, stack.length)) + return; + + if (!session) + session = this.$session; + + if (this.$redoStackBaseRev !== this.$rev && this.$redoStack.length) + this.$redoStack = []; + + this.$fromUndo = true; + + var deltaSet = stack.pop(); + var undoSelectionRange = null; + if (deltaSet && deltaSet.length) { + undoSelectionRange = session.undoChanges(deltaSet, dontSelect); + this.$redoStack.push(deltaSet); + this.$syncRev(); + } + + this.$fromUndo = false; + + return undoSelectionRange; + }; + this.redo = function(session, dontSelect) { + this.lastDeltas = null; + + if (!session) + session = this.$session; + + this.$fromUndo = true; + if (this.$redoStackBaseRev != this.$rev) { + var diff = this.getDeltas(this.$redoStackBaseRev, this.$rev + 1); + rebaseRedoStack(this.$redoStack, diff); + this.$redoStackBaseRev = this.$rev; + this.$redoStack.forEach(function(x) { + x[0].id = ++this.$maxRev; + }, this); + } + var deltaSet = this.$redoStack.pop(); + var redoSelectionRange = null; + + if (deltaSet) { + redoSelectionRange = session.redoChanges(deltaSet, dontSelect); + this.$undoStack.push(deltaSet); + this.$syncRev(); + } + this.$fromUndo = false; + + return redoSelectionRange; + }; + + this.$syncRev = function() { + var stack = this.$undoStack; + var nextDelta = stack[stack.length - 1]; + var id = nextDelta && nextDelta[0].id || 0; + this.$redoStackBaseRev = id; + this.$rev = id; + }; + this.reset = function() { + this.lastDeltas = null; + this.$lastDelta = null; + this.$undoStack = []; + this.$redoStack = []; + this.$rev = 0; + this.mark = 0; + this.$redoStackBaseRev = this.$rev; + this.selections = []; + }; + this.canUndo = function() { + return this.$undoStack.length > 0; + }; + this.canRedo = function() { + return this.$redoStack.length > 0; + }; + this.bookmark = function(rev) { + if (rev == undefined) + rev = this.$rev; + this.mark = rev; + }; + this.isAtBookmark = function() { + return this.$rev === this.mark; + }; + + this.toJSON = function() { + + }; + + this.fromJSON = function() { + + }; + + this.hasUndo = this.canUndo; + this.hasRedo = this.canRedo; + this.isClean = this.isAtBookmark; + this.markClean = this.bookmark; + + this.$prettyPrint = function(delta) { + if (delta) return stringifyDelta(delta); + return stringifyDelta(this.$undoStack) + "\n---\n" + stringifyDelta(this.$redoStack); + }; +}).call(UndoManager.prototype); + +function rearrangeUndoStack(stack, pos) { + for (var i = pos; i--; ) { + var deltaSet = stack[i]; + if (deltaSet && !deltaSet[0].ignore) { + while(i < pos - 1) { + var swapped = swapGroups(stack[i], stack[i + 1]); + stack[i] = swapped[0]; + stack[i + 1] = swapped[1]; + i++; + } + return true; + } + } +} + +var Range = require("./range").Range; +var cmp = Range.comparePoints; +var comparePoints = Range.comparePoints; + +function $updateMarkers(delta) { + var isInsert = delta.action == "insert"; + var start = delta.start; + var end = delta.end; + var rowShift = (end.row - start.row) * (isInsert ? 1 : -1); + var colShift = (end.column - start.column) * (isInsert ? 1 : -1); + if (isInsert) end = start; + + for (var i in this.marks) { + var point = this.marks[i]; + var cmp = comparePoints(point, start); + if (cmp < 0) { + continue; // delta starts after the range + } + if (cmp === 0) { + if (isInsert) { + if (point.bias == 1) { + cmp = 1; + } + else { + point.bias == -1; + continue; + } + } + } + var cmp2 = isInsert ? cmp : comparePoints(point, end); + if (cmp2 > 0) { + point.row += rowShift; + point.column += point.row == end.row ? colShift : 0; + continue; + } + if (!isInsert && cmp2 <= 0) { + point.row = start.row; + point.column = start.column; + if (cmp2 === 0) + point.bias = 1; + } + } +} + + + +function clonePos(pos) { + return {row: pos.row,column: pos.column}; +} +function cloneDelta(d) { + return { + start: clonePos(d.start), + end: clonePos(d.end), + action: d.action, + lines: d.lines.slice() + }; +} +function stringifyDelta(d) { + d = d || this; + if (Array.isArray(d)) { + return d.map(stringifyDelta).join("\n"); + } + var type = ""; + if (d.action) { + type = d.action == "insert" ? "+" : "-"; + type += "[" + d.lines + "]"; + } else if (d.value) { + if (Array.isArray(d.value)) { + type = d.value.map(stringifyRange).join("\n"); + } else { + type = stringifyRange(d.value); + } + } + if (d.start) { + type += stringifyRange(d); + } + if (d.id || d.rev) { + type += "\t(" + (d.id || d.rev) + ")"; + } + return type; +} +function stringifyRange(r) { + return r.start.row + ":" + r.start.column + + "=>" + r.end.row + ":" + r.end.column; +} + +function swap(d1, d2) { + var i1 = d1.action == "insert"; + var i2 = d2.action == "insert"; + + if (i1 && i2) { + if (cmp(d2.start, d1.end) >= 0) { + shift(d2, d1, -1); + } else if (cmp(d2.start, d1.start) <= 0) { + shift(d1, d2, +1); + } else { + return null; + } + } else if (i1 && !i2) { + if (cmp(d2.start, d1.end) >= 0) { + shift(d2, d1, -1); + } else if (cmp(d2.end, d1.start) <= 0) { + shift(d1, d2, -1); + } else { + return null; + } + } else if (!i1 && i2) { + if (cmp(d2.start, d1.start) >= 0) { + shift(d2, d1, +1); + } else if (cmp(d2.start, d1.start) <= 0) { + shift(d1, d2, +1); + } else { + return null; + } + } else if (!i1 && !i2) { + if (cmp(d2.start, d1.start) >= 0) { + shift(d2, d1, +1); + } else if (cmp(d2.end, d1.start) <= 0) { + shift(d1, d2, -1); + } else { + return null; + } + } + return [d2, d1]; +} +function swapGroups(ds1, ds2) { + for (var i = ds1.length; i--; ) { + for (var j = 0; j < ds2.length; j++) { + if (!swap(ds1[i], ds2[j])) { + while (i < ds1.length) { + while (j--) { + swap(ds2[j], ds1[i]); + } + j = ds2.length; + i++; + } + return [ds1, ds2]; + } + } + } + ds1.selectionBefore = ds2.selectionBefore = + ds1.selectionAfter = ds2.selectionAfter = null; + return [ds2, ds1]; +} +function xform(d1, c1) { + var i1 = d1.action == "insert"; + var i2 = c1.action == "insert"; + + if (i1 && i2) { + if (cmp(d1.start, c1.start) < 0) { + shift(c1, d1, 1); + } else { + shift(d1, c1, 1); + } + } else if (i1 && !i2) { + if (cmp(d1.start, c1.end) >= 0) { + shift(d1, c1, -1); + } else if (cmp(d1.start, c1.start) <= 0) { + shift(c1, d1, +1); + } else { + shift(d1, Range.fromPoints(c1.start, d1.start), -1); + shift(c1, d1, +1); + } + } else if (!i1 && i2) { + if (cmp(c1.start, d1.end) >= 0) { + shift(c1, d1, -1); + } else if (cmp(c1.start, d1.start) <= 0) { + shift(d1, c1, +1); + } else { + shift(c1, Range.fromPoints(d1.start, c1.start), -1); + shift(d1, c1, +1); + } + } else if (!i1 && !i2) { + if (cmp(c1.start, d1.end) >= 0) { + shift(c1, d1, -1); + } else if (cmp(c1.end, d1.start) <= 0) { + shift(d1, c1, -1); + } else { + var before, after; + if (cmp(d1.start, c1.start) < 0) { + before = d1; + d1 = splitDelta(d1, c1.start); + } + if (cmp(d1.end, c1.end) > 0) { + after = splitDelta(d1, c1.end); + } + + shiftPos(c1.end, d1.start, d1.end, -1); + if (after && !before) { + d1.lines = after.lines; + d1.start = after.start; + d1.end = after.end; + after = d1; + } + + return [c1, before, after].filter(Boolean); + } + } + return [c1, d1]; +} + +function shift(d1, d2, dir) { + shiftPos(d1.start, d2.start, d2.end, dir); + shiftPos(d1.end, d2.start, d2.end, dir); +} +function shiftPos(pos, start, end, dir) { + if (pos.row == (dir == 1 ? start : end).row) { + pos.column += dir * (end.column - start.column); + } + pos.row += dir * (end.row - start.row); +} +function splitDelta(c, pos) { + var lines = c.lines; + var end = c.end; + c.end = clonePos(pos); + var rowsBefore = c.end.row - c.start.row; + var otherLines = lines.splice(rowsBefore, lines.length); + + var col = rowsBefore ? pos.column : pos.column - c.start.column; + lines.push(otherLines[0].substring(0, col)); + otherLines[0] = otherLines[0].substr(col) ; + var rest = { + start: clonePos(pos), + end: end, + lines: otherLines, + action: c.action + }; + return rest; +} + +function moveDeltasByOne(redoStack, d) { + d = cloneDelta(d); + for (var j = redoStack.length; j--;) { + var deltaSet = redoStack[j]; + for (var i = 0; i < deltaSet.length; i++) { + var x = deltaSet[i]; + var xformed = xform(x, d); + d = xformed[0]; + if (xformed.length != 2) { + if (xformed[2]) { + deltaSet.splice(i + 1, 1, xformed[1], xformed[2]); + i++; + } else if (!xformed[1]) { + deltaSet.splice(i, 1); + i--; + } + } + } + if (!deltaSet.length) { + redoStack.splice(j, 1); + } + } + return redoStack; +} +function rebaseRedoStack(redoStack, deltaSets) { + for (var i = 0; i < deltaSets.length; i++) { + var deltas = deltaSets[i]; + for (var j = 0; j < deltas.length; j++) { + moveDeltasByOne(redoStack, deltas[j]); + } + } +} + +exports.UndoManager = UndoManager; + +}); + +define("ace/layer/lines",["require","exports","module","ace/lib/dom"], function(require, exports, module) { +"use strict"; + +var dom = require("../lib/dom"); + +var Lines = function(element, canvasHeight) { + this.element = element; + this.canvasHeight = canvasHeight || 500000; + this.element.style.height = (this.canvasHeight * 2) + "px"; + + this.cells = []; + this.cellCache = []; + this.$offsetCoefficient = 0; +}; + +(function() { + + this.moveContainer = function(config) { + dom.translate(this.element, 0, -((config.firstRowScreen * config.lineHeight) % this.canvasHeight) - config.offset * this.$offsetCoefficient); + }; + + this.pageChanged = function(oldConfig, newConfig) { + return ( + Math.floor((oldConfig.firstRowScreen * oldConfig.lineHeight) / this.canvasHeight) !== + Math.floor((newConfig.firstRowScreen * newConfig.lineHeight) / this.canvasHeight) + ); + }; + + this.computeLineTop = function(row, config, session) { + var screenTop = config.firstRowScreen * config.lineHeight; + var screenPage = Math.floor(screenTop / this.canvasHeight); + var lineTop = session.documentToScreenRow(row, 0) * config.lineHeight; + return lineTop - (screenPage * this.canvasHeight); + }; + + this.computeLineHeight = function(row, config, session) { + return config.lineHeight * session.getRowLength(row); + }; + + this.getLength = function() { + return this.cells.length; + }; + + this.get = function(index) { + return this.cells[index]; + }; + + this.shift = function() { + this.$cacheCell(this.cells.shift()); + }; + + this.pop = function() { + this.$cacheCell(this.cells.pop()); + }; + + this.push = function(cell) { + if (Array.isArray(cell)) { + this.cells.push.apply(this.cells, cell); + var fragment = dom.createFragment(this.element); + for (var i=0; i foldStart) { + row = fold.end.row + 1; + fold = session.getNextFoldLine(row, fold); + foldStart = fold ? fold.start.row : Infinity; + } + if (row > lastRow) { + while (this.$lines.getLength() > index + 1) + this.$lines.pop(); + + break; + } + + cell = this.$lines.get(++index); + if (cell) { + cell.row = row; + } else { + cell = this.$lines.createCell(row, config, this.session, onCreateCell); + this.$lines.push(cell); + } + + this.$renderCell(cell, config, fold, row); + row++; + } + + this._signal("afterRender"); + this.$updateGutterWidth(config); + }; + + this.$updateGutterWidth = function(config) { + var session = this.session; + + var gutterRenderer = session.gutterRenderer || this.$renderer; + + var firstLineNumber = session.$firstLineNumber; + var lastLineText = this.$lines.last() ? this.$lines.last().text : ""; + + if (this.$fixedWidth || session.$useWrapMode) + lastLineText = session.getLength() + firstLineNumber - 1; + + var gutterWidth = gutterRenderer + ? gutterRenderer.getWidth(session, lastLineText, config) + : lastLineText.toString().length * config.characterWidth; + + var padding = this.$padding || this.$computePadding(); + gutterWidth += padding.left + padding.right; + if (gutterWidth !== this.gutterWidth && !isNaN(gutterWidth)) { + this.gutterWidth = gutterWidth; + this.element.parentNode.style.width = + this.element.style.width = Math.ceil(this.gutterWidth) + "px"; + this._signal("changeGutterWidth", gutterWidth); + } + }; + + this.$updateCursorRow = function() { + if (!this.$highlightGutterLine) + return; + + var position = this.session.selection.getCursor(); + if (this.$cursorRow === position.row) + return; + + this.$cursorRow = position.row; + }; + + this.updateLineHighlight = function() { + if (!this.$highlightGutterLine) + return; + var row = this.session.selection.cursor.row; + this.$cursorRow = row; + + if (this.$cursorCell && this.$cursorCell.row == row) + return; + if (this.$cursorCell) + this.$cursorCell.element.className = this.$cursorCell.element.className.replace("ace_gutter-active-line ", ""); + var cells = this.$lines.cells; + this.$cursorCell = null; + for (var i = 0; i < cells.length; i++) { + var cell = cells[i]; + if (cell.row >= this.$cursorRow) { + if (cell.row > this.$cursorRow) { + var fold = this.session.getFoldLine(this.$cursorRow); + if (i > 0 && fold && fold.start.row == cells[i - 1].row) + cell = cells[i - 1]; + else + break; + } + cell.element.className = "ace_gutter-active-line " + cell.element.className; + this.$cursorCell = cell; + break; + } + } + }; + + this.scrollLines = function(config) { + var oldConfig = this.config; + this.config = config; + + this.$updateCursorRow(); + if (this.$lines.pageChanged(oldConfig, config)) + return this.update(config); + + this.$lines.moveContainer(config); + + var lastRow = Math.min(config.lastRow + config.gutterOffset, // needed to compensate for hor scollbar + this.session.getLength() - 1); + var oldLastRow = this.oldLastRow; + this.oldLastRow = lastRow; + + if (!oldConfig || oldLastRow < config.firstRow) + return this.update(config); + + if (lastRow < oldConfig.firstRow) + return this.update(config); + + if (oldConfig.firstRow < config.firstRow) + for (var row=this.session.getFoldedRowCount(oldConfig.firstRow, config.firstRow - 1); row>0; row--) + this.$lines.shift(); + + if (oldLastRow > lastRow) + for (var row=this.session.getFoldedRowCount(lastRow + 1, oldLastRow); row>0; row--) + this.$lines.pop(); + + if (config.firstRow < oldConfig.firstRow) { + this.$lines.unshift(this.$renderLines(config, config.firstRow, oldConfig.firstRow - 1)); + } + + if (lastRow > oldLastRow) { + this.$lines.push(this.$renderLines(config, oldLastRow + 1, lastRow)); + } + + this.updateLineHighlight(); + + this._signal("afterRender"); + this.$updateGutterWidth(config); + }; + + this.$renderLines = function(config, firstRow, lastRow) { + var fragment = []; + var row = firstRow; + var foldLine = this.session.getNextFoldLine(row); + var foldStart = foldLine ? foldLine.start.row : Infinity; + + while (true) { + if (row > foldStart) { + row = foldLine.end.row+1; + foldLine = this.session.getNextFoldLine(row, foldLine); + foldStart = foldLine ? foldLine.start.row : Infinity; + } + if (row > lastRow) + break; + + var cell = this.$lines.createCell(row, config, this.session, onCreateCell); + this.$renderCell(cell, config, foldLine, row); + fragment.push(cell); + + row++; + } + return fragment; + }; + + this.$renderCell = function(cell, config, fold, row) { + var element = cell.element; + + var session = this.session; + + var textNode = element.childNodes[0]; + var foldWidget = element.childNodes[1]; + + var firstLineNumber = session.$firstLineNumber; + + var breakpoints = session.$breakpoints; + var decorations = session.$decorations; + var gutterRenderer = session.gutterRenderer || this.$renderer; + var foldWidgets = this.$showFoldWidgets && session.foldWidgets; + var foldStart = fold ? fold.start.row : Number.MAX_VALUE; + + var className = "ace_gutter-cell "; + if (this.$highlightGutterLine) { + if (row == this.$cursorRow || (fold && row < this.$cursorRow && row >= foldStart && this.$cursorRow <= fold.end.row)) { + className += "ace_gutter-active-line "; + if (this.$cursorCell != cell) { + if (this.$cursorCell) + this.$cursorCell.element.className = this.$cursorCell.element.className.replace("ace_gutter-active-line ", ""); + this.$cursorCell = cell; + } + } + } + + if (breakpoints[row]) + className += breakpoints[row]; + if (decorations[row]) + className += decorations[row]; + if (this.$annotations[row]) + className += this.$annotations[row].className; + if (element.className != className) + element.className = className; + + if (foldWidgets) { + var c = foldWidgets[row]; + if (c == null) + c = foldWidgets[row] = session.getFoldWidget(row); + } + + if (c) { + var className = "ace_fold-widget ace_" + c; + if (c == "start" && row == foldStart && row < fold.end.row) + className += " ace_closed"; + else + className += " ace_open"; + if (foldWidget.className != className) + foldWidget.className = className; + + var foldHeight = config.lineHeight + "px"; + dom.setStyle(foldWidget.style, "height", foldHeight); + dom.setStyle(foldWidget.style, "display", "inline-block"); + } else { + if (foldWidget) { + dom.setStyle(foldWidget.style, "display", "none"); + } + } + + var text = (gutterRenderer + ? gutterRenderer.getText(session, row) + : row + firstLineNumber).toString(); + + if (text !== textNode.data) { + textNode.data = text; + } + + dom.setStyle(cell.element.style, "height", this.$lines.computeLineHeight(row, config, session) + "px"); + dom.setStyle(cell.element.style, "top", this.$lines.computeLineTop(row, config, session) + "px"); + + cell.text = text; + return cell; + }; + + this.$fixedWidth = false; + + this.$highlightGutterLine = true; + this.$renderer = ""; + this.setHighlightGutterLine = function(highlightGutterLine) { + this.$highlightGutterLine = highlightGutterLine; + }; + + this.$showLineNumbers = true; + this.$renderer = ""; + this.setShowLineNumbers = function(show) { + this.$renderer = !show && { + getWidth: function() {return 0;}, + getText: function() {return "";} + }; + }; + + this.getShowLineNumbers = function() { + return this.$showLineNumbers; + }; + + this.$showFoldWidgets = true; + this.setShowFoldWidgets = function(show) { + if (show) + dom.addCssClass(this.element, "ace_folding-enabled"); + else + dom.removeCssClass(this.element, "ace_folding-enabled"); + + this.$showFoldWidgets = show; + this.$padding = null; + }; + + this.getShowFoldWidgets = function() { + return this.$showFoldWidgets; + }; + + this.$computePadding = function() { + if (!this.element.firstChild) + return {left: 0, right: 0}; + var style = dom.computedStyle(this.element.firstChild); + this.$padding = {}; + this.$padding.left = (parseInt(style.borderLeftWidth) || 0) + + (parseInt(style.paddingLeft) || 0) + 1; + this.$padding.right = (parseInt(style.borderRightWidth) || 0) + + (parseInt(style.paddingRight) || 0); + return this.$padding; + }; + + this.getRegion = function(point) { + var padding = this.$padding || this.$computePadding(); + var rect = this.element.getBoundingClientRect(); + if (point.x < padding.left + rect.left) + return "markers"; + if (this.$showFoldWidgets && point.x > rect.right - padding.right) + return "foldWidgets"; + }; + +}).call(Gutter.prototype); + +function onCreateCell(element) { + var textNode = document.createTextNode(''); + element.appendChild(textNode); + + var foldWidget = dom.createElement("span"); + element.appendChild(foldWidget); + + return element; +} + +exports.Gutter = Gutter; + +}); + +define("ace/layer/marker",["require","exports","module","ace/range","ace/lib/dom"], function(require, exports, module) { +"use strict"; + +var Range = require("../range").Range; +var dom = require("../lib/dom"); + +var Marker = function(parentEl) { + this.element = dom.createElement("div"); + this.element.className = "ace_layer ace_marker-layer"; + parentEl.appendChild(this.element); +}; + +(function() { + + this.$padding = 0; + + this.setPadding = function(padding) { + this.$padding = padding; + }; + this.setSession = function(session) { + this.session = session; + }; + + this.setMarkers = function(markers) { + this.markers = markers; + }; + + this.elt = function(className, css) { + var x = this.i != -1 && this.element.childNodes[this.i]; + if (!x) { + x = document.createElement("div"); + this.element.appendChild(x); + this.i = -1; + } else { + this.i++; + } + x.style.cssText = css; + x.className = className; + }; + + this.update = function(config) { + if (!config) return; + + this.config = config; + + this.i = 0; + var html; + for (var key in this.markers) { + var marker = this.markers[key]; + + if (!marker.range) { + marker.update(html, this, this.session, config); + continue; + } + + var range = marker.range.clipRows(config.firstRow, config.lastRow); + if (range.isEmpty()) continue; + + range = range.toScreenRange(this.session); + if (marker.renderer) { + var top = this.$getTop(range.start.row, config); + var left = this.$padding + range.start.column * config.characterWidth; + marker.renderer(html, range, left, top, config); + } else if (marker.type == "fullLine") { + this.drawFullLineMarker(html, range, marker.clazz, config); + } else if (marker.type == "screenLine") { + this.drawScreenLineMarker(html, range, marker.clazz, config); + } else if (range.isMultiLine()) { + if (marker.type == "text") + this.drawTextMarker(html, range, marker.clazz, config); + else + this.drawMultiLineMarker(html, range, marker.clazz, config); + } else { + this.drawSingleLineMarker(html, range, marker.clazz + " ace_start" + " ace_br15", config); + } + } + if (this.i !=-1) { + while (this.i < this.element.childElementCount) + this.element.removeChild(this.element.lastChild); + } + }; + + this.$getTop = function(row, layerConfig) { + return (row - layerConfig.firstRowScreen) * layerConfig.lineHeight; + }; + + function getBorderClass(tl, tr, br, bl) { + return (tl ? 1 : 0) | (tr ? 2 : 0) | (br ? 4 : 0) | (bl ? 8 : 0); + } + this.drawTextMarker = function(stringBuilder, range, clazz, layerConfig, extraStyle) { + var session = this.session; + var start = range.start.row; + var end = range.end.row; + var row = start; + var prev = 0; + var curr = 0; + var next = session.getScreenLastRowColumn(row); + var lineRange = new Range(row, range.start.column, row, curr); + for (; row <= end; row++) { + lineRange.start.row = lineRange.end.row = row; + lineRange.start.column = row == start ? range.start.column : session.getRowWrapIndent(row); + lineRange.end.column = next; + prev = curr; + curr = next; + next = row + 1 < end ? session.getScreenLastRowColumn(row + 1) : row == end ? 0 : range.end.column; + this.drawSingleLineMarker(stringBuilder, lineRange, + clazz + (row == start ? " ace_start" : "") + " ace_br" + + getBorderClass(row == start || row == start + 1 && range.start.column, prev < curr, curr > next, row == end), + layerConfig, row == end ? 0 : 1, extraStyle); + } + }; + this.drawMultiLineMarker = function(stringBuilder, range, clazz, config, extraStyle) { + var padding = this.$padding; + var height = config.lineHeight; + var top = this.$getTop(range.start.row, config); + var left = padding + range.start.column * config.characterWidth; + extraStyle = extraStyle || ""; + + if (this.session.$bidiHandler.isBidiRow(range.start.row)) { + var range1 = range.clone(); + range1.end.row = range1.start.row; + range1.end.column = this.session.getLine(range1.start.row).length; + this.drawBidiSingleLineMarker(stringBuilder, range1, clazz + " ace_br1 ace_start", config, null, extraStyle); + } else { + this.elt( + clazz + " ace_br1 ace_start", + "height:"+ height+ "px;"+ "right:0;"+ "top:"+top+ "px;left:"+ left+ "px;" + (extraStyle || "") + ); + } + if (this.session.$bidiHandler.isBidiRow(range.end.row)) { + var range1 = range.clone(); + range1.start.row = range1.end.row; + range1.start.column = 0; + this.drawBidiSingleLineMarker(stringBuilder, range1, clazz + " ace_br12", config, null, extraStyle); + } else { + top = this.$getTop(range.end.row, config); + var width = range.end.column * config.characterWidth; + + this.elt( + clazz + " ace_br12", + "height:"+ height+ "px;"+ + "width:"+ width+ "px;"+ + "top:"+ top+ "px;"+ + "left:"+ padding+ "px;"+ (extraStyle || "") + ); + } + height = (range.end.row - range.start.row - 1) * config.lineHeight; + if (height <= 0) + return; + top = this.$getTop(range.start.row + 1, config); + + var radiusClass = (range.start.column ? 1 : 0) | (range.end.column ? 0 : 8); + + this.elt( + clazz + (radiusClass ? " ace_br" + radiusClass : ""), + "height:"+ height+ "px;"+ + "right:0;"+ + "top:"+ top+ "px;"+ + "left:"+ padding+ "px;"+ (extraStyle || "") + ); + }; + this.drawSingleLineMarker = function(stringBuilder, range, clazz, config, extraLength, extraStyle) { + if (this.session.$bidiHandler.isBidiRow(range.start.row)) + return this.drawBidiSingleLineMarker(stringBuilder, range, clazz, config, extraLength, extraStyle); + var height = config.lineHeight; + var width = (range.end.column + (extraLength || 0) - range.start.column) * config.characterWidth; + + var top = this.$getTop(range.start.row, config); + var left = this.$padding + range.start.column * config.characterWidth; + + this.elt( + clazz, + "height:"+ height+ "px;"+ + "width:"+ width+ "px;"+ + "top:"+ top+ "px;"+ + "left:"+ left+ "px;"+ (extraStyle || "") + ); + }; + this.drawBidiSingleLineMarker = function(stringBuilder, range, clazz, config, extraLength, extraStyle) { + var height = config.lineHeight, top = this.$getTop(range.start.row, config), padding = this.$padding; + var selections = this.session.$bidiHandler.getSelections(range.start.column, range.end.column); + + selections.forEach(function(selection) { + this.elt( + clazz, + "height:" + height + "px;" + + "width:" + selection.width + (extraLength || 0) + "px;" + + "top:" + top + "px;" + + "left:" + (padding + selection.left) + "px;" + (extraStyle || "") + ); + }, this); + }; + + this.drawFullLineMarker = function(stringBuilder, range, clazz, config, extraStyle) { + var top = this.$getTop(range.start.row, config); + var height = config.lineHeight; + if (range.start.row != range.end.row) + height += this.$getTop(range.end.row, config) - top; + + this.elt( + clazz, + "height:"+ height+ "px;"+ + "top:"+ top+ "px;"+ + "left:0;right:0;"+ (extraStyle || "") + ); + }; + + this.drawScreenLineMarker = function(stringBuilder, range, clazz, config, extraStyle) { + var top = this.$getTop(range.start.row, config); + var height = config.lineHeight; + + this.elt( + clazz, + "height:"+ height+ "px;"+ + "top:"+ top+ "px;"+ + "left:0;right:0;"+ (extraStyle || "") + ); + }; + +}).call(Marker.prototype); + +exports.Marker = Marker; + +}); + +define("ace/layer/text",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/layer/lines","ace/lib/event_emitter"], function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var dom = require("../lib/dom"); +var lang = require("../lib/lang"); +var Lines = require("./lines").Lines; +var EventEmitter = require("../lib/event_emitter").EventEmitter; + +var Text = function(parentEl) { + this.dom = dom; + this.element = this.dom.createElement("div"); + this.element.className = "ace_layer ace_text-layer"; + parentEl.appendChild(this.element); + this.$updateEolChar = this.$updateEolChar.bind(this); + this.$lines = new Lines(this.element); +}; + +(function() { + + oop.implement(this, EventEmitter); + + this.EOF_CHAR = "\xB6"; + this.EOL_CHAR_LF = "\xAC"; + this.EOL_CHAR_CRLF = "\xa4"; + this.EOL_CHAR = this.EOL_CHAR_LF; + this.TAB_CHAR = "\u2014"; //"\u21E5"; + this.SPACE_CHAR = "\xB7"; + this.$padding = 0; + this.MAX_LINE_LENGTH = 10000; + + this.$updateEolChar = function() { + var doc = this.session.doc; + var unixMode = doc.getNewLineCharacter() == "\n" && doc.getNewLineMode() != "windows"; + var EOL_CHAR = unixMode ? this.EOL_CHAR_LF : this.EOL_CHAR_CRLF; + if (this.EOL_CHAR != EOL_CHAR) { + this.EOL_CHAR = EOL_CHAR; + return true; + } + }; + + this.setPadding = function(padding) { + this.$padding = padding; + this.element.style.margin = "0 " + padding + "px"; + }; + + this.getLineHeight = function() { + return this.$fontMetrics.$characterSize.height || 0; + }; + + this.getCharacterWidth = function() { + return this.$fontMetrics.$characterSize.width || 0; + }; + + this.$setFontMetrics = function(measure) { + this.$fontMetrics = measure; + this.$fontMetrics.on("changeCharacterSize", function(e) { + this._signal("changeCharacterSize", e); + }.bind(this)); + this.$pollSizeChanges(); + }; + + this.checkForSizeChanges = function() { + this.$fontMetrics.checkForSizeChanges(); + }; + this.$pollSizeChanges = function() { + return this.$pollSizeChangesTimer = this.$fontMetrics.$pollSizeChanges(); + }; + this.setSession = function(session) { + this.session = session; + if (session) + this.$computeTabString(); + }; + + this.showInvisibles = false; + this.setShowInvisibles = function(showInvisibles) { + if (this.showInvisibles == showInvisibles) + return false; + + this.showInvisibles = showInvisibles; + this.$computeTabString(); + return true; + }; + + this.displayIndentGuides = true; + this.setDisplayIndentGuides = function(display) { + if (this.displayIndentGuides == display) + return false; + + this.displayIndentGuides = display; + this.$computeTabString(); + return true; + }; + + this.$tabStrings = []; + this.onChangeTabSize = + this.$computeTabString = function() { + var tabSize = this.session.getTabSize(); + this.tabSize = tabSize; + var tabStr = this.$tabStrings = [0]; + for (var i = 1; i < tabSize + 1; i++) { + if (this.showInvisibles) { + var span = this.dom.createElement("span"); + span.className = "ace_invisible ace_invisible_tab"; + span.textContent = lang.stringRepeat(this.TAB_CHAR, i); + tabStr.push(span); + } else { + tabStr.push(this.dom.createTextNode(lang.stringRepeat(" ", i), this.element)); + } + } + if (this.displayIndentGuides) { + this.$indentGuideRe = /\s\S| \t|\t |\s$/; + var className = "ace_indent-guide"; + var spaceClass = ""; + var tabClass = ""; + if (this.showInvisibles) { + className += " ace_invisible"; + spaceClass = " ace_invisible_space"; + tabClass = " ace_invisible_tab"; + var spaceContent = lang.stringRepeat(this.SPACE_CHAR, this.tabSize); + var tabContent = lang.stringRepeat(this.TAB_CHAR, this.tabSize); + } else { + var spaceContent = lang.stringRepeat(" ", this.tabSize); + var tabContent = spaceContent; + } + + var span = this.dom.createElement("span"); + span.className = className + spaceClass; + span.textContent = spaceContent; + this.$tabStrings[" "] = span; + + var span = this.dom.createElement("span"); + span.className = className + tabClass; + span.textContent = tabContent; + this.$tabStrings["\t"] = span; + } + }; + + this.updateLines = function(config, firstRow, lastRow) { + if (this.config.lastRow != config.lastRow || + this.config.firstRow != config.firstRow) { + return this.update(config); + } + + this.config = config; + + var first = Math.max(firstRow, config.firstRow); + var last = Math.min(lastRow, config.lastRow); + + var lineElements = this.element.childNodes; + var lineElementsIdx = 0; + + for (var row = config.firstRow; row < first; row++) { + var foldLine = this.session.getFoldLine(row); + if (foldLine) { + if (foldLine.containsRow(first)) { + first = foldLine.start.row; + break; + } else { + row = foldLine.end.row; + } + } + lineElementsIdx ++; + } + + var heightChanged = false; + var row = first; + var foldLine = this.session.getNextFoldLine(row); + var foldStart = foldLine ? foldLine.start.row : Infinity; + + while (true) { + if (row > foldStart) { + row = foldLine.end.row+1; + foldLine = this.session.getNextFoldLine(row, foldLine); + foldStart = foldLine ? foldLine.start.row :Infinity; + } + if (row > last) + break; + + var lineElement = lineElements[lineElementsIdx++]; + if (lineElement) { + this.dom.removeChildren(lineElement); + this.$renderLine( + lineElement, row, row == foldStart ? foldLine : false + ); + + if (heightChanged) + lineElement.style.top = this.$lines.computeLineTop(row, config, this.session) + "px"; + + var height = (config.lineHeight * this.session.getRowLength(row)) + "px"; + if (lineElement.style.height != height) { + heightChanged = true; + lineElement.style.height = height; + } + } + row++; + } + if (heightChanged) { + while (lineElementsIdx < this.$lines.cells.length) { + var cell = this.$lines.cells[lineElementsIdx++]; + cell.element.style.top = this.$lines.computeLineTop(cell.row, config, this.session) + "px"; + } + } + }; + + this.scrollLines = function(config) { + var oldConfig = this.config; + this.config = config; + + if (this.$lines.pageChanged(oldConfig, config)) + return this.update(config); + + this.$lines.moveContainer(config); + + var lastRow = config.lastRow; + var oldLastRow = oldConfig ? oldConfig.lastRow : -1; + + if (!oldConfig || oldLastRow < config.firstRow) + return this.update(config); + + if (lastRow < oldConfig.firstRow) + return this.update(config); + + if (!oldConfig || oldConfig.lastRow < config.firstRow) + return this.update(config); + + if (config.lastRow < oldConfig.firstRow) + return this.update(config); + + if (oldConfig.firstRow < config.firstRow) + for (var row=this.session.getFoldedRowCount(oldConfig.firstRow, config.firstRow - 1); row>0; row--) + this.$lines.shift(); + + if (oldConfig.lastRow > config.lastRow) + for (var row=this.session.getFoldedRowCount(config.lastRow + 1, oldConfig.lastRow); row>0; row--) + this.$lines.pop(); + + if (config.firstRow < oldConfig.firstRow) { + this.$lines.unshift(this.$renderLinesFragment(config, config.firstRow, oldConfig.firstRow - 1)); + } + + if (config.lastRow > oldConfig.lastRow) { + this.$lines.push(this.$renderLinesFragment(config, oldConfig.lastRow + 1, config.lastRow)); + } + }; + + this.$renderLinesFragment = function(config, firstRow, lastRow) { + var fragment = []; + var row = firstRow; + var foldLine = this.session.getNextFoldLine(row); + var foldStart = foldLine ? foldLine.start.row : Infinity; + + while (true) { + if (row > foldStart) { + row = foldLine.end.row+1; + foldLine = this.session.getNextFoldLine(row, foldLine); + foldStart = foldLine ? foldLine.start.row : Infinity; + } + if (row > lastRow) + break; + + var line = this.$lines.createCell(row, config, this.session); + + var lineEl = line.element; + this.dom.removeChildren(lineEl); + dom.setStyle(lineEl.style, "height", this.$lines.computeLineHeight(row, config, this.session) + "px"); + dom.setStyle(lineEl.style, "top", this.$lines.computeLineTop(row, config, this.session) + "px"); + this.$renderLine(lineEl, row, row == foldStart ? foldLine : false); + + if (this.$useLineGroups()) { + lineEl.className = "ace_line_group"; + } else { + lineEl.className = "ace_line"; + } + fragment.push(line); + + row++; + } + return fragment; + }; + + this.update = function(config) { + this.$lines.moveContainer(config); + + this.config = config; + + var firstRow = config.firstRow; + var lastRow = config.lastRow; + + var lines = this.$lines; + while (lines.getLength()) + lines.pop(); + + lines.push(this.$renderLinesFragment(config, firstRow, lastRow)); + }; + + this.$textToken = { + "text": true, + "rparen": true, + "lparen": true + }; + + this.$renderToken = function(parent, screenColumn, token, value) { + var self = this; + var re = /(\t)|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\uFEFF\uFFF9-\uFFFC]+)|(\u3000)|([\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3001-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]|[\uD800-\uDBFF][\uDC00-\uDFFF])/g; + + var valueFragment = this.dom.createFragment(this.element); + + var m; + var i = 0; + while (m = re.exec(value)) { + var tab = m[1]; + var simpleSpace = m[2]; + var controlCharacter = m[3]; + var cjkSpace = m[4]; + var cjk = m[5]; + + if (!self.showInvisibles && simpleSpace) + continue; + + var before = i != m.index ? value.slice(i, m.index) : ""; + + i = m.index + m[0].length; + + if (before) { + valueFragment.appendChild(this.dom.createTextNode(before, this.element)); + } + + if (tab) { + var tabSize = self.session.getScreenTabSize(screenColumn + m.index); + valueFragment.appendChild(self.$tabStrings[tabSize].cloneNode(true)); + screenColumn += tabSize - 1; + } else if (simpleSpace) { + if (self.showInvisibles) { + var span = this.dom.createElement("span"); + span.className = "ace_invisible ace_invisible_space"; + span.textContent = lang.stringRepeat(self.SPACE_CHAR, simpleSpace.length); + valueFragment.appendChild(span); + } else { + valueFragment.appendChild(this.com.createTextNode(simpleSpace, this.element)); + } + } else if (controlCharacter) { + var span = this.dom.createElement("span"); + span.className = "ace_invisible ace_invisible_space ace_invalid"; + span.textContent = lang.stringRepeat(self.SPACE_CHAR, controlCharacter.length); + valueFragment.appendChild(span); + } else if (cjkSpace) { + screenColumn += 1; + + var span = this.dom.createElement("span"); + span.style.width = (self.config.characterWidth * 2) + "px"; + span.className = self.showInvisibles ? "ace_cjk ace_invisible ace_invisible_space" : "ace_cjk"; + span.textContent = self.showInvisibles ? self.SPACE_CHAR : cjkSpace; + valueFragment.appendChild(span); + } else if (cjk) { + screenColumn += 1; + var span = this.dom.createElement("span"); + span.style.width = (self.config.characterWidth * 2) + "px"; + span.className = "ace_cjk"; + span.textContent = cjk; + valueFragment.appendChild(span); + } + } + + valueFragment.appendChild(this.dom.createTextNode(i ? value.slice(i) : value, this.element)); + + if (!this.$textToken[token.type]) { + var classes = "ace_" + token.type.replace(/\./g, " ace_"); + var span = this.dom.createElement("span"); + if (token.type == "fold") + span.style.width = (token.value.length * this.config.characterWidth) + "px"; + + span.className = classes; + span.appendChild(valueFragment); + + parent.appendChild(span); + } + else { + parent.appendChild(valueFragment); + } + + return screenColumn + value.length; + }; + + this.renderIndentGuide = function(parent, value, max) { + var cols = value.search(this.$indentGuideRe); + if (cols <= 0 || cols >= max) + return value; + if (value[0] == " ") { + cols -= cols % this.tabSize; + var count = cols/this.tabSize; + for (var i=0; i= splitChars) { + screenColumn = this.$renderToken( + lineEl, screenColumn, + token, value.substring(0, splitChars - chars) + ); + value = value.substring(splitChars - chars); + chars = splitChars; + + lineEl = this.$createLineElement(); + parent.appendChild(lineEl); + + lineEl.appendChild(this.dom.createTextNode(lang.stringRepeat("\xa0", splits.indent), this.element)); + + split ++; + screenColumn = 0; + splitChars = splits[split] || Number.MAX_VALUE; + } + if (value.length != 0) { + chars += value.length; + screenColumn = this.$renderToken( + lineEl, screenColumn, token, value + ); + } + } + } + + if (splits[splits.length - 1] > this.MAX_LINE_LENGTH) + this.$renderOverflowMessage(lineEl, screenColumn, null, "", true); + }; + + this.$renderSimpleLine = function(parent, tokens) { + var screenColumn = 0; + var token = tokens[0]; + var value = token.value; + if (this.displayIndentGuides) + value = this.renderIndentGuide(parent, value); + if (value) + screenColumn = this.$renderToken(parent, screenColumn, token, value); + for (var i = 1; i < tokens.length; i++) { + token = tokens[i]; + value = token.value; + if (screenColumn + value.length > this.MAX_LINE_LENGTH) + return this.$renderOverflowMessage(parent, screenColumn, token, value); + screenColumn = this.$renderToken(parent, screenColumn, token, value); + } + }; + + this.$renderOverflowMessage = function(parent, screenColumn, token, value, hide) { + token && this.$renderToken(parent, screenColumn, token, + value.slice(0, this.MAX_LINE_LENGTH - screenColumn)); + + var overflowEl = this.dom.createElement("span"); + overflowEl.className = "ace_inline_button ace_keyword ace_toggle_wrap"; + overflowEl.textContent = hide ? "" : ""; + + parent.appendChild(overflowEl); + }; + this.$renderLine = function(parent, row, foldLine) { + if (!foldLine && foldLine != false) + foldLine = this.session.getFoldLine(row); + + if (foldLine) + var tokens = this.$getFoldLineTokens(row, foldLine); + else + var tokens = this.session.getTokens(row); + + var lastLineEl = parent; + if (tokens.length) { + var splits = this.session.getRowSplitData(row); + if (splits && splits.length) { + this.$renderWrappedLine(parent, tokens, splits); + var lastLineEl = parent.lastChild; + } else { + var lastLineEl = parent; + if (this.$useLineGroups()) { + lastLineEl = this.$createLineElement(); + parent.appendChild(lastLineEl); + } + this.$renderSimpleLine(lastLineEl, tokens); + } + } else if (this.$useLineGroups()) { + lastLineEl = this.$createLineElement(); + parent.appendChild(lastLineEl); + } + + if (this.showInvisibles && lastLineEl) { + if (foldLine) + row = foldLine.end.row; + + var invisibleEl = this.dom.createElement("span"); + invisibleEl.className = "ace_invisible ace_invisible_eol"; + invisibleEl.textContent = row == this.session.getLength() - 1 ? this.EOF_CHAR : this.EOL_CHAR; + + lastLineEl.appendChild(invisibleEl); + } + }; + + this.$getFoldLineTokens = function(row, foldLine) { + var session = this.session; + var renderTokens = []; + + function addTokens(tokens, from, to) { + var idx = 0, col = 0; + while ((col + tokens[idx].value.length) < from) { + col += tokens[idx].value.length; + idx++; + + if (idx == tokens.length) + return; + } + if (col != from) { + var value = tokens[idx].value.substring(from - col); + if (value.length > (to - from)) + value = value.substring(0, to - from); + + renderTokens.push({ + type: tokens[idx].type, + value: value + }); + + col = from + value.length; + idx += 1; + } + + while (col < to && idx < tokens.length) { + var value = tokens[idx].value; + if (value.length + col > to) { + renderTokens.push({ + type: tokens[idx].type, + value: value.substring(0, to - col) + }); + } else + renderTokens.push(tokens[idx]); + col += value.length; + idx += 1; + } + } + + var tokens = session.getTokens(row); + foldLine.walk(function(placeholder, row, column, lastColumn, isNewRow) { + if (placeholder != null) { + renderTokens.push({ + type: "fold", + value: placeholder + }); + } else { + if (isNewRow) + tokens = session.getTokens(row); + + if (tokens.length) + addTokens(tokens, lastColumn, column); + } + }, foldLine.end.row, this.session.getLine(foldLine.end.row).length); + + return renderTokens; + }; + + this.$useLineGroups = function() { + return this.session.getUseWrapMode(); + }; + + this.destroy = function() {}; +}).call(Text.prototype); + +exports.Text = Text; + +}); + +define("ace/layer/cursor",["require","exports","module","ace/lib/dom"], function(require, exports, module) { +"use strict"; + +var dom = require("../lib/dom"); + +var Cursor = function(parentEl) { + this.element = dom.createElement("div"); + this.element.className = "ace_layer ace_cursor-layer"; + parentEl.appendChild(this.element); + + this.isVisible = false; + this.isBlinking = true; + this.blinkInterval = 1000; + this.smoothBlinking = false; + + this.cursors = []; + this.cursor = this.addCursor(); + dom.addCssClass(this.element, "ace_hidden-cursors"); + this.$updateCursors = this.$updateOpacity.bind(this); +}; + +(function() { + + this.$updateOpacity = function(val) { + var cursors = this.cursors; + for (var i = cursors.length; i--; ) + dom.setStyle(cursors[i].style, "opacity", val ? "" : "0"); + }; + + this.$startCssAnimation = function() { + var cursors = this.cursors; + for (var i = cursors.length; i--; ) + cursors[i].style.animationDuration = this.blinkInterval + "ms"; + + setTimeout(function() { + dom.addCssClass(this.element, "ace_animate-blinking"); + }.bind(this)); + }; + + this.$stopCssAnimation = function() { + dom.removeCssClass(this.element, "ace_animate-blinking"); + }; + + this.$padding = 0; + this.setPadding = function(padding) { + this.$padding = padding; + }; + + this.setSession = function(session) { + this.session = session; + }; + + this.setBlinking = function(blinking) { + if (blinking != this.isBlinking) { + this.isBlinking = blinking; + this.restartTimer(); + } + }; + + this.setBlinkInterval = function(blinkInterval) { + if (blinkInterval != this.blinkInterval) { + this.blinkInterval = blinkInterval; + this.restartTimer(); + } + }; + + this.setSmoothBlinking = function(smoothBlinking) { + if (smoothBlinking != this.smoothBlinking) { + this.smoothBlinking = smoothBlinking; + dom.setCssClass(this.element, "ace_smooth-blinking", smoothBlinking); + this.$updateCursors(true); + this.restartTimer(); + } + }; + + this.addCursor = function() { + var el = dom.createElement("div"); + el.className = "ace_cursor"; + 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.element, "ace_hidden-cursors"); + this.restartTimer(); + }; + + this.showCursor = function() { + this.isVisible = true; + dom.removeCssClass(this.element, "ace_hidden-cursors"); + this.restartTimer(); + }; + + this.restartTimer = function() { + var update = this.$updateCursors; + clearInterval(this.intervalId); + clearTimeout(this.timeoutId); + this.$stopCssAnimation(); + + if (this.smoothBlinking) { + dom.removeCssClass(this.element, "ace_smooth-blinking"); + } + + update(true); + + if (!this.isBlinking || !this.blinkInterval || !this.isVisible) { + this.$stopCssAnimation(); + return; + } + + if (this.smoothBlinking) { + setTimeout(function(){ + dom.addCssClass(this.element, "ace_smooth-blinking"); + }.bind(this)); + } + + if (dom.HAS_CSS_ANIMATION) { + this.$startCssAnimation(); + } else { + var blink = function(){ + this.timeoutId = setTimeout(function() { + update(false); + }, 0.6 * this.blinkInterval); + }.bind(this); + + this.intervalId = setInterval(function() { + update(true); + blink(); + }, this.blinkInterval); + blink(); + } + }; + + this.getPixelPosition = function(position, onScreen) { + if (!this.config || !this.session) + return {left : 0, top : 0}; + + if (!position) + position = this.session.selection.getCursor(); + var pos = this.session.documentToScreenPosition(position); + var cursorLeft = this.$padding + (this.session.$bidiHandler.isBidiRow(pos.row, position.row) + ? this.session.$bidiHandler.getPosLeft(pos.column) + : pos.column * this.config.characterWidth); + + var cursorTop = (pos.row - (onScreen ? this.config.firstRowScreen : 0)) * + this.config.lineHeight; + + return {left : cursorLeft, top : cursorTop}; + }; + + this.isCursorInView = function(pixelPos, config) { + return pixelPos.top >= 0 && pixelPos.top < config.maxHeight; + }; + + this.update = function(config) { + this.config = config; + + var selections = this.session.$selectionMarkers; + var i = 0, cursorIndex = 0; + + if (selections === undefined || selections.length === 0){ + selections = [{cursor: null}]; + } + + for (var i = 0, n = selections.length; i < n; i++) { + var pixelPos = this.getPixelPosition(selections[i].cursor, true); + if ((pixelPos.top > config.height + config.offset || + pixelPos.top < 0) && i > 1) { + continue; + } + + var element = this.cursors[cursorIndex++] || this.addCursor(); + var style = element.style; + + if (!this.drawCursor) { + if (!this.isCursorInView(pixelPos, config)) { + dom.setStyle(style, "display", "none"); + } else { + dom.setStyle(style, "display", "block"); + dom.translate(element, pixelPos.left, pixelPos.top); + dom.setStyle(style, "width", Math.round(config.characterWidth) + "px"); + dom.setStyle(style, "height", config.lineHeight + "px"); + } + } else { + this.drawCursor(element, pixelPos, config, selections[i], this.session); + } + } + while (this.cursors.length > cursorIndex) + this.removeCursor(); + + var overwrite = this.session.getOverwrite(); + this.$setOverwrite(overwrite); + this.$pixelPos = pixelPos; + this.restartTimer(); + }; + + this.drawCursor = null; + + this.$setOverwrite = function(overwrite) { + if (overwrite != this.overwrite) { + this.overwrite = overwrite; + if (overwrite) + dom.addCssClass(this.element, "ace_overwrite-cursors"); + else + dom.removeCssClass(this.element, "ace_overwrite-cursors"); + } + }; + + this.destroy = function() { + clearInterval(this.intervalId); + clearTimeout(this.timeoutId); + }; + +}).call(Cursor.prototype); + +exports.Cursor = Cursor; + +}); + +define("ace/scrollbar",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/event","ace/lib/event_emitter"], function(require, exports, module) { +"use strict"; + +var oop = require("./lib/oop"); +var dom = require("./lib/dom"); +var event = require("./lib/event"); +var EventEmitter = require("./lib/event_emitter").EventEmitter; +var MAX_SCROLL_H = 0x8000; +var ScrollBar = function(parent) { + this.element = dom.createElement("div"); + this.element.className = "ace_scrollbar ace_scrollbar" + this.classSuffix; + + this.inner = dom.createElement("div"); + this.inner.className = "ace_scrollbar-inner"; + this.inner.textContent = "\xa0"; + this.element.appendChild(this.inner); + + parent.appendChild(this.element); + + this.setVisible(false); + this.skipEvent = false; + + event.addListener(this.element, "scroll", this.onScroll.bind(this)); + event.addListener(this.element, "mousedown", event.preventDefault); +}; + +(function() { + oop.implement(this, EventEmitter); + + this.setVisible = function(isVisible) { + this.element.style.display = isVisible ? "" : "none"; + this.isVisible = isVisible; + this.coeff = 1; + }; +}).call(ScrollBar.prototype); +var VScrollBar = function(parent, renderer) { + ScrollBar.call(this, parent); + this.scrollTop = 0; + this.scrollHeight = 0; + renderer.$scrollbarWidth = + this.width = dom.scrollbarWidth(parent.ownerDocument); + this.inner.style.width = + this.element.style.width = (this.width || 15) + 5 + "px"; + this.$minWidth = 0; +}; + +oop.inherits(VScrollBar, ScrollBar); + +(function() { + + this.classSuffix = '-v'; + this.onScroll = function() { + if (!this.skipEvent) { + this.scrollTop = this.element.scrollTop; + if (this.coeff != 1) { + var h = this.element.clientHeight / this.scrollHeight; + this.scrollTop = this.scrollTop * (1 - h) / (this.coeff - h); + } + this._emit("scroll", {data: this.scrollTop}); + } + this.skipEvent = false; + }; + this.getWidth = function() { + return Math.max(this.isVisible ? this.width : 0, this.$minWidth || 0); + }; + this.setHeight = function(height) { + this.element.style.height = height + "px"; + }; + this.setInnerHeight = + this.setScrollHeight = function(height) { + this.scrollHeight = height; + if (height > MAX_SCROLL_H) { + this.coeff = MAX_SCROLL_H / height; + height = MAX_SCROLL_H; + } else if (this.coeff != 1) { + this.coeff = 1; + } + this.inner.style.height = height + "px"; + }; + this.setScrollTop = function(scrollTop) { + if (this.scrollTop != scrollTop) { + this.skipEvent = true; + this.scrollTop = scrollTop; + this.element.scrollTop = scrollTop * this.coeff; + } + }; + +}).call(VScrollBar.prototype); +var HScrollBar = function(parent, renderer) { + ScrollBar.call(this, parent); + this.scrollLeft = 0; + this.height = renderer.$scrollbarWidth; + this.inner.style.height = + this.element.style.height = (this.height || 15) + 5 + "px"; +}; + +oop.inherits(HScrollBar, ScrollBar); + +(function() { + + this.classSuffix = '-h'; + this.onScroll = function() { + if (!this.skipEvent) { + this.scrollLeft = this.element.scrollLeft; + this._emit("scroll", {data: this.scrollLeft}); + } + this.skipEvent = false; + }; + this.getHeight = function() { + return this.isVisible ? this.height : 0; + }; + this.setWidth = function(width) { + this.element.style.width = width + "px"; + }; + this.setInnerWidth = function(width) { + this.inner.style.width = width + "px"; + }; + this.setScrollWidth = function(width) { + this.inner.style.width = width + "px"; + }; + this.setScrollLeft = function(scrollLeft) { + if (this.scrollLeft != scrollLeft) { + this.skipEvent = true; + this.scrollLeft = this.element.scrollLeft = scrollLeft; + } + }; + +}).call(HScrollBar.prototype); + + +exports.ScrollBar = VScrollBar; // backward compatibility +exports.ScrollBarV = VScrollBar; // backward compatibility +exports.ScrollBarH = HScrollBar; // backward compatibility + +exports.VScrollBar = VScrollBar; +exports.HScrollBar = HScrollBar; +}); + +define("ace/renderloop",["require","exports","module","ace/lib/event"], function(require, exports, module) { +"use strict"; + +var event = require("./lib/event"); + + +var RenderLoop = function(onRender, win) { + this.onRender = onRender; + this.pending = false; + this.changes = 0; + this.$recursionLimit = 2; + this.window = win || window; + var _self = this; + this._flush = function(ts) { + _self.pending = false; + var changes = _self.changes; + + if (changes) { + event.blockIdle(100); + _self.changes = 0; + _self.onRender(changes); + } + + if (_self.changes) { + if (_self.$recursionLimit-- < 0) return; + _self.schedule(); + } else { + _self.$recursionLimit = 2; + } + }; +}; + +(function() { + + this.schedule = function(change) { + this.changes = this.changes | change; + if (this.changes && !this.pending) { + event.nextFrame(this._flush); + this.pending = true; + } + }; + + this.clear = function(change) { + var changes = this.changes; + this.changes = 0; + return changes; + }; + +}).call(RenderLoop.prototype); + +exports.RenderLoop = RenderLoop; +}); + +define("ace/layer/font_metrics",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/lib/event","ace/lib/useragent","ace/lib/event_emitter"], function(require, exports, module) { + +var oop = require("../lib/oop"); +var dom = require("../lib/dom"); +var lang = require("../lib/lang"); +var event = require("../lib/event"); +var useragent = require("../lib/useragent"); +var EventEmitter = require("../lib/event_emitter").EventEmitter; + +var CHAR_COUNT = 256; +var USE_OBSERVER = typeof ResizeObserver == "function"; +var L = 200; + +var FontMetrics = exports.FontMetrics = function(parentEl) { + this.el = dom.createElement("div"); + this.$setMeasureNodeStyles(this.el.style, true); + + this.$main = dom.createElement("div"); + this.$setMeasureNodeStyles(this.$main.style); + + this.$measureNode = dom.createElement("div"); + this.$setMeasureNodeStyles(this.$measureNode.style); + + + this.el.appendChild(this.$main); + this.el.appendChild(this.$measureNode); + parentEl.appendChild(this.el); + + this.$measureNode.innerHTML = lang.stringRepeat("X", CHAR_COUNT); + + this.$characterSize = {width: 0, height: 0}; + + + if (USE_OBSERVER) + this.$addObserver(); + else + this.checkForSizeChanges(); +}; + +(function() { + + oop.implement(this, EventEmitter); + + this.$characterSize = {width: 0, height: 0}; + + this.$setMeasureNodeStyles = function(style, isRoot) { + style.width = style.height = "auto"; + style.left = style.top = "0px"; + style.visibility = "hidden"; + style.position = "absolute"; + style.whiteSpace = "pre"; + + if (useragent.isIE < 8) { + style["font-family"] = "inherit"; + } else { + style.font = "inherit"; + } + style.overflow = isRoot ? "hidden" : "visible"; + }; + + this.checkForSizeChanges = function(size) { + if (size === undefined) + size = this.$measureSizes(); + if (size && (this.$characterSize.width !== size.width || this.$characterSize.height !== size.height)) { + this.$measureNode.style.fontWeight = "bold"; + var boldSize = this.$measureSizes(); + this.$measureNode.style.fontWeight = ""; + this.$characterSize = size; + this.charSizes = Object.create(null); + this.allowBoldFonts = boldSize && boldSize.width === size.width && boldSize.height === size.height; + this._emit("changeCharacterSize", {data: size}); + } + }; + + this.$addObserver = function() { + var self = this; + this.$observer = new window.ResizeObserver(function(e) { + var rect = e[0].contentRect; + self.checkForSizeChanges({ + height: rect.height, + width: rect.width / CHAR_COUNT + }); + }); + this.$observer.observe(this.$measureNode); + }; + + this.$pollSizeChanges = function() { + if (this.$pollSizeChangesTimer || this.$observer) + return this.$pollSizeChangesTimer; + var self = this; + + return this.$pollSizeChangesTimer = event.onIdle(function cb() { + self.checkForSizeChanges(); + event.onIdle(cb, 500); + }, 500); + }; + + this.setPolling = function(val) { + if (val) { + this.$pollSizeChanges(); + } else if (this.$pollSizeChangesTimer) { + clearInterval(this.$pollSizeChangesTimer); + this.$pollSizeChangesTimer = 0; + } + }; + + this.$measureSizes = function(node) { + var size = { + height: (node || this.$measureNode).clientHeight, + width: (node || this.$measureNode).clientWidth / CHAR_COUNT + }; + if (size.width === 0 || size.height === 0) + return null; + return size; + }; + + this.$measureCharWidth = function(ch) { + this.$main.innerHTML = lang.stringRepeat(ch, CHAR_COUNT); + var rect = this.$main.getBoundingClientRect(); + return rect.width / CHAR_COUNT; + }; + + this.getCharacterWidth = function(ch) { + var w = this.charSizes[ch]; + if (w === undefined) { + w = this.charSizes[ch] = this.$measureCharWidth(ch) / this.$characterSize.width; + } + return w; + }; + + this.destroy = function() { + clearInterval(this.$pollSizeChangesTimer); + if (this.$observer) + this.$observer.disconnect(); + if (this.el && this.el.parentNode) + this.el.parentNode.removeChild(this.el); + }; + + + this.$getZoom = function getZoom(element) { + if (!element) return 1; + return (window.getComputedStyle(element).zoom || 1) * getZoom(element.parentElement); + }; + this.$initTransformMeasureNodes = function() { + var t = function(t, l) { + return ["div", { + style: "position: absolute;top:" + t + "px;left:" + l + "px;" + }]; + }; + this.els = dom.buildDom([t(0, 0), t(L, 0), t(0, L), t(L, L)], this.el); + }; + this.transformCoordinates = function(clientPos, elPos) { + if (clientPos) { + var zoom = this.$getZoom(this.el); + clientPos = mul(1 / zoom, clientPos); + } + function solve(l1, l2, r) { + var det = l1[1] * l2[0] - l1[0] * l2[1]; + return [ + (-l2[1] * r[0] + l2[0] * r[1]) / det, + (+l1[1] * r[0] - l1[0] * r[1]) / det + ]; + } + function sub(a, b) { return [a[0] - b[0], a[1] - b[1]]; } + function add(a, b) { return [a[0] + b[0], a[1] + b[1]]; } + function mul(a, b) { return [a * b[0], a * b[1]]; } + + if (!this.els) + this.$initTransformMeasureNodes(); + + function p(el) { + var r = el.getBoundingClientRect(); + return [r.left, r.top]; + } + + var a = p(this.els[0]); + var b = p(this.els[1]); + var c = p(this.els[2]); + var d = p(this.els[3]); + + var h = solve(sub(d, b), sub(d, c), sub(add(b, c), add(d, a))); + + var m1 = mul(1 + h[0], sub(b, a)); + var m2 = mul(1 + h[1], sub(c, a)); + + if (elPos) { + var x = elPos; + var k = h[0] * x[0] / L + h[1] * x[1] / L + 1; + var ut = add(mul(x[0], m1), mul(x[1], m2)); + return add(mul(1 / k / L, ut), a); + } + var u = sub(clientPos, a); + var f = solve(sub(m1, mul(h[0], u)), sub(m2, mul(h[1], u)), u); + return mul(L, f); + }; + +}).call(FontMetrics.prototype); + +}); + +define("ace/virtual_renderer",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/config","ace/layer/gutter","ace/layer/marker","ace/layer/text","ace/layer/cursor","ace/scrollbar","ace/scrollbar","ace/renderloop","ace/layer/font_metrics","ace/lib/event_emitter","ace/lib/useragent"], function(require, exports, module) { +"use strict"; + +var oop = require("./lib/oop"); +var dom = require("./lib/dom"); +var config = require("./config"); +var GutterLayer = require("./layer/gutter").Gutter; +var MarkerLayer = require("./layer/marker").Marker; +var TextLayer = require("./layer/text").Text; +var CursorLayer = require("./layer/cursor").Cursor; +var HScrollBar = require("./scrollbar").HScrollBar; +var VScrollBar = require("./scrollbar").VScrollBar; +var RenderLoop = require("./renderloop").RenderLoop; +var FontMetrics = require("./layer/font_metrics").FontMetrics; +var EventEmitter = require("./lib/event_emitter").EventEmitter; +var editorCss = "\ +.ace_br1 {border-top-left-radius : 3px;}\ +.ace_br2 {border-top-right-radius : 3px;}\ +.ace_br3 {border-top-left-radius : 3px; border-top-right-radius: 3px;}\ +.ace_br4 {border-bottom-right-radius: 3px;}\ +.ace_br5 {border-top-left-radius : 3px; border-bottom-right-radius: 3px;}\ +.ace_br6 {border-top-right-radius : 3px; border-bottom-right-radius: 3px;}\ +.ace_br7 {border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px;}\ +.ace_br8 {border-bottom-left-radius : 3px;}\ +.ace_br9 {border-top-left-radius : 3px; border-bottom-left-radius: 3px;}\ +.ace_br10{border-top-right-radius : 3px; border-bottom-left-radius: 3px;}\ +.ace_br11{border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-left-radius: 3px;}\ +.ace_br12{border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}\ +.ace_br13{border-top-left-radius : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}\ +.ace_br14{border-top-right-radius : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}\ +.ace_br15{border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}\ +.ace_editor {\ +position: relative;\ +overflow: hidden;\ +font: 12px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;\ +direction: ltr;\ +text-align: left;\ +-webkit-tap-highlight-color: rgba(0, 0, 0, 0);\ +}\ +.ace_scroller {\ +position: absolute;\ +overflow: hidden;\ +top: 0;\ +bottom: 0;\ +background-color: inherit;\ +-ms-user-select: none;\ +-moz-user-select: none;\ +-webkit-user-select: none;\ +user-select: none;\ +cursor: text;\ +}\ +.ace_content {\ +position: absolute;\ +box-sizing: border-box;\ +min-width: 100%;\ +contain: style size layout;\ +}\ +.ace_dragging .ace_scroller:before{\ +position: absolute;\ +top: 0;\ +left: 0;\ +right: 0;\ +bottom: 0;\ +content: '';\ +background: rgba(250, 250, 250, 0.01);\ +z-index: 1000;\ +}\ +.ace_dragging.ace_dark .ace_scroller:before{\ +background: rgba(0, 0, 0, 0.01);\ +}\ +.ace_selecting, .ace_selecting * {\ +cursor: text !important;\ +}\ +.ace_gutter {\ +position: absolute;\ +overflow : hidden;\ +width: auto;\ +top: 0;\ +bottom: 0;\ +left: 0;\ +cursor: default;\ +z-index: 4;\ +-ms-user-select: none;\ +-moz-user-select: none;\ +-webkit-user-select: none;\ +user-select: none;\ +contain: style size layout;\ +}\ +.ace_gutter-active-line {\ +position: absolute;\ +left: 0;\ +right: 0;\ +}\ +.ace_scroller.ace_scroll-left {\ +box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset;\ +}\ +.ace_gutter-cell {\ +position: absolute;\ +top: 0;\ +left: 0;\ +right: 0;\ +padding-left: 19px;\ +padding-right: 6px;\ +background-repeat: no-repeat;\ +}\ +.ace_gutter-cell.ace_error {\ +background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABOFBMVEX/////////QRswFAb/Ui4wFAYwFAYwFAaWGAfDRymzOSH/PxswFAb/SiUwFAYwFAbUPRvjQiDllog5HhHdRybsTi3/Tyv9Tir+Syj/UC3////XurebMBIwFAb/RSHbPx/gUzfdwL3kzMivKBAwFAbbvbnhPx66NhowFAYwFAaZJg8wFAaxKBDZurf/RB6mMxb/SCMwFAYwFAbxQB3+RB4wFAb/Qhy4Oh+4QifbNRcwFAYwFAYwFAb/QRzdNhgwFAYwFAbav7v/Uy7oaE68MBK5LxLewr/r2NXewLswFAaxJw4wFAbkPRy2PyYwFAaxKhLm1tMwFAazPiQwFAaUGAb/QBrfOx3bvrv/VC/maE4wFAbRPBq6MRO8Qynew8Dp2tjfwb0wFAbx6eju5+by6uns4uH9/f36+vr/GkHjAAAAYnRSTlMAGt+64rnWu/bo8eAA4InH3+DwoN7j4eLi4xP99Nfg4+b+/u9B/eDs1MD1mO7+4PHg2MXa347g7vDizMLN4eG+Pv7i5evs/v79yu7S3/DV7/498Yv24eH+4ufQ3Ozu/v7+y13sRqwAAADLSURBVHjaZc/XDsFgGIBhtDrshlitmk2IrbHFqL2pvXf/+78DPokj7+Fz9qpU/9UXJIlhmPaTaQ6QPaz0mm+5gwkgovcV6GZzd5JtCQwgsxoHOvJO15kleRLAnMgHFIESUEPmawB9ngmelTtipwwfASilxOLyiV5UVUyVAfbG0cCPHig+GBkzAENHS0AstVF6bacZIOzgLmxsHbt2OecNgJC83JERmePUYq8ARGkJx6XtFsdddBQgZE2nPR6CICZhawjA4Fb/chv+399kfR+MMMDGOQAAAABJRU5ErkJggg==\");\ +background-repeat: no-repeat;\ +background-position: 2px center;\ +}\ +.ace_gutter-cell.ace_warning {\ +background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAmVBMVEX///8AAAD///8AAAAAAABPSzb/5sAAAAB/blH/73z/ulkAAAAAAAD85pkAAAAAAAACAgP/vGz/rkDerGbGrV7/pkQICAf////e0IsAAAD/oED/qTvhrnUAAAD/yHD/njcAAADuv2r/nz//oTj/p064oGf/zHAAAAA9Nir/tFIAAAD/tlTiuWf/tkIAAACynXEAAAAAAAAtIRW7zBpBAAAAM3RSTlMAABR1m7RXO8Ln31Z36zT+neXe5OzooRDfn+TZ4p3h2hTf4t3k3ucyrN1K5+Xaks52Sfs9CXgrAAAAjklEQVR42o3PbQ+CIBQFYEwboPhSYgoYunIqqLn6/z8uYdH8Vmdnu9vz4WwXgN/xTPRD2+sgOcZjsge/whXZgUaYYvT8QnuJaUrjrHUQreGczuEafQCO/SJTufTbroWsPgsllVhq3wJEk2jUSzX3CUEDJC84707djRc5MTAQxoLgupWRwW6UB5fS++NV8AbOZgnsC7BpEAAAAABJRU5ErkJggg==\");\ +background-position: 2px center;\ +}\ +.ace_gutter-cell.ace_info {\ +background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAJ0Uk5TAAB2k804AAAAPklEQVQY02NgIB68QuO3tiLznjAwpKTgNyDbMegwisCHZUETUZV0ZqOquBpXj2rtnpSJT1AEnnRmL2OgGgAAIKkRQap2htgAAAAASUVORK5CYII=\");\ +background-position: 2px center;\ +}\ +.ace_dark .ace_gutter-cell.ace_info {\ +background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAChoaGAgIAqKiq+vr6tra1ZWVmUlJSbm5s8PDxubm56enrdgzg3AAAAAXRSTlMAQObYZgAAAClJREFUeNpjYMAPdsMYHegyJZFQBlsUlMFVCWUYKkAZMxZAGdxlDMQBAG+TBP4B6RyJAAAAAElFTkSuQmCC\");\ +}\ +.ace_scrollbar {\ +contain: strict;\ +position: absolute;\ +right: 0;\ +bottom: 0;\ +z-index: 6;\ +}\ +.ace_scrollbar-inner {\ +position: absolute;\ +cursor: text;\ +left: 0;\ +top: 0;\ +}\ +.ace_scrollbar-v{\ +overflow-x: hidden;\ +overflow-y: scroll;\ +top: 0;\ +}\ +.ace_scrollbar-h {\ +overflow-x: scroll;\ +overflow-y: hidden;\ +left: 0;\ +}\ +.ace_print-margin {\ +position: absolute;\ +height: 100%;\ +}\ +.ace_text-input {\ +position: absolute;\ +z-index: 0;\ +width: 0.5em;\ +height: 1em;\ +opacity: 0;\ +background: transparent;\ +-moz-appearance: none;\ +appearance: none;\ +border: none;\ +resize: none;\ +outline: none;\ +overflow: hidden;\ +font: inherit;\ +padding: 0 1px;\ +margin: 0 -1px;\ +contain: strict;\ +-ms-user-select: text;\ +-moz-user-select: text;\ +-webkit-user-select: text;\ +user-select: text;\ +white-space: pre!important;\ +}\ +.ace_text-input.ace_composition {\ +background: transparent;\ +color: inherit;\ +z-index: 1000;\ +opacity: 1;\ +}\ +.ace_composition_placeholder { color: transparent }\ +.ace_composition_marker { \ +border-bottom: 1px solid;\ +position: absolute;\ +border-radius: 0;\ +margin-top: 1px;\ +}\ +[ace_nocontext=true] {\ +transform: none!important;\ +filter: none!important;\ +perspective: none!important;\ +clip-path: none!important;\ +mask : none!important;\ +contain: none!important;\ +perspective: none!important;\ +mix-blend-mode: initial!important;\ +z-index: auto;\ +}\ +.ace_layer {\ +z-index: 1;\ +position: absolute;\ +overflow: hidden;\ +word-wrap: normal;\ +white-space: pre;\ +height: 100%;\ +width: 100%;\ +box-sizing: border-box;\ +pointer-events: none;\ +}\ +.ace_gutter-layer {\ +position: relative;\ +width: auto;\ +text-align: right;\ +pointer-events: auto;\ +height: 1000000px;\ +contain: style size layout;\ +}\ +.ace_text-layer {\ +font: inherit !important;\ +position: absolute;\ +height: 1000000px;\ +width: 1000000px;\ +contain: style size layout;\ +}\ +.ace_text-layer > .ace_line, .ace_text-layer > .ace_line_group {\ +contain: style size layout;\ +position: absolute;\ +top: 0;\ +left: 0;\ +right: 0;\ +}\ +.ace_hidpi .ace_text-layer,\ +.ace_hidpi .ace_gutter-layer,\ +.ace_hidpi .ace_content,\ +.ace_hidpi .ace_gutter {\ +contain: strict;\ +will-change: transform;\ +}\ +.ace_hidpi .ace_text-layer > .ace_line, \ +.ace_hidpi .ace_text-layer > .ace_line_group {\ +contain: strict;\ +}\ +.ace_cjk {\ +display: inline-block;\ +text-align: center;\ +}\ +.ace_cursor-layer {\ +z-index: 4;\ +}\ +.ace_cursor {\ +z-index: 4;\ +position: absolute;\ +box-sizing: border-box;\ +border-left: 2px solid;\ +transform: translatez(0);\ +}\ +.ace_multiselect .ace_cursor {\ +border-left-width: 1px;\ +}\ +.ace_slim-cursors .ace_cursor {\ +border-left-width: 1px;\ +}\ +.ace_overwrite-cursors .ace_cursor {\ +border-left-width: 0;\ +border-bottom: 1px solid;\ +}\ +.ace_hidden-cursors .ace_cursor {\ +opacity: 0.2;\ +}\ +.ace_hasPlaceholder .ace_hidden-cursors .ace_cursor {\ +opacity: 0;\ +}\ +.ace_smooth-blinking .ace_cursor {\ +transition: opacity 0.18s;\ +}\ +.ace_animate-blinking .ace_cursor {\ +animation-duration: 1000ms;\ +animation-timing-function: step-end;\ +animation-name: blink-ace-animate;\ +animation-iteration-count: infinite;\ +}\ +.ace_animate-blinking.ace_smooth-blinking .ace_cursor {\ +animation-duration: 1000ms;\ +animation-timing-function: ease-in-out;\ +animation-name: blink-ace-animate-smooth;\ +}\ +@keyframes blink-ace-animate {\ +from, to { opacity: 1; }\ +60% { opacity: 0; }\ +}\ +@keyframes blink-ace-animate-smooth {\ +from, to { opacity: 1; }\ +45% { opacity: 1; }\ +60% { opacity: 0; }\ +85% { opacity: 0; }\ +}\ +.ace_marker-layer .ace_step, .ace_marker-layer .ace_stack {\ +position: absolute;\ +z-index: 3;\ +}\ +.ace_marker-layer .ace_selection {\ +position: absolute;\ +z-index: 5;\ +}\ +.ace_marker-layer .ace_bracket {\ +position: absolute;\ +z-index: 6;\ +}\ +.ace_marker-layer .ace_active-line {\ +position: absolute;\ +z-index: 2;\ +}\ +.ace_marker-layer .ace_selected-word {\ +position: absolute;\ +z-index: 4;\ +box-sizing: border-box;\ +}\ +.ace_line .ace_fold {\ +box-sizing: border-box;\ +display: inline-block;\ +height: 11px;\ +margin-top: -2px;\ +vertical-align: middle;\ +background-image:\ +url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII=\"),\ +url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACJJREFUeNpi+P//fxgTAwPDBxDxD078RSX+YeEyDFMCIMAAI3INmXiwf2YAAAAASUVORK5CYII=\");\ +background-repeat: no-repeat, repeat-x;\ +background-position: center center, top left;\ +color: transparent;\ +border: 1px solid black;\ +border-radius: 2px;\ +cursor: pointer;\ +pointer-events: auto;\ +}\ +.ace_dark .ace_fold {\ +}\ +.ace_fold:hover{\ +background-image:\ +url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII=\"),\ +url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACBJREFUeNpi+P//fz4TAwPDZxDxD5X4i5fLMEwJgAADAEPVDbjNw87ZAAAAAElFTkSuQmCC\");\ +}\ +.ace_tooltip {\ +background-color: #FFF;\ +background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.1));\ +border: 1px solid gray;\ +border-radius: 1px;\ +box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);\ +color: black;\ +max-width: 100%;\ +padding: 3px 4px;\ +position: fixed;\ +z-index: 999999;\ +box-sizing: border-box;\ +cursor: default;\ +white-space: pre;\ +word-wrap: break-word;\ +line-height: normal;\ +font-style: normal;\ +font-weight: normal;\ +letter-spacing: normal;\ +pointer-events: none;\ +}\ +.ace_folding-enabled > .ace_gutter-cell {\ +padding-right: 13px;\ +}\ +.ace_fold-widget {\ +box-sizing: border-box;\ +margin: 0 -12px 0 1px;\ +display: none;\ +width: 11px;\ +vertical-align: top;\ +background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42mWKsQ0AMAzC8ixLlrzQjzmBiEjp0A6WwBCSPgKAXoLkqSot7nN3yMwR7pZ32NzpKkVoDBUxKAAAAABJRU5ErkJggg==\");\ +background-repeat: no-repeat;\ +background-position: center;\ +border-radius: 3px;\ +border: 1px solid transparent;\ +cursor: pointer;\ +}\ +.ace_folding-enabled .ace_fold-widget {\ +display: inline-block; \ +}\ +.ace_fold-widget.ace_end {\ +background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42m3HwQkAMAhD0YzsRchFKI7sAikeWkrxwScEB0nh5e7KTPWimZki4tYfVbX+MNl4pyZXejUO1QAAAABJRU5ErkJggg==\");\ +}\ +.ace_fold-widget.ace_closed {\ +background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAGCAYAAAAG5SQMAAAAOUlEQVR42jXKwQkAMAgDwKwqKD4EwQ26sSOkVWjgIIHAzPiCgaqiqnJHZnKICBERHN194O5b9vbLuAVRL+l0YWnZAAAAAElFTkSuQmCCXA==\");\ +}\ +.ace_fold-widget:hover {\ +border: 1px solid rgba(0, 0, 0, 0.3);\ +background-color: rgba(255, 255, 255, 0.2);\ +box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);\ +}\ +.ace_fold-widget:active {\ +border: 1px solid rgba(0, 0, 0, 0.4);\ +background-color: rgba(0, 0, 0, 0.05);\ +box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);\ +}\ +.ace_dark .ace_fold-widget {\ +background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHklEQVQIW2P4//8/AzoGEQ7oGCaLLAhWiSwB146BAQCSTPYocqT0AAAAAElFTkSuQmCC\");\ +}\ +.ace_dark .ace_fold-widget.ace_end {\ +background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAH0lEQVQIW2P4//8/AxQ7wNjIAjDMgC4AxjCVKBirIAAF0kz2rlhxpAAAAABJRU5ErkJggg==\");\ +}\ +.ace_dark .ace_fold-widget.ace_closed {\ +background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAHElEQVQIW2P4//+/AxAzgDADlOOAznHAKgPWAwARji8UIDTfQQAAAABJRU5ErkJggg==\");\ +}\ +.ace_dark .ace_fold-widget:hover {\ +box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);\ +background-color: rgba(255, 255, 255, 0.1);\ +}\ +.ace_dark .ace_fold-widget:active {\ +box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);\ +}\ +.ace_inline_button {\ +border: 1px solid lightgray;\ +display: inline-block;\ +margin: -1px 8px;\ +padding: 0 5px;\ +pointer-events: auto;\ +cursor: pointer;\ +}\ +.ace_inline_button:hover {\ +border-color: gray;\ +background: rgba(200,200,200,0.2);\ +display: inline-block;\ +pointer-events: auto;\ +}\ +.ace_fold-widget.ace_invalid {\ +background-color: #FFB4B4;\ +border-color: #DE5555;\ +}\ +.ace_fade-fold-widgets .ace_fold-widget {\ +transition: opacity 0.4s ease 0.05s;\ +opacity: 0;\ +}\ +.ace_fade-fold-widgets:hover .ace_fold-widget {\ +transition: opacity 0.05s ease 0.05s;\ +opacity:1;\ +}\ +.ace_underline {\ +text-decoration: underline;\ +}\ +.ace_bold {\ +font-weight: bold;\ +}\ +.ace_nobold .ace_bold {\ +font-weight: normal;\ +}\ +.ace_italic {\ +font-style: italic;\ +}\ +.ace_error-marker {\ +background-color: rgba(255, 0, 0,0.2);\ +position: absolute;\ +z-index: 9;\ +}\ +.ace_highlight-marker {\ +background-color: rgba(255, 255, 0,0.2);\ +position: absolute;\ +z-index: 8;\ +}\ +.ace_mobile-menu {\ +position: absolute;\ +line-height: 1.5;\ +border-radius: 4px;\ +-ms-user-select: none;\ +-moz-user-select: none;\ +-webkit-user-select: none;\ +user-select: none;\ +background: white;\ +box-shadow: 1px 3px 2px grey;\ +border: 1px solid #dcdcdc;\ +color: black;\ +}\ +.ace_dark > .ace_mobile-menu {\ +background: #333;\ +color: #ccc;\ +box-shadow: 1px 3px 2px grey;\ +border: 1px solid #444;\ +}\ +.ace_mobile-button {\ +padding: 2px;\ +cursor: pointer;\ +overflow: hidden;\ +}\ +.ace_mobile-button:hover {\ +background-color: #eee;\ +opacity:1;\ +}\ +.ace_mobile-button:active {\ +background-color: #ddd;\ +}\ +.ace_placeholder {\ +font-family: arial;\ +transform: scale(0.9);\ +opacity: 0.7;\ +transform-origin: left;\ +text-indent: 10px;\ +}"; + +var useragent = require("./lib/useragent"); +var HIDE_TEXTAREA = useragent.isIE; + +dom.importCssString(editorCss, "ace_editor.css"); + +var VirtualRenderer = function(container, theme) { + var _self = this; + + this.container = container || dom.createElement("div"); + + dom.addCssClass(this.container, "ace_editor"); + if (dom.HI_DPI) dom.addCssClass(this.container, "ace_hidpi"); + + this.setTheme(theme); + + this.$gutter = dom.createElement("div"); + this.$gutter.className = "ace_gutter"; + this.container.appendChild(this.$gutter); + this.$gutter.setAttribute("aria-hidden", true); + + this.scroller = dom.createElement("div"); + this.scroller.className = "ace_scroller"; + + this.container.appendChild(this.scroller); + + this.content = dom.createElement("div"); + this.content.className = "ace_content"; + this.scroller.appendChild(this.content); + + this.$gutterLayer = new GutterLayer(this.$gutter); + this.$gutterLayer.on("changeGutterWidth", this.onGutterResize.bind(this)); + + this.$markerBack = new MarkerLayer(this.content); + + var textLayer = this.$textLayer = new TextLayer(this.content); + this.canvas = textLayer.element; + + this.$markerFront = new MarkerLayer(this.content); + + this.$cursorLayer = new CursorLayer(this.content); + this.$horizScroll = false; + this.$vScroll = false; + + this.scrollBar = + this.scrollBarV = new VScrollBar(this.container, this); + this.scrollBarH = new HScrollBar(this.container, this); + this.scrollBarV.addEventListener("scroll", function(e) { + if (!_self.$scrollAnimation) + _self.session.setScrollTop(e.data - _self.scrollMargin.top); + }); + this.scrollBarH.addEventListener("scroll", function(e) { + if (!_self.$scrollAnimation) + _self.session.setScrollLeft(e.data - _self.scrollMargin.left); + }); + + this.scrollTop = 0; + this.scrollLeft = 0; + + this.cursorPos = { + row : 0, + column : 0 + }; + + this.$fontMetrics = new FontMetrics(this.container); + this.$textLayer.$setFontMetrics(this.$fontMetrics); + this.$textLayer.addEventListener("changeCharacterSize", function(e) { + _self.updateCharacterSize(); + _self.onResize(true, _self.gutterWidth, _self.$size.width, _self.$size.height); + _self._signal("changeCharacterSize", e); + }); + + this.$size = { + width: 0, + height: 0, + scrollerHeight: 0, + scrollerWidth: 0, + $dirty: true + }; + + this.layerConfig = { + width : 1, + padding : 0, + firstRow : 0, + firstRowScreen: 0, + lastRow : 0, + lineHeight : 0, + characterWidth : 0, + minHeight : 1, + maxHeight : 1, + offset : 0, + height : 1, + gutterOffset: 1 + }; + + this.scrollMargin = { + left: 0, + right: 0, + top: 0, + bottom: 0, + v: 0, + h: 0 + }; + + this.margin = { + left: 0, + right: 0, + top: 0, + bottom: 0, + v: 0, + h: 0 + }; + + this.$keepTextAreaAtCursor = !useragent.isIOS; + + this.$loop = new RenderLoop( + this.$renderChanges.bind(this), + this.container.ownerDocument.defaultView + ); + this.$loop.schedule(this.CHANGE_FULL); + + this.updateCharacterSize(); + this.setPadding(4); + config.resetOptions(this); + config._signal("renderer", this); +}; + +(function() { + + this.CHANGE_CURSOR = 1; + this.CHANGE_MARKER = 2; + this.CHANGE_GUTTER = 4; + this.CHANGE_SCROLL = 8; + this.CHANGE_LINES = 16; + this.CHANGE_TEXT = 32; + this.CHANGE_SIZE = 64; + this.CHANGE_MARKER_BACK = 128; + this.CHANGE_MARKER_FRONT = 256; + this.CHANGE_FULL = 512; + this.CHANGE_H_SCROLL = 1024; + + oop.implement(this, EventEmitter); + + this.updateCharacterSize = function() { + if (this.$textLayer.allowBoldFonts != this.$allowBoldFonts) { + this.$allowBoldFonts = this.$textLayer.allowBoldFonts; + this.setStyle("ace_nobold", !this.$allowBoldFonts); + } + + this.layerConfig.characterWidth = + this.characterWidth = this.$textLayer.getCharacterWidth(); + this.layerConfig.lineHeight = + this.lineHeight = this.$textLayer.getLineHeight(); + this.$updatePrintMargin(); + dom.setStyle(this.scroller.style, "line-height", this.lineHeight + "px"); + }; + this.setSession = function(session) { + if (this.session) + this.session.doc.off("changeNewLineMode", this.onChangeNewLineMode); + + this.session = session; + if (session && this.scrollMargin.top && session.getScrollTop() <= 0) + session.setScrollTop(-this.scrollMargin.top); + + this.$cursorLayer.setSession(session); + this.$markerBack.setSession(session); + this.$markerFront.setSession(session); + this.$gutterLayer.setSession(session); + this.$textLayer.setSession(session); + if (!session) + return; + + this.$loop.schedule(this.CHANGE_FULL); + this.session.$setFontMetrics(this.$fontMetrics); + this.scrollBarH.scrollLeft = this.scrollBarV.scrollTop = null; + + this.onChangeNewLineMode = this.onChangeNewLineMode.bind(this); + this.onChangeNewLineMode(); + this.session.doc.on("changeNewLineMode", this.onChangeNewLineMode); + }; + this.updateLines = function(firstRow, lastRow, force) { + if (lastRow === undefined) + lastRow = Infinity; + + if (!this.$changedLines) { + this.$changedLines = { + firstRow: firstRow, + lastRow: lastRow + }; + } + else { + if (this.$changedLines.firstRow > firstRow) + this.$changedLines.firstRow = firstRow; + + if (this.$changedLines.lastRow < lastRow) + this.$changedLines.lastRow = lastRow; + } + if (this.$changedLines.lastRow < this.layerConfig.firstRow) { + if (force) + this.$changedLines.lastRow = this.layerConfig.lastRow; + else + return; + } + if (this.$changedLines.firstRow > this.layerConfig.lastRow) + return; + this.$loop.schedule(this.CHANGE_LINES); + }; + + this.onChangeNewLineMode = function() { + this.$loop.schedule(this.CHANGE_TEXT); + this.$textLayer.$updateEolChar(); + this.session.$bidiHandler.setEolChar(this.$textLayer.EOL_CHAR); + }; + + this.onChangeTabSize = function() { + this.$loop.schedule(this.CHANGE_TEXT | this.CHANGE_MARKER); + this.$textLayer.onChangeTabSize(); + }; + this.updateText = function() { + this.$loop.schedule(this.CHANGE_TEXT); + }; + this.updateFull = function(force) { + if (force) + this.$renderChanges(this.CHANGE_FULL, true); + else + this.$loop.schedule(this.CHANGE_FULL); + }; + this.updateFontSize = function() { + this.$textLayer.checkForSizeChanges(); + }; + + this.$changes = 0; + this.$updateSizeAsync = function() { + if (this.$loop.pending) + this.$size.$dirty = true; + else + this.onResize(); + }; + this.onResize = function(force, gutterWidth, width, height) { + if (this.resizing > 2) + return; + else if (this.resizing > 0) + this.resizing++; + else + this.resizing = force ? 1 : 0; + var el = this.container; + if (!height) + height = el.clientHeight || el.scrollHeight; + if (!width) + width = el.clientWidth || el.scrollWidth; + var changes = this.$updateCachedSize(force, gutterWidth, width, height); + + + if (!this.$size.scrollerHeight || (!width && !height)) + return this.resizing = 0; + + if (force) + this.$gutterLayer.$padding = null; + + if (force) + this.$renderChanges(changes | this.$changes, true); + else + this.$loop.schedule(changes | this.$changes); + + if (this.resizing) + this.resizing = 0; + this.scrollBarV.scrollLeft = this.scrollBarV.scrollTop = null; + }; + + this.$updateCachedSize = function(force, gutterWidth, width, height) { + height -= (this.$extraHeight || 0); + var changes = 0; + var size = this.$size; + var oldSize = { + width: size.width, + height: size.height, + scrollerHeight: size.scrollerHeight, + scrollerWidth: size.scrollerWidth + }; + if (height && (force || size.height != height)) { + size.height = height; + changes |= this.CHANGE_SIZE; + + size.scrollerHeight = size.height; + if (this.$horizScroll) + size.scrollerHeight -= this.scrollBarH.getHeight(); + this.scrollBarV.element.style.bottom = this.scrollBarH.getHeight() + "px"; + + changes = changes | this.CHANGE_SCROLL; + } + + if (width && (force || size.width != width)) { + changes |= this.CHANGE_SIZE; + size.width = width; + + if (gutterWidth == null) + gutterWidth = this.$showGutter ? this.$gutter.offsetWidth : 0; + + this.gutterWidth = gutterWidth; + + dom.setStyle(this.scrollBarH.element.style, "left", gutterWidth + "px"); + dom.setStyle(this.scroller.style, "left", gutterWidth + this.margin.left + "px"); + size.scrollerWidth = Math.max(0, width - gutterWidth - this.scrollBarV.getWidth() - this.margin.h); + dom.setStyle(this.$gutter.style, "left", this.margin.left + "px"); + + var right = this.scrollBarV.getWidth() + "px"; + dom.setStyle(this.scrollBarH.element.style, "right", right); + dom.setStyle(this.scroller.style, "right", right); + dom.setStyle(this.scroller.style, "bottom", this.scrollBarH.getHeight()); + + if (this.session && this.session.getUseWrapMode() && this.adjustWrapLimit() || force) { + changes |= this.CHANGE_FULL; + } + } + + size.$dirty = !width || !height; + + if (changes) + this._signal("resize", oldSize); + + return changes; + }; + + this.onGutterResize = function(width) { + var gutterWidth = this.$showGutter ? width : 0; + if (gutterWidth != this.gutterWidth) + this.$changes |= this.$updateCachedSize(true, gutterWidth, this.$size.width, this.$size.height); + + if (this.session.getUseWrapMode() && this.adjustWrapLimit()) { + this.$loop.schedule(this.CHANGE_FULL); + } else if (this.$size.$dirty) { + this.$loop.schedule(this.CHANGE_FULL); + } else { + this.$computeLayerConfig(); + } + }; + this.adjustWrapLimit = function() { + var availableWidth = this.$size.scrollerWidth - this.$padding * 2; + var limit = Math.floor(availableWidth / this.characterWidth); + return this.session.adjustWrapLimit(limit, this.$showPrintMargin && this.$printMarginColumn); + }; + this.setAnimatedScroll = function(shouldAnimate){ + this.setOption("animatedScroll", shouldAnimate); + }; + this.getAnimatedScroll = function() { + return this.$animatedScroll; + }; + this.setShowInvisibles = function(showInvisibles) { + this.setOption("showInvisibles", showInvisibles); + this.session.$bidiHandler.setShowInvisibles(showInvisibles); + }; + this.getShowInvisibles = function() { + return this.getOption("showInvisibles"); + }; + this.getDisplayIndentGuides = function() { + return this.getOption("displayIndentGuides"); + }; + + this.setDisplayIndentGuides = function(display) { + this.setOption("displayIndentGuides", display); + }; + this.setShowPrintMargin = function(showPrintMargin) { + this.setOption("showPrintMargin", showPrintMargin); + }; + this.getShowPrintMargin = function() { + return this.getOption("showPrintMargin"); + }; + this.setPrintMarginColumn = function(showPrintMargin) { + this.setOption("printMarginColumn", showPrintMargin); + }; + this.getPrintMarginColumn = function() { + return this.getOption("printMarginColumn"); + }; + this.getShowGutter = function(){ + return this.getOption("showGutter"); + }; + this.setShowGutter = function(show){ + return this.setOption("showGutter", show); + }; + + this.getFadeFoldWidgets = function(){ + return this.getOption("fadeFoldWidgets"); + }; + + this.setFadeFoldWidgets = function(show) { + this.setOption("fadeFoldWidgets", show); + }; + + this.setHighlightGutterLine = function(shouldHighlight) { + this.setOption("highlightGutterLine", shouldHighlight); + }; + + this.getHighlightGutterLine = function() { + return this.getOption("highlightGutterLine"); + }; + + this.$updatePrintMargin = function() { + if (!this.$showPrintMargin && !this.$printMarginEl) + return; + + if (!this.$printMarginEl) { + var containerEl = dom.createElement("div"); + containerEl.className = "ace_layer ace_print-margin-layer"; + this.$printMarginEl = dom.createElement("div"); + this.$printMarginEl.className = "ace_print-margin"; + containerEl.appendChild(this.$printMarginEl); + this.content.insertBefore(containerEl, this.content.firstChild); + } + + var style = this.$printMarginEl.style; + style.left = Math.round(this.characterWidth * this.$printMarginColumn + this.$padding) + "px"; + style.visibility = this.$showPrintMargin ? "visible" : "hidden"; + + if (this.session && this.session.$wrap == -1) + this.adjustWrapLimit(); + }; + this.getContainerElement = function() { + return this.container; + }; + this.getMouseEventTarget = function() { + return this.scroller; + }; + this.getTextAreaContainer = function() { + return this.container; + }; + this.$moveTextAreaToCursor = function() { + if (this.$isMousePressed) return; + var style = this.textarea.style; + var composition = this.$composition; + if (!this.$keepTextAreaAtCursor && !composition) { + dom.translate(this.textarea, -100, 0); + return; + } + var pixelPos = this.$cursorLayer.$pixelPos; + if (!pixelPos) + return; + if (composition && composition.markerRange) + pixelPos = this.$cursorLayer.getPixelPosition(composition.markerRange.start, true); + + var config = this.layerConfig; + var posTop = pixelPos.top; + var posLeft = pixelPos.left; + posTop -= config.offset; + + var h = composition && composition.useTextareaForIME ? this.lineHeight : HIDE_TEXTAREA ? 0 : 1; + if (posTop < 0 || posTop > config.height - h) { + dom.translate(this.textarea, 0, 0); + return; + } + + var w = 1; + var maxTop = this.$size.height - h; + if (!composition) { + posTop += this.lineHeight; + } + else { + if (composition.useTextareaForIME) { + var val = this.textarea.value; + w = this.characterWidth * (this.session.$getStringScreenWidth(val)[0]); + } + else { + posTop += this.lineHeight + 2; + } + } + + posLeft -= this.scrollLeft; + if (posLeft > this.$size.scrollerWidth - w) + posLeft = this.$size.scrollerWidth - w; + + posLeft += this.gutterWidth + this.margin.left; + + dom.setStyle(style, "height", h + "px"); + dom.setStyle(style, "width", w + "px"); + dom.translate(this.textarea, Math.min(posLeft, this.$size.scrollerWidth - w), Math.min(posTop, maxTop)); + }; + this.getFirstVisibleRow = function() { + return this.layerConfig.firstRow; + }; + this.getFirstFullyVisibleRow = function() { + return this.layerConfig.firstRow + (this.layerConfig.offset === 0 ? 0 : 1); + }; + this.getLastFullyVisibleRow = function() { + var config = this.layerConfig; + var lastRow = config.lastRow; + var top = this.session.documentToScreenRow(lastRow, 0) * config.lineHeight; + if (top - this.session.getScrollTop() > config.height - config.lineHeight) + return lastRow - 1; + return lastRow; + }; + this.getLastVisibleRow = function() { + return this.layerConfig.lastRow; + }; + + this.$padding = null; + this.setPadding = function(padding) { + this.$padding = padding; + this.$textLayer.setPadding(padding); + this.$cursorLayer.setPadding(padding); + this.$markerFront.setPadding(padding); + this.$markerBack.setPadding(padding); + this.$loop.schedule(this.CHANGE_FULL); + this.$updatePrintMargin(); + }; + + this.setScrollMargin = function(top, bottom, left, right) { + var sm = this.scrollMargin; + sm.top = top|0; + sm.bottom = bottom|0; + sm.right = right|0; + sm.left = left|0; + sm.v = sm.top + sm.bottom; + sm.h = sm.left + sm.right; + if (sm.top && this.scrollTop <= 0 && this.session) + this.session.setScrollTop(-sm.top); + this.updateFull(); + }; + + this.setMargin = function(top, bottom, left, right) { + var sm = this.margin; + sm.top = top|0; + sm.bottom = bottom|0; + sm.right = right|0; + sm.left = left|0; + sm.v = sm.top + sm.bottom; + sm.h = sm.left + sm.right; + this.$updateCachedSize(true, this.gutterWidth, this.$size.width, this.$size.height); + this.updateFull(); + }; + this.getHScrollBarAlwaysVisible = function() { + return this.$hScrollBarAlwaysVisible; + }; + this.setHScrollBarAlwaysVisible = function(alwaysVisible) { + this.setOption("hScrollBarAlwaysVisible", alwaysVisible); + }; + this.getVScrollBarAlwaysVisible = function() { + return this.$vScrollBarAlwaysVisible; + }; + this.setVScrollBarAlwaysVisible = function(alwaysVisible) { + this.setOption("vScrollBarAlwaysVisible", alwaysVisible); + }; + + this.$updateScrollBarV = function() { + var scrollHeight = this.layerConfig.maxHeight; + var scrollerHeight = this.$size.scrollerHeight; + if (!this.$maxLines && this.$scrollPastEnd) { + scrollHeight -= (scrollerHeight - this.lineHeight) * this.$scrollPastEnd; + if (this.scrollTop > scrollHeight - scrollerHeight) { + scrollHeight = this.scrollTop + scrollerHeight; + this.scrollBarV.scrollTop = null; + } + } + this.scrollBarV.setScrollHeight(scrollHeight + this.scrollMargin.v); + this.scrollBarV.setScrollTop(this.scrollTop + this.scrollMargin.top); + }; + this.$updateScrollBarH = function() { + this.scrollBarH.setScrollWidth(this.layerConfig.width + 2 * this.$padding + this.scrollMargin.h); + this.scrollBarH.setScrollLeft(this.scrollLeft + this.scrollMargin.left); + }; + + this.$frozen = false; + this.freeze = function() { + this.$frozen = true; + }; + + this.unfreeze = function() { + this.$frozen = false; + }; + + this.$renderChanges = function(changes, force) { + if (this.$changes) { + changes |= this.$changes; + this.$changes = 0; + } + if ((!this.session || !this.container.offsetWidth || this.$frozen) || (!changes && !force)) { + this.$changes |= changes; + return; + } + if (this.$size.$dirty) { + this.$changes |= changes; + return this.onResize(true); + } + if (!this.lineHeight) { + this.$textLayer.checkForSizeChanges(); + } + + this._signal("beforeRender"); + + if (this.session && this.session.$bidiHandler) + this.session.$bidiHandler.updateCharacterWidths(this.$fontMetrics); + + var config = this.layerConfig; + if (changes & this.CHANGE_FULL || + changes & this.CHANGE_SIZE || + changes & this.CHANGE_TEXT || + changes & this.CHANGE_LINES || + changes & this.CHANGE_SCROLL || + changes & this.CHANGE_H_SCROLL + ) { + changes |= this.$computeLayerConfig() | this.$loop.clear(); + if (config.firstRow != this.layerConfig.firstRow && config.firstRowScreen == this.layerConfig.firstRowScreen) { + var st = this.scrollTop + (config.firstRow - this.layerConfig.firstRow) * this.lineHeight; + if (st > 0) { + this.scrollTop = st; + changes = changes | this.CHANGE_SCROLL; + changes |= this.$computeLayerConfig() | this.$loop.clear(); + } + } + config = this.layerConfig; + this.$updateScrollBarV(); + if (changes & this.CHANGE_H_SCROLL) + this.$updateScrollBarH(); + + dom.translate(this.content, -this.scrollLeft, -config.offset); + + var width = config.width + 2 * this.$padding + "px"; + var height = config.minHeight + "px"; + + dom.setStyle(this.content.style, "width", width); + dom.setStyle(this.content.style, "height", height); + } + if (changes & this.CHANGE_H_SCROLL) { + dom.translate(this.content, -this.scrollLeft, -config.offset); + this.scroller.className = this.scrollLeft <= 0 ? "ace_scroller" : "ace_scroller ace_scroll-left"; + } + if (changes & this.CHANGE_FULL) { + this.$changedLines = null; + this.$textLayer.update(config); + if (this.$showGutter) + this.$gutterLayer.update(config); + this.$markerBack.update(config); + this.$markerFront.update(config); + this.$cursorLayer.update(config); + this.$moveTextAreaToCursor(); + this._signal("afterRender"); + return; + } + if (changes & this.CHANGE_SCROLL) { + this.$changedLines = null; + if (changes & this.CHANGE_TEXT || changes & this.CHANGE_LINES) + this.$textLayer.update(config); + else + this.$textLayer.scrollLines(config); + + if (this.$showGutter) { + if (changes & this.CHANGE_GUTTER || changes & this.CHANGE_LINES) + this.$gutterLayer.update(config); + else + this.$gutterLayer.scrollLines(config); + } + this.$markerBack.update(config); + this.$markerFront.update(config); + this.$cursorLayer.update(config); + this.$moveTextAreaToCursor(); + this._signal("afterRender"); + return; + } + + if (changes & this.CHANGE_TEXT) { + this.$changedLines = null; + this.$textLayer.update(config); + if (this.$showGutter) + this.$gutterLayer.update(config); + } + else if (changes & this.CHANGE_LINES) { + if (this.$updateLines() || (changes & this.CHANGE_GUTTER) && this.$showGutter) + this.$gutterLayer.update(config); + } + else if (changes & this.CHANGE_TEXT || changes & this.CHANGE_GUTTER) { + if (this.$showGutter) + this.$gutterLayer.update(config); + } + else if (changes & this.CHANGE_CURSOR) { + if (this.$highlightGutterLine) + this.$gutterLayer.updateLineHighlight(config); + } + + if (changes & this.CHANGE_CURSOR) { + this.$cursorLayer.update(config); + this.$moveTextAreaToCursor(); + } + + if (changes & (this.CHANGE_MARKER | this.CHANGE_MARKER_FRONT)) { + this.$markerFront.update(config); + } + + if (changes & (this.CHANGE_MARKER | this.CHANGE_MARKER_BACK)) { + this.$markerBack.update(config); + } + + this._signal("afterRender"); + }; + + + this.$autosize = function() { + var height = this.session.getScreenLength() * this.lineHeight; + var maxHeight = this.$maxLines * this.lineHeight; + var desiredHeight = Math.min(maxHeight, + Math.max((this.$minLines || 1) * this.lineHeight, height) + ) + this.scrollMargin.v + (this.$extraHeight || 0); + if (this.$horizScroll) + desiredHeight += this.scrollBarH.getHeight(); + if (this.$maxPixelHeight && desiredHeight > this.$maxPixelHeight) + desiredHeight = this.$maxPixelHeight; + + var hideScrollbars = desiredHeight <= 2 * this.lineHeight; + var vScroll = !hideScrollbars && height > maxHeight; + + if (desiredHeight != this.desiredHeight || + this.$size.height != this.desiredHeight || vScroll != this.$vScroll) { + if (vScroll != this.$vScroll) { + this.$vScroll = vScroll; + this.scrollBarV.setVisible(vScroll); + } + + var w = this.container.clientWidth; + this.container.style.height = desiredHeight + "px"; + this.$updateCachedSize(true, this.$gutterWidth, w, desiredHeight); + this.desiredHeight = desiredHeight; + + this._signal("autosize"); + } + }; + + this.$computeLayerConfig = function() { + var session = this.session; + var size = this.$size; + + var hideScrollbars = size.height <= 2 * this.lineHeight; + var screenLines = this.session.getScreenLength(); + var maxHeight = screenLines * this.lineHeight; + + var longestLine = this.$getLongestLine(); + + var horizScroll = !hideScrollbars && (this.$hScrollBarAlwaysVisible || + size.scrollerWidth - longestLine - 2 * this.$padding < 0); + + var hScrollChanged = this.$horizScroll !== horizScroll; + if (hScrollChanged) { + this.$horizScroll = horizScroll; + this.scrollBarH.setVisible(horizScroll); + } + var vScrollBefore = this.$vScroll; // autosize can change vscroll value in which case we need to update longestLine + if (this.$maxLines && this.lineHeight > 1) + this.$autosize(); + + var minHeight = size.scrollerHeight + this.lineHeight; + + var scrollPastEnd = !this.$maxLines && this.$scrollPastEnd + ? (size.scrollerHeight - this.lineHeight) * this.$scrollPastEnd + : 0; + maxHeight += scrollPastEnd; + + var sm = this.scrollMargin; + this.session.setScrollTop(Math.max(-sm.top, + Math.min(this.scrollTop, maxHeight - size.scrollerHeight + sm.bottom))); + + this.session.setScrollLeft(Math.max(-sm.left, Math.min(this.scrollLeft, + longestLine + 2 * this.$padding - size.scrollerWidth + sm.right))); + + var vScroll = !hideScrollbars && (this.$vScrollBarAlwaysVisible || + size.scrollerHeight - maxHeight + scrollPastEnd < 0 || this.scrollTop > sm.top); + var vScrollChanged = vScrollBefore !== vScroll; + if (vScrollChanged) { + this.$vScroll = vScroll; + this.scrollBarV.setVisible(vScroll); + } + + var offset = this.scrollTop % this.lineHeight; + var lineCount = Math.ceil(minHeight / this.lineHeight) - 1; + var firstRow = Math.max(0, Math.round((this.scrollTop - offset) / this.lineHeight)); + var lastRow = firstRow + lineCount; + var firstRowScreen, firstRowHeight; + var lineHeight = this.lineHeight; + firstRow = session.screenToDocumentRow(firstRow, 0); + var foldLine = session.getFoldLine(firstRow); + if (foldLine) { + firstRow = foldLine.start.row; + } + + firstRowScreen = session.documentToScreenRow(firstRow, 0); + firstRowHeight = session.getRowLength(firstRow) * lineHeight; + + lastRow = Math.min(session.screenToDocumentRow(lastRow, 0), session.getLength() - 1); + minHeight = size.scrollerHeight + session.getRowLength(lastRow) * lineHeight + + firstRowHeight; + + offset = this.scrollTop - firstRowScreen * lineHeight; + + var changes = 0; + if (this.layerConfig.width != longestLine || hScrollChanged) + changes = this.CHANGE_H_SCROLL; + if (hScrollChanged || vScrollChanged) { + changes |= this.$updateCachedSize(true, this.gutterWidth, size.width, size.height); + this._signal("scrollbarVisibilityChanged"); + if (vScrollChanged) + longestLine = this.$getLongestLine(); + } + + this.layerConfig = { + width : longestLine, + padding : this.$padding, + firstRow : firstRow, + firstRowScreen: firstRowScreen, + lastRow : lastRow, + lineHeight : lineHeight, + characterWidth : this.characterWidth, + minHeight : minHeight, + maxHeight : maxHeight, + offset : offset, + gutterOffset : lineHeight ? Math.max(0, Math.ceil((offset + size.height - size.scrollerHeight) / lineHeight)) : 0, + height : this.$size.scrollerHeight + }; + + if (this.session.$bidiHandler) + this.session.$bidiHandler.setContentWidth(longestLine - this.$padding); + + return changes; + }; + + this.$updateLines = function() { + if (!this.$changedLines) return; + var firstRow = this.$changedLines.firstRow; + var lastRow = this.$changedLines.lastRow; + this.$changedLines = null; + + var layerConfig = this.layerConfig; + + if (firstRow > layerConfig.lastRow + 1) { return; } + if (lastRow < layerConfig.firstRow) { return; } + if (lastRow === Infinity) { + if (this.$showGutter) + this.$gutterLayer.update(layerConfig); + this.$textLayer.update(layerConfig); + return; + } + this.$textLayer.updateLines(layerConfig, firstRow, lastRow); + return true; + }; + + this.$getLongestLine = function() { + var charCount = this.session.getScreenWidth(); + if (this.showInvisibles && !this.session.$useWrapMode) + charCount += 1; + + if (this.$textLayer && charCount > this.$textLayer.MAX_LINE_LENGTH) + charCount = this.$textLayer.MAX_LINE_LENGTH + 30; + + return Math.max(this.$size.scrollerWidth - 2 * this.$padding, Math.round(charCount * this.characterWidth)); + }; + this.updateFrontMarkers = function() { + this.$markerFront.setMarkers(this.session.getMarkers(true)); + this.$loop.schedule(this.CHANGE_MARKER_FRONT); + }; + this.updateBackMarkers = function() { + this.$markerBack.setMarkers(this.session.getMarkers()); + this.$loop.schedule(this.CHANGE_MARKER_BACK); + }; + this.addGutterDecoration = function(row, className){ + this.$gutterLayer.addGutterDecoration(row, className); + }; + this.removeGutterDecoration = function(row, className){ + this.$gutterLayer.removeGutterDecoration(row, className); + }; + this.updateBreakpoints = function(rows) { + this.$loop.schedule(this.CHANGE_GUTTER); + }; + this.setAnnotations = function(annotations) { + this.$gutterLayer.setAnnotations(annotations); + this.$loop.schedule(this.CHANGE_GUTTER); + }; + this.updateCursor = function() { + this.$loop.schedule(this.CHANGE_CURSOR); + }; + this.hideCursor = function() { + this.$cursorLayer.hideCursor(); + }; + this.showCursor = function() { + this.$cursorLayer.showCursor(); + }; + + this.scrollSelectionIntoView = function(anchor, lead, offset) { + this.scrollCursorIntoView(anchor, offset); + this.scrollCursorIntoView(lead, offset); + }; + this.scrollCursorIntoView = function(cursor, offset, $viewMargin) { + if (this.$size.scrollerHeight === 0) + return; + + var pos = this.$cursorLayer.getPixelPosition(cursor); + + var left = pos.left; + var top = pos.top; + + var topMargin = $viewMargin && $viewMargin.top || 0; + var bottomMargin = $viewMargin && $viewMargin.bottom || 0; + + var scrollTop = this.$scrollAnimation ? this.session.getScrollTop() : this.scrollTop; + + if (scrollTop + topMargin > top) { + if (offset && scrollTop + topMargin > top + this.lineHeight) + top -= offset * this.$size.scrollerHeight; + if (top === 0) + top = -this.scrollMargin.top; + this.session.setScrollTop(top); + } else if (scrollTop + this.$size.scrollerHeight - bottomMargin < top + this.lineHeight) { + if (offset && scrollTop + this.$size.scrollerHeight - bottomMargin < top - this.lineHeight) + top += offset * this.$size.scrollerHeight; + this.session.setScrollTop(top + this.lineHeight + bottomMargin - this.$size.scrollerHeight); + } + + var scrollLeft = this.scrollLeft; + + if (scrollLeft > left) { + if (left < this.$padding + 2 * this.layerConfig.characterWidth) + left = -this.scrollMargin.left; + this.session.setScrollLeft(left); + } else if (scrollLeft + this.$size.scrollerWidth < left + this.characterWidth) { + this.session.setScrollLeft(Math.round(left + this.characterWidth - this.$size.scrollerWidth)); + } else if (scrollLeft <= this.$padding && left - scrollLeft < this.characterWidth) { + this.session.setScrollLeft(0); + } + }; + this.getScrollTop = function() { + return this.session.getScrollTop(); + }; + this.getScrollLeft = function() { + return this.session.getScrollLeft(); + }; + this.getScrollTopRow = function() { + return this.scrollTop / this.lineHeight; + }; + this.getScrollBottomRow = function() { + return Math.max(0, Math.floor((this.scrollTop + this.$size.scrollerHeight) / this.lineHeight) - 1); + }; + this.scrollToRow = function(row) { + this.session.setScrollTop(row * this.lineHeight); + }; + + this.alignCursor = function(cursor, alignment) { + if (typeof cursor == "number") + cursor = {row: cursor, column: 0}; + + var pos = this.$cursorLayer.getPixelPosition(cursor); + var h = this.$size.scrollerHeight - this.lineHeight; + var offset = pos.top - h * (alignment || 0); + + this.session.setScrollTop(offset); + return offset; + }; + + this.STEPS = 8; + this.$calcSteps = function(fromValue, toValue){ + var i = 0; + var l = this.STEPS; + var steps = []; + + var func = function(t, x_min, dx) { + return dx * (Math.pow(t - 1, 3) + 1) + x_min; + }; + + for (i = 0; i < l; ++i) + steps.push(func(i / this.STEPS, fromValue, toValue - fromValue)); + + return steps; + }; + this.scrollToLine = function(line, center, animate, callback) { + var pos = this.$cursorLayer.getPixelPosition({row: line, column: 0}); + var offset = pos.top; + if (center) + offset -= this.$size.scrollerHeight / 2; + + var initialScroll = this.scrollTop; + this.session.setScrollTop(offset); + if (animate !== false) + this.animateScrolling(initialScroll, callback); + }; + + this.animateScrolling = function(fromValue, callback) { + var toValue = this.scrollTop; + if (!this.$animatedScroll) + return; + var _self = this; + + if (fromValue == toValue) + return; + + if (this.$scrollAnimation) { + var oldSteps = this.$scrollAnimation.steps; + if (oldSteps.length) { + fromValue = oldSteps[0]; + if (fromValue == toValue) + return; + } + } + + var steps = _self.$calcSteps(fromValue, toValue); + this.$scrollAnimation = {from: fromValue, to: toValue, steps: steps}; + + clearInterval(this.$timer); + + _self.session.setScrollTop(steps.shift()); + _self.session.$scrollTop = toValue; + this.$timer = setInterval(function() { + if (steps.length) { + _self.session.setScrollTop(steps.shift()); + _self.session.$scrollTop = toValue; + } else if (toValue != null) { + _self.session.$scrollTop = -1; + _self.session.setScrollTop(toValue); + toValue = null; + } else { + _self.$timer = clearInterval(_self.$timer); + _self.$scrollAnimation = null; + callback && callback(); + } + }, 10); + }; + this.scrollToY = function(scrollTop) { + if (this.scrollTop !== scrollTop) { + this.$loop.schedule(this.CHANGE_SCROLL); + this.scrollTop = scrollTop; + } + }; + this.scrollToX = function(scrollLeft) { + if (this.scrollLeft !== scrollLeft) + this.scrollLeft = scrollLeft; + this.$loop.schedule(this.CHANGE_H_SCROLL); + }; + this.scrollTo = function(x, y) { + this.session.setScrollTop(y); + this.session.setScrollLeft(y); + }; + this.scrollBy = function(deltaX, deltaY) { + deltaY && this.session.setScrollTop(this.session.getScrollTop() + deltaY); + deltaX && this.session.setScrollLeft(this.session.getScrollLeft() + deltaX); + }; + this.isScrollableBy = function(deltaX, deltaY) { + if (deltaY < 0 && this.session.getScrollTop() >= 1 - this.scrollMargin.top) + return true; + if (deltaY > 0 && this.session.getScrollTop() + this.$size.scrollerHeight + - this.layerConfig.maxHeight < -1 + this.scrollMargin.bottom) + return true; + if (deltaX < 0 && this.session.getScrollLeft() >= 1 - this.scrollMargin.left) + return true; + if (deltaX > 0 && this.session.getScrollLeft() + this.$size.scrollerWidth + - this.layerConfig.width < -1 + this.scrollMargin.right) + return true; + }; + + this.pixelToScreenCoordinates = function(x, y) { + var canvasPos; + if (this.$hasCssTransforms) { + canvasPos = {top:0, left: 0}; + var p = this.$fontMetrics.transformCoordinates([x, y]); + x = p[1] - this.gutterWidth - this.margin.left; + y = p[0]; + } else { + canvasPos = this.scroller.getBoundingClientRect(); + } + + var offsetX = x + this.scrollLeft - canvasPos.left - this.$padding; + var offset = offsetX / this.characterWidth; + var row = Math.floor((y + this.scrollTop - canvasPos.top) / this.lineHeight); + var col = this.$blockCursor ? Math.floor(offset) : Math.round(offset); + + return {row: row, column: col, side: offset - col > 0 ? 1 : -1, offsetX: offsetX}; + }; + + this.screenToTextCoordinates = function(x, y) { + var canvasPos; + if (this.$hasCssTransforms) { + canvasPos = {top:0, left: 0}; + var p = this.$fontMetrics.transformCoordinates([x, y]); + x = p[1] - this.gutterWidth - this.margin.left; + y = p[0]; + } else { + canvasPos = this.scroller.getBoundingClientRect(); + } + + var offsetX = x + this.scrollLeft - canvasPos.left - this.$padding; + var offset = offsetX / this.characterWidth; + var col = this.$blockCursor ? Math.floor(offset) : Math.round(offset); + + var row = Math.floor((y + this.scrollTop - canvasPos.top) / this.lineHeight); + + return this.session.screenToDocumentPosition(row, Math.max(col, 0), offsetX); + }; + this.textToScreenCoordinates = function(row, column) { + var canvasPos = this.scroller.getBoundingClientRect(); + var pos = this.session.documentToScreenPosition(row, column); + + var x = this.$padding + (this.session.$bidiHandler.isBidiRow(pos.row, row) + ? this.session.$bidiHandler.getPosLeft(pos.column) + : Math.round(pos.column * this.characterWidth)); + + var y = pos.row * this.lineHeight; + + return { + pageX: canvasPos.left + x - this.scrollLeft, + pageY: canvasPos.top + y - this.scrollTop + }; + }; + this.visualizeFocus = function() { + dom.addCssClass(this.container, "ace_focus"); + }; + this.visualizeBlur = function() { + dom.removeCssClass(this.container, "ace_focus"); + }; + this.showComposition = function(composition) { + this.$composition = composition; + if (!composition.cssText) { + composition.cssText = this.textarea.style.cssText; + } + composition.useTextareaForIME = this.$useTextareaForIME; + + if (this.$useTextareaForIME) { + dom.addCssClass(this.textarea, "ace_composition"); + this.textarea.style.cssText = ""; + this.$moveTextAreaToCursor(); + this.$cursorLayer.element.style.display = "none"; + } + else { + composition.markerId = this.session.addMarker(composition.markerRange, "ace_composition_marker", "text"); + } + }; + this.setCompositionText = function(text) { + var cursor = this.session.selection.cursor; + this.addToken(text, "composition_placeholder", cursor.row, cursor.column); + this.$moveTextAreaToCursor(); + }; + this.hideComposition = function() { + if (!this.$composition) + return; + + if (this.$composition.markerId) + this.session.removeMarker(this.$composition.markerId); + + dom.removeCssClass(this.textarea, "ace_composition"); + this.textarea.style.cssText = this.$composition.cssText; + this.$composition = null; + this.$cursorLayer.element.style.display = ""; + }; + + this.addToken = function(text, type, row, column) { + var session = this.session; + session.bgTokenizer.lines[row] = null; + var newToken = {type: type, value: text}; + var tokens = session.getTokens(row); + if (column == null) { + tokens.push(newToken); + } else { + var l = 0; + for (var i =0; i < tokens.length; i++) { + var token = tokens[i]; + l += token.value.length; + if (column <= l) { + var diff = token.value.length - (l - column); + var before = token.value.slice(0, diff); + var after = token.value.slice(diff); + + tokens.splice(i, 1, {type: token.type, value: before}, newToken, {type: token.type, value: after}); + break; + } + } + } + this.updateLines(row, row); + }; + this.setTheme = function(theme, cb) { + var _self = this; + this.$themeId = theme; + _self._dispatchEvent('themeChange',{theme:theme}); + + if (!theme || typeof theme == "string") { + var moduleName = theme || this.$options.theme.initialValue; + config.loadModule(["theme", moduleName], afterLoad); + } else { + afterLoad(theme); + } + + function afterLoad(module) { + if (_self.$themeId != theme) + return cb && cb(); + if (!module || !module.cssClass) + throw new Error("couldn't load module " + theme + " or it didn't call define"); + if (module.$id) + _self.$themeId = module.$id; + dom.importCssString( + module.cssText, + module.cssClass, + _self.container + ); + + if (_self.theme) + dom.removeCssClass(_self.container, _self.theme.cssClass); + + var padding = "padding" in module ? module.padding + : "padding" in (_self.theme || {}) ? 4 : _self.$padding; + if (_self.$padding && padding != _self.$padding) + _self.setPadding(padding); + _self.$theme = module.cssClass; + + _self.theme = module; + dom.addCssClass(_self.container, module.cssClass); + dom.setCssClass(_self.container, "ace_dark", module.isDark); + if (_self.$size) { + _self.$size.width = 0; + _self.$updateSizeAsync(); + } + + _self._dispatchEvent('themeLoaded', {theme:module}); + cb && cb(); + } + }; + this.getTheme = function() { + return this.$themeId; + }; + this.setStyle = function(style, include) { + dom.setCssClass(this.container, style, include !== false); + }; + this.unsetStyle = function(style) { + dom.removeCssClass(this.container, style); + }; + + this.setCursorStyle = function(style) { + dom.setStyle(this.scroller.style, "cursor", style); + }; + this.setMouseCursor = function(cursorStyle) { + dom.setStyle(this.scroller.style, "cursor", cursorStyle); + }; + + this.attachToShadowRoot = function() { + dom.importCssString(editorCss, "ace_editor.css", this.container); + }; + this.destroy = function() { + this.freeze(); + this.$fontMetrics.destroy(); + this.$cursorLayer.destroy(); + }; + +}).call(VirtualRenderer.prototype); + + +config.defineOptions(VirtualRenderer.prototype, "renderer", { + animatedScroll: {initialValue: false}, + showInvisibles: { + set: function(value) { + if (this.$textLayer.setShowInvisibles(value)) + this.$loop.schedule(this.CHANGE_TEXT); + }, + initialValue: false + }, + showPrintMargin: { + set: function() { this.$updatePrintMargin(); }, + initialValue: true + }, + printMarginColumn: { + set: function() { this.$updatePrintMargin(); }, + initialValue: 80 + }, + printMargin: { + set: function(val) { + if (typeof val == "number") + this.$printMarginColumn = val; + this.$showPrintMargin = !!val; + this.$updatePrintMargin(); + }, + get: function() { + return this.$showPrintMargin && this.$printMarginColumn; + } + }, + showGutter: { + set: function(show){ + this.$gutter.style.display = show ? "block" : "none"; + this.$loop.schedule(this.CHANGE_FULL); + this.onGutterResize(); + }, + initialValue: true + }, + fadeFoldWidgets: { + set: function(show) { + dom.setCssClass(this.$gutter, "ace_fade-fold-widgets", show); + }, + initialValue: false + }, + showFoldWidgets: { + set: function(show) { + this.$gutterLayer.setShowFoldWidgets(show); + this.$loop.schedule(this.CHANGE_GUTTER); + }, + initialValue: true + }, + displayIndentGuides: { + set: function(show) { + if (this.$textLayer.setDisplayIndentGuides(show)) + this.$loop.schedule(this.CHANGE_TEXT); + }, + initialValue: true + }, + highlightGutterLine: { + set: function(shouldHighlight) { + this.$gutterLayer.setHighlightGutterLine(shouldHighlight); + this.$loop.schedule(this.CHANGE_GUTTER); + }, + initialValue: true + }, + hScrollBarAlwaysVisible: { + set: function(val) { + if (!this.$hScrollBarAlwaysVisible || !this.$horizScroll) + this.$loop.schedule(this.CHANGE_SCROLL); + }, + initialValue: false + }, + vScrollBarAlwaysVisible: { + set: function(val) { + if (!this.$vScrollBarAlwaysVisible || !this.$vScroll) + this.$loop.schedule(this.CHANGE_SCROLL); + }, + initialValue: false + }, + fontSize: { + set: function(size) { + if (typeof size == "number") + size = size + "px"; + this.container.style.fontSize = size; + this.updateFontSize(); + }, + initialValue: 12 + }, + fontFamily: { + set: function(name) { + this.container.style.fontFamily = name; + this.updateFontSize(); + } + }, + maxLines: { + set: function(val) { + this.updateFull(); + } + }, + minLines: { + set: function(val) { + if (!(this.$minLines < 0x1ffffffffffff)) + this.$minLines = 0; + this.updateFull(); + } + }, + maxPixelHeight: { + set: function(val) { + this.updateFull(); + }, + initialValue: 0 + }, + scrollPastEnd: { + set: function(val) { + val = +val || 0; + if (this.$scrollPastEnd == val) + return; + this.$scrollPastEnd = val; + this.$loop.schedule(this.CHANGE_SCROLL); + }, + initialValue: 0, + handlesSet: true + }, + fixedWidthGutter: { + set: function(val) { + this.$gutterLayer.$fixedWidth = !!val; + this.$loop.schedule(this.CHANGE_GUTTER); + } + }, + theme: { + set: function(val) { this.setTheme(val); }, + get: function() { return this.$themeId || this.theme; }, + initialValue: "./theme/textmate", + handlesSet: true + }, + hasCssTransforms: { + }, + useTextareaForIME: { + initialValue: !useragent.isMobile && !useragent.isIE + } +}); + +exports.VirtualRenderer = VirtualRenderer; +}); + +define("ace/worker/worker_client",["require","exports","module","ace/lib/oop","ace/lib/net","ace/lib/event_emitter","ace/config"], function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var net = require("../lib/net"); +var EventEmitter = require("../lib/event_emitter").EventEmitter; +var config = require("../config"); + +function $workerBlob(workerUrl) { + var script = "importScripts('" + net.qualifyURL(workerUrl) + "');"; + try { + return new Blob([script], {"type": "application/javascript"}); + } catch (e) { // Backwards-compatibility + var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder; + var blobBuilder = new BlobBuilder(); + blobBuilder.append(script); + return blobBuilder.getBlob("application/javascript"); + } +} + +function createWorker(workerUrl) { + if (typeof Worker == "undefined") + return { postMessage: function() {}, terminate: function() {} }; + if (config.get("loadWorkerFromBlob")) { + var blob = $workerBlob(workerUrl); + var URL = window.URL || window.webkitURL; + var blobURL = URL.createObjectURL(blob); + return new Worker(blobURL); + } + return new Worker(workerUrl); +} + +var WorkerClient = function(worker) { + if (!worker.postMessage) + worker = this.$createWorkerFromOldConfig.apply(this, arguments); + + this.$worker = worker; + this.$sendDeltaQueue = this.$sendDeltaQueue.bind(this); + this.changeListener = this.changeListener.bind(this); + this.onMessage = this.onMessage.bind(this); + + this.callbackId = 1; + this.callbacks = {}; + + this.$worker.onmessage = this.onMessage; +}; + +(function(){ + + oop.implement(this, EventEmitter); + + this.$createWorkerFromOldConfig = function(topLevelNamespaces, mod, classname, workerUrl, importScripts) { + if (require.nameToUrl && !require.toUrl) + require.toUrl = require.nameToUrl; + + if (config.get("packaged") || !require.toUrl) { + workerUrl = workerUrl || config.moduleUrl(mod, "worker"); + } else { + var normalizePath = this.$normalizePath; + workerUrl = workerUrl || normalizePath(require.toUrl("ace/worker/worker.js", null, "_")); + + var tlns = {}; + topLevelNamespaces.forEach(function(ns) { + tlns[ns] = normalizePath(require.toUrl(ns, null, "_").replace(/(\.js)?(\?.*)?$/, "")); + }); + } + + this.$worker = createWorker(workerUrl); + if (importScripts) { + this.send("importScripts", importScripts); + } + this.$worker.postMessage({ + init : true, + tlns : tlns, + module : mod, + classname : classname + }); + return this.$worker; + }; + + this.onMessage = function(e) { + var msg = e.data; + switch (msg.type) { + case "event": + this._signal(msg.name, {data: msg.data}); + break; + case "call": + var callback = this.callbacks[msg.id]; + if (callback) { + callback(msg.data); + delete this.callbacks[msg.id]; + } + break; + case "error": + this.reportError(msg.data); + break; + case "log": + window.console && console.log && console.log.apply(console, msg.data); + break; + } + }; + + this.reportError = function(err) { + window.console && console.error && console.error(err); + }; + + this.$normalizePath = function(path) { + return net.qualifyURL(path); + }; + + this.terminate = function() { + this._signal("terminate", {}); + this.deltaQueue = null; + this.$worker.terminate(); + this.$worker = null; + if (this.$doc) + this.$doc.off("change", this.changeListener); + this.$doc = null; + }; + + this.send = function(cmd, args) { + this.$worker.postMessage({command: cmd, args: args}); + }; + + this.call = function(cmd, args, callback) { + if (callback) { + var id = this.callbackId++; + this.callbacks[id] = callback; + args.push(id); + } + this.send(cmd, args); + }; + + this.emit = function(event, data) { + try { + if (data.data && data.data.err) + data.data.err = {message: data.data.err.message, stack: data.data.err.stack, code: data.data.err.code}; + this.$worker.postMessage({event: event, data: {data: data.data}}); + } + catch(ex) { + console.error(ex.stack); + } + }; + + this.attachToDocument = function(doc) { + if (this.$doc) + this.terminate(); + + this.$doc = doc; + this.call("setValue", [doc.getValue()]); + doc.on("change", this.changeListener); + }; + + this.changeListener = function(delta) { + if (!this.deltaQueue) { + this.deltaQueue = []; + setTimeout(this.$sendDeltaQueue, 0); + } + if (delta.action == "insert") + this.deltaQueue.push(delta.start, delta.lines); + else + this.deltaQueue.push(delta.start, delta.end); + }; + + this.$sendDeltaQueue = function() { + var q = this.deltaQueue; + if (!q) return; + this.deltaQueue = null; + if (q.length > 50 && q.length > this.$doc.getLength() >> 1) { + this.call("setValue", [this.$doc.getValue()]); + } else + this.emit("change", {data: q}); + }; + +}).call(WorkerClient.prototype); + + +var UIWorkerClient = function(topLevelNamespaces, mod, classname) { + var main = null; + var emitSync = false; + var sender = Object.create(EventEmitter); + + var messageBuffer = []; + var workerClient = new WorkerClient({ + messageBuffer: messageBuffer, + terminate: function() {}, + postMessage: function(e) { + messageBuffer.push(e); + if (!main) return; + if (emitSync) + setTimeout(processNext); + else + processNext(); + } + }); + + workerClient.setEmitSync = function(val) { emitSync = val; }; + + var processNext = function() { + var msg = messageBuffer.shift(); + if (msg.command) + main[msg.command].apply(main, msg.args); + else if (msg.event) + sender._signal(msg.event, msg.data); + }; + + sender.postMessage = function(msg) { + workerClient.onMessage({data: msg}); + }; + sender.callback = function(data, callbackId) { + this.postMessage({type: "call", id: callbackId, data: data}); + }; + sender.emit = function(name, data) { + this.postMessage({type: "event", name: name, data: data}); + }; + + config.loadModule(["worker", mod], function(Main) { + main = new Main[classname](sender); + while (messageBuffer.length) + processNext(); + }); + + return workerClient; +}; + +exports.UIWorkerClient = UIWorkerClient; +exports.WorkerClient = WorkerClient; +exports.createWorker = createWorker; + + +}); + +define("ace/placeholder",["require","exports","module","ace/range","ace/lib/event_emitter","ace/lib/oop"], function(require, exports, module) { +"use strict"; + +var Range = require("./range").Range; +var EventEmitter = require("./lib/event_emitter").EventEmitter; +var oop = require("./lib/oop"); + +var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) { + var _self = this; + this.length = length; + this.session = session; + this.doc = session.getDocument(); + this.mainClass = mainClass; + this.othersClass = othersClass; + this.$onUpdate = this.onUpdate.bind(this); + this.doc.on("change", this.$onUpdate); + this.$others = others; + + this.$onCursorChange = function() { + setTimeout(function() { + _self.onCursorChange(); + }); + }; + + this.$pos = pos; + var undoStack = session.getUndoManager().$undoStack || session.getUndoManager().$undostack || {length: -1}; + this.$undoStackDepth = undoStack.length; + this.setup(); + + session.selection.on("changeCursor", this.$onCursorChange); +}; + +(function() { + + oop.implement(this, EventEmitter); + this.setup = function() { + var _self = this; + var doc = this.doc; + var session = this.session; + + this.selectionBefore = session.selection.toJSON(); + if (session.selection.inMultiSelectMode) + session.selection.toSingleRange(); + + this.pos = doc.createAnchor(this.$pos.row, this.$pos.column); + var pos = this.pos; + pos.$insertRight = true; + pos.detach(); + pos.markerId = session.addMarker(new Range(pos.row, pos.column, pos.row, pos.column + this.length), this.mainClass, null, false); + this.others = []; + this.$others.forEach(function(other) { + var anchor = doc.createAnchor(other.row, other.column); + anchor.$insertRight = true; + anchor.detach(); + _self.others.push(anchor); + }); + session.setUndoSelect(false); + }; + this.showOtherMarkers = function() { + if (this.othersActive) return; + var session = this.session; + var _self = this; + this.othersActive = true; + this.others.forEach(function(anchor) { + anchor.markerId = session.addMarker(new Range(anchor.row, anchor.column, anchor.row, anchor.column+_self.length), _self.othersClass, null, false); + }); + }; + this.hideOtherMarkers = function() { + if (!this.othersActive) return; + this.othersActive = false; + for (var i = 0; i < this.others.length; i++) { + this.session.removeMarker(this.others[i].markerId); + } + }; + this.onUpdate = function(delta) { + if (this.$updating) + return this.updateAnchors(delta); + + var range = delta; + if (range.start.row !== range.end.row) return; + if (range.start.row !== this.pos.row) return; + this.$updating = true; + var lengthDiff = delta.action === "insert" ? range.end.column - range.start.column : range.start.column - range.end.column; + var inMainRange = range.start.column >= this.pos.column && range.start.column <= this.pos.column + this.length + 1; + var distanceFromStart = range.start.column - this.pos.column; + + this.updateAnchors(delta); + + if (inMainRange) + this.length += lengthDiff; + + if (inMainRange && !this.session.$fromUndo) { + if (delta.action === 'insert') { + for (var i = this.others.length - 1; i >= 0; i--) { + var otherPos = this.others[i]; + var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart}; + this.doc.insertMergedLines(newPos, delta.lines); + } + } else if (delta.action === 'remove') { + for (var i = this.others.length - 1; i >= 0; i--) { + var otherPos = this.others[i]; + var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart}; + this.doc.remove(new Range(newPos.row, newPos.column, newPos.row, newPos.column - lengthDiff)); + } + } + } + + this.$updating = false; + this.updateMarkers(); + }; + + this.updateAnchors = function(delta) { + this.pos.onChange(delta); + for (var i = this.others.length; i--;) + this.others[i].onChange(delta); + this.updateMarkers(); + }; + + this.updateMarkers = function() { + if (this.$updating) + return; + var _self = this; + var session = this.session; + var updateMarker = function(pos, className) { + session.removeMarker(pos.markerId); + pos.markerId = session.addMarker(new Range(pos.row, pos.column, pos.row, pos.column+_self.length), className, null, false); + }; + updateMarker(this.pos, this.mainClass); + for (var i = this.others.length; i--;) + updateMarker(this.others[i], this.othersClass); + }; + + this.onCursorChange = function(event) { + if (this.$updating || !this.session) return; + var pos = this.session.selection.getCursor(); + if (pos.row === this.pos.row && pos.column >= this.pos.column && pos.column <= this.pos.column + this.length) { + this.showOtherMarkers(); + this._emit("cursorEnter", event); + } else { + this.hideOtherMarkers(); + this._emit("cursorLeave", event); + } + }; + this.detach = function() { + this.session.removeMarker(this.pos && this.pos.markerId); + this.hideOtherMarkers(); + this.doc.removeEventListener("change", this.$onUpdate); + this.session.selection.removeEventListener("changeCursor", this.$onCursorChange); + this.session.setUndoSelect(true); + this.session = null; + }; + this.cancel = function() { + if (this.$undoStackDepth === -1) + return; + var undoManager = this.session.getUndoManager(); + var undosRequired = (undoManager.$undoStack || undoManager.$undostack).length - this.$undoStackDepth; + for (var i = 0; i < undosRequired; i++) { + undoManager.undo(this.session, true); + } + if (this.selectionBefore) + this.session.selection.fromJSON(this.selectionBefore); + }; +}).call(PlaceHolder.prototype); + + +exports.PlaceHolder = PlaceHolder; +}); + +define("ace/mouse/multi_select_handler",["require","exports","module","ace/lib/event","ace/lib/useragent"], function(require, exports, module) { + +var event = require("../lib/event"); +var useragent = require("../lib/useragent"); +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 = ev.ctrlKey; + var accel = e.getAccelKey(); + var button = e.getButton(); + + if (ctrl && useragent.isMac) + button = ev.button; + + if (e.editor.inMultiSelectMode && button == 2) { + e.editor.textInput.onContextMenu(e.domEvent); + return; + } + + if (!ctrl && !alt && !accel) { + if (button === 0 && e.editor.inMultiSelectMode) + e.editor.exitMultiSelectMode(); + return; + } + + if (button !== 0) + 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.x, mouseY = e.y; + var onMouseSelection = function(e) { + mouseX = e.clientX; + mouseY = e.clientY; + }; + + var session = editor.session; + var screenAnchor = editor.renderer.pixelToScreenCoordinates(mouseX, mouseY); + var screenCursor = screenAnchor; + + var selectionMode; + if (editor.$mouseHandler.$enableJumpToDef) { + if (ctrl && alt || accel && alt) + selectionMode = shift ? "block" : "add"; + else if (alt && editor.$blockSelectEnabled) + selectionMode = "block"; + } else { + if (accel && !alt) { + selectionMode = "add"; + if (!isMultiSelect && shift) + return; + } else if (alt && editor.$blockSelectEnabled) { + selectionMode = "block"; + } + } + + if (selectionMode && useragent.isMac && ev.ctrlKey) { + editor.$mouseHandler.cancelContextMenu(); + } + + if (selectionMode == "add") { + if (!isMultiSelect && inSelection) + return; // dragging + + if (!isMultiSelect) { + var range = selection.toOrientedRange(); + editor.addSelectionMarker(range); + } + + var oldRange = selection.rangeList.rangeAtPoint(pos); + + editor.inVirtualSelectionMode = true; + + if (shift) { + oldRange = null; + range = selection.ranges[0] || range; + editor.removeSelectionMarker(range); + } + editor.once("mouseup", function() { + var tmpSel = selection.toOrientedRange(); + + if (oldRange && tmpSel.isEmpty() && isSamePoint(oldRange.cursor, tmpSel.cursor)) + selection.substractPoint(tmpSel.cursor); + else { + if (shift) { + selection.substractPoint(range.cursor); + } else if (range) { + editor.removeSelectionMarker(range); + selection.addRange(range); + } + selection.addRange(tmpSel); + } + editor.inVirtualSelectionMode = false; + }); + + } else if (selectionMode == "block") { + e.stop(); + editor.inVirtualSelectionMode = true; + var initialRange; + var rectSel = []; + var blockSelect = function() { + var newCursor = editor.renderer.pixelToScreenCoordinates(mouseX, mouseY); + var cursor = session.screenToDocumentPosition(newCursor.row, newCursor.column, newCursor.offsetX); + + if (isSamePoint(screenCursor, newCursor) && isSamePoint(cursor, selection.lead)) + return; + screenCursor = newCursor; + + editor.selection.moveToPosition(cursor); + editor.renderer.scrollCursorIntoView(); + + editor.removeSelectionMarkers(rectSel); + rectSel = selection.rectangularRangeBlock(screenCursor, screenAnchor); + if (editor.$mouseHandler.$clickSelection && rectSel.length == 1 && rectSel[0].isEmpty()) + rectSel[0] = editor.$mouseHandler.$clickSelection.clone(); + rectSel.forEach(editor.addSelectionMarker, editor); + editor.updateSelectionMarkers(); + }; + if (isMultiSelect && !accel) { + selection.toSingleRange(); + } else if (!isMultiSelect && accel) { + initialRange = selection.toOrientedRange(); + editor.addSelectionMarker(initialRange); + } + + if (shift) + screenAnchor = session.documentToScreenPosition(selection.lead); + else + selection.moveToPosition(pos); + + screenCursor = {row: -1, column: -1}; + + var onMouseSelectionEnd = function(e) { + blockSelect(); + clearInterval(timerId); + editor.removeSelectionMarkers(rectSel); + if (!rectSel.length) + rectSel = [selection.toOrientedRange()]; + if (initialRange) { + editor.removeSelectionMarker(initialRange); + selection.toSingleRange(initialRange); + } + for (var i = 0; i < rectSel.length; i++) + selection.addRange(rectSel[i]); + editor.inVirtualSelectionMode = false; + editor.$mouseHandler.$clickSelection = null; + }; + + var onSelectionInterval = blockSelect; + + event.capture(editor.container, onMouseSelection, onMouseSelectionEnd); + var timerId = setInterval(function() {onSelectionInterval();}, 20); + + return e.preventDefault(); + } +} + + +exports.onMouseDown = onMouseDown; + +}); + +define("ace/commands/multi_select_commands",["require","exports","module","ace/keyboard/hash_handler"], function(require, exports, module) { +exports.defaultCommands = [{ + name: "addCursorAbove", + description: "Add cursor above", + exec: function(editor) { editor.selectMoreLines(-1); }, + bindKey: {win: "Ctrl-Alt-Up", mac: "Ctrl-Alt-Up"}, + scrollIntoView: "cursor", + readOnly: true +}, { + name: "addCursorBelow", + description: "Add cursor below", + exec: function(editor) { editor.selectMoreLines(1); }, + bindKey: {win: "Ctrl-Alt-Down", mac: "Ctrl-Alt-Down"}, + scrollIntoView: "cursor", + readOnly: true +}, { + name: "addCursorAboveSkipCurrent", + description: "Add cursor above (skip current)", + exec: function(editor) { editor.selectMoreLines(-1, true); }, + bindKey: {win: "Ctrl-Alt-Shift-Up", mac: "Ctrl-Alt-Shift-Up"}, + scrollIntoView: "cursor", + readOnly: true +}, { + name: "addCursorBelowSkipCurrent", + description: "Add cursor below (skip current)", + exec: function(editor) { editor.selectMoreLines(1, true); }, + bindKey: {win: "Ctrl-Alt-Shift-Down", mac: "Ctrl-Alt-Shift-Down"}, + scrollIntoView: "cursor", + readOnly: true +}, { + name: "selectMoreBefore", + description: "Select more before", + exec: function(editor) { editor.selectMore(-1); }, + bindKey: {win: "Ctrl-Alt-Left", mac: "Ctrl-Alt-Left"}, + scrollIntoView: "cursor", + readOnly: true +}, { + name: "selectMoreAfter", + description: "Select more after", + exec: function(editor) { editor.selectMore(1); }, + bindKey: {win: "Ctrl-Alt-Right", mac: "Ctrl-Alt-Right"}, + scrollIntoView: "cursor", + readOnly: true +}, { + name: "selectNextBefore", + description: "Select next before", + exec: function(editor) { editor.selectMore(-1, true); }, + bindKey: {win: "Ctrl-Alt-Shift-Left", mac: "Ctrl-Alt-Shift-Left"}, + scrollIntoView: "cursor", + readOnly: true +}, { + name: "selectNextAfter", + description: "Select next after", + exec: function(editor) { editor.selectMore(1, true); }, + bindKey: {win: "Ctrl-Alt-Shift-Right", mac: "Ctrl-Alt-Shift-Right"}, + scrollIntoView: "cursor", + readOnly: true +}, { + name: "splitIntoLines", + description: "Split into lines", + exec: function(editor) { editor.multiSelect.splitIntoLines(); }, + bindKey: {win: "Ctrl-Alt-L", mac: "Ctrl-Alt-L"}, + readOnly: true +}, { + name: "alignCursors", + description: "Align cursors", + exec: function(editor) { editor.alignCursors(); }, + bindKey: {win: "Ctrl-Alt-A", mac: "Ctrl-Alt-A"}, + scrollIntoView: "cursor" +}, { + name: "findAll", + description: "Find all", + exec: function(editor) { editor.findAll(); }, + bindKey: {win: "Ctrl-Alt-K", mac: "Ctrl-Alt-G"}, + scrollIntoView: "cursor", + readOnly: true +}]; +exports.multiSelectCommands = [{ + name: "singleSelection", + description: "Single selection", + bindKey: "esc", + exec: function(editor) { editor.exitMultiSelectMode(); }, + scrollIntoView: "cursor", + readOnly: true, + isAvailable: function(editor) {return editor && editor.inMultiSelectMode;} +}]; + +var HashHandler = require("../keyboard/hash_handler").HashHandler; +exports.keyboardHandler = new HashHandler(exports.multiSelectCommands); + +}); + +define("ace/multi_select",["require","exports","module","ace/range_list","ace/range","ace/selection","ace/mouse/multi_select_handler","ace/lib/event","ace/lib/lang","ace/commands/multi_select_commands","ace/search","ace/edit_session","ace/editor","ace/config"], 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; +var event = require("./lib/event"); +var lang = require("./lib/lang"); +var commands = require("./commands/multi_select_commands"); +exports.commands = commands.defaultCommands.concat(commands.multiSelectCommands); +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); +} +var EditSession = require("./edit_session").EditSession; +(function() { + this.getSelectionMarkers = function() { + return this.$selectionMarkers; + }; +}).call(EditSession.prototype); +(function() { + this.ranges = null; + this.rangeList = null; + this.addRange = function(range, $blockChangeEvents) { + if (!range) + return; + + if (!this.inMultiSelectMode && this.rangeCount === 0) { + var oldRange = this.toOrientedRange(); + this.rangeList.add(oldRange); + this.rangeList.add(range); + if (this.rangeList.ranges.length != 2) { + this.rangeList.removeAll(); + return $blockChangeEvents || this.fromOrientedRange(range); + } + this.rangeList.removeAll(); + this.rangeList.add(oldRange); + this.$onAddRange(oldRange); + } + + 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 > 1 && !this.inMultiSelectMode) { + this._signal("multiSelect"); + this.inMultiSelectMode = true; + this.session.$undoSelect = false; + this.rangeList.attach(this.session); + } + + return $blockChangeEvents || this.fromOrientedRange(range); + }; + + this.toSingleRange = function(range) { + range = range || this.ranges[0]; + var removed = this.rangeList.removeAll(); + if (removed.length) + this.$onRemoveRange(removed); + + range && this.fromOrientedRange(range); + }; + this.substractPoint = function(pos) { + var removed = this.rangeList.substractPoint(pos); + if (removed) { + this.$onRemoveRange(removed); + return removed[0]; + } + }; + this.mergeOverlappingRanges = function() { + var removed = this.rangeList.merge(); + if (removed.length) + this.$onRemoveRange(removed); + }; + + this.$onAddRange = function(range) { + this.rangeCount = this.rangeList.ranges.length; + this.ranges.unshift(range); + this._signal("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._signal("removeRange", {ranges: removed}); + + if (this.rangeCount === 0 && this.inMultiSelectMode) { + this.inMultiSelectMode = false; + this._signal("singleSelect"); + this.session.$undoSelect = true; + this.rangeList.detach(this.session); + } + + lastRange = lastRange || this.ranges[0]; + if (lastRange && !lastRange.isEqual(this.getRange())) + this.fromOrientedRange(lastRange); + }; + this.$initRangeList = function() { + if (this.rangeList) + return; + + this.rangeList = new RangeList(); + this.ranges = []; + this.rangeCount = 0; + }; + this.getAllRanges = function() { + return this.rangeCount ? this.rangeList.ranges.concat() : [this.getRange()]; + }; + + 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 range = this.getRange(); + var isBackwards = this.isBackwards(); + var startRow = range.start.row; + var endRow = range.end.row; + if (startRow == endRow) { + if (isBackwards) + var start = range.end, end = range.start; + else + var start = range.start, end = range.end; + + this.addRange(Range.fromPoints(end, end)); + this.addRange(Range.fromPoints(start, start)); + return; + } + + var rectSel = []; + var r = this.getLineRange(startRow, true); + r.start.column = range.start.column; + rectSel.push(r); + + for (var i = startRow + 1; i < endRow; i++) + rectSel.push(this.getLineRange(i, true)); + + r = this.getLineRange(endRow, true); + r.end.column = range.end.column; + rectSel.push(r); + + rectSel.forEach(this.addRange, this); + } + }; + this.toggleBlockSelection = 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.cursor); + var anchor = this.session.documentToScreenPosition(this.anchor); + + var rectSel = this.rectangularRangeBlock(cursor, anchor); + rectSel.forEach(this.addRange, this); + } + }; + this.rectangularRangeBlock = function(screenCursor, screenAnchor, includeEmptyLines) { + var rectSel = []; + + var xBackwards = screenCursor.column < screenAnchor.column; + if (xBackwards) { + var startColumn = screenCursor.column; + var endColumn = screenAnchor.column; + var startOffsetX = screenCursor.offsetX; + var endOffsetX = screenAnchor.offsetX; + } else { + var startColumn = screenAnchor.column; + var endColumn = screenCursor.column; + var startOffsetX = screenAnchor.offsetX; + var endOffsetX = screenCursor.offsetX; + } + + 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; + + var docEnd; + for (var row = startRow; row <= endRow; row++) { + var range = Range.fromPoints( + this.session.screenToDocumentPosition(row, startColumn, startOffsetX), + this.session.screenToDocumentPosition(row, endColumn, endOffsetX) + ); + if (range.isEmpty()) { + if (docEnd && isSamePoint(range.end, docEnd)) + break; + 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); +var Editor = require("./editor").Editor; +(function() { + this.updateSelectionMarkers = function() { + this.renderer.updateCursor(); + this.renderer.updateBackMarkers(); + }; + 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.removeSelectionMarker = function(range) { + if (!range.marker) + return; + 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.removeSelectionMarkers = function(ranges) { + var markerList = this.session.$selectionMarkers; + for (var i = ranges.length; i--; ) { + var range = ranges[i]; + if (!range.marker) + continue; + this.session.removeMarker(range.marker); + var index = markerList.indexOf(range); + if (index != -1) + markerList.splice(index, 1); + } + this.session.selectionMarkerCount = markerList.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("ace_multiselect"); + this.keyBinding.addKeyboardHandler(commands.keyboardHandler); + this.commands.setDefaultHandler("exec", this.$onMultiSelectExec); + + this.renderer.updateCursor(); + this.renderer.updateBackMarkers(); + }; + + this.$onSingleSelect = function(e) { + if (this.session.multiSelect.inVirtualMode) + return; + this.inMultiSelectMode = false; + + this.unsetStyle("ace_multiselect"); + this.keyBinding.removeKeyboardHandler(commands.keyboardHandler); + + this.commands.removeDefaultHandler("exec", this.$onMultiSelectExec); + this.renderer.updateCursor(); + this.renderer.updateBackMarkers(); + this._emit("changeSelection"); + }; + + this.$onMultiSelectExec = function(e) { + var command = e.command; + var editor = e.editor; + if (!editor.multiSelect) + return; + if (!command.multiSelectAction) { + var result = command.exec(editor, e.args || {}); + editor.multiSelect.addRange(editor.multiSelect.toOrientedRange()); + editor.multiSelect.mergeOverlappingRanges(); + } else if (command.multiSelectAction == "forEach") { + result = editor.forEachSelection(command, e.args); + } else if (command.multiSelectAction == "forEachLine") { + result = editor.forEachSelection(command, e.args, true); + } else if (command.multiSelectAction == "single") { + editor.exitMultiSelectMode(); + result = command.exec(editor, e.args || {}); + } else { + result = command.multiSelectAction(editor, e.args || {}); + } + return result; + }; + this.forEachSelection = function(cmd, args, options) { + if (this.inVirtualSelectionMode) + return; + var keepOrder = options && options.keepOrder; + var $byLines = options == true || options && options.$byLines; + var session = this.session; + var selection = this.selection; + var rangeList = selection.rangeList; + var ranges = (keepOrder ? selection : rangeList).ranges; + var result; + + if (!ranges.length) + return cmd.exec ? cmd.exec(this, args || {}) : cmd(this, args || {}); + + var reg = selection._eventRegistry; + selection._eventRegistry = {}; + + var tmpSel = new Selection(session); + this.inVirtualSelectionMode = true; + for (var i = ranges.length; i--;) { + if ($byLines) { + while (i > 0 && ranges[i].start.row == ranges[i - 1].end.row) + i--; + } + tmpSel.fromOrientedRange(ranges[i]); + tmpSel.index = i; + this.selection = session.selection = tmpSel; + var cmdResult = cmd.exec ? cmd.exec(this, args || {}) : cmd(this, args || {}); + if (!result && cmdResult !== undefined) + result = cmdResult; + tmpSel.toOrientedRange(ranges[i]); + } + tmpSel.detach(); + + this.selection = session.selection = selection; + this.inVirtualSelectionMode = false; + selection._eventRegistry = reg; + selection.mergeOverlappingRanges(); + if (selection.ranges[0]) + selection.fromOrientedRange(selection.ranges[0]); + + var anim = this.renderer.$scrollAnimation; + this.onCursorChange(); + this.onSelectionChange(); + if (anim && anim.from == anim.to) + this.renderer.animateScrolling(anim.from); + + return result; + }; + this.exitMultiSelectMode = function() { + if (!this.inMultiSelectMode || this.inVirtualSelectionMode) + return; + this.multiSelect.toSingleRange(); + }; + + this.getSelectedText = function() { + var text = ""; + if (this.inMultiSelectMode && !this.inVirtualSelectionMode) { + var ranges = this.multiSelect.rangeList.ranges; + var buf = []; + for (var i = 0; i < ranges.length; i++) { + buf.push(this.session.getTextRange(ranges[i])); + } + var nl = this.session.getDocument().getNewLineCharacter(); + text = buf.join(nl); + if (text.length == (buf.length - 1) * nl.length) + text = ""; + } else if (!this.selection.isEmpty()) { + text = this.session.getTextRange(this.getSelectionRange()); + } + return text; + }; + + this.$checkMultiselectChange = function(e, anchor) { + if (this.inMultiSelectMode && !this.inVirtualSelectionMode) { + var range = this.multiSelect.ranges[0]; + if (this.multiSelect.isEmpty() && anchor == this.multiSelect.anchor) + return; + var pos = anchor == this.multiSelect.anchor + ? range.cursor == range.start ? range.end : range.start + : range.cursor; + if (pos.row != anchor.row + || this.session.$clipPositionToDocument(pos.row, pos.column).column != anchor.column) + this.multiSelect.toSingleRange(this.multiSelect.toOrientedRange()); + else + this.multiSelect.mergeOverlappingRanges(); + } + }; + this.findAll = function(needle, options, additive) { + options = options || {}; + options.needle = needle || options.needle; + if (options.needle == undefined) { + var range = this.selection.isEmpty() + ? this.selection.getWordRange() + : this.selection.getRange(); + options.needle = this.session.getTextRange(range); + } + this.$search.set(options); + + var ranges = this.$search.findAll(this.session); + if (!ranges.length) + return 0; + + var selection = this.multiSelect; + + if (!additive) + selection.toSingleRange(ranges[0]); + + for (var i = ranges.length; i--; ) + selection.addRange(ranges[i], true); + if (range && selection.rangeList.rangeAtPoint(range.start)) + selection.addRange(range, true); + + return ranges.length; + }; + 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); + }; + 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; + } + sel.fromOrientedRange(sel.ranges[0]); + }; + this.selectMore = function(dir, skip, stopAtFirst) { + var session = this.session; + var sel = session.multiSelect; + + var range = sel.toOrientedRange(); + if (range.isEmpty()) { + range = session.getWordRange(range.start.row, range.start.column); + range.cursor = dir == -1 ? range.start : range.end; + this.multiSelect.addRange(range); + if (stopAtFirst) + return; + } + var needle = session.getTextRange(range); + + var newRange = find(session, needle, dir); + if (newRange) { + newRange.cursor = dir == -1 ? newRange.start : newRange.end; + this.session.unfold(newRange); + this.multiSelect.addRange(newRange); + this.renderer.scrollCursorIntoView(null, 0.5); + } + if (skip) + this.multiSelect.substractPoint(range.cursor); + }; + this.alignCursors = function() { + var session = this.session; + var sel = session.multiSelect; + var ranges = sel.ranges; + var row = -1; + var sameRowRanges = ranges.filter(function(r) { + if (r.cursor.row == row) + return true; + row = r.cursor.row; + }); + + if (!ranges.length || sameRowRanges.length == ranges.length - 1) { + var range = this.selection.getRange(); + var fr = range.start.row, lr = range.end.row; + var guessRange = fr == lr; + if (guessRange) { + var max = this.session.getLength(); + var line; + do { + line = this.session.getLine(lr); + } while (/[=:]/.test(line) && ++lr < max); + do { + line = this.session.getLine(fr); + } while (/[=:]/.test(line) && --fr > 0); + + if (fr < 0) fr = 0; + if (lr >= max) lr = max - 1; + } + var lines = this.session.removeFullLines(fr, lr); + lines = this.$reAlignText(lines, guessRange); + this.session.insert({row: fr, column: 0}, lines.join("\n") + "\n"); + if (!guessRange) { + range.start.column = 0; + range.end.column = lines[lines.length - 1].length; + } + this.selection.setRange(range); + } else { + sameRowRanges.forEach(function(r) { + sel.substractPoint(r.cursor); + }); + + var maxCol = 0; + var minSpace = Infinity; + var spaceOffsets = ranges.map(function(r) { + var p = r.cursor; + var line = session.getLine(p.row); + var spaceOffset = line.substr(p.column).search(/\S/g); + if (spaceOffset == -1) + spaceOffset = 0; + + if (p.column > maxCol) + maxCol = p.column; + if (spaceOffset < minSpace) + minSpace = spaceOffset; + return spaceOffset; + }); + ranges.forEach(function(r, i) { + var p = r.cursor; + var l = maxCol - p.column; + var d = spaceOffsets[i] - minSpace; + if (l > d) + session.insert(p, lang.stringRepeat(" ", l - d)); + else + session.remove(new Range(p.row, p.column, p.row, p.column - l + d)); + + r.start.column = r.end.column = maxCol; + r.start.row = r.end.row = p.row; + r.cursor = r.end; + }); + sel.fromOrientedRange(ranges[0]); + this.renderer.updateCursor(); + this.renderer.updateBackMarkers(); + } + }; + + this.$reAlignText = function(lines, forceLeft) { + var isLeftAligned = true, isRightAligned = true; + var startW, textW, endW; + + return lines.map(function(line) { + var m = line.match(/(\s*)(.*?)(\s*)([=:].*)/); + if (!m) + return [line]; + + if (startW == null) { + startW = m[1].length; + textW = m[2].length; + endW = m[3].length; + return m; + } + + if (startW + textW + endW != m[1].length + m[2].length + m[3].length) + isRightAligned = false; + if (startW != m[1].length) + isLeftAligned = false; + + if (startW > m[1].length) + startW = m[1].length; + if (textW < m[2].length) + textW = m[2].length; + if (endW > m[3].length) + endW = m[3].length; + + return m; + }).map(forceLeft ? alignLeft : + isLeftAligned ? isRightAligned ? alignRight : alignLeft : unAlign); + + function spaces(n) { + return lang.stringRepeat(" ", n); + } + + function alignLeft(m) { + return !m[2] ? m[0] : spaces(startW) + m[2] + + spaces(textW - m[2].length + endW) + + m[4].replace(/^([=:])\s+/, "$1 "); + } + function alignRight(m) { + return !m[2] ? m[0] : spaces(startW + textW - m[2].length) + m[2] + + spaces(endW) + + m[4].replace(/^([=:])\s+/, "$1 "); + } + function unAlign(m) { + return !m[2] ? m[0] : spaces(startW) + m[2] + + spaces(endW) + + m[4].replace(/^([=:])\s+/, "$1 "); + } + }; +}).call(Editor.prototype); + + +function isSamePoint(p1, p2) { + return p1.row == p2.row && p1.column == p2.column; +} +exports.onSessionChange = function(e) { + var session = e.session; + if (session && !session.multiSelect) { + session.$selectionMarkers = []; + session.selection.$initRangeList(); + session.multiSelect = session.selection; + } + this.multiSelect = session && session.multiSelect; + + var oldSession = e.oldSession; + if (oldSession) { + oldSession.multiSelect.off("addRange", this.$onAddRange); + oldSession.multiSelect.off("removeRange", this.$onRemoveRange); + oldSession.multiSelect.off("multiSelect", this.$onMultiSelect); + oldSession.multiSelect.off("singleSelect", this.$onSingleSelect); + oldSession.multiSelect.lead.off("change", this.$checkMultiselectChange); + oldSession.multiSelect.anchor.off("change", this.$checkMultiselectChange); + } + + if (session) { + session.multiSelect.on("addRange", this.$onAddRange); + session.multiSelect.on("removeRange", this.$onRemoveRange); + session.multiSelect.on("multiSelect", this.$onMultiSelect); + session.multiSelect.on("singleSelect", this.$onSingleSelect); + session.multiSelect.lead.on("change", this.$checkMultiselectChange); + session.multiSelect.anchor.on("change", this.$checkMultiselectChange); + } + + if (session && this.inMultiSelectMode != session.selection.inMultiSelectMode) { + if (session.selection.inMultiSelectMode) + this.$onMultiSelect(); + else + this.$onSingleSelect(); + } +}; +function MultiSelect(editor) { + if (editor.$multiselectOnSessionChange) + return; + editor.$onAddRange = editor.$onAddRange.bind(editor); + editor.$onRemoveRange = editor.$onRemoveRange.bind(editor); + editor.$onMultiSelect = editor.$onMultiSelect.bind(editor); + editor.$onSingleSelect = editor.$onSingleSelect.bind(editor); + editor.$multiselectOnSessionChange = exports.onSessionChange.bind(editor); + editor.$checkMultiselectChange = editor.$checkMultiselectChange.bind(editor); + + editor.$multiselectOnSessionChange(editor); + editor.on("changeSession", editor.$multiselectOnSessionChange); + + editor.on("mousedown", onMouseDown); + editor.commands.addCommands(commands.defaultCommands); + + addAltCursorListeners(editor); +} + +function addAltCursorListeners(editor){ + if (!editor.textInput) return; + var el = editor.textInput.getElement(); + var altCursor = false; + event.addListener(el, "keydown", function(e) { + var altDown = e.keyCode == 18 && !(e.ctrlKey || e.shiftKey || e.metaKey); + if (editor.$blockSelectEnabled && altDown) { + if (!altCursor) { + editor.renderer.setMouseCursor("crosshair"); + altCursor = true; + } + } else if (altCursor) { + reset(); + } + }); + + event.addListener(el, "keyup", reset); + event.addListener(el, "blur", reset); + function reset(e) { + if (altCursor) { + editor.renderer.setMouseCursor(""); + altCursor = false; + } + } +} + +exports.MultiSelect = MultiSelect; + + +require("./config").defineOptions(Editor.prototype, "editor", { + enableMultiselect: { + set: function(val) { + MultiSelect(this); + if (val) { + this.on("changeSession", this.$multiselectOnSessionChange); + this.on("mousedown", onMouseDown); + } else { + this.off("changeSession", this.$multiselectOnSessionChange); + this.off("mousedown", onMouseDown); + } + }, + value: true + }, + enableBlockSelect: { + set: function(val) { + this.$blockSelectEnabled = val; + }, + value: true + } +}); + + + +}); + +define("ace/mode/folding/fold_mode",["require","exports","module","ace/range"], function(require, exports, module) { +"use strict"; + +var Range = require("../../range").Range; + +var FoldMode = exports.FoldMode = function() {}; + +(function() { + + this.foldingStartMarker = null; + this.foldingStopMarker = null; + this.getFoldWidget = function(session, foldStyle, row) { + var line = session.getLine(row); + if (this.foldingStartMarker.test(line)) + return "start"; + if (foldStyle == "markbeginend" + && this.foldingStopMarker + && this.foldingStopMarker.test(line)) + return "end"; + return ""; + }; + + this.getFoldWidgetRange = function(session, foldStyle, row) { + return null; + }; + + this.indentationBlock = function(session, row, column) { + var re = /\S/; + var line = session.getLine(row); + var startLevel = line.search(re); + if (startLevel == -1) + return; + + var startColumn = column || line.length; + var maxRow = session.getLength(); + var startRow = row; + var endRow = row; + + while (++row < maxRow) { + var level = session.getLine(row).search(re); + + if (level == -1) + continue; + + if (level <= startLevel) { + var token = session.getTokenAt(row, 0); + if (!token || token.type !== "string") + break; + } + + endRow = row; + } + + if (endRow > startRow) { + var endColumn = session.getLine(endRow).length; + return new Range(startRow, startColumn, endRow, endColumn); + } + }; + + this.openingBracketBlock = function(session, bracket, row, column, typeRe) { + var start = {row: row, column: column + 1}; + var end = session.$findClosingBracket(bracket, start, typeRe); + if (!end) + return; + + var fw = session.foldWidgets[end.row]; + if (fw == null) + fw = session.getFoldWidget(end.row); + + if (fw == "start" && end.row > start.row) { + end.row --; + end.column = session.getLine(end.row).length; + } + return Range.fromPoints(start, end); + }; + + this.closingBracketBlock = function(session, bracket, row, column, typeRe) { + var end = {row: row, column: column}; + var start = session.$findOpeningBracket(bracket, end); + + if (!start) + return; + + start.column++; + end.column--; + + return Range.fromPoints(start, end); + }; +}).call(FoldMode.prototype); + +}); + +define("ace/theme/textmate",["require","exports","module","ace/lib/dom"], function(require, exports, module) { +"use strict"; + +exports.isDark = false; +exports.cssClass = "ace-tm"; +exports.cssText = ".ace-tm .ace_gutter {\ +background: #f0f0f0;\ +color: #333;\ +}\ +.ace-tm .ace_print-margin {\ +width: 1px;\ +background: #e8e8e8;\ +}\ +.ace-tm .ace_fold {\ +background-color: #6B72E6;\ +}\ +.ace-tm {\ +background-color: #FFFFFF;\ +color: black;\ +}\ +.ace-tm .ace_cursor {\ +color: black;\ +}\ +.ace-tm .ace_invisible {\ +color: rgb(191, 191, 191);\ +}\ +.ace-tm .ace_storage,\ +.ace-tm .ace_keyword {\ +color: blue;\ +}\ +.ace-tm .ace_constant {\ +color: rgb(197, 6, 11);\ +}\ +.ace-tm .ace_constant.ace_buildin {\ +color: rgb(88, 72, 246);\ +}\ +.ace-tm .ace_constant.ace_language {\ +color: rgb(88, 92, 246);\ +}\ +.ace-tm .ace_constant.ace_library {\ +color: rgb(6, 150, 14);\ +}\ +.ace-tm .ace_invalid {\ +background-color: rgba(255, 0, 0, 0.1);\ +color: red;\ +}\ +.ace-tm .ace_support.ace_function {\ +color: rgb(60, 76, 114);\ +}\ +.ace-tm .ace_support.ace_constant {\ +color: rgb(6, 150, 14);\ +}\ +.ace-tm .ace_support.ace_type,\ +.ace-tm .ace_support.ace_class {\ +color: rgb(109, 121, 222);\ +}\ +.ace-tm .ace_keyword.ace_operator {\ +color: rgb(104, 118, 135);\ +}\ +.ace-tm .ace_string {\ +color: rgb(3, 106, 7);\ +}\ +.ace-tm .ace_comment {\ +color: rgb(76, 136, 107);\ +}\ +.ace-tm .ace_comment.ace_doc {\ +color: rgb(0, 102, 255);\ +}\ +.ace-tm .ace_comment.ace_doc.ace_tag {\ +color: rgb(128, 159, 191);\ +}\ +.ace-tm .ace_constant.ace_numeric {\ +color: rgb(0, 0, 205);\ +}\ +.ace-tm .ace_variable {\ +color: rgb(49, 132, 149);\ +}\ +.ace-tm .ace_xml-pe {\ +color: rgb(104, 104, 91);\ +}\ +.ace-tm .ace_entity.ace_name.ace_function {\ +color: #0000A2;\ +}\ +.ace-tm .ace_heading {\ +color: rgb(12, 7, 255);\ +}\ +.ace-tm .ace_list {\ +color:rgb(185, 6, 144);\ +}\ +.ace-tm .ace_meta.ace_tag {\ +color:rgb(0, 22, 142);\ +}\ +.ace-tm .ace_string.ace_regex {\ +color: rgb(255, 0, 0)\ +}\ +.ace-tm .ace_marker-layer .ace_selection {\ +background: rgb(181, 213, 255);\ +}\ +.ace-tm.ace_multiselect .ace_selection.ace_start {\ +box-shadow: 0 0 3px 0px white;\ +}\ +.ace-tm .ace_marker-layer .ace_step {\ +background: rgb(252, 255, 0);\ +}\ +.ace-tm .ace_marker-layer .ace_stack {\ +background: rgb(164, 229, 101);\ +}\ +.ace-tm .ace_marker-layer .ace_bracket {\ +margin: -1px 0 0 -1px;\ +border: 1px solid rgb(192, 192, 192);\ +}\ +.ace-tm .ace_marker-layer .ace_active-line {\ +background: rgba(0, 0, 0, 0.07);\ +}\ +.ace-tm .ace_gutter-active-line {\ +background-color : #dcdcdc;\ +}\ +.ace-tm .ace_marker-layer .ace_selected-word {\ +background: rgb(250, 250, 255);\ +border: 1px solid rgb(200, 200, 250);\ +}\ +.ace-tm .ace_indent-guide {\ +background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==\") right repeat-y;\ +}\ +"; +exports.$id = "ace/theme/textmate"; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); + +define("ace/line_widgets",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/range"], function(require, exports, module) { +"use strict"; + +var oop = require("./lib/oop"); +var dom = require("./lib/dom"); +var Range = require("./range").Range; + + +function LineWidgets(session) { + this.session = session; + this.session.widgetManager = this; + this.session.getRowLength = this.getRowLength; + this.session.$getWidgetScreenLength = this.$getWidgetScreenLength; + this.updateOnChange = this.updateOnChange.bind(this); + this.renderWidgets = this.renderWidgets.bind(this); + this.measureWidgets = this.measureWidgets.bind(this); + this.session._changedWidgets = []; + this.$onChangeEditor = this.$onChangeEditor.bind(this); + + this.session.on("change", this.updateOnChange); + this.session.on("changeFold", this.updateOnFold); + this.session.on("changeEditor", this.$onChangeEditor); +} + +(function() { + this.getRowLength = function(row) { + var h; + if (this.lineWidgets) + h = this.lineWidgets[row] && this.lineWidgets[row].rowCount || 0; + else + h = 0; + if (!this.$useWrapMode || !this.$wrapData[row]) { + return 1 + h; + } else { + return this.$wrapData[row].length + 1 + h; + } + }; + + this.$getWidgetScreenLength = function() { + var screenRows = 0; + this.lineWidgets.forEach(function(w){ + if (w && w.rowCount && !w.hidden) + screenRows += w.rowCount; + }); + return screenRows; + }; + + this.$onChangeEditor = function(e) { + this.attach(e.editor); + }; + + this.attach = function(editor) { + if (editor && editor.widgetManager && editor.widgetManager != this) + editor.widgetManager.detach(); + + if (this.editor == editor) + return; + + this.detach(); + this.editor = editor; + + if (editor) { + editor.widgetManager = this; + editor.renderer.on("beforeRender", this.measureWidgets); + editor.renderer.on("afterRender", this.renderWidgets); + } + }; + this.detach = function(e) { + var editor = this.editor; + if (!editor) + return; + + this.editor = null; + editor.widgetManager = null; + + editor.renderer.off("beforeRender", this.measureWidgets); + editor.renderer.off("afterRender", this.renderWidgets); + var lineWidgets = this.session.lineWidgets; + lineWidgets && lineWidgets.forEach(function(w) { + if (w && w.el && w.el.parentNode) { + w._inDocument = false; + w.el.parentNode.removeChild(w.el); + } + }); + }; + + this.updateOnFold = function(e, session) { + var lineWidgets = session.lineWidgets; + if (!lineWidgets || !e.action) + return; + var fold = e.data; + var start = fold.start.row; + var end = fold.end.row; + var hide = e.action == "add"; + for (var i = start + 1; i < end; i++) { + if (lineWidgets[i]) + lineWidgets[i].hidden = hide; + } + if (lineWidgets[end]) { + if (hide) { + if (!lineWidgets[start]) + lineWidgets[start] = lineWidgets[end]; + else + lineWidgets[end].hidden = hide; + } else { + if (lineWidgets[start] == lineWidgets[end]) + lineWidgets[start] = undefined; + lineWidgets[end].hidden = hide; + } + } + }; + + this.updateOnChange = function(delta) { + var lineWidgets = this.session.lineWidgets; + if (!lineWidgets) return; + + var startRow = delta.start.row; + var len = delta.end.row - startRow; + + if (len === 0) { + } else if (delta.action == 'remove') { + var removed = lineWidgets.splice(startRow + 1, len); + removed.forEach(function(w) { + w && this.removeLineWidget(w); + }, this); + this.$updateRows(); + } else { + var args = new Array(len); + args.unshift(startRow, 0); + lineWidgets.splice.apply(lineWidgets, args); + this.$updateRows(); + } + }; + + this.$updateRows = function() { + var lineWidgets = this.session.lineWidgets; + if (!lineWidgets) return; + var noWidgets = true; + lineWidgets.forEach(function(w, i) { + if (w) { + noWidgets = false; + w.row = i; + while (w.$oldWidget) { + w.$oldWidget.row = i; + w = w.$oldWidget; + } + } + }); + if (noWidgets) + this.session.lineWidgets = null; + }; + + this.addLineWidget = function(w) { + if (!this.session.lineWidgets) + this.session.lineWidgets = new Array(this.session.getLength()); + + var old = this.session.lineWidgets[w.row]; + if (old) { + w.$oldWidget = old; + if (old.el && old.el.parentNode) { + old.el.parentNode.removeChild(old.el); + old._inDocument = false; + } + } + + this.session.lineWidgets[w.row] = w; + + w.session = this.session; + + var renderer = this.editor.renderer; + if (w.html && !w.el) { + w.el = dom.createElement("div"); + w.el.innerHTML = w.html; + } + if (w.el) { + dom.addCssClass(w.el, "ace_lineWidgetContainer"); + w.el.style.position = "absolute"; + w.el.style.zIndex = 5; + renderer.container.appendChild(w.el); + w._inDocument = true; + } + + if (!w.coverGutter) { + w.el.style.zIndex = 3; + } + if (w.pixelHeight == null) { + w.pixelHeight = w.el.offsetHeight; + } + if (w.rowCount == null) { + w.rowCount = w.pixelHeight / renderer.layerConfig.lineHeight; + } + + var fold = this.session.getFoldAt(w.row, 0); + w.$fold = fold; + if (fold) { + var lineWidgets = this.session.lineWidgets; + if (w.row == fold.end.row && !lineWidgets[fold.start.row]) + lineWidgets[fold.start.row] = w; + else + w.hidden = true; + } + + this.session._emit("changeFold", {data:{start:{row: w.row}}}); + + this.$updateRows(); + this.renderWidgets(null, renderer); + this.onWidgetChanged(w); + return w; + }; + + this.removeLineWidget = function(w) { + w._inDocument = false; + w.session = null; + if (w.el && w.el.parentNode) + w.el.parentNode.removeChild(w.el); + if (w.editor && w.editor.destroy) try { + w.editor.destroy(); + } catch(e){} + if (this.session.lineWidgets) { + var w1 = this.session.lineWidgets[w.row]; + if (w1 == w) { + this.session.lineWidgets[w.row] = w.$oldWidget; + if (w.$oldWidget) + this.onWidgetChanged(w.$oldWidget); + } else { + while (w1) { + if (w1.$oldWidget == w) { + w1.$oldWidget = w.$oldWidget; + break; + } + w1 = w1.$oldWidget; + } + } + } + this.session._emit("changeFold", {data:{start:{row: w.row}}}); + this.$updateRows(); + }; + + this.getWidgetsAtRow = function(row) { + var lineWidgets = this.session.lineWidgets; + var w = lineWidgets && lineWidgets[row]; + var list = []; + while (w) { + list.push(w); + w = w.$oldWidget; + } + return list; + }; + + this.onWidgetChanged = function(w) { + this.session._changedWidgets.push(w); + this.editor && this.editor.renderer.updateFull(); + }; + + this.measureWidgets = function(e, renderer) { + var changedWidgets = this.session._changedWidgets; + var config = renderer.layerConfig; + + if (!changedWidgets || !changedWidgets.length) return; + var min = Infinity; + for (var i = 0; i < changedWidgets.length; i++) { + var w = changedWidgets[i]; + if (!w || !w.el) continue; + if (w.session != this.session) continue; + if (!w._inDocument) { + if (this.session.lineWidgets[w.row] != w) + continue; + w._inDocument = true; + renderer.container.appendChild(w.el); + } + + w.h = w.el.offsetHeight; + + if (!w.fixedWidth) { + w.w = w.el.offsetWidth; + w.screenWidth = Math.ceil(w.w / config.characterWidth); + } + + var rowCount = w.h / config.lineHeight; + if (w.coverLine) { + rowCount -= this.session.getRowLineCount(w.row); + if (rowCount < 0) + rowCount = 0; + } + if (w.rowCount != rowCount) { + w.rowCount = rowCount; + if (w.row < min) + min = w.row; + } + } + if (min != Infinity) { + this.session._emit("changeFold", {data:{start:{row: min}}}); + this.session.lineWidgetWidth = null; + } + this.session._changedWidgets = []; + }; + + this.renderWidgets = function(e, renderer) { + var config = renderer.layerConfig; + var lineWidgets = this.session.lineWidgets; + if (!lineWidgets) + return; + var first = Math.min(this.firstRow, config.firstRow); + var last = Math.max(this.lastRow, config.lastRow, lineWidgets.length); + + while (first > 0 && !lineWidgets[first]) + first--; + + this.firstRow = config.firstRow; + this.lastRow = config.lastRow; + + renderer.$cursorLayer.config = config; + for (var i = first; i <= last; i++) { + var w = lineWidgets[i]; + if (!w || !w.el) continue; + if (w.hidden) { + w.el.style.top = -100 - (w.pixelHeight || 0) + "px"; + continue; + } + if (!w._inDocument) { + w._inDocument = true; + renderer.container.appendChild(w.el); + } + var top = renderer.$cursorLayer.getPixelPosition({row: i, column:0}, true).top; + if (!w.coverLine) + top += config.lineHeight * this.session.getRowLineCount(w.row); + w.el.style.top = top - config.offset + "px"; + + var left = w.coverGutter ? 0 : renderer.gutterWidth; + if (!w.fixedWidth) + left -= renderer.scrollLeft; + w.el.style.left = left + "px"; + + if (w.fullWidth && w.screenWidth) { + w.el.style.minWidth = config.width + 2 * config.padding + "px"; + } + + if (w.fixedWidth) { + w.el.style.right = renderer.scrollBar.getWidth() + "px"; + } else { + w.el.style.right = ""; + } + } + }; + +}).call(LineWidgets.prototype); + + +exports.LineWidgets = LineWidgets; + +}); + +define("ace/ext/error_marker",["require","exports","module","ace/line_widgets","ace/lib/dom","ace/range"], function(require, exports, module) { +"use strict"; +var LineWidgets = require("../line_widgets").LineWidgets; +var dom = require("../lib/dom"); +var Range = require("../range").Range; + +function binarySearch(array, needle, comparator) { + var first = 0; + var last = array.length - 1; + + while (first <= last) { + var mid = (first + last) >> 1; + var c = comparator(needle, array[mid]); + if (c > 0) + first = mid + 1; + else if (c < 0) + last = mid - 1; + else + return mid; + } + return -(first + 1); +} + +function findAnnotations(session, row, dir) { + var annotations = session.getAnnotations().sort(Range.comparePoints); + if (!annotations.length) + return; + + var i = binarySearch(annotations, {row: row, column: -1}, Range.comparePoints); + if (i < 0) + i = -i - 1; + + if (i >= annotations.length) + i = dir > 0 ? 0 : annotations.length - 1; + else if (i === 0 && dir < 0) + i = annotations.length - 1; + + var annotation = annotations[i]; + if (!annotation || !dir) + return; + + if (annotation.row === row) { + do { + annotation = annotations[i += dir]; + } while (annotation && annotation.row === row); + if (!annotation) + return annotations.slice(); + } + + + var matched = []; + row = annotation.row; + do { + matched[dir < 0 ? "unshift" : "push"](annotation); + annotation = annotations[i += dir]; + } while (annotation && annotation.row == row); + return matched.length && matched; +} + +exports.showErrorMarker = function(editor, dir) { + var session = editor.session; + if (!session.widgetManager) { + session.widgetManager = new LineWidgets(session); + session.widgetManager.attach(editor); + } + + var pos = editor.getCursorPosition(); + var row = pos.row; + var oldWidget = session.widgetManager.getWidgetsAtRow(row).filter(function(w) { + return w.type == "errorMarker"; + })[0]; + if (oldWidget) { + oldWidget.destroy(); + } else { + row -= dir; + } + var annotations = findAnnotations(session, row, dir); + var gutterAnno; + if (annotations) { + var annotation = annotations[0]; + pos.column = (annotation.pos && typeof annotation.column != "number" + ? annotation.pos.sc + : annotation.column) || 0; + pos.row = annotation.row; + gutterAnno = editor.renderer.$gutterLayer.$annotations[pos.row]; + } else if (oldWidget) { + return; + } else { + gutterAnno = { + text: ["Looks good!"], + className: "ace_ok" + }; + } + editor.session.unfold(pos.row); + editor.selection.moveToPosition(pos); + + var w = { + row: pos.row, + fixedWidth: true, + coverGutter: true, + el: dom.createElement("div"), + type: "errorMarker" + }; + var el = w.el.appendChild(dom.createElement("div")); + var arrow = w.el.appendChild(dom.createElement("div")); + arrow.className = "error_widget_arrow " + gutterAnno.className; + + var left = editor.renderer.$cursorLayer + .getPixelPosition(pos).left; + arrow.style.left = left + editor.renderer.gutterWidth - 5 + "px"; + + w.el.className = "error_widget_wrapper"; + el.className = "error_widget " + gutterAnno.className; + el.innerHTML = gutterAnno.text.join("
"); + + el.appendChild(dom.createElement("div")); + + var kb = function(_, hashId, keyString) { + if (hashId === 0 && (keyString === "esc" || keyString === "return")) { + w.destroy(); + return {command: "null"}; + } + }; + + w.destroy = function() { + if (editor.$mouseHandler.isMousePressed) + return; + editor.keyBinding.removeKeyboardHandler(kb); + session.widgetManager.removeLineWidget(w); + editor.off("changeSelection", w.destroy); + editor.off("changeSession", w.destroy); + editor.off("mouseup", w.destroy); + editor.off("change", w.destroy); + }; + + editor.keyBinding.addKeyboardHandler(kb); + editor.on("changeSelection", w.destroy); + editor.on("changeSession", w.destroy); + editor.on("mouseup", w.destroy); + editor.on("change", w.destroy); + + editor.session.widgetManager.addLineWidget(w); + + w.el.onmousedown = editor.focus.bind(editor); + + editor.renderer.scrollCursorIntoView(null, 0.5, {bottom: w.el.offsetHeight}); +}; + + +dom.importCssString("\ + .error_widget_wrapper {\ + background: inherit;\ + color: inherit;\ + border:none\ + }\ + .error_widget {\ + border-top: solid 2px;\ + border-bottom: solid 2px;\ + margin: 5px 0;\ + padding: 10px 40px;\ + white-space: pre-wrap;\ + }\ + .error_widget.ace_error, .error_widget_arrow.ace_error{\ + border-color: #ff5a5a\ + }\ + .error_widget.ace_warning, .error_widget_arrow.ace_warning{\ + border-color: #F1D817\ + }\ + .error_widget.ace_info, .error_widget_arrow.ace_info{\ + border-color: #5a5a5a\ + }\ + .error_widget.ace_ok, .error_widget_arrow.ace_ok{\ + border-color: #5aaa5a\ + }\ + .error_widget_arrow {\ + position: absolute;\ + border: solid 5px;\ + border-top-color: transparent!important;\ + border-right-color: transparent!important;\ + border-left-color: transparent!important;\ + top: -5px;\ + }\ +", ""); + +}); + +define("ace/ace",["require","exports","module","ace/lib/fixoldbrowsers","ace/lib/dom","ace/lib/event","ace/range","ace/editor","ace/edit_session","ace/undomanager","ace/virtual_renderer","ace/worker/worker_client","ace/keyboard/hash_handler","ace/placeholder","ace/multi_select","ace/mode/folding/fold_mode","ace/theme/textmate","ace/ext/error_marker","ace/config"], function(require, exports, module) { +"use strict"; + +require("./lib/fixoldbrowsers"); + +var dom = require("./lib/dom"); +var event = require("./lib/event"); + +var Range = require("./range").Range; +var Editor = require("./editor").Editor; +var EditSession = require("./edit_session").EditSession; +var UndoManager = require("./undomanager").UndoManager; +var Renderer = require("./virtual_renderer").VirtualRenderer; +require("./worker/worker_client"); +require("./keyboard/hash_handler"); +require("./placeholder"); +require("./multi_select"); +require("./mode/folding/fold_mode"); +require("./theme/textmate"); +require("./ext/error_marker"); + +exports.config = require("./config"); +exports.require = require; + +if (typeof define === "function") + exports.define = define; +exports.edit = function(el, options) { + if (typeof el == "string") { + var _id = el; + el = document.getElementById(_id); + if (!el) + throw new Error("ace.edit can't find div #" + _id); + } + + if (el && el.env && el.env.editor instanceof Editor) + return el.env.editor; + + var value = ""; + if (el && /input|textarea/i.test(el.tagName)) { + var oldNode = el; + value = oldNode.value; + el = dom.createElement("pre"); + oldNode.parentNode.replaceChild(el, oldNode); + } else if (el) { + value = el.textContent; + el.innerHTML = ""; + } + + var doc = exports.createEditSession(value); + + var editor = new Editor(new Renderer(el), doc, options); + + var env = { + document: doc, + editor: editor, + onResize: editor.resize.bind(editor, null) + }; + if (oldNode) env.textarea = oldNode; + event.addListener(window, "resize", env.onResize); + editor.on("destroy", function() { + event.removeListener(window, "resize", env.onResize); + env.editor.container.env = null; // prevent memory leak on old ie + }); + editor.container.env = editor.env = env; + return editor; +}; +exports.createEditSession = function(text, mode) { + var doc = new EditSession(text, mode); + doc.setUndoManager(new UndoManager()); + return doc; +}; +exports.Range = Range; +exports.Editor = Editor; +exports.EditSession = EditSession; +exports.UndoManager = UndoManager; +exports.VirtualRenderer = Renderer; +exports.version = exports.config.version; +}); (function() { + window.require(["ace/ace"], function(a) { + if (a) { + a.config.init(true); + a.define = window.define; + } + if (!window.ace) + window.ace = a; + for (var key in a) if (a.hasOwnProperty(key)) + window.ace[key] = a[key]; + window.ace["default"] = window.ace; + if (typeof module == "object" && typeof exports == "object" && module) { + module.exports = window.ace; + } + }); + })(); + \ No newline at end of file diff --git a/ace/ext-searchbox.js b/ace/ext-searchbox.js new file mode 100644 index 0000000..35eed19 --- /dev/null +++ b/ace/ext-searchbox.js @@ -0,0 +1,8 @@ +define("ace/ext/searchbox",["require","exports","module","ace/lib/dom","ace/lib/lang","ace/lib/event","ace/keyboard/hash_handler","ace/lib/keys"],function(e,t,n){"use strict";var r=e("../lib/dom"),i=e("../lib/lang"),s=e("../lib/event"),o='.ace_search {background-color: #ddd;color: #666;border: 1px solid #cbcbcb;border-top: 0 none;overflow: hidden;margin: 0;padding: 4px 6px 0 4px;position: absolute;top: 0;z-index: 99;white-space: normal;}.ace_search.left {border-left: 0 none;border-radius: 0px 0px 5px 0px;left: 0;}.ace_search.right {border-radius: 0px 0px 0px 5px;border-right: 0 none;right: 0;}.ace_search_form, .ace_replace_form {margin: 0 20px 4px 0;overflow: hidden;line-height: 1.9;}.ace_replace_form {margin-right: 0;}.ace_search_form.ace_nomatch {outline: 1px solid red;}.ace_search_field {border-radius: 3px 0 0 3px;background-color: white;color: black;border: 1px solid #cbcbcb;border-right: 0 none;outline: 0;padding: 0;font-size: inherit;margin: 0;line-height: inherit;padding: 0 6px;min-width: 17em;vertical-align: top;min-height: 1.8em;box-sizing: content-box;}.ace_searchbtn {border: 1px solid #cbcbcb;line-height: inherit;display: inline-block;padding: 0 6px;background: #fff;border-right: 0 none;border-left: 1px solid #dcdcdc;cursor: pointer;margin: 0;position: relative;color: #666;}.ace_searchbtn:last-child {border-radius: 0 3px 3px 0;border-right: 1px solid #cbcbcb;}.ace_searchbtn:disabled {background: none;cursor: default;}.ace_searchbtn:hover {background-color: #eef1f6;}.ace_searchbtn.prev, .ace_searchbtn.next {padding: 0px 0.7em}.ace_searchbtn.prev:after, .ace_searchbtn.next:after {content: "";border: solid 2px #888;width: 0.5em;height: 0.5em;border-width: 2px 0 0 2px;display:inline-block;transform: rotate(-45deg);}.ace_searchbtn.next:after {border-width: 0 2px 2px 0 ;}.ace_searchbtn_close {background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAcCAYAAABRVo5BAAAAZ0lEQVR42u2SUQrAMAhDvazn8OjZBilCkYVVxiis8H4CT0VrAJb4WHT3C5xU2a2IQZXJjiQIRMdkEoJ5Q2yMqpfDIo+XY4k6h+YXOyKqTIj5REaxloNAd0xiKmAtsTHqW8sR2W5f7gCu5nWFUpVjZwAAAABJRU5ErkJggg==) no-repeat 50% 0;border-radius: 50%;border: 0 none;color: #656565;cursor: pointer;font: 16px/16px Arial;padding: 0;height: 14px;width: 14px;top: 9px;right: 7px;position: absolute;}.ace_searchbtn_close:hover {background-color: #656565;background-position: 50% 100%;color: white;}.ace_button {margin-left: 2px;cursor: pointer;-webkit-user-select: none;-moz-user-select: none;-o-user-select: none;-ms-user-select: none;user-select: none;overflow: hidden;opacity: 0.7;border: 1px solid rgba(100,100,100,0.23);padding: 1px;box-sizing: border-box!important;color: black;}.ace_button:hover {background-color: #eee;opacity:1;}.ace_button:active {background-color: #ddd;}.ace_button.checked {border-color: #3399ff;opacity:1;}.ace_search_options{margin-bottom: 3px;text-align: right;-webkit-user-select: none;-moz-user-select: none;-o-user-select: none;-ms-user-select: none;user-select: none;clear: both;}.ace_search_counter {float: left;font-family: arial;padding: 0 8px;}',u=e("../keyboard/hash_handler").HashHandler,a=e("../lib/keys"),f=999;r.importCssString(o,"ace_searchbox",!1);var l=function(e,t,n){var i=r.createElement("div");r.buildDom(["div",{"class":"ace_search right"},["span",{action:"hide","class":"ace_searchbtn_close"}],["div",{"class":"ace_search_form"},["input",{"class":"ace_search_field",placeholder:"Search for",spellcheck:"false"}],["span",{action:"findPrev","class":"ace_searchbtn prev"},"\u200b"],["span",{action:"findNext","class":"ace_searchbtn next"},"\u200b"],["span",{action:"findAll","class":"ace_searchbtn",title:"Alt-Enter"},"All"]],["div",{"class":"ace_replace_form"},["input",{"class":"ace_search_field",placeholder:"Replace with",spellcheck:"false"}],["span",{action:"replaceAndFindNext","class":"ace_searchbtn"},"Replace"],["span",{action:"replaceAll","class":"ace_searchbtn"},"All"]],["div",{"class":"ace_search_options"},["span",{action:"toggleReplace","class":"ace_button",title:"Toggle Replace mode",style:"float:left;margin-top:-2px;padding:0 5px;"},"+"],["span",{"class":"ace_search_counter"}],["span",{action:"toggleRegexpMode","class":"ace_button",title:"RegExp Search"},".*"],["span",{action:"toggleCaseSensitive","class":"ace_button",title:"CaseSensitive Search"},"Aa"],["span",{action:"toggleWholeWords","class":"ace_button",title:"Whole Word Search"},"\\b"],["span",{action:"searchInSelection","class":"ace_button",title:"Search In Selection"},"S"]]],i),this.element=i.firstChild,this.setSession=this.setSession.bind(this),this.$init(),this.setEditor(e),r.importCssString(o,"ace_searchbox",e.container)};(function(){this.setEditor=function(e){e.searchBox=this,e.renderer.scroller.appendChild(this.element),this.editor=e},this.setSession=function(e){this.searchRange=null,this.$syncOptions(!0)},this.$initElements=function(e){this.searchBox=e.querySelector(".ace_search_form"),this.replaceBox=e.querySelector(".ace_replace_form"),this.searchOption=e.querySelector("[action=searchInSelection]"),this.replaceOption=e.querySelector("[action=toggleReplace]"),this.regExpOption=e.querySelector("[action=toggleRegexpMode]"),this.caseSensitiveOption=e.querySelector("[action=toggleCaseSensitive]"),this.wholeWordOption=e.querySelector("[action=toggleWholeWords]"),this.searchInput=this.searchBox.querySelector(".ace_search_field"),this.replaceInput=this.replaceBox.querySelector(".ace_search_field"),this.searchCounter=e.querySelector(".ace_search_counter")},this.$init=function(){var e=this.element;this.$initElements(e);var t=this;s.addListener(e,"mousedown",function(e){setTimeout(function(){t.activeInput.focus()},0),s.stopPropagation(e)}),s.addListener(e,"click",function(e){var n=e.target||e.srcElement,r=n.getAttribute("action");r&&t[r]?t[r]():t.$searchBarKb.commands[r]&&t.$searchBarKb.commands[r].exec(t),s.stopPropagation(e)}),s.addCommandKeyListener(e,function(e,n,r){var i=a.keyCodeToString(r),o=t.$searchBarKb.findKeyCommand(n,i);o&&o.exec&&(o.exec(t),s.stopEvent(e))}),this.$onChange=i.delayedCall(function(){t.find(!1,!1)}),s.addListener(this.searchInput,"input",function(){t.$onChange.schedule(20)}),s.addListener(this.searchInput,"focus",function(){t.activeInput=t.searchInput,t.searchInput.value&&t.highlight()}),s.addListener(this.replaceInput,"focus",function(){t.activeInput=t.replaceInput,t.searchInput.value&&t.highlight()})},this.$closeSearchBarKb=new u([{bindKey:"Esc",name:"closeSearchBar",exec:function(e){e.searchBox.hide()}}]),this.$searchBarKb=new u,this.$searchBarKb.bindKeys({"Ctrl-f|Command-f":function(e){var t=e.isReplace=!e.isReplace;e.replaceBox.style.display=t?"":"none",e.replaceOption.checked=!1,e.$syncOptions(),e.searchInput.focus()},"Ctrl-H|Command-Option-F":function(e){if(e.editor.getReadOnly())return;e.replaceOption.checked=!0,e.$syncOptions(),e.replaceInput.focus()},"Ctrl-G|Command-G":function(e){e.findNext()},"Ctrl-Shift-G|Command-Shift-G":function(e){e.findPrev()},esc:function(e){setTimeout(function(){e.hide()})},Return:function(e){e.activeInput==e.replaceInput&&e.replace(),e.findNext()},"Shift-Return":function(e){e.activeInput==e.replaceInput&&e.replace(),e.findPrev()},"Alt-Return":function(e){e.activeInput==e.replaceInput&&e.replaceAll(),e.findAll()},Tab:function(e){(e.activeInput==e.replaceInput?e.searchInput:e.replaceInput).focus()}}),this.$searchBarKb.addCommands([{name:"toggleRegexpMode",bindKey:{win:"Alt-R|Alt-/",mac:"Ctrl-Alt-R|Ctrl-Alt-/"},exec:function(e){e.regExpOption.checked=!e.regExpOption.checked,e.$syncOptions()}},{name:"toggleCaseSensitive",bindKey:{win:"Alt-C|Alt-I",mac:"Ctrl-Alt-R|Ctrl-Alt-I"},exec:function(e){e.caseSensitiveOption.checked=!e.caseSensitiveOption.checked,e.$syncOptions()}},{name:"toggleWholeWords",bindKey:{win:"Alt-B|Alt-W",mac:"Ctrl-Alt-B|Ctrl-Alt-W"},exec:function(e){e.wholeWordOption.checked=!e.wholeWordOption.checked,e.$syncOptions()}},{name:"toggleReplace",exec:function(e){e.replaceOption.checked=!e.replaceOption.checked,e.$syncOptions()}},{name:"searchInSelection",exec:function(e){e.searchOption.checked=!e.searchRange,e.setSearchRange(e.searchOption.checked&&e.editor.getSelectionRange()),e.$syncOptions()}}]),this.setSearchRange=function(e){this.searchRange=e,e?this.searchRangeMarker=this.editor.session.addMarker(e,"ace_active-line"):this.searchRangeMarker&&(this.editor.session.removeMarker(this.searchRangeMarker),this.searchRangeMarker=null)},this.$syncOptions=function(e){r.setCssClass(this.replaceOption,"checked",this.searchRange),r.setCssClass(this.searchOption,"checked",this.searchOption.checked),this.replaceOption.textContent=this.replaceOption.checked?"-":"+",r.setCssClass(this.regExpOption,"checked",this.regExpOption.checked),r.setCssClass(this.wholeWordOption,"checked",this.wholeWordOption.checked),r.setCssClass(this.caseSensitiveOption,"checked",this.caseSensitiveOption.checked);var t=this.editor.getReadOnly();this.replaceOption.style.display=t?"none":"",this.replaceBox.style.display=this.replaceOption.checked&&!t?"":"none",this.find(!1,!1,e)},this.highlight=function(e){this.editor.session.highlight(e||this.editor.$search.$options.re),this.editor.renderer.updateBackMarkers()},this.find=function(e,t,n){var i=this.editor.find(this.searchInput.value,{skipCurrent:e,backwards:t,wrap:!0,regExp:this.regExpOption.checked,caseSensitive:this.caseSensitiveOption.checked,wholeWord:this.wholeWordOption.checked,preventScroll:n,range:this.searchRange}),s=!i&&this.searchInput.value;r.setCssClass(this.searchBox,"ace_nomatch",s),this.editor._emit("findSearchBox",{match:!s}),this.highlight(),this.updateCounter()},this.updateCounter=function(){var e=this.editor,t=e.$search.$options.re,n=0,r=0;if(t){var i=this.searchRange?e.session.getTextRange(this.searchRange):e.getValue(),s=e.session.doc.positionToIndex(e.selection.anchor);this.searchRange&&(s-=e.session.doc.positionToIndex(this.searchRange.start));var o=t.lastIndex=0,u;while(u=t.exec(i)){n++,o=u.index,o<=s&&r++;if(n>f)break;if(!u[0]){t.lastIndex=o+=1;if(o>=i.length)break}}}this.searchCounter.textContent=r+" of "+(n>f?f+"+":n)},this.findNext=function(){this.find(!0,!1)},this.findPrev=function(){this.find(!0,!0)},this.findAll=function(){var e=this.editor.findAll(this.searchInput.value,{regExp:this.regExpOption.checked,caseSensitive:this.caseSensitiveOption.checked,wholeWord:this.wholeWordOption.checked}),t=!e&&this.searchInput.value;r.setCssClass(this.searchBox,"ace_nomatch",t),this.editor._emit("findSearchBox",{match:!t}),this.highlight(),this.hide()},this.replace=function(){this.editor.getReadOnly()||this.editor.replace(this.replaceInput.value)},this.replaceAndFindNext=function(){this.editor.getReadOnly()||(this.editor.replace(this.replaceInput.value),this.findNext())},this.replaceAll=function(){this.editor.getReadOnly()||this.editor.replaceAll(this.replaceInput.value)},this.hide=function(){this.active=!1,this.setSearchRange(null),this.editor.off("changeSession",this.setSession),this.element.style.display="none",this.editor.keyBinding.removeKeyboardHandler(this.$closeSearchBarKb),this.editor.focus()},this.show=function(e,t){this.active=!0,this.editor.on("changeSession",this.setSession),this.element.style.display="",this.replaceOption.checked=t,e&&(this.searchInput.value=e),this.searchInput.focus(),this.searchInput.select(),this.editor.keyBinding.addKeyboardHandler(this.$closeSearchBarKb),this.$syncOptions(!0)},this.isFocused=function(){var e=document.activeElement;return e==this.searchInput||e==this.replaceInput}}).call(l.prototype),t.SearchBox=l,t.Search=function(e,t){var n=e.searchBox||new l(e);n.show(e.session.getTextRange(),t)}}); (function() { + window.require(["ace/ext/searchbox"], function(m) { + if (typeof module == "object" && typeof exports == "object" && module) { + module.exports = m; + } + }); + })(); + \ No newline at end of file diff --git a/ace/keybinding-vim.js b/ace/keybinding-vim.js new file mode 100644 index 0000000..327b5c1 --- /dev/null +++ b/ace/keybinding-vim.js @@ -0,0 +1,5895 @@ +define("ace/keyboard/vim",["require","exports","module","ace/range","ace/lib/event_emitter","ace/lib/dom","ace/lib/oop","ace/lib/keys","ace/lib/event","ace/search","ace/lib/useragent","ace/search_highlight","ace/commands/multi_select_commands","ace/mode/text","ace/multi_select"], function(require, exports, module) { + 'use strict'; + + function log() { + var d = ""; + function format(p) { + if (typeof p != "object") + return p + ""; + if ("line" in p) { + return p.line + ":" + p.ch; + } + if ("anchor" in p) { + return format(p.anchor) + "->" + format(p.head); + } + if (Array.isArray(p)) + return "[" + p.map(function(x) { + return format(x); + }) + "]"; + return JSON.stringify(p); + } + for (var i = 0; i < arguments.length; i++) { + var p = arguments[i]; + var f = format(p); + d += f + " "; + } + console.log(d); + } + var Range = require("../range").Range; + var EventEmitter = require("../lib/event_emitter").EventEmitter; + var dom = require("../lib/dom"); + var oop = require("../lib/oop"); + var KEYS = require("../lib/keys"); + var event = require("../lib/event"); + var Search = require("../search").Search; + var useragent = require("../lib/useragent"); + var SearchHighlight = require("../search_highlight").SearchHighlight; + var multiSelectCommands = require("../commands/multi_select_commands"); + var TextModeTokenRe = require("../mode/text").Mode.prototype.tokenRe; + require("../multi_select"); + + var CodeMirror = function(ace) { + this.ace = ace; + this.state = {}; + this.marks = {}; + this.$uid = 0; + this.onChange = this.onChange.bind(this); + this.onSelectionChange = this.onSelectionChange.bind(this); + this.onBeforeEndOperation = this.onBeforeEndOperation.bind(this); + this.ace.on('change', this.onChange); + this.ace.on('changeSelection', this.onSelectionChange); + this.ace.on('beforeEndOperation', this.onBeforeEndOperation); + }; + CodeMirror.Pos = function(line, ch) { + if (!(this instanceof Pos)) return new Pos(line, ch); + this.line = line; this.ch = ch; + }; + CodeMirror.defineOption = function(name, val, setter) {}; + CodeMirror.commands = { + redo: function(cm) { cm.ace.redo(); }, + undo: function(cm) { cm.ace.undo(); }, + newlineAndIndent: function(cm) { cm.ace.insert("\n"); } + }; + CodeMirror.keyMap = {}; + CodeMirror.addClass = CodeMirror.rmClass = function() {}; + CodeMirror.e_stop = CodeMirror.e_preventDefault = event.stopEvent; + CodeMirror.keyName = function(e) { + var key = (KEYS[e.keyCode] || e.key || ""); + if (key.length == 1) key = key.toUpperCase(); + key = event.getModifierString(e).replace(/(^|-)\w/g, function(m) { + return m.toUpperCase(); + }) + key; + return key; + }; + CodeMirror.keyMap['default'] = function(key) { + return function(cm) { + var cmd = cm.ace.commands.commandKeyBinding[key.toLowerCase()]; + return cmd && cm.ace.execCommand(cmd) !== false; + }; + }; + CodeMirror.lookupKey = function lookupKey(key, map, handle) { + if (!map) map = "default"; + if (typeof map == "string") + map = CodeMirror.keyMap[map]; + var found = typeof map == "function" ? map(key) : map[key]; + if (found === false) return "nothing"; + if (found === "...") return "multi"; + if (found != null && handle(found)) return "handled"; + + if (map.fallthrough) { + if (!Array.isArray(map.fallthrough)) + return lookupKey(key, map.fallthrough, handle); + for (var i = 0; i < map.fallthrough.length; i++) { + var result = lookupKey(key, map.fallthrough[i], handle); + if (result) return result; + } + } + }; + + CodeMirror.signal = function(o, name, e) { return o._signal(name, e) }; + CodeMirror.on = event.addListener; + CodeMirror.off = event.removeListener; + CodeMirror.isWordChar = function(ch) { + if (ch < "\x7f") return /^\w$/.test(ch); + TextModeTokenRe.lastIndex = 0; + return TextModeTokenRe.test(ch); + }; + +(function() { + oop.implement(CodeMirror.prototype, EventEmitter); + + this.destroy = function() { + this.ace.off('change', this.onChange); + this.ace.off('changeSelection', this.onSelectionChange); + this.ace.off('beforeEndOperation', this.onBeforeEndOperation); + this.removeOverlay(); + }; + this.virtualSelectionMode = function() { + return this.ace.inVirtualSelectionMode && this.ace.selection.index; + }; + this.onChange = function(delta) { + var change = { text: delta.action[0] == 'i' ? delta.lines : [] }; + var curOp = this.curOp = this.curOp || {}; + if (!curOp.changeHandlers) + curOp.changeHandlers = this._eventRegistry["change"] && this._eventRegistry["change"].slice(); + if (!curOp.lastChange) { + curOp.lastChange = curOp.change = change; + } else { + curOp.lastChange.next = curOp.lastChange = change; + } + this.$updateMarkers(delta); + }; + this.onSelectionChange = function() { + var curOp = this.curOp = this.curOp || {}; + if (!curOp.cursorActivityHandlers) + curOp.cursorActivityHandlers = this._eventRegistry["cursorActivity"] && this._eventRegistry["cursorActivity"].slice(); + this.curOp.cursorActivity = true; + if (this.ace.inMultiSelectMode) { + this.ace.keyBinding.removeKeyboardHandler(multiSelectCommands.keyboardHandler); + } + }; + this.operation = function(fn, force) { + if (!force && this.curOp || force && this.curOp && this.curOp.force) { + return fn(); + } + if (force || !this.ace.curOp) { + if (this.curOp) + this.onBeforeEndOperation(); + } + if (!this.ace.curOp) { + var prevOp = this.ace.prevOp; + this.ace.startOperation({ + command: { name: "vim", scrollIntoView: "cursor" } + }); + } + var curOp = this.curOp = this.curOp || {}; + this.curOp.force = force; + var result = fn(); + if (this.ace.curOp && this.ace.curOp.command.name == "vim") { + if (this.state.dialog) + this.ace.curOp.command.scrollIntoView = false; + this.ace.endOperation(); + if (!curOp.cursorActivity && !curOp.lastChange && prevOp) + this.ace.prevOp = prevOp; + } + if (force || !this.ace.curOp) { + if (this.curOp) + this.onBeforeEndOperation(); + } + return result; + }; + this.onBeforeEndOperation = function() { + var op = this.curOp; + if (op) { + if (op.change) { this.signal("change", op.change, op); } + if (op && op.cursorActivity) { this.signal("cursorActivity", null, op); } + this.curOp = null; + } + }; + + this.signal = function(eventName, e, handlers) { + var listeners = handlers ? handlers[eventName + "Handlers"] + : (this._eventRegistry || {})[eventName]; + if (!listeners) + return; + listeners = listeners.slice(); + for (var i=0; i 0) { + point.row += rowShift; + point.column += point.row == end.row ? colShift : 0; + continue; + } + if (!isInsert && cmp2 <= 0) { + point.row = start.row; + point.column = start.column; + if (cmp2 === 0) + point.bias = 1; + } + } + }; + var Marker = function(cm, id, row, column) { + this.cm = cm; + this.id = id; + this.row = row; + this.column = column; + cm.marks[this.id] = this; + }; + Marker.prototype.clear = function() { delete this.cm.marks[this.id] }; + Marker.prototype.find = function() { return toCmPos(this) }; + this.setBookmark = function(cursor, options) { + var bm = new Marker(this, this.$uid++, cursor.line, cursor.ch); + if (!options || !options.insertLeft) + bm.$insertRight = true; + this.marks[bm.id] = bm; + return bm; + }; + this.moveH = function(increment, unit) { + if (unit == 'char') { + var sel = this.ace.selection; + sel.clearSelection(); + sel.moveCursorBy(0, increment); + } + }; + this.findPosV = function(start, amount, unit, goalColumn) { + if (unit == 'page') { + var renderer = this.ace.renderer; + var config = renderer.layerConfig; + amount = amount * Math.floor(config.height / config.lineHeight); + unit = 'line'; + } + if (unit == 'line') { + var screenPos = this.ace.session.documentToScreenPosition(start.line, start.ch); + if (goalColumn != null) + screenPos.column = goalColumn; + screenPos.row += amount; + screenPos.row = Math.min(Math.max(0, screenPos.row), this.ace.session.getScreenLength() - 1); + var pos = this.ace.session.screenToDocumentPosition(screenPos.row, screenPos.column); + return toCmPos(pos); + } else { + debugger; + } + }; + this.charCoords = function(pos, mode) { + if (mode == 'div' || !mode) { + var sc = this.ace.session.documentToScreenPosition(pos.line, pos.ch); + return {left: sc.column, top: sc.row}; + }if (mode == 'local') { + var renderer = this.ace.renderer; + var sc = this.ace.session.documentToScreenPosition(pos.line, pos.ch); + var lh = renderer.layerConfig.lineHeight; + var cw = renderer.layerConfig.characterWidth; + var top = lh * sc.row; + return {left: sc.column * cw, top: top, bottom: top + lh}; + } + }; + this.coordsChar = function(pos, mode) { + var renderer = this.ace.renderer; + if (mode == 'local') { + var row = Math.max(0, Math.floor(pos.top / renderer.lineHeight)); + var col = Math.max(0, Math.floor(pos.left / renderer.characterWidth)); + var ch = renderer.session.screenToDocumentPosition(row, col); + return toCmPos(ch); + } else if (mode == 'div') { + throw "not implemented"; + } + }; + this.getSearchCursor = function(query, pos, caseFold) { + var caseSensitive = false; + var isRegexp = false; + if (query instanceof RegExp && !query.global) { + caseSensitive = !query.ignoreCase; + query = query.source; + isRegexp = true; + } + var search = new Search(); + if (pos.ch == undefined) pos.ch = Number.MAX_VALUE; + var acePos = {row: pos.line, column: pos.ch}; + var cm = this; + var last = null; + return { + findNext: function() { return this.find(false) }, + findPrevious: function() {return this.find(true) }, + find: function(back) { + search.setOptions({ + needle: query, + caseSensitive: caseSensitive, + wrap: false, + backwards: back, + regExp: isRegexp, + start: last || acePos + }); + var range = search.find(cm.ace.session); + if (range && range.isEmpty()) { + if (cm.getLine(range.start.row).length == range.start.column) { + search.$options.start = range; + range = search.find(cm.ace.session); + } + } + last = range; + return last; + }, + from: function() { return last && toCmPos(last.start) }, + to: function() { return last && toCmPos(last.end) }, + replace: function(text) { + if (last) { + last.end = cm.ace.session.doc.replace(last, text); + } + } + }; + }; + this.scrollTo = function(x, y) { + var renderer = this.ace.renderer; + var config = renderer.layerConfig; + var maxHeight = config.maxHeight; + maxHeight -= (renderer.$size.scrollerHeight - renderer.lineHeight) * renderer.$scrollPastEnd; + if (y != null) this.ace.session.setScrollTop(Math.max(0, Math.min(y, maxHeight))); + if (x != null) this.ace.session.setScrollLeft(Math.max(0, Math.min(x, config.width))); + }; + this.scrollInfo = function() { return 0; }; + this.scrollIntoView = function(pos, margin) { + if (pos) { + var renderer = this.ace.renderer; + var viewMargin = { "top": 0, "bottom": margin }; + renderer.scrollCursorIntoView(toAcePos(pos), + (renderer.lineHeight * 2) / renderer.$size.scrollerHeight, viewMargin); + } + }; + this.getLine = function(row) { return this.ace.session.getLine(row) }; + this.getRange = function(s, e) { + return this.ace.session.getTextRange(new Range(s.line, s.ch, e.line, e.ch)); + }; + this.replaceRange = function(text, s, e) { + if (!e) e = s; + return this.ace.session.replace(new Range(s.line, s.ch, e.line, e.ch), text); + }; + this.replaceSelections = function(p) { + var sel = this.ace.selection; + if (this.ace.inVirtualSelectionMode) { + this.ace.session.replace(sel.getRange(), p[0] || ""); + return; + } + sel.inVirtualSelectionMode = true; + var ranges = sel.rangeList.ranges; + if (!ranges.length) ranges = [this.ace.multiSelect.getRange()]; + for (var i = ranges.length; i--;) + this.ace.session.replace(ranges[i], p[i] || ""); + sel.inVirtualSelectionMode = false; + }; + this.getSelection = function() { + return this.ace.getSelectedText(); + }; + this.getSelections = function() { + return this.listSelections().map(function(x) { + return this.getRange(x.anchor, x.head); + }, this); + }; + this.getInputField = function() { + return this.ace.textInput.getElement(); + }; + this.getWrapperElement = function() { + return this.ace.container; + }; + var optMap = { + indentWithTabs: "useSoftTabs", + indentUnit: "tabSize", + tabSize: "tabSize", + firstLineNumber: "firstLineNumber", + readOnly: "readOnly" + }; + this.setOption = function(name, val) { + this.state[name] = val; + switch (name) { + case 'indentWithTabs': + name = optMap[name]; + val = !val; + break; + case 'keyMap': + this.state.$keyMap = val; + return; + break; + default: + name = optMap[name]; + } + if (name) + this.ace.setOption(name, val); + }; + this.getOption = function(name, val) { + var aceOpt = optMap[name]; + if (aceOpt) + val = this.ace.getOption(aceOpt); + switch (name) { + case 'indentWithTabs': + name = optMap[name]; + return !val; + case 'keyMap': + return this.state.$keyMap; + } + return aceOpt ? val : this.state[name]; + }; + this.toggleOverwrite = function(on) { + this.state.overwrite = on; + return this.ace.setOverwrite(on); + }; + this.addOverlay = function(o) { + if (!this.$searchHighlight || !this.$searchHighlight.session) { + var highlight = new SearchHighlight(null, "ace_highlight-marker", "text"); + var marker = this.ace.session.addDynamicMarker(highlight); + highlight.id = marker.id; + highlight.session = this.ace.session; + highlight.destroy = function(o) { + highlight.session.off("change", highlight.updateOnChange); + highlight.session.off("changeEditor", highlight.destroy); + highlight.session.removeMarker(highlight.id); + highlight.session = null; + }; + highlight.updateOnChange = function(delta) { + var row = delta.start.row; + if (row == delta.end.row) highlight.cache[row] = undefined; + else highlight.cache.splice(row, highlight.cache.length); + }; + highlight.session.on("changeEditor", highlight.destroy); + highlight.session.on("change", highlight.updateOnChange); + } + var re = new RegExp(o.query.source, "gmi"); + this.$searchHighlight = o.highlight = highlight; + this.$searchHighlight.setRegexp(re); + this.ace.renderer.updateBackMarkers(); + }; + this.removeOverlay = function(o) { + if (this.$searchHighlight && this.$searchHighlight.session) { + this.$searchHighlight.destroy(); + } + }; + this.getScrollInfo = function() { + var renderer = this.ace.renderer; + var config = renderer.layerConfig; + return { + left: renderer.scrollLeft, + top: renderer.scrollTop, + height: config.maxHeight, + width: config.width, + clientHeight: config.height, + clientWidth: config.width + }; + }; + this.getValue = function() { + return this.ace.getValue(); + }; + this.setValue = function(v) { + return this.ace.setValue(v, -1); + }; + this.getTokenTypeAt = function(pos) { + var token = this.ace.session.getTokenAt(pos.line, pos.ch); + return token && /comment|string/.test(token.type) ? "string" : ""; + }; + this.findMatchingBracket = function(pos) { + var m = this.ace.session.findMatchingBracket(toAcePos(pos)); + return {to: m && toCmPos(m)}; + }; + this.indentLine = function(line, method) { + if (method === true) + this.ace.session.indentRows(line, line, "\t"); + else if (method === false) + this.ace.session.outdentRows(new Range(line, 0, line, 0)); + }; + this.indexFromPos = function(pos) { + return this.ace.session.doc.positionToIndex(toAcePos(pos)); + }; + this.posFromIndex = function(index) { + return toCmPos(this.ace.session.doc.indexToPosition(index)); + }; + this.focus = function(index) { + return this.ace.textInput.focus(); + }; + this.blur = function(index) { + return this.ace.blur(); + }; + this.defaultTextHeight = function(index) { + return this.ace.renderer.layerConfig.lineHeight; + }; + this.scanForBracket = function(pos, dir, _, options) { + var re = options.bracketRegex.source; + var tokenRe = /paren|text|operator|tag/; + if (dir == 1) { + var m = this.ace.session.$findClosingBracket(re.slice(1, 2), toAcePos(pos), tokenRe); + } else { + var m = this.ace.session.$findOpeningBracket(re.slice(-2, -1), {row: pos.line, column: pos.ch + 1}, tokenRe); + } + return m && {pos: toCmPos(m)}; + }; + this.refresh = function() { + return this.ace.resize(true); + }; + this.getMode = function() { + return { name : this.getOption("mode") }; + }; + this.execCommand = function() { + + }; +}).call(CodeMirror.prototype); + function toAcePos(cmPos) { + return {row: cmPos.line, column: cmPos.ch}; + } + function toCmPos(acePos) { + return new Pos(acePos.row, acePos.column); + } + + var StringStream = CodeMirror.StringStream = function(string, tabSize) { + this.pos = this.start = 0; + this.string = string; + this.tabSize = tabSize || 8; + this.lastColumnPos = this.lastColumnValue = 0; + this.lineStart = 0; + }; + + StringStream.prototype = { + eol: function() {return this.pos >= this.string.length;}, + sol: function() {return this.pos == this.lineStart;}, + peek: function() {return this.string.charAt(this.pos) || undefined;}, + next: function() { + if (this.pos < this.string.length) + return this.string.charAt(this.pos++); + }, + eat: function(match) { + var ch = this.string.charAt(this.pos); + if (typeof match == "string") var ok = ch == match; + else var ok = ch && (match.test ? match.test(ch) : match(ch)); + if (ok) {++this.pos; return ch;} + }, + eatWhile: function(match) { + var start = this.pos; + while (this.eat(match)){} + return this.pos > start; + }, + eatSpace: function() { + var start = this.pos; + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; + return this.pos > start; + }, + skipToEnd: function() {this.pos = this.string.length;}, + skipTo: function(ch) { + var found = this.string.indexOf(ch, this.pos); + if (found > -1) {this.pos = found; return true;} + }, + backUp: function(n) {this.pos -= n;}, + column: function() { + throw "not implemented"; + }, + indentation: function() { + throw "not implemented"; + }, + match: function(pattern, consume, caseInsensitive) { + if (typeof pattern == "string") { + var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; + var substr = this.string.substr(this.pos, pattern.length); + if (cased(substr) == cased(pattern)) { + if (consume !== false) this.pos += pattern.length; + return true; + } + } else { + var match = this.string.slice(this.pos).match(pattern); + if (match && match.index > 0) return null; + if (match && consume !== false) this.pos += match[0].length; + return match; + } + }, + current: function(){return this.string.slice(this.start, this.pos);}, + hideFirstChars: function(n, inner) { + this.lineStart += n; + try { return inner(); } + finally { this.lineStart -= n; } + } + }; +CodeMirror.defineExtension = function(name, fn) { + CodeMirror.prototype[name] = fn; +}; +dom.importCssString(".normal-mode .ace_cursor{\ + border: none;\ + background-color: rgba(255,0,0,0.5);\ +}\ +.normal-mode .ace_hidden-cursors .ace_cursor{\ + background-color: transparent;\ + border: 1px solid red;\ + opacity: 0.7\ +}\ +.ace_dialog {\ + position: absolute;\ + left: 0; right: 0;\ + background: inherit;\ + z-index: 15;\ + padding: .1em .8em;\ + overflow: hidden;\ + color: inherit;\ +}\ +.ace_dialog-top {\ + border-bottom: 1px solid #444;\ + top: 0;\ +}\ +.ace_dialog-bottom {\ + border-top: 1px solid #444;\ + bottom: 0;\ +}\ +.ace_dialog input {\ + border: none;\ + outline: none;\ + background: transparent;\ + width: 20em;\ + color: inherit;\ + font-family: monospace;\ +}", "vimMode"); +(function() { + function dialogDiv(cm, template, bottom) { + var wrap = cm.ace.container; + var dialog; + dialog = wrap.appendChild(document.createElement("div")); + if (bottom) + dialog.className = "ace_dialog ace_dialog-bottom"; + else + dialog.className = "ace_dialog ace_dialog-top"; + + if (typeof template == "string") { + dialog.innerHTML = template; + } else { // Assuming it's a detached DOM element. + dialog.appendChild(template); + } + return dialog; + } + + function closeNotification(cm, newVal) { + if (cm.state.currentNotificationClose) + cm.state.currentNotificationClose(); + cm.state.currentNotificationClose = newVal; + } + + CodeMirror.defineExtension("openDialog", function(template, callback, options) { + if (this.virtualSelectionMode()) return; + if (!options) options = {}; + + closeNotification(this, null); + + var dialog = dialogDiv(this, template, options.bottom); + var closed = false, me = this; + this.state.dialog = dialog; + function close(newVal) { + if (typeof newVal == 'string') { + inp.value = newVal; + } else { + if (closed) return; + + if (newVal && newVal.type == "blur") { + if (document.activeElement === inp) + return; + } + + me.state.dialog = null; + closed = true; + dialog.parentNode.removeChild(dialog); + me.focus(); + + if (options.onClose) options.onClose(dialog); + } + } + + var inp = dialog.getElementsByTagName("input")[0], button; + if (inp) { + if (options.value) { + inp.value = options.value; + if (options.selectValueOnOpen !== false) inp.select(); + } + + if (options.onInput) + CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);}); + if (options.onKeyUp) + CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);}); + + CodeMirror.on(inp, "keydown", function(e) { + if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; } + if (e.keyCode == 13) callback(inp.value); + if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) { + inp.blur(); + CodeMirror.e_stop(e); + close(); + } + }); + + if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close); + + inp.focus(); + } else if (button = dialog.getElementsByTagName("button")[0]) { + CodeMirror.on(button, "click", function() { + close(); + me.focus(); + }); + + if (options.closeOnBlur !== false) CodeMirror.on(button, "blur", close); + + button.focus(); + } + return close; + }); + + CodeMirror.defineExtension("openNotification", function(template, options) { + if (this.virtualSelectionMode()) return; + closeNotification(this, close); + var dialog = dialogDiv(this, template, options && options.bottom); + var closed = false, doneTimer; + var duration = options && typeof options.duration !== "undefined" ? options.duration : 5000; + + function close() { + if (closed) return; + closed = true; + clearTimeout(doneTimer); + dialog.parentNode.removeChild(dialog); + } + + CodeMirror.on(dialog, 'click', function(e) { + CodeMirror.e_preventDefault(e); + close(); + }); + + if (duration) + doneTimer = setTimeout(close, duration); + + return close; + }); +})(); + + + var defaultKeymap = [ + { keys: '', type: 'keyToKey', toKeys: 'h' }, + { keys: '', type: 'keyToKey', toKeys: 'l' }, + { keys: '', type: 'keyToKey', toKeys: 'k' }, + { keys: '', type: 'keyToKey', toKeys: 'j' }, + { keys: '', type: 'keyToKey', toKeys: 'l' }, + { keys: '', type: 'keyToKey', toKeys: 'h', context: 'normal'}, + { keys: '', type: 'keyToKey', toKeys: 'x', context: 'normal'}, + { keys: '', type: 'keyToKey', toKeys: 'W' }, + { keys: '', type: 'keyToKey', toKeys: 'B', context: 'normal' }, + { keys: '', type: 'keyToKey', toKeys: 'w' }, + { keys: '', type: 'keyToKey', toKeys: 'b', context: 'normal' }, + { keys: '', type: 'keyToKey', toKeys: 'j' }, + { keys: '', type: 'keyToKey', toKeys: 'k' }, + { keys: '', type: 'keyToKey', toKeys: '' }, + { keys: '', type: 'keyToKey', toKeys: '' }, + { keys: '', type: 'keyToKey', toKeys: '', context: 'insert' }, + { keys: '', type: 'keyToKey', toKeys: '', context: 'insert' }, + { keys: '', type: 'keyToKey', toKeys: '' }, // ace_patch ipad keyboard sends C-Esc instead of C-[ + { keys: '', type: 'keyToKey', toKeys: '', context: 'insert' }, + { keys: 's', type: 'keyToKey', toKeys: 'cl', context: 'normal' }, + { keys: 's', type: 'keyToKey', toKeys: 'c', context: 'visual'}, + { keys: 'S', type: 'keyToKey', toKeys: 'cc', context: 'normal' }, + { keys: 'S', type: 'keyToKey', toKeys: 'VdO', context: 'visual' }, + { keys: '', type: 'keyToKey', toKeys: '0' }, + { keys: '', type: 'keyToKey', toKeys: '$' }, + { keys: '', type: 'keyToKey', toKeys: '' }, + { keys: '', type: 'keyToKey', toKeys: '' }, + { keys: '', type: 'keyToKey', toKeys: 'j^', context: 'normal' }, + { keys: '', type: 'action', action: 'toggleOverwrite', context: 'insert' }, + { keys: 'H', type: 'motion', motion: 'moveToTopLine', motionArgs: { linewise: true, toJumplist: true }}, + { keys: 'M', type: 'motion', motion: 'moveToMiddleLine', motionArgs: { linewise: true, toJumplist: true }}, + { keys: 'L', type: 'motion', motion: 'moveToBottomLine', motionArgs: { linewise: true, toJumplist: true }}, + { keys: 'h', type: 'motion', motion: 'moveByCharacters', motionArgs: { forward: false }}, + { keys: 'l', type: 'motion', motion: 'moveByCharacters', motionArgs: { forward: true }}, + { keys: 'j', type: 'motion', motion: 'moveByLines', motionArgs: { forward: true, linewise: true }}, + { keys: 'k', type: 'motion', motion: 'moveByLines', motionArgs: { forward: false, linewise: true }}, + { keys: 'gj', type: 'motion', motion: 'moveByDisplayLines', motionArgs: { forward: true }}, + { keys: 'gk', type: 'motion', motion: 'moveByDisplayLines', motionArgs: { forward: false }}, + { keys: 'w', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: false }}, + { keys: 'W', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: false, bigWord: true }}, + { keys: 'e', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: true, inclusive: true }}, + { keys: 'E', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: true, bigWord: true, inclusive: true }}, + { keys: 'b', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: false }}, + { keys: 'B', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: false, bigWord: true }}, + { keys: 'ge', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: true, inclusive: true }}, + { keys: 'gE', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: true, bigWord: true, inclusive: true }}, + { keys: '{', type: 'motion', motion: 'moveByParagraph', motionArgs: { forward: false, toJumplist: true }}, + { keys: '}', type: 'motion', motion: 'moveByParagraph', motionArgs: { forward: true, toJumplist: true }}, + { keys: '(', type: 'motion', motion: 'moveBySentence', motionArgs: { forward: false }}, + { keys: ')', type: 'motion', motion: 'moveBySentence', motionArgs: { forward: true }}, + { keys: '', type: 'motion', motion: 'moveByPage', motionArgs: { forward: true }}, + { keys: '', type: 'motion', motion: 'moveByPage', motionArgs: { forward: false }}, + { keys: '', type: 'motion', motion: 'moveByScroll', motionArgs: { forward: true, explicitRepeat: true }}, + { keys: '', type: 'motion', motion: 'moveByScroll', motionArgs: { forward: false, explicitRepeat: true }}, + { keys: 'gg', type: 'motion', motion: 'moveToLineOrEdgeOfDocument', motionArgs: { forward: false, explicitRepeat: true, linewise: true, toJumplist: true }}, + { keys: 'G', type: 'motion', motion: 'moveToLineOrEdgeOfDocument', motionArgs: { forward: true, explicitRepeat: true, linewise: true, toJumplist: true }}, + { keys: '0', type: 'motion', motion: 'moveToStartOfLine' }, + { keys: '^', type: 'motion', motion: 'moveToFirstNonWhiteSpaceCharacter' }, + { keys: '+', type: 'motion', motion: 'moveByLines', motionArgs: { forward: true, toFirstChar:true }}, + { keys: '-', type: 'motion', motion: 'moveByLines', motionArgs: { forward: false, toFirstChar:true }}, + { keys: '_', type: 'motion', motion: 'moveByLines', motionArgs: { forward: true, toFirstChar:true, repeatOffset:-1 }}, + { keys: '$', type: 'motion', motion: 'moveToEol', motionArgs: { inclusive: true }}, + { keys: '%', type: 'motion', motion: 'moveToMatchedSymbol', motionArgs: { inclusive: true, toJumplist: true }}, + { keys: 'f', type: 'motion', motion: 'moveToCharacter', motionArgs: { forward: true , inclusive: true }}, + { keys: 'F', type: 'motion', motion: 'moveToCharacter', motionArgs: { forward: false }}, + { keys: 't', type: 'motion', motion: 'moveTillCharacter', motionArgs: { forward: true, inclusive: true }}, + { keys: 'T', type: 'motion', motion: 'moveTillCharacter', motionArgs: { forward: false }}, + { keys: ';', type: 'motion', motion: 'repeatLastCharacterSearch', motionArgs: { forward: true }}, + { keys: ',', type: 'motion', motion: 'repeatLastCharacterSearch', motionArgs: { forward: false }}, + { keys: '\'', type: 'motion', motion: 'goToMark', motionArgs: {toJumplist: true, linewise: true}}, + { keys: '`', type: 'motion', motion: 'goToMark', motionArgs: {toJumplist: true}}, + { keys: ']`', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true } }, + { keys: '[`', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false } }, + { keys: ']\'', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true, linewise: true } }, + { keys: '[\'', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false, linewise: true } }, + { keys: ']p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: true, isEdit: true, matchIndent: true}}, + { keys: '[p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: false, isEdit: true, matchIndent: true}}, + { keys: ']', type: 'motion', motion: 'moveToSymbol', motionArgs: { forward: true, toJumplist: true}}, + { keys: '[', type: 'motion', motion: 'moveToSymbol', motionArgs: { forward: false, toJumplist: true}}, + { keys: '|', type: 'motion', motion: 'moveToColumn'}, + { keys: 'o', type: 'motion', motion: 'moveToOtherHighlightedEnd', context:'visual'}, + { keys: 'O', type: 'motion', motion: 'moveToOtherHighlightedEnd', motionArgs: {sameLine: true}, context:'visual'}, + { keys: 'd', type: 'operator', operator: 'delete' }, + { keys: 'y', type: 'operator', operator: 'yank' }, + { keys: 'c', type: 'operator', operator: 'change' }, + { keys: '=', type: 'operator', operator: 'indentAuto' }, + { keys: '>', type: 'operator', operator: 'indent', operatorArgs: { indentRight: true }}, + { keys: '<', type: 'operator', operator: 'indent', operatorArgs: { indentRight: false }}, + { keys: 'g~', type: 'operator', operator: 'changeCase' }, + { keys: 'gu', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: true}, isEdit: true }, + { keys: 'gU', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: false}, isEdit: true }, + { keys: 'n', type: 'motion', motion: 'findNext', motionArgs: { forward: true, toJumplist: true }}, + { keys: 'N', type: 'motion', motion: 'findNext', motionArgs: { forward: false, toJumplist: true }}, + { keys: 'x', type: 'operatorMotion', operator: 'delete', motion: 'moveByCharacters', motionArgs: { forward: true }, operatorMotionArgs: { visualLine: false }}, + { keys: 'X', type: 'operatorMotion', operator: 'delete', motion: 'moveByCharacters', motionArgs: { forward: false }, operatorMotionArgs: { visualLine: true }}, + { keys: 'D', type: 'operatorMotion', operator: 'delete', motion: 'moveToEol', motionArgs: { inclusive: true }, context: 'normal'}, + { keys: 'D', type: 'operator', operator: 'delete', operatorArgs: { linewise: true }, context: 'visual'}, + { keys: 'Y', type: 'operatorMotion', operator: 'yank', motion: 'expandToLine', motionArgs: { linewise: true }, context: 'normal'}, + { keys: 'Y', type: 'operator', operator: 'yank', operatorArgs: { linewise: true }, context: 'visual'}, + { keys: 'C', type: 'operatorMotion', operator: 'change', motion: 'moveToEol', motionArgs: { inclusive: true }, context: 'normal'}, + { keys: 'C', type: 'operator', operator: 'change', operatorArgs: { linewise: true }, context: 'visual'}, + { keys: '~', type: 'operatorMotion', operator: 'changeCase', motion: 'moveByCharacters', motionArgs: { forward: true }, operatorArgs: { shouldMoveCursor: true }, context: 'normal'}, + { keys: '~', type: 'operator', operator: 'changeCase', context: 'visual'}, + { keys: '', type: 'operatorMotion', operator: 'delete', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: false }, context: 'insert' }, + { keys: '', type: 'idle', context: 'normal' }, + { keys: '', type: 'action', action: 'jumpListWalk', actionArgs: { forward: true }}, + { keys: '', type: 'action', action: 'jumpListWalk', actionArgs: { forward: false }}, + { keys: '', type: 'action', action: 'scroll', actionArgs: { forward: true, linewise: true }}, + { keys: '', type: 'action', action: 'scroll', actionArgs: { forward: false, linewise: true }}, + { keys: 'a', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'charAfter' }, context: 'normal' }, + { keys: 'A', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'eol' }, context: 'normal' }, + { keys: 'A', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'endOfSelectedArea' }, context: 'visual' }, + { keys: 'i', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'inplace' }, context: 'normal' }, + { keys: 'I', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'firstNonBlank'}, context: 'normal' }, + { keys: 'I', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'startOfSelectedArea' }, context: 'visual' }, + { keys: 'o', type: 'action', action: 'newLineAndEnterInsertMode', isEdit: true, interlaceInsertRepeat: true, actionArgs: { after: true }, context: 'normal' }, + { keys: 'O', type: 'action', action: 'newLineAndEnterInsertMode', isEdit: true, interlaceInsertRepeat: true, actionArgs: { after: false }, context: 'normal' }, + { keys: 'v', type: 'action', action: 'toggleVisualMode' }, + { keys: 'V', type: 'action', action: 'toggleVisualMode', actionArgs: { linewise: true }}, + { keys: '', type: 'action', action: 'toggleVisualMode', actionArgs: { blockwise: true }}, + { keys: '', type: 'action', action: 'toggleVisualMode', actionArgs: { blockwise: true }}, + { keys: 'gv', type: 'action', action: 'reselectLastSelection' }, + { keys: 'J', type: 'action', action: 'joinLines', isEdit: true }, + { keys: 'p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: true, isEdit: true }}, + { keys: 'P', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: false, isEdit: true }}, + { keys: 'r', type: 'action', action: 'replace', isEdit: true }, + { keys: '@', type: 'action', action: 'replayMacro' }, + { keys: 'q', type: 'action', action: 'enterMacroRecordMode' }, + { keys: 'R', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { replace: true }, context: 'normal'}, + { keys: 'R', type: 'operator', operator: 'change', operatorArgs: { linewise: true, fullLine: true }, context: 'visual', exitVisualBlock: true}, + { keys: 'u', type: 'action', action: 'undo', context: 'normal' }, + { keys: 'u', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: true}, context: 'visual', isEdit: true }, + { keys: 'U', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: false}, context: 'visual', isEdit: true }, + { keys: '', type: 'action', action: 'redo' }, + { keys: 'm', type: 'action', action: 'setMark' }, + { keys: '"', type: 'action', action: 'setRegister' }, + { keys: 'zz', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'center' }}, + { keys: 'z.', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'center' }, motion: 'moveToFirstNonWhiteSpaceCharacter' }, + { keys: 'zt', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'top' }}, + { keys: 'z', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'top' }, motion: 'moveToFirstNonWhiteSpaceCharacter' }, + { keys: 'z-', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'bottom' }}, + { keys: 'zb', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'bottom' }, motion: 'moveToFirstNonWhiteSpaceCharacter' }, + { keys: '.', type: 'action', action: 'repeatLastEdit' }, + { keys: '', type: 'action', action: 'incrementNumberToken', isEdit: true, actionArgs: {increase: true, backtrack: false}}, + { keys: '', type: 'action', action: 'incrementNumberToken', isEdit: true, actionArgs: {increase: false, backtrack: false}}, + { keys: '', type: 'action', action: 'indent', actionArgs: { indentRight: true }, context: 'insert' }, + { keys: '', type: 'action', action: 'indent', actionArgs: { indentRight: false }, context: 'insert' }, + { keys: 'a', type: 'motion', motion: 'textObjectManipulation' }, + { keys: 'i', type: 'motion', motion: 'textObjectManipulation', motionArgs: { textObjectInner: true }}, + { keys: '/', type: 'search', searchArgs: { forward: true, querySrc: 'prompt', toJumplist: true }}, + { keys: '?', type: 'search', searchArgs: { forward: false, querySrc: 'prompt', toJumplist: true }}, + { keys: '*', type: 'search', searchArgs: { forward: true, querySrc: 'wordUnderCursor', wholeWordOnly: true, toJumplist: true }}, + { keys: '#', type: 'search', searchArgs: { forward: false, querySrc: 'wordUnderCursor', wholeWordOnly: true, toJumplist: true }}, + { keys: 'g*', type: 'search', searchArgs: { forward: true, querySrc: 'wordUnderCursor', toJumplist: true }}, + { keys: 'g#', type: 'search', searchArgs: { forward: false, querySrc: 'wordUnderCursor', toJumplist: true }}, + { keys: ':', type: 'ex' } + ]; + var defaultKeymapLength = defaultKeymap.length; + var defaultExCommandMap = [ + { name: 'colorscheme', shortName: 'colo' }, + { name: 'map' }, + { name: 'imap', shortName: 'im' }, + { name: 'nmap', shortName: 'nm' }, + { name: 'vmap', shortName: 'vm' }, + { name: 'unmap' }, + { name: 'write', shortName: 'w' }, + { name: 'undo', shortName: 'u' }, + { name: 'redo', shortName: 'red' }, + { name: 'set', shortName: 'se' }, + { name: 'set', shortName: 'se' }, + { name: 'setlocal', shortName: 'setl' }, + { name: 'setglobal', shortName: 'setg' }, + { name: 'sort', shortName: 'sor' }, + { name: 'substitute', shortName: 's', possiblyAsync: true }, + { name: 'nohlsearch', shortName: 'noh' }, + { name: 'yank', shortName: 'y' }, + { name: 'delmarks', shortName: 'delm' }, + { name: 'registers', shortName: 'reg', excludeFromCommandHistory: true }, + { name: 'global', shortName: 'g' } + ]; + + var Pos = CodeMirror.Pos; + + var Vim = function() { return vimApi; } //{ + function enterVimMode(cm) { + cm.setOption('disableInput', true); + cm.setOption('showCursorWhenSelecting', false); + CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"}); + cm.on('cursorActivity', onCursorActivity); + maybeInitVimState(cm); + CodeMirror.on(cm.getInputField(), 'paste', getOnPasteFn(cm)); + } + + function leaveVimMode(cm) { + cm.setOption('disableInput', false); + cm.off('cursorActivity', onCursorActivity); + CodeMirror.off(cm.getInputField(), 'paste', getOnPasteFn(cm)); + cm.state.vim = null; + } + + function detachVimMap(cm, next) { + if (this == CodeMirror.keyMap.vim) + CodeMirror.rmClass(cm.getWrapperElement(), "cm-fat-cursor"); + + if (!next || next.attach != attachVimMap) + leaveVimMode(cm); + } + function attachVimMap(cm, prev) { + if (this == CodeMirror.keyMap.vim) + CodeMirror.addClass(cm.getWrapperElement(), "cm-fat-cursor"); + + if (!prev || prev.attach != attachVimMap) + enterVimMode(cm); + } + CodeMirror.defineOption('vimMode', false, function(cm, val, prev) { + if (val && cm.getOption("keyMap") != "vim") + cm.setOption("keyMap", "vim"); + else if (!val && prev != CodeMirror.Init && /^vim/.test(cm.getOption("keyMap"))) + cm.setOption("keyMap", "default"); + }); + + function cmKey(key, cm) { + if (!cm) { return undefined; } + if (this[key]) { return this[key]; } + var vimKey = cmKeyToVimKey(key); + if (!vimKey) { + return false; + } + var cmd = CodeMirror.Vim.findKey(cm, vimKey); + if (typeof cmd == 'function') { + CodeMirror.signal(cm, 'vim-keypress', vimKey); + } + return cmd; + } + + var modifiers = {'Shift': 'S', 'Ctrl': 'C', 'Alt': 'A', 'Cmd': 'D', 'Mod': 'A'}; + var specialKeys = {Enter:'CR',Backspace:'BS',Delete:'Del',Insert:'Ins'}; + function cmKeyToVimKey(key) { + if (key.charAt(0) == '\'') { + return key.charAt(1); + } + var pieces = key.split(/-(?!$)/); + var lastPiece = pieces[pieces.length - 1]; + if (pieces.length == 1 && pieces[0].length == 1) { + return false; + } else if (pieces.length == 2 && pieces[0] == 'Shift' && lastPiece.length == 1) { + return false; + } + var hasCharacter = false; + for (var i = 0; i < pieces.length; i++) { + var piece = pieces[i]; + if (piece in modifiers) { pieces[i] = modifiers[piece]; } + else { hasCharacter = true; } + if (piece in specialKeys) { pieces[i] = specialKeys[piece]; } + } + if (!hasCharacter) { + return false; + } + if (isUpperCase(lastPiece)) { + pieces[pieces.length - 1] = lastPiece.toLowerCase(); + } + return '<' + pieces.join('-') + '>'; + } + + function getOnPasteFn(cm) { + var vim = cm.state.vim; + if (!vim.onPasteFn) { + vim.onPasteFn = function() { + if (!vim.insertMode) { + cm.setCursor(offsetCursor(cm.getCursor(), 0, 1)); + actions.enterInsertMode(cm, {}, vim); + } + }; + } + return vim.onPasteFn; + } + + var numberRegex = /[\d]/; + var wordCharTest = [CodeMirror.isWordChar, function(ch) { + return ch && !CodeMirror.isWordChar(ch) && !/\s/.test(ch); + }], bigWordCharTest = [function(ch) { + return /\S/.test(ch); + }]; + function makeKeyRange(start, size) { + var keys = []; + for (var i = start; i < start + size; i++) { + keys.push(String.fromCharCode(i)); + } + return keys; + } + var upperCaseAlphabet = makeKeyRange(65, 26); + var lowerCaseAlphabet = makeKeyRange(97, 26); + var numbers = makeKeyRange(48, 10); + var validMarks = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['<', '>']); + var validRegisters = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['-', '"', '.', ':', '/']); + + function isLine(cm, line) { + return line >= cm.firstLine() && line <= cm.lastLine(); + } + function isLowerCase(k) { + return (/^[a-z]$/).test(k); + } + function isMatchableSymbol(k) { + return '()[]{}'.indexOf(k) != -1; + } + function isNumber(k) { + return numberRegex.test(k); + } + function isUpperCase(k) { + return (/^[A-Z]$/).test(k); + } + function isWhiteSpaceString(k) { + return (/^\s*$/).test(k); + } + function isEndOfSentenceSymbol(k) { + return '.?!'.indexOf(k) != -1; + } + function inArray(val, arr) { + for (var i = 0; i < arr.length; i++) { + if (arr[i] == val) { + return true; + } + } + return false; + } + + var options = {}; + function defineOption(name, defaultValue, type, aliases, callback) { + if (defaultValue === undefined && !callback) { + throw Error('defaultValue is required unless callback is provided'); + } + if (!type) { type = 'string'; } + options[name] = { + type: type, + defaultValue: defaultValue, + callback: callback + }; + if (aliases) { + for (var i = 0; i < aliases.length; i++) { + options[aliases[i]] = options[name]; + } + } + if (defaultValue) { + setOption(name, defaultValue); + } + } + + function setOption(name, value, cm, cfg) { + var option = options[name]; + cfg = cfg || {}; + var scope = cfg.scope; + if (!option) { + return new Error('Unknown option: ' + name); + } + if (option.type == 'boolean') { + if (value && value !== true) { + return new Error('Invalid argument: ' + name + '=' + value); + } else if (value !== false) { + value = true; + } + } + if (option.callback) { + if (scope !== 'local') { + option.callback(value, undefined); + } + if (scope !== 'global' && cm) { + option.callback(value, cm); + } + } else { + if (scope !== 'local') { + option.value = option.type == 'boolean' ? !!value : value; + } + if (scope !== 'global' && cm) { + cm.state.vim.options[name] = {value: value}; + } + } + } + + function getOption(name, cm, cfg) { + var option = options[name]; + cfg = cfg || {}; + var scope = cfg.scope; + if (!option) { + return new Error('Unknown option: ' + name); + } + if (option.callback) { + var local = cm && option.callback(undefined, cm); + if (scope !== 'global' && local !== undefined) { + return local; + } + if (scope !== 'local') { + return option.callback(); + } + return; + } else { + var local = (scope !== 'global') && (cm && cm.state.vim.options[name]); + return (local || (scope !== 'local') && option || {}).value; + } + } + + defineOption('filetype', undefined, 'string', ['ft'], function(name, cm) { + if (cm === undefined) { + return; + } + if (name === undefined) { + var mode = cm.getOption('mode'); + return mode == 'null' ? '' : mode; + } else { + var mode = name == '' ? 'null' : name; + cm.setOption('mode', mode); + } + }); + + var createCircularJumpList = function() { + var size = 100; + var pointer = -1; + var head = 0; + var tail = 0; + var buffer = new Array(size); + function add(cm, oldCur, newCur) { + var current = pointer % size; + var curMark = buffer[current]; + function useNextSlot(cursor) { + var next = ++pointer % size; + var trashMark = buffer[next]; + if (trashMark) { + trashMark.clear(); + } + buffer[next] = cm.setBookmark(cursor); + } + if (curMark) { + var markPos = curMark.find(); + if (markPos && !cursorEqual(markPos, oldCur)) { + useNextSlot(oldCur); + } + } else { + useNextSlot(oldCur); + } + useNextSlot(newCur); + head = pointer; + tail = pointer - size + 1; + if (tail < 0) { + tail = 0; + } + } + function move(cm, offset) { + pointer += offset; + if (pointer > head) { + pointer = head; + } else if (pointer < tail) { + pointer = tail; + } + var mark = buffer[(size + pointer) % size]; + if (mark && !mark.find()) { + var inc = offset > 0 ? 1 : -1; + var newCur; + var oldCur = cm.getCursor(); + do { + pointer += inc; + mark = buffer[(size + pointer) % size]; + if (mark && + (newCur = mark.find()) && + !cursorEqual(oldCur, newCur)) { + break; + } + } while (pointer < head && pointer > tail); + } + return mark; + } + return { + cachedCursor: undefined, //used for # and * jumps + add: add, + move: move + }; + }; + var createInsertModeChanges = function(c) { + if (c) { + return { + changes: c.changes, + expectCursorActivityForChange: c.expectCursorActivityForChange + }; + } + return { + changes: [], + expectCursorActivityForChange: false + }; + }; + + function MacroModeState() { + this.latestRegister = undefined; + this.isPlaying = false; + this.isRecording = false; + this.replaySearchQueries = []; + this.onRecordingDone = undefined; + this.lastInsertModeChanges = createInsertModeChanges(); + } + MacroModeState.prototype = { + exitMacroRecordMode: function() { + var macroModeState = vimGlobalState.macroModeState; + if (macroModeState.onRecordingDone) { + macroModeState.onRecordingDone(); // close dialog + } + macroModeState.onRecordingDone = undefined; + macroModeState.isRecording = false; + }, + enterMacroRecordMode: function(cm, registerName) { + var register = + vimGlobalState.registerController.getRegister(registerName); + if (register) { + register.clear(); + this.latestRegister = registerName; + if (cm.openDialog) { + this.onRecordingDone = cm.openDialog( + '(recording)['+registerName+']', null, {bottom:true}); + } + this.isRecording = true; + } + } + }; + + function maybeInitVimState(cm) { + if (!cm.state.vim) { + cm.state.vim = { + inputState: new InputState(), + lastEditInputState: undefined, + lastEditActionCommand: undefined, + lastHPos: -1, + lastHSPos: -1, + lastMotion: null, + marks: {}, + fakeCursor: null, + insertMode: false, + insertModeRepeat: undefined, + visualMode: false, + visualLine: false, + visualBlock: false, + lastSelection: null, + lastPastedText: null, + sel: {}, + options: {} + }; + } + return cm.state.vim; + } + var vimGlobalState; + function resetVimGlobalState() { + vimGlobalState = { + searchQuery: null, + searchIsReversed: false, + lastSubstituteReplacePart: undefined, + jumpList: createCircularJumpList(), + macroModeState: new MacroModeState, + lastCharacterSearch: {increment:0, forward:true, selectedCharacter:''}, + registerController: new RegisterController({}), + searchHistoryController: new HistoryController(), + exCommandHistoryController : new HistoryController() + }; + for (var optionName in options) { + var option = options[optionName]; + option.value = option.defaultValue; + } + } + + var lastInsertModeKeyTimer; + var vimApi= { + buildKeyMap: function() { + }, + getRegisterController: function() { + return vimGlobalState.registerController; + }, + resetVimGlobalState_: resetVimGlobalState, + getVimGlobalState_: function() { + return vimGlobalState; + }, + maybeInitVimState_: maybeInitVimState, + + suppressErrorLogging: false, + + InsertModeKey: InsertModeKey, + map: function(lhs, rhs, ctx) { + exCommandDispatcher.map(lhs, rhs, ctx); + }, + unmap: function(lhs, ctx) { + exCommandDispatcher.unmap(lhs, ctx); + }, + noremap: function(lhs, rhs, ctx) { + function toCtxArray(ctx) { + return ctx ? [ctx] : ['normal', 'insert', 'visual']; + } + var ctxsToMap = toCtxArray(ctx); + var actualLength = defaultKeymap.length, origLength = defaultKeymapLength; + for (var i = actualLength - origLength; + i < actualLength && ctxsToMap.length; + i++) { + var mapping = defaultKeymap[i]; + if (mapping.keys == rhs && + (!ctx || !mapping.context || mapping.context === ctx) && + mapping.type.substr(0, 2) !== 'ex' && + mapping.type.substr(0, 3) !== 'key') { + var newMapping = {}; + for (var key in mapping) { + newMapping[key] = mapping[key]; + } + newMapping.keys = lhs; + if (ctx && !newMapping.context) { + newMapping.context = ctx; + } + this._mapCommand(newMapping); + var mappedCtxs = toCtxArray(mapping.context); + ctxsToMap = ctxsToMap.filter(function(el) { return mappedCtxs.indexOf(el) === -1; }); + } + } + }, + mapclear: function(ctx) { + var actualLength = defaultKeymap.length, + origLength = defaultKeymapLength; + var userKeymap = defaultKeymap.slice(0, actualLength - origLength); + defaultKeymap = defaultKeymap.slice(actualLength - origLength); + if (ctx) { + for (var i = userKeymap.length - 1; i >= 0; i--) { + var mapping = userKeymap[i]; + if (ctx !== mapping.context) { + if (mapping.context) { + this._mapCommand(mapping); + } else { + var contexts = ['normal', 'insert', 'visual']; + for (var j in contexts) { + if (contexts[j] !== ctx) { + var newMapping = {}; + for (var key in mapping) { + newMapping[key] = mapping[key]; + } + newMapping.context = contexts[j]; + this._mapCommand(newMapping); + } + } + } + } + } + } + }, + setOption: setOption, + getOption: getOption, + defineOption: defineOption, + defineEx: function(name, prefix, func){ + if (!prefix) { + prefix = name; + } else if (name.indexOf(prefix) !== 0) { + throw new Error('(Vim.defineEx) "'+prefix+'" is not a prefix of "'+name+'", command not registered'); + } + exCommands[name]=func; + exCommandDispatcher.commandMap_[prefix]={name:name, shortName:prefix, type:'api'}; + }, + handleKey: function (cm, key, origin) { + var command = this.findKey(cm, key, origin); + if (typeof command === 'function') { + return command(); + } + }, + findKey: function(cm, key, origin) { + var vim = maybeInitVimState(cm); + function handleMacroRecording() { + var macroModeState = vimGlobalState.macroModeState; + if (macroModeState.isRecording) { + if (key == 'q') { + macroModeState.exitMacroRecordMode(); + clearInputState(cm); + return true; + } + if (origin != 'mapping') { + logKey(macroModeState, key); + } + } + } + function handleEsc() { + if (key == '') { + clearInputState(cm); + if (vim.visualMode) { + exitVisualMode(cm); + } else if (vim.insertMode) { + exitInsertMode(cm); + } + return true; + } + } + function doKeyToKey(keys) { + var match; + while (keys) { + match = (/<\w+-.+?>|<\w+>|./).exec(keys); + key = match[0]; + keys = keys.substring(match.index + key.length); + CodeMirror.Vim.handleKey(cm, key, 'mapping'); + } + } + + function handleKeyInsertMode() { + if (handleEsc()) { return true; } + var keys = vim.inputState.keyBuffer = vim.inputState.keyBuffer + key; + var keysAreChars = key.length == 1; + var match = commandDispatcher.matchCommand(keys, defaultKeymap, vim.inputState, 'insert'); + while (keys.length > 1 && match.type != 'full') { + var keys = vim.inputState.keyBuffer = keys.slice(1); + var thisMatch = commandDispatcher.matchCommand(keys, defaultKeymap, vim.inputState, 'insert'); + if (thisMatch.type != 'none') { match = thisMatch; } + } + if (match.type == 'none') { clearInputState(cm); return false; } + else if (match.type == 'partial') { + if (lastInsertModeKeyTimer) { window.clearTimeout(lastInsertModeKeyTimer); } + lastInsertModeKeyTimer = window.setTimeout( + function() { if (vim.insertMode && vim.inputState.keyBuffer) { clearInputState(cm); } }, + getOption('insertModeEscKeysTimeout')); + return !keysAreChars; + } + + if (lastInsertModeKeyTimer) { window.clearTimeout(lastInsertModeKeyTimer); } + if (keysAreChars) { + var selections = cm.listSelections(); + for (var i = 0; i < selections.length; i++) { + var here = selections[i].head; + cm.replaceRange('', offsetCursor(here, 0, -(keys.length - 1)), here, '+input'); + } + vimGlobalState.macroModeState.lastInsertModeChanges.changes.pop(); + } + clearInputState(cm); + return match.command; + } + + function handleKeyNonInsertMode() { + if (handleMacroRecording() || handleEsc()) { return true; } + + var keys = vim.inputState.keyBuffer = vim.inputState.keyBuffer + key; + if (/^[1-9]\d*$/.test(keys)) { return true; } + + var keysMatcher = /^(\d*)(.*)$/.exec(keys); + if (!keysMatcher) { clearInputState(cm); return false; } + var context = vim.visualMode ? 'visual' : + 'normal'; + var match = commandDispatcher.matchCommand(keysMatcher[2] || keysMatcher[1], defaultKeymap, vim.inputState, context); + if (match.type == 'none') { clearInputState(cm); return false; } + else if (match.type == 'partial') { return true; } + + vim.inputState.keyBuffer = ''; + var keysMatcher = /^(\d*)(.*)$/.exec(keys); + if (keysMatcher[1] && keysMatcher[1] != '0') { + vim.inputState.pushRepeatDigit(keysMatcher[1]); + } + return match.command; + } + + var command; + if (vim.insertMode) { command = handleKeyInsertMode(); } + else { command = handleKeyNonInsertMode(); } + if (command === false) { + return undefined; //ace_patch + } else if (command === true) { + return function() { return true; }; + } else { + return function() { + if ((command.operator || command.isEdit) && cm.getOption('readOnly')) + return; // ace_patch + return cm.operation(function() { + cm.curOp.isVimOp = true; + try { + if (command.type == 'keyToKey') { + doKeyToKey(command.toKeys); + } else { + commandDispatcher.processCommand(cm, vim, command); + } + } catch (e) { + cm.state.vim = undefined; + maybeInitVimState(cm); + if (!CodeMirror.Vim.suppressErrorLogging) { + console['log'](e); + } + throw e; + } + return true; + }); + }; + } + }, + handleEx: function(cm, input) { + exCommandDispatcher.processCommand(cm, input); + }, + + defineMotion: defineMotion, + defineAction: defineAction, + defineOperator: defineOperator, + mapCommand: mapCommand, + _mapCommand: _mapCommand, + + defineRegister: defineRegister, + + exitVisualMode: exitVisualMode, + exitInsertMode: exitInsertMode + }; + function InputState() { + this.prefixRepeat = []; + this.motionRepeat = []; + + this.operator = null; + this.operatorArgs = null; + this.motion = null; + this.motionArgs = null; + this.keyBuffer = []; // For matching multi-key commands. + this.registerName = null; // Defaults to the unnamed register. + } + InputState.prototype.pushRepeatDigit = function(n) { + if (!this.operator) { + this.prefixRepeat = this.prefixRepeat.concat(n); + } else { + this.motionRepeat = this.motionRepeat.concat(n); + } + }; + InputState.prototype.getRepeat = function() { + var repeat = 0; + if (this.prefixRepeat.length > 0 || this.motionRepeat.length > 0) { + repeat = 1; + if (this.prefixRepeat.length > 0) { + repeat *= parseInt(this.prefixRepeat.join(''), 10); + } + if (this.motionRepeat.length > 0) { + repeat *= parseInt(this.motionRepeat.join(''), 10); + } + } + return repeat; + }; + + function clearInputState(cm, reason) { + cm.state.vim.inputState = new InputState(); + CodeMirror.signal(cm, 'vim-command-done', reason); + } + function Register(text, linewise, blockwise) { + this.clear(); + this.keyBuffer = [text || '']; + this.insertModeChanges = []; + this.searchQueries = []; + this.linewise = !!linewise; + this.blockwise = !!blockwise; + } + Register.prototype = { + setText: function(text, linewise, blockwise) { + this.keyBuffer = [text || '']; + this.linewise = !!linewise; + this.blockwise = !!blockwise; + }, + pushText: function(text, linewise) { + if (linewise) { + if (!this.linewise) { + this.keyBuffer.push('\n'); + } + this.linewise = true; + } + this.keyBuffer.push(text); + }, + pushInsertModeChanges: function(changes) { + this.insertModeChanges.push(createInsertModeChanges(changes)); + }, + pushSearchQuery: function(query) { + this.searchQueries.push(query); + }, + clear: function() { + this.keyBuffer = []; + this.insertModeChanges = []; + this.searchQueries = []; + this.linewise = false; + }, + toString: function() { + return this.keyBuffer.join(''); + } + }; + function defineRegister(name, register) { + var registers = vimGlobalState.registerController.registers; + if (!name || name.length != 1) { + throw Error('Register name must be 1 character'); + } + registers[name] = register; + validRegisters.push(name); + } + function RegisterController(registers) { + this.registers = registers; + this.unnamedRegister = registers['"'] = new Register(); + registers['.'] = new Register(); + registers[':'] = new Register(); + registers['/'] = new Register(); + } + RegisterController.prototype = { + pushText: function(registerName, operator, text, linewise, blockwise) { + if (linewise && text.charAt(text.length - 1) !== '\n'){ + text += '\n'; + } + var register = this.isValidRegister(registerName) ? + this.getRegister(registerName) : null; + if (!register) { + switch (operator) { + case 'yank': + this.registers['0'] = new Register(text, linewise, blockwise); + break; + case 'delete': + case 'change': + if (text.indexOf('\n') == -1) { + this.registers['-'] = new Register(text, linewise); + } else { + this.shiftNumericRegisters_(); + this.registers['1'] = new Register(text, linewise); + } + break; + } + this.unnamedRegister.setText(text, linewise, blockwise); + return; + } + var append = isUpperCase(registerName); + if (append) { + register.pushText(text, linewise); + } else { + register.setText(text, linewise, blockwise); + } + this.unnamedRegister.setText(register.toString(), linewise); + }, + getRegister: function(name) { + if (!this.isValidRegister(name)) { + return this.unnamedRegister; + } + name = name.toLowerCase(); + if (!this.registers[name]) { + this.registers[name] = new Register(); + } + return this.registers[name]; + }, + isValidRegister: function(name) { + return name && inArray(name, validRegisters); + }, + shiftNumericRegisters_: function() { + for (var i = 9; i >= 2; i--) { + this.registers[i] = this.getRegister('' + (i - 1)); + } + } + }; + function HistoryController() { + this.historyBuffer = []; + this.iterator = 0; + this.initialPrefix = null; + } + HistoryController.prototype = { + nextMatch: function (input, up) { + var historyBuffer = this.historyBuffer; + var dir = up ? -1 : 1; + if (this.initialPrefix === null) this.initialPrefix = input; + for (var i = this.iterator + dir; up ? i >= 0 : i < historyBuffer.length; i+= dir) { + var element = historyBuffer[i]; + for (var j = 0; j <= element.length; j++) { + if (this.initialPrefix == element.substring(0, j)) { + this.iterator = i; + return element; + } + } + } + if (i >= historyBuffer.length) { + this.iterator = historyBuffer.length; + return this.initialPrefix; + } + if (i < 0 ) return input; + }, + pushInput: function(input) { + var index = this.historyBuffer.indexOf(input); + if (index > -1) this.historyBuffer.splice(index, 1); + if (input.length) this.historyBuffer.push(input); + }, + reset: function() { + this.initialPrefix = null; + this.iterator = this.historyBuffer.length; + } + }; + var commandDispatcher = { + matchCommand: function(keys, keyMap, inputState, context) { + var matches = commandMatches(keys, keyMap, context, inputState); + if (!matches.full && !matches.partial) { + return {type: 'none'}; + } else if (!matches.full && matches.partial) { + return {type: 'partial'}; + } + + var bestMatch; + for (var i = 0; i < matches.full.length; i++) { + var match = matches.full[i]; + if (!bestMatch) { + bestMatch = match; + } + } + if (bestMatch.keys.slice(-11) == '') { + var character = lastChar(keys); + if (//.test(character) || !character) return {type: 'none'}; //ace_patch + inputState.selectedCharacter = character; + } + return {type: 'full', command: bestMatch}; + }, + processCommand: function(cm, vim, command) { + vim.inputState.repeatOverride = command.repeatOverride; + switch (command.type) { + case 'motion': + this.processMotion(cm, vim, command); + break; + case 'operator': + this.processOperator(cm, vim, command); + break; + case 'operatorMotion': + this.processOperatorMotion(cm, vim, command); + break; + case 'action': + this.processAction(cm, vim, command); + break; + case 'search': + this.processSearch(cm, vim, command); + break; + case 'ex': + case 'keyToEx': + this.processEx(cm, vim, command); + break; + default: + break; + } + }, + processMotion: function(cm, vim, command) { + vim.inputState.motion = command.motion; + vim.inputState.motionArgs = copyArgs(command.motionArgs); + this.evalInput(cm, vim); + }, + processOperator: function(cm, vim, command) { + var inputState = vim.inputState; + if (inputState.operator) { + if (inputState.operator == command.operator) { + inputState.motion = 'expandToLine'; + inputState.motionArgs = { linewise: true }; + this.evalInput(cm, vim); + return; + } else { + clearInputState(cm); + } + } + inputState.operator = command.operator; + inputState.operatorArgs = copyArgs(command.operatorArgs); + if (command.exitVisualBlock) { + vim.visualBlock = false; + updateCmSelection(cm); + } + if (vim.visualMode) { + this.evalInput(cm, vim); + } + }, + processOperatorMotion: function(cm, vim, command) { + var visualMode = vim.visualMode; + var operatorMotionArgs = copyArgs(command.operatorMotionArgs); + if (operatorMotionArgs) { + if (visualMode && operatorMotionArgs.visualLine) { + vim.visualLine = true; + } + } + this.processOperator(cm, vim, command); + if (!visualMode) { + this.processMotion(cm, vim, command); + } + }, + processAction: function(cm, vim, command) { + var inputState = vim.inputState; + var repeat = inputState.getRepeat(); + var repeatIsExplicit = !!repeat; + var actionArgs = copyArgs(command.actionArgs) || {}; + if (inputState.selectedCharacter) { + actionArgs.selectedCharacter = inputState.selectedCharacter; + } + if (command.operator) { + this.processOperator(cm, vim, command); + } + if (command.motion) { + this.processMotion(cm, vim, command); + } + if (command.motion || command.operator) { + this.evalInput(cm, vim); + } + actionArgs.repeat = repeat || 1; + actionArgs.repeatIsExplicit = repeatIsExplicit; + actionArgs.registerName = inputState.registerName; + clearInputState(cm); + vim.lastMotion = null; + if (command.isEdit) { + this.recordLastEdit(vim, inputState, command); + } + actions[command.action](cm, actionArgs, vim); + }, + processSearch: function(cm, vim, command) { + if (!cm.getSearchCursor) { + return; + } + var forward = command.searchArgs.forward; + var wholeWordOnly = command.searchArgs.wholeWordOnly; + getSearchState(cm).setReversed(!forward); + var promptPrefix = (forward) ? '/' : '?'; + var originalQuery = getSearchState(cm).getQuery(); + var originalScrollPos = cm.getScrollInfo(); + function handleQuery(query, ignoreCase, smartCase) { + vimGlobalState.searchHistoryController.pushInput(query); + vimGlobalState.searchHistoryController.reset(); + try { + updateSearchQuery(cm, query, ignoreCase, smartCase); + } catch (e) { + showConfirm(cm, 'Invalid regex: ' + query); + clearInputState(cm); + return; + } + commandDispatcher.processMotion(cm, vim, { + type: 'motion', + motion: 'findNext', + motionArgs: { forward: true, toJumplist: command.searchArgs.toJumplist } + }); + } + function onPromptClose(query) { + handleQuery(query, true /** ignoreCase */, true /** smartCase */); + var macroModeState = vimGlobalState.macroModeState; + if (macroModeState.isRecording) { + logSearchQuery(macroModeState, query); + } + } + function onPromptKeyUp(e, query, close) { + var keyName = CodeMirror.keyName(e), up, offset; + if (keyName == 'Up' || keyName == 'Down') { + up = keyName == 'Up' ? true : false; + offset = e.target ? e.target.selectionEnd : 0; + query = vimGlobalState.searchHistoryController.nextMatch(query, up) || ''; + close(query); + if (offset && e.target) e.target.selectionEnd = e.target.selectionStart = Math.min(offset, e.target.value.length); + } else { + if ( keyName != 'Left' && keyName != 'Right' && keyName != 'Ctrl' && keyName != 'Alt' && keyName != 'Shift') + vimGlobalState.searchHistoryController.reset(); + } + var parsedQuery; + try { + parsedQuery = updateSearchQuery(cm, query, + true /** ignoreCase */, true /** smartCase */); + } catch (e) { + } + if (parsedQuery) { + cm.scrollIntoView(findNext(cm, !forward, parsedQuery), 30); + } else { + clearSearchHighlight(cm); + cm.scrollTo(originalScrollPos.left, originalScrollPos.top); + } + } + function onPromptKeyDown(e, query, close) { + var keyName = CodeMirror.keyName(e); + if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[' || + (keyName == 'Backspace' && query == '')) { + vimGlobalState.searchHistoryController.pushInput(query); + vimGlobalState.searchHistoryController.reset(); + updateSearchQuery(cm, originalQuery); + clearSearchHighlight(cm); + cm.scrollTo(originalScrollPos.left, originalScrollPos.top); + CodeMirror.e_stop(e); + clearInputState(cm); + close(); + cm.focus(); + } else if (keyName == 'Up' || keyName == 'Down') { + CodeMirror.e_stop(e); + } else if (keyName == 'Ctrl-U') { + CodeMirror.e_stop(e); + close(''); + } + } + switch (command.searchArgs.querySrc) { + case 'prompt': + var macroModeState = vimGlobalState.macroModeState; + if (macroModeState.isPlaying) { + var query = macroModeState.replaySearchQueries.shift(); + handleQuery(query, true /** ignoreCase */, false /** smartCase */); + } else { + showPrompt(cm, { + onClose: onPromptClose, + prefix: promptPrefix, + desc: searchPromptDesc, + onKeyUp: onPromptKeyUp, + onKeyDown: onPromptKeyDown + }); + } + break; + case 'wordUnderCursor': + var word = expandWordUnderCursor(cm, false /** inclusive */, + true /** forward */, false /** bigWord */, + true /** noSymbol */); + var isKeyword = true; + if (!word) { + word = expandWordUnderCursor(cm, false /** inclusive */, + true /** forward */, false /** bigWord */, + false /** noSymbol */); + isKeyword = false; + } + if (!word) { + return; + } + var query = cm.getLine(word.start.line).substring(word.start.ch, + word.end.ch); + if (isKeyword && wholeWordOnly) { + query = '\\b' + query + '\\b'; + } else { + query = escapeRegex(query); + } + vimGlobalState.jumpList.cachedCursor = cm.getCursor(); + cm.setCursor(word.start); + + handleQuery(query, true /** ignoreCase */, false /** smartCase */); + break; + } + }, + processEx: function(cm, vim, command) { + function onPromptClose(input) { + vimGlobalState.exCommandHistoryController.pushInput(input); + vimGlobalState.exCommandHistoryController.reset(); + exCommandDispatcher.processCommand(cm, input); + } + function onPromptKeyDown(e, input, close) { + var keyName = CodeMirror.keyName(e), up, offset; + if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[' || + (keyName == 'Backspace' && input == '')) { + vimGlobalState.exCommandHistoryController.pushInput(input); + vimGlobalState.exCommandHistoryController.reset(); + CodeMirror.e_stop(e); + clearInputState(cm); + close(); + cm.focus(); + } + if (keyName == 'Up' || keyName == 'Down') { + CodeMirror.e_stop(e); + up = keyName == 'Up' ? true : false; + offset = e.target ? e.target.selectionEnd : 0; + input = vimGlobalState.exCommandHistoryController.nextMatch(input, up) || ''; + close(input); + if (offset && e.target) e.target.selectionEnd = e.target.selectionStart = Math.min(offset, e.target.value.length); + } else if (keyName == 'Ctrl-U') { + CodeMirror.e_stop(e); + close(''); + } else { + if ( keyName != 'Left' && keyName != 'Right' && keyName != 'Ctrl' && keyName != 'Alt' && keyName != 'Shift') + vimGlobalState.exCommandHistoryController.reset(); + } + } + if (command.type == 'keyToEx') { + exCommandDispatcher.processCommand(cm, command.exArgs.input); + } else { + if (vim.visualMode) { + showPrompt(cm, { onClose: onPromptClose, prefix: ':', value: '\'<,\'>', + onKeyDown: onPromptKeyDown, selectValueOnOpen: false}); + } else { + showPrompt(cm, { onClose: onPromptClose, prefix: ':', + onKeyDown: onPromptKeyDown}); + } + } + }, + evalInput: function(cm, vim) { + var inputState = vim.inputState; + var motion = inputState.motion; + var motionArgs = inputState.motionArgs || {}; + var operator = inputState.operator; + var operatorArgs = inputState.operatorArgs || {}; + var registerName = inputState.registerName; + var sel = vim.sel; + var origHead = copyCursor(vim.visualMode ? clipCursorToContent(cm, sel.head): cm.getCursor('head')); + var origAnchor = copyCursor(vim.visualMode ? clipCursorToContent(cm, sel.anchor) : cm.getCursor('anchor')); + var oldHead = copyCursor(origHead); + var oldAnchor = copyCursor(origAnchor); + var newHead, newAnchor; + var repeat; + if (operator) { + this.recordLastEdit(vim, inputState); + } + if (inputState.repeatOverride !== undefined) { + repeat = inputState.repeatOverride; + } else { + repeat = inputState.getRepeat(); + } + if (repeat > 0 && motionArgs.explicitRepeat) { + motionArgs.repeatIsExplicit = true; + } else if (motionArgs.noRepeat || + (!motionArgs.explicitRepeat && repeat === 0)) { + repeat = 1; + motionArgs.repeatIsExplicit = false; + } + if (inputState.selectedCharacter) { + motionArgs.selectedCharacter = operatorArgs.selectedCharacter = + inputState.selectedCharacter; + } + motionArgs.repeat = repeat; + clearInputState(cm); + if (motion) { + var motionResult = motions[motion](cm, origHead, motionArgs, vim); + vim.lastMotion = motions[motion]; + if (!motionResult) { + return; + } + if (motionArgs.toJumplist) { + if (!operator && cm.ace.curOp != null) + cm.ace.curOp.command.scrollIntoView = "center-animate"; // ace_patch + var jumpList = vimGlobalState.jumpList; + var cachedCursor = jumpList.cachedCursor; + if (cachedCursor) { + recordJumpPosition(cm, cachedCursor, motionResult); + delete jumpList.cachedCursor; + } else { + recordJumpPosition(cm, origHead, motionResult); + } + } + if (motionResult instanceof Array) { + newAnchor = motionResult[0]; + newHead = motionResult[1]; + } else { + newHead = motionResult; + } + if (!newHead) { + newHead = copyCursor(origHead); + } + if (vim.visualMode) { + if (!(vim.visualBlock && newHead.ch === Infinity)) { + newHead = clipCursorToContent(cm, newHead, vim.visualBlock); + } + if (newAnchor) { + newAnchor = clipCursorToContent(cm, newAnchor, true); + } + newAnchor = newAnchor || oldAnchor; + sel.anchor = newAnchor; + sel.head = newHead; + updateCmSelection(cm); + updateMark(cm, vim, '<', + cursorIsBefore(newAnchor, newHead) ? newAnchor + : newHead); + updateMark(cm, vim, '>', + cursorIsBefore(newAnchor, newHead) ? newHead + : newAnchor); + } else if (!operator) { + newHead = clipCursorToContent(cm, newHead); + cm.setCursor(newHead.line, newHead.ch); + } + } + if (operator) { + if (operatorArgs.lastSel) { + newAnchor = oldAnchor; + var lastSel = operatorArgs.lastSel; + var lineOffset = Math.abs(lastSel.head.line - lastSel.anchor.line); + var chOffset = Math.abs(lastSel.head.ch - lastSel.anchor.ch); + if (lastSel.visualLine) { + newHead = Pos(oldAnchor.line + lineOffset, oldAnchor.ch); + } else if (lastSel.visualBlock) { + newHead = Pos(oldAnchor.line + lineOffset, oldAnchor.ch + chOffset); + } else if (lastSel.head.line == lastSel.anchor.line) { + newHead = Pos(oldAnchor.line, oldAnchor.ch + chOffset); + } else { + newHead = Pos(oldAnchor.line + lineOffset, oldAnchor.ch); + } + vim.visualMode = true; + vim.visualLine = lastSel.visualLine; + vim.visualBlock = lastSel.visualBlock; + sel = vim.sel = { + anchor: newAnchor, + head: newHead + }; + updateCmSelection(cm); + } else if (vim.visualMode) { + operatorArgs.lastSel = { + anchor: copyCursor(sel.anchor), + head: copyCursor(sel.head), + visualBlock: vim.visualBlock, + visualLine: vim.visualLine + }; + } + var curStart, curEnd, linewise, mode; + var cmSel; + if (vim.visualMode) { + curStart = cursorMin(sel.head, sel.anchor); + curEnd = cursorMax(sel.head, sel.anchor); + linewise = vim.visualLine || operatorArgs.linewise; + mode = vim.visualBlock ? 'block' : + linewise ? 'line' : + 'char'; + cmSel = makeCmSelection(cm, { + anchor: curStart, + head: curEnd + }, mode); + if (linewise) { + var ranges = cmSel.ranges; + if (mode == 'block') { + for (var i = 0; i < ranges.length; i++) { + ranges[i].head.ch = lineLength(cm, ranges[i].head.line); + } + } else if (mode == 'line') { + ranges[0].head = Pos(ranges[0].head.line + 1, 0); + } + } + } else { + curStart = copyCursor(newAnchor || oldAnchor); + curEnd = copyCursor(newHead || oldHead); + if (cursorIsBefore(curEnd, curStart)) { + var tmp = curStart; + curStart = curEnd; + curEnd = tmp; + } + linewise = motionArgs.linewise || operatorArgs.linewise; + if (linewise) { + expandSelectionToLine(cm, curStart, curEnd); + } else if (motionArgs.forward) { + clipToLine(cm, curStart, curEnd); + } + mode = 'char'; + var exclusive = !motionArgs.inclusive || linewise; + cmSel = makeCmSelection(cm, { + anchor: curStart, + head: curEnd + }, mode, exclusive); + } + cm.setSelections(cmSel.ranges, cmSel.primary); + vim.lastMotion = null; + operatorArgs.repeat = repeat; // For indent in visual mode. + operatorArgs.registerName = registerName; + operatorArgs.linewise = linewise; + var operatorMoveTo = operators[operator]( + cm, operatorArgs, cmSel.ranges, oldAnchor, newHead); + if (vim.visualMode) { + exitVisualMode(cm, operatorMoveTo != null); + } + if (operatorMoveTo) { + cm.setCursor(operatorMoveTo); + } + } + }, + recordLastEdit: function(vim, inputState, actionCommand) { + var macroModeState = vimGlobalState.macroModeState; + if (macroModeState.isPlaying) { return; } + vim.lastEditInputState = inputState; + vim.lastEditActionCommand = actionCommand; + macroModeState.lastInsertModeChanges.changes = []; + macroModeState.lastInsertModeChanges.expectCursorActivityForChange = false; + macroModeState.lastInsertModeChanges.visualBlock = vim.visualBlock ? vim.sel.head.line - vim.sel.anchor.line : 0; + } + }; + var motions = { + moveToTopLine: function(cm, _head, motionArgs) { + var line = getUserVisibleLines(cm).top + motionArgs.repeat -1; + return Pos(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line))); + }, + moveToMiddleLine: function(cm) { + var range = getUserVisibleLines(cm); + var line = Math.floor((range.top + range.bottom) * 0.5); + return Pos(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line))); + }, + moveToBottomLine: function(cm, _head, motionArgs) { + var line = getUserVisibleLines(cm).bottom - motionArgs.repeat +1; + return Pos(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line))); + }, + expandToLine: function(_cm, head, motionArgs) { + var cur = head; + return Pos(cur.line + motionArgs.repeat - 1, Infinity); + }, + findNext: function(cm, _head, motionArgs) { + var state = getSearchState(cm); + var query = state.getQuery(); + if (!query) { + return; + } + var prev = !motionArgs.forward; + prev = (state.isReversed()) ? !prev : prev; + highlightSearchMatches(cm, query); + return findNext(cm, prev/** prev */, query, motionArgs.repeat); + }, + goToMark: function(cm, _head, motionArgs, vim) { + var pos = getMarkPos(cm, vim, motionArgs.selectedCharacter); + if (pos) { + return motionArgs.linewise ? { line: pos.line, ch: findFirstNonWhiteSpaceCharacter(cm.getLine(pos.line)) } : pos; + } + return null; + }, + moveToOtherHighlightedEnd: function(cm, _head, motionArgs, vim) { + if (vim.visualBlock && motionArgs.sameLine) { + var sel = vim.sel; + return [ + clipCursorToContent(cm, Pos(sel.anchor.line, sel.head.ch)), + clipCursorToContent(cm, Pos(sel.head.line, sel.anchor.ch)) + ]; + } else { + return ([vim.sel.head, vim.sel.anchor]); + } + }, + jumpToMark: function(cm, head, motionArgs, vim) { + var best = head; + for (var i = 0; i < motionArgs.repeat; i++) { + var cursor = best; + for (var key in vim.marks) { + if (!isLowerCase(key)) { + continue; + } + var mark = vim.marks[key].find(); + var isWrongDirection = (motionArgs.forward) ? + cursorIsBefore(mark, cursor) : cursorIsBefore(cursor, mark); + + if (isWrongDirection) { + continue; + } + if (motionArgs.linewise && (mark.line == cursor.line)) { + continue; + } + + var equal = cursorEqual(cursor, best); + var between = (motionArgs.forward) ? + cursorIsBetween(cursor, mark, best) : + cursorIsBetween(best, mark, cursor); + + if (equal || between) { + best = mark; + } + } + } + + if (motionArgs.linewise) { + best = Pos(best.line, findFirstNonWhiteSpaceCharacter(cm.getLine(best.line))); + } + return best; + }, + moveByCharacters: function(_cm, head, motionArgs) { + var cur = head; + var repeat = motionArgs.repeat; + var ch = motionArgs.forward ? cur.ch + repeat : cur.ch - repeat; + return Pos(cur.line, ch); + }, + moveByLines: function(cm, head, motionArgs, vim) { + var cur = head; + var endCh = cur.ch; + switch (vim.lastMotion) { + case this.moveByLines: + case this.moveByDisplayLines: + case this.moveByScroll: + case this.moveToColumn: + case this.moveToEol: + endCh = vim.lastHPos; + break; + default: + vim.lastHPos = endCh; + } + var repeat = motionArgs.repeat+(motionArgs.repeatOffset||0); + var line = motionArgs.forward ? cur.line + repeat : cur.line - repeat; + var first = cm.firstLine(); + var last = cm.lastLine(); + if (line < first && cur.line == first){ + return this.moveToStartOfLine(cm, head, motionArgs, vim); + }else if (line > last && cur.line == last){ + return this.moveToEol(cm, head, motionArgs, vim, true); + } + var fold = cm.ace.session.getFoldLine(line); + if (fold) { + if (motionArgs.forward) { + if (line > fold.start.row) + line = fold.end.row + 1; + } else { + line = fold.start.row; + } + } + if (motionArgs.toFirstChar){ + endCh=findFirstNonWhiteSpaceCharacter(cm.getLine(line)); + vim.lastHPos = endCh; + } + vim.lastHSPos = cm.charCoords(Pos(line, endCh),'div').left; + return Pos(line, endCh); + }, + moveByDisplayLines: function(cm, head, motionArgs, vim) { + var cur = head; + switch (vim.lastMotion) { + case this.moveByDisplayLines: + case this.moveByScroll: + case this.moveByLines: + case this.moveToColumn: + case this.moveToEol: + break; + default: + vim.lastHSPos = cm.charCoords(cur,'div').left; + } + var repeat = motionArgs.repeat; + var res=cm.findPosV(cur,(motionArgs.forward ? repeat : -repeat),'line',vim.lastHSPos); + if (res.hitSide) { + if (motionArgs.forward) { + var lastCharCoords = cm.charCoords(res, 'div'); + var goalCoords = { top: lastCharCoords.top + 8, left: vim.lastHSPos }; + var res = cm.coordsChar(goalCoords, 'div'); + } else { + var resCoords = cm.charCoords(Pos(cm.firstLine(), 0), 'div'); + resCoords.left = vim.lastHSPos; + res = cm.coordsChar(resCoords, 'div'); + } + } + vim.lastHPos = res.ch; + return res; + }, + moveByPage: function(cm, head, motionArgs) { + var curStart = head; + var repeat = motionArgs.repeat; + return cm.findPosV(curStart, (motionArgs.forward ? repeat : -repeat), 'page'); + }, + moveByParagraph: function(cm, head, motionArgs) { + var dir = motionArgs.forward ? 1 : -1; + return findParagraph(cm, head, motionArgs.repeat, dir); + }, + moveBySentence: function(cm, head, motionArgs) { + var dir = motionArgs.forward ? 1 : -1; + return findSentence(cm, head, motionArgs.repeat, dir); + }, + moveByScroll: function(cm, head, motionArgs, vim) { + var scrollbox = cm.getScrollInfo(); + var curEnd = null; + var repeat = motionArgs.repeat; + if (!repeat) { + repeat = scrollbox.clientHeight / (2 * cm.defaultTextHeight()); + } + var orig = cm.charCoords(head, 'local'); + motionArgs.repeat = repeat; + var curEnd = motions.moveByDisplayLines(cm, head, motionArgs, vim); + if (!curEnd) { + return null; + } + var dest = cm.charCoords(curEnd, 'local'); + cm.scrollTo(null, scrollbox.top + dest.top - orig.top); + return curEnd; + }, + moveByWords: function(cm, head, motionArgs) { + return moveToWord(cm, head, motionArgs.repeat, !!motionArgs.forward, + !!motionArgs.wordEnd, !!motionArgs.bigWord); + }, + moveTillCharacter: function(cm, _head, motionArgs) { + var repeat = motionArgs.repeat; + var curEnd = moveToCharacter(cm, repeat, motionArgs.forward, + motionArgs.selectedCharacter); + var increment = motionArgs.forward ? -1 : 1; + recordLastCharacterSearch(increment, motionArgs); + if (!curEnd) return null; + curEnd.ch += increment; + return curEnd; + }, + moveToCharacter: function(cm, head, motionArgs) { + var repeat = motionArgs.repeat; + recordLastCharacterSearch(0, motionArgs); + return moveToCharacter(cm, repeat, motionArgs.forward, + motionArgs.selectedCharacter) || head; + }, + moveToSymbol: function(cm, head, motionArgs) { + var repeat = motionArgs.repeat; + return findSymbol(cm, repeat, motionArgs.forward, + motionArgs.selectedCharacter) || head; + }, + moveToColumn: function(cm, head, motionArgs, vim) { + var repeat = motionArgs.repeat; + vim.lastHPos = repeat - 1; + vim.lastHSPos = cm.charCoords(head,'div').left; + return moveToColumn(cm, repeat); + }, + moveToEol: function(cm, head, motionArgs, vim, keepHPos) { + var cur = head; + var retval= Pos(cur.line + motionArgs.repeat - 1, Infinity); + var end=cm.clipPos(retval); + end.ch--; + if (!keepHPos) { + vim.lastHPos = Infinity; + vim.lastHSPos = cm.charCoords(end,'div').left; + } + return retval; + }, + moveToFirstNonWhiteSpaceCharacter: function(cm, head) { + var cursor = head; + return Pos(cursor.line, + findFirstNonWhiteSpaceCharacter(cm.getLine(cursor.line))); + }, + moveToMatchedSymbol: function(cm, head) { + var cursor = head; + var line = cursor.line; + var ch = cursor.ch; + var lineText = cm.getLine(line); + var symbol; + for (; ch < lineText.length; ch++) { + symbol = lineText.charAt(ch); + if (symbol && isMatchableSymbol(symbol)) { + var style = cm.getTokenTypeAt(Pos(line, ch + 1)); + if (style !== "string" && style !== "comment") { + break; + } + } + } + if (ch < lineText.length) { + var re = /[<>]/.test(lineText[ch]) ? /[(){}[\]<>]/ : /[(){}[\]]/; + var matched = cm.findMatchingBracket(Pos(line, ch+1), {bracketRegex: re}); + return matched.to; + } else { + return cursor; + } + }, + moveToStartOfLine: function(_cm, head) { + return Pos(head.line, 0); + }, + moveToLineOrEdgeOfDocument: function(cm, _head, motionArgs) { + var lineNum = motionArgs.forward ? cm.lastLine() : cm.firstLine(); + if (motionArgs.repeatIsExplicit) { + lineNum = motionArgs.repeat - cm.getOption('firstLineNumber'); + } + return Pos(lineNum, + findFirstNonWhiteSpaceCharacter(cm.getLine(lineNum))); + }, + textObjectManipulation: function(cm, head, motionArgs, vim) { + var mirroredPairs = {'(': ')', ')': '(', + '{': '}', '}': '{', + '[': ']', ']': '[', + '<': '>', '>': '<'}; + var selfPaired = {'\'': true, '"': true, '`': true}; + + var character = motionArgs.selectedCharacter; + if (character == 'b') { + character = '('; + } else if (character == 'B') { + character = '{'; + } + var inclusive = !motionArgs.textObjectInner; + + var tmp; + if (mirroredPairs[character]) { + tmp = selectCompanionObject(cm, head, character, inclusive); + } else if (selfPaired[character]) { + tmp = findBeginningAndEnd(cm, head, character, inclusive); + } else if (character === 'W') { + tmp = expandWordUnderCursor(cm, inclusive, true /** forward */, + true /** bigWord */); + } else if (character === 'w') { + tmp = expandWordUnderCursor(cm, inclusive, true /** forward */, + false /** bigWord */); + } else if (character === 'p') { + tmp = findParagraph(cm, head, motionArgs.repeat, 0, inclusive); + motionArgs.linewise = true; + if (vim.visualMode) { + if (!vim.visualLine) { vim.visualLine = true; } + } else { + var operatorArgs = vim.inputState.operatorArgs; + if (operatorArgs) { operatorArgs.linewise = true; } + tmp.end.line--; + } + } else { + return null; + } + + if (!cm.state.vim.visualMode) { + return [tmp.start, tmp.end]; + } else { + return expandSelection(cm, tmp.start, tmp.end); + } + }, + + repeatLastCharacterSearch: function(cm, head, motionArgs) { + var lastSearch = vimGlobalState.lastCharacterSearch; + var repeat = motionArgs.repeat; + var forward = motionArgs.forward === lastSearch.forward; + var increment = (lastSearch.increment ? 1 : 0) * (forward ? -1 : 1); + cm.moveH(-increment, 'char'); + motionArgs.inclusive = forward ? true : false; + var curEnd = moveToCharacter(cm, repeat, forward, lastSearch.selectedCharacter); + if (!curEnd) { + cm.moveH(increment, 'char'); + return head; + } + curEnd.ch += increment; + return curEnd; + } + }; + + function defineMotion(name, fn) { + motions[name] = fn; + } + + function fillArray(val, times) { + var arr = []; + for (var i = 0; i < times; i++) { + arr.push(val); + } + return arr; + } + var operators = { + change: function(cm, args, ranges) { + var finalHead, text; + var vim = cm.state.vim; + var anchor = ranges[0].anchor, + head = ranges[0].head; + if (!vim.visualMode) { + text = cm.getRange(anchor, head); + var lastState = vim.lastEditInputState || {}; + if (lastState.motion == "moveByWords" && !isWhiteSpaceString(text)) { + var match = (/\s+$/).exec(text); + if (match && lastState.motionArgs && lastState.motionArgs.forward) { + head = offsetCursor(head, 0, - match[0].length); + text = text.slice(0, - match[0].length); + } + } + var prevLineEnd = new Pos(anchor.line - 1, Number.MAX_VALUE); + var wasLastLine = cm.firstLine() == cm.lastLine(); + if (head.line > cm.lastLine() && args.linewise && !wasLastLine) { + cm.replaceRange('', prevLineEnd, head); + } else { + cm.replaceRange('', anchor, head); + } + if (args.linewise) { + if (!wasLastLine) { + cm.setCursor(prevLineEnd); + CodeMirror.commands.newlineAndIndent(cm); + } + anchor.ch = Number.MAX_VALUE; + } + finalHead = anchor; + } else if (args.fullLine) { + head.ch = Number.MAX_VALUE; + head.line--; + cm.setSelection(anchor, head) + text = cm.getSelection(); + cm.replaceSelections(""); + finalHead = anchor + } else { + text = cm.getSelection(); + var replacement = fillArray('', ranges.length); + cm.replaceSelections(replacement); + finalHead = cursorMin(ranges[0].head, ranges[0].anchor); + } + vimGlobalState.registerController.pushText( + args.registerName, 'change', text, + args.linewise, ranges.length > 1); + actions.enterInsertMode(cm, {head: finalHead}, cm.state.vim); + }, + 'delete': function(cm, args, ranges) { + var finalHead, text; + var vim = cm.state.vim; + if (!vim.visualBlock) { + var anchor = ranges[0].anchor, + head = ranges[0].head; + if (args.linewise && + head.line != cm.firstLine() && + anchor.line == cm.lastLine() && + anchor.line == head.line - 1) { + if (anchor.line == cm.firstLine()) { + anchor.ch = 0; + } else { + anchor = Pos(anchor.line - 1, lineLength(cm, anchor.line - 1)); + } + } + text = cm.getRange(anchor, head); + cm.replaceRange('', anchor, head); + finalHead = anchor; + if (args.linewise) { + finalHead = motions.moveToFirstNonWhiteSpaceCharacter(cm, anchor); + } + } else { + text = cm.getSelection(); + var replacement = fillArray('', ranges.length); + cm.replaceSelections(replacement); + finalHead = ranges[0].anchor; + } + vimGlobalState.registerController.pushText( + args.registerName, 'delete', text, + args.linewise, vim.visualBlock); + var includeLineBreak = vim.insertMode + return clipCursorToContent(cm, finalHead, includeLineBreak); + }, + indent: function(cm, args, ranges) { + var vim = cm.state.vim; + var startLine = ranges[0].anchor.line; + var endLine = vim.visualBlock ? + ranges[ranges.length - 1].anchor.line : + ranges[0].head.line; + var repeat = (vim.visualMode) ? args.repeat : 1; + if (args.linewise) { + endLine--; + } + for (var i = startLine; i <= endLine; i++) { + for (var j = 0; j < repeat; j++) { + cm.indentLine(i, args.indentRight); + } + } + return motions.moveToFirstNonWhiteSpaceCharacter(cm, ranges[0].anchor); + }, + indentAuto: function(cm, _args, ranges) { + cm.execCommand("indentAuto"); + return motions.moveToFirstNonWhiteSpaceCharacter(cm, ranges[0].anchor); + }, + changeCase: function(cm, args, ranges, oldAnchor, newHead) { + var selections = cm.getSelections(); + var swapped = []; + var toLower = args.toLower; + for (var j = 0; j < selections.length; j++) { + var toSwap = selections[j]; + var text = ''; + if (toLower === true) { + text = toSwap.toLowerCase(); + } else if (toLower === false) { + text = toSwap.toUpperCase(); + } else { + for (var i = 0; i < toSwap.length; i++) { + var character = toSwap.charAt(i); + text += isUpperCase(character) ? character.toLowerCase() : + character.toUpperCase(); + } + } + swapped.push(text); + } + cm.replaceSelections(swapped); + if (args.shouldMoveCursor){ + return newHead; + } else if (!cm.state.vim.visualMode && args.linewise && ranges[0].anchor.line + 1 == ranges[0].head.line) { + return motions.moveToFirstNonWhiteSpaceCharacter(cm, oldAnchor); + } else if (args.linewise){ + return oldAnchor; + } else { + return cursorMin(ranges[0].anchor, ranges[0].head); + } + }, + yank: function(cm, args, ranges, oldAnchor) { + var vim = cm.state.vim; + var text = cm.getSelection(); + var endPos = vim.visualMode + ? cursorMin(vim.sel.anchor, vim.sel.head, ranges[0].head, ranges[0].anchor) + : oldAnchor; + vimGlobalState.registerController.pushText( + args.registerName, 'yank', + text, args.linewise, vim.visualBlock); + return endPos; + } + }; + + function defineOperator(name, fn) { + operators[name] = fn; + } + + var actions = { + jumpListWalk: function(cm, actionArgs, vim) { + if (vim.visualMode) { + return; + } + var repeat = actionArgs.repeat; + var forward = actionArgs.forward; + var jumpList = vimGlobalState.jumpList; + + var mark = jumpList.move(cm, forward ? repeat : -repeat); + var markPos = mark ? mark.find() : undefined; + markPos = markPos ? markPos : cm.getCursor(); + cm.setCursor(markPos); + cm.ace.curOp.command.scrollIntoView = "center-animate"; // ace_patch + }, + scroll: function(cm, actionArgs, vim) { + if (vim.visualMode) { + return; + } + var repeat = actionArgs.repeat || 1; + var lineHeight = cm.defaultTextHeight(); + var top = cm.getScrollInfo().top; + var delta = lineHeight * repeat; + var newPos = actionArgs.forward ? top + delta : top - delta; + var cursor = copyCursor(cm.getCursor()); + var cursorCoords = cm.charCoords(cursor, 'local'); + if (actionArgs.forward) { + if (newPos > cursorCoords.top) { + cursor.line += (newPos - cursorCoords.top) / lineHeight; + cursor.line = Math.ceil(cursor.line); + cm.setCursor(cursor); + cursorCoords = cm.charCoords(cursor, 'local'); + cm.scrollTo(null, cursorCoords.top); + } else { + cm.scrollTo(null, newPos); + } + } else { + var newBottom = newPos + cm.getScrollInfo().clientHeight; + if (newBottom < cursorCoords.bottom) { + cursor.line -= (cursorCoords.bottom - newBottom) / lineHeight; + cursor.line = Math.floor(cursor.line); + cm.setCursor(cursor); + cursorCoords = cm.charCoords(cursor, 'local'); + cm.scrollTo( + null, cursorCoords.bottom - cm.getScrollInfo().clientHeight); + } else { + cm.scrollTo(null, newPos); + } + } + }, + scrollToCursor: function(cm, actionArgs) { + var lineNum = cm.getCursor().line; + var charCoords = cm.charCoords(Pos(lineNum, 0), 'local'); + var height = cm.getScrollInfo().clientHeight; + var y = charCoords.top; + var lineHeight = charCoords.bottom - y; + switch (actionArgs.position) { + case 'center': y = y - (height / 2) + lineHeight; + break; + case 'bottom': y = y - height + lineHeight; + break; + } + cm.scrollTo(null, y); + }, + replayMacro: function(cm, actionArgs, vim) { + var registerName = actionArgs.selectedCharacter; + var repeat = actionArgs.repeat; + var macroModeState = vimGlobalState.macroModeState; + if (registerName == '@') { + registerName = macroModeState.latestRegister; + } else { + macroModeState.latestRegister = registerName; + } + while(repeat--){ + executeMacroRegister(cm, vim, macroModeState, registerName); + } + }, + enterMacroRecordMode: function(cm, actionArgs) { + var macroModeState = vimGlobalState.macroModeState; + var registerName = actionArgs.selectedCharacter; + if (vimGlobalState.registerController.isValidRegister(registerName)) { + macroModeState.enterMacroRecordMode(cm, registerName); + } + }, + toggleOverwrite: function(cm) { + if (!cm.state.overwrite) { + cm.toggleOverwrite(true); + cm.setOption('keyMap', 'vim-replace'); + CodeMirror.signal(cm, "vim-mode-change", {mode: "replace"}); + } else { + cm.toggleOverwrite(false); + cm.setOption('keyMap', 'vim-insert'); + CodeMirror.signal(cm, "vim-mode-change", {mode: "insert"}); + } + }, + enterInsertMode: function(cm, actionArgs, vim) { + if (cm.getOption('readOnly')) { return; } + vim.insertMode = true; + vim.insertModeRepeat = actionArgs && actionArgs.repeat || 1; + var insertAt = (actionArgs) ? actionArgs.insertAt : null; + var sel = vim.sel; + var head = actionArgs.head || cm.getCursor('head'); + var height = cm.listSelections().length; + if (insertAt == 'eol') { + head = Pos(head.line, lineLength(cm, head.line)); + } else if (insertAt == 'charAfter') { + head = offsetCursor(head, 0, 1); + } else if (insertAt == 'firstNonBlank') { + head = motions.moveToFirstNonWhiteSpaceCharacter(cm, head); + } else if (insertAt == 'startOfSelectedArea') { + if (!vim.visualMode) + return; + if (!vim.visualBlock) { + if (sel.head.line < sel.anchor.line) { + head = sel.head; + } else { + head = Pos(sel.anchor.line, 0); + } + } else { + head = Pos( + Math.min(sel.head.line, sel.anchor.line), + Math.min(sel.head.ch, sel.anchor.ch)); + height = Math.abs(sel.head.line - sel.anchor.line) + 1; + } + } else if (insertAt == 'endOfSelectedArea') { + if (!vim.visualMode) + return; + if (!vim.visualBlock) { + if (sel.head.line >= sel.anchor.line) { + head = offsetCursor(sel.head, 0, 1); + } else { + head = Pos(sel.anchor.line, 0); + } + } else { + head = Pos( + Math.min(sel.head.line, sel.anchor.line), + Math.max(sel.head.ch + 1, sel.anchor.ch)); + height = Math.abs(sel.head.line - sel.anchor.line) + 1; + } + } else if (insertAt == 'inplace') { + if (vim.visualMode){ + return; + } + } + cm.setOption('disableInput', false); + if (actionArgs && actionArgs.replace) { + cm.toggleOverwrite(true); + cm.setOption('keyMap', 'vim-replace'); + CodeMirror.signal(cm, "vim-mode-change", {mode: "replace"}); + } else { + cm.toggleOverwrite(false); + cm.setOption('keyMap', 'vim-insert'); + CodeMirror.signal(cm, "vim-mode-change", {mode: "insert"}); + } + if (!vimGlobalState.macroModeState.isPlaying) { + cm.on('change', onChange); + CodeMirror.on(cm.getInputField(), 'keydown', onKeyEventTargetKeyDown); + } + if (vim.visualMode) { + exitVisualMode(cm); + } + selectForInsert(cm, head, height); + }, + toggleVisualMode: function(cm, actionArgs, vim) { + var repeat = actionArgs.repeat; + var anchor = cm.getCursor(); + var head; + if (!vim.visualMode) { + vim.visualMode = true; + vim.visualLine = !!actionArgs.linewise; + vim.visualBlock = !!actionArgs.blockwise; + head = clipCursorToContent( + cm, Pos(anchor.line, anchor.ch + repeat - 1), + true /** includeLineBreak */); + vim.sel = { + anchor: anchor, + head: head + }; + CodeMirror.signal(cm, "vim-mode-change", {mode: "visual", subMode: vim.visualLine ? "linewise" : vim.visualBlock ? "blockwise" : ""}); + updateCmSelection(cm); + updateMark(cm, vim, '<', cursorMin(anchor, head)); + updateMark(cm, vim, '>', cursorMax(anchor, head)); + } else if (vim.visualLine ^ actionArgs.linewise || + vim.visualBlock ^ actionArgs.blockwise) { + vim.visualLine = !!actionArgs.linewise; + vim.visualBlock = !!actionArgs.blockwise; + CodeMirror.signal(cm, "vim-mode-change", {mode: "visual", subMode: vim.visualLine ? "linewise" : vim.visualBlock ? "blockwise" : ""}); + updateCmSelection(cm); + } else { + exitVisualMode(cm); + } + }, + reselectLastSelection: function(cm, _actionArgs, vim) { + var lastSelection = vim.lastSelection; + if (vim.visualMode) { + updateLastSelection(cm, vim); + } + if (lastSelection) { + var anchor = lastSelection.anchorMark.find(); + var head = lastSelection.headMark.find(); + if (!anchor || !head) { + return; + } + vim.sel = { + anchor: anchor, + head: head + }; + vim.visualMode = true; + vim.visualLine = lastSelection.visualLine; + vim.visualBlock = lastSelection.visualBlock; + updateCmSelection(cm); + updateMark(cm, vim, '<', cursorMin(anchor, head)); + updateMark(cm, vim, '>', cursorMax(anchor, head)); + CodeMirror.signal(cm, 'vim-mode-change', { + mode: 'visual', + subMode: vim.visualLine ? 'linewise' : + vim.visualBlock ? 'blockwise' : ''}); + } + }, + joinLines: function(cm, actionArgs, vim) { + var curStart, curEnd; + if (vim.visualMode) { + curStart = cm.getCursor('anchor'); + curEnd = cm.getCursor('head'); + if (cursorIsBefore(curEnd, curStart)) { + var tmp = curEnd; + curEnd = curStart; + curStart = tmp; + } + curEnd.ch = lineLength(cm, curEnd.line) - 1; + } else { + var repeat = Math.max(actionArgs.repeat, 2); + curStart = cm.getCursor(); + curEnd = clipCursorToContent(cm, Pos(curStart.line + repeat - 1, + Infinity)); + } + var finalCh = 0; + for (var i = curStart.line; i < curEnd.line; i++) { + finalCh = lineLength(cm, curStart.line); + var tmp = Pos(curStart.line + 1, + lineLength(cm, curStart.line + 1)); + var text = cm.getRange(curStart, tmp); + text = text.replace(/\n\s*/g, ' '); + cm.replaceRange(text, curStart, tmp); + } + var curFinalPos = Pos(curStart.line, finalCh); + if (vim.visualMode) { + exitVisualMode(cm, false); + } + cm.setCursor(curFinalPos); + }, + newLineAndEnterInsertMode: function(cm, actionArgs, vim) { + vim.insertMode = true; + var insertAt = copyCursor(cm.getCursor()); + if (insertAt.line === cm.firstLine() && !actionArgs.after) { + cm.replaceRange('\n', Pos(cm.firstLine(), 0)); + cm.setCursor(cm.firstLine(), 0); + } else { + insertAt.line = (actionArgs.after) ? insertAt.line : + insertAt.line - 1; + insertAt.ch = lineLength(cm, insertAt.line); + cm.setCursor(insertAt); + var newlineFn = CodeMirror.commands.newlineAndIndentContinueComment || + CodeMirror.commands.newlineAndIndent; + newlineFn(cm); + } + this.enterInsertMode(cm, { repeat: actionArgs.repeat }, vim); + }, + paste: function(cm, actionArgs, vim) { + var cur = copyCursor(cm.getCursor()); + var register = vimGlobalState.registerController.getRegister( + actionArgs.registerName); + var text = register.toString(); + if (!text) { + return; + } + if (actionArgs.matchIndent) { + var tabSize = cm.getOption("tabSize"); + var whitespaceLength = function(str) { + var tabs = (str.split("\t").length - 1); + var spaces = (str.split(" ").length - 1); + return tabs * tabSize + spaces * 1; + }; + var currentLine = cm.getLine(cm.getCursor().line); + var indent = whitespaceLength(currentLine.match(/^\s*/)[0]); + var chompedText = text.replace(/\n$/, ''); + var wasChomped = text !== chompedText; + var firstIndent = whitespaceLength(text.match(/^\s*/)[0]); + var text = chompedText.replace(/^\s*/gm, function(wspace) { + var newIndent = indent + (whitespaceLength(wspace) - firstIndent); + if (newIndent < 0) { + return ""; + } + else if (cm.getOption("indentWithTabs")) { + var quotient = Math.floor(newIndent / tabSize); + return Array(quotient + 1).join('\t'); + } + else { + return Array(newIndent + 1).join(' '); + } + }); + text += wasChomped ? "\n" : ""; + } + if (actionArgs.repeat > 1) { + var text = Array(actionArgs.repeat + 1).join(text); + } + var linewise = register.linewise; + var blockwise = register.blockwise; + if (blockwise) { + text = text.split('\n'); + if (linewise) { + text.pop(); + } + for (var i = 0; i < text.length; i++) { + text[i] = (text[i] == '') ? ' ' : text[i]; + } + cur.ch += actionArgs.after ? 1 : 0; + cur.ch = Math.min(lineLength(cm, cur.line), cur.ch); + } else if (linewise) { + if(vim.visualMode) { + text = vim.visualLine ? text.slice(0, -1) : '\n' + text.slice(0, text.length - 1) + '\n'; + } else if (actionArgs.after) { + text = '\n' + text.slice(0, text.length - 1); + cur.ch = lineLength(cm, cur.line); + } else { + cur.ch = 0; + } + } else { + cur.ch += actionArgs.after ? 1 : 0; + } + var curPosFinal; + var idx; + if (vim.visualMode) { + vim.lastPastedText = text; + var lastSelectionCurEnd; + var selectedArea = getSelectedAreaRange(cm, vim); + var selectionStart = selectedArea[0]; + var selectionEnd = selectedArea[1]; + var selectedText = cm.getSelection(); + var selections = cm.listSelections(); + var emptyStrings = new Array(selections.length).join('1').split('1'); + if (vim.lastSelection) { + lastSelectionCurEnd = vim.lastSelection.headMark.find(); + } + vimGlobalState.registerController.unnamedRegister.setText(selectedText); + if (blockwise) { + cm.replaceSelections(emptyStrings); + selectionEnd = Pos(selectionStart.line + text.length-1, selectionStart.ch); + cm.setCursor(selectionStart); + selectBlock(cm, selectionEnd); + cm.replaceSelections(text); + curPosFinal = selectionStart; + } else if (vim.visualBlock) { + cm.replaceSelections(emptyStrings); + cm.setCursor(selectionStart); + cm.replaceRange(text, selectionStart, selectionStart); + curPosFinal = selectionStart; + } else { + cm.replaceRange(text, selectionStart, selectionEnd); + curPosFinal = cm.posFromIndex(cm.indexFromPos(selectionStart) + text.length - 1); + } + if(lastSelectionCurEnd) { + vim.lastSelection.headMark = cm.setBookmark(lastSelectionCurEnd); + } + if (linewise) { + curPosFinal.ch=0; + } + } else { + if (blockwise) { + cm.setCursor(cur); + for (var i = 0; i < text.length; i++) { + var line = cur.line+i; + if (line > cm.lastLine()) { + cm.replaceRange('\n', Pos(line, 0)); + } + var lastCh = lineLength(cm, line); + if (lastCh < cur.ch) { + extendLineToColumn(cm, line, cur.ch); + } + } + cm.setCursor(cur); + selectBlock(cm, Pos(cur.line + text.length-1, cur.ch)); + cm.replaceSelections(text); + curPosFinal = cur; + } else { + cm.replaceRange(text, cur); + if (linewise && actionArgs.after) { + curPosFinal = Pos( + cur.line + 1, + findFirstNonWhiteSpaceCharacter(cm.getLine(cur.line + 1))); + } else if (linewise && !actionArgs.after) { + curPosFinal = Pos( + cur.line, + findFirstNonWhiteSpaceCharacter(cm.getLine(cur.line))); + } else if (!linewise && actionArgs.after) { + idx = cm.indexFromPos(cur); + curPosFinal = cm.posFromIndex(idx + text.length - 1); + } else { + idx = cm.indexFromPos(cur); + curPosFinal = cm.posFromIndex(idx + text.length); + } + } + } + if (vim.visualMode) { + exitVisualMode(cm, false); + } + cm.setCursor(curPosFinal); + }, + undo: function(cm, actionArgs) { + cm.operation(function() { + repeatFn(cm, CodeMirror.commands.undo, actionArgs.repeat)(); + cm.setCursor(cm.getCursor('anchor')); + }); + }, + redo: function(cm, actionArgs) { + repeatFn(cm, CodeMirror.commands.redo, actionArgs.repeat)(); + }, + setRegister: function(_cm, actionArgs, vim) { + vim.inputState.registerName = actionArgs.selectedCharacter; + }, + setMark: function(cm, actionArgs, vim) { + var markName = actionArgs.selectedCharacter; + updateMark(cm, vim, markName, cm.getCursor()); + }, + replace: function(cm, actionArgs, vim) { + var replaceWith = actionArgs.selectedCharacter; + var curStart = cm.getCursor(); + var replaceTo; + var curEnd; + var selections = cm.listSelections(); + if (vim.visualMode) { + curStart = cm.getCursor('start'); + curEnd = cm.getCursor('end'); + } else { + var line = cm.getLine(curStart.line); + replaceTo = curStart.ch + actionArgs.repeat; + if (replaceTo > line.length) { + replaceTo=line.length; + } + curEnd = Pos(curStart.line, replaceTo); + } + if (replaceWith=='\n') { + if (!vim.visualMode) cm.replaceRange('', curStart, curEnd); + (CodeMirror.commands.newlineAndIndentContinueComment || CodeMirror.commands.newlineAndIndent)(cm); + } else { + var replaceWithStr = cm.getRange(curStart, curEnd); + replaceWithStr = replaceWithStr.replace(/[^\n]/g, replaceWith); + if (vim.visualBlock) { + var spaces = new Array(cm.getOption("tabSize")+1).join(' '); + replaceWithStr = cm.getSelection(); + replaceWithStr = replaceWithStr.replace(/\t/g, spaces).replace(/[^\n]/g, replaceWith).split('\n'); + cm.replaceSelections(replaceWithStr); + } else { + cm.replaceRange(replaceWithStr, curStart, curEnd); + } + if (vim.visualMode) { + curStart = cursorIsBefore(selections[0].anchor, selections[0].head) ? + selections[0].anchor : selections[0].head; + cm.setCursor(curStart); + exitVisualMode(cm, false); + } else { + cm.setCursor(offsetCursor(curEnd, 0, -1)); + } + } + }, + incrementNumberToken: function(cm, actionArgs) { + var cur = cm.getCursor(); + var lineStr = cm.getLine(cur.line); + var re = /(-?)(?:(0x)([\da-f]+)|(0b|0|)(\d+))/gi; + var match; + var start; + var end; + var numberStr; + while ((match = re.exec(lineStr)) !== null) { + start = match.index; + end = start + match[0].length; + if (cur.ch < end)break; + } + if (!actionArgs.backtrack && (end <= cur.ch))return; + if (match) { + var baseStr = match[2] || match[4] + var digits = match[3] || match[5] + var increment = actionArgs.increase ? 1 : -1; + var base = {'0b': 2, '0': 8, '': 10, '0x': 16}[baseStr.toLowerCase()]; + var number = parseInt(match[1] + digits, base) + (increment * actionArgs.repeat); + numberStr = number.toString(base); + var zeroPadding = baseStr ? new Array(digits.length - numberStr.length + 1 + match[1].length).join('0') : '' + if (numberStr.charAt(0) === '-') { + numberStr = '-' + baseStr + zeroPadding + numberStr.substr(1); + } else { + numberStr = baseStr + zeroPadding + numberStr; + } + var from = Pos(cur.line, start); + var to = Pos(cur.line, end); + cm.replaceRange(numberStr, from, to); + } else { + return; + } + cm.setCursor(Pos(cur.line, start + numberStr.length - 1)); + }, + repeatLastEdit: function(cm, actionArgs, vim) { + var lastEditInputState = vim.lastEditInputState; + if (!lastEditInputState) { return; } + var repeat = actionArgs.repeat; + if (repeat && actionArgs.repeatIsExplicit) { + vim.lastEditInputState.repeatOverride = repeat; + } else { + repeat = vim.lastEditInputState.repeatOverride || repeat; + } + repeatLastEdit(cm, vim, repeat, false /** repeatForInsert */); + }, + indent: function(cm, actionArgs) { + cm.indentLine(cm.getCursor().line, actionArgs.indentRight); + }, + exitInsertMode: exitInsertMode + }; + + function defineAction(name, fn) { + actions[name] = fn; + } + function clipCursorToContent(cm, cur, includeLineBreak) { + var line = Math.min(Math.max(cm.firstLine(), cur.line), cm.lastLine() ); + var maxCh = lineLength(cm, line) - 1; + maxCh = (includeLineBreak) ? maxCh + 1 : maxCh; + var ch = Math.min(Math.max(0, cur.ch), maxCh); + return Pos(line, ch); + } + function copyArgs(args) { + var ret = {}; + for (var prop in args) { + if (args.hasOwnProperty(prop)) { + ret[prop] = args[prop]; + } + } + return ret; + } + function offsetCursor(cur, offsetLine, offsetCh) { + if (typeof offsetLine === 'object') { + offsetCh = offsetLine.ch; + offsetLine = offsetLine.line; + } + return Pos(cur.line + offsetLine, cur.ch + offsetCh); + } + function commandMatches(keys, keyMap, context, inputState) { + var match, partial = [], full = []; + for (var i = 0; i < keyMap.length; i++) { + var command = keyMap[i]; + if (context == 'insert' && command.context != 'insert' || + command.context && command.context != context || + inputState.operator && command.type == 'action' || + !(match = commandMatch(keys, command.keys))) { continue; } + if (match == 'partial') { partial.push(command); } + if (match == 'full') { full.push(command); } + } + return { + partial: partial.length && partial, + full: full.length && full + }; + } + function commandMatch(pressed, mapped) { + if (mapped.slice(-11) == '') { + var prefixLen = mapped.length - 11; + var pressedPrefix = pressed.slice(0, prefixLen); + var mappedPrefix = mapped.slice(0, prefixLen); + return pressedPrefix == mappedPrefix && pressed.length > prefixLen ? 'full' : + mappedPrefix.indexOf(pressedPrefix) == 0 ? 'partial' : false; + } else { + return pressed == mapped ? 'full' : + mapped.indexOf(pressed) == 0 ? 'partial' : false; + } + } + function lastChar(keys) { + var match = /^.*(<[^>]+>)$/.exec(keys); + var selectedCharacter = match ? match[1] : keys.slice(-1); + if (selectedCharacter.length > 1){ + switch(selectedCharacter){ + case '': + selectedCharacter='\n'; + break; + case '': + selectedCharacter=' '; + break; + default: + selectedCharacter=''; + break; + } + } + return selectedCharacter; + } + function repeatFn(cm, fn, repeat) { + return function() { + for (var i = 0; i < repeat; i++) { + fn(cm); + } + }; + } + function copyCursor(cur) { + return Pos(cur.line, cur.ch); + } + function cursorEqual(cur1, cur2) { + return cur1.ch == cur2.ch && cur1.line == cur2.line; + } + function cursorIsBefore(cur1, cur2) { + if (cur1.line < cur2.line) { + return true; + } + if (cur1.line == cur2.line && cur1.ch < cur2.ch) { + return true; + } + return false; + } + function cursorMin(cur1, cur2) { + if (arguments.length > 2) { + cur2 = cursorMin.apply(undefined, Array.prototype.slice.call(arguments, 1)); + } + return cursorIsBefore(cur1, cur2) ? cur1 : cur2; + } + function cursorMax(cur1, cur2) { + if (arguments.length > 2) { + cur2 = cursorMax.apply(undefined, Array.prototype.slice.call(arguments, 1)); + } + return cursorIsBefore(cur1, cur2) ? cur2 : cur1; + } + function cursorIsBetween(cur1, cur2, cur3) { + var cur1before2 = cursorIsBefore(cur1, cur2); + var cur2before3 = cursorIsBefore(cur2, cur3); + return cur1before2 && cur2before3; + } + function lineLength(cm, lineNum) { + return cm.getLine(lineNum).length; + } + function trim(s) { + if (s.trim) { + return s.trim(); + } + return s.replace(/^\s+|\s+$/g, ''); + } + function escapeRegex(s) { + return s.replace(/([.?*+$\[\]\/\\(){}|\-])/g, '\\$1'); + } + function extendLineToColumn(cm, lineNum, column) { + var endCh = lineLength(cm, lineNum); + var spaces = new Array(column-endCh+1).join(' '); + cm.setCursor(Pos(lineNum, endCh)); + cm.replaceRange(spaces, cm.getCursor()); + } + function selectBlock(cm, selectionEnd) { + var selections = [], ranges = cm.listSelections(); + var head = copyCursor(cm.clipPos(selectionEnd)); + var isClipped = !cursorEqual(selectionEnd, head); + var curHead = cm.getCursor('head'); + var primIndex = getIndex(ranges, curHead); + var wasClipped = cursorEqual(ranges[primIndex].head, ranges[primIndex].anchor); + var max = ranges.length - 1; + var index = max - primIndex > primIndex ? max : 0; + var base = ranges[index].anchor; + + var firstLine = Math.min(base.line, head.line); + var lastLine = Math.max(base.line, head.line); + var baseCh = base.ch, headCh = head.ch; + + var dir = ranges[index].head.ch - baseCh; + var newDir = headCh - baseCh; + if (dir > 0 && newDir <= 0) { + baseCh++; + if (!isClipped) { headCh--; } + } else if (dir < 0 && newDir >= 0) { + baseCh--; + if (!wasClipped) { headCh++; } + } else if (dir < 0 && newDir == -1) { + baseCh--; + headCh++; + } + for (var line = firstLine; line <= lastLine; line++) { + var range = {anchor: new Pos(line, baseCh), head: new Pos(line, headCh)}; + selections.push(range); + } + cm.setSelections(selections); + selectionEnd.ch = headCh; + base.ch = baseCh; + return base; + } + function selectForInsert(cm, head, height) { + var sel = []; + for (var i = 0; i < height; i++) { + var lineHead = offsetCursor(head, i, 0); + sel.push({anchor: lineHead, head: lineHead}); + } + cm.setSelections(sel, 0); + } + function getIndex(ranges, cursor, end) { + for (var i = 0; i < ranges.length; i++) { + var atAnchor = end != 'head' && cursorEqual(ranges[i].anchor, cursor); + var atHead = end != 'anchor' && cursorEqual(ranges[i].head, cursor); + if (atAnchor || atHead) { + return i; + } + } + return -1; + } + function getSelectedAreaRange(cm, vim) { + var lastSelection = vim.lastSelection; + var getCurrentSelectedAreaRange = function() { + var selections = cm.listSelections(); + var start = selections[0]; + var end = selections[selections.length-1]; + var selectionStart = cursorIsBefore(start.anchor, start.head) ? start.anchor : start.head; + var selectionEnd = cursorIsBefore(end.anchor, end.head) ? end.head : end.anchor; + return [selectionStart, selectionEnd]; + }; + var getLastSelectedAreaRange = function() { + var selectionStart = cm.getCursor(); + var selectionEnd = cm.getCursor(); + var block = lastSelection.visualBlock; + if (block) { + var width = block.width; + var height = block.height; + selectionEnd = Pos(selectionStart.line + height, selectionStart.ch + width); + var selections = []; + for (var i = selectionStart.line; i < selectionEnd.line; i++) { + var anchor = Pos(i, selectionStart.ch); + var head = Pos(i, selectionEnd.ch); + var range = {anchor: anchor, head: head}; + selections.push(range); + } + cm.setSelections(selections); + } else { + var start = lastSelection.anchorMark.find(); + var end = lastSelection.headMark.find(); + var line = end.line - start.line; + var ch = end.ch - start.ch; + selectionEnd = {line: selectionEnd.line + line, ch: line ? selectionEnd.ch : ch + selectionEnd.ch}; + if (lastSelection.visualLine) { + selectionStart = Pos(selectionStart.line, 0); + selectionEnd = Pos(selectionEnd.line, lineLength(cm, selectionEnd.line)); + } + cm.setSelection(selectionStart, selectionEnd); + } + return [selectionStart, selectionEnd]; + }; + if (!vim.visualMode) { + return getLastSelectedAreaRange(); + } else { + return getCurrentSelectedAreaRange(); + } + } + function updateLastSelection(cm, vim) { + var anchor = vim.sel.anchor; + var head = vim.sel.head; + if (vim.lastPastedText) { + head = cm.posFromIndex(cm.indexFromPos(anchor) + vim.lastPastedText.length); + vim.lastPastedText = null; + } + vim.lastSelection = {'anchorMark': cm.setBookmark(anchor), + 'headMark': cm.setBookmark(head), + 'anchor': copyCursor(anchor), + 'head': copyCursor(head), + 'visualMode': vim.visualMode, + 'visualLine': vim.visualLine, + 'visualBlock': vim.visualBlock}; + } + function expandSelection(cm, start, end) { + var sel = cm.state.vim.sel; + var head = sel.head; + var anchor = sel.anchor; + var tmp; + if (cursorIsBefore(end, start)) { + tmp = end; + end = start; + start = tmp; + } + if (cursorIsBefore(head, anchor)) { + head = cursorMin(start, head); + anchor = cursorMax(anchor, end); + } else { + anchor = cursorMin(start, anchor); + head = cursorMax(head, end); + head = offsetCursor(head, 0, -1); + if (head.ch == -1 && head.line != cm.firstLine()) { + head = Pos(head.line - 1, lineLength(cm, head.line - 1)); + } + } + return [anchor, head]; + } + function updateCmSelection(cm, sel, mode) { + var vim = cm.state.vim; + sel = sel || vim.sel; + var mode = mode || + vim.visualLine ? 'line' : vim.visualBlock ? 'block' : 'char'; + var cmSel = makeCmSelection(cm, sel, mode); + cm.setSelections(cmSel.ranges, cmSel.primary); + updateFakeCursor(cm); + } + function makeCmSelection(cm, sel, mode, exclusive) { + var head = copyCursor(sel.head); + var anchor = copyCursor(sel.anchor); + if (mode == 'char') { + var headOffset = !exclusive && !cursorIsBefore(sel.head, sel.anchor) ? 1 : 0; + var anchorOffset = cursorIsBefore(sel.head, sel.anchor) ? 1 : 0; + head = offsetCursor(sel.head, 0, headOffset); + anchor = offsetCursor(sel.anchor, 0, anchorOffset); + return { + ranges: [{anchor: anchor, head: head}], + primary: 0 + }; + } else if (mode == 'line') { + if (!cursorIsBefore(sel.head, sel.anchor)) { + anchor.ch = 0; + + var lastLine = cm.lastLine(); + if (head.line > lastLine) { + head.line = lastLine; + } + head.ch = lineLength(cm, head.line); + } else { + head.ch = 0; + anchor.ch = lineLength(cm, anchor.line); + } + return { + ranges: [{anchor: anchor, head: head}], + primary: 0 + }; + } else if (mode == 'block') { + var top = Math.min(anchor.line, head.line), + left = Math.min(anchor.ch, head.ch), + bottom = Math.max(anchor.line, head.line), + right = Math.max(anchor.ch, head.ch) + 1; + var height = bottom - top + 1; + var primary = head.line == top ? 0 : height - 1; + var ranges = []; + for (var i = 0; i < height; i++) { + ranges.push({ + anchor: Pos(top + i, left), + head: Pos(top + i, right) + }); + } + return { + ranges: ranges, + primary: primary + }; + } + } + function getHead(cm) { + var cur = cm.getCursor('head'); + if (cm.getSelection().length == 1) { + cur = cursorMin(cur, cm.getCursor('anchor')); + } + return cur; + } + function exitVisualMode(cm, moveHead) { + var vim = cm.state.vim; + if (moveHead !== false) { + cm.setCursor(clipCursorToContent(cm, vim.sel.head)); + } + updateLastSelection(cm, vim); + vim.visualMode = false; + vim.visualLine = false; + vim.visualBlock = false; + CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"}); + if (vim.fakeCursor) { + vim.fakeCursor.clear(); + } + } + function clipToLine(cm, curStart, curEnd) { + var selection = cm.getRange(curStart, curEnd); + if (/\n\s*$/.test(selection)) { + var lines = selection.split('\n'); + lines.pop(); + var line; + for (var line = lines.pop(); lines.length > 0 && line && isWhiteSpaceString(line); line = lines.pop()) { + curEnd.line--; + curEnd.ch = 0; + } + if (line) { + curEnd.line--; + curEnd.ch = lineLength(cm, curEnd.line); + } else { + curEnd.ch = 0; + } + } + } + function expandSelectionToLine(_cm, curStart, curEnd) { + curStart.ch = 0; + curEnd.ch = 0; + curEnd.line++; + } + + function findFirstNonWhiteSpaceCharacter(text) { + if (!text) { + return 0; + } + var firstNonWS = text.search(/\S/); + return firstNonWS == -1 ? text.length : firstNonWS; + } + + function expandWordUnderCursor(cm, inclusive, _forward, bigWord, noSymbol) { + var cur = getHead(cm); + var line = cm.getLine(cur.line); + var idx = cur.ch; + var test = noSymbol ? wordCharTest[0] : bigWordCharTest [0]; + while (!test(line.charAt(idx))) { + idx++; + if (idx >= line.length) { return null; } + } + + if (bigWord) { + test = bigWordCharTest[0]; + } else { + test = wordCharTest[0]; + if (!test(line.charAt(idx))) { + test = wordCharTest[1]; + } + } + + var end = idx, start = idx; + while (test(line.charAt(end)) && end < line.length) { end++; } + while (test(line.charAt(start)) && start >= 0) { start--; } + start++; + + if (inclusive) { + var wordEnd = end; + while (/\s/.test(line.charAt(end)) && end < line.length) { end++; } + if (wordEnd == end) { + var wordStart = start; + while (/\s/.test(line.charAt(start - 1)) && start > 0) { start--; } + if (!start) { start = wordStart; } + } + } + return { start: Pos(cur.line, start), end: Pos(cur.line, end) }; + } + + function recordJumpPosition(cm, oldCur, newCur) { + if (!cursorEqual(oldCur, newCur)) { + vimGlobalState.jumpList.add(cm, oldCur, newCur); + } + } + + function recordLastCharacterSearch(increment, args) { + vimGlobalState.lastCharacterSearch.increment = increment; + vimGlobalState.lastCharacterSearch.forward = args.forward; + vimGlobalState.lastCharacterSearch.selectedCharacter = args.selectedCharacter; + } + + var symbolToMode = { + '(': 'bracket', ')': 'bracket', '{': 'bracket', '}': 'bracket', + '[': 'section', ']': 'section', + '*': 'comment', '/': 'comment', + 'm': 'method', 'M': 'method', + '#': 'preprocess' + }; + var findSymbolModes = { + bracket: { + isComplete: function(state) { + if (state.nextCh === state.symb) { + state.depth++; + if (state.depth >= 1)return true; + } else if (state.nextCh === state.reverseSymb) { + state.depth--; + } + return false; + } + }, + section: { + init: function(state) { + state.curMoveThrough = true; + state.symb = (state.forward ? ']' : '[') === state.symb ? '{' : '}'; + }, + isComplete: function(state) { + return state.index === 0 && state.nextCh === state.symb; + } + }, + comment: { + isComplete: function(state) { + var found = state.lastCh === '*' && state.nextCh === '/'; + state.lastCh = state.nextCh; + return found; + } + }, + method: { + init: function(state) { + state.symb = (state.symb === 'm' ? '{' : '}'); + state.reverseSymb = state.symb === '{' ? '}' : '{'; + }, + isComplete: function(state) { + if (state.nextCh === state.symb)return true; + return false; + } + }, + preprocess: { + init: function(state) { + state.index = 0; + }, + isComplete: function(state) { + if (state.nextCh === '#') { + var token = state.lineText.match(/#(\w+)/)[1]; + if (token === 'endif') { + if (state.forward && state.depth === 0) { + return true; + } + state.depth++; + } else if (token === 'if') { + if (!state.forward && state.depth === 0) { + return true; + } + state.depth--; + } + if (token === 'else' && state.depth === 0)return true; + } + return false; + } + } + }; + function findSymbol(cm, repeat, forward, symb) { + var cur = copyCursor(cm.getCursor()); + var increment = forward ? 1 : -1; + var endLine = forward ? cm.lineCount() : -1; + var curCh = cur.ch; + var line = cur.line; + var lineText = cm.getLine(line); + var state = { + lineText: lineText, + nextCh: lineText.charAt(curCh), + lastCh: null, + index: curCh, + symb: symb, + reverseSymb: (forward ? { ')': '(', '}': '{' } : { '(': ')', '{': '}' })[symb], + forward: forward, + depth: 0, + curMoveThrough: false + }; + var mode = symbolToMode[symb]; + if (!mode)return cur; + var init = findSymbolModes[mode].init; + var isComplete = findSymbolModes[mode].isComplete; + if (init) { init(state); } + while (line !== endLine && repeat) { + state.index += increment; + state.nextCh = state.lineText.charAt(state.index); + if (!state.nextCh) { + line += increment; + state.lineText = cm.getLine(line) || ''; + if (increment > 0) { + state.index = 0; + } else { + var lineLen = state.lineText.length; + state.index = (lineLen > 0) ? (lineLen-1) : 0; + } + state.nextCh = state.lineText.charAt(state.index); + } + if (isComplete(state)) { + cur.line = line; + cur.ch = state.index; + repeat--; + } + } + if (state.nextCh || state.curMoveThrough) { + return Pos(line, state.index); + } + return cur; + } + function findWord(cm, cur, forward, bigWord, emptyLineIsWord) { + var lineNum = cur.line; + var pos = cur.ch; + var line = cm.getLine(lineNum); + var dir = forward ? 1 : -1; + var charTests = bigWord ? bigWordCharTest: wordCharTest; + + if (emptyLineIsWord && line == '') { + lineNum += dir; + line = cm.getLine(lineNum); + if (!isLine(cm, lineNum)) { + return null; + } + pos = (forward) ? 0 : line.length; + } + + while (true) { + if (emptyLineIsWord && line == '') { + return { from: 0, to: 0, line: lineNum }; + } + var stop = (dir > 0) ? line.length : -1; + var wordStart = stop, wordEnd = stop; + while (pos != stop) { + var foundWord = false; + for (var i = 0; i < charTests.length && !foundWord; ++i) { + if (charTests[i](line.charAt(pos))) { + wordStart = pos; + while (pos != stop && charTests[i](line.charAt(pos))) { + pos += dir; + } + wordEnd = pos; + foundWord = wordStart != wordEnd; + if (wordStart == cur.ch && lineNum == cur.line && + wordEnd == wordStart + dir) { + continue; + } else { + return { + from: Math.min(wordStart, wordEnd + 1), + to: Math.max(wordStart, wordEnd), + line: lineNum }; + } + } + } + if (!foundWord) { + pos += dir; + } + } + lineNum += dir; + if (!isLine(cm, lineNum)) { + return null; + } + line = cm.getLine(lineNum); + pos = (dir > 0) ? 0 : line.length; + } + } + function moveToWord(cm, cur, repeat, forward, wordEnd, bigWord) { + var curStart = copyCursor(cur); + var words = []; + if (forward && !wordEnd || !forward && wordEnd) { + repeat++; + } + var emptyLineIsWord = !(forward && wordEnd); + for (var i = 0; i < repeat; i++) { + var word = findWord(cm, cur, forward, bigWord, emptyLineIsWord); + if (!word) { + var eodCh = lineLength(cm, cm.lastLine()); + words.push(forward + ? {line: cm.lastLine(), from: eodCh, to: eodCh} + : {line: 0, from: 0, to: 0}); + break; + } + words.push(word); + cur = Pos(word.line, forward ? (word.to - 1) : word.from); + } + var shortCircuit = words.length != repeat; + var firstWord = words[0]; + var lastWord = words.pop(); + if (forward && !wordEnd) { + if (!shortCircuit && (firstWord.from != curStart.ch || firstWord.line != curStart.line)) { + lastWord = words.pop(); + } + return Pos(lastWord.line, lastWord.from); + } else if (forward && wordEnd) { + return Pos(lastWord.line, lastWord.to - 1); + } else if (!forward && wordEnd) { + if (!shortCircuit && (firstWord.to != curStart.ch || firstWord.line != curStart.line)) { + lastWord = words.pop(); + } + return Pos(lastWord.line, lastWord.to); + } else { + return Pos(lastWord.line, lastWord.from); + } + } + + function moveToCharacter(cm, repeat, forward, character) { + var cur = cm.getCursor(); + var start = cur.ch; + var idx; + for (var i = 0; i < repeat; i ++) { + var line = cm.getLine(cur.line); + idx = charIdxInLine(start, line, character, forward, true); + if (idx == -1) { + return null; + } + start = idx; + } + return Pos(cm.getCursor().line, idx); + } + + function moveToColumn(cm, repeat) { + var line = cm.getCursor().line; + return clipCursorToContent(cm, Pos(line, repeat - 1)); + } + + function updateMark(cm, vim, markName, pos) { + if (!inArray(markName, validMarks)) { + return; + } + if (vim.marks[markName]) { + vim.marks[markName].clear(); + } + vim.marks[markName] = cm.setBookmark(pos); + } + + function charIdxInLine(start, line, character, forward, includeChar) { + var idx; + if (forward) { + idx = line.indexOf(character, start + 1); + if (idx != -1 && !includeChar) { + idx -= 1; + } + } else { + idx = line.lastIndexOf(character, start - 1); + if (idx != -1 && !includeChar) { + idx += 1; + } + } + return idx; + } + + function findParagraph(cm, head, repeat, dir, inclusive) { + var line = head.line; + var min = cm.firstLine(); + var max = cm.lastLine(); + var start, end, i = line; + function isEmpty(i) { return !/\S/.test(cm.getLine(i)); } // ace_patch + function isBoundary(i, dir, any) { + if (any) { return isEmpty(i) != isEmpty(i + dir); } + return !isEmpty(i) && isEmpty(i + dir); + } + function skipFold(i) { + dir = dir > 0 ? 1 : -1; + var foldLine = cm.ace.session.getFoldLine(i); + if (foldLine) { + if (i + dir > foldLine.start.row && i + dir < foldLine.end.row) + dir = (dir > 0 ? foldLine.end.row : foldLine.start.row) - i; + } + } + if (dir) { + while (min <= i && i <= max && repeat > 0) { + skipFold(i); + if (isBoundary(i, dir)) { repeat--; } + i += dir; + } + return new Pos(i, 0); + } + + var vim = cm.state.vim; + if (vim.visualLine && isBoundary(line, 1, true)) { + var anchor = vim.sel.anchor; + if (isBoundary(anchor.line, -1, true)) { + if (!inclusive || anchor.line != line) { + line += 1; + } + } + } + var startState = isEmpty(line); + for (i = line; i <= max && repeat; i++) { + if (isBoundary(i, 1, true)) { + if (!inclusive || isEmpty(i) != startState) { + repeat--; + } + } + } + end = new Pos(i, 0); + if (i > max && !startState) { startState = true; } + else { inclusive = false; } + for (i = line; i > min; i--) { + if (!inclusive || isEmpty(i) == startState || i == line) { + if (isBoundary(i, -1, true)) { break; } + } + } + start = new Pos(i, 0); + return { start: start, end: end }; + } + + function findSentence(cm, cur, repeat, dir) { + function nextChar(cm, idx) { + if (idx.pos + idx.dir < 0 || idx.pos + idx.dir >= idx.line.length) { + idx.ln += idx.dir; + if (!isLine(cm, idx.ln)) { + idx.line = null; + idx.ln = null; + idx.pos = null; + return; + } + idx.line = cm.getLine(idx.ln); + idx.pos = (idx.dir > 0) ? 0 : idx.line.length - 1; + } + else { + idx.pos += idx.dir; + } + } + function forward(cm, ln, pos, dir) { + var line = cm.getLine(ln); + var stop = (line === ""); + + var curr = { + line: line, + ln: ln, + pos: pos, + dir: dir, + } + + var last_valid = { + ln: curr.ln, + pos: curr.pos, + } + + var skip_empty_lines = (curr.line === ""); + nextChar(cm, curr); + + while (curr.line !== null) { + last_valid.ln = curr.ln; + last_valid.pos = curr.pos; + + if (curr.line === "" && !skip_empty_lines) { + return { ln: curr.ln, pos: curr.pos, }; + } + else if (stop && curr.line !== "" && !isWhiteSpaceString(curr.line[curr.pos])) { + return { ln: curr.ln, pos: curr.pos, }; + } + else if (isEndOfSentenceSymbol(curr.line[curr.pos]) + && !stop + && (curr.pos === curr.line.length - 1 + || isWhiteSpaceString(curr.line[curr.pos + 1]))) { + stop = true; + } + + nextChar(cm, curr); + } + var line = cm.getLine(last_valid.ln); + last_valid.pos = 0; + for(var i = line.length - 1; i >= 0; --i) { + if (!isWhiteSpaceString(line[i])) { + last_valid.pos = i; + break; + } + } + + return last_valid; + + } + function reverse(cm, ln, pos, dir) { + var line = cm.getLine(ln); + + var curr = { + line: line, + ln: ln, + pos: pos, + dir: dir, + } + + var last_valid = { + ln: curr.ln, + pos: null, + }; + + var skip_empty_lines = (curr.line === ""); + nextChar(cm, curr); + + while (curr.line !== null) { + + if (curr.line === "" && !skip_empty_lines) { + if (last_valid.pos !== null) { + return last_valid; + } + else { + return { ln: curr.ln, pos: curr.pos }; + } + } + else if (isEndOfSentenceSymbol(curr.line[curr.pos]) + && last_valid.pos !== null + && !(curr.ln === last_valid.ln && curr.pos + 1 === last_valid.pos)) { + return last_valid; + } + else if (curr.line !== "" && !isWhiteSpaceString(curr.line[curr.pos])) { + skip_empty_lines = false; + last_valid = { ln: curr.ln, pos: curr.pos } + } + + nextChar(cm, curr); + } + var line = cm.getLine(last_valid.ln); + last_valid.pos = 0; + for(var i = 0; i < line.length; ++i) { + if (!isWhiteSpaceString(line[i])) { + last_valid.pos = i; + break; + } + } + return last_valid; + } + + var curr_index = { + ln: cur.line, + pos: cur.ch, + }; + + while (repeat > 0) { + if (dir < 0) { + curr_index = reverse(cm, curr_index.ln, curr_index.pos, dir); + } + else { + curr_index = forward(cm, curr_index.ln, curr_index.pos, dir); + } + repeat--; + } + + return Pos(curr_index.ln, curr_index.pos); + } + function selectCompanionObject(cm, head, symb, inclusive) { + var cur = head, start, end; + + var bracketRegexp = ({ + '(': /[()]/, ')': /[()]/, + '[': /[[\]]/, ']': /[[\]]/, + '{': /[{}]/, '}': /[{}]/, + '<': /[<>]/, '>': /[<>]/})[symb]; + var openSym = ({ + '(': '(', ')': '(', + '[': '[', ']': '[', + '{': '{', '}': '{', + '<': '<', '>': '<'})[symb]; + var curChar = cm.getLine(cur.line).charAt(cur.ch); + var offset = curChar === openSym ? 1 : 0; + + start = cm.scanForBracket(Pos(cur.line, cur.ch + offset), -1, undefined, {'bracketRegex': bracketRegexp}); + end = cm.scanForBracket(Pos(cur.line, cur.ch + offset), 1, undefined, {'bracketRegex': bracketRegexp}); + + if (!start || !end) { + return { start: cur, end: cur }; + } + + start = start.pos; + end = end.pos; + + if ((start.line == end.line && start.ch > end.ch) + || (start.line > end.line)) { + var tmp = start; + start = end; + end = tmp; + } + + if (inclusive) { + end.ch += 1; + } else { + start.ch += 1; + } + + return { start: start, end: end }; + } + function findBeginningAndEnd(cm, head, symb, inclusive) { + var cur = copyCursor(head); + var line = cm.getLine(cur.line); + var chars = line.split(''); + var start, end, i, len; + var firstIndex = chars.indexOf(symb); + if (cur.ch < firstIndex) { + cur.ch = firstIndex; + } + else if (firstIndex < cur.ch && chars[cur.ch] == symb) { + end = cur.ch; // assign end to the current cursor + --cur.ch; // make sure to look backwards + } + if (chars[cur.ch] == symb && !end) { + start = cur.ch + 1; // assign start to ahead of the cursor + } else { + for (i = cur.ch; i > -1 && !start; i--) { + if (chars[i] == symb) { + start = i + 1; + } + } + } + if (start && !end) { + for (i = start, len = chars.length; i < len && !end; i++) { + if (chars[i] == symb) { + end = i; + } + } + } + if (!start || !end) { + return { start: cur, end: cur }; + } + if (inclusive) { + --start; ++end; + } + + return { + start: Pos(cur.line, start), + end: Pos(cur.line, end) + }; + } + defineOption('pcre', true, 'boolean'); + function SearchState() {} + SearchState.prototype = { + getQuery: function() { + return vimGlobalState.query; + }, + setQuery: function(query) { + vimGlobalState.query = query; + }, + getOverlay: function() { + return this.searchOverlay; + }, + setOverlay: function(overlay) { + this.searchOverlay = overlay; + }, + isReversed: function() { + return vimGlobalState.isReversed; + }, + setReversed: function(reversed) { + vimGlobalState.isReversed = reversed; + }, + getScrollbarAnnotate: function() { + return this.annotate; + }, + setScrollbarAnnotate: function(annotate) { + this.annotate = annotate; + } + }; + function getSearchState(cm) { + var vim = cm.state.vim; + return vim.searchState_ || (vim.searchState_ = new SearchState()); + } + function dialog(cm, template, shortText, onClose, options) { + if (cm.openDialog) { + cm.openDialog(template, onClose, { bottom: true, value: options.value, + onKeyDown: options.onKeyDown, onKeyUp: options.onKeyUp, + selectValueOnOpen: false, onClose: function() { + if (cm.state.vim) { + cm.state.vim.status = ""; + cm.ace.renderer.$loop.schedule(cm.ace.renderer.CHANGE_CURSOR); + } + }}); + } + else { + onClose(prompt(shortText, '')); + } + } + function splitBySlash(argString) { + return splitBySeparator(argString, '/'); + } + + function findUnescapedSlashes(argString) { + return findUnescapedSeparators(argString, '/'); + } + + function splitBySeparator(argString, separator) { + var slashes = findUnescapedSeparators(argString, separator) || []; + if (!slashes.length) return []; + var tokens = []; + if (slashes[0] !== 0) return; + for (var i = 0; i < slashes.length; i++) { + if (typeof slashes[i] == 'number') + tokens.push(argString.substring(slashes[i] + 1, slashes[i+1])); + } + return tokens; + } + + function findUnescapedSeparators(str, separator) { + if (!separator) + separator = '/'; + + var escapeNextChar = false; + var slashes = []; + for (var i = 0; i < str.length; i++) { + var c = str.charAt(i); + if (!escapeNextChar && c == separator) { + slashes.push(i); + } + escapeNextChar = !escapeNextChar && (c == '\\'); + } + return slashes; + } + function translateRegex(str) { + var specials = '|(){'; + var unescape = '}'; + var escapeNextChar = false; + var out = []; + for (var i = -1; i < str.length; i++) { + var c = str.charAt(i) || ''; + var n = str.charAt(i+1) || ''; + var specialComesNext = (n && specials.indexOf(n) != -1); + if (escapeNextChar) { + if (c !== '\\' || !specialComesNext) { + out.push(c); + } + escapeNextChar = false; + } else { + if (c === '\\') { + escapeNextChar = true; + if (n && unescape.indexOf(n) != -1) { + specialComesNext = true; + } + if (!specialComesNext || n === '\\') { + out.push(c); + } + } else { + out.push(c); + if (specialComesNext && n !== '\\') { + out.push('\\'); + } + } + } + } + return out.join(''); + } + var charUnescapes = {'\\n': '\n', '\\r': '\r', '\\t': '\t'}; + function translateRegexReplace(str) { + var escapeNextChar = false; + var out = []; + for (var i = -1; i < str.length; i++) { + var c = str.charAt(i) || ''; + var n = str.charAt(i+1) || ''; + if (charUnescapes[c + n]) { + out.push(charUnescapes[c+n]); + i++; + } else if (escapeNextChar) { + out.push(c); + escapeNextChar = false; + } else { + if (c === '\\') { + escapeNextChar = true; + if ((isNumber(n) || n === '$')) { + out.push('$'); + } else if (n !== '/' && n !== '\\') { + out.push('\\'); + } + } else { + if (c === '$') { + out.push('$'); + } + out.push(c); + if (n === '/') { + out.push('\\'); + } + } + } + } + return out.join(''); + } + var unescapes = {'\\/': '/', '\\\\': '\\', '\\n': '\n', '\\r': '\r', '\\t': '\t'}; + function unescapeRegexReplace(str) { + var stream = new CodeMirror.StringStream(str); + var output = []; + while (!stream.eol()) { + while (stream.peek() && stream.peek() != '\\') { + output.push(stream.next()); + } + var matched = false; + for (var matcher in unescapes) { + if (stream.match(matcher, true)) { + matched = true; + output.push(unescapes[matcher]); + break; + } + } + if (!matched) { + output.push(stream.next()); + } + } + return output.join(''); + } + function parseQuery(query, ignoreCase, smartCase) { + var lastSearchRegister = vimGlobalState.registerController.getRegister('/'); + lastSearchRegister.setText(query); + if (query instanceof RegExp) { return query; } + var slashes = findUnescapedSlashes(query); + var regexPart; + var forceIgnoreCase; + if (!slashes.length) { + regexPart = query; + } else { + regexPart = query.substring(0, slashes[0]); + var flagsPart = query.substring(slashes[0]); + forceIgnoreCase = (flagsPart.indexOf('i') != -1); + } + if (!regexPart) { + return null; + } + if (!getOption('pcre')) { + regexPart = translateRegex(regexPart); + } + if (smartCase) { + ignoreCase = (/^[^A-Z]*$/).test(regexPart); + } + var regexp = new RegExp(regexPart, + (ignoreCase || forceIgnoreCase) ? 'i' : undefined); + return regexp; + } + function showConfirm(cm, text) { + if (cm.openNotification) { + cm.openNotification('' + text + '', + {bottom: true, duration: 5000}); + } else { + alert(text); + } + } + function makePrompt(prefix, desc) { + var raw = '' + + (prefix || "") + ''; + if (desc) + raw += ' ' + desc + ''; + return raw; + } + var searchPromptDesc = '(Javascript regexp)'; + function showPrompt(cm, options) { + var shortText = (options.prefix || '') + ' ' + (options.desc || ''); + var prompt = makePrompt(options.prefix, options.desc); + dialog(cm, prompt, shortText, options.onClose, options); + } + function regexEqual(r1, r2) { + if (r1 instanceof RegExp && r2 instanceof RegExp) { + var props = ['global', 'multiline', 'ignoreCase', 'source']; + for (var i = 0; i < props.length; i++) { + var prop = props[i]; + if (r1[prop] !== r2[prop]) { + return false; + } + } + return true; + } + return false; + } + function updateSearchQuery(cm, rawQuery, ignoreCase, smartCase) { + if (!rawQuery) { + return; + } + var state = getSearchState(cm); + var query = parseQuery(rawQuery, !!ignoreCase, !!smartCase); + if (!query) { + return; + } + highlightSearchMatches(cm, query); + if (regexEqual(query, state.getQuery())) { + return query; + } + state.setQuery(query); + return query; + } + function searchOverlay(query) { + if (query.source.charAt(0) == '^') { + var matchSol = true; + } + return { + token: function(stream) { + if (matchSol && !stream.sol()) { + stream.skipToEnd(); + return; + } + var match = stream.match(query, false); + if (match) { + if (match[0].length == 0) { + stream.next(); + return 'searching'; + } + if (!stream.sol()) { + stream.backUp(1); + if (!query.exec(stream.next() + match[0])) { + stream.next(); + return null; + } + } + stream.match(query); + return 'searching'; + } + while (!stream.eol()) { + stream.next(); + if (stream.match(query, false)) break; + } + }, + query: query + }; + } + function highlightSearchMatches(cm, query) { + var searchState = getSearchState(cm); + var overlay = searchState.getOverlay(); + if (!overlay || query != overlay.query) { + if (overlay) { + cm.removeOverlay(overlay); + } + overlay = searchOverlay(query); + cm.addOverlay(overlay); + if (cm.showMatchesOnScrollbar) { + if (searchState.getScrollbarAnnotate()) { + searchState.getScrollbarAnnotate().clear(); + } + searchState.setScrollbarAnnotate(cm.showMatchesOnScrollbar(query)); + } + searchState.setOverlay(overlay); + } + } + function findNext(cm, prev, query, repeat) { + if (repeat === undefined) { repeat = 1; } + return cm.operation(function() { + var pos = cm.getCursor(); + var cursor = cm.getSearchCursor(query, pos); + for (var i = 0; i < repeat; i++) { + var found = cursor.find(prev); + if (i == 0 && found && cursorEqual(cursor.from(), pos)) { found = cursor.find(prev); } + if (!found) { + cursor = cm.getSearchCursor(query, + (prev) ? Pos(cm.lastLine()) : Pos(cm.firstLine(), 0) ); + if (!cursor.find(prev)) { + return; + } + } + } + return cursor.from(); + }); + } + function clearSearchHighlight(cm) { + var state = getSearchState(cm); + cm.removeOverlay(getSearchState(cm).getOverlay()); + state.setOverlay(null); + if (state.getScrollbarAnnotate()) { + state.getScrollbarAnnotate().clear(); + state.setScrollbarAnnotate(null); + } + } + function isInRange(pos, start, end) { + if (typeof pos != 'number') { + pos = pos.line; + } + if (start instanceof Array) { + return inArray(pos, start); + } else { + if (end) { + return (pos >= start && pos <= end); + } else { + return pos == start; + } + } + } + function getUserVisibleLines(cm) { + var renderer = cm.ace.renderer; + return { + top: renderer.getFirstFullyVisibleRow(), + bottom: renderer.getLastFullyVisibleRow() + } + } + + function getMarkPos(cm, vim, markName) { + + var mark = vim.marks[markName]; + return mark && mark.find(); + } + + var ExCommandDispatcher = function() { + this.buildCommandMap_(); + }; + ExCommandDispatcher.prototype = { + processCommand: function(cm, input, opt_params) { + var that = this; + cm.operation(function () { + cm.curOp.isVimOp = true; + that._processCommand(cm, input, opt_params); + }); + }, + _processCommand: function(cm, input, opt_params) { + var vim = cm.state.vim; + var commandHistoryRegister = vimGlobalState.registerController.getRegister(':'); + var previousCommand = commandHistoryRegister.toString(); + if (vim.visualMode) { + exitVisualMode(cm); + } + var inputStream = new CodeMirror.StringStream(input); + commandHistoryRegister.setText(input); + var params = opt_params || {}; + params.input = input; + try { + this.parseInput_(cm, inputStream, params); + } catch(e) { + showConfirm(cm, e); + throw e; + } + var command; + var commandName; + if (!params.commandName) { + if (params.line !== undefined) { + commandName = 'move'; + } + } else { + command = this.matchCommand_(params.commandName); + if (command) { + commandName = command.name; + if (command.excludeFromCommandHistory) { + commandHistoryRegister.setText(previousCommand); + } + this.parseCommandArgs_(inputStream, params, command); + if (command.type == 'exToKey') { + for (var i = 0; i < command.toKeys.length; i++) { + CodeMirror.Vim.handleKey(cm, command.toKeys[i], 'mapping'); + } + return; + } else if (command.type == 'exToEx') { + this.processCommand(cm, command.toInput); + return; + } + } + } + if (!commandName) { + showConfirm(cm, 'Not an editor command ":' + input + '"'); + return; + } + try { + exCommands[commandName](cm, params); + if ((!command || !command.possiblyAsync) && params.callback) { + params.callback(); + } + } catch(e) { + showConfirm(cm, e); + throw e; + } + }, + parseInput_: function(cm, inputStream, result) { + inputStream.eatWhile(':'); + if (inputStream.eat('%')) { + result.line = cm.firstLine(); + result.lineEnd = cm.lastLine(); + } else { + result.line = this.parseLineSpec_(cm, inputStream); + if (result.line !== undefined && inputStream.eat(',')) { + result.lineEnd = this.parseLineSpec_(cm, inputStream); + } + } + var commandMatch = inputStream.match(/^(\w+)/); + if (commandMatch) { + result.commandName = commandMatch[1]; + } else { + result.commandName = inputStream.match(/.*/)[0]; + } + + return result; + }, + parseLineSpec_: function(cm, inputStream) { + var numberMatch = inputStream.match(/^(\d+)/); + if (numberMatch) { + return parseInt(numberMatch[1], 10) - 1; + } + switch (inputStream.next()) { + case '.': + return this.parseLineSpecOffset_(inputStream, cm.getCursor().line); + case '$': + return this.parseLineSpecOffset_(inputStream, cm.lastLine()); + case '\'': + var markName = inputStream.next(); + var markPos = getMarkPos(cm, cm.state.vim, markName); + if (!markPos) throw new Error('Mark not set'); + return this.parseLineSpecOffset_(inputStream, markPos.line); + case '-': + case '+': + inputStream.backUp(1); + return this.parseLineSpecOffset_(inputStream, cm.getCursor().line); + default: + inputStream.backUp(1); + return undefined; + } + }, + parseLineSpecOffset_: function(inputStream, line) { + var offsetMatch = inputStream.match(/^([+-])?(\d+)/); + if (offsetMatch) { + var offset = parseInt(offsetMatch[2], 10); + if (offsetMatch[1] == "-") { + line -= offset; + } else { + line += offset; + } + } + return line; + }, + parseCommandArgs_: function(inputStream, params, command) { + if (inputStream.eol()) { + return; + } + params.argString = inputStream.match(/.*/)[0]; + var delim = command.argDelimiter || /\s+/; + var args = trim(params.argString).split(delim); + if (args.length && args[0]) { + params.args = args; + } + }, + matchCommand_: function(commandName) { + for (var i = commandName.length; i > 0; i--) { + var prefix = commandName.substring(0, i); + if (this.commandMap_[prefix]) { + var command = this.commandMap_[prefix]; + if (command.name.indexOf(commandName) === 0) { + return command; + } + } + } + return null; + }, + buildCommandMap_: function() { + this.commandMap_ = {}; + for (var i = 0; i < defaultExCommandMap.length; i++) { + var command = defaultExCommandMap[i]; + var key = command.shortName || command.name; + this.commandMap_[key] = command; + } + }, + map: function(lhs, rhs, ctx) { + if (lhs != ':' && lhs.charAt(0) == ':') { + if (ctx) { throw Error('Mode not supported for ex mappings'); } + var commandName = lhs.substring(1); + if (rhs != ':' && rhs.charAt(0) == ':') { + this.commandMap_[commandName] = { + name: commandName, + type: 'exToEx', + toInput: rhs.substring(1), + user: true + }; + } else { + this.commandMap_[commandName] = { + name: commandName, + type: 'exToKey', + toKeys: rhs, + user: true + }; + } + } else { + if (rhs != ':' && rhs.charAt(0) == ':') { + var mapping = { + keys: lhs, + type: 'keyToEx', + exArgs: { input: rhs.substring(1) } + }; + if (ctx) { mapping.context = ctx; } + defaultKeymap.unshift(mapping); + } else { + var mapping = { + keys: lhs, + type: 'keyToKey', + toKeys: rhs + }; + if (ctx) { mapping.context = ctx; } + defaultKeymap.unshift(mapping); + } + } + }, + unmap: function(lhs, ctx) { + if (lhs != ':' && lhs.charAt(0) == ':') { + if (ctx) { throw Error('Mode not supported for ex mappings'); } + var commandName = lhs.substring(1); + if (this.commandMap_[commandName] && this.commandMap_[commandName].user) { + delete this.commandMap_[commandName]; + return; + } + } else { + var keys = lhs; + for (var i = 0; i < defaultKeymap.length; i++) { + if (keys == defaultKeymap[i].keys + && defaultKeymap[i].context === ctx) { + defaultKeymap.splice(i, 1); + return; + } + } + } + } + }; + + var exCommands = { + colorscheme: function(cm, params) { + if (!params.args || params.args.length < 1) { + showConfirm(cm, cm.getOption('theme')); + return; + } + cm.setOption('theme', params.args[0]); + }, + map: function(cm, params, ctx) { + var mapArgs = params.args; + if (!mapArgs || mapArgs.length < 2) { + if (cm) { + showConfirm(cm, 'Invalid mapping: ' + params.input); + } + return; + } + exCommandDispatcher.map(mapArgs[0], mapArgs[1], ctx); + }, + imap: function(cm, params) { this.map(cm, params, 'insert'); }, + nmap: function(cm, params) { this.map(cm, params, 'normal'); }, + vmap: function(cm, params) { this.map(cm, params, 'visual'); }, + unmap: function(cm, params, ctx) { + var mapArgs = params.args; + if (!mapArgs || mapArgs.length < 1) { + if (cm) { + showConfirm(cm, 'No such mapping: ' + params.input); + } + return; + } + exCommandDispatcher.unmap(mapArgs[0], ctx); + }, + move: function(cm, params) { + commandDispatcher.processCommand(cm, cm.state.vim, { + type: 'motion', + motion: 'moveToLineOrEdgeOfDocument', + motionArgs: { forward: false, explicitRepeat: true, + linewise: true }, + repeatOverride: params.line+1}); + }, + set: function(cm, params) { + var setArgs = params.args; + var setCfg = params.setCfg || {}; + if (!setArgs || setArgs.length < 1) { + if (cm) { + showConfirm(cm, 'Invalid mapping: ' + params.input); + } + return; + } + var expr = setArgs[0].split('='); + var optionName = expr[0]; + var value = expr[1]; + var forceGet = false; + + if (optionName.charAt(optionName.length - 1) == '?') { + if (value) { throw Error('Trailing characters: ' + params.argString); } + optionName = optionName.substring(0, optionName.length - 1); + forceGet = true; + } + if (value === undefined && optionName.substring(0, 2) == 'no') { + optionName = optionName.substring(2); + value = false; + } + + var optionIsBoolean = options[optionName] && options[optionName].type == 'boolean'; + if (optionIsBoolean && value == undefined) { + value = true; + } + if (!optionIsBoolean && value === undefined || forceGet) { + var oldValue = getOption(optionName, cm, setCfg); + if (oldValue instanceof Error) { + showConfirm(cm, oldValue.message); + } else if (oldValue === true || oldValue === false) { + showConfirm(cm, ' ' + (oldValue ? '' : 'no') + optionName); + } else { + showConfirm(cm, ' ' + optionName + '=' + oldValue); + } + } else { + var setOptionReturn = setOption(optionName, value, cm, setCfg); + if (setOptionReturn instanceof Error) { + showConfirm(cm, setOptionReturn.message); + } + } + }, + setlocal: function (cm, params) { + params.setCfg = {scope: 'local'}; + this.set(cm, params); + }, + setglobal: function (cm, params) { + params.setCfg = {scope: 'global'}; + this.set(cm, params); + }, + registers: function(cm, params) { + var regArgs = params.args; + var registers = vimGlobalState.registerController.registers; + var regInfo = '----------Registers----------

'; + if (!regArgs) { + for (var registerName in registers) { + var text = registers[registerName].toString(); + if (text.length) { + regInfo += '"' + registerName + ' ' + text + '
'; + } + } + } else { + var registerName; + regArgs = regArgs.join(''); + for (var i = 0; i < regArgs.length; i++) { + registerName = regArgs.charAt(i); + if (!vimGlobalState.registerController.isValidRegister(registerName)) { + continue; + } + var register = registers[registerName] || new Register(); + regInfo += '"' + registerName + ' ' + register.toString() + '
'; + } + } + showConfirm(cm, regInfo); + }, + sort: function(cm, params) { + var reverse, ignoreCase, unique, number, pattern; + function parseArgs() { + if (params.argString) { + var args = new CodeMirror.StringStream(params.argString); + if (args.eat('!')) { reverse = true; } + if (args.eol()) { return; } + if (!args.eatSpace()) { return 'Invalid arguments'; } + var opts = args.match(/([dinuox]+)?\s*(\/.+\/)?\s*/); + if (!opts && !args.eol()) { return 'Invalid arguments'; } + if (opts[1]) { + ignoreCase = opts[1].indexOf('i') != -1; + unique = opts[1].indexOf('u') != -1; + var decimal = opts[1].indexOf('d') != -1 || opts[1].indexOf('n') != -1 && 1; + var hex = opts[1].indexOf('x') != -1 && 1; + var octal = opts[1].indexOf('o') != -1 && 1; + if (decimal + hex + octal > 1) { return 'Invalid arguments'; } + number = decimal && 'decimal' || hex && 'hex' || octal && 'octal'; + } + if (opts[2]) { + pattern = new RegExp(opts[2].substr(1, opts[2].length - 2), ignoreCase ? 'i' : ''); + } + } + } + var err = parseArgs(); + if (err) { + showConfirm(cm, err + ': ' + params.argString); + return; + } + var lineStart = params.line || cm.firstLine(); + var lineEnd = params.lineEnd || params.line || cm.lastLine(); + if (lineStart == lineEnd) { return; } + var curStart = Pos(lineStart, 0); + var curEnd = Pos(lineEnd, lineLength(cm, lineEnd)); + var text = cm.getRange(curStart, curEnd).split('\n'); + var numberRegex = pattern ? pattern : + (number == 'decimal') ? /(-?)([\d]+)/ : + (number == 'hex') ? /(-?)(?:0x)?([0-9a-f]+)/i : + (number == 'octal') ? /([0-7]+)/ : null; + var radix = (number == 'decimal') ? 10 : (number == 'hex') ? 16 : (number == 'octal') ? 8 : null; + var numPart = [], textPart = []; + if (number || pattern) { + for (var i = 0; i < text.length; i++) { + var matchPart = pattern ? text[i].match(pattern) : null; + if (matchPart && matchPart[0] != '') { + numPart.push(matchPart); + } else if (!pattern && numberRegex.exec(text[i])) { + numPart.push(text[i]); + } else { + textPart.push(text[i]); + } + } + } else { + textPart = text; + } + function compareFn(a, b) { + if (reverse) { var tmp; tmp = a; a = b; b = tmp; } + if (ignoreCase) { a = a.toLowerCase(); b = b.toLowerCase(); } + var anum = number && numberRegex.exec(a); + var bnum = number && numberRegex.exec(b); + if (!anum) { return a < b ? -1 : 1; } + anum = parseInt((anum[1] + anum[2]).toLowerCase(), radix); + bnum = parseInt((bnum[1] + bnum[2]).toLowerCase(), radix); + return anum - bnum; + } + function comparePatternFn(a, b) { + if (reverse) { var tmp; tmp = a; a = b; b = tmp; } + if (ignoreCase) { a[0] = a[0].toLowerCase(); b[0] = b[0].toLowerCase(); } + return (a[0] < b[0]) ? -1 : 1; + } + numPart.sort(pattern ? comparePatternFn : compareFn); + if (pattern) { + for (var i = 0; i < numPart.length; i++) { + numPart[i] = numPart[i].input; + } + } else if (!number) { textPart.sort(compareFn); } + text = (!reverse) ? textPart.concat(numPart) : numPart.concat(textPart); + if (unique) { // Remove duplicate lines + var textOld = text; + var lastLine; + text = []; + for (var i = 0; i < textOld.length; i++) { + if (textOld[i] != lastLine) { + text.push(textOld[i]); + } + lastLine = textOld[i]; + } + } + cm.replaceRange(text.join('\n'), curStart, curEnd); + }, + global: function(cm, params) { + var argString = params.argString; + if (!argString) { + showConfirm(cm, 'Regular Expression missing from global'); + return; + } + var lineStart = (params.line !== undefined) ? params.line : cm.firstLine(); + var lineEnd = params.lineEnd || params.line || cm.lastLine(); + var tokens = splitBySlash(argString); + var regexPart = argString, cmd; + if (tokens.length) { + regexPart = tokens[0]; + cmd = tokens.slice(1, tokens.length).join('/'); + } + if (regexPart) { + try { + updateSearchQuery(cm, regexPart, true /** ignoreCase */, + true /** smartCase */); + } catch (e) { + showConfirm(cm, 'Invalid regex: ' + regexPart); + return; + } + } + var query = getSearchState(cm).getQuery(); + var matchedLines = [], content = ''; + for (var i = lineStart; i <= lineEnd; i++) { + var matched = query.test(cm.getLine(i)); + if (matched) { + matchedLines.push(i+1); + content+= cm.getLine(i) + '
'; + } + } + if (!cmd) { + showConfirm(cm, content); + return; + } + var index = 0; + var nextCommand = function() { + if (index < matchedLines.length) { + var command = matchedLines[index] + cmd; + exCommandDispatcher.processCommand(cm, command, { + callback: nextCommand + }); + } + index++; + }; + nextCommand(); + }, + substitute: function(cm, params) { + if (!cm.getSearchCursor) { + throw new Error('Search feature not available. Requires searchcursor.js or ' + + 'any other getSearchCursor implementation.'); + } + var argString = params.argString; + var tokens = argString ? splitBySeparator(argString, argString[0]) : []; + var regexPart, replacePart = '', trailing, flagsPart, count; + var confirm = false; // Whether to confirm each replace. + var global = false; // True to replace all instances on a line, false to replace only 1. + if (tokens.length) { + regexPart = tokens[0]; + replacePart = tokens[1]; + if (regexPart && regexPart[regexPart.length - 1] === '$') { + regexPart = regexPart.slice(0, regexPart.length - 1) + '\\n'; + replacePart = replacePart ? replacePart + '\n' : '\n'; + } + if (replacePart !== undefined) { + if (getOption('pcre')) { + replacePart = unescapeRegexReplace(replacePart); + } else { + replacePart = translateRegexReplace(replacePart); + } + vimGlobalState.lastSubstituteReplacePart = replacePart; + } + trailing = tokens[2] ? tokens[2].split(' ') : []; + } else { + if (argString && argString.length) { + showConfirm(cm, 'Substitutions should be of the form ' + + ':s/pattern/replace/'); + return; + } + } + if (trailing) { + flagsPart = trailing[0]; + count = parseInt(trailing[1]); + if (flagsPart) { + if (flagsPart.indexOf('c') != -1) { + confirm = true; + flagsPart.replace('c', ''); + } + if (flagsPart.indexOf('g') != -1) { + global = true; + flagsPart.replace('g', ''); + } + regexPart = regexPart.replace(/\//g, "\\/") + '/' + flagsPart; + } + } + if (regexPart) { + try { + updateSearchQuery(cm, regexPart, true /** ignoreCase */, + true /** smartCase */); + } catch (e) { + showConfirm(cm, 'Invalid regex: ' + regexPart); + return; + } + } + replacePart = replacePart || vimGlobalState.lastSubstituteReplacePart; + if (replacePart === undefined) { + showConfirm(cm, 'No previous substitute regular expression'); + return; + } + var state = getSearchState(cm); + var query = state.getQuery(); + var lineStart = (params.line !== undefined) ? params.line : cm.getCursor().line; + var lineEnd = params.lineEnd || lineStart; + if (lineStart == cm.firstLine() && lineEnd == cm.lastLine()) { + lineEnd = Infinity; + } + if (count) { + lineStart = lineEnd; + lineEnd = lineStart + count - 1; + } + var startPos = clipCursorToContent(cm, Pos(lineStart, 0)); + var cursor = cm.getSearchCursor(query, startPos); + doReplace(cm, confirm, global, lineStart, lineEnd, cursor, query, replacePart, params.callback); + }, + redo: CodeMirror.commands.redo, + undo: CodeMirror.commands.undo, + write: function(cm) { + if (CodeMirror.commands.save) { + CodeMirror.commands.save(cm); + } else if (cm.save) { + cm.save(); + } + }, + nohlsearch: function(cm) { + clearSearchHighlight(cm); + }, + yank: function (cm) { + var cur = copyCursor(cm.getCursor()); + var line = cur.line; + var lineText = cm.getLine(line); + vimGlobalState.registerController.pushText( + '0', 'yank', lineText, true, true); + }, + delmarks: function(cm, params) { + if (!params.argString || !trim(params.argString)) { + showConfirm(cm, 'Argument required'); + return; + } + + var state = cm.state.vim; + var stream = new CodeMirror.StringStream(trim(params.argString)); + while (!stream.eol()) { + stream.eatSpace(); + var count = stream.pos; + + if (!stream.match(/[a-zA-Z]/, false)) { + showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count)); + return; + } + + var sym = stream.next(); + if (stream.match('-', true)) { + if (!stream.match(/[a-zA-Z]/, false)) { + showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count)); + return; + } + + var startMark = sym; + var finishMark = stream.next(); + if (isLowerCase(startMark) && isLowerCase(finishMark) || + isUpperCase(startMark) && isUpperCase(finishMark)) { + var start = startMark.charCodeAt(0); + var finish = finishMark.charCodeAt(0); + if (start >= finish) { + showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count)); + return; + } + for (var j = 0; j <= finish - start; j++) { + var mark = String.fromCharCode(start + j); + delete state.marks[mark]; + } + } else { + showConfirm(cm, 'Invalid argument: ' + startMark + '-'); + return; + } + } else { + delete state.marks[sym]; + } + } + } + }; + + var exCommandDispatcher = new ExCommandDispatcher(); + function doReplace(cm, confirm, global, lineStart, lineEnd, searchCursor, query, + replaceWith, callback) { + cm.state.vim.exMode = true; + var done = false; + var lastPos = searchCursor.from(); + function replaceAll() { + cm.operation(function() { + while (!done) { + replace(); + next(); + } + stop(); + }); + } + function replace() { + var text = cm.getRange(searchCursor.from(), searchCursor.to()); + var newText = text.replace(query, replaceWith); + searchCursor.replace(newText); + } + function next() { + while(searchCursor.findNext() && + isInRange(searchCursor.from(), lineStart, lineEnd)) { + if (!global && lastPos && searchCursor.from().line == lastPos.line) { + continue; + } + cm.scrollIntoView(searchCursor.from(), 30); + cm.setSelection(searchCursor.from(), searchCursor.to()); + lastPos = searchCursor.from(); + done = false; + return; + } + done = true; + } + function stop(close) { + if (close) { close(); } + cm.focus(); + if (lastPos) { + cm.setCursor(lastPos); + var vim = cm.state.vim; + vim.exMode = false; + vim.lastHPos = vim.lastHSPos = lastPos.ch; + } + if (callback) { callback(); } + } + function onPromptKeyDown(e, _value, close) { + CodeMirror.e_stop(e); + var keyName = CodeMirror.keyName(e); + switch (keyName) { + case 'Y': + replace(); next(); break; + case 'N': + next(); break; + case 'A': + var savedCallback = callback; + callback = undefined; + cm.operation(replaceAll); + callback = savedCallback; + break; + case 'L': + replace(); + case 'Q': + case 'Esc': + case 'Ctrl-C': + case 'Ctrl-[': + stop(close); + break; + } + if (done) { stop(close); } + return true; + } + next(); + if (done) { + showConfirm(cm, 'No matches for ' + query.source); + return; + } + if (!confirm) { + replaceAll(); + if (callback) { callback(); } + return; + } + showPrompt(cm, { + prefix: 'replace with ' + replaceWith + ' (y/n/a/q/l)', + onKeyDown: onPromptKeyDown + }); + } + + CodeMirror.keyMap.vim = { + attach: attachVimMap, + detach: detachVimMap, + call: cmKey + }; + + function exitInsertMode(cm) { + var vim = cm.state.vim; + var macroModeState = vimGlobalState.macroModeState; + var insertModeChangeRegister = vimGlobalState.registerController.getRegister('.'); + var isPlaying = macroModeState.isPlaying; + var lastChange = macroModeState.lastInsertModeChanges; + if (!isPlaying) { + cm.off('change', onChange); + CodeMirror.off(cm.getInputField(), 'keydown', onKeyEventTargetKeyDown); + } + if (!isPlaying && vim.insertModeRepeat > 1) { + repeatLastEdit(cm, vim, vim.insertModeRepeat - 1, + true /** repeatForInsert */); + vim.lastEditInputState.repeatOverride = vim.insertModeRepeat; + } + delete vim.insertModeRepeat; + vim.insertMode = false; + cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1); + cm.setOption('keyMap', 'vim'); + cm.setOption('disableInput', true); + cm.toggleOverwrite(false); // exit replace mode if we were in it. + insertModeChangeRegister.setText(lastChange.changes.join('')); + CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"}); + if (macroModeState.isRecording) { + logInsertModeChange(macroModeState); + } + } + + function _mapCommand(command) { + defaultKeymap.unshift(command); + } + + function mapCommand(keys, type, name, args, extra) { + var command = {keys: keys, type: type}; + command[type] = name; + command[type + "Args"] = args; + for (var key in extra) + command[key] = extra[key]; + _mapCommand(command); + } + defineOption('insertModeEscKeysTimeout', 200, 'number'); + + CodeMirror.keyMap['vim-insert'] = { + fallthrough: ['default'], + attach: attachVimMap, + detach: detachVimMap, + call: cmKey + }; + + CodeMirror.keyMap['vim-replace'] = { + 'Backspace': 'goCharLeft', + fallthrough: ['vim-insert'], + attach: attachVimMap, + detach: detachVimMap, + call: cmKey + }; + + function executeMacroRegister(cm, vim, macroModeState, registerName) { + var register = vimGlobalState.registerController.getRegister(registerName); + if (registerName == ':') { + if (register.keyBuffer[0]) { + exCommandDispatcher.processCommand(cm, register.keyBuffer[0]); + } + macroModeState.isPlaying = false; + return; + } + var keyBuffer = register.keyBuffer; + var imc = 0; + macroModeState.isPlaying = true; + macroModeState.replaySearchQueries = register.searchQueries.slice(0); + for (var i = 0; i < keyBuffer.length; i++) { + var text = keyBuffer[i]; + var match, key; + while (text) { + match = (/<\w+-.+?>|<\w+>|./).exec(text); + key = match[0]; + text = text.substring(match.index + key.length); + CodeMirror.Vim.handleKey(cm, key, 'macro'); + if (vim.insertMode) { + var changes = register.insertModeChanges[imc++].changes; + vimGlobalState.macroModeState.lastInsertModeChanges.changes = + changes; + repeatInsertModeChanges(cm, changes, 1); + exitInsertMode(cm); + } + } + } + macroModeState.isPlaying = false; + } + + function logKey(macroModeState, key) { + if (macroModeState.isPlaying) { return; } + var registerName = macroModeState.latestRegister; + var register = vimGlobalState.registerController.getRegister(registerName); + if (register) { + register.pushText(key); + } + } + + function logInsertModeChange(macroModeState) { + if (macroModeState.isPlaying) { return; } + var registerName = macroModeState.latestRegister; + var register = vimGlobalState.registerController.getRegister(registerName); + if (register && register.pushInsertModeChanges) { + register.pushInsertModeChanges(macroModeState.lastInsertModeChanges); + } + } + + function logSearchQuery(macroModeState, query) { + if (macroModeState.isPlaying) { return; } + var registerName = macroModeState.latestRegister; + var register = vimGlobalState.registerController.getRegister(registerName); + if (register && register.pushSearchQuery) { + register.pushSearchQuery(query); + } + } + function onChange(cm, changeObj) { + var macroModeState = vimGlobalState.macroModeState; + var lastChange = macroModeState.lastInsertModeChanges; + if (!macroModeState.isPlaying) { + while(changeObj) { + lastChange.expectCursorActivityForChange = true; + if (lastChange.ignoreCount > 1) { + lastChange.ignoreCount--; + } else if (changeObj.origin == '+input' || changeObj.origin == 'paste' + || changeObj.origin === undefined /* only in testing */) { + var selectionCount = cm.listSelections().length; + if (selectionCount > 1) + lastChange.ignoreCount = selectionCount; + var text = changeObj.text.join('\n'); + if (lastChange.maybeReset) { + lastChange.changes = []; + lastChange.maybeReset = false; + } + if (text) { + if (cm.state.overwrite && !/\n/.test(text)) { + lastChange.changes.push([text]); + } else { + lastChange.changes.push(text); + } + } + } + changeObj = changeObj.next; + } + } + } + function onCursorActivity(cm) { + var vim = cm.state.vim; + if (vim.insertMode) { + var macroModeState = vimGlobalState.macroModeState; + if (macroModeState.isPlaying) { return; } + var lastChange = macroModeState.lastInsertModeChanges; + if (lastChange.expectCursorActivityForChange) { + lastChange.expectCursorActivityForChange = false; + } else { + lastChange.maybeReset = true; + } + } else if (!cm.curOp.isVimOp) { + handleExternalSelection(cm, vim); + } + if (vim.visualMode) { + updateFakeCursor(cm); + } + } + function updateFakeCursor(cm) { + var vim = cm.state.vim; + var from = clipCursorToContent(cm, copyCursor(vim.sel.head)); + var to = offsetCursor(from, 0, 1); + if (vim.fakeCursor) { + vim.fakeCursor.clear(); + } + vim.fakeCursor = cm.markText(from, to, {className: 'cm-animate-fat-cursor'}); + } + function handleExternalSelection(cm, vim, keepHPos) { + var anchor = cm.getCursor('anchor'); + var head = cm.getCursor('head'); + if (vim.visualMode && !cm.somethingSelected()) { + exitVisualMode(cm, false); + } else if (!vim.visualMode && !vim.insertMode && cm.somethingSelected()) { + vim.visualMode = true; + vim.visualLine = false; + CodeMirror.signal(cm, "vim-mode-change", {mode: "visual"}); + } + if (vim.visualMode) { + var headOffset = !cursorIsBefore(head, anchor) ? -1 : 0; + var anchorOffset = cursorIsBefore(head, anchor) ? -1 : 0; + head = offsetCursor(head, 0, headOffset); + anchor = offsetCursor(anchor, 0, anchorOffset); + vim.sel = { + anchor: anchor, + head: head + }; + updateMark(cm, vim, '<', cursorMin(head, anchor)); + updateMark(cm, vim, '>', cursorMax(head, anchor)); + } else if (!vim.insertMode && !keepHPos) { + vim.lastHPos = cm.getCursor().ch; + } + } + function InsertModeKey(keyName) { + this.keyName = keyName; + } + function onKeyEventTargetKeyDown(e) { + var macroModeState = vimGlobalState.macroModeState; + var lastChange = macroModeState.lastInsertModeChanges; + var keyName = CodeMirror.keyName(e); + if (!keyName) { return; } + function onKeyFound() { + if (lastChange.maybeReset) { + lastChange.changes = []; + lastChange.maybeReset = false; + } + lastChange.changes.push(new InsertModeKey(keyName)); + return true; + } + if (keyName.indexOf('Delete') != -1 || keyName.indexOf('Backspace') != -1) { + CodeMirror.lookupKey(keyName, 'vim-insert', onKeyFound); + } + } + function repeatLastEdit(cm, vim, repeat, repeatForInsert) { + var macroModeState = vimGlobalState.macroModeState; + macroModeState.isPlaying = true; + var isAction = !!vim.lastEditActionCommand; + var cachedInputState = vim.inputState; + function repeatCommand() { + if (isAction) { + commandDispatcher.processAction(cm, vim, vim.lastEditActionCommand); + } else { + commandDispatcher.evalInput(cm, vim); + } + } + function repeatInsert(repeat) { + if (macroModeState.lastInsertModeChanges.changes.length > 0) { + repeat = !vim.lastEditActionCommand ? 1 : repeat; + var changeObject = macroModeState.lastInsertModeChanges; + repeatInsertModeChanges(cm, changeObject.changes, repeat); + } + } + vim.inputState = vim.lastEditInputState; + if (isAction && vim.lastEditActionCommand.interlaceInsertRepeat) { + for (var i = 0; i < repeat; i++) { + repeatCommand(); + repeatInsert(1); + } + } else { + if (!repeatForInsert) { + repeatCommand(); + } + repeatInsert(repeat); + } + vim.inputState = cachedInputState; + if (vim.insertMode && !repeatForInsert) { + exitInsertMode(cm); + } + macroModeState.isPlaying = false; + } + + function repeatInsertModeChanges(cm, changes, repeat) { + function keyHandler(binding) { + if (typeof binding == 'string') { + CodeMirror.commands[binding](cm); + } else { + binding(cm); + } + return true; + } + var head = cm.getCursor('head'); + var visualBlock = vimGlobalState.macroModeState.lastInsertModeChanges.visualBlock; + if (visualBlock) { + selectForInsert(cm, head, visualBlock + 1); + repeat = cm.listSelections().length; + cm.setCursor(head); + } + for (var i = 0; i < repeat; i++) { + if (visualBlock) { + cm.setCursor(offsetCursor(head, i, 0)); + } + for (var j = 0; j < changes.length; j++) { + var change = changes[j]; + if (change instanceof InsertModeKey) { + CodeMirror.lookupKey(change.keyName, 'vim-insert', keyHandler); + } else if (typeof change == "string") { + var cur = cm.getCursor(); + cm.replaceRange(change, cur, cur); + } else { + var start = cm.getCursor(); + var end = offsetCursor(start, 0, change[0].length); + cm.replaceRange(change[0], start, end); + } + } + } + if (visualBlock) { + cm.setCursor(offsetCursor(head, 0, 1)); + } + } + + resetVimGlobalState(); + CodeMirror.Vim = Vim(); + + Vim = CodeMirror.Vim; + + var specialKey = {'return':'CR',backspace:'BS','delete':'Del',esc:'Esc', + left:'Left',right:'Right',up:'Up',down:'Down',space: 'Space', + home:'Home',end:'End',pageup:'PageUp',pagedown:'PageDown', enter: 'CR' + }; + function lookupKey(hashId, key, e) { + if (key.length > 1 && key[0] == "n") { + key = key.replace("numpad", ""); + } + key = specialKey[key] || key; + var name = ''; + if (e.ctrlKey) { name += 'C-'; } + if (e.altKey) { name += 'A-'; } + if ((name || key.length > 1) && e.shiftKey) { name += 'S-'; } + + name += key; + if (name.length > 1) { name = '<' + name + '>'; } + return name; + } + var handleKey = Vim.handleKey.bind(Vim); + Vim.handleKey = function(cm, key, origin) { + return cm.operation(function() { + return handleKey(cm, key, origin); + }, true); + } + function cloneVimState(state) { + var n = new state.constructor(); + Object.keys(state).forEach(function(key) { + var o = state[key]; + if (Array.isArray(o)) + o = o.slice(); + else if (o && typeof o == "object" && o.constructor != Object) + o = cloneVimState(o); + n[key] = o; + }); + if (state.sel) { + n.sel = { + head: state.sel.head && copyCursor(state.sel.head), + anchor: state.sel.anchor && copyCursor(state.sel.anchor) + }; + } + return n; + } + function multiSelectHandleKey(cm, key, origin) { + var isHandled = false; + var vim = Vim.maybeInitVimState_(cm); + var visualBlock = vim.visualBlock || vim.wasInVisualBlock; + + var wasMultiselect = cm.ace.inMultiSelectMode; + if (vim.wasInVisualBlock && !wasMultiselect) { + vim.wasInVisualBlock = false; + } else if (wasMultiselect && vim.visualBlock) { + vim.wasInVisualBlock = true; + } + + if (key == '' && !vim.insertMode && !vim.visualMode && wasMultiselect) { + cm.ace.exitMultiSelectMode(); + } else if (visualBlock || !wasMultiselect || cm.ace.inVirtualSelectionMode) { + isHandled = Vim.handleKey(cm, key, origin); + } else { + var old = cloneVimState(vim); + cm.operation(function() { + cm.ace.forEachSelection(function() { + var sel = cm.ace.selection; + cm.state.vim.lastHPos = sel.$desiredColumn == null ? sel.lead.column : sel.$desiredColumn; + var head = cm.getCursor("head"); + var anchor = cm.getCursor("anchor"); + var headOffset = !cursorIsBefore(head, anchor) ? -1 : 0; + var anchorOffset = cursorIsBefore(head, anchor) ? -1 : 0; + head = offsetCursor(head, 0, headOffset); + anchor = offsetCursor(anchor, 0, anchorOffset); + cm.state.vim.sel.head = head; + cm.state.vim.sel.anchor = anchor; + + isHandled = handleKey(cm, key, origin); + sel.$desiredColumn = cm.state.vim.lastHPos == -1 ? null : cm.state.vim.lastHPos; + if (cm.virtualSelectionMode()) { + cm.state.vim = cloneVimState(old); + } + }); + if (cm.curOp.cursorActivity && !isHandled) + cm.curOp.cursorActivity = false; + }, true); + } + if (isHandled && !vim.visualMode && !vim.insert && vim.visualMode != cm.somethingSelected()) { + handleExternalSelection(cm, vim, true); + } + return isHandled; + } + exports.CodeMirror = CodeMirror; + var getVim = Vim.maybeInitVimState_; + exports.handler = { + $id: "ace/keyboard/vim", + drawCursor: function(element, pixelPos, config, sel, session) { + var vim = this.state.vim || {}; + var w = config.characterWidth; + var h = config.lineHeight; + var top = pixelPos.top; + var left = pixelPos.left; + if (!vim.insertMode) { + var isbackwards = !sel.cursor + ? session.selection.isBackwards() || session.selection.isEmpty() + : Range.comparePoints(sel.cursor, sel.start) <= 0; + if (!isbackwards && left > w) + left -= w; + } + if (!vim.insertMode && vim.status) { + h = h / 2; + top += h; + } + dom.translate(element, left, top); + dom.setStyle(element.style, "width", w + "px"); + dom.setStyle(element.style, "height", h + "px"); + }, + handleKeyboard: function(data, hashId, key, keyCode, e) { + var editor = data.editor; + var cm = editor.state.cm; + var vim = getVim(cm); + if (keyCode == -1) return; + if (!vim.insertMode) { + if (hashId == -1) { + if (key.charCodeAt(0) > 0xFF) { + if (data.inputKey) { + key = data.inputKey; + if (key && data.inputHash == 4) + key = key.toUpperCase(); + } + } + data.inputChar = key; + } + else if (hashId == 4 || hashId == 0) { + if (data.inputKey == key && data.inputHash == hashId && data.inputChar) { + key = data.inputChar; + hashId = -1 + } + else { + data.inputChar = null; + data.inputKey = key; + data.inputHash = hashId; + } + } + else { + data.inputChar = data.inputKey = null; + } + } + if (key == "c" && hashId == 1) { // key == "ctrl-c" + if (!useragent.isMac && editor.getCopyText()) { + editor.once("copy", function() { + editor.selection.clearSelection(); + }); + return {command: "null", passEvent: true}; + } + } + + if (key == "esc" && !vim.insertMode && !vim.visualMode && !cm.ace.inMultiSelectMode) { + var searchState = getSearchState(cm); + var overlay = searchState.getOverlay(); + if (overlay) cm.removeOverlay(overlay); + } + + if (hashId == -1 || hashId & 1 || hashId === 0 && key.length > 1) { + var insertMode = vim.insertMode; + var name = lookupKey(hashId, key, e || {}); + if (vim.status == null) + vim.status = ""; + var isHandled = multiSelectHandleKey(cm, name, 'user'); + vim = getVim(cm); // may be changed by multiSelectHandleKey + if (isHandled && vim.status != null) + vim.status += name; + else if (vim.status == null) + vim.status = ""; + cm._signal("changeStatus"); + if (!isHandled && (hashId != -1 || insertMode)) + return; + return {command: "null", passEvent: !isHandled}; + } + }, + attach: function(editor) { + if (!editor.state) editor.state = {}; + var cm = new CodeMirror(editor); + editor.state.cm = cm; + editor.$vimModeHandler = this; + CodeMirror.keyMap.vim.attach(cm); + getVim(cm).status = null; + cm.on('vim-command-done', function() { + if (cm.virtualSelectionMode()) return; + getVim(cm).status = null; + cm.ace._signal("changeStatus"); + cm.ace.session.markUndoGroup(); + }); + cm.on("changeStatus", function() { + cm.ace.renderer.updateCursor(); + cm.ace._signal("changeStatus"); + }); + cm.on("vim-mode-change", function() { + if (cm.virtualSelectionMode()) return; + updateInputMode(); + cm._signal("changeStatus"); + }); + function updateInputMode() { + var isIntsert = getVim(cm).insertMode; + cm.ace.renderer.setStyle("normal-mode", !isIntsert); + editor.textInput.setCommandMode(!isIntsert); + editor.renderer.$keepTextAreaAtCursor = isIntsert; + editor.renderer.$blockCursor = !isIntsert; + } + updateInputMode(); + editor.renderer.$cursorLayer.drawCursor = this.drawCursor.bind(cm); + }, + detach: function(editor) { + var cm = editor.state.cm; + CodeMirror.keyMap.vim.detach(cm); + cm.destroy(); + editor.state.cm = null; + editor.$vimModeHandler = null; + editor.renderer.$cursorLayer.drawCursor = null; + editor.renderer.setStyle("normal-mode", false); + editor.textInput.setCommandMode(false); + editor.renderer.$keepTextAreaAtCursor = true; + }, + getStatusText: function(editor) { + var cm = editor.state.cm; + var vim = getVim(cm); + if (vim.insertMode) + return "INSERT"; + var status = ""; + if (vim.visualMode) { + status += "VISUAL"; + if (vim.visualLine) + status += " LINE"; + if (vim.visualBlock) + status += " BLOCK"; + } + if (vim.status) + status += (status ? " " : "") + vim.status; + return status; + } + }; + Vim.defineOption({ + name: "wrap", + set: function(value, cm) { + if (cm) {cm.ace.setOption("wrap", value)} + }, + type: "boolean" + }, false); + Vim.defineEx('write', 'w', function() { + console.log(':write is not implemented') + }); + defaultKeymap.push( + { keys: 'zc', type: 'action', action: 'fold', actionArgs: { open: false } }, + { keys: 'zC', type: 'action', action: 'fold', actionArgs: { open: false, all: true } }, + { keys: 'zo', type: 'action', action: 'fold', actionArgs: { open: true } }, + { keys: 'zO', type: 'action', action: 'fold', actionArgs: { open: true, all: true } }, + { keys: 'za', type: 'action', action: 'fold', actionArgs: { toggle: true } }, + { keys: 'zA', type: 'action', action: 'fold', actionArgs: { toggle: true, all: true } }, + { keys: 'zf', type: 'action', action: 'fold', actionArgs: { open: true, all: true } }, + { keys: 'zd', type: 'action', action: 'fold', actionArgs: { open: true, all: true } }, + + { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorAbove" } }, + { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorBelow" } }, + { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorAboveSkipCurrent" } }, + { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorBelowSkipCurrent" } }, + { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "selectMoreBefore" } }, + { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "selectMoreAfter" } }, + { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "selectNextBefore" } }, + { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "selectNextAfter" } } + ); + actions.aceCommand = function(cm, actionArgs, vim) { + cm.vimCmd = actionArgs; + if (cm.ace.inVirtualSelectionMode) + cm.ace.on("beforeEndOperation", delayedExecAceCommand); + else + delayedExecAceCommand(null, cm.ace); + }; + function delayedExecAceCommand(op, ace) { + ace.off("beforeEndOperation", delayedExecAceCommand); + var cmd = ace.state.cm.vimCmd; + if (cmd) { + ace.execCommand(cmd.exec ? cmd : cmd.name, cmd.args); + } + ace.curOp = ace.prevOp; + } + actions.fold = function(cm, actionArgs, vim) { + cm.ace.execCommand(['toggleFoldWidget', 'toggleFoldWidget', 'foldOther', 'unfoldall' + ][(actionArgs.all ? 2 : 0) + (actionArgs.open ? 1 : 0)]); + }; + + exports.handler.defaultKeymap = defaultKeymap; + exports.handler.actions = actions; + exports.Vim = Vim; +}); (function() { + window.require(["ace/keyboard/vim"], function(m) { + if (typeof module == "object" && typeof exports == "object" && module) { + module.exports = m; + } + }); + })(); + \ No newline at end of file diff --git a/ace/mode-javascript.js b/ace/mode-javascript.js new file mode 100644 index 0000000..f9640e8 --- /dev/null +++ b/ace/mode-javascript.js @@ -0,0 +1,797 @@ +define("ace/mode/doc_comment_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"], function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var DocCommentHighlightRules = function() { + this.$rules = { + "start" : [ { + token : "comment.doc.tag", + regex : "@[\\w\\d_]+" // TODO: fix email addresses + }, + DocCommentHighlightRules.getTagRule(), + { + defaultToken : "comment.doc", + caseInsensitive: true + }] + }; +}; + +oop.inherits(DocCommentHighlightRules, TextHighlightRules); + +DocCommentHighlightRules.getTagRule = function(start) { + return { + token : "comment.doc.tag.storage.type", + regex : "\\b(?:TODO|FIXME|XXX|HACK)\\b" + }; +}; + +DocCommentHighlightRules.getStartRule = function(start) { + return { + token : "comment.doc", // doc comment + regex : "\\/\\*(?=\\*)", + next : start + }; +}; + +DocCommentHighlightRules.getEndRule = function (start) { + return { + token : "comment.doc", // closing comment + regex : "\\*\\/", + next : start + }; +}; + + +exports.DocCommentHighlightRules = DocCommentHighlightRules; + +}); + +define("ace/mode/javascript_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/doc_comment_highlight_rules","ace/mode/text_highlight_rules"], function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var DocCommentHighlightRules = require("./doc_comment_highlight_rules").DocCommentHighlightRules; +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; +var identifierRe = "[a-zA-Z\\$_\u00a1-\uffff][a-zA-Z\\d\\$_\u00a1-\uffff]*"; + +var JavaScriptHighlightRules = function(options) { + var keywordMapper = this.createKeywordMapper({ + "variable.language": + "Array|Boolean|Date|Function|Iterator|Number|Object|RegExp|String|Proxy|" + // Constructors + "Namespace|QName|XML|XMLList|" + // E4X + "ArrayBuffer|Float32Array|Float64Array|Int16Array|Int32Array|Int8Array|" + + "Uint16Array|Uint32Array|Uint8Array|Uint8ClampedArray|" + + "Error|EvalError|InternalError|RangeError|ReferenceError|StopIteration|" + // Errors + "SyntaxError|TypeError|URIError|" + + "decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|eval|isFinite|" + // Non-constructor functions + "isNaN|parseFloat|parseInt|" + + "JSON|Math|" + // Other + "this|arguments|prototype|window|document" , // Pseudo + "keyword": + "const|yield|import|get|set|async|await|" + + "break|case|catch|continue|default|delete|do|else|finally|for|function|" + + "if|in|of|instanceof|new|return|switch|throw|try|typeof|let|var|while|with|debugger|" + + "__parent__|__count__|escape|unescape|with|__proto__|" + + "class|enum|extends|super|export|implements|private|public|interface|package|protected|static", + "storage.type": + "const|let|var|function", + "constant.language": + "null|Infinity|NaN|undefined", + "support.function": + "alert", + "constant.language.boolean": "true|false" + }, "identifier"); + var kwBeforeRe = "case|do|else|finally|in|instanceof|return|throw|try|typeof|yield|void"; + + var escapedRe = "\\\\(?:x[0-9a-fA-F]{2}|" + // hex + "u[0-9a-fA-F]{4}|" + // unicode + "u{[0-9a-fA-F]{1,6}}|" + // es6 unicode + "[0-2][0-7]{0,2}|" + // oct + "3[0-7][0-7]?|" + // oct + "[4-7][0-7]?|" + //oct + ".)"; + + this.$rules = { + "no_regex" : [ + DocCommentHighlightRules.getStartRule("doc-start"), + comments("no_regex"), + { + token : "string", + regex : "'(?=.)", + next : "qstring" + }, { + token : "string", + regex : '"(?=.)', + next : "qqstring" + }, { + token : "constant.numeric", // hexadecimal, octal and binary + regex : /0(?:[xX][0-9a-fA-F]+|[oO][0-7]+|[bB][01]+)\b/ + }, { + token : "constant.numeric", // decimal integers and floats + regex : /(?:\d\d*(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+\b)?/ + }, { + token : [ + "storage.type", "punctuation.operator", "support.function", + "punctuation.operator", "entity.name.function", "text","keyword.operator" + ], + regex : "(" + identifierRe + ")(\\.)(prototype)(\\.)(" + identifierRe +")(\\s*)(=)", + next: "function_arguments" + }, { + token : [ + "storage.type", "punctuation.operator", "entity.name.function", "text", + "keyword.operator", "text", "storage.type", "text", "paren.lparen" + ], + regex : "(" + identifierRe + ")(\\.)(" + identifierRe +")(\\s*)(=)(\\s*)(function)(\\s*)(\\()", + next: "function_arguments" + }, { + token : [ + "entity.name.function", "text", "keyword.operator", "text", "storage.type", + "text", "paren.lparen" + ], + regex : "(" + identifierRe +")(\\s*)(=)(\\s*)(function)(\\s*)(\\()", + next: "function_arguments" + }, { + token : [ + "storage.type", "punctuation.operator", "entity.name.function", "text", + "keyword.operator", "text", + "storage.type", "text", "entity.name.function", "text", "paren.lparen" + ], + regex : "(" + identifierRe + ")(\\.)(" + identifierRe +")(\\s*)(=)(\\s*)(function)(\\s+)(\\w+)(\\s*)(\\()", + next: "function_arguments" + }, { + token : [ + "storage.type", "text", "entity.name.function", "text", "paren.lparen" + ], + regex : "(function)(\\s+)(" + identifierRe + ")(\\s*)(\\()", + next: "function_arguments" + }, { + token : [ + "entity.name.function", "text", "punctuation.operator", + "text", "storage.type", "text", "paren.lparen" + ], + regex : "(" + identifierRe + ")(\\s*)(:)(\\s*)(function)(\\s*)(\\()", + next: "function_arguments" + }, { + token : [ + "text", "text", "storage.type", "text", "paren.lparen" + ], + regex : "(:)(\\s*)(function)(\\s*)(\\()", + next: "function_arguments" + }, { + token : "keyword", + regex : "from(?=\\s*('|\"))" + }, { + token : "keyword", + regex : "(?:" + kwBeforeRe + ")\\b", + next : "start" + }, { + token : ["support.constant"], + regex : /that\b/ + }, { + token : ["storage.type", "punctuation.operator", "support.function.firebug"], + regex : /(console)(\.)(warn|info|log|error|time|trace|timeEnd|assert)\b/ + }, { + token : keywordMapper, + regex : identifierRe + }, { + token : "punctuation.operator", + regex : /[.](?![.])/, + next : "property" + }, { + token : "storage.type", + regex : /=>/, + next : "start" + }, { + token : "keyword.operator", + regex : /--|\+\+|\.{3}|===|==|=|!=|!==|<+=?|>+=?|!|&&|\|\||\?:|[!$%&*+\-~\/^]=?/, + next : "start" + }, { + token : "punctuation.operator", + regex : /[?:,;.]/, + next : "start" + }, { + token : "paren.lparen", + regex : /[\[({]/, + next : "start" + }, { + token : "paren.rparen", + regex : /[\])}]/ + }, { + token: "comment", + regex: /^#!.*$/ + } + ], + property: [{ + token : "text", + regex : "\\s+" + }, { + token : [ + "storage.type", "punctuation.operator", "entity.name.function", "text", + "keyword.operator", "text", + "storage.type", "text", "entity.name.function", "text", "paren.lparen" + ], + regex : "(" + identifierRe + ")(\\.)(" + identifierRe +")(\\s*)(=)(\\s*)(function)(?:(\\s+)(\\w+))?(\\s*)(\\()", + next: "function_arguments" + }, { + token : "punctuation.operator", + regex : /[.](?![.])/ + }, { + token : "support.function", + regex : /(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 : "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|ClassName)|ById)|Attribute(?:Node)?)|blur)\b(?=\()/ + }, { + token : "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 : "identifier", + regex : identifierRe + }, { + regex: "", + token: "empty", + next: "no_regex" + } + ], + "start": [ + DocCommentHighlightRules.getStartRule("doc-start"), + comments("start"), + { + token: "string.regexp", + regex: "\\/", + next: "regex" + }, { + token : "text", + regex : "\\s+|^$", + next : "start" + }, { + token: "empty", + regex: "", + next: "no_regex" + } + ], + "regex": [ + { + token: "regexp.keyword.operator", + regex: "\\\\(?:u[\\da-fA-F]{4}|x[\\da-fA-F]{2}|.)" + }, { + token: "string.regexp", + regex: "/[sxngimy]*", + next: "no_regex" + }, { + token : "invalid", + regex: /\{\d+\b,?\d*\}[+*]|[+*$^?][+*]|[$^][?]|\?{3,}/ + }, { + token : "constant.language.escape", + regex: /\(\?[:=!]|\)|\{\d+\b,?\d*\}|[+*]\?|[()$^+*?.]/ + }, { + token : "constant.language.delimiter", + regex: /\|/ + }, { + token: "constant.language.escape", + regex: /\[\^?/, + next: "regex_character_class" + }, { + token: "empty", + regex: "$", + next: "no_regex" + }, { + defaultToken: "string.regexp" + } + ], + "regex_character_class": [ + { + token: "regexp.charclass.keyword.operator", + regex: "\\\\(?:u[\\da-fA-F]{4}|x[\\da-fA-F]{2}|.)" + }, { + token: "constant.language.escape", + regex: "]", + next: "regex" + }, { + token: "constant.language.escape", + regex: "-" + }, { + token: "empty", + regex: "$", + next: "no_regex" + }, { + defaultToken: "string.regexp.charachterclass" + } + ], + "function_arguments": [ + { + token: "variable.parameter", + regex: identifierRe + }, { + token: "punctuation.operator", + regex: "[, ]+" + }, { + token: "punctuation.operator", + regex: "$" + }, { + token: "empty", + regex: "", + next: "no_regex" + } + ], + "qqstring" : [ + { + token : "constant.language.escape", + regex : escapedRe + }, { + token : "string", + regex : "\\\\$", + consumeLineEnd : true + }, { + token : "string", + regex : '"|$', + next : "no_regex" + }, { + defaultToken: "string" + } + ], + "qstring" : [ + { + token : "constant.language.escape", + regex : escapedRe + }, { + token : "string", + regex : "\\\\$", + consumeLineEnd : true + }, { + token : "string", + regex : "'|$", + next : "no_regex" + }, { + defaultToken: "string" + } + ] + }; + + + if (!options || !options.noES6) { + this.$rules.no_regex.unshift({ + regex: "[{}]", onMatch: function(val, state, stack) { + this.next = val == "{" ? this.nextState : ""; + if (val == "{" && stack.length) { + stack.unshift("start", state); + } + else if (val == "}" && stack.length) { + stack.shift(); + this.next = stack.shift(); + if (this.next.indexOf("string") != -1 || this.next.indexOf("jsx") != -1) + return "paren.quasi.end"; + } + return val == "{" ? "paren.lparen" : "paren.rparen"; + }, + nextState: "start" + }, { + token : "string.quasi.start", + regex : /`/, + push : [{ + token : "constant.language.escape", + regex : escapedRe + }, { + token : "paren.quasi.start", + regex : /\${/, + push : "start" + }, { + token : "string.quasi.end", + regex : /`/, + next : "pop" + }, { + defaultToken: "string.quasi" + }] + }); + + if (!options || options.jsx != false) + JSX.call(this); + } + + this.embedRules(DocCommentHighlightRules, "doc-", + [ DocCommentHighlightRules.getEndRule("no_regex") ]); + + this.normalizeRules(); +}; + +oop.inherits(JavaScriptHighlightRules, TextHighlightRules); + +function JSX() { + var tagRegex = identifierRe.replace("\\d", "\\d\\-"); + var jsxTag = { + onMatch : function(val, state, stack) { + var offset = val.charAt(1) == "/" ? 2 : 1; + if (offset == 1) { + if (state != this.nextState) + stack.unshift(this.next, this.nextState, 0); + else + stack.unshift(this.next); + stack[2]++; + } else if (offset == 2) { + if (state == this.nextState) { + stack[1]--; + if (!stack[1] || stack[1] < 0) { + stack.shift(); + stack.shift(); + } + } + } + return [{ + type: "meta.tag.punctuation." + (offset == 1 ? "" : "end-") + "tag-open.xml", + value: val.slice(0, offset) + }, { + type: "meta.tag.tag-name.xml", + value: val.substr(offset) + }]; + }, + regex : "", + onMatch : function(value, currentState, stack) { + if (currentState == stack[0]) + stack.shift(); + if (value.length == 2) { + if (stack[0] == this.nextState) + stack[1]--; + if (!stack[1] || stack[1] < 0) { + stack.splice(0, 2); + } + } + this.next = stack[0] || "start"; + return [{type: this.token, value: value}]; + }, + nextState: "jsx" + }, + jsxJsRule, + comments("jsxAttributes"), + { + token : "entity.other.attribute-name.xml", + regex : tagRegex + }, { + token : "keyword.operator.attribute-equals.xml", + regex : "=" + }, { + token : "text.tag-whitespace.xml", + regex : "\\s+" + }, { + token : "string.attribute-value.xml", + regex : "'", + stateName : "jsx_attr_q", + push : [ + {token : "string.attribute-value.xml", regex: "'", next: "pop"}, + {include : "reference"}, + {defaultToken : "string.attribute-value.xml"} + ] + }, { + token : "string.attribute-value.xml", + regex : '"', + stateName : "jsx_attr_qq", + push : [ + {token : "string.attribute-value.xml", regex: '"', next: "pop"}, + {include : "reference"}, + {defaultToken : "string.attribute-value.xml"} + ] + }, + jsxTag + ]; + this.$rules.reference = [{ + token : "constant.language.escape.reference.xml", + regex : "(?:&#[0-9]+;)|(?:&#x[0-9a-fA-F]+;)|(?:&[a-zA-Z0-9_:\\.-]+;)" + }]; +} + +function comments(next) { + return [ + { + token : "comment", // multi line comment + regex : /\/\*/, + next: [ + DocCommentHighlightRules.getTagRule(), + {token : "comment", regex : "\\*\\/", next : next || "pop"}, + {defaultToken : "comment", caseInsensitive: true} + ] + }, { + token : "comment", + regex : "\\/\\/", + next: [ + DocCommentHighlightRules.getTagRule(), + {token : "comment", regex : "$|^", next : next || "pop"}, + {defaultToken : "comment", caseInsensitive: true} + ] + } + ]; +} +exports.JavaScriptHighlightRules = JavaScriptHighlightRules; +}); + +define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"], function(require, exports, module) { +"use strict"; + +var Range = require("../range").Range; + +var MatchingBraceOutdent = function() {}; + +(function() { + + this.checkOutdent = function(line, input) { + if (! /^\s+$/.test(line)) + return false; + + return /^\s*\}/.test(input); + }; + + this.autoOutdent = function(doc, row) { + var line = doc.getLine(row); + var match = line.match(/^(\s*\})/); + + if (!match) return 0; + + var column = match[1].length; + var openBracePos = doc.findMatchingBracket({row: row, column: column}); + + if (!openBracePos || openBracePos.row == row) return 0; + + var indent = this.$getIndent(doc.getLine(openBracePos.row)); + doc.replace(new Range(row, 0, row, column-1), indent); + }; + + this.$getIndent = function(line) { + return line.match(/^\s*/)[0]; + }; + +}).call(MatchingBraceOutdent.prototype); + +exports.MatchingBraceOutdent = MatchingBraceOutdent; +}); + +define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"], function(require, exports, module) { +"use strict"; + +var oop = require("../../lib/oop"); +var Range = require("../../range").Range; +var BaseFoldMode = require("./fold_mode").FoldMode; + +var FoldMode = exports.FoldMode = function(commentRegex) { + if (commentRegex) { + this.foldingStartMarker = new RegExp( + this.foldingStartMarker.source.replace(/\|[^|]*?$/, "|" + commentRegex.start) + ); + this.foldingStopMarker = new RegExp( + this.foldingStopMarker.source.replace(/\|[^|]*?$/, "|" + commentRegex.end) + ); + } +}; +oop.inherits(FoldMode, BaseFoldMode); + +(function() { + + this.foldingStartMarker = /([\{\[\(])[^\}\]\)]*$|^\s*(\/\*)/; + this.foldingStopMarker = /^[^\[\{\(]*([\}\]\)])|^[\s\*]*(\*\/)/; + this.singleLineBlockCommentRe= /^\s*(\/\*).*\*\/\s*$/; + this.tripleStarBlockCommentRe = /^\s*(\/\*\*\*).*\*\/\s*$/; + this.startRegionRe = /^\s*(\/\*|\/\/)#?region\b/; + this._getFoldWidgetBase = this.getFoldWidget; + this.getFoldWidget = function(session, foldStyle, row) { + var line = session.getLine(row); + + if (this.singleLineBlockCommentRe.test(line)) { + if (!this.startRegionRe.test(line) && !this.tripleStarBlockCommentRe.test(line)) + return ""; + } + + var fw = this._getFoldWidgetBase(session, foldStyle, row); + + if (!fw && this.startRegionRe.test(line)) + return "start"; // lineCommentRegionStart + + return fw; + }; + + this.getFoldWidgetRange = function(session, foldStyle, row, forceMultiline) { + var line = session.getLine(row); + + if (this.startRegionRe.test(line)) + return this.getCommentRegionBlock(session, line, row); + + var match = line.match(this.foldingStartMarker); + if (match) { + var i = match.index; + + if (match[1]) + return this.openingBracketBlock(session, match[1], row, i); + + var range = session.getCommentFoldRange(row, i + match[0].length, 1); + + if (range && !range.isMultiLine()) { + if (forceMultiline) { + range = this.getSectionRange(session, row); + } else if (foldStyle != "all") + range = null; + } + + return range; + } + + if (foldStyle === "markbegin") + return; + + var match = line.match(this.foldingStopMarker); + if (match) { + var i = match.index + match[0].length; + + if (match[1]) + return this.closingBracketBlock(session, match[1], row, i); + + return session.getCommentFoldRange(row, i, -1); + } + }; + + this.getSectionRange = function(session, row) { + var line = session.getLine(row); + var startIndent = line.search(/\S/); + var startRow = row; + var startColumn = line.length; + row = row + 1; + var endRow = row; + var maxRow = session.getLength(); + while (++row < maxRow) { + line = session.getLine(row); + var indent = line.search(/\S/); + if (indent === -1) + continue; + if (startIndent > indent) + break; + var subRange = this.getFoldWidgetRange(session, "all", row); + + if (subRange) { + if (subRange.start.row <= startRow) { + break; + } else if (subRange.isMultiLine()) { + row = subRange.end.row; + } else if (startIndent == indent) { + break; + } + } + endRow = row; + } + + return new Range(startRow, startColumn, endRow, session.getLine(endRow).length); + }; + this.getCommentRegionBlock = function(session, line, row) { + var startColumn = line.search(/\s*$/); + var maxRow = session.getLength(); + var startRow = row; + + var re = /^\s*(?:\/\*|\/\/|--)#?(end)?region\b/; + var depth = 1; + while (++row < maxRow) { + line = session.getLine(row); + var m = re.exec(line); + if (!m) continue; + if (m[1]) depth--; + else depth++; + + if (!depth) break; + } + + var endRow = row; + if (endRow > startRow) { + return new Range(startRow, startColumn, endRow, line.length); + } + }; + +}).call(FoldMode.prototype); + +}); + +define("ace/mode/javascript",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/javascript_highlight_rules","ace/mode/matching_brace_outdent","ace/worker/worker_client","ace/mode/behaviour/cstyle","ace/mode/folding/cstyle"], function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var JavaScriptHighlightRules = require("./javascript_highlight_rules").JavaScriptHighlightRules; +var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; +var WorkerClient = require("../worker/worker_client").WorkerClient; +var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour; +var CStyleFoldMode = require("./folding/cstyle").FoldMode; + +var Mode = function() { + this.HighlightRules = JavaScriptHighlightRules; + + this.$outdent = new MatchingBraceOutdent(); + this.$behaviour = new CstyleBehaviour(); + this.foldingRules = new CStyleFoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + + this.lineCommentStart = "//"; + this.blockComment = {start: "/*", end: "*/"}; + this.$quotes = {'"': '"', "'": "'", "`": "`"}; + + this.getNextLineIndent = function(state, line, tab) { + var indent = this.$getIndent(line); + + var tokenizedLine = this.getTokenizer().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" || state == "no_regex") { + var match = line.match(/^.*(?:\bcase\b.*:|[\{\(\[])\s*$/); + if (match) { + indent += tab; + } + } else if (state == "doc-start") { + if (endState == "start" || endState == "no_regex") { + return ""; + } + var match = line.match(/^\s*(\/?)\*/); + if (match) { + if (match[1]) { + indent += " "; + } + indent += "* "; + } + } + + 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); + }; + + this.createWorker = function(session) { + var worker = new WorkerClient(["ace"], "ace/mode/javascript_worker", "JavaScriptWorker"); + worker.attachToDocument(session.getDocument()); + + worker.on("annotate", function(results) { + session.setAnnotations(results.data); + }); + + worker.on("terminate", function() { + session.clearAnnotations(); + }); + + return worker; + }; + + this.$id = "ace/mode/javascript"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); (function() { + window.require(["ace/mode/javascript"], function(m) { + if (typeof module == "object" && typeof exports == "object" && module) { + module.exports = m; + } + }); + })(); + \ No newline at end of file diff --git a/docs/images/background.png b/docs/images/background.png new file mode 100644 index 0000000000000000000000000000000000000000..de7baac8cf93fa7fab9d99a5fc3117d19fcca011 GIT binary patch literal 16072 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 Aw*UYD literal 0 HcmV?d00001 diff --git a/docs/images/exec.png b/docs/images/exec.png new file mode 100644 index 0000000000000000000000000000000000000000..83ce9271619f2fdfdb9839e34b5d397f97935a16 GIT binary patch literal 54506 zcmZU)b9iOV(mtGI;$$YaZQGgHww;M>+fF97?TIz9ZQHhgd!A>`Iq!FU`&xgj-K)F0 zyHsOm0>ck*%MdH%AC8{`S(4+Q4dXd+y>OzXR1A(VR5}q&C$Ye%q+8 zG_>5Z<1Ee?hR!3!5(B{h^`pWsqq=)b^z5_TqFh8(Od=-@cGQt=- zl2LJEgt1uMsuzM+q8ooh+&S$-By9agV@&whudHnAjS0t>hIbIz_hB>j&-uGpIW~cM z#IthuVIRM~adFGz)B-;oK#~$R(@_o$7&Tpr<#k0r<7Ez^pVCacLF(K@%{6UI`=tuz zeLR6ly2kw)6tD+ghbSv!W|dJ*DC``F$(&o6K41%7ydYFyn1Ct5DF>R4qX;$E^> z#p69ivefHfn!LI%QA_9Z(iI|t`o#oy<%&PNWbaauboE1W703DqGCde4Kbma-`rZ|& zK0Z9?-2~e>QJ3?@(HF!}Q15Pt&`XJrJKLpBr0@(Ye!{0nd_4I3rtF6YZ9MphA+`?* zmx-NjmsjgE=NNqYuq}9IDh-^}236#=Tx<3Z_rQ>6-A6*P;``N8nF{q3Nd zZz9oR@K-*usragReQh+fxjvpxgSaM$voRQhuzDg4HoiPh%~r;$qdfR5H+*9)ei-P& z6~~wEhtD>bQ~r<^ZVjv&U$9lg!JRHJ12jK{IrvpiRmW&2xv=WN+V}K^mpaJ|Wb)_CIggG_ZbJ( z3e@d?R?nv6+AlP4G4$(~p)as2e^3Q9YB$uAFa1sotQ=4oKhhDfp&qcMACj%0$r@fD ze#UOMcPt1a|2KAE=pGE)Z(2afJuJ3J%zi3YK-?g*-|^6aE@RuDKo7b>)PODELAUWG zLcbaKHRA(|!N&U~;ya1KF$Pr-kPUsg2@uFd|G}3CzR&+Wg;9cC7HrMmlnWupHV4Q zzl39s5mpa61>wN2U!Oz`;+JoxzAif=FQjR&uq~JtOcTDHH&o2;+bc@Uh$2CU{QkH# zW}(&GjwytrfTR2)rlZj#5l4s@5_i}R-;b!=z8b?mdP;PnNTLBaq>$lmWPM78uPHJ{ z>z=iP)pr zn;hngtKK%d5^!Z{r{RUq_UDVL?swS%`HStz>25~ z-z68P2qkAG-y%<Yf@LEs{3iPa1eYF8x)S zZJe1VS|wH`W+9z5^8w^sa0QApB|1hXWFmq#>Vi<4Y@N)Vx&yug!3*E(+dIpP&I=g0 z1~><}N3d%!VsIO5ek6T9em;UBy&>(c^uYH4T`6oS4JlqJb*V-vx)g8vdIk%|S9(*X zMFu$fPlIifX+tQ3VM8+mx5;o56yrvNC_|pnm0`|Fk;$TwgZ`i6&I#uuEe; z?;svsk?&ZJYevKCi8fYfXE^0C|gvMAI@lqfiKmlSv@OR0&J$n@|uk+feaxnq&zGHGAaVNycU*wlewh$0eD zFKL3PiKs8t^ed?=B`QcO3o9QrU6!Yon^)(SDwfPw4^}$sk$y$gS~L~cxinV)`rOVr zjlHBlAwPEQzAi;7SM*h^XPQ{vXqjTlZhTXjN=U zShI1{D~>ZQJ@ikGUZkkzu#vt5xx~O@$@a{q&}G^5+%)53=}Pcs z`oR1U{&eD&7JfEov45 zFJ>;HJbEp>8KOD{nDBXod32Gej)S{Fpy9W{$o{gypM4*Z^)YQIvPgKCn+f=7u}Snv zCE2bNP?>v4bDi0yJ|iEsUo;>_-~=Fe;C|ula3y*lDb{_z*+=%2kQ=F2DxG_qD`XC7 z_~{sZw|5uT3m#H!1kXgs6dYZG%aI&50XuXy9zRYw@sfF-`A#fKSxj#FUa~k%Hdqjo z$@|M~?a|eyO5kD{X$dKp4E&b)hW2oFkL*A;gPChtty?=*yGH3qXGxn_)$s!PLussZ zdbX%IJ>oe+7P&h6nvY2?Pg_BCL?=!8C4a2#tY3Y+zVVQKVn5^6iFfPm)IQ*50JV95ASMzfTH0H>NP1@4s}0ts zwT--$Su>GcaamGv;~s7A`kKd+$MGZUCE13qHH=NV&(@<}-g?LTy5L|)HD?84#zCVC6dHdQ&zzkC}VfRYR?4XYqFGTYa!j(8j=F_+L`6Vl!B^)~_txHC*06Fv zy1h83vBqireiu9>GHR2s*_%#~p1xfmHuF#p6p2l)s|(br49tHF3Z#t(p!HT4!TIx#Zg8D$>L2th0P!w=b7*Vw=`;=(V*?SS zJVlKr#s~YTl|PXd(6LZ8Rk+MOmb};X$D!C0+TgV*9&;aQ+M?PX-5TPo-BjFBJWOAS zpI)AqUo0Soz{0_=LF)tMf_~>p>hErQA-E9IiQvTWA}1iM!pF#5iCeD1eS^eR;xI}) zi$_dw=dPsZIj&jT4vSnP`k4x%j=YQy;googa%Fd~b&K@PZQ^-?36Eg&1&d5QEA$c5qg-a?}S$^4(;^1&2I&phSan&2LIWK_vS zF1WH(m-L&ApW)pVTTHnyzvBo`@{IDT`zFqzkdx6qX|Ba?niB(IeI3!+Vkxp(>#}yf zw>eh?7eit6x768yq-Ke`bN%)#>|3uZ7B}5 z8+QJ73D>4bcZk7A0SQM5Iu~6ITN^#mf^Z2o#Y)Afg@uJ7IL^aUT!d+1!=6dX8Rr?j z+4atjcT4rVO%9XU>?w!w)%NlCd*(fQ+v9nP#nG7)bhLa9<$LnSr*+Hq7Kaq0EmTHy z=sJ!a$SQ6%l&3e-CwrJPDE;Mq<(pMrRoWdg%{^|42S1Iy6a>9?Cr$QOw`uxas+w3g zI~=NCKW@GRJgnldW{zqLuh+@y++&~KA2GS--b;AUKYg`xwQhHDb~AIL`r!KPv0|wJ z0U}e3g=YBz#Pt>EhBKDa0jQMg8c0n6M6VoH&c72#_y{<5WNGsdB9Pmv#usD?$fO%A z&=*PVl2*YfuK zW#2i)MKnx=SQTY-F3LUY1v(A<|X z2JA@>iV#eS$GNCG)vwjLmav=7>qNPZI8E5^o9SEKFUsv+kNilcT@84WJ9ypTUdLYK zpVL8+!DYZMzfwTHBU)q2BMFB_hq_@E<85Y;XDPY)zUqlH8cOJ3^78Co-Nbc|wVY+- z6AWVA{E(?b^`tH1J@*c-EvPH}AxCX&c*qH-LRV*gSiW(ARbGAZ ztCWu~@T6^;e8x4DB03Y21C}HZ6^{j$COQ}2E4?T~F%cTmBGv^Xu8j@_Z}(&PXE=Xr zPI)Z0!svMTUFe2DmO;yo8R9EReqnn7i!mf)N8PeL>5bG)1hfruTOwu>l~QyW=|z+D}ty_G5?{6 z>KZRZ6VpW|?t6jrq`j`IYJUS|z*fYgr_> zc!S4BoJ2lHh9H_od>kKk3Paw6M3$@sS1C#~ryZ}4DE}qG7RAkQo5a4v(u{Yf&N_hu zf#v>EiCoIh(M5}tsze>d@^{aUr=pw64RD2B4F}-}WvXUPugwOl+IOvxL!zWXZrLf> zY@P_O=<`wU@2=_$Tf9aOq)*!Ouch);cB3&A36CZz2Qr=rTCNWrdizIZ(`jQb%TY01 zXfC@k;CsH9>hIkAu;f5EdQfYzOL+V$-W(+mF+GrV7f`YI1yJV!@i~Y`w9LVTqIog` zD0we>;7bsl5hkK!`KAmqDW+;TXWAK<7r?0$%N{r6+$bNMK|H{u%<>}eg<*W9oTU+F z20t>7B9EdlD$t`+kyC}$_SDyx5ts5gxH+s^##+W*$6TeK$DS&|*1+-uqoEc9% zpNWu21}`%xTQDoMvGV*cd6k)Muv-{W`E4Wjdx_eF?tgpXKnLN`i=scli zr;hJ*^J&uB(bmx6{q?(3;a2c@Fcq(y567Feim^(hinXfhedaCcque8^*`(gtywWDq zQrm&Y`+eYL416+pR^($KAu4KfrmMpz`{n)a@lyI&I(vLJok#OJ<|Zj=+1ryJ)C!26 zC_Q}>47hv$OHEu;ON&ZvON$*a1#2+y515VTs`~eeT<{#nQ%ywImG;)F%}c6J80)Gb zy!=!O13>N|(@aUtQB7Kk)6m9>R^Q0Rz?jz6$`+7L00QE6G3X;NYO6XQX3fqyf~Rad5MC)OV$^b|Cs!$baMr89Nx- zo7p;=*;wQMk*jZDr~9vLKvV8N zrJQnRuEv&XLS|OR)((I^cv)EKx&NvE|9kSk9{*2E_5ah7{{PeR|2+BIlAG?&1pd#2 z{?*n$r2uvDLUYsoSM|KmiRB@dKtTLJ;zHk*T!GIrA@q=iUk9=SnBA*qJQ66wLBjD% zkj+@{s>KxL5rDr7_k06^o=JxeMSkZO3ct%E6id)4fb@sgK$H-h{5V`6-8k32h?i`Z zq}@xsY&*L+J4@WmICHpcXEK~t0{Q|K3-tFgA^-uNa4Jl*BmHfGh!6bloim1||eqrc_r-KT^+(AN&%OMfS49^3uWO!@+pJZ0x za_d_B5YAzVT9aolZd%@cAYj}wqk-xX{22=4s)l}I_nC7+jtgbH z7Lp*u{2;_zR3PFiN$pVbLpbR8AmFY0{i^#6x`<*hey4Wb_n<2uGruFv!~p}s=R#;k zE!07#B*#NH_LJ`wfmKiF-XBdyKtS;8?&jYcO@<4CL392wG@L*tU#3K{H5G+WHL{DnbdN< zPfxC}*zEBA;V6RhWydVIxUY`MO=+tqH%*gE={z&(H+~1Zo@( zWgHxfvQ7J37-q4Cq5oA+K{~&sC&*6HI!Q=YKnXfta1<6>p6O&3I+ru`!`bp~Z~PnE z>2j}M@hAve$DTPc^l%-ehs{8$kF%sPcd4X_y=$6snCFNJa-(3tMf-NZ;g&DNn z8BL*1a*HT1u1aK#wVb`Xzvc)Ui!>j!-7bbeA9DDmH zkY8`0Vwl6H-W*-yTipLx6yQ*gmei>~8f0 z49^%F^<{Ti4UpNu2{@XXyFbbGk)I|s_3qE2YIU8RYo+4-vyFV| zpq`Yvhiv26<0QnS?%t(}-LgS!cwjSlz}q=-UDYwXWJ+DGH>BNB9IvlUsPqQlx3ZFLfP7+ENE7)~>wus}eRMounCy)nq zHKe?HA;!;610^=b)bFeB77V{RS?2E(-U?ITw_vedB$Z3roS`&{Y$(McA|jHn)L=oT zR)Y`uhBK4t(BC8+xP#-e2HflScrc#M?tVw!`T60oeknGw4koVHkmY~$yZ$sU(&-KG0orVbXmCYD=aj9SOP;GE0|%C8tC+0L zwrLy)ojQ6dW4Xxv`~uDgDy4Xw<^&?4T$k+h0#9$wVylYPs3Mbrhz$qwi7O8x(vX5k z^6K*i8WlpMLT=Dt;gDFjwgx>{k&i@A34>`9oVcs0t1%o~{eYb~MgvuSf7dLQVlshD zHW)Io)9ZC-S`<&X$$A}M(23CKW=|fY4FCFu!~3n7SCFFcjql^ha2>&Qr!Qc^zQD&n6ow?bRvkw2&3c~EiG|W>G+J*Al4tFav;w8f**2XW=Ei2p4^L<%Oo2Fq{^YoeO_L4QB3=3c84-8uiK-yADju3j1oXFUe+*5}l|y@A_GB|GY&ba=%rP z?xCZ;!g~H@`}Lvooe*z5dby6;m!Nkh_)728L)I{K!_eVWPxAzOVp$AE^I{#>kYB)j zrMac!pNb#Ia6r0vHE>koou&KxTFxTc5z2$uus*4P7nGK-$i3lJ2}$UsY>gs>>^!$~EC+ z!%2BCkS=h41eI?j5y18NNfB>7J>2LEN1_$hnuIk)lzH&g7!lSO6gi;}b4L;x568-0 z*QvzSU#jMadsuw!BX~5ur_vP2EZD|9RX*|Qr%tyCuI*E65-$JO>$DNUk@XJc;hl~;Gpyz2F!W|^cIk( zZJ1M~Lwy`8;hoHu1&34$W-GuR2uq@ytBFC#^4X+x9b@tb35aZq9^4}4gQTc-;L}^6 zKb?w;lb~kAd;j5dz_PPP4kB6PB&+x>k4shaaww9_?wgD(e1wX`Pn6-=nyR6>AJ2|Q zQ^2y^*MYS7!b%b;%x3W)akm3eSf{H9E zXmWyzq?bMQZa@{l3^TkXaC-$G|HZrb^-yYq2#js0)Y<=oz%%^5Af#VwQWF1D)XfJe*Zm~QSA+T& zi1CA%;cv~Vi@_UaJJF}OhEuIW&RsQ)n({LUn{1f|;z-A0QxK&#UK z062aS^%Nj5Dbx#YmCV1w>!<)^I>E4jvuHGS&%^mD0nE~{JgTI{bY4*BOL=XIhI3H% zhBMx(9nxl}18%K+So4i8woZmC#KlGIN53Vlc5`TT@wiCSg>1fOkiB(zqv@hfg=Wh) zFNpR?Znt@vuw{0wF2oods;Ye3W1u-7a$Q!^o}z?513ZAgDg^_;My8hyPKUz@;fuAF z=|V{~FX1Hy!vX%EHKt-*eqLBMdOsp|**o|!oiq>Tnb2?V%qr5nNzPMAco4E1W{o_x zJj31kga+~Dt#C;`M<=%XF34ej+_4os@C4wA>IxYMJRHPjcEMP3{pk?_&?BkMMmsvY zEk3U2)pzY~F(xjjlfaMn*WIaH!58S7Iy%GvQ&0m!B!<&*2lpK~6=i`!@Rq5I#yr>R zdGRqk-0-%QeZgr)>j(a;3dk4*^;j<)|;AHy^i?~IP%q4ZSYWcnwlK%_^yD)nVRGs@6yw*CGX zQYxP>5=^I$_p+%D>sCs(=X$s0&3!8-sWg)CrK8oE|ET3NlJe#J`e}l^!#cPt;%5nK z0=7Z*V>HSlzTF3=fuX_Gu;!QA^CoG?HczNti1wme8?9VoXRGy{>iJ*uk`K)%FDiCY zoN`~3FGr#R6Ghi7C$9tlSxVinpo~i0T3y~ac%D~&8{wweUZ@!7eONdsLBgBkB9pY| z*GKF3w!1GZj;=dqmRgMW*D# z%dm-l{|pJ=0n%uRuZPWMqfgVOBM1Q0b`oTHzXKvHrsDpxIUKG zbIueNHxL7ZJcM|vWYPOp`(tQ>-8tF~Yk>*h404qQbXuKu-#($oJVMnfcw}m&DQVh= zAJ6x6SfUb;u)pwk1h5BqAL-0l#{Ss$6kp(WH{yz;t*Gy-9U)Q zCiy$xz^1BBkzA|1u(Z0I=XXbhH$sJkTmubuHbTnOt__;=f+;(CHh04r2>yuy_=Dkx z;DL#D_Q%;a=R%@+U(cAlD4l{ECZq}IzM}hQy@N05JSdyb*(c06HK22JWHUgr~p7mOpqUkA^RJ ztagM`hTXrLeSK`Qj2?L00F(SSk0Aq28#bFbPZg5}b}0Q}R!KDb$GQMPJw^Mb9Oa3)pSEJzs4J($tvrYmn$^!4QX4 ztJHI1t|@OO7|0jOTa)Ni>21{9me|?gHe9Hy`OxkN_}|2Yi5NTS`s8{fY95dvnr>)* zCHvs@>vF!7|4F;3yUpJCOS)}v#h~}(UT62RYC`=xb89)*?mw(TIil@*byu>+Eg;0z zzdxCOF>r1)FSJS-kW{`>XO(BmhqogU;3y)8@r}TT=@f6a=aABU8y80G>mMNC)EEzV zpjWan(0zX>6gQ4#n$mc%;R`(FSX*uJt-EtgQAd?UMZ$`xq1uLow(q!*_OEj%p-f0( zdrpr7166gPEtTe7_bjVn?g3X9je@@8j>@47Cc6*>rLJGBoMBntE9?Tmt@23V&jL#6W(kN-MR z>nOlbq-u1E|60#4v z@XCDlp3Pkj2Ua7f@ac)Y>UWTkDtO7m#5JLt%M~*)Z{oM(HPh{ER z-=jPkcbZR=PnYP)##H9!C9hMKKP$Xxc*S#kYiqZm{#iTm|H20)L5$FQPx9VmlpEqp z5HM^u+PA}^1hitZRHJL=!Y|3IBM%G)PM>H(ZjNLqAy>db2VFq~b9CQpzeXzL`XE zg&kl1Ms}U&x>DXW$?-BuRbH2}#(#*}pOEvW&Zxh_^^Um?hkx zi0cXd>`FLDBR60oD{6TD`VI)MabjN5SUR$<5MGh7vp>r27Qr8dBN(pU@Nbo^0#n_s z&!&s4By)>51Ks0F5q%#%Ji^K{yVvjegEnGu{*jeQOc(omgruN`y50w7yW8(eiDK~t z&0e?Yzb_8}XBhpvtr!CLXylOTHVB73{{o!uCQx!cDbIe8-hU~iKP=KGs3&J2ahqJV zMk92a^ZAVGZlz8Kr;()JHyq9!&*vL&QL;+Zl->}y-Pg;m#U{zv`Cu$I>&Pq~50hn- z;P)y)HG;pCk*#2NF=~orGOhm2-f*+)HDRmMX)vL1xZZF)$&2L2*>b&gS)$vtS#9@F zc*7s2Dg@6PQeF8e0FJjiiAr^<$wrs^eooPv4SuYBq1NcH)MhWpCr6Tv)5U5cW@cpN za+O8|%~nSWQmK?2o2#W#MKVoK4Vetp9qG~f4Jj_04Q^($8Bl<@g?f|-#dKCH+p{GG zYz})NG}aC37`K0eHUJzW)2rw^RfLi1^nAwdi{S4%%<_2q>7_wUKLfcuIt))|PlKhH z)}PkL@L!tKHT%!*EI-NO_0ov>27R-k@KiM-E~};CrI#_f)Z##9GMQBwfsSBf2Blam z)8Ak=3y*>l^anh#vX5o+@tKUL724#a{A^G8`4{b3yZo`%c6N5~)AlEG6mL(vF@K1w zi_TZ;HJ{IS??Ki|RCI?g(Rh4SO_G5Tp((z;4bP&I%R79E06r2HgAugD{eFgqa|fB) zTktOv16U=_AZ8w;E7`YCXKO7Et+Q3ne!*X{2xYUl56HXNWvjtNu;T%G3E%0DFdY3! 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
M`Mp%lw;D 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 literal 0 HcmV?d00001 diff --git a/docs/images/follow_cursor.gif b/docs/images/follow_cursor.gif new file mode 100644 index 0000000000000000000000000000000000000000..49c5e0f8748b6bd5ab33bf67988595c8be611c53 GIT binary patch literal 26109 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

ab&EE)$>p%G4(cz93 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 literal 0 HcmV?d00001 diff --git a/docs/images/test.png b/docs/images/test.png new file mode 100644 index 0000000000000000000000000000000000000000..59701170ba598776100499ef16e5294036789b2d GIT binary patch literal 224614 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 z%0D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 + + + + + + + + + + + + + + + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..4efd107 --- /dev/null +++ b/package.json @@ -0,0 +1,3 @@ +{ + "type" : "module" +} diff --git a/service_worker.js b/service_worker.js new file mode 100644 index 0000000..704f51c --- /dev/null +++ b/service_worker.js @@ -0,0 +1,30 @@ +/* +Should prevent navigator.serviceWorker.controller from being null on first load, but doesn't work for some reason. +TODO: compare with +https://googlechrome.github.io/samples/service-worker/post-message/ +which seems to work on first load + +self.addEventListener('install', function(event) { + //event.waitUntil(self.skipWaiting()); // Activate worker immediately +}); + +self.addEventListener('activate', function(event) { + event.waitUntil(self.clients.claim()); // Become available to all pages +}); +*/ + +let data + +self.addEventListener('message', async function(e) { + const msg = e.data + let reply + if(msg.type == 'SET') { + data = msg.data + reply = null + } else if(msg.type == 'GET') { + reply = data + } else { + throw new Error('unknown message type: ' + msg.type) + } + e.ports[0].postMessage(reply) +}) diff --git a/src/ast_utils.js b/src/ast_utils.js new file mode 100644 index 0000000..bf417ec --- /dev/null +++ b/src/ast_utils.js @@ -0,0 +1,167 @@ +import {uniq} from './utils.js' + +export const collect_destructuring_identifiers = node => { + if(Array.isArray(node)) { + return node.map(collect_destructuring_identifiers).flat() + } else if(node.type == 'identifier') { + return [node] + } else if(['destructuring_default', 'destructuring_rest'].includes(node.type)){ + return collect_destructuring_identifiers(node.name_node) + } else if(node.type == 'destructuring_pair') { + return collect_destructuring_identifiers(node.value) + } else if( + ['array_destructuring', 'object_destructuring', 'function_args'] + .includes(node.type) + ) { + return node.elements + .map(collect_destructuring_identifiers) + .flat() + } else { + console.error(node) + throw new Error('not implemented') + } +} + +export const map_destructuring_identifiers = (node, mapper) => { + const map = node => map_destructuring_identifiers(node, mapper) + if(node.type == 'identifier') { + return mapper(node) + } else if(node.type == 'destructuring_default') { + return {...node, children: [map(node.children[0]), node.children[1]]} + } else if(node.type == 'destructuring_rest') { + return {...node, children: [mapper(node.children[0])]} + } else if(node.type == 'destructuring_pair') { + return {...node, children: [node.children[0], map(node.children[1])]} + } else if(node.type == 'array_destructuring' || node.type == 'object_destructuring') { + return {...node, children: node.children.map(map)} + } else { + console.error(node) + throw new Error('not implemented') + } +} + +export const collect_imports = module => { + const imports = module.stmts + .filter(n => n.type == 'import') + .map(n => + n.imports.map(i => + ({name: i.value, module: n.full_import_path}) + ) + ) + .flat() + + const modules = uniq(imports.map(i => i.module)) + const by_module = Object.fromEntries(modules.map(m => + [ + m, + imports + .filter(i => i.module == m) + .map(i => i.name) + ] + )) + return by_module +} + + +export const find_leaf = (node, index) => { + if(!(node.index <= index && node.index + node.length > index)){ + return null + } else { + if(node.children == null){ + return node + } else { + const children = node.children.map(n => find_leaf(n, index)) + const child = children.find(c => c != null) + return child || node + } + } +} + + +export const is_child = (child, parent) => { + return parent.index <= child.index && + (parent.index + parent.length) >= child.index + child.length +} + +// TODO inconsistency. Sometimes we compare by identity, sometimes by this +// function +export const is_eq = (a, b) => { + return a.index == b.index && a.length == b.length + // Two different nodes can have the same index and length. Currently there + // is only one case: single-child do statement and its only child. So we + // add `type` to comparison. Better refactor it and add unique id to every + // node? Maybe also include `module` to id? + && a.type == b.type +} + +export const ancestry = (child, parent) => { + if(is_eq(parent, child)){ + return [] + } else { + if(parent.children == null){ + return null + } else { + const c = parent.children.find(c => is_child(child, c)) + if(c == null){ + return null + } else { + return ancestry(child, c).concat([parent]) + } + } + } +} + +export const ancestry_inc = (child, parent) => + [child, ...ancestry(child, parent)] + +export const find_fn_by_location = (node, loc) => { + if( + node.index == loc.index && node.length == loc.length + // see comment for is_eq + && node.type == 'function_expr' + ) { + return node + } else if(node.children == null){ + throw new Error('illegal state') + } else { + const c = node.children.find(c => is_child(loc, c)) + if(c == null){ + throw new Error('illegal state') + } else { + return find_fn_by_location(c, loc) + } + } +} + +export const find_node = (node, pred) => { + if(pred(node)) { + return node + } + if(node.children == null) { + return null + } + return node + .children + .reduce( + (result, c) => result ?? find_node(c, pred), + null + ) +} + +export const find_error_origin_node = node => + find_node( + node, + n => n.result != null && !n.result.ok && n.result.error != null + ) + +/* Maps tree nodes, discarding mapped children, so maps only node contents, not + * allowing to modify structure */ +export const map_tree = (node, mapper) => { + const mapped = mapper(node) + if(node.children == null) { + return mapped + } + return {...mapped, + children: node.children.map(c => map_tree(c, mapper)) + } +} diff --git a/src/calltree.js b/src/calltree.js new file mode 100644 index 0000000..31afdf7 --- /dev/null +++ b/src/calltree.js @@ -0,0 +1,782 @@ +import {map_accum, map_find, map_object, stringify, findLast} from './utils.js' +import {is_eq, find_error_origin_node} from './ast_utils.js' +import {find_node, find_leaf, ancestry_inc} from './ast_utils.js' +import {color} from './color.js' +import {eval_frame} from './eval.js' + +export const pp_calltree = calltree => map_object( + calltree, + (module, {exports, calls}) => stringify(do_pp_calltree(calls)) +) + +const do_pp_calltree = tree => ({ + id: tree.id, + has_more_children: tree.has_more_children, + string: tree.code.string, + children: tree.children && tree.children.map(do_pp_calltree) +}) + +const is_stackoverflow = node => + // Chrome + node.error.message == 'Maximum call stack size exceeded' + || + // Firefox + node.error.message == "too much recursion" + +export const calltree_node_loc = node => node.toplevel + ? {module: node.module} + : node.fn.__location + +// Finds the last module that was evaluated. If all modules evaluated without +// problems, then it is the entrypoint module. Else it is the module that +// throws error +export const root_calltree_module = state => + findLast( + state.parse_result.sorted, + module => state.calltree[module] != null + ) + +export const root_calltree_node = state => + state.calltree[root_calltree_module(state)].calls + +export const is_native_fn = calltree_node => + !calltree_node.toplevel && calltree_node.fn.__location == null + +export const active_frame = state => + state.frames[state.active_calltree_node.id] + +const get_calltree_node_by_loc = (state, node) => + state.calltree_node_by_loc + ?.[state.current_module] + ?.[ + state.parse_result.modules[state.current_module] == node + // identify toplevel by index `-1`, because function and toplevel can + // have the same index (in case when module starts with function_expr) + ? -1 + : node.index + ] + +const add_calltree_node_by_loc = (state, loc, node_id) => { + return { + ...state, + calltree_node_by_loc: + {...state.calltree_node_by_loc, + [loc.module]: { + ...state.calltree_node_by_loc?.[loc.module], + [loc.index ?? -1]: node_id + } + } + } +} + +export const set_active_calltree_node = ( + state, + active_calltree_node, + current_calltree_node = state.current_calltree_node, +) => { + const result = { + ...state, + active_calltree_node, + current_calltree_node, + } + // TODO currently commented, required to implement livecoding second and + // subsequent fn calls + /* + // Record last_good_state every time active_calltree_node changes + return {...result, last_good_state: result} + */ + return result +} + +export const add_frame = ( + state, + active_calltree_node, + current_calltree_node = active_calltree_node, +) => { + let with_frame + if(state.frames?.[active_calltree_node.id] == null) { + const frame = eval_frame(active_calltree_node, state.calltree) + const coloring = color(frame) + with_frame = {...state, + frames: {...state.frames, + [active_calltree_node.id]: {...frame, coloring} + } + } + } else { + with_frame = state + } + const result = add_calltree_node_by_loc( + with_frame, + calltree_node_loc(active_calltree_node), + active_calltree_node.id, + ) + return set_active_calltree_node(result, active_calltree_node, current_calltree_node) +} + + +const replace_calltree_node = (root, node, replacement) => { + const do_replace = root => { + if(root.id == node.id) { + return [true, replacement] + } + + if(root.children == null) { + return [false, root] + } + + const [replaced, children] = map_accum( + (replaced, c) => replaced + // Already replaced, do not look for replacement + ? [true, c] + : do_replace(c), + false, + root.children, + ) + + if(replaced) { + return [true, {...root, children}] + } else { + return [false, root] + } + } + + const [replaced, result] = do_replace(root) + + if(!replaced) { + throw new Error('illegal state') + } + + return result +} + +const expand_calltree_node = (state, node) => { + if(node.has_more_children) { + const root = root_calltree_module(state) + const next_node = state.calltree_actions.expand_calltree_node(node) + // Update calltree, replacing node with expanded node + const {exports, calls} = state.calltree[root] + const calltree = {...state.calltree, + [root]: { + exports, + calls: replace_calltree_node(calls, node, next_node), + } + } + return {state: {...state, calltree}, node: next_node} + } else { + return {state, node} + } +} + +const jump_calltree_node = (_state, _current_calltree_node) => { + const {state, node: current_calltree_node} = expand_calltree_node( + _state, _current_calltree_node + ) + + /* + When node is selected or expanded/collapsed + If native, goto call site + If hosted + If parent is native + goto inside fn + If parent is hosted + If expanded, goto inside fn + If collapsed, goto call site + */ + + /* Whether to show fn body (true) or callsite (false) */ + let show_body + const [parent] = path_to_root( + root_calltree_node(state), + current_calltree_node + ) + if(current_calltree_node.toplevel) { + show_body = true + } else if(is_native_fn(current_calltree_node)) { + show_body = false + } else { + if(is_native_fn(parent)) { + show_body = true + } else { + const is_expanded = state.calltree_node_is_expanded[current_calltree_node.id] + show_body = is_expanded + } + } + + const active_calltree_node = show_body ? current_calltree_node : parent + + const next = add_frame(state, active_calltree_node, current_calltree_node) + + const loc = show_body + ? calltree_node_loc(next.active_calltree_node) + : find_callsite(next.calltree, active_calltree_node, current_calltree_node) + + return { + state: {...next, current_module: loc.module}, + effects: next.current_calltree_node.toplevel + ? {type: 'unembed_value_explorer'} + : [ + { + type: 'set_caret_position', + // TODO: better jump not start of function (arguments), but start + // of body? + args: [loc.index], + }, + { + type: 'embed_value_explorer', + args: [{ + index: loc.index, + result: { + ok: true, + value: current_calltree_node.ok + ? { + '*arguments*': current_calltree_node.args, + '*return*': current_calltree_node.value, + } + : { + '*arguments*': current_calltree_node.args, + '*throws*': current_calltree_node.error, + } + } + }], + }, + ] + } +} + +export const path_to_root = (root, child) => { + const do_path = (root) => { + if(root.id == child.id) { + return [] + } + if(root.children == null) { + return null + } + return root.children.reduce( + (result, c) => { + if(result != null) { + return result + } + const path = do_path(c) + if(path == null) { + return null + } + return [...path, root] + }, + null + ) + } + + const result = do_path(root) + + if(result == null) { + throw new Error('illegal state') + } + + return result +} + +export const is_expandable = node => + // Hosted node always can be expanded, even if has not children + // Toplevel cannot be expanded if has no children + (!is_native_fn(node) && !node.toplevel) + || + (node.children != null || node.has_more_children) + +/* + Right - + - does not has children - nothing + - has children - first click expands, second jumps to first element + + Left - + - root - nothing + - not root collapse node, goes to parent if already collapsed + + Up - goes to prev visible element + Down - goes to next visible element + + Click - select and toggle expand + + step_into - select and expand +*/ + +const arrow_down = state => { + const current = state.current_calltree_node + let next_node + + if( + is_expandable(current) + && state.calltree_node_is_expanded[current.id] + && current.children != null + ) { + + next_node = current.children[0] + + } else { + + const next = (n, path) => { + if(n == root_calltree_node(state)) { + return null + } + const [parent, ...grandparents] = path + const child_index = parent.children.findIndex(c => + c == n + ) + const next_child = parent.children[child_index + 1] + if(next_child == null) { + return next(parent, grandparents) + } else { + return next_child + } + } + + next_node = next( + current, + path_to_root(root_calltree_node(state), current) + ) + } + + return next_node == null + ? state + : jump_calltree_node(state, next_node) +} + +const arrow_up = state => { + const current = state.current_calltree_node + if(current == root_calltree_node(state)) { + return state + } + const [parent] = path_to_root(root_calltree_node(state), current) + const child_index = parent.children.findIndex(c => + c == current + ) + const next_child = parent.children[child_index - 1] + let next_node + if(next_child == null) { + next_node = parent + } else { + const last = node => { + if( + !is_expandable(node) + || !state.calltree_node_is_expanded[node.id] + || node.children == null + ) { + return node + } else { + return last(node.children[node.children.length - 1]) + } + } + next_node = last(next_child) + } + return jump_calltree_node(state, next_node) +} + +const arrow_left = state => { + const current = state.current_calltree_node + const is_expanded = state.calltree_node_is_expanded[current.id] + if(!is_expandable(current) || !is_expanded) { + if(current != root_calltree_node(state)) { + const [parent] = path_to_root(root_calltree_node(state), current) + return jump_calltree_node(state, parent) + } else { + return state + } + } else { + return toggle_expanded(state) + } +} + +const arrow_right = state => { + const current = state.current_calltree_node + if(is_expandable(current)) { + const is_expanded = state.calltree_node_is_expanded[current.id] + if(!is_expanded) { + return toggle_expanded(state) + } else { + if(current.children != null) { + return jump_calltree_node(state, current.children[0]) + } else { + return state + } + } + } else { + return state + } +} + +const find_callsite = (calltree, parent, node) => { + const frame = eval_frame(parent, calltree) + const result = find_node(frame, n => n.result?.call == node) + return {module: calltree_node_loc(parent).module, index: result.index} +} + +export const toggle_expanded = (state, is_exp) => { + const node_id = state.current_calltree_node.id + const prev = state.calltree_node_is_expanded[node_id] + const next_is_exp = is_exp ?? !prev + const expanded_state = { + ...state, + calltree_node_is_expanded: { + ...state.calltree_node_is_expanded, + [node_id]: next_is_exp, + } + } + return jump_calltree_node( + expanded_state, + state.current_calltree_node, + ) +} + +const click = (state, id) => { + const node = find_node(root_calltree_node(state), n => n.id == id) + // Effects are intentionally discarded, correct `set_caret_position` will be + // applied in `toggle_expanded` + const {state: nextstate, effects} = jump_calltree_node(state, node) + if(is_expandable(node)) { + return toggle_expanded(nextstate) + } else { + return {state: nextstate} + } +} + +/* +After find_call, we have two calltrees that have common subtree (starting from +root node). Nodes in these subtrees are the same, but have different ids. Copy +nodes that are in the second tree that are not in the first tree +*/ +const merge_calltrees = (prev, next) => { + return Object.fromEntries( + Object.entries(prev).map(([module, {exports, calls}]) => + [ + module, + {exports, calls: merge_calltree_nodes(calls, next[module].calls)[1]} + ] + ) + ) +} + +const merge_calltree_nodes = (a, b) => { + // TODO Quick workaround, should be fixed by not saving stack in eval.js in + // case of stackoverflow + if(!a.ok && is_stackoverflow(a)) { + return [false, a] + } + + if(a.has_more_children) { + if(b.has_more_children) { + return [false, a] + } else { + // Preserve id + return [true, {...b, id: a.id}] + } + } + + if(a.children == null) { + return [false, a] + } + + if(b.has_more_children) { + return [false, a] + } + + const [has_update, children] = map_accum( + (has_update, c, i) => { + const [upd, merged] = merge_calltree_nodes(c, b.children[i]) + return [has_update || upd, merged] + }, + false, + a.children + ) + + if(has_update) { + return [true, {...a, children}] + } else { + return [false, a] + } +} + +/* + Finds node in calltree `a` that has the same position that node with id `id` + in calltree `b`. Null if not found +*/ +const find_same_node = (a, b, id) => { + return map_find( + Object.entries(a), + ([module, {calls}]) => do_find_same_node(calls, b[module].calls, id) + ) +} + +const do_find_same_node = (a, b, id) => { + if(b == null) { + return null + } + + if(b.id == id) { + return a + } + + if(a.children == null || b.children == null) { + return null + } + + return map_find( + a.children, + (c, i) => do_find_same_node(c, b.children[i], id) + ) +} + +export const expand_path = (state, node) => ({ + ...state, + calltree_node_is_expanded: { + ...state.calltree_node_is_expanded, + ...Object.fromEntries( + path_to_root(root_calltree_node(state), node) + .map(n => [n.id, true]) + ), + // Also expand node, since it is not included in + // path_to_root + [node.id]: true, + } +}) + +export const initial_calltree_node = state => { + const root = root_calltree_node(state) + if( + root.ok + || + // Not looking for error origin, stack too deep + is_stackoverflow(root) + ) { + return { + state: expand_path(state, root), + node: root, + } + } else { + // Find error origin + const node = find_node(root, + n => !n.ok && ( + // All children are ok + n.children == null + || + n.children.find(c => !c.ok) == null + ) + ) + return {state: expand_path(state, node), node} + } +} + +export const default_expand_path = state => initial_calltree_node(state).state + +export const find_call_node = (state, index) => { + const module = state.parse_result.modules[state.current_module] + + if(module == null) { + // Module is not executed + return null + } + + let node + + if(index < module.index || index >= module.index + module.length) { + // index is outside of module, it can happen because of whitespace and + // comments in the beginning and the end + node = module + } else { + const leaf = find_leaf(module, index) + const anc = ancestry_inc(leaf, module) + const fn = anc.find(n => n.type == 'function_expr') + node = fn == null + ? module + : fn + } + + return node +} + +export const find_call = (state, index) => { + const node = find_call_node(state, index) + + if(node == null) { + return state + } + + if(state.active_calltree_node != null && is_eq(node, state.active_calltree_node.code)) { + return state + } + + const ct_node_id = get_calltree_node_by_loc(state, node) + + if(ct_node_id === null) { + // strict compare (===) with null, to check if we put null earlier to + // designate that fn is not reachable + return set_active_calltree_node(state, null) + } + + if(ct_node_id != null) { + const ct_node = find_node( + root_calltree_node(state), + n => n.id == ct_node_id + ) + if(ct_node == null) { + throw new Error('illegal state') + } + return set_active_calltree_node(state, ct_node, ct_node) + } + + if(node == state.parse_result.modules[root_calltree_module(state)]) { + const toplevel = root_calltree_node(state) + return add_frame( + expand_path( + state, + toplevel + ), + toplevel, + ) + } else if(node.type == 'do') { + // Currently we only allow to eval in toplevel of entrypoint module + return state + } + + const loc = {index: node.index, module: state.current_module} + const {calltree, call} = state.calltree_actions.find_call( + root_calltree_module(state), + loc + ) + if(call == null) { + return add_calltree_node_by_loc( + // Remove active_calltree_node + // current_calltree_node may stay not null, because it is calltree node + // explicitly selected by user in calltree view + set_active_calltree_node(state, null), + loc, + null + ) + } + + const merged = merge_calltrees(state.calltree, calltree) + const active_calltree_node = find_same_node(merged, calltree, call.id) + + return add_frame( + expand_path( + {...state, + calltree: merged, + calltree_changed_token: {}, + }, + active_calltree_node + ), + active_calltree_node, + ) +} + +const select_return_value = state => { + if(state.current_calltree_node.toplevel) { + return {state} + } + + const code = state.active_calltree_node.code + const loc = calltree_node_loc(state.active_calltree_node) + const frame = active_frame(state) + + let node, result_node + + if(state.current_calltree_node == state.active_calltree_node) { + if(frame.result.ok) { + if(code.body.type == 'do') { + const return_statement = find_node(frame, n => + n.type == 'return' && n.result?.ok + ) + + if(return_statement == null) { + // Fn has no return statement + return { + state: {...state, current_module: loc.module}, + effects: {type: 'set_caret_position', args: [code.body.index, true]} + } + } else { + result_node = return_statement.children[0] + } + + } else { + // Last children is function body expr + result_node = frame.children[frame.children.length - 1] + } + } else { + result_node = find_error_origin_node(frame) + } + + node = find_node(code, n => is_eq(result_node, n)) + + } else { + result_node = find_node(frame, n => + n.type == 'function_call' + && + n.result.call.id == state.current_calltree_node.id + ) + node = find_node(code, n => is_eq(result_node, n)) + } + + return { + state: {...state, + current_module: loc.module, + selection_state: { + index: node.index, + node, + initial_is_expand: true, + result: result_node.result, + } + }, + effects: {type: 'set_caret_position', args: [node.index, true]} + } + +} + +const select_arguments = state => { + if(state.current_calltree_node.toplevel) { + return {state} + } + + const loc = calltree_node_loc(state.active_calltree_node) + const frame = active_frame(state) + + let node, result + + if(state.current_calltree_node == state.active_calltree_node) { + if(state.active_calltree_node.toplevel) { + return {state} + } + node = state.active_calltree_node.code.children[0] // function_args + result = frame.children[0].result + + } else { + const call = find_node(frame, n => + n.type == 'function_call' + && + n.result.call.id == state.current_calltree_node.id + ) + const call_node = find_node(state.active_calltree_node.code, n => is_eq(n, call)) + node = call_node.children[1] // call_args + result = call.children[1].result + } + + return { + state: {...state, + current_module: loc.module, + selection_state: { + index: node.index, + node, + initial_is_expand: true, + result, + } + }, + effects: {type: 'set_caret_position', args: [node.index, true]} + } +} + +export const calltree_commands = { + arrow_down, + arrow_up, + arrow_left, + arrow_right, + click, + select_return_value, + select_arguments, +} diff --git a/src/cmd.js b/src/cmd.js new file mode 100644 index 0000000..8c4f733 --- /dev/null +++ b/src/cmd.js @@ -0,0 +1,661 @@ +import {map_object, pick_keys} from './utils.js' +import { + is_eq, is_child, ancestry, ancestry_inc, map_tree, + find_leaf, find_fn_by_location, find_node, find_error_origin_node +} from './ast_utils.js' +import {load_modules} from './parse_js.js' +import {find_export} from './find_definitions.js' +import {eval_modules} from './eval.js' +import { + root_calltree_node, root_calltree_module, calltree_commands, + add_frame, calltree_node_loc, expand_path, + initial_calltree_node, default_expand_path, toggle_expanded, active_frame, + find_call, find_call_node, set_active_calltree_node +} from './calltree.js' + +const apply_active_calltree_node = (state, index) => { + if(!state.parse_result.ok) { + return state + } + + const node = find_call_node(state, index) + + if( + // edit module that is not imported (maybe recursively by state.entrypoint) + node == null + || + node.type == 'do' /* toplevel AST node */ + ) { + const result = eval_modules(state.parse_result.modules, state.parse_result.sorted) + const next = { + ...state, + calltree: result.calltree, + calltree_actions: result.calltree_actions, + } + if(node == state.parse_result.modules[root_calltree_module(next)]) { + const toplevel = root_calltree_node(next) + return add_frame( + default_expand_path( + next, + toplevel + ), + toplevel, + ) + } else { + const {node, state: next2} = initial_calltree_node(next) + return set_active_calltree_node(next2, null, node) + } + } + + const {calltree, call, calltree_actions} = eval_modules( + state.parse_result.modules, + state.parse_result.sorted, + {index: node.index, module: state.current_module}, + ) + + if(call == null) { + // Unreachable call + const {node, state: next} = initial_calltree_node({ + ...state, + calltree, + calltree_actions, + }) + return set_active_calltree_node(next, null, node) + } + + const next = {...state, calltree, calltree_actions } + // We cannot use `call` because `code` was not assigned to it + const active_calltree_node = find_node(root_calltree_node(next), + n => n.id == call.id + ) + + return add_frame( + default_expand_path( + expand_path( + next, + active_calltree_node + ) + ), + active_calltree_node, + ) +} + +const input = (state, code, index) => { + const files = {...state.files, [state.current_module]: code} + const next = apply_active_calltree_node( + apply_code({...state, files}, [state.current_module]), + index + ) + const effects1 = next.current_module == '' + ? {type: 'save_to_localstorage', args: ['code', code]} + : {type: 'write', args: [ + next.current_module, + next.files[next.current_module], + ]} + const {state: next2, effects: effects2} = do_move_cursor(next, index) + return { + state: next2, + effects: [effects1, effects2], + } +} + +const apply_code = (state, dirty_files) => { + const parse_result = load_modules(state.entrypoint, module => { + if(dirty_files != null && dirty_files.includes(module)) { + return state.files[module] + } + + if(state.parse_result != null) { + const result = state.parse_result.cache[module] + if(result != null) { + return result + } else { + return state.files[module] + } + } else { + return state.files[module] + } + + }) + + return { + ...state, + parse_result, + calltree: null, + + // Shows that calltree is brand new and requires entire rerender + calltree_changed_token: {}, + + calltree_actions: null, + current_calltree_node: null, + active_calltree_node: null, + calltree_node_is_expanded: null, + frames: null, + calltree_node_by_loc: null, + // TODO keep selection_state? + selection_state: null, + } + +} + +export const apply_code_with_active_calltree_node = (state, index) => { + const next = apply_code(state) + return apply_active_calltree_node(next, index) +} + +const can_evaluate_node = (parent, node) => { + // TODO also can evaluate in top level even if stepped into (and evaluate in + // any stack frame that was before current one) + + const anc = ancestry(node, parent) + if(anc == null){ + return {ok: false, message: 'out of scope'} + } + + const intermediate_fn = anc.find(n => + !is_eq(n, parent) && !is_eq(n, node) && n.type == 'function_expr' + ) + + if(intermediate_fn != null){ + // TODO check if identifier is defined in current scope, and eval + return {ok: false, message: 'cannot eval inside function: first step into it'} + } + + return {ok: true} +} + +const validate_index_action = state => { + if(!state.parse_result.ok){ + return {state, effects: {type: 'set_status', args: ['invalid syntax']}} + } + if( + state.active_calltree_node == null + || + calltree_node_loc(state.active_calltree_node).module != state.current_module + ) { + return { + state, + effects: { + type: 'set_status', + args: ['code was not reached during program execution'] + } + } + } +} + +const get_step_into_node = (ast, frame, index) => { + // TODO step into from toplevel (must be fixed by frame follows cursor) + + const node = find_leaf(ast, index) + + // Find parent node with function call + const call = ancestry_inc(node, ast).find(n => n.type == 'function_call') + + if(call == null){ + return {ok: false, message: 'no function call to step into'} + } + + const can_eval = can_evaluate_node(frame, call) + if(!can_eval.ok){ + return {ok: false, message: can_eval.message} + } + + const callnode = find_node(frame, n => is_eq(n, call)) + if(callnode.result == null) { + return {ok: false, message: 'call was not reached during program execution'} + } else { + return {ok: true, calltree_node: callnode.result.call} + } +} + +const step_into = (state, index) => { + + const validate_result = validate_index_action(state) + if(validate_result != null) { + return validate_result + } + + const {ok, message, calltree_node} = get_step_into_node( + state.parse_result.modules[state.current_module], + active_frame(state), + index + ) + if(!ok){ + return {state, effects: {type: 'set_status', args: [message]}} + } else { + const expanded = { + ...state, calltree_node_is_expanded: { + ...state.calltree_node_is_expanded, [calltree_node.id]: true + } + } + return toggle_expanded( + {...expanded, current_calltree_node: calltree_node}, + true + ) + } +} + +const get_next_selection_state = (selection_state, frame, is_expand, index) => { + if(selection_state != null && selection_state.index == index){ + // Expanding/collapsing selection + let next_node + const effective_is_expand = selection_state.initial_is_expand == is_expand + if(effective_is_expand){ + if(is_eq(selection_state.node, frame)) { + next_node = selection_state.node + } else { + next_node = ancestry(selection_state.node, frame).find(n => !n.not_evaluatable) + if(next_node.is_statement) { + next_node = selection_state.node + } + } + } else { + // TODO when collapsing, also check that node is evaluatable + // collapse + if(selection_state.node.children != null){ + next_node = + selection_state.node.children.find(n => + n.index <= index && n.index + n.length > index + ) + ?? + // caret not inside child but in whitespace + selection_state.node + } else { + // no children, cannot collapse + next_node = selection_state.node + } + } + return { + ok: true, + initial_is_expand: selection_state.initial_is_expand, + node: next_node, + index, + } + } else { + // Creating new selection + const leaf = find_leaf(frame, index); + const a = ancestry_inc(leaf, frame); + const node = a.find(n => !n.not_evaluatable); + if(node.is_statement) { + return { + ok: false, + message: 'can only evaluate expression, not statement', + } + } + return { + ok: true, + index, + node, + initial_is_expand: is_expand, + } + } +} + +export const selection = (selection_state, frame, is_expand, index) => { + const leaf = find_leaf(frame, index) + if(leaf == null) { + return { + ok: false, + message: 'out of scope', + } + } + + const next_selection_state = get_next_selection_state(selection_state, frame, is_expand, index) + + if(!next_selection_state.ok) { + return next_selection_state + } + + const {ok, message} = can_evaluate_node(frame, next_selection_state.node) + if(ok){ + const node = find_node(frame, n => is_eq(n, next_selection_state.node)) + if(node.result == null) { + return { + ...next_selection_state, + ok: false, + message: 'expression was not reached during program execution', + } + } else { + let result + if(node.result.ok) { + result = node.result + } else { + const error_node = find_error_origin_node(node) + result = error_node.result + } + return {...next_selection_state, ok: true, result} + } + } else { + return {...next_selection_state, ok: false, message} + } +} + +const eval_selection = (state, index, is_expand) => { + const validate_result = validate_index_action(state) + if(validate_result != null) { + return validate_result + } + + const selection_state = selection( + state.selection_state, + active_frame(state), + is_expand, + index + ) + + const nextstate = {...state, selection_state} + + if(!selection_state.ok) { + return {state: nextstate, effects: {type: 'set_status', args: [selection_state.message]}} + } + + return {state: nextstate} +} + + +const change_current_module = (state, current_module) => { + if(state.files[current_module] == null) { + return { + state, + effects: {type: 'set_status', args: ['File not found']} + } + } else { + return {...state, current_module} + } +} + +const change_entrypoint = (state, entrypoint, index) => { + return apply_code_with_active_calltree_node( + {...state, + entrypoint, + current_module: entrypoint, + }, + index + ) +} + +const goto_definition = (state, index) => { + if(!state.parse_result.ok){ + return {state, effects: {type: 'set_status', args: ['unresolved syntax errors']}} + } else { + const module = state.parse_result.modules[state.current_module] + const node = find_leaf(module, index) + if(node == null || node.type != 'identifier') { + return {state, effects: {type: 'set_status', args: ['not an identifier']}} + } else { + const d = node.definition + if(d == 'global') { + return {state, effects: {type: 'set_status', args: ['global variable']}} + } else if (d == 'self') { + // place where identifier is declared, nothing to do + return {state} + } else { + let loc + if(d.module != null) { + const exp = find_export(node.value, state.parse_result.modules[d.module]) + loc = {module: d.module, index: exp.index} + } else { + loc = {module: state.current_module, index: d.index} + } + return { + state: {...state, current_module: loc.module}, + effects: {type: 'set_caret_position', args: [loc.index]} + } + } + } + } +} + +const goto_problem = (state, p) => { + return { + state: {...state, current_module: p.module}, + // TODO set focus after jump + effects: {type: 'set_caret_position', args: [p.index]} + } +} + + +// TODO remove? +// TODO: to every child, add displayed_children property +/* +const filter_calltree = (calltree, pred) => { + const do_filter_calltree = calltree => { + const children = calltree.children && calltree.children + .map(c => do_filter_calltree(c)) + .flat() + + if(pred(calltree)) { + return [{...calltree, children}] + } else { + return children + } + } + + const result = do_filter_calltree(calltree) + + if(result.length == 1 && result[0].toplevel) { + return result[0] + } else { + return {...calltree, children: result} + } +} +*/ + +const get_value_explorer = (state, index) => { + if(state.active_calltree_node == null) { + return null + } + + const frame = active_frame(state) + + if(frame.type == 'function_expr' && frame.body.type != 'do') { + return { + index: frame.children[1].index + frame.children[1].length, + result: frame.children[1].result + } + } + + if( + true + // not toplevel, function expr + && frame.type == 'function_expr' + && index >= frame.children[0].index + && index < frame.children[0].index + frame.children[0].length + ) { + if(frame.children[0].children.length == 0) { + // Zero args + return null + } else { + // cursor in args, show args + return { + index: frame.children[0].index + frame.children[0].length, + result: frame.children[0].result, + } + } + } + + const leaf = find_leaf(frame, index) + const adjusted_leaf = ( + // We are in the whitespace at the beginning or at the end of the file + leaf == null + || + // Empty body or cursor between statements + leaf.type == 'do' && index > frame.index + ) + // Try find statement one symbol before, in case we are typing at the end + // of current statement + ? find_leaf(frame, index - 1) + : leaf + + if( + adjusted_leaf == null + || + adjusted_leaf.type == 'do' + || + /* between body and args*/ + is_eq(frame, adjusted_leaf) + ) { + return null + } + + const anc = ancestry_inc(adjusted_leaf, frame) + const intermediate_fn = anc.find(n => + !is_eq(n, frame) && !is_eq(n, adjusted_leaf) && n.type == 'function_expr' + ) + if(intermediate_fn != null) { + // TODO maybe cut `anc` from frame to intermediate fn, so we do not look + // inside intermediate fn. But it should be fixed by frame follows cursor + return null + } + + // Find inner do + const do_index = anc.findIndex(n => n.type == 'do') + const do_node = anc[do_index] + const stmt = anc[do_index - 1] + + if(stmt.result == null) { + // statement was not evaluated + return null + } + + let result + + if(stmt.result.ok) { + if(['const', 'assignment'].includes(stmt.type)) { + result = stmt.children[1].result + } else if(stmt.type == 'return') { + result = stmt.children[0].result + } else if(stmt.type == 'let') { + return { + index: stmt.index + stmt.length, + result: + { + ok: true, + value: Object.fromEntries( + stmt.children.map(c => + [c.value, c.result.value] + ) + ) + } + } + } else if(stmt.type == 'if'){ + return null + } else if(stmt.type == 'import'){ + result = { + ok: true, + value: pick_keys( + state.calltree[stmt.full_import_path].exports, + stmt.imports.map(i => i.value) + ), + } + } else if (stmt.type == 'export') { + result = stmt.children[0].children[1].result + } else { + result = stmt.result + } + } else { + result = find_error_origin_node(stmt).result + } + + const pos = stmt.index + stmt.length + + return {index: pos, result} +} + +const do_move_cursor = (state, index) => { + const value_exp = get_value_explorer(state, index) + if(value_exp == null) { + return { + state, + effects: {type: 'unembed_value_explorer', args: []} + } + } else { + return { + state, + effects: + state.current_module == + calltree_node_loc(state.active_calltree_node).module + ? {type: 'embed_value_explorer', args: [value_exp]} + : null + + } + } +} + +const move_cursor = (s, index) => { + if(!s.parse_result.ok){ + return {state: s} + } + + // Remove selection on move cursor + const state_sel_removed = {...s, selection_state: null} + + const state = find_call(state_sel_removed, index) + + const validate_result = validate_index_action(state) + if(validate_result != null) { + return { + state, + effects: {type: 'unembed_value_explorer', args: []} + } + } + + return do_move_cursor(state, index) +} + +const load_dir = (state, dir) => { + const collect_files = dir => dir.kind == 'file' + ? [dir] + : dir.children.map(collect_files).flat() + + const files = Object.fromEntries( + collect_files(dir).map(f => [f.path, f.contents]) + ) + + return { + ...state, + project_dir: dir, + files: {...files, ...state.files} + } +} + +const create_file = (state, dir, current_module) => { + return {...load_dir(state, dir), current_module} +} + +export const get_initial_state = state => { + const with_files = state.project_dir == null + ? state + : load_dir(state, state.project_dir) + + const entrypoint = with_files.entrypoint + const current_module = with_files.current_module + + const s = { + ...with_files, + // If module for entrypoint or current_module does not exist, use *scratch* + entrypoint: + with_files.files[entrypoint] == null + ? '' + : entrypoint, + current_module: with_files.files[current_module] == null + ? '' + : current_module, + } + + return apply_code_with_active_calltree_node(s, 0) +} + +export const COMMANDS = { + input, + load_dir, + create_file, + step_into, + change_current_module, + change_entrypoint, + goto_definition, + goto_problem, + move_cursor, + eval_selection, + calltree: calltree_commands, +} diff --git a/src/color.js b/src/color.js new file mode 100644 index 0000000..aa00200 --- /dev/null +++ b/src/color.js @@ -0,0 +1,214 @@ +const is_result_eq = (a,b) => a.result == null + ? b.result == null + : b.result != null + && a.result.ok == b.result.ok + && a.result.error_origin == b.result.error_origin + +const node_to_color = node => ({ + index: node.index, + length: node.length, + result: node.result == null + ? null + : node.type == 'function_expr' + ? null + : node.result.ok + ? {ok: true} + : node.result.error == null + ? {ok: false, error_origin: false} + : {ok: false, error_origin: true} +}) + +const is_short_circuit = node => + node.type == 'binary' || node.type == 'ternary' + +const color_children = (node, is_root) => { + const coloring = node.children.map(n => do_color(n)).reduce( + (coloring, [range, ...rest]) => { + if(coloring.length == 0) { + return [range, ...rest] + } else { + const prev_range = coloring[coloring.length - 1] + if(is_result_eq(prev_range, range)) { + // Merge ranges + return [ + ...coloring.slice(0, coloring.length - 1), + { + index: prev_range.index, + length: range.index - prev_range.index + range.length, + result: range.result == null ? null : {ok: range.result.ok} + }, + ...rest + ] + } else if(!is_short_circuit(node) && prev_range.result == null && range.result?.ok){ + // Expand range back to the end of prev range + const index = prev_range.index + prev_range.length + return [ + ...coloring, + {...range, + index, + length: range.index - index + range.length, + }, + ...rest, + ] + } else if(!is_short_circuit(node) && prev_range.result?.ok && range.result == null) { + // Expand prev_range until beginning of range + const index = prev_range.index + prev_range.length + return [ + ...coloring.slice(0, coloring.length - 1), + {...prev_range, + length: range.index - prev_range.index + }, + range, + ...rest, + ] + } else { + // Append range + return [ + ...coloring, + range, + ...rest, + ] + } + } + }, + [] + ) + + if( + node.result == null || node.result?.ok + && + // All colors the same + coloring.reduce( + (result, c) => result && is_result_eq(coloring[0], c), + true + ) + ) { + + if(is_result_eq(node, coloring[0])) { + if(is_root && node.type == 'function_expr') { + // Override null result for function expr + return [{...node_to_color(node), result: {ok: node.result.ok}}] + } else { + return [node_to_color(node)] + } + } else { + const node_color = node_to_color(node) + const last = coloring[coloring.length - 1] + const index = coloring[0].index + coloring[0].length + return [ + { + ...node_color, + length: coloring[0].index - node_color.index, + }, + ...coloring, + { + ...node_color, + index, + length: node.index + node.length - index, + }, + ] + } + + } + + if(coloring.length == 0) { + throw new Error('illegal state') + } + + // if first child is ok, then expand it to the beginning of parent + const first = coloring[0] + const adj_left = is_result_eq(first, node) && node.result?.ok + ? [ + {...first, + index: node.index, + length: first.length + first.index - node.index + }, + ...coloring.slice(1), + ] + : coloring + + // if last child is ok, then expand it to the end of parent + const last = adj_left[adj_left.length - 1] + const adj_right = is_result_eq(last, node) && node.result?.ok + ? [ + ...adj_left.slice(0, adj_left.length - 1), + {...last, + index: last.index, + length: node.index + node.length - last.index, + }, + ] + : adj_left + + return adj_right +} + +const do_color = (node, is_root = false) => { + if(node.type == 'function_expr' && !is_root) { + return [{...node_to_color(node), result: null}] + } + + if( + false + || node.children == null + || node.children.length == 0 + ) { + return [node_to_color(node)] + } + + if(node.result?.error != null) { + return [node_to_color(node)] + } + + const result = color_children(node, is_root) + return node.result != null && !node.result.ok + ? result.map(c => c.result == null + ? {...c, result: {ok: false, error_origin: false}} + : c + ) + : result +} + +export const color = frame => { + const coloring = do_color(frame, true) + .filter(c => + // Previously we colored nodes that were not reach to grey color, now we + // just skip them + c.result != null + && + // Parts that were not error origins + (c.result.ok || c.result.error_origin) + ) + + // Sanity-check result + const {ok} = coloring.reduce( + ({ok, prev}, c) => { + if(!ok) { + return {ok} + } + if(prev == null) { + return {ok, prev: c} + } else { + // Check that prev is before next + // TODO check that next is right after prev, ie change > to == + if(prev.index + prev.length > c.index) { + return {ok: false} + } else { + return {ok: true, prev: c} + } + } + }, + {ok: true, prev: null} + ) + if(!ok) { + throw new Error('illegal state') + } + return coloring +} + +export const color_file = (state, file) => + Object + .values(state.calltree_node_by_loc?.[file] ?? {}) + // node_id == null means it is unreachable, so do not color + .filter(node_id => node_id != null) + .map(node_id => state.frames[node_id].coloring) + .flat() diff --git a/src/editor/calltree.js b/src/editor/calltree.js new file mode 100644 index 0000000..7ede4a5 --- /dev/null +++ b/src/editor/calltree.js @@ -0,0 +1,173 @@ +import {exec} from '../index.js' +import {el, stringify, fn_link, scrollIntoViewIfNeeded} from './domutils.js' +import {FLAGS} from '../feature_flags.js' +import {stringify_for_header} from './value_explorer.js' +import {find_node} from '../ast_utils.js' +import {is_expandable, root_calltree_node} from '../calltree.js' + +// TODO perf - quadratic difficulty +const join = arr => arr.reduce( + (acc, el) => acc.length == 0 + ? [el] + : [...acc, ',', el], + [], +) + +export class CallTree { + constructor(ui, container) { + this.ui = ui + this.container = container + + this.container.addEventListener('keydown', (e) => { + + // Do not scroll + e.preventDefault() + + if(e.key == 'F1') { + this.ui.editor.focus() + } + + if(e.key == 'F2') { + this.ui.editor.focus_value_explorer(this.container) + } + + if(e.key == 'a') { + if(FLAGS.embed_value_explorer) { + exec('calltree.select_arguments') + } else { + // TODO make clear that arguments are shown + this.ui.eval.show_value(this.state.current_calltree_node.args) + this.ui.eval.focus_value_or_error(this.container) + } + } + + if(e.key == 'r' || e.key == 'Enter') { + if(FLAGS.embed_value_explorer) { + exec('calltree.select_return_value') + } else { + // TODO make clear that return value is shown + this.ui.eval.show_value_or_error(this.state.current_calltree_node) + this.ui.eval.focus_value_or_error(this.container) + } + } + + if(e.key == 'ArrowDown' || e.key == 'j'){ + exec('calltree.arrow_down') + } + + if(e.key == 'ArrowUp' || e.key == 'k'){ + exec('calltree.arrow_up') + } + + if(e.key == 'ArrowLeft' || e.key == 'h'){ + exec('calltree.arrow_left') + } + + if(e.key == 'ArrowRight' || e.key == 'l'){ + exec('calltree.arrow_right') + } + }) + + } + + on_click_node(id) { + exec('calltree.click', id) + } + + clear_calltree(){ + this.container.innerHTML = '' + this.node_to_el = new Map() + this.state = null + } + + render_node(n, current_node){ + const is_expanded = this.state.calltree_node_is_expanded[n.id] + + const result = el('div', 'callnode', + el('div', { + 'class': (n == current_node ? 'call_el active' : 'call_el'), + click: () => this.on_click_node(n.id), + }, + !is_expandable(n) + ? '\xa0' + : is_expanded ? '▼' : '▶', + n.toplevel + ? el('span', '', + el('i', '', + 'toplevel: ' + (n.module == '' ? '*scratch*' : n.module), + ), + n.ok ? '' : el('span', 'call_header error', '\xa0', n.error.toString()), + ) + : el('span', + 'call_header ' + + (n.ok ? '' : 'error') + + (n.fn.__location == null ? ' native' : '') + , + // TODO show `this` argument + n.fn.__location == null + ? fn_link(n.fn) + : n.fn.name + , + '(' , + ...join( + n.args.map( + a => typeof(a) == 'function' + ? fn_link(a) + : stringify_for_header(a) + ) + ), + ')' , + // TODO: show error message only where it was thrown, not every frame? + ': ', (n.ok ? stringify_for_header(n.value) : n.error.toString()) + ), + ), + (n.children == null || !is_expanded) + ? null + : n.children.map(c => this.render_node(c, current_node)) + ) + + this.node_to_el.set(n.id, result) + + result.is_expanded = is_expanded + + return result + } + + render_active(node, is_active) { + const dom = this.node_to_el.get(node.id).getElementsByClassName('call_el')[0] + if(is_active) { + dom.classList.add('active') + } else { + dom.classList.remove('active') + } + } + + render_select_node(state) { + this.render_active(this.state.current_calltree_node, false) + this.state = state + this.render_active(this.state.current_calltree_node, true) + scrollIntoViewIfNeeded( + this.container, + this.node_to_el.get(this.state.current_calltree_node.id).getElementsByClassName('call_el')[0] + ) + } + + render_expand_node(state) { + this.state = state + const current_node = this.state.current_calltree_node + const prev_dom_node = this.node_to_el.get(current_node.id) + const next = this.render_node(current_node, current_node) + prev_dom_node.parentNode.replaceChild(next, prev_dom_node) + } + + // TODO on hover highlight line where function defined/ + // TODO hover ? + render_calltree(state){ + this.clear_calltree() + this.state = state + const root = root_calltree_node(this.state) + const current_node = state.current_calltree_node + this.container.appendChild(this.render_node(root, current_node)) + this.render_select_node(state, root, current_node) + } +} diff --git a/src/editor/domutils.js b/src/editor/domutils.js new file mode 100644 index 0000000..7e53282 --- /dev/null +++ b/src/editor/domutils.js @@ -0,0 +1,117 @@ +export function el(tag, className, ...children){ + const result = document.createElement(tag) + if(typeof(className) == 'string'){ + result.setAttribute('class', className) + } else { + const attrs = className + for(let attrName in attrs){ + const value = attrs[attrName] + if(['change','click'].includes(attrName)){ + result.addEventListener(attrName, value) + } else if(attrName == 'checked') { + if(attrs[attrName]){ + result.setAttribute(attrName, "checked") + } + } else { + result.setAttribute(attrName, value) + } + } + } + children.forEach(child => { + const append = child => { + if(typeof(child) == 'undefined') { + throw new Error('illegal state') + } else if(child !== null) { + result.appendChild( + typeof(child) == 'string' + ? document.createTextNode(child) + : child + ) + } + } + if(Array.isArray(child)) { + child.forEach(append) + } else { + append(child) + } + }) + return result +} + +export function stringify(val){ + function fn_to_str(fn){ + // TODO if name is 'anonymous', then change name for code + return fn.__location == null + ? `${fn.name}` + : `fn ${fn.name}` + } + if(typeof(val) == 'undefined') { + return 'undefined' + } else if(typeof(val) == 'function'){ + return fn_to_str(val) + } else { + return JSON.stringify(val, (key, value) => { + if(typeof(value) == 'function'){ + return fn_to_str(value) + } else { + return value + } + }) + } +} + +export function fn_link(fn){ + const str = stringify(fn) + const c = document.createElement('div') + c.innerHTML = str + return c.children[0] +} + + + +// Idea is borrowed from: +// https://mhk-bit.medium.com/scroll-into-view-if-needed-10a96e0bdb61 +// https://stackoverflow.com/questions/37137450/scroll-all-nested-scrollbars-to-bring-an-html-element-into-view +export const scrollIntoViewIfNeeded = (container, target) => { + + // Target is outside the viewport from the top + if(target.offsetTop - container.scrollTop - container.offsetTop < 0){ + // The top of the target will be aligned to the top of the visible area of the scrollable ancestor + target.scrollIntoView(true); + // Do not scroll horizontally + container.scrollLeft = 0 + } + + // Target is outside the view from the bottom + if(target.offsetTop - container.scrollTop - container.offsetTop - container.clientHeight + target.clientHeight > 0) { + // The bottom of the target will be aligned to the bottom of the visible area of the scrollable ancestor. + target.scrollIntoView(false); + // Do not scroll horizontally + container.scrollLeft = 0 + } + + /* + Also works + + // Target is outside the view from the top + if (target.getBoundingClientRect().y < container.getBoundingClientRect().y) { + // The top of the target will be aligned to the top of the visible area of the scrollable ancestor + target.scrollIntoView(); + } + + // Target is outside the view from the bottom + if ( + target.getBoundingClientRect().bottom - container.getBoundingClientRect().bottom + + // Adjust for scrollbar size + container.offsetHeight - container.clientHeight + > 0 + ) { + // The bottom of the target will be aligned to the bottom of the visible area of the scrollable ancestor. + target.scrollIntoView(false); + } + */ + +}; diff --git a/src/editor/editor.js b/src/editor/editor.js new file mode 100644 index 0000000..aaa0fbc --- /dev/null +++ b/src/editor/editor.js @@ -0,0 +1,469 @@ +import {exec, get_state} from '../index.js' +import {ValueExplorer} from './value_explorer.js' +import {el, stringify, fn_link} from './domutils.js' +import {FLAGS} from '../feature_flags.js' + +/* + normalize events 'change' and 'changeSelection': + - change is debounced + - changeSelection must not fire if 'change' is fired. So for every keystroke, + either change or changeSelection should be fired, not both + - changeSelection fired only once (ace fires it multiple times for single + keystroke) +*/ +const normalize_events = (ace_editor, { + on_change, + on_change_selection, + is_change_selection_supressed, + on_change_immediate, +}) => { + const TIMEOUT = 1000 + + let state + + const set_initial_state = () => { + state = {} + } + + set_initial_state() + + const flush = () => { + if(state.change_args != null) { + on_change(...state.change_args) + } else if(state.change_selection_args != null) { + on_change_selection(...state.change_selection_args) + } + set_initial_state() + } + + ace_editor.on('change', (...args) => { + on_change_immediate() + + if(state.tid != null) { + clearTimeout(state.tid) + } + + state.change_args = args + + state.tid = setTimeout(() => { + state.tid = null + flush() + }, TIMEOUT) + }) + + ace_editor.on('changeSelection', (...args) => { + if(is_change_selection_supressed()) { + return + } + if(state.tid != null) { + // flush is already by `change`, skip `changeSelection` + return + } + state.change_selection_args = args + if(!state.is_flush_set) { + state.is_flush_set = true + Promise.resolve().then(() => { + if(state.tid == null) { + flush() + } + }) + } + }) +} + +export class Editor { + + constructor(ui, editor_container){ + this.ui = ui + this.editor_container = editor_container + + this.markers = {} + this.sessions = {} + + this.ace_editor = ace.edit(this.editor_container) + + this.ace_editor.setOptions({ + behavioursEnabled: false, + // Scroll past end for value explorer + scrollPastEnd: 100 /* Allows to scroll 100* */, + }) + + normalize_events(this.ace_editor, { + on_change: () => { + try { + exec('input', this.ace_editor.getValue(), this.get_caret_position()) + } catch(e) { + // Do not throw Error to ACE because it breaks typing + console.error(e) + this.ui.set_status(e.message) + } + }, + + on_change_immediate: () => { + this.update_value_explorer_margin() + }, + + on_change_selection: () => { + try { + if(!this.is_change_selection_supressed) { + exec('move_cursor', this.get_caret_position()) + } + } catch(e) { + // Do not throw Error to ACE because it breaks typing + console.error(e) + this.ui.set_status(e.message) + } + }, + + is_change_selection_supressed: () => { + return this.is_change_selection_supressed + } + }) + + this.focus() + + this.init_keyboard() + } + + focus() { + this.ace_editor.focus() + } + + supress_change_selection(action) { + try { + this.is_change_selection_supressed = true + action() + } finally { + this.is_change_selection_supressed = false + } + } + + ensure_session(file, code) { + let session = this.sessions[file] + if(session == null) { + session = ace.createEditSession(code) + this.sessions[file] = session + session.setUseWorker(false) + session.setOptions({ + mode: "ace/mode/javascript", + tabSize: 2, + useSoftTabs: true, + }) + } + return session + } + + get_session(file) { + return this.sessions[file] + } + + switch_session(file) { + // Supress selection change triggered by switching sessions + this.supress_change_selection(() => { + this.ace_editor.setSession(this.get_session(file)) + }) + } + + unembed_value_explorer() { + if(this.widget != null) { + this.ace_editor.getSession().widgetManager.removeLineWidget(this.widget) + this.widget = null + } + } + + update_value_explorer_margin() { + if(this.widget != null) { + this.widget.content.style.marginLeft = + (this.ace_editor.getSession().getScreenWidth() + 1) + 'ch' + } + } + + embed_value_explorer({index, result: {ok, value, error}}) { + this.unembed_value_explorer() + + const session = this.ace_editor.getSession() + const pos = session.doc.indexToPosition(index) + const row = pos.row + + const line_height = this.ace_editor.renderer.lineHeight + + let content + const container = el('div', {'class': 'embed_value_explorer_container'}, + el('div', {'class': 'embed_value_explorer_wrapper'}, + content = el('div', { + // Ace editor cannot render widget before the first line. So we + // render in on the next line and apply translate + 'style': `transform: translate(0px, -${line_height}px)`, + 'class': 'embed_value_explorer_content', + tabindex: 0 + }) + ) + ) + + let initial_scroll_top + + const escape = () => { + if(initial_scroll_top != null) { + // restore scroll + session.setScrollTop(initial_scroll_top) + } + if(this.widget.return_to == null) { + this.focus() + } else { + this.widget.return_to.focus() + } + // TODO select root in value explorer + } + + container.addEventListener('keydown', e => { + if(e.key == 'Escape') { + escape() + } + }) + + if(ok) { + const exp = new ValueExplorer({ + container: content, + event_target: container, + on_escape: escape, + scroll_to_element: t => { + if(initial_scroll_top == null) { + initial_scroll_top = session.getScrollTop() + } + let scroll + const out_of_bottom = t.getBoundingClientRect().bottom - this.editor_container.getBoundingClientRect().bottom + if(out_of_bottom > 0) { + session.setScrollTop(session.getScrollTop() + out_of_bottom) + } + const out_of_top = this.editor_container.getBoundingClientRect().top - t.getBoundingClientRect().top + if(out_of_top > 0) { + session.setScrollTop(session.getScrollTop() - out_of_top) + } + }, + }) + + exp.render(value) + } else { + content.appendChild(el('span', 'eval_error', error.toString())) + } + + this.widget = { + row, + fixedWidth: true, + el: container, + content, + } + + this.update_value_explorer_margin() + + const LineWidgets = require("ace/line_widgets").LineWidgets; + if (!session.widgetManager) { + session.widgetManager = new LineWidgets(session); + session.widgetManager.attach(this.ace_editor); + } + session.widgetManager.addLineWidget(this.widget) + } + + focus_value_explorer(return_to) { + if(FLAGS.embed_value_explorer) { + if(this.widget != null) { + this.widget.return_to = return_to + this.widget.content.focus({preventScroll: true}) + } + } else { + if(get_state().selection_state != null) { + this.ui.eval.focus_value_or_error() + } + } + } + + set_keyboard_handler(type) { + if(type != null) { + localStorage.keyboard = type + } + this.ace_editor.setKeyboardHandler( + type == 'vim' ? "ace/keyboard/vim" : null + ) + } + + init_keyboard(){ + this.set_keyboard_handler(localStorage.keyboard) + + const VimApi = require("ace/keyboard/vim").CodeMirror.Vim + + + this.ace_editor.commands.bindKey("F1", "switch_window"); + VimApi._mapCommand({ + keys: '', + type: 'action', + action: 'aceCommand', + actionArgs: { name: "switch_window" } + }) + this.ace_editor.commands.addCommand({ + name: 'switch_window', + exec: (editor) => { + this.ui.calltree_container.focus() + } + }) + + + this.ace_editor.commands.bindKey("F3", "goto_definition"); + VimApi._mapCommand({ + keys: 'gd', + type: 'action', + action: 'aceCommand', + actionArgs: { name: "goto_definition" } + }) + this.ace_editor.commands.addCommand({ + name: 'goto_definition', + exec: (editor) => { + this.goto_definition() + } + }) + + + this.ace_editor.commands.bindKey("F2", "focus_value_explorer"); + this.ace_editor.commands.addCommand({ + name: 'focus_value_explorer', + exec: (editor) => { + this.focus_value_explorer() + } + }) + + + this.ace_editor.commands.bindKey("ctrl-i", 'step_into') + VimApi._mapCommand({ + keys: '\\i', + type: 'action', + action: 'aceCommand', + actionArgs: { name: "step_into" } + }) + this.ace_editor.commands.addCommand({ + name: 'step_into', + exec: (editor) => { + exec('step_into', this.get_caret_position()) + } + }) + + + this.ace_editor.commands.bindKey("ctrl-o", 'step_out') + VimApi._mapCommand({ + keys: '\\o', + type: 'action', + action: 'aceCommand', + actionArgs: { name: "step_out" } + }) + this.ace_editor.commands.addCommand({ + name: 'step_out', + exec: (editor) => { + exec('calltree.arrow_left') + } + }) + + + this.ace_editor.commands.addCommand({ + name: 'expand_selection', + exec: () => { + exec('eval_selection', this.get_caret_position(), true) + } + }) + this.ace_editor.commands.addCommand({ + name: 'collapse_selection', + exec: () => { + exec('eval_selection', this.get_caret_position(), false) + } + }) + this.ace_editor.commands.bindKey("ctrl-j", 'expand_selection') + this.ace_editor.commands.bindKey("ctrl-down", 'expand_selection') + this.ace_editor.commands.bindKey("ctrl-k", 'collapse_selection') + this.ace_editor.commands.bindKey("ctrl-up", 'collapse_selection') + + + this.ace_editor.commands.addCommand({ + name: 'edit', + exec: (editor, input) => { + const module = input.args == null ? '' : input.args[0] + exec('change_current_module', module) + } + }) + VimApi.defineEx("edit", "e", function(cm, input) { + cm.ace.execCommand("edit", input) + }) + + // TODO remove my custom binding + VimApi.map('jj', '', 'insert') + } + + add_marker(file, className, from, to){ + const session = this.get_session(file) + const from_pos = session.doc.indexToPosition(from) + const to_pos = session.doc.indexToPosition(to) + const markerId = session.addMarker( + new ace.Range(from_pos.row,from_pos.column,to_pos.row,to_pos.column), + className + ) + if(this.markers[file] == null){ + this.markers[file] = [] + } + this.markers[file].push({className, from, to, markerId}) + } + + remove_markers_of_type(file, type){ + if(this.markers[file] == null){ + this.markers[file] = [] + } + const for_removal = this.markers[file].filter(h => h.className == type) + const session = this.get_session(file) + for(let marker of for_removal){ + session.removeMarker(marker.markerId) + } + this.markers[file] = this.markers[file].filter(h => h.className != type) + } + + + get_caret_position(file){ + const session = file == null + ? this.ace_editor.getSession() + : this.get_session(file) + + // Session was not created for file + if(session == null) { + return null + } + + return session.doc.positionToIndex(session.selection.getCursor()) + } + + set_caret_position(index){ + if(index == null) { + throw new Error('illegal state') + } + + const pos = this.ace_editor.session.doc.indexToPosition(index) + console.log('set caret position', index, pos) + + this.supress_change_selection(() => { + const pos = this.ace_editor.session.doc.indexToPosition(index) + this.ace_editor.moveCursorToPosition(pos) + // Moving cursor performs selection, clear it + this.ace_editor.clearSelection() + const first = this.ace_editor.renderer.getFirstVisibleRow() + const last = this.ace_editor.renderer.getLastVisibleRow() + if(pos.row < first || pos.row > last) { + this.ace_editor.scrollToLine(pos.row) + } + }) + } + + goto_definition(){ + const index = this.get_caret_position() + exec('goto_definition', index) + } + + for_each_session(cb) { + for(let file in this.sessions) { + cb(file, this.sessions[file]) + } + } +} + diff --git a/src/editor/eval.js b/src/editor/eval.js new file mode 100644 index 0000000..ed99c59 --- /dev/null +++ b/src/editor/eval.js @@ -0,0 +1,67 @@ +import {ValueExplorer} from './value_explorer.js' +import {el} from './domutils.js' + +export class Eval { + + constructor(ui, container) { + this.ui = ui + this.container = container + + this.container.addEventListener('keydown', (e) => { + if(e.key == 'Escape') { + this.escape() + } + }) + + // TODO jump to fn location, view function calls + // container.addEventListener('click', jump_to_fn_location) + + } + + escape() { + if(this.focusedFrom == null) { + this.ui.editor.focus() + } else { + this.focusedFrom.focus() + this.focusedFrom = null + } + } + + show_value(value){ + this.container.innerHTML = '' + const container = el('div', {'class': 'eval_content', tabindex: 0}) + this.container.appendChild(container) + const explorer = new ValueExplorer({ + container, + on_escape: () => this.escape() + }) + explorer.render(value) + } + + show_error(error){ + this.container.innerHTML = '' + this.container.appendChild(el('span', 'eval_error', error.toString())) + } + + show_value_or_error({ok, value, error}){ + if(ok) { + this.show_value(value) + } else { + this.show_error(error) + } + } + + clear_value_or_error() { + this.container.innerHTML = '' + } + + focus_value_or_error(from) { + this.focusedFrom = from + if(this.container.childElementCount != 1) { + throw new Error('illegal state') + } + this.container.children[0].focus() + } + + +} diff --git a/src/editor/files.js b/src/editor/files.js new file mode 100644 index 0000000..f2168c8 --- /dev/null +++ b/src/editor/files.js @@ -0,0 +1,164 @@ +import {el} from './domutils.js' +import {map_find} from '../utils.js' +import {load_dir, create_file} from '../filesystem.js' +import {exec, get_state} from '../index.js' + +export class Files { + constructor(ui) { + this.ui = ui + this.el = el('div', 'files_container') + this.render(get_state()) + } + + open_directory() { + load_dir(true).then(dir => { + exec('load_dir', dir) + }) + } + + render(state) { + if(state.project_dir == null) { + this.el.innerHTML = '' + this.el.appendChild( + el('div', 'allow_file_access', + el('a', { + href: 'javascript:void(0)', + click: this.open_directory.bind(this), + }, + `Allow access to local project folder`, + ), + el('div', 'subtitle', `Your files will never leave your device`) + ) + ) + } else { + this.render_files(state.project_dir, state.current_module) + } + } + + render_files(dir, current_module) { + const files = this.el.querySelector('.files') + + const children = [ + this.render_file({name: '*scratch*', path: ''}, current_module), + this.render_file(dir, current_module), + ] + + if(files == null) { + this.el.innerHTML = '' + this.el.appendChild( + el('div', 'file_actions', + el('a', { + href: 'javascript: void(0)', + click: this.create_file.bind(this, false), + }, + 'Create file' + ), + el('a', { + href: 'javascript: void(0)', + click: this.create_file.bind(this, true), + }, 'Create dir'), + ) + ) + this.el.appendChild( + el('div', 'files', + children + ) + ) + } else { + // Replace to preserve scroll position + files.replaceChildren(...children) + } + } + + render_file(file, current_module) { + const result = el('div', 'file', + el('div', { + 'class': 'file_title' + (file.path == current_module ? ' active' : ''), + click: e => this.on_click(e, file) + }, + el('span', 'icon', + file.kind == 'directory' + ? '\u{1F4C1}' // folder icon + : '\xa0', + ), + file.name, + ), + file.children == null + ? null + : file.children.map(c => this.render_file(c, current_module)) + ) + + if(file.path == current_module) { + this.active_el = result + this.active_file = file + } + + return result + } + + async create_file(is_dir) { + + if(this.active_file == null) { + throw new Error('no active file') + } + + let name = prompt(`Enter ${is_dir ? 'directory' : 'file'} name`) + if(name == null) { + return + } + + let dir + + const root = get_state().project_dir + + if(this.active_file.path == '' /* scratch */) { + // Create in root directory + dir = root + } else { + if(this.active_file.kind == 'directory') { + dir = this.active_file + } else { + + const find_parent = (dir, parent) => { + if(dir.path == this.active_file.path) { + return parent + } + if(dir.children == null) { + return null + } + return map_find(dir.children, c => find_parent(c, dir)) + } + + dir = find_parent(root) + + if(dir == null) { + throw new Error('illegal state') + } + } + } + + const path = dir == root ? name : dir.path + '/' + name + await create_file(path, is_dir) + + // Reload all files for simplicity + load_dir(false).then(dir => { + if(is_dir) { + exec('load_dir', dir) + } else { + exec('create_file', dir, path) + } + }) + } + + + on_click(e, file) { + e.stopPropagation() + this.active_el.querySelector('.file_title').classList.remove('active') + this.active_el = e.currentTarget.parentElement + e.currentTarget.classList.add('active') + this.active_file = file + if(file.kind != 'directory') { + exec('change_current_module', file.path) + } + } +} diff --git a/src/editor/ui.js b/src/editor/ui.js new file mode 100644 index 0000000..aebca1a --- /dev/null +++ b/src/editor/ui.js @@ -0,0 +1,267 @@ +import {exec, get_state} from '../index.js' +import {Editor} from './editor.js' +import {Files} from './files.js' +import {CallTree} from './calltree.js' +import {Eval} from './eval.js' +import {el} from './domutils.js' +import {FLAGS} from '../feature_flags.js' + +export class UI { + constructor(container, state){ + this.change_entrypoint = this.change_entrypoint.bind(this) + + this.files = new Files(this) + + container.appendChild( + (this.root = el('div', + 'root ' + (FLAGS.embed_value_explorer ? 'embed_value_explorer' : ''), + this.editor_container = el('div', 'editor_container'), + FLAGS.embed_value_explorer + ? null + : (this.eval_container = el('div', {class: 'eval'})), + el('div', 'bottom', + this.calltree_container = el('div', {"class": 'calltree', tabindex: 0}), + this.problems_container = el('div', {"class": 'problems', tabindex: 0}), + this.entrypoint_select = el('div', 'entrypoint_select') + ), + + this.files.el, + + this.statusbar = el('div', 'statusbar', + this.status = el('div', 'status'), + this.current_module = el('div', 'current_module'), + /* + // Fullscreen cancelled on escape, TODO + el('a', { + "class" : 'request_fullscreen', + href: 'javascript:void(0)', + click: e => document.body.requestFullscreen(), + }, + 'Fullscreen' + ), + */ + this.options = el('div', 'options', + el('label', {'for': 'standard'}, + el('input', { + id: 'standard', + type: 'radio', + name: 'keyboard', + checked: localStorage.keyboard == 'standard' + || localStorage.keyboard == null, + change: () => { + this.editor.set_keyboard_handler('standard') + } + }), + 'Standard' + ), + el('label', {'for': 'vim'}, + el('input', { + id: 'vim', + type: 'radio', + name: 'keyboard', + checked: localStorage.keyboard == 'vim', + change: () => { + this.editor.set_keyboard_handler('vim') + } + }), + 'VIM' + ) + ), + el('a', { + 'class': 'show_help', + href: 'javascript: void(0)', + click: () => this.help_dialog.showModal(), + }, + 'Help', + ), + el('a', { + 'class': 'github', + href: 'https://github.com/leporello-js/leporello-js', + target: '__blank', + }, 'Github'), + this.help_dialog = this.render_help(), + ) + )) + ) + + this.root.addEventListener('keydown', () => this.clear_status(), true) + this.root.addEventListener('click', () => this.clear_status(), true) + + this.editor_container.addEventListener('keydown', e => { + if( + e.key.toLowerCase() == 'w' && e.ctrlKey == true + || + // We bind F1 later, this one to work from embed_value_explorer + e.key == 'F1' + ){ + this.calltree_container.focus() + } + }) + + this.calltree_container.addEventListener('keydown', e => { + if( + (e.key.toLowerCase() == 'w' && e.ctrlKey == true) + || + e.key == 'Escape' + ){ + this.editor.focus() + } + }) + + + if(!FLAGS.embed_value_explorer) { + this.eval = new Eval(this, this.eval_container) + } else { + // Stub + this.eval = { + show_value_or_error(){}, + clear_value_or_error(){}, + focus_value_or_error(){}, + } + } + + this.editor = new Editor(this, this.editor_container) + + this.calltree = new CallTree(this, this.calltree_container) + + // TODO jump to another module + // TODO use exec + const jump_to_fn_location = (e) => { + let loc + if((loc = e.target.dataset.location) != null){ + loc = JSON.parse(loc) + this.editor.set_caret_position(loc.index) + this.editor.focus() + } + } + + // TODO when click in calltree, do not jump to location, navigateCallTree + // instead + this.calltree_container.addEventListener('click', jump_to_fn_location) + + this.render_entrypoint_select(state) + this.render_current_module(state.current_module) + } + + render_entrypoint_select(state) { + this.entrypoint_select.replaceChildren( + el('span', 'entrypoint_title', 'entrypoint'), + el('select', { + click: e => e.stopPropagation(), + change: this.change_entrypoint, + }, + Object.keys(state.files).sort().map(f => + el('option', + state.entrypoint == f + ? { value: f, selected: true } + : { value: f}, + f == '' ? "*scratch*" : f + ) + ) + ) + ) + } + + change_entrypoint(e) { + const file = e.target.value + const index = this.editor.get_caret_position(file) + // if index is null, session was not created, and index after session + // creation will be 0 + ?? 0 + exec('change_entrypoint', file, index) + this.editor.focus() + } + + render_calltree(state) { + this.calltree_container.style = '' + this.problems_container.style = 'display: none' + this.calltree.render_calltree(state) + } + + render_problems(problems) { + this.calltree_container.style = 'display: none' + this.problems_container.style = '' + this.problems_container.innerHTML = '' + problems.forEach(p => { + const s = this.editor.get_session(p.module) + const pos = s.doc.indexToPosition(p.index) + const module = p.module == '' ? "*scratch*" : p.module + this.problems_container.appendChild( + el('div', 'problem', + el('a', { + href: 'javascript:void(0)', + click: () => exec('goto_problem', p) + }, + `${module}:${pos.row + 1}:${pos.column} - ${p.message}` + ) + ) + ) + }) + } + + set_status(text){ + this.current_module.style = 'display: none' + this.status.style = '' + this.status.innerText = text + } + + clear_status(){ + this.render_current_module(get_state().current_module) + } + + render_current_module(current_module) { + this.status.style = 'display: none' + this.current_module.innerText = + current_module == '' + ? '*scratch*' + : current_module + this.current_module.style = '' + } + + render_help() { + const options = [ + ['Switch between editor and call tree', 'F1 or Ctrl-w'], + ['Go from call tree to editor', 'F1 or Esc'], + ['Focus value explorer', 'F2'], + ['Navigate value explorer', '← → ↑ ↓ or hjkl'], + ['Leave value explorer', 'Esc'], + ['Jump to definition', 'F3', 'gd'], + ['Expand selection to eval expression', 'Ctrl-↓ or Ctrl-j'], + ['Collapse selection', 'Ctrl-↑ or Ctrl-k'], + ['Navigate call tree view', '← → ↑ ↓ or hjkl'], + ['Step into call', 'Ctrl-i', '\\i'], + ['Step out of call', 'Ctrl-o', '\\o'], + ['When in call tree view, jump to return statement', 'Enter'], + ['When in call tree view, jump to function arguments', 'a'], + ] + return el('dialog', 'help_dialog', + el('table', 'help', + el('thead', '', + el('th', '', 'Action'), + el('th', 'key', 'Standard'), + el('th', 'key', 'VIM'), + ), + el('tbody', '', + options.map(([text, standard, vim]) => + el('tr', '', + el('td', '', text), + el('td', + vim == null + ? {'class': 'key spanned', colspan: 2} + : {'class': 'key'}, + standard + ), + vim == null + ? null + : el('td', 'key', vim), + ) + ) + ) + ), + el('form', {method: 'dialog'}, + el('button', null, 'Close'), + ), + ) + } + +} diff --git a/src/editor/value_explorer.js b/src/editor/value_explorer.js new file mode 100644 index 0000000..47aaf1a --- /dev/null +++ b/src/editor/value_explorer.js @@ -0,0 +1,356 @@ +// TODO large arrays/objects +// TODO maps, sets +// TODO show Errors in red + +import {el, stringify, scrollIntoViewIfNeeded} from './domutils.js' + +const displayed_entries = object => { + if(Array.isArray(object)) { + return object.map((v, i) => [i, v]) + } else { + const result = Object.entries(object) + return (object instanceof Error) + ? [['message', object.message], ...result] + : result + } +} + +const is_expandable = v => typeof(v) == 'object' + && v != null + && displayed_entries(v).length != 0 + + +export const stringify_for_header = v => { + const type = typeof(v) + + if(v === null) { + return 'null' + } else if(v === undefined) { + return 'undefined' + } else if(type == 'function') { + // TODO clickable link, 'fn', cursive + return 'fn ' + v.name + } else if(v instanceof Error) { + return v.toString() + } else if(type == 'object') { + if(Array.isArray(v)) { + if(v.length == 0) { + return '[]' + } else { + return '[…]' + } + } else { + if(displayed_entries(v).length == 0) { + return '{}' + } else { + return '{…}' + } + } + } else if(type == 'string') { + return JSON.stringify(v) + } else { + return v.toString() + } +} + +const header = object => { + if(typeof(object) == 'undefined') { + return 'undefined' + } else if(object == null) { + return 'null' + } else if(typeof(object) == 'object') { + if(object instanceof Error) { + return object.toString() + } else if(Array.isArray(object)) { + return '[' + + object + .map(stringify_for_header) + .join(', ') + + ']' + } else { + const inner = displayed_entries(object) + .map(([k,v]) => { + const value = stringify_for_header(v) + return `${k}: ${value}` + }) + .join(', ') + return `{${inner}}` + } + } else if(typeof(object) == 'function') { + // TODO clickable link, 'fn', cursive + return 'fn ' + object.name + } else if(typeof(object) == 'string') { + return JSON.stringify(object) + } else { + return object.toString() + } + return header +} + +const get_path = (o, path) => { + if(path.length == 0) { + return o + } else { + const [start, ...rest] = path + return get_path(o[start], rest) + } +} + +export class ValueExplorer { + + constructor({ + container, + event_target = container, + scroll_to_element, + on_escape = () => {}, + } = {} + ) { + this.container = container + this.scroll_to_element = scroll_to_element + this.on_escape = on_escape + + event_target.addEventListener('keydown', (e) => { + + /* + Right - + - does not has children - nothing + - has children - first click expands, second jumps to first element + + Left - + - root - nothing + - not root collapse node, goes to parent if already collapsed + + Up - goes to prev visible element + Down - goes to next visible element + + Click - select and toggles expand + */ + + const current_object = get_path(this.value, this.current_path) + + if(e.key == 'ArrowDown' || e.key == 'j'){ + // Do not scroll + e.preventDefault() + + if(is_expandable(current_object) && this.is_expanded(this.current_path)) { + this.select_path(this.current_path.concat( + displayed_entries(current_object)[0][0] + )) + } else { + const next = p => { + if(p.length == 0) { + return null + } + const parent = p.slice(0, p.length - 1) + const children = displayed_entries(get_path(this.value, parent)) + const child_index = children.findIndex(([k,v]) => + k == p[p.length - 1] + ) + const next_child = children[child_index + 1] + if(next_child == null) { + return next(parent) + } else { + return [...parent, next_child[0]] + } + } + + const next_path = next(this.current_path) + if(next_path != null) { + this.select_path(next_path) + } + } + } + + if(e.key == 'ArrowUp' || e.key == 'k'){ + // Do not scroll + e.preventDefault() + + if(this.current_path.length == 0) { + this.on_escape() + return + } + const parent = this.current_path.slice(0, this.current_path.length - 1) + const children = displayed_entries(get_path(this.value, parent)) + const child_index = children.findIndex(([k,v]) => + k == this.current_path[this.current_path.length - 1] + ) + const next_child = children[child_index - 1] + if(next_child == null) { + this.select_path(parent) + } else { + const last = p => { + if(!is_expandable(get_path(this.value, p)) || !this.is_expanded(p)) { + return p + } else { + const children = displayed_entries(get_path(this.value, p)) + .map(([k,v]) => k) + return last([...p, children[children.length - 1]]) + + } + } + this.select_path(last([...parent, next_child[0]])) + } + } + + if(e.key == 'ArrowLeft' || e.key == 'h'){ + // Do not scroll + e.preventDefault() + + const is_expanded = this.is_expanded(this.current_path) + if(!is_expandable(current_object) || !is_expanded) { + if(this.current_path.length != 0) { + const parent = this.current_path.slice(0, this.current_path.length - 1) + this.select_path(parent) + } else { + this.on_escape() + } + } else { + this.toggle_expanded() + } + } + + if(e.key == 'ArrowRight' || e.key == 'l'){ + // Do not scroll + e.preventDefault() + + if(is_expandable(current_object)) { + const is_expanded = this.is_expanded(this.current_path) + if(!is_expanded) { + this.toggle_expanded() + } else { + const children = displayed_entries(get_path(this.value, this.current_path)) + this.select_path( + [ + ...this.current_path, + children[0][0], + ] + ) + } + } + } + }) + } + + get_node_data(path, node_data = this.node_data) { + if(path.length == 0) { + return node_data + } else { + const [start, ...rest] = path + return this.get_node_data(rest, node_data.children[start]) + } + } + + is_expanded(path) { + return this.get_node_data(path).is_expanded + } + + on_click(path) { + this.select_path(path) + this.toggle_expanded() + } + + clear() { + this.container.innerHTML = '' + this.node_data = {is_expanded: true} + } + + render(value) { + this.clear() + this.value = value + const path = [] + this.container.appendChild(this.render_value_explorer_node(null, value, path, this.node_data)) + this.select_path(path) + } + + select_path(current_path) { + if(this.current_path != null) { + this.set_active(this.current_path, false) + } + this.current_path = current_path + this.set_active(this.current_path, true) + // Check that was already added to document + if(document.contains(this.container)) { + const target = this.get_node_data(current_path).el.getElementsByClassName('value_explorer_header')[0] + if(this.scroll_to_element == null) { + scrollIntoViewIfNeeded(this.container.parentNode, target) + } else { + this.scroll_to_element(target) + } + } + } + + set_active(path, is_active) { + const el = this.get_node_data(path).el.getElementsByClassName('value_explorer_header')[0] + if(is_active) { + el.classList.add('active') + } else { + el.classList.remove('active') + } + } + + set_expanded(fn) { + if(typeof(fn) == 'boolean') { + return this.set_expanded(() => fn) + } + const val = this.is_expanded(this.current_path) + const data = this.get_node_data(this.current_path) + data.is_expanded = fn(data.is_expanded) + const prev_dom_node = data.el + const key = this.current_path.length == 0 + ? null + : this.current_path[this.current_path.length - 1] + const value = get_path(this.value, this.current_path) + const next = this.render_value_explorer_node(key, value, this.current_path, data) + prev_dom_node.parentNode.replaceChild(next, prev_dom_node) + } + + toggle_expanded() { + this.set_expanded(e => !e) + this.set_active(this.current_path, true) + } + + render_value_explorer_node(key, value, path, node_data) { + + const is_exp = is_expandable(value) + const is_expanded = is_exp && node_data.is_expanded + + node_data.children = {} + + const result = el('div', 'value_explorer_node', + + el('span', { + class: 'value_explorer_header', + click: this.on_click.bind(this, path), + }, + is_exp + ? (is_expanded ? '▼' : '▶') + : '\xa0', + + key == null + ? null + : el('span', 'value_explorer_key', key.toString(), ': '), + + key == null || !is_exp || !is_expanded + // Full header + ? header(value) + // Short header + : Array.isArray(value) + ? 'Array(' + value.length + ')' + : '' + ), + + (is_exp && is_expanded) + ? displayed_entries(value).map(([k,v]) => { + node_data.children[k] = {} + return this.render_value_explorer_node(k, v, [...path, k], node_data.children[k]) + }) + : [] + ) + + node_data.el = result + + return result + } + + +} diff --git a/src/effects.js b/src/effects.js new file mode 100644 index 0000000..d38486f --- /dev/null +++ b/src/effects.js @@ -0,0 +1,232 @@ +import {write_file} from './filesystem.js' +import {color_file} from './color.js' +import {root_calltree_node, calltree_node_loc} from './calltree.js' +import {FLAGS} from './feature_flags.js' + +const ensure_session = (ui, state, file = state.current_module) => { + ui.editor.ensure_session(file, state.files[file]) +} + +const clear_coloring = (ui, file) => { + ui.editor.remove_markers_of_type(file, 'evaluated_ok') + ui.editor.remove_markers_of_type(file, 'evaluated_error') +} + +const render_coloring = (ui, state) => { + const file = state.current_module + + clear_coloring(ui, file) + + color_file(state, file).forEach(c => { + ui.editor.add_marker( + file, + c.result.ok + ? 'evaluated_ok' + : 'evaluated_error', + c.index, + c.index + c.length + ) + }) +} + +const render_parse_result = (ui, state) => { + ui.editor.for_each_session((file, session) => { + ui.editor.remove_markers_of_type(file, 'error-code') + session.clearAnnotations() + }) + + if(!state.parse_result.ok){ + + ui.editor.for_each_session((file, session) => { + session.setAnnotations( + state.parse_result.problems + .filter(p => p.module == file) + .map(p => { + const pos = session.doc.indexToPosition(p.index) + return { + row: pos.row, + column: pos.column, + text: p.message, + type: "error", + } + }) + ) + }) + + state.parse_result.problems.forEach(problem => { + ensure_session(ui, state, problem.module) + // TODO unexpected end of input + ui.editor.add_marker( + problem.module, + 'error-code', + problem.index, + // TODO check if we can show token + problem.token == null + ? problem.index + 1 + : problem.index + problem.token.length + ) + }) + + ui.render_problems(state.parse_result.problems) + } else { + // Ensure session for each loaded module + Object.keys(state.parse_result.modules).forEach(file => { + ensure_session(ui, state, file) + }) + } +} + +export const render_initial_state = (ui, state) => { + ensure_session(ui, state) + ui.editor.switch_session(state.current_module) + render_parse_result(ui, state) + if(state.current_calltree_node != null) { + ui.render_calltree(state) + render_coloring(ui, state) + } +} + +export const render_common_side_effects = (prev, next, command, ui) => { + if( + prev.project_dir != next.project_dir + || + prev.current_module != next.current_module + ) { + ui.render_entrypoint_select(next) + ui.files.render(next) + } + + if(prev.current_module != next.current_module) { + localStorage.current_module = next.current_module + ui.render_current_module(next.current_module) + } + + if(prev.entrypoint != next.entrypoint) { + localStorage.entrypoint = next.entrypoint + } + + if(prev.current_module != next.current_module) { + ensure_session(ui, next) + ui.editor.unembed_value_explorer() + ui.editor.switch_session(next.current_module) + } + + if(prev.parse_result != next.parse_result) { + render_parse_result(ui, next) + } + + if(next.current_calltree_node == null) { + + ui.calltree.clear_calltree() + ui.editor.for_each_session((file, session) => clear_coloring(ui, file)) + ui.editor.unembed_value_explorer() + + } else { + + if( + prev.current_calltree_node == null + || + prev.calltree_changed_token != next.calltree_changed_token + ) { + // Rerender entire calltree + ui.render_calltree(next) + ui.eval.clear_value_or_error() + ui.editor.for_each_session(f => clear_coloring(ui, f)) + render_coloring(ui, next) + ui.editor.unembed_value_explorer() + } else { + const node_changed = next.current_calltree_node != prev.current_calltree_node + const id = next.current_calltree_node.id + const exp_changed = !!prev.calltree_node_is_expanded[id] + != + !!next.calltree_node_is_expanded[id] + + if(node_changed) { + ui.calltree.render_select_node(next) + } + + if(exp_changed) { + ui.calltree.render_expand_node(next) + } + + if(node_changed) { + if(!next.current_calltree_node.toplevel) { + ui.eval.show_value_or_error(next.current_calltree_node) + } else { + ui.eval.clear_value_or_error() + } + } + + if(prev.calltree_node_by_loc != next.calltree_node_by_loc) { + render_coloring(ui, next) + } + } + } + + // Render + + /* Eval selection */ + + const selnode = next.selection_state?.node + if(prev.selection_state?.node != selnode) { + ui.editor.remove_markers_of_type(next.current_module, 'selection') + if(selnode != null) { + ui.editor.add_marker( + next.current_module, + 'selection', + selnode.index, + selnode.index + selnode.length + ) + } + } + + const selresult = next.selection_state?.result + if(selresult != null && prev.selection_state?.result != selresult) { + if(FLAGS.embed_value_explorer) { + const node = next.selection_state.node + ui.editor.embed_value_explorer({ + index: node.index + node.length, + result: next.selection_state.result, + }) + } else { + ui.eval.show_value_or_error(next.selection_state.result) + } + } +} + + +export const EFFECTS = { + set_caret_position: (state, [index, with_focus], ui) => { + ui.editor.set_caret_position(index) + if(with_focus) { + ui.editor.focus() + } + }, + + set_status: (state, [msg], ui) => { + ui.set_status(msg) + }, + + save_to_localstorage(state, [key, value]){ + localStorage[key] = value + }, + + write: (state, [name, contents], ui) => write_file(name, contents), + + embed_value_explorer(state, [{index, result}], ui){ + if(FLAGS.embed_value_explorer) { + ui.editor.embed_value_explorer({index, result}) + } else { + ui.eval.show_value_or_error(result) + } + }, + + unembed_value_explorer(state, _, ui){ + if(FLAGS.embed_value_explorer) { + ui.editor.unembed_value_explorer() + } else { + ui.eval.clear_value_or_error() + } + }, +} + diff --git a/src/eval.js b/src/eval.js new file mode 100644 index 0000000..af1c9e4 --- /dev/null +++ b/src/eval.js @@ -0,0 +1,1224 @@ +import {zip, stringify, map_object, filter_object} from './utils.js' + +import { + find_fn_by_location, + collect_destructuring_identifiers, + map_destructuring_identifiers, + map_tree, +} from './ast_utils.js' + +// TODO: fix error messages. For example, "__fn is not a function" + +/* +Generate code that records all function invocations. + +for each invokation, record + - function that was called with its closed variables + - args + - return value (or exception) + - child invocations (deeper in the stack) + +When calling function, we check if it is native or not (call it hosted). If +it is native, we record invocation at call site. If it is hosted, we dont +record invocation at call site, but function expression was wrapped in code +that records invocation. So its call will be recorded. + +Note that it is not enough to record all invocation at call site, because +hosted function can be called by native functions (for example Array::map). + +For each invocation, we can replay function body with metacirculat interpreter, +collecting information for editor +*/ + +/* +type ToplevelCall = { + toplevel: true, + code, + ok, + value, + error, + children +} +type Call = { + args, + code, + fn, + ok, + value, + error, + children, +} +type Node = ToplevelCall | Call +*/ + +const codegen_function_expr = (node, cxt, name) => { + const do_codegen = n => codegen(n, cxt) + + const args = node.function_args.children.map(do_codegen).join(',') + + const call = `(${args}) => ` + ( + (node.body.type == 'do') + ? '{' + do_codegen(node.body) + '}' + : '(' + do_codegen(node.body) + ')' + ) + + const argscount = node.function_args.children.find(a => a.type == 'rest') != null + ? node.function_args.children.length + : null + + const location = `{index: ${node.index}, length: ${node.length}, module: '${cxt.module}'}` + + // TODO first create all functions, then assign __closure, after everything + // is declared. See 'out of order decl' test. Currently we assign __closure + // on first call (see `trace`) + const get_closure = `() => ({${[...node.closed].join(',')}})` + + return `trace(${call}, "${name}", ${argscount}, ${location}, ${get_closure})` +} + +// TODO if statically can prove that function is hosted, then do not codegen +// trace +const codegen_function_call = (node, cxt) => { + + const do_codegen = n => codegen(n, cxt) + + const args = `[${node.args.children.map(do_codegen).join(',')}]` + + let call + if(node.fn.type == 'member_access') { + // Wrap to IIFE to create scope to calculate obj. + // We cant do `codegen(obj)[prop].bind(codegen(obj))` because codegen(obj) + // can be expr we dont want to eval twice + + const op = node.fn.is_optional_chaining ? '?.' : '' + + // TODO gensym __obj, __fn + return `((() => { + const __obj = ${do_codegen(node.fn.object)}; + const __fn = __obj${op}[${do_codegen(node.fn.property)}] + return trace_call(__fn, __obj, ${args}) + })())` + } else { + return `trace_call(${do_codegen(node.fn)}, null, ${args})` + } + +} + +const codegen = (node, cxt, parent) => { + + const do_codegen = (n, parent) => codegen(n, cxt, parent) + + if([ + 'identifier', + 'number', + 'string_literal', + 'builtin_identifier', + 'backtick_string', + ].includes(node.type)){ + return node.value + } else if(node.type == 'do'){ + return node.stmts.reduce( + (result, stmt) => result + (do_codegen(stmt)) + ';\n', + '' + ) + } else if(node.type == 'return') { + return 'return ' + do_codegen(node.expr) + ';' + } else if(node.type == 'throw') { + return 'throw ' + do_codegen(node.expr) + ';' + } else if(node.type == 'if') { + const left = 'if(' + do_codegen(node.cond) + '){' + + do_codegen(node.branches[0]) + ' } ' + return node.branches[1] == null + ? left + : left + ' else { ' + do_codegen(node.branches[1]) + ' }' + } else if(node.type == 'array_literal'){ + return '[' + node.elements.map(c => do_codegen(c)).join(', ') + ']' + } else if(node.type == 'object_literal'){ + const elements = + node.elements.map(el => { + if(el.type == 'spread'){ + return do_codegen(el) + } else if(el.type == 'identifier') { + return el.value + } else if(el.type == 'key_value_pair') { + return '[' + do_codegen(el.key.type == 'computed_property' ? el.key.expr : el.key) + ']' + + ': (' + do_codegen(el.value) + ')' + } else { + throw new Error('unknown node type ' + el.type) + } + }) + .join(',') + return '({' + elements + '})' + } else if(node.type == 'function_call'){ + return codegen_function_call(node, cxt) + } else if(node.type == 'function_expr'){ + const name = parent != null && parent.type == 'const' + // TODO here we deduce fn name from left-side of assignment + // TODO name inference is much more sophisticated, for example + // `{foo: () => {...}}` infers name `foo` + ? parent.name + : 'anonymous' + return codegen_function_expr(node, cxt, name) + } else if(node.type == 'ternary'){ + return '' + + '(' + + do_codegen(node.cond) + + ')\n? ' + + do_codegen(node.branches[0]) + +'\n: ' + + do_codegen(node.branches[1]) + } else if(node.type == 'const'){ + const res = 'const ' + do_codegen(node.name_node) + ' = ' + do_codegen(node.expr, node) + ';' + if(node.name_node.type == 'identifier' && node.expr.type == 'function_call') { + // generate function name + // TODO test it + return res + ` + if(typeof(${node.name_node.value}) == 'function') { + Object.defineProperty(${node.name_node.value}, "name", {value: "${node.name_node.value}"}); + } + ` + } else { + return res + } + } else if(node.type == 'let') { + return 'let ' + node.names.join(',') + ';'; + } else if(node.type == 'assignment') { + return node.name + ' = ' + do_codegen(node.expr, node) + ';'; + } else if(node.type == 'member_access'){ + return '(' + + do_codegen(node.object) + + (node.is_optional_chaining ? ')?.[' : ')[') + + do_codegen(node.property) + + ']' + } else if(node.type == 'unary') { + return '(' + node.operator + ' ' + do_codegen(node.expr) + ')' + } else if(node.type == 'binary'){ + return '' + + do_codegen(node.args[0]) + + ' ' + + node.operator + + ' ' + + do_codegen(node.args[1]) + } else if(node.type == 'spread'){ + return '...(' + do_codegen(node.expr) + ')' + } else if(node.type == 'new') { + return '(new (' + codegen(node.constructor) + ')(' + node.args.map(do_codegen).join(',') + '))' + } else if(node.type == 'grouping'){ + return '(' + do_codegen(node.expr) + ')' + } else if(node.type == 'array_destructuring') { + return '[' + node.elements.map(n => do_codegen(n)).join(', ') + ']' + } else if(node.type == 'object_destructuring') { + return '{' + node.elements.map(n => do_codegen(n)).join(', ') + '}' + } else if(node.type == 'destructuring_rest') { + return '...' + do_codegen(node.name_node) + } else if(node.type == 'destructuring_default') { + return do_codegen(node.name_node) + ' = ' + do_codegen(node.expr); + } else if(node.type == 'destructuring_pair') { + return do_codegen(node.key) + ' : ' + do_codegen(node.value); + } else if(node.type == 'import') { + const names = node.imports.map(n => n.value) + return `const {${names.join(',')}} = __modules['${node.full_import_path}'].exports;`; + } else if(node.type == 'export') { + const identifiers = collect_destructuring_identifiers(node.binding.name_node) + .map(i => i.value) + return do_codegen(node.binding) + + + `Object.assign(__exports, {${identifiers.join(',')}});` + } else { + console.error(node) + throw new Error('unknown node type: ' + node.type) + } +} + +export const eval_modules = (modules, sorted, location) => { + // TODO gensym __modules, __exports + + const codestring = + ` + const MAX_DEPTH = 1 + let depth + let current_call + let call_counter = 0 + + let enable_find_call + let searched_location + let found_call + + function add_call(call) { + depth++ + call.id = call_counter++ + if(current_call.children == null) { + current_call.children = [] + } + current_call.children.push(call) + current_call = call + } + + const expand_calltree_node = (node) => { + depth = 0 + current_call = {} + try { + node.fn.apply(node.context, node.args) + } catch(e) { + // do nothing. Exception was caught and recorded inside 'trace' + } + if(node.fn.__location != null) { + // fn is hosted, it created call, this time with children + const result = current_call.children[0] + result.id = node.id + return result + } else { + // fn is native, it did not created call, only its child did + return {...node, + children: current_call.children, + has_more_children: null, + } + } + } + + const find_call = (entrypoint, location) => { + searched_location = location + const calltree = run(entrypoint) + searched_location = null + const call = found_call + found_call = null + return {calltree, call} + } + + const trace = (fn, name, argscount, __location, get_closure) => { + const result = (...args) => { + if(result.__closure == null) { + result.__closure = get_closure() + } + + const prev = current_call + add_call({ + fn: result, + args: argscount == null + ? args + // Do not capture unused args + : args.slice(0, argscount) + }) + + if( + enable_find_call + && + (searched_location != null && found_call == null) + && + ( + __location.index == searched_location.index + && + __location.module == searched_location.module + ) + ) { + found_call = current_call + + // Set depth to record children of found call + depth = 1 + } + + try { + const value = fn(...args) + current_call.ok = true + current_call.value = value + if(depth > MAX_DEPTH) { + if(current_call.children != null && current_call.children.length > 0) { + current_call.has_more_children = true + current_call.children = null + } + } + return value + } catch(error) { + current_call.ok = false + current_call.error = error + throw error + } finally { + depth-- + if(found_call != null && depth < 1) { + // Set depth to 1 to record sibling calls for calls that precede + // found call + depth = 1 + } + current_call = prev + } + } + + Object.defineProperty(result, 'name', {value: name}) + result.__location = __location + return result + } + + const trace_call = (fn, context, args) => { + if(fn != null && fn.__location != null) { + return fn(...args) + } + if(typeof(fn) != 'function') { + return fn.apply(context, args) + } + const prev = current_call + add_call({fn, args, context}) + try { + const value = fn.apply(context, args) + current_call.ok = true + current_call.value = value + if(depth > MAX_DEPTH) { + if(current_call.children != null && current_call.children.length > 0) { + current_call.has_more_children = true + current_call.children = null + } + } + return value + } catch(error) { + current_call.ok = false + current_call.error = error + throw error + } finally { + depth-- + if(found_call != null && depth < 1) { + // Set depth to 1 to record sibling calls for calls that precede + // found call + depth = 1 + } + current_call = prev + } + } + + const run = find_call_entrypoint => { + depth = 1 + const __modules = {} + ` + + + sorted + .map((m, i) => + ` + enable_find_call = find_call_entrypoint == '${m}' + __modules['${m}'] = {} + current_call = { + toplevel: true, + module: '${m}', + id: call_counter++ + } + __modules['${m}'].calls = current_call + __modules['${m}'].exports = + (() => { + try { + const __exports = {}; + ${codegen(modules[m], {module: m})}; + current_call.ok = true + return __exports + } catch(error) { + current_call.ok = false + current_call.error = error + } + })() + if(!__modules['${m}'].calls.ok) { + return __modules + } + ` + ) + .join('') + + + ` + return __modules + } + + return { + run, + expand_calltree_node, + find_call, + } + ` + + const actions = (new Function(codestring))() + + const calltree_actions = { + expand_calltree_node: (node) => { + const expanded = actions.expand_calltree_node(node) + return assign_code(modules, expanded) + }, + find_call: (entrypoint, loc) => { + const {calltree, call} = actions.find_call(entrypoint, loc) + return { + calltree: assign_code_calltree(modules, calltree), + // TODO: `call` does not have `code` property here. Currently it is + // worked around by callers. Refactor + call, + } + } + } + + let calltree, call + + if(location == null) { + // Intentionally do not pass arg to run() + calltree = actions.run() + } else { + const result = calltree_actions.find_call( + sorted[sorted.length - 1], + location + ) + calltree = result.calltree + call = result.call + } + + return { + calltree: assign_code_calltree(modules, calltree), + call, + calltree_actions, + } +} + +const assign_code_calltree = (modules, calltree) => + map_object( + calltree, + (module, {calls, exports}) => { + return {exports, calls: assign_code(modules, calls, modules[module])} + } + ) + +const assign_code = (modules, call, module) => { + if(call.toplevel) { + return {...call, + code: module, + children: call.children && call.children.map(call => assign_code(modules, call)), + } + } else { + return {...call, + code: call.fn == null || call.fn.__location == null + ? null + : find_fn_by_location(modules[call.fn.__location.module], call.fn.__location), + children: call.children && call.children.map(call => assign_code(modules, call)), + } + } +} + +export const eval_tree = node => { + return eval_modules({'': node}, ['']).calltree[''].calls +} + + +/* ------------- Metacircular interpreter ---------------------------- */ + +/* +Evaluate single function call + +For each statement or expression, calculate if it was executed or not. + +Add evaluation result to each statement or expression and put it to `result` +prop. Evaluate expressions from leaves to root, substituting function calls for +already recorded results. + +Add `result` prop to each local variable. + +Eval statements from top to bottom, selecting effective if branch and stopping +on `return` and `throw`. When descending to nested blocks, take scope into +account +*/ + +// Workaround with statement forbidden in strict mode (imposed by ES6 modules) +// Also currently try/catch is not implemented TODO +const eval_codestring = new Function('codestring', 'scope', + // Make a copy of `scope` to not mutate it with assignments + ` + try { + return {ok: true, value: eval('with({...scope}){' + codestring + '}')} + } catch(error) { + return {ok: false, error} + } + ` +) + +const get_args_scope = (fn_node, args) => { + const arg_names = + collect_destructuring_identifiers(fn_node.function_args) + .map(i => i.value) + + const destructuring = fn_node.function_args.children.map(n => codegen(n)).join(',') + + /* + // TODO gensym __args. Or + new Function(` + return ({foo, bar}) => ({foo, bar}) + `)(args) + + to avoid gensym + */ + const codestring = `(([${destructuring}]) => [${arg_names.join(',')}])(__args)` + + const {ok, value, error} = eval_codestring(codestring, {__args: args}) + + if(!ok) { + // TODO show exact destructuring error + return {ok, error} + } else { + return { + ok, + value: Object.fromEntries( + zip( + arg_names, + value, + ) + ), + } + } +} + +const eval_binary_expr = (node, scope, callsleft) => { + const {ok, children, calls} = eval_children(node, scope, callsleft) + if(!ok) { + return {ok, children, calls} + } + + const op = node.operator + const a = children[0].result.value + const b = children[1].result.value + const value = (new Function('a', 'b', ' return a ' + op + ' b'))(a, b) + return {ok, children, calls, value} +} + + +const do_eval_frame_expr = (node, scope, callsleft) => { + if([ + 'identifier', + 'builtin_identifier', + 'number', + 'string_literal', + 'backtick_string', + ].includes(node.type)){ + // TODO exprs inside backtick string + // Pass scope for backtick string + return {...eval_codestring(node.value, scope), calls: callsleft} + } else if([ + 'spread', + 'key_value_pair', + 'computed_property' + ].includes(node.type)) { + return eval_children(node, scope, callsleft) + } else if(node.type == 'array_literal' || node.type == 'call_args'){ + const {ok, children, calls} = eval_children(node, scope, callsleft) + if(!ok) { + return {ok, children, calls} + } + const value = children.reduce( + (arr, el) => { + if(el.type == 'spread') { + return [...arr, ...el.children[0].result.value] + } else { + return [...arr, el.result.value] + } + }, + [], + ) + return {ok, children, calls, value} + } else if(node.type == 'object_literal'){ + const {ok, children, calls} = eval_children(node, scope, callsleft) + if(!ok) { + return {ok, children, calls} + } + const value = children.reduce( + (value, el) => { + if(el.type == 'spread'){ + return {...value, ...el.children[0].result.value} + } else if(el.type == 'identifier') { + // TODO check that it works + return {...value, ...{[el.value]: el.result.value}} + } else if(el.type == 'key_value_pair') { + const [key, val] = el.children + let k + if(key.type == 'computed_property') { + k = key.children[0].result.value + } else { + k = key.result.value + } + return { + ...value, + ...{[k]: val.result.value}, + } + } else { + throw new Error('unknown node type ' + el.type) + } + }, + {} + ) + return {ok, children, value, calls} + } else if(node.type == 'function_call'){ + const {ok, children, calls} = eval_children(node, scope, callsleft) + if(!ok) { + return {ok: false, children, calls} + } else { + if(typeof(children[0].result.value) != 'function') { + return { + ok: false, + // TODO pass calltree_node here and extract error + // TODO fix error messages + error: new Error('is not a function'), + children, + } + } + const c = calls[0] + if(c == null) { + throw new Error('illegal state') + } + return { + ok: c.ok, + call: c, + value: c.value, + error: c.error, + children, + calls: calls.slice(1) + } + } + } else if(node.type == 'function_expr'){ + // It will never be called, create empty function + // TODO use new Function constructor with code? + // TODO generate function name + const fn_placeholder = Object.defineProperty( + () => {}, + 'name', + {value: 'anonymous'} + ) + return { + ok: true, + value: fn_placeholder, + calls: callsleft, + children: node.children, + } + } else if(node.type == 'ternary'){ + const {node: cond_evaled, calls: calls_after_cond} = eval_frame_expr( + node.cond, + scope, + callsleft + ) + const {ok, value} = cond_evaled.result + const branches = node.branches + if(!ok) { + return { + ok: false, + children: [cond_evaled, branches[0], branches[1]], + calls: calls_after_cond, + } + } else { + const {node: branch_evaled, calls: calls_after_branch} = eval_frame_expr( + branches[value ? 0 : 1], + scope, + calls_after_cond + ) + const children = value + ? [cond_evaled, branch_evaled, branches[1]] + : [cond_evaled, branches[0], branch_evaled] + const ok = branch_evaled.result.ok + if(ok) { + return {ok, children, calls: calls_after_branch, value: branch_evaled.result.value} + } else { + return {ok, children, calls: calls_after_branch} + } + } + } else if(node.type == 'member_access'){ + const {ok, children, calls} = eval_children(node, scope, callsleft) + if(!ok) { + return {ok: false, children, calls} + } + + const [obj, prop] = children + + const codestring = node.is_optional_chaining ? 'obj?.[prop]' : 'obj[prop]' + + // TODO do not use eval here + return { + ...eval_codestring(codestring, { + obj: obj.result.value, + prop: prop.result.value, + }), + children, + calls, + } + + } else if(node.type == 'unary') { + const {ok, children, calls} = eval_children(node, scope, callsleft) + if(!ok) { + return {ok: false, children, calls} + } else { + const expr = children[0] + let value + if(node.operator == '!') { + value = !expr.result.value + } else if(node.operator == 'typeof') { + value = typeof(expr.result.value) + } else { + throw new Error('unknown op') + } + return {ok: true, children, calls, value} + } + } else if(node.type == 'binary' && !['&&', '||', '??'].includes(node.operator)){ + + return eval_binary_expr(node, scope, callsleft) + + } else if(node.type == 'binary' && ['&&', '||', '??'].includes(node.operator)){ + const {node: left_evaled, calls} = eval_frame_expr( + node.children[0], + scope, + callsleft + ) + + const {ok, value} = left_evaled.result + if( + !ok + || + (node.operator == '&&' && !value) + || + (node.operator == '||' && value) + || + (node.operator == '??' && value != null) + ) { + return { + ok, + value, + children: [left_evaled, node.children[1]], + calls, + } + } else { + return eval_binary_expr(node, scope, callsleft) + } + + } else if(node.type == 'new') { + const {ok, children, calls} = eval_children(node, scope, callsleft) + if(!ok) { + return {ok, children, calls} + } else { + const [constructor, ...args] = children + const value = new (constructor.result.value)(...args.map(a => a.result.value)) + return {ok, children, value, calls} + } + } else if(node.type == 'grouping'){ + const {ok, children, calls} = eval_children(node, scope, callsleft) + if(!ok) { + return {ok, children, calls} + } else { + return {ok: true, children, calls, value: children[0].result.value} + } + } else { + console.error(node) + throw new Error('unknown node type: ' + node.type) + } +} + +const eval_children = (node, scope, calls) => { + return node.children.reduce( + ({ok, children, calls}, child) => { + let next_child, next_ok, next_calls + if(!ok) { + next_child = child; + next_ok = false; + next_calls = calls; + } else { + const result = eval_frame_expr(child, scope, calls); + next_child = result.node; + next_calls = result.calls; + next_ok = next_child.result.ok; + } + return {ok: next_ok, children: [...children, next_child], calls: next_calls} + }, + {ok: true, children: [], calls} + ) +} + +const eval_frame_expr = (node, scope, callsleft) => { + const {ok, error, value, call, children, calls} = do_eval_frame_expr(node, scope, callsleft) + if(callsleft != null && calls == null) { + // TODO remove it, just for debug + console.error('node', node) + throw new Error('illegal state') + } + return { + node: { + ...node, + children, + // Add `call` for step_into + result: {ok, error, value, call} + }, + calls, + } +} + +const apply_assignments = (do_node, assignments) => { + const let_ids = do_node + .children + .filter(c => c.type == 'let') + .map(l => l.children) + .flat() + .map(c => c.index) + + const unused_assignments = filter_object(assignments, (index, val) => + let_ids.find(i => i.toString() == index) == null + ) + + // Scope we return to parent block + const scope = Object.fromEntries( + Object + .entries(assignments) + .filter(([index, v]) => + let_ids.find(i => i.toString() == index) == null + ) + .map(([k, {name, value}]) => [name, value]) + ) + + const node = {...do_node, + children: do_node.children.map(_let => { + if(_let.type != 'let') { + return _let + } + const children = _let.children.map(id => { + const a = assignments[id.index] + if(a == null) { + return id + } else { + return {...id, result: {ok: true, value: a.value}} + } + }) + return {..._let, + result: children.every(c => c.result != null) ? {ok: true} : null, + children + } + }) + } + + return {node, scope} +} + + +const eval_statement = (s, scope, calls, calltree) => { + if(s.type == 'do') { + const node = s + const {ok, assignments, returned, stmts, calls: nextcalls} = node.stmts.reduce( + ({ok, returned, stmts, scope, calls, assignments}, s) => { + if(returned || !ok) { + return {ok, returned, scope, calls, stmts: [...stmts, s], assignments} + } else { + const { + ok, + returned, + node, + assignments: next_assignments, + scope: nextscope, + calls: next_calls, + } = eval_statement(s, scope, calls, calltree) + return { + ok, + returned, + assignments: {...assignments, ...next_assignments}, + scope: nextscope, + calls: next_calls, + stmts: [...stmts, node], + } + } + }, + {ok: true, returned: false, stmts: [], scope, calls, assignments: {}} + ) + const {node: next_node, scope: next_scope} = + apply_assignments({...node, children: stmts, result: {ok}}, assignments) + return { + ok, + node: next_node, + scope: {...scope, ...next_scope}, + returned, + assignments, + calls: nextcalls, + } + } else if(s.type == 'const' || s.type == 'assignment') { + // TODO default values for destructuring can be function calls + + const {node, calls: next_calls} = eval_frame_expr(s.expr, scope, calls) + const s_expr_evaled = {...s, children: [s.name_node, node]} + if(!node.result.ok) { + return { + ok: false, + node: {...s_expr_evaled, result: {ok: false}}, + scope, + calls: next_calls, + } + } + + const name_nodes = collect_destructuring_identifiers(s.name_node) + const names = name_nodes.map(n => n.value) + const destructuring = codegen(s.name_node) + + // TODO unique name for __value (gensym) + const codestring = ` + const ${destructuring} = __value; + ({${names.join(',')}}); + ` + const {ok, value: next_scope, error} = eval_codestring( + codestring, + {...scope, __value: node.result.value} + ) + + // TODO fine-grained destructuring error, only for identifiers that failed + // destructuring + const name_node_with_result = map_tree( + map_destructuring_identifiers( + s.name_node, + node => ({...node, + result: { + ok, + error: ok ? null : error, + value: !ok ? null : next_scope[node.value], + } + }) + ), + n => n.result == null + ? {...n, result: {ok}} + : n + ) + + const s_evaled = {...s_expr_evaled, children: [ + name_node_with_result, + s_expr_evaled.children[1], + ]} + + if(!ok) { + return { + ok: false, + // TODO assign error to node where destructuring failed, not to every node + node: {...s_evaled, result: {ok, error}}, + scope, + calls, + } + } + + return { + ok: true, + node: {...s_evaled, result: {ok: true}}, + scope: {...scope, ...next_scope}, + calls: next_calls, + assignments: s.type == 'assignment' + ? Object.fromEntries( + name_nodes.map(n => [ + n.definition.index, + { + value: next_scope[n.value], + name: n.value, + } + ]) + ) + : null + } + } else if(s.type == 'return') { + + const {node, calls: next_calls} = eval_frame_expr(s.expr, scope, calls) + + return { + ok: node.result.ok, + returned: node.result.ok, + node: {...s, children: [node], result: {ok: node.result.ok}}, + scope, + calls: next_calls, + } + + } else if(s.type == 'export') { + const {ok, scope: nextscope, calls: next_calls, node} = eval_statement(s.binding, scope, calls) + return { + ok, + scope: nextscope, + calls: next_calls, + node: {...s, children: [node], result: {ok: node.result.ok}} + } + } else if(s.type == 'import') { + const children = s.imports.map(i => ( + {...i, + result: {ok: true, value: calltree[s.full_import_path].exports[i.value]} + } + )) + const imported_scope = Object.fromEntries(children.map(i => [i.value, i.result.value])) + return { + ok: true, + scope: {...scope, ...imported_scope}, + calls, + node: {...s, children, result: {ok: true}} + } + } else if(s.type == 'if') { + + const {node, calls: next_calls} = eval_frame_expr(s.cond, scope, calls) + + if(!node.result.ok) { + return { + ok: false, + node: {...s, children: [node, ...s.branches], result: {ok: false}}, + scope, + calls: next_calls, + } + } + + if(s.branches.length == 1) { + // if without else + if(node.result.value) { + // Execute branch + const { + node: evaled_branch, + returned, + assignments, + scope: next_scope, + calls: next_calls2, + } = eval_statement( + s.branches[0], + scope, + next_calls, + ) + return { + ok: evaled_branch.result.ok, + returned, + assignments, + node: {...s, + children: [node, evaled_branch], + result: {ok: evaled_branch.result.ok} + }, + scope: next_scope, + calls: next_calls2, + } + } else { + // Branch is not executed + return { + ok: true, + node: {...s, children: [node, s.branches[0]], result: {ok: true}}, + scope, + calls: next_calls, + } + } + } else { + // if with else + const active_branch = node.result.value ? s.branches[0] : s.branches[1] + + const { + node: evaled_branch, + returned, + assignments, + scope: next_scope, + calls: next_calls2 + } = eval_statement( + active_branch, + scope, + next_calls, + ) + + const children = node.result.value + ? [node, evaled_branch, s.branches[1]] + : [node, s.branches[0], evaled_branch] + + return { + ok: evaled_branch.result.ok, + returned, + assignments, + node: {...s, children, result: {ok: evaled_branch.result.ok}}, + scope: next_scope, + calls: next_calls2, + } + } + + } else if(s.type == 'let') { + + return { ok: true, node: s, scope, calls } + + } else if(s.type == 'throw') { + + const {node, calls: next_calls} = eval_frame_expr(s.expr, scope, calls) + + return { + ok: false, + node: {...s, + children: [node], + result: { + ok: false, + error: node.result.ok ? node.result.value : null, + } + }, + scope, + calls: next_calls, + } + + } else { + // stmt type is expression + const {node, calls: next_calls} = eval_frame_expr( + s, + scope, + calls, + ) + return { + ok: node.result.ok, + node, + scope, + calls: next_calls, + } + } +} + +export const eval_frame = (calltree_node, calltree) => { + if(calltree_node.has_more_children) { + throw new Error('illegal state') + } + const node = calltree_node.code + if(node.type == 'do') { + return eval_statement( + node, + {}, + calltree_node.children, + calltree, + ).node + } else { + // TODO default values for destructuring can be function calls + + const args_scope_result = get_args_scope(node, calltree_node.args) + + // TODO fine-grained destructuring error, only for identifiers that + // failed destructuring + const function_args_with_result = { + ...node.function_args, + result: args_scope_result, + children: node.function_args.children.map(arg => + map_tree( + map_destructuring_identifiers( + arg, + a => ({...a, + result: { + ok: args_scope_result.ok, + error: args_scope_result.ok ? null : args_scope_result.error, + value: !args_scope_result.ok ? null : args_scope_result.value[a.value], + } + }) + ), + n => n.result == null + ? {...n, result: {ok: args_scope_result.ok}} + : n + ) + ) + } + + const body = node.body + + if(!args_scope_result.ok) { + return {...node, + result: {ok: false}, + children: [function_args_with_result, body], + } + } + + const scope = {...calltree_node.fn.__closure, ...args_scope_result.value} + + + let nextbody + + if(body.type == 'do') { + nextbody = eval_statement( + body, + scope, + calltree_node.children, + ).node + } else { + nextbody = eval_frame_expr(body, scope, calltree_node.children) + .node + } + + return {...node, + result: {ok: nextbody.result.ok}, + children: [function_args_with_result, nextbody], + } + } +} diff --git a/src/feature_flags.js b/src/feature_flags.js new file mode 100644 index 0000000..2bb7c21 --- /dev/null +++ b/src/feature_flags.js @@ -0,0 +1,3 @@ +export const FLAGS = { + embed_value_explorer: true, +} diff --git a/src/filesystem.js b/src/filesystem.js new file mode 100644 index 0000000..80707c6 --- /dev/null +++ b/src/filesystem.js @@ -0,0 +1,135 @@ +// code is borrowed from +// https://googlechrome.github.io/samples/service-worker/post-message/ +const send_message = (message) => { + return new Promise(function(resolve) { + const messageChannel = new MessageChannel(); + messageChannel.port1.onmessage = function(event) { + resolve(event.data) + }; + if(navigator.serviceWorker.controller == null) { + // Service worker will be available after reload + window.location.reload() + } + navigator.serviceWorker.controller.postMessage(message, + [messageChannel.port2]); + }); +} + +globalThis.clear_directory_handle = () => { + send_message({type: 'SET', data: null}) + window.location.reload() +} + +let dir_handle + +const request_directory_handle = async () => { + dir_handle = await showDirectoryPicker() + await send_message({type: 'SET', data: dir_handle}) + return dir_handle +} + +export const load_persisted_directory_handle = () => { + return navigator.serviceWorker.register('service_worker.js') + .then(() => navigator.serviceWorker.ready) + .then(() => send_message({type: 'GET'})) + .then(async h => { + if(h == null || (await h.queryPermission()) != 'granted') { + return null + } + // test if directory handle is valid + try { + await h.entries().next() + } catch(e) { + return null + } + dir_handle = h + return dir_handle + }) +} + +const file_handle = async (dir_handle, filename, is_directory = false, options) => { + if(typeof(filename) == 'string') { + filename = filename.split('/') + } + const [first, ...rest] = filename + if(rest.length == 0) { + return is_directory + ? await dir_handle.getDirectoryHandle(first, options) + : await dir_handle.getFileHandle(first, options) + } else { + const nested_dir_handle = await dir_handle.getDirectoryHandle(first) + return file_handle(nested_dir_handle, rest, is_directory, options) + } +} + +export const write_file = async (name, contents) => { + const f_hanlde = await file_handle(dir_handle, name) + // Create a FileSystemWritableFileStream to write to. + const writable = await f_hanlde.createWritable() + // Write the contents of the file to the stream. + await writable.write(contents) + // Close the file and write the contents to disk. + await writable.close() +} + +// Blacklist hidden dirs and node_modules +const is_blacklisted = h => h.name == 'node_modules' || h.name.startsWith('.') + +const read_file = async handle => { + const file_data = await handle.getFile() + return await file_data.text() +} + +const do_load_dir = async (handle, path) => { + if(handle.kind == 'directory') { + const children = [] + for await (let [name, h] of handle) { + if(!is_blacklisted(h)) { + children.push(h) + } + } + return { + name: handle.name, + path, + kind: 'directory', + children: await Promise.all( + children + .map(c => + do_load_dir(c, path == null ? c.name : path + '/' + c.name) + ) + .sort((a,b) => a.name > b.name) + ) + } + } else if(handle.kind == 'file') { + return { + name: handle.name, + path, + kind: 'file', + contents: await read_file(handle) + } + } else { + throw new Error('unknown kind') + } +} + +export const create_file = (path, is_dir) => { + return file_handle( + dir_handle, + path, + is_dir, + {create: true} + ) +} + +export const load_dir = async (should_request_access) => { + let handle + if(should_request_access) { + handle = await request_directory_handle() + } else { + handle = await load_persisted_directory_handle() + if(handle == null) { + return null + } + } + return do_load_dir(handle, null) +} diff --git a/src/find_definitions.js b/src/find_definitions.js new file mode 100644 index 0000000..0e75a8e --- /dev/null +++ b/src/find_definitions.js @@ -0,0 +1,304 @@ +// TODO rename to analyze.js + +import {set_push, set_diff, set_union, map_object, map_find, uniq} from './utils.js' +import {collect_destructuring_identifiers, collect_imports, ancestry, find_leaf} from './ast_utils.js' + +// TODO get complete list of globals (borrow from eslint?) +import {globals} from './globals.js' + +const map_find_definitions = (nodes, mapper) => { + const result = nodes.map(mapper) + const undeclared = result.reduce( + (acc, el) => el.undeclared == null ? acc : acc.concat(el.undeclared), + [] + ) + const closed = result.map(r => r.closed).reduce(set_union, new Set()) + return { + nodes: result.map(r => r.node), + undeclared, + closed, + } +} + + +const scope_from_node = n => { + if(n.type == 'import') { + return Object.fromEntries( + n.imports.map(i => [i.value, i]) + ) + } else if(n.type == 'export'){ + return scope_from_node(n.binding) + } else if(n.type == 'const' || n.type == 'let'){ + return Object.fromEntries( + collect_destructuring_identifiers(n.name_node).map(node => [ + node.value, node + ]) + ) + } else { + return null + } +} + +const add_trivial_definition = node => { + if(node.type == 'identifier') { + return {...node, definition: 'self'} + } else if(['destructuring_default', 'destructuring_rest'].includes(node.type)){ + return {...node, + children: [add_trivial_definition(node.name_node), ...node.children.slice(1)] + } + } else if(node.type == 'destructuring_pair') { + return {...node, children: [ + node.children[0], // key + add_trivial_definition(node.children[1]), // value + ]} + } else if(['array_destructuring', 'object_destructuring'].includes(node.type)) { + return {...node, children: node.children.map(add_trivial_definition)} + } else { + console.error(node) + throw new Error('not implemented') + } +} + +/* + * The function does these things: + * - For each occurence of identifier, attaches definition to this identifier + * - For each closure, attaches 'closed` property with set of vars it closes + * over + * - Finds undeclared identifiers + * + * `scope` is names that are already defined and can be used immediately. + * `closure_scope` is names that are defined but not yet assigned, but they + * will be assigned by the time the closures would be called + */ + +// TODO in same pass find already declared +export const find_definitions = (ast, scope = {}, closure_scope = {}, module_name) => { + if(ast.type == 'identifier'){ + if(ast.definition != null) { + // Definition previously added by add_trivial_definition + return {node: ast, undeclared: null, closed: new Set([ast.value])} + } else { + const definition = scope[ast.value] + if(definition == null){ + if(globals.has(ast.value)) { + return {node: {...ast, definition: 'global'}, undeclared: null, closed: new Set()} + } else { + return {node: ast, undeclared: [ast], closed: new Set()} + } + } else { + return { + node: {...ast, definition: {index: definition.index}}, + undeclared: null, + closed: new Set([ast.value]) + } + } + } + } else if(ast.type == 'do'){ + const children_with_scope = ast.children.reduce( + ({scope, children}, node) => ({ + scope: {...scope, ...scope_from_node(node)}, + children: children.concat([{node, scope}]), + }) + , + {scope: {}, children: []} + ) + const local_scope = children_with_scope.scope + const {nodes, undeclared, closed} = map_find_definitions(children_with_scope.children, cs => + find_definitions(cs.node, {...scope, ...cs.scope}, local_scope, module_name) + ) + return { + node: {...ast, children: nodes}, + undeclared, + closed: set_diff(closed, new Set(Object.keys(local_scope))), + } + } else if (ast.type == 'function_expr'){ + const args_identifiers = collect_destructuring_identifiers(ast.function_args) + const args_scope = Object.fromEntries(args_identifiers.map(a => [ + a.value, a + ])) + const {nodes, undeclared, closed} = map_find_definitions(ast.children, + node => find_definitions(node, {...scope, ...closure_scope, ...args_scope}) + ) + const next_closed = set_diff(closed, new Set(args_identifiers.map(a => a.value))) + return { + node: {...ast, children: nodes, closed: next_closed}, + undeclared, + closed: new Set(), + } + } else if(ast.children != null){ + let children, full_import_path + if(ast.type == 'import') { + full_import_path = concat_path(module_name, ast.module) + children = ast.children.map(c => ({...c, definition: {module: full_import_path}})) + } else if(ast.type == 'const') { + children = [add_trivial_definition(ast.name_node), ...ast.children.slice(1)] + } else if(ast.type == 'let') { + children = ast.name_node.map(add_trivial_definition) + } else { + children = ast.children + } + + const {nodes, undeclared, closed} = map_find_definitions(children, + c => find_definitions(c, scope, closure_scope) + ) + + return { + node: ast.type == 'import' + ? {...ast, children: nodes, full_import_path} + : {...ast, children: nodes}, + undeclared, + closed + } + } else { + return {node: ast, undeclared: null, closed: new Set()} + } +} + +// see https://stackoverflow.com/a/29855511 + +// Joins path segments. Preserves initial "/" and resolves ".." and "." +// Does not support using ".." to go above/outside the root. +// This means that join("foo", "../../bar") will not resolve to "../bar" + +const join = new Function(` + // Split the inputs into a list of path commands. + var parts = []; + for (var i = 0, l = arguments.length; i < l; i++) { + parts = parts.concat(arguments[i].split("/")); + } + // Interpret the path commands to get the new resolved path. + var newParts = []; + for (i = 0, l = parts.length; i < l; i++) { + var part = parts[i]; + // Remove leading and trailing slashes + // Also remove "." segments + if (!part || part === ".") continue; + // Interpret ".." to pop the last segment + if (part === "..") newParts.pop(); + // Push new path segments. + else newParts.push(part); + } + // Preserve the initial slash if there was one. + if (parts[0] === "") newParts.unshift(""); + // Turn back into a single string path. + return newParts.join("/") || (newParts.length ? "/" : "."); +`) + +const concat_path = (base, imported) => + base == '' ? join(imported) : join(base, '..', imported) + +export const find_export = (name, module) => { + return map_find(module.stmts, n => { + if(n.type != 'export') { + return null + } + const ids = collect_destructuring_identifiers(n.binding.name_node) + return ids.find(i => i.value == name) + }) +} + + +export const topsort_modules = (modules) => { + const sort_module_deps = (module) => { + return Object.keys(collect_imports(modules[module])) + .reduce( + (result, m) => result.concat(sort_module_deps(m)), + [] + ) + .concat(module) + } + + const sorted = Object.keys(modules).reduce( + (result, module) => result.concat(sort_module_deps(module)), + [] + ) + + // now remove duplicates + // quadratic, but N is supposed to be small + return sorted.reduce( + (result, elem) => + result.includes(elem) + ? result + : [...result, elem] + , + [] + ) +} + +// TODO not implemented +// TODO detect cycles when loading modules +export const check_imports = modules => { + // TODO allow circular imports + return map_object(modules, (module, node) => { + const imports = node.stmts + .filter(n => n.type == 'import') + .reduce( + (imports, n) => [ + ...imports, + ...(n.imports.map(i => ({name: i.value, from: n.module}))) + ], + [] + ) + const exports = node.statement + .filter(n => n.type == 'export') + .map(n => collect_destructuring_identifiers(n.binding.name_node)) + .reduce((all, current) => [...all, ...current], []) + + return {imports, exports} + //TODO check for each import, there is export + }) + // Topological sort + // For each module + // Depth-traverse deps and detect cycles +} + +/* +TODO: relax, only disallow code that leads to broken target code + +code analysis: +- function must have one and only one return statement in every branch +- return must be the last statement in block + +- name is declared once and only once (including function args). Name can be imported once +- let must be assigned once and only once (in each branch) +- every assignment can only be to if identifier is earlier declared by let +- assignment can only be inside if statement (after let) (relax it?) +- cannot import names that are not exported from modules +- cannot return from modules (even inside toplevel if statements) +*/ +export const analyze = (node, is_toplevel = true) => { + // TODO remove + return [] + + /* + // TODO sort by location? + if(node.type == 'do') { + let illegal_returns + if(is_toplevel) { + illegal_returns = node.stmts.filter(s => s.type == 'return') + } else { + const last = node.stmts[node.stmts.length - 1]; + illegal_returns = node.stmts.filter(s => s.type == 'return' && s != last); + + returns.map(node => ({ + node, + message: 'illegal return statement', + })); + + const last_return = last.type == 'return' + ? null + : {node: last, message: 'block must end with return statement'} + + + // TODO recur to childs + } + } else if(node.children != null){ + return node.children + .map(n => analyze(n, node.type == 'function_expr' ? false : is_toplevel)) + .reduce((ps, p) => ps.concat(p), []) + } else { + // TODO + 1 + } + */ +} diff --git a/src/globals.js b/src/globals.js new file mode 100644 index 0000000..19e36df --- /dev/null +++ b/src/globals.js @@ -0,0 +1,39 @@ +export const globals = new Set([ + 'globalThis', + // TODO Promise, + // TODO Symbol + 'Set', + 'Map', + "Infinity", + "NaN", + "undefined", + "Function", + "Object", + "Array", + "Number", + "String", + "Boolean", + "Date", + "Math", + "RegExp", + "JSON", + "Error", + "EvalError", + "RangeError", + "ReferenceError", + "SyntaxError", + "TypeError", + "URIError", + "isNaN", + "isFinite", + "parseFloat", + "parseInt", + "eval", + "escape", + "unescape", + "decodeURI", + "decodeURIComponent", + "encodeURI", + "encodeURIComponent", + "console", +]) diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..621d8fc --- /dev/null +++ b/src/index.js @@ -0,0 +1,112 @@ +import {COMMANDS, get_initial_state} from './cmd.js' +import {active_frame} from './calltree.js' +import {UI} from './editor/ui.js' +import {EFFECTS, render_initial_state, render_common_side_effects} from './effects.js' +import {load_dir} from './filesystem.js' + +const EXAMPLE = `const fib = n => + n == 0 || n == 1 + ? n + : fib(n - 1) + fib(n - 2) +fib(6)` + +const read_modules = async () => { + const default_module = {'': localStorage.code || EXAMPLE} + const current = { + // TODO fix when there are no such modules anymore + current_module: localStorage.current_module ?? '', + entrypoint: localStorage.entrypoint ?? '', + } + const project_dir = await load_dir(false) + if(project_dir == null) { + // Single anonymous module + return { + ...current, + files: default_module, + } + } else { + return { + ...current, + project_dir, + files: default_module, + } + } +} + +let ui +let state + +export const init = (container) => { + // TODO err.message + window.onerror = (msg, src, lineNum, colNum, err) => { + ui.set_status(msg) + } + window.addEventListener('unhandledrejection', (event) => { + ui.set_status(event.reason) + }) + + read_modules().then(initial_state => { + state = get_initial_state(initial_state) + // Expose state for debugging + globalThis.__state = state + ui = new UI(container, state) + // Expose for debugging + globalThis.__ui = ui + render_initial_state(ui, state) + }) +} + +export const get_state = () => state + +export const exec = (cmd, ...args) => { + if(cmd == 'input' || cmd == 'write') { + // Do not print file to console + console.log('exec', cmd) + } else { + console.log('exec', cmd, ...args) + } + + const comm = cmd.split('.').reduce( + (comm, segment) => comm?.[segment], + COMMANDS + ) + if(comm == null) { + throw new Error('command ' + cmd + ' + not found') + } + + const result = comm(state, ...args) + console.log('nextstate', result) + + let nextstate, effects + if(result.state != null) { + ({state: nextstate, effects} = result) + } else { + nextstate = result + effects = null + } + + // Sanity check + if(state?.parse_result == null) { + console.error('command did not return state, returned', result) + throw new Error('illegal state') + } + + render_common_side_effects(state, nextstate, cmd, ui); + + if(effects != null) { + (Array.isArray(effects) ? effects : [effects]).forEach(e => { + if(e.type == 'write' || e.type == 'save_to_localstorage') { + // do not spam to console + console.log('apply effect', e.type) + } else { + console.log('apply effect', e.type, ...(e.args ?? [])) + } + EFFECTS[e.type](nextstate, e.args, ui) + }) + } + + // Expose for debugging + globalThis.__prev_state = state + globalThis.__state = nextstate + state = nextstate +} diff --git a/src/parse_js.js b/src/parse_js.js new file mode 100644 index 0000000..3d8987d --- /dev/null +++ b/src/parse_js.js @@ -0,0 +1,1633 @@ +import {stringify, zip, uniq, map_object} from './utils.js' + +import { + find_definitions, + topsort_modules, + check_imports, + analyze, +} from './find_definitions.js' + +import {reserved} from './reserved.js' + +import {collect_imports} from './ast_utils.js' + +const builtin_identifiers = ['true', 'false', 'null'] + +// Workaround that regexp cannot be drained with imperative code +// TODO foreign pragma +const drain_regexp = new Function('regexp', 'str', ` + const result = [] + let match + while((match = regexp.exec(str)) != null) { + result.push(match) + } + return result +`) + +// https://deplinenoise.wordpress.com/2012/01/04/python-tip-regex-based-tokenizer/ +const tokenize_js = (str) => { + + const arithmetic_ops = [ + '+', '-', '*', '/', '%', '**', + ] + + const logic_ops = [ + '===', '==', '!==', '!=', '!', '&&', '||', '??', + ] + + const punctuation = [ + // Braces + '(', ')', + + // Array literal, property access + '[', ']', + + // Map literal, blocks + '{', '}', + + // Spread + '...', + + // Property access + '.', + + // Optional chaining + '?.', + + ';', + + ',', + + // function expression, must be before `=` to take precedence + '=>', + + ...arithmetic_ops, + + ...logic_ops, + + + '=', + + // Comparison + '<=', '>=', '>', '<', + + // Ternary + '?', ':', + + // TODO bit operations + ] + + const TOKENS = [ + {name: 'comment' , re: '//[^\n]*'}, + {name: 'comment' , re: '\\/\\*[\\s\\S]*?\\*\\/'}, + {name: 'newline' , re: '[\r\n\]+'}, + + + // whitespace except newline + //https://stackoverflow.com/a/3469155 + {name: 'whitespace' , re: '[^\\S\\r\\n]+'}, + + {name: 'string_literal' , re: "'.*?'"}, + {name: 'string_literal' , re: '".*?"'}, + + // TODO parse vars inside backtick string + {name: 'backtick_string' , re: '`[\\s\\S]*?`'}, + + {name: 'builtin_identifier' , re: builtin_identifiers + .map(i => '\\b' + i + '\\b') + .join('|')}, + {name: 'keyword' , re: reserved.map(r => '\\b' + r + '\\b').join('|')}, + // TODO all possible notatins for js numbers + {name: 'number' , re: '-?\\d*\\.?\\d+'}, + {name: 'identifier' , re: '[A-Za-z_][A-Za-z0-9_]*'}, + + {name: 'punctuation' , + re: '(' + + punctuation.map( + str => [...str].map(symbol => '\\' + symbol).join('') + ).join('|') + + ')'}, + ] + + // TODO test unbalanced quotes + const regexp_str = TOKENS.map(({re}) => '(' + re + ')').join('|') + const r = new RegExp(regexp_str, 'mg') + + const matches = drain_regexp(r, str) + + const tokens = matches.map(m => { + const type = TOKENS + .find((t,i) => + m[i + 1] != null + ) + .name + + return { + type, + index: m.index, + string: m[0], + length: m[0].length, + } + }) + + if(tokens.length == 0) { + return {ok: true, tokens} + } else { + const unexpected_token = + zip( + [{index: 0, length: 0}, ...tokens], + [...tokens, {index: str.length}], + ) + .find(([prev, current]) => prev.index + prev.length != current.index) + + if(unexpected_token != null) { + const prev = unexpected_token[0] + return { + ok: false, + index: prev.index + prev.length, + message: 'unexpected lexical token', + } + } else { + return {ok: true, tokens} + } + } +} + +/* + Parser combinators +*/ + +/* +let log_level = 1 +const log = (label, fn) => { + return (...args) => { + const cxt = args[0]; + const prefix = '-'.repeat(log_level) + console.log(prefix, label, 'args', cxt.str.slice(cxt.tokens[cxt.current].index)); + log_level++ + const result = fn(...args); + log_level-- + const {ok, value, error, cxt: cxterr} = result; + if(ok) { + console.log(prefix, label, 'ok', stringify(value)); + } else { + console.log(prefix, label, 'error', error, cxterr.str.slice(cxterr.tokens[cxterr.current].index)); + } + return result + } +} +const log_mute = (label, fn) => { + return fn +} +*/ + +const current = cxt => cxt.current < cxt.tokens.length + ? cxt.tokens[cxt.current] + : null + +const literal = str => by_pred(token => token.string == str, 'expected ' + str) + +const by_pred = (pred, error) => { + const result = cxt => { + const token = current(cxt) + + if(token == null) { + return {ok: false, error, cxt} + } + + if(pred(token)) { + return { + ok: true, + value: {...token, value: token.string, string: undefined}, + cxt: {...cxt, current: cxt.current + 1} + } + } + + if(token.type == 'newline') { + return result({...cxt, current: cxt.current + 1}) + } + + return {ok: false, error, cxt} + } + + return result +} + +const by_type = type => by_pred( + token => token.type == type, + 'expected ' + type +) + +const newline = by_type('newline') + +export const eof = cxt => { + const c = current(cxt) + if(c == null) { + return {ok: true, cxt} + } + if(c.type == 'newline') { + return eof({...cxt, current: cxt.current + 1}) + } + return {ok: false, error: 'unexpected token, expected eof', cxt} +} + +const either = (...parsers) => cxt => { + return parsers.reduce( + (result, p) => { + if(result.ok) { + return result + } else { + const other = p(cxt) + if(other.ok) { + return other + } else { + // Select error that matched more tokens + return result.cxt.current > other.cxt.current + ? result + : other + } + } + }, + {ok: false, cxt: {current: 0}}, + ) +} + +const optional = parser => cxt => { + const result = parser(cxt) + return result.ok + ? result + : {ok: true, value: null, cxt} +} + +const apply_location = result => { + if(result.ok) { + const first = result.value.find(v => v != null) + const last = [...result.value].reverse().find(v => v != null) + const value = { + value: result.value, + index: first.index, + length: (last.index + last.length) - first.index, + } + return {...result, value} + } else { + return result + } +} + +const seq = parsers => cxt => { + const seqresult = parsers.reduce( + (result, parser) => { + if(result.ok) { + const nextresult = parser(result.cxt) + if(nextresult.ok) { + return {...nextresult, value: result.value.concat([nextresult.value])} + } else { + return nextresult + } + } else { + return result + } + }, + {cxt, ok: true, value: []} + ) + if(seqresult.ok) { + return apply_location(seqresult) + } else { + return seqresult + } +} + +const if_ok = (parser, fn) => cxt => { + const result = parser(cxt) + if(!result.ok) { + return result + } else { + return {...result, value: fn(result.value)} + } +} + +const if_fail = (parser, error) => cxt => { + const result = parser(cxt) + if(result.ok) { + return result + } else { + return {...result, error} + } +} + +const if_ok_then = (parser, fn) => cxt => { + const result = parser(cxt) + return !result.ok + ? result + : fn(result.value)(result.cxt) +} + + +const seq_select = (index, parsers) => + if_ok( + seq(parsers), + node => ({...node, value: node.value[index]}) + ) + +const repeat = parser => cxt => { + const dorepeat = (cxt, values) => { + const result = parser(cxt) + if(result.ok) { + return dorepeat(result.cxt, values.concat([result.value])) + } else { + return values.length == 0 + ? result + : {ok: true, value: values, cxt} + } + } + const result = dorepeat(cxt, []) + if(!result.ok) { + return result + } else { + return apply_location(result) + } +} + +const repeat_until = (parser, stop) => cxt => { + const dorepeat = (cxt, values) => { + const result_stop = stop(cxt) + if(result_stop.ok) { + return {ok: true, cxt, value: values} + } else { + const result = parser(cxt) + if(result.ok) { + return dorepeat(result.cxt, values.concat([result.value])) + } else { + return result + } + } + } + const result = dorepeat(cxt, []) + if(!result.ok) { + return result + } else { + if(result.value.length == 0) { + return {...result, value: {value: result.value}} + } else { + return apply_location(result) + } + } +} + +const lookahead = parser => cxt => { + const result = parser(cxt) + if(result.ok) { + return {...result, cxt} + } else { + return result + } +} + +const finished = parser => + if_ok( + seq_select(0, [ + parser, + eof + ]), + ({value}) => value + ) + +/* + End parser combinators +*/ + + + +////////////////////////////////////////////////////////////// + // PARSER +////////////////////////////////////////////////////////////// + +const not_followed_by = (followed, follower) => cxt => { + const result = followed(cxt) + if(!result.ok) { + return result + } else { + const nextresult = follower(result.cxt) + if(nextresult.ok) { + return {ok: false, cxt, error: 'not_followed_by'} + } else { + return result + } + } +} + +/* ret from return */ +const ret = value => cxt => ({ok: true, value, cxt}) + +const attach_or_pass = (nested, attachment, add_attachment) => + if_ok( + seq([ + nested, + optional(attachment), + ]), + ({value, ...node}) => { + const [item, attachment] = value + if(attachment == null) { + return item + } else { + return {...node, ...add_attachment(item, attachment)} + } + } + ) + +const identifier = by_type('identifier') + +const builtin_identifier = if_ok( + by_type('builtin_identifier'), + ({...token}) => ({...token, type: 'builtin_identifier'}), +) + +const string_literal = by_type('string_literal') + +const unary = operator => nested => + if_ok( + seq([ + optional( + literal(operator) + ), + nested, + ]), + ({value, ...node}) => ( + value[0] == null + ? value[1] + : { + ...node, + type: 'unary', + operator, + children: [value[1]], + } + ) + ) + +const binary = ops => nested => + attach_or_pass( + nested, + + repeat( + seq([ + by_pred(token => ops.includes(token.string), 'expected ' + ops.join(',')), + nested, + ]) + ), + + (item, repetitions) => + repetitions.value.reduce( + (prev_node, rep) => { + const children = [ + prev_node, + rep.value[1], + ] + return { + // TODO refactor. This code is copypasted to other places that use 'repeat' + index: item.index, + length: rep.index - item.index + rep.length, + type: 'binary', + operator: rep.value[0].value, + children, + } + }, + item, + ) + ) + + +/* + // TODO check how ternary work + (foo ? bar : baz) ? qux : quux + foo ? bar : (baz ? qux : quux) +*/ +const ternary = nested => + attach_or_pass( + nested, + if_ok( + seq([ + literal('?'), + cxt => expr(cxt), + literal(':'), + cxt => expr(cxt), + ]), + value => { + const [_, left, __, right] = value.value; + return {...value, value: [left, right]} + }, + ), + (cond, {value: branches}) => { + return { + type: 'ternary', + cond, + branches, + children: [cond, ...branches], + } + } + ) + +const list = (separators, element_parser) => cxt => { + const cs = if_ok_then( + optional(lookahead(literal(separators[1]))), + value => + value != null + ? ret([]) + : if_ok_then( + element_parser, + value => if_ok_then( + optional(literal(',')), + comma => + comma == null + ? ret([value]) + : if_ok_then( + cs, + values => ret([value, ...values]) + ) + ) + ) + ) + + return seq_select(1, [ + literal(separators[0]), + cs, + literal(separators[1]), + ])(cxt) + +} + +const comma_separated_1 = element => cxt => { + + const do_comma_separated_1 = cxt => { + + const result = element(cxt) + if(!result.ok) { + return result + } + + const comma_result = literal(',')(result.cxt) + if(!comma_result.ok) { + return {...result, value: [result.value]} + } + + const rest = do_comma_separated_1(comma_result.cxt) + if(!rest.ok) { + return rest + } + + return {...rest, value: [result.value, ...rest.value]} + } + + const result = do_comma_separated_1(cxt) + if(!result.ok) { + return result + } else { + return apply_location(result) + } + +} + +const list_destructuring = (separators, node_type) => if_ok( + + list( + separators, + either( + // identifier = value + if_ok( + seq([ + cxt => destructuring(cxt), + literal('='), + cxt => expr(cxt), + ]), + ({value, ...node}) => ({ + ...node, + not_evaluatable: true, + type: 'destructuring_default', + children: [value[0], value[2]], + }) + ), + + // just identifier + cxt => destructuring(cxt), + + if_ok( + seq_select(1, [ + literal('...'), + cxt => destructuring(cxt), + ]), + ({value, ...node}) => ({ + ...node, + type: 'destructuring_rest', + not_evaluatable: true, + children: [value], + }) + ) + ) + ), + + ({value, ...node}) => ({ + // TODO check that rest is last element + ...node, + type: node_type, + not_evaluatable: true, + children: value, + }), + +) + +const array_destructuring = + list_destructuring(['[', ']'], 'array_destructuring') + +const object_destructuring = if_ok( + + // TODO computed property names, like `const {[x]: y} = {}` + // TODO default values, like `const {x = 1} = {}` + // TODO string keys `const {'x': x} = {x: 2}` + + list( + ['{', '}'], + either( + // identifier: destructuring + if_ok( + seq([ + // Normalize key without quotes to quoted key + if_ok( + identifier, + iden => ({...iden, type: 'string_literal', value: '"' + iden.value + '"'}), + ), + literal(':'), + cxt => destructuring(cxt), + ]), + ({value, ...node}) => ({ + ...node, + not_evaluatable: true, + type: 'destructuring_pair', + children: [value[0], value[2]], + }) + ), + + // just identifier + identifier, + + // rest + if_ok( + seq_select(1, [ + literal('...'), + identifier, + ]), + ({value, ...node}) => ({ + ...node, + type: 'destructuring_rest', + not_evaluatable: true, + children: [value], + }) + ) + ), + ), + + ({value, ...node}) => ({ + // TODO check that rest is last element + ...node, + type: 'object_destructuring', + not_evaluatable: true, + children: value, + }), + +) + +const destructuring = + either(identifier, array_destructuring, object_destructuring) + +/* Parse function_call, member_access or computed_member_access which are of + * the same priority + */ +const function_call_or_member_access = nested => + attach_or_pass( + nested, + + repeat( + either( + + // Member access + if_ok( + seq([ + either( + literal('?.'), + literal('.'), + ), + // Adjust identifier to string literal + if_ok( + identifier, + iden => ({...iden, + type: 'string_literal', + value: '"' + iden.value + '"', + not_evaluatable: true, + }), + ), + ]), + + ({value: [op, id], ...node}) => ({ + ...node, + value: id, + type: 'member_access', + is_optional_chaining: op.value == '?.', + }) + ), + + // Computed member access + if_ok( + seq([ + optional(literal('?.')), + literal('['), + cxt => expr(cxt), + literal(']'), + ]), + ({value: [optional_chaining, _1, value, _3], ...node}) => ( + {...node, + value, + type: 'computed_member_access', + is_optional_chaining: optional_chaining != null, + } + ) + ), + + // Function call + if_ok( + list( + ['(', ')'], + array_element, + ), + node => ({...node, type: 'function_call'}) + ) + ) + ), + + (object, repetitions) => repetitions.value.reduce( + (object, rep) => { + // TODO refactor. This code is copypasted to other places that use 'repeat' + const index = object.index + const length = rep.index - object.index + rep.length + let result + if(rep.type == 'member_access' || rep.type == 'computed_member_access') { + result = { + type: 'member_access', + is_optional_chaining: rep.is_optional_chaining, + children: [object, rep.value], + } + } else if(rep.type == 'function_call') { + const fn = object + + const {value, ...rest} = rep + const call_args = { + ...rest, + children: value, + not_evaluatable: value.length == 0, + type: 'call_args' + } + result = { + type: 'function_call', + children: [fn, call_args] + } + } else { + throw new Error() + } + return {...result, index, length} + }, + object + ) + ) + + +const grouping = nested => either( + if_ok( + not_followed_by( + seq_select(1, [ + literal('('), + nested, + literal(')'), + ]), + literal('=>') + ), + ({value, ...node}) => ({ + ...node, + type: 'grouping', + children: [value], + }) + ), + primary, +) + +const array_element = either( + if_ok( + seq_select(1, [ + literal('...'), + cxt => expr(cxt), + ]), + ({value, ...node}) => ({...node, type: 'spread', not_evaluatable: true, children: [value]}) + ), + cxt => expr(cxt), +) + +const array_literal = + if_ok( + // TODO array literal can have several commas in a row, like that: + // `[,,,]` + // Each comma creates empty array element + list( + ['[', ']'], + array_element, + ), + ({value, ...node}) => ({...node, type: 'array_literal', children: value}) + ) + +const object_literal = + if_ok( + list( + ['{', '}'], + + either( + // Either object spread + if_ok( + seq_select(1, [ + literal('...'), + cxt => expr(cxt), + ]), + ({value, ...node}) => ({...node, type: 'spread', children: [value], not_evaluatable: true}) + ), + + // Or key-value pair + if_ok( + seq([ + + // key is one of + either( + + // Normalize key without quotes to quoted key + if_ok( + identifier, + iden => ({...iden, type: 'string_literal', value: '"' + iden.value + '"'}), + ), + + string_literal, + + // Computed property name + if_ok( + seq_select(1, [ + literal('['), + cxt => expr(cxt), + literal(']'), + ]), + ({value, ...node}) => ({...node, type: 'computed_property', not_evaluatable: true, children: [value]}) + ) + ), + literal(':'), + cxt => expr(cxt), + ]), + + ({value: [key, _colon, value], ...node}) => ( + {...node, type: 'key_value_pair', not_evaluatable: true, children: [key, value]} + ), + ), + + // Or shorthand property + identifier, + + ), + ), + + ({value, ...node}) => ( + ({...node, type: 'object_literal', children: value}) + ) + ) + +const function_expr = + if_ok( + seq([ + either( + // arguments inside braces + list_destructuring(['(', ')'], 'function_args'), + identifier, + ), + + literal('=>'), + + either( + // With curly braces + if_ok( + seq_select(1, [ + literal('{'), + cxt => parse_do(cxt), + literal('}'), + ]), + + ({value, ...node}) => ({...value, ...node}), + ), + + // Just expression + cxt => expr(cxt), + ) + ]), + + ({value, ...node}) => { + const [args, _, body] = value + const function_args = args.type == 'identifier' + ? { + ...args, + not_evaluatable: true, + type: 'function_args', + children: [args] + } + : // args.type == 'function_args' + { + ...args, + not_evaluatable: args.children.length == 0 + } + return { + ...node, + type: 'function_expr', + body, + children: [function_args, body] + } + }, + ) + +/* + new is actually is operator with same precedence as function call and member access. + So it allows to parse expressions like `new x.y.z()` as `(new x.y.z)()`. + + Currently we only allow new only in form of `new (args)` + or `new(expr)(args)`, where expr is closed in braces + + TODO implement complete new operator support +*/ +const new_expr = if_ok( + seq([ + literal('new'), + either( + identifier, + if_ok( + seq_select(1, [ + literal('('), + cxt => expr(cxt), + literal(')'), + ]), + ({value}) => value, + ), + ), + list( + ['(', ')'], + array_element, + ) + ]), + ({value, ...node}) => ({ + ...node, + type: 'new', + children: [value[1], ...value[2].value], + }) +) + +const primary = if_fail( + either( + new_expr, + object_literal, + array_literal, + function_expr, + + // not_followed_by for better error messages + // y => { } must parse as function expr, not as identifier `y` + // followed by `=>` + not_followed_by(builtin_identifier, literal('=>')), + not_followed_by(identifier, literal('=>')), + + string_literal, + by_type('backtick_string'), + by_type('number'), + ), + 'expected expression' +) + +// operator precedence https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence +// TODO unary minus +// TODO instanceof +const expr = + [ + grouping, + function_call_or_member_access, + unary('!'), + unary('typeof'), + binary(['**']), + binary(['*','/','%']), + binary(['+','-']), + binary(['<','>','<=','>=']), + binary(['===', '==', '!==', '!=']), + binary(['&&']), + binary(['||', '??']), + ternary, + ].reduce( + (prev, next) => next(prev), + cxt => expr(cxt) + ) + +// TODO multiple decls, like `const x = 1, y = 2` +const const_statement = + if_ok( + seq([ + literal('const'), + destructuring, + literal('='), + expr, + ]), + ({value, ...node}) => { + const [_const, identifier, _eq, expr] = value + return { + ...node, + type: 'const', + name: identifier.value, + children: [identifier, expr], + } + } + ) + +const let_declaration = if_ok( + seq_select(1, [ + literal('let'), + comma_separated_1(identifier), + ]), + ({value, ...node}) => ({ + ...node, + type: 'let', + children: value.value, + names: value.value.map(n => n.value), + }) +) + +const assignment = if_ok( + seq([ + // TODO object assignment required braces, like ({foo} = {foo: 1}) + destructuring, + literal('='), + expr, + ]), + ({value, ...node}) => { + const [identifier, _eq, expr] = value + return { + ...node, + type: 'assignment', + name: identifier.value, + children: [identifier, expr], + } + }, +) + +const return_statement = + if_ok( + seq_select(1, [ + + // We forbid bare return statement + // TODO implement bare return statement compatible with ASI + // see https://riptutorial.com/javascript/example/15248/rules-of-automatic-semicolon-insertion + // see ASI_restrited unit test + not_followed_by( + literal('return'), + newline, + ), + expr, + ]), + ({value, ...node}) => ({ + ...node, + type: 'return', + children: [value], + }) + ) + +const if_branch = if_ok( + seq_select(1, [ + literal('{'), + cxt => parse_do(cxt), + literal('}'), + ]), + ({value, ...node}) => ({...value, ...node}) +) + +const if_statement = + // TODO allow single statement without curly braces? + if_ok( + seq([ + literal('if'), + literal('('), + expr, + literal(')'), + if_branch, + if_ok_then( + optional(literal('else')), + value => value == null + ? ret(null) + : either( + if_branch, + + // else if + cxt => if_statement(cxt), + ) + ) + ]), + + ({value, ...node}) => { + const cond = value[2] + const left = value[4] + const else_ = value[5] + if(else_ == null) { + return { + ...node, + type: 'if', + children: [cond, left], + } + } else { + return { + ...node, + type: 'if', + children: [cond, left, else_], + } + } + }, + ) + +const throw_statement = if_ok( + seq_select(1, [ + not_followed_by( + literal('throw'), + newline, + ), + expr, + ]), + ({value, ...node}) => ({ + ...node, + type: 'throw', + children: [value], + }) +) + +const import_statement = + // TODO import *, import as + if_ok( + seq([ + literal('import'), + list( + ['{', '}'], + identifier, + ), + literal('from'), + string_literal + ]), + ({value: [_0, identifiers, _2, module], ...node}) => ({ + ...node, + not_evaluatable: true, + type: 'import', + // TODO refactor hanlding of string literals. Drop quotes from value and + // fix codegen for string_literal + module: module.value.slice(1, module.value.length - 1), + children: identifiers.value, + }) + ) + +const export_statement = + if_ok( + seq_select(1, [ + literal('export'), + // TODO export let statement, export default, etc. Or not allow + // let statement because export let cannot be compiled properly? + const_statement, + ]), + ({value, ...node}) => ({ + ...node, + not_evaluatable: true, + type: 'export', + children: [value], + }) + ) + + +const do_statement = either( + const_statement, + let_declaration, + assignment, + if_statement, + throw_statement, + return_statement, +) + +const module_statement = either( + const_statement, + let_declaration, + assignment, + if_statement, + throw_statement, + import_statement, + export_statement, +) + +const parse_do_or_module = (is_module) => + if_ok( + repeat_until( + either( + // allows to repeat semicolons + literal(';'), + + // expr or statement + if_ok( + seq_select(0, [ + either( + is_module + ? module_statement + : do_statement, + expr, + ), + if_fail( + either( + literal(';'), + // Parse newline as semicolon (automatic semicolon insertion) + newline, + eof, + lookahead(literal('}')), + ), + 'unexpected token' + ) + ]), + // TODO fix that here we drop ';' from string. use node.length and node.index + node => node.value + ) + ), + + // Until + either( + eof, + lookahead(literal('}')), + ), + ), + ({value, ...node}) => ({ + ...node, + type: 'do', + children: value + // drop semicolons + .filter(n => n.type != 'punctuation'), + }) + ) + +const parse_do = parse_do_or_module(false) + +const program = (is_module) => either( + // either empty program + if_ok(eof, _ => ({type: 'do', index: 0, length: 0, children: []})), + + is_module ? parse_do_or_module(true) : parse_do +) + +const finished_program = (is_module) => finished(program(is_module)) + +const update_children_not_rec = (node, children = node.children) => { + if(node.type == 'object_literal'){ + return { ...node, elements: children} + } else if(node.type == 'array_literal'){ + return {...node, elements: children} + } else if([ + 'identifier', + 'number', + 'string_literal', + 'builtin_identifier', + 'backtick_string', + ].includes(node.type)) + { + return node + } else if(node.type == 'function_expr'){ + return {...node, + function_args: children[0], + body: children[children.length - 1], + } + } else if(node.type == 'ternary'){ + return {...node, + cond: children[0], + branches: children.slice(1), + } + } else if(node.type == 'const'){ + return {...node, + name_node: children[0], + expr: children[1], + is_statement: true, + } + } else if(node.type == 'let'){ + return {...node, + name_node: children, + is_statement: true, + } + } else if(node.type == 'assignment'){ + return {...node, + name_node: children[0], + expr: children[1], + is_statement: true, + } + } else if(node.type == 'do'){ + return {...node, + stmts: children, + is_statement: true, + } + } else if(node.type == 'unary') { + return {...node, + expr: children[0], + } + } else if(node.type == 'binary'){ + return {...node, + args: children, + } + } else if(node.type == 'member_access'){ + return {...node, + object: children[0], + property: children[1], + } + } else if(node.type == 'function_call'){ + return {...node, + fn: children[0], + args: children[1], + } + } else if(node.type == 'call_args') { + return node + } else if(node.type == 'member_access') { + return {...node, + object: children[0], + property: children[1], + } + } else if(node.type == 'spread') { + return {...node, + expr: children[0], + } + } else if(node.type == 'key_value_pair') { + return {...node, + key: children[0], + value: children[1], + } + } else if(node.type == 'computed_property') { + return {...node, + expr: children[0] + } + } else if(node.type == 'new') { + return {...node, constructor: children[0], args: children.slice(1)} + } else if(node.type == 'grouping') { + return {...node, expr: children[0]} + } else if(node.type == 'return') { + return {...node, + expr: children[0], + is_statement: true, + } + } else if(node.type == 'throw') { + return {...node, + expr: children[0], + is_statement: true, + } + } else if(node.type == 'if'){ + return {...node, + cond: children[0], + branches: children.slice(1), + is_statement: true, + } + } else if( + ['array_destructuring', 'object_destructuring', 'function_args'] + .includes(node.type) + ) { + return {...node, + elements: children, + } + } else if(node.type == 'destructuring_default') { + return {...node, + name_node: children[0], + expr: children[1], + } + } else if(node.type == 'destructuring_rest') { + return {...node, + name_node: children[0], + } + } else if(node.type == 'destructuring_pair') { + return {...node, + key: children[0], + value: children[1], + } + } else if(node.type == 'import') { + return {...node, + imports: children, + is_statement: true, + } + } else if(node.type == 'export') { + return {...node, + binding: children[0], + is_statement: true, + } + } else { + console.error('invalid node', node) + throw new Error('unknown node type ' + node.type) + } +} + +const update_children = node => { + if(Array.isArray(node)) { + return node.map(update_children) + } else { + const children = node.children == null + ? null + : update_children(node.children); + + return {...update_children_not_rec(node, children), children} + } +} + +export const parse = (str, is_module = false, module_name) => { + + // Add string to node for debugging + // TODO remove, only need for debug + const populate_string = node => { + if( + (node.index == null || node.length == null || isNaN(node.index) || isNaN(node.length)) + ) { + console.error(node) + throw new Error('invalid node') + } else { + const withstring = {...node, string: str.slice(node.index, node.index + node.length)} + return withstring.children == null + ? withstring + : {...withstring, children: withstring.children.map(populate_string)} + } + } + + const {tokens, ok, index, message} = tokenize_js(str) + if(!ok) { + return {ok: false, problems: [{message, index}]} + } else { + const significant_tokens = tokens.filter(token => + token.type != 'whitespace' && token.type != 'comment' + ) + + const cxt = { + tokens: significant_tokens, + current: 0, + // TODO remove, str here is only for debug (see `log` function) + str + } + const result = finished_program(is_module)(cxt) + if(!result.ok) { + const token = current(result.cxt) + const index = token == null ? str.length - 1 : token.index + return { + ok: false, + problems: [{ + message: result.error, + token, + index, + // Only for debugging + errorlocation: str.slice(index, 20) + }], + } + } else { + const {node, undeclared} = find_definitions(update_children(result.value), null, null, module_name) + if(undeclared.length != 0){ + return { + ok: false, + problems: undeclared.map(u => ({ + index: u.index, + length: u.length, + message: 'undeclared identifier: ' + u.value, + })) + } + } else { + // TODO remove populate_string (it is left for debug) + // + // call update_children, becase find_definitions adds `definition` + // property to some nodes, and children no more equal to other properties + // of nodes by idenitity, which somehow breaks code (i dont remember how + // exactly). Refactor it? + const fixed_node = update_children(populate_string(node)) + const problems = analyze(fixed_node) + if(problems.length != 0) { + return {ok: false, problems} + } else { + return {ok: true, node: fixed_node} + } + } + } + } +} + +export const print_debug_node = node => { + const do_print_debug_node = node => { + const {index, length, string, type, children} = node + const res = {index, length, string, type} + if(children == null) { + return res + } else { + const next_children = children.map(do_print_debug_node) + return {...res, children: next_children} + } + } + return stringify(do_print_debug_node(node)) +} + +const do_load_modules = (module_names, loader, already_loaded) => { + const parsed = module_names + .filter(module_name => already_loaded[module_name] == null) + .map(module_name => { + const m = loader(module_name) + if(m == null) { + return [module_name, {ok: false, problems: [{is_load_error: true}]}] + } else if(typeof(m) == 'object' && m.ok != null) { + // Allows cache parse result + return [module_name, m] + } else if(typeof(m) == 'string') { + return [module_name, parse(m, true, module_name)] + } else { + throw new Error('illegal state') + } + }) + + const {ok, problems} = parsed.reduce( + ({ok, problems}, [module_name, parsed]) => ({ + ok: ok && parsed.ok, + problems: [ + ...problems, + ...(parsed.problems ?? []).map(p => ({...p, module: module_name})) + ], + }), + {ok: true, problems: []} + ) + + const cache = Object.fromEntries(parsed) + + if(!ok) { + return {ok: false, problems, cache} + } + + const modules = Object.fromEntries( + parsed.map(([module_name, parsed]) => + [module_name, parsed.node] + ) + ) + + const deps = uniq( + Object.values(modules) + .map(m => Object.keys(collect_imports(m))) + .flat() + ) + + if(deps.length == 0) { + return {ok: true, modules, cache} + } + + // TODO when refactor this function to async, do not forget that different + // deps can be loaded independently. So dont just put `await Promise.all(` + // here + const loaded_deps = do_load_modules(deps, loader, {...already_loaded, ...modules}) + if(loaded_deps.ok) { + return { + ok: true, + modules: {...modules, ...loaded_deps.modules}, + cache: {...cache, ...loaded_deps.cache}, + } + } else { + // Match modules failed to load with import statements and generate + // problems for this import statements + + const failed_to_load = loaded_deps.problems + .filter(p => p.is_load_error) + .map(p => p.module) + + const load_problems = Object.entries(modules) + .map(([module, node]) => + node.children + .filter(n => n.type == 'import') + .map(i => [module, i]) + ) + .flat() + .filter(([module, i]) => + failed_to_load.find(m => m == i.full_import_path) != null + ) + .map(([module, i]) => ({ + message: 'failed lo load module ' + i.full_import_path, + module, + index: i.index + })) + + return { + ok: false, + problems: [ + ...load_problems, + ...loaded_deps.problems.filter(p => !p.is_load_error), + ], + cache: {...cache, ...loaded_deps.cache}, + } + } +} + +export const load_modules = (entry_module, loader) => { + // TODO check_imports. detect cycles while modules are loading, in + // do_load_modules + + const result = do_load_modules([entry_module], loader, {}) + if(!result.ok) { + return result + } else { + return {...result, sorted: topsort_modules(result.modules)} + } +} diff --git a/src/reserved.js b/src/reserved.js new file mode 100644 index 0000000..2c76d9f --- /dev/null +++ b/src/reserved.js @@ -0,0 +1,48 @@ +// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#keywords + +export const reserved = [ +'break', +'case', +'catch', +'class', +'const', +'continue', +'debugger', +'default', +'delete', +'do', +'else', +'export', +'extends', +'finally', +'for', +'function', +'if', +'import', +'in', +'instanceof', +'new', +'return', +'super', +'switch', +'this', +'throw', +'try', +'typeof', +'var', +'void', +'while', +'with', +'yield', +'enum', +'implements', +'interface', +'let', +'package', +'private', +'protected', +'public', +'static', +'yield', +'await', +] diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..a16e0b7 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,95 @@ +export const findLast = new Function('arr', 'pred', ` + for(let i = arr.length - 1; i >= 0; i--) { + if(pred(arr[i])) { + return arr[i] + } + } +`) + +export const set_push = (x,y) => new Set([...x, y]) + +export const set_union = (x,y) => new Set([...x, ...y]) + +export const set_diff = (x,y) => { + return new Set([...x].filter(el => !y.has(el))) +} + +export const map_object = (obj, mapper) => Object.fromEntries( + Object.entries(obj).map(([k, v]) => [k, mapper(k,v)]) +) + +export const filter_object = (obj, pred) => Object.fromEntries( + Object.entries(obj).filter(([k, v]) => pred(k,v)) +) + +// https://bit.cloud/ramda/ramda/map-accum/~code +export const map_accum = new Function('fn', 'acc', 'arr', ` + let idx = 0; + const len = arr.length; + const result = []; + let tuple = [acc]; + while (idx < len) { + tuple = fn(tuple[0], arr[idx], idx); + result[idx] = tuple[1]; + idx += 1; + } + return [tuple[0], result]; +`) + +export const map_find = (arr, mapper) => arr.reduce( + (result, curr, i) => result ?? mapper(curr, i), + null +) + +export const pick_keys = (obj, keys) => { + return Object.fromEntries( + Object.entries(obj).filter(([k,v]) => keys.includes(k)) + ) +} + +export const stringify = val => JSON.stringify(val, null, 2) + +export const zip = (x,y) => { + if(x.length != y.length){ + throw new Error('zipped arrays must have same length') + } else { + return x.map((el, i) => [el, y[i]]) + } +} + +export const uniq = arr => [...new Set(arr)] + +// TODO remove +/* +function object_diff(a,b){ + function do_object_diff(a,b, context=[]) { + if(a == b){ + return + } + if(a == null && b == null){ + return + } + if(typeof(a) != 'object' || typeof(b) != 'object'){ + throw new Error(`not an object ${a} ${b}`) + } + for(let key in a) { + if(b[key] == null) { + throw new Error(`missing ${key} in right object ${context.join('.')}`) + } + } + for(let key in b) { + if(a[key] == null) { + throw new Error(`missing ${key} in left object ${context.join('.')}`) + } + do_object_diff(a[key], b[key], context.concat([key])) + } + } + try { + do_object_diff(a,b) + } catch(e){ + return e.message + } +} +*/ + + diff --git a/test/run.js b/test/run.js new file mode 100644 index 0000000..a59bb7c --- /dev/null +++ b/test/run.js @@ -0,0 +1,4 @@ +import {tests} from './test.js' +import {run} from './utils.js' + +run(tests) diff --git a/test/self_hosted_test.js b/test/self_hosted_test.js new file mode 100644 index 0000000..001d3c2 --- /dev/null +++ b/test/self_hosted_test.js @@ -0,0 +1,82 @@ +import fs from 'fs' + +import {load_modules} from '../src/parse_js.js' +import {eval_modules, eval_frame} from '../src/eval.js' + +import { + assert_equal, + run, + stringify, + test, +} from './utils.js' + +const entry = ` + import {parse, load_modules} from './src/parse_js.js'; + + import {get_initial_state} from './src/cmd.js'; + //console.time('p'); + //const parsed = parse(globalThis.module_cache['./src/parse_js.js']); + //console.timeEnd('p'); + //const parsed = parse('1'); + + const loader = module => globalThis.module_cache[module]; + console.time('p2'); + load_modules('src/parse_js.js', (m) => { + return loader(m) + + }); + console.timeEnd('p2') + //import {} from './test/test.js' +` + +globalThis.module_cache = {} + +const load_module = (dir, module) => { + return (globalThis.module_cache[module] = fs.readFileSync(dir + module, 'utf8')) +} +const loader = module => { + return module == '' + ? entry + : load_module('./', module) +} + +run([ + test('self-hosted', () => { + //console.time('p0') + const parsed = load_modules('', loader) + //log('cache', Object.keys(globalThis.module_cache)) + //console.log('p', parsed) + //console.timeEnd('p0') + if(!parsed.ok) { + const p = parsed.problems[0] + console.error('FAIL', p.index, p.message, p.module) + console.log(loader(p.module).slice(p.index, p.index + 100)) + } else { + assert_equal(parsed.ok, true) + console.time('eval') + const result = eval_modules(parsed.modules, parsed.sorted).calltree + console.timeEnd('eval') + + /* TODO remove + + const count_nodes = node => node.children == null + ? 1 + : 1 + node.children.reduce( + (total, c) => total + count_nodes(c), + 0, + ) + console.log( + Object.entries(result) + .map(([k,v]) => count_nodes(v.calls)) + .reduce((total, c) => total +c) + ) + */ + ///const frame = eval_frame(result[''].calls, result) + ///log('f', frame.children[frame.children.length - 1]) + ///assert_equal( + /// frame.children[frame.children.length - 1].result.value.value, + /// 1 + ///) + } + }) +]) diff --git a/test/test.js b/test/test.js new file mode 100644 index 0000000..d3afac9 --- /dev/null +++ b/test/test.js @@ -0,0 +1,1998 @@ +import {find_leaf, ancestry, find_node} from '../src/ast_utils.js' +import {parse, print_debug_node} from '../src/parse_js.js' +import {eval_tree, eval_frame, eval_modules} from '../src/eval.js' +import {COMMANDS, get_initial_state} from '../src/cmd.js' +import {root_calltree_node, active_frame, pp_calltree} from '../src/calltree.js' +import {color_file} from '../src/color.js' +import { + test, + test_only, + assert_equal, + stringify, + assert_code_evals_to, + assert_code_error, + parse_modules, + test_initial_state, + print_debug_ct_node, +} from './utils.js' + +export const tests = [ + + test('invalid token in the beginning', () => { + const result = parse('# import') + assert_equal(result, { + ok: false, + problems: [ { message: 'unexpected lexical token', index: 0 } ] + }) + }), + + test('invalid token in the middle', () => { + const result = parse(': # import') + assert_equal(result, { + ok: false, + problems: [ { message: 'unexpected lexical token', index: 2 } ] + }) + }), + + test('invalid token in the end', () => { + const result = parse(': ^') + assert_equal(result, { + ok: false, + problems: [ { message: 'unexpected lexical token', index: 2 } ] + }) + }), + + test('empty program', () => { + const parse_result = parse('') + assert_equal(parse_result.ok, true) + const tree = eval_tree(parse_result.node) + const frame = eval_frame(tree) + assert_equal(frame.children, []) + assert_equal(frame.result, {ok: true}) + }), + + test('empty if branch', () => { + const r = parse(` + if(true) { + } else { + } + `) + assert_equal(r.ok, true) + }), + + test('Must be finished by eof', () => { + const result = parse('}') + assert_equal(result.ok, false) + }), + + test('Only semicolons', () => { + const parse_result = parse(';;;;') + assert_equal(parse_result.ok, true) + const tree = eval_tree(parse_result.node) + const frame = eval_frame(tree) + assert_equal(frame.children, []) + assert_equal(frame.result, {ok: true}) + }), + + test('Comments', () => { + assert_code_evals_to(` + /*Qux + + */ + // Foo + 1 //Bar + /* Baz */ + + `, + 1 + ) + }), + + test('backtick_string', () => { + assert_code_evals_to( + 'const x = `b`; `a${x}a`', + 'aba', + ) + }), + + test('Simple expression', () => { + return assert_code_evals_to('1+1;', 2) + }), + + test('Logical not', () => { + return assert_code_evals_to('!false', true) + }), + + test('More complex expression', () => { + assert_code_evals_to( + ` + const plusone = x => x + 1; + plusone(3); + `, + 4 + ) + }), + + test('closure', () => { + const parsed = parse( + ` + const x = 1 + const y = () => x; + y() + ` + ) + const tree = eval_tree(parsed.node) + const frame = eval_frame(tree.children[0]) + assert_equal(frame.children[1].result.value, 1) + }), + + test('member access', () => { + assert_code_evals_to( + 'const foo = {bar: {baz: 2}};foo.bar.baz;', + 2 + ) + }), + + test('optional chaining', () => { + assert_code_evals_to(`null?.foo`, undefined) + assert_code_evals_to(`{foo:1}?.foo`, 1) + }), + + test('optional chaining computed', () => { + assert_code_evals_to(`null?.['foo']`, undefined) + assert_code_evals_to(`{foo: 1}?.['foo']`, 1) + }), + + test('factorial', () => { + assert_code_evals_to( + ` + const fac = x => x == 0 ? 1 : x * fac(x - 1); + fac(10); + `, + 3628800 + ) + }), + + test('sort_1', () => { + assert_code_evals_to( + ` + const sort = x => x.length == 0 + ? [] + : [ + ...sort(x.slice(1).filter(y => y < x[0])), + x[0], + ...sort(x.slice(1).filter(y => x[0] <= y)), + ]; + sort([4, 7, 8, 9, 15, 1, 3, 2, 1]); + `, + [1, 1, 2, 3, 4, 7, 8, 9, 15] + ) + }), + + test('sort_2', () => { + assert_code_evals_to( + ` + const sort = x => { + return x.length == 0 + ? [] + : [ + ...sort(x.slice(1).filter(y => y < x[0])), + x[0], + ...sort(x.slice(1).filter(y => x[0] <= y)), + ] + }; + sort([4, 7, 8, 9, 15, 1, 3, 2, 1]); + `, + [1, 1, 2, 3, 4, 7, 8, 9, 15] + ) + }), + + test('chaining', () => { + assert_code_evals_to( + 'const foo = () => ({bar: 42}); foo().bar;', + 42 + ) + }), + + test('logic ops', () => { + assert_code_evals_to( + ` + const foo = false; + const bar = true; + const baz = false; + const foo2 = false; + foo || bar && baz || (foo2); + `, + false + ) + }), + + test('strict eq', () => { + assert_code_evals_to( + `null === undefined`, + false + ) + }), + + test('ternary', () => { + assert_code_evals_to(`true ? 1 : 2;`, 1) + }), + + test('nested ternary', () => { + assert_code_evals_to(`false ? 0 : true ? 1 : 2`, 1) + }), + + test('complex expression', () => { + assert_code_evals_to('(x => 2*x)(({foo: 1}).foo + 2 + 3)*10;', 120) + }), + + test('function_call spread', () => { + assert_code_evals_to( + ` + const test = (...args) => args[0] + args[1]; + const data = [1,2]; + const result = test(...data); + result + `, + 3 + ) + }), + + test('destructuring array', () => { + assert_code_evals_to( + ` + const [a,b=2,...c] = [1, undefined, 3,4]; + [a,b,...c]; + `, + [1,2,3,4] + ) + }), + + test('destructuring object', () => { + assert_code_evals_to( + ` + const {a, b: [b], ...c} = {a: 1, b: [2], c: 3, d: 4}; + [a,b,c]; + `, + [1, 2, {c:3, d: 4}] + ) + }), + + test('destructuring function arguments', () => { + assert_code_evals_to( + ` + const test = (first, ...others) => [first, others]; + test(1,2,3); + `, + [1, [2,3]] + ) + }), + + test('else if', () => { + const code = ` + let x + if(false) { + let x + x = 0 + } else if(true) { + x = 1 + } else { + x = 2 + }; + x + ` + const parse_result = parse(code) + const assignment = find_leaf( + parse_result.node, + code.indexOf('x = 0') + ) + assert_code_evals_to( + code, + 1 + ) + }), + + test('if without else', () => { + assert_code_evals_to( + ` + let x + if(true) { + x = 1 + } + if(false) { + throw new Error() + } + x + `, + 1 + ) + }), + + test('out of order decl', () => { + const code = + ` + const y = () => x; + const x = 1; + y(); + ` + const parsed = parse(code) + assert_equal(parsed.ok, true) + const tree = eval_tree(parsed.node) + assert_equal(tree.children[0].value, 1) + }), + + test('nested closure', () => { + const code = + ` + const x = () => () => y; + x(); + const y = 1; + ` + const parsed = parse(code) + assert_equal(parsed.ok, true) + const tree = eval_tree(parsed.node) + assert_equal(tree.ok, true) + // TODO assert + }), + + test('Simple expression ASI', () => { + return assert_code_evals_to('1+1', 2) + }), + + test('Closing bracket ASI', () => { + return assert_code_evals_to( + ` + let x + if(true) { + x = 1 + } else { + x = 2 + }; + x + `, + 1 + ) + }), + + test('ASI_1', () => { + const parse_result = parse(` + 1 + const y = 2; + `) + assert_equal(parse_result.ok, true) + assert_equal( + parse_result.node.children.map(c => c.type), + ['number', 'const'] + ) + }), + + test('ASI_2', () => { + const parse_result = parse(` + 1 + 2 + `) + assert_equal(parse_result.ok, true) + assert_equal( + parse_result.node.children.map(c => c.type), + ['number', 'number'] + ) + }), + + test('ASI_restrited', () => { + // Currently we forbid bare return statement, TODO + assert_equal( + parse(` + return + 1 + `).ok, + false + ) + assert_equal( + parse(` + throw + 1 + `).ok, + false + ) + }), + + test('throw', () => { + assert_code_error(` + const x = () => { throw 1 }; + x() + `, + 1 + ) + }), + + test('new', () => { + assert_code_evals_to('new Error("test").message', 'test') + }), + + test('new constructor expr', () => { + assert_code_evals_to(` + const x = {Error}; + new (x.Error)('test').message + `, 'test') + }), + + test('method chaining', () => { + assert_code_evals_to( + ` + const x = [1,2,3,4]; + x.slice(1).slice(1).slice(1); + `, + [4] + ) + }), + + test('undefined is not a function', () => { + const code = + ` + const x = () => null(); + const unreachable = () => 1 + x(); + ` + const s1 = test_initial_state(code) + // TODO fix error messages + assert_equal( + root_calltree_node(s1).error.message, + "Cannot read property 'apply' of null" + ) + }), + + test('native throws', () => { + const s1 = test_initial_state( + ` + const throws = new Function('throw new Error("sorry")') + throws() + ` + ) + assert_equal( + root_calltree_node(s1).error.message, + "sorry" + ) + }), + + test('function name', () => { + // TODO + /* + assert_code_evals_to( + ` + const x = () => null(); + x.name; + `, + 'x', + ) + */ + }), + + test('record call chain', () => { + const code = ` + const x = () => ({ + y: () => 1, + }) + x().y() + ` + const s1 = test_initial_state(code) + assert_equal(s1.current_calltree_node.children.length, 2) + }), + + test('record native call chain', () => { + const code = ` Object.entries({}).map(() => null) ` + const s1 = test_initial_state(code) + assert_equal(s1.current_calltree_node.children.length, 2) + }), + + test('eval_frame logical short circuit', () => { + assert_code_evals_to( + `true || false`, + true, + ) + }), + + test('eval_frame array_literal', () => { + assert_code_evals_to( + `[1,2,3,...[4,5]];`, + [1,2,3,4,5] + ) + }), + + test('eval_frame object_literal', () => { + assert_code_evals_to( + `{foo: 1, ...{bar: 2}, ['baz']: 3};`, + {foo:1, bar:2, baz: 3} + ) + }), + + test('eval_frame ternary', () => { + assert_code_evals_to(`false ? 1 : 2`, 2) + }), + + test('eval_frame unary', () => { + assert_code_evals_to(`! false`, true) + }), + + test('typeof', () => { + assert_code_evals_to('typeof 1', 'number') + }), + + test('eval_frame unary minus', () => { + // TODO + //assert_code_evals_to(`-(1)`, -1) + }), + + test('eval_frame binary', () => { + const parsed = parse(` + 1 + 1 + `) + const tree = eval_tree(parsed.node) + assert_equal(eval_frame(tree).children[0].result.value, 2) + }), + + test('eval_frame grouping', () => { + const parsed = parse('(1+1)') + const tree = eval_tree(parsed.node) + assert_equal(eval_frame(tree).children[0].result.value, 2) + }), + + test('eval_frame member_access', () => { + const parsed = parse('{foo: "bar"}["foo"]') + const tree = eval_tree(parsed.node) + assert_equal(eval_frame(tree).children[0].result.value, 'bar') + }), + + test('eval_frame new', () => { + const parsed = parse('new Error("foobar")') + const tree = eval_tree(parsed.node) + assert_equal(eval_frame(tree).children[0].result.value.message, 'foobar') + }), + + test('eval_frame function_call', () => { + const parsed = parse(` + const x = () => 1; + 2 * x(); + `) + const tree = eval_tree(parsed.node) + assert_equal(eval_frame(tree).children[1].result.value, 2) + }), + + test('eval_frame function_body_expr', () => { + const parsed = parse(` + const x = y => y; + x(2); + `) + const tree = eval_tree(parsed.node) + assert_equal(eval_frame(tree.children[0]).children[1].result, {ok: true, value: 2}) + }), + + test('eval_frame function_body_do', () => { + const parsed = parse(` + const x = y => { + return y; + const z = 1; + }; + x(2); + `) + const tree = eval_tree(parsed.node) + const frame = eval_frame(tree.children[0]) + const ret = frame.children[1].children[0] + const z_after_ret = frame.children[1].children[1] + assert_equal(ret.result, {ok: true}) + assert_equal(z_after_ret.result, null) + }), + + test('eval_frame if', () => { + const parsed = parse(` + if(1) { + const x = 1; + } else { + const x = 1; + } + `) + const tree = eval_tree(parsed.node) + const frame = eval_frame(tree) + const _if = frame.children[0] + assert_equal(_if.children[0].result, {ok: true, value: 1}) + assert_equal(_if.children[1].result, {ok: true}) + assert_equal(_if.children[2].result, null) + }), + + test('eval_frame if without else', () => { + const parsed = parse(` + if(1) { + const x = 1; + } + `) + const tree = eval_tree(parsed.node) + const frame = eval_frame(tree) + const _if = frame.children[0] + assert_equal(_if.children.length, 2) + assert_equal(_if.children[0].result, {ok: true, value: 1}) + assert_equal(_if.children[1].result, {ok: true}) + }), + + test('eval_frame modules', () => { + const parsed = parse_modules( + 'b', + { + 'a' : 'export const a = 1;', + 'b' : 'import {a} from "a"; export const b = a*2;', + } + ) + const calltree = eval_modules(parsed.modules, parsed.sorted).calltree; + const frame = eval_frame(calltree.b.calls, calltree) + assert_equal(frame.children[1].result, {ok: true}) + assert_equal(frame.children[1].children[0].children[1].result, {ok: true, value: 2}) + }), + + test('eval_frame error', () => { + const parsed = parse(` + const x = ({a}) => 0; + x(null); + `) + const tree = eval_tree(parsed.node) + const frame = eval_frame(tree.children[0]) + assert_equal(frame.result, {ok: false}) + }), + + test('eval_frame binary &&', () => { + const parsed = parse(` + const x = () => 1; + const y = () => 2; + false && x(); + y(); + `) + const tree = eval_tree(parsed.node) + const frame = eval_frame(tree) + assert_equal(frame.children[3].result.value, 2) + }), + + test('eval_frame binary ||', () => { + const parsed = parse(` + const x = () => 1; + const y = () => 2; + true || x(); + y(); + `) + const tree = eval_tree(parsed.node) + const frame = eval_frame(tree) + assert_equal(frame.children[3].result.value, 2) + }), + + test('eval_frame binary ??', () => { + const parsed = parse(` + const x = () => 1; + const y = () => 2; + 1 ?? x(); + y(); + `) + const tree = eval_tree(parsed.node) + const frame = eval_frame(tree) + assert_equal(frame.children[3].result.value, 2) + }), + + test('eval_frame null call', () => { + const parsed = parse(`null()`) + const tree = eval_tree(parsed.node) + const frame = eval_frame(tree) + assert_equal(frame.children[0].result.ok, false) + }), + + test('eval_frame destructuring args', () => { + const parsed = parse(` + const x = (...a) => a; + x(1,2,3); + `) + const tree = eval_tree(parsed.node) + const frame = eval_frame(tree.children[0]) + assert_equal(frame.children[0].children[0].children[0].result.value, [1,2,3]) + }), + + test('module not found', () => { + const parsed = parse_modules( + 'a', + { + 'a' : 'import {b} from "b"; import {c} from "c"', + 'b' : 'for' + } + ) + assert_equal(parsed.ok, false) + assert_equal( + parsed.problems.map(p => ({message: p.message, index: p.index, module: p.module})), + [ + { + message: "failed lo load module c", + index: 21, + module: "a", + }, + { + message: 'expected expression', + index: 0, + module: "b" + } + ] + ) + }), + + test('module parse cache', () => { + const s = test_initial_state({ + '' : `import {b} from 'b'`, + 'b' : `import {c} from 'c'`, + 'c' : `export const c = 1`, + }) + // change module '' + const s2 = COMMANDS.input(s, 'import {c} from "c"', 0) + // TODO assert that module 'c' was loaded from cache + }), + + test('modules', () => { + const parsed = parse_modules( + 'd', + { + 'a' : 'export const a = 1;', + 'b' : 'import {a} from "a"; export const b = a*2;', + 'c1' : 'import {b} from "b"; import {a} from "a"; export const c1 = b*2;', + 'c2' : 'import {b} from "b"; import {a} from "a"; export const c2 = b*2;', + 'd' : 'import {c1} from "c1"; import {c2} from "c2"; export const d = c1 + c2;', + } + ) + assert_equal(parsed.sorted, ['a', 'b', 'c1', 'c2', 'd']) + const result = eval_modules(parsed.modules, parsed.sorted).calltree; + assert_equal(result.d.exports.d, 8) + }), + + test('module loaded just once', () => { + /* + root -> intermediate1 -> leaf + root -> intermediate2 -> leaf + */ + const parsed = parse_modules( + 'root', + { + 'root' : ` + import {l1} from "intermediate1"; + import {l2} from "intermediate2"; + export const is_eq = l1 == l2; + `, + 'intermediate1' : 'import {leaf} from "leaf"; export const l1 = leaf;', + 'intermediate2' : 'import {leaf} from "leaf"; export const l2 = leaf;', + 'leaf' : 'export const leaf = {}', + } + ) + const mods = eval_modules(parsed.modules, parsed.sorted).calltree + // Check that the same symbol improted through different paths gives the + // same result + assert_equal(mods.root.exports.is_eq, true) + }), + + // Static analysis + + test('undeclared', () => { + const undeclared_test = ` + const foo = 1; + const bar = baz => qux(foo, bar, baz, quux); + const qux = 3; + ` + const result = parse(undeclared_test) + assert_equal(result.problems.length, 1) + assert_equal(result.problems[0].message, 'undeclared identifier: quux') + }), + + test('name reuse', () => { + assert_code_evals_to( + ` + const f = f => f; + f(x => x + 1)(10); + `, + 11 + ) + }), + + test('assign to itself', () => { + const code = ` + const x = x; + ` + return assert_equal(parse(code).problems[0].message, 'undeclared identifier: x') + }), + + /* + TODO use before assignment + test('no use before assignment', () => { + const test = ` + let x; + x; + ` + return assert_equal(parse(test).problems[0].message, 'undeclared identifier: x') + }), + */ + + test('goto_definition', () => { + const entry = ` + import {x} from 'a' + const y = x*x + ` + const a = `export const x = 2` + const s = test_initial_state({ + '' : entry, + a, + }) + const y_result = COMMANDS.goto_definition(s, entry.indexOf('y')) + assert_equal(y_result.effects, null) + + const x_result_1 = COMMANDS.goto_definition(s, entry.indexOf('x*x')) + assert_equal(x_result_1.state.current_module, '') + assert_equal( + x_result_1.effects, + {type: 'set_caret_position', args: [entry.indexOf('x')]} + ) + + const x_result_2 = COMMANDS.goto_definition(s, entry.indexOf('x')) + assert_equal(x_result_2.state.current_module, 'a') + assert_equal( + x_result_2.effects, + {type: 'set_caret_position', args: [a.indexOf('x = 2')]} + ) + + }), + + test('assignment', () => { + const frame = assert_code_evals_to( + ` + let x; + x = 1; + x; + `, + 1 + ) + // assert let has result + assert_equal(frame.children[0].result, {ok: true}) + // assert x value + assert_equal(frame.children[0].children[0].result, {ok: true, value: 1}) + }), + + test('block scoping', () => { + assert_code_evals_to( + ` + const x = 10 + let y + if(true) { + const x = 1 + y = x + } else { + const x = 2 + y = x + } + y + `, + 1 + ) + }), + + test('block scoping shadow', () => { + assert_code_evals_to( + ` + let y + y = 1 + if(true) { + let y + y = 2 + } + y + `, + 1 + ) + }), + + test('step_into', () => { + const code = ` + const x = () => 1; + const y = () => 1; + + if(1) { + x(); + } else { + y(); + } + ` + const initial = test_initial_state(code) + const {state, effects} = COMMANDS.step_into(initial, code.indexOf('x()')) + const call_code = state.current_calltree_node.code + assert_equal(call_code.index, code.indexOf('() =>')) + assert_equal(effects[0], { + type: 'set_caret_position', + args: [code.indexOf('() =>')], + }) + assert_equal(effects[1].type, 'embed_value_explorer') + }), + + test('step_into deepest', () => { + const code = ` + const x = () => () => 1; + x(2)(3); + ` + const initial = test_initial_state(code) + const next = COMMANDS.step_into(initial, code.indexOf('3')) + const cn = next.state.current_calltree_node.code + assert_equal(cn.index, code.indexOf('() => 1')) + }), + + test('step_into expand_calltree_node', () => { + const code = ` + const x = () => 1 + const y = () => x() + y() + + ` + const initial = test_initial_state(code) + const next = COMMANDS.step_into(initial, code.indexOf('y()')) + const cn = next.state.current_calltree_node.code + assert_equal(cn.index, code.indexOf('() => x()')) + }), + + test('coloring', () => { + const code = ` + const x = () => { + throw new Error() + } + const y = x() + ` + + const initial = test_initial_state(code) + // only `throw new Error()` colored + assert_equal( + color_file(initial, ''), + [ + { + index: code.indexOf('const x'), + length: 'const x = '.length, + result: { ok: true } + }, + { + index: code.indexOf('x()'), + length: 'x()'.length, + result: { ok: false, error_origin: true } + } + ] + ) + + const step_into = COMMANDS.calltree.click(initial, 1).state + assert_equal( + color_file(step_into, '').sort((a,b) => a.index - b.index), + [ + { + index: code.indexOf('const x'), + length: 'const x = '.length, + result: { ok: true } + }, + { + index: code.indexOf('() =>'), + length: '()'.length, + result: { ok: true } + }, + { + index: code.indexOf('throw'), + length: 'throw new Error()'.length, + result: { ok: false, error_origin: true } + }, + { + index: code.indexOf('x()'), + length: "x()".length, + result: { ok: false, error_origin: true } + } + ] + ) + }), + + test('coloring failed member access', () => { + const code = '(null[1])'; + const initial = test_initial_state(code) + // Color only index access, not grouping braces + assert_equal( + color_file(initial, ''), + [ { index: 1, length: 7, result: { ok: false, error_origin: true } } ], + ) + }), + + test('coloring if', () => { + const code = ` + const x = () => { + if(false) {/*m1*/ + if(true) { + 1 + } + 2 + } else { + 3 + } + }/*end*/ + + x()` + const initial = test_initial_state(code) + const step_into = COMMANDS.calltree.click(initial, 1).state + + assert_equal( + color_file(step_into, '').sort((c1, c2) => c1.index - c2.index), + [ + { + index: code.indexOf('const x'), + length: code.indexOf('() =>') - code.indexOf('const x'), + result: { ok: true } + }, + { + index: code.indexOf('() =>'), + length: code.indexOf(' {/*m1*/') - code.indexOf('() =>') + 1, + result: { ok: true } + }, + { + index: code.indexOf(' else'), + length: code.indexOf('/*end*/') - code.indexOf(' else'), + result: { ok: true } + }, + { + index: code.indexOf('/*end*/'), + length: code.length - code.indexOf('/*end*/'), + result: { ok: true } + }, + ] + ) + }), + + + test('coloring failed toplevel', () => { + const code = `throw new Error()` + const initial = test_initial_state(code) + assert_equal( + color_file(initial, ''), + [ + { + index: 0, + length: code.length, + result: { ok: false, error_origin: true } + } + ] + ) + }), + + test('coloring short circuit', () => { + const code = `true || false` + const initial = test_initial_state(code) + assert_equal( + color_file(initial, ''), + [ + { + index: 0, + length: "true".length, + result: { ok: true } + } + ] + ) + }), + + test('coloring nested', () => { + const code = + `const x = () => { + return () => { + return 123 + } +} +const y = x()` + const initial = test_initial_state(code) + const s = COMMANDS.move_cursor(initial, code.indexOf('return')).state + const coloring = color_file(s, '').sort((c1, c2) => c1.index - c2.index) + // Checked by eye, test for regression + assert_equal( + coloring, + [ + { index: 0, length: 10, result: { ok: true } }, + { index: 10, length: 18, result: { ok: true } }, + { index: 56, length: 2, result: { ok: true } }, + { index: 58, length: 14, result: { ok: true } } + ] + ) + }), + + test('better parse errors', () => { + const code = ` + const x = z => { + 1 2 + } + ` + const r = parse(code) + assert_equal(r.ok, false) + const p = r.problems[0] + assert_equal(p.index, code.indexOf('2')) + }), + + test('better parse errors 2', () => { + const code = ` + if(true) { + const x = 1 + } else { + , + } + ` + const r = parse(code) + assert_equal(r.ok, false) + const p = r.problems[0] + assert_equal(p.index, code.indexOf(',')) + }), + + test('better parse errors 3', () => { + const code = `[() => { , }] ` + const r = parse(code) + const p = r.problems[0] + assert_equal(p.index, code.indexOf(',')) + }), + + test('edit function', () => { + const s = test_initial_state(` + const x = foo => { + return foo*2 + }; + + x(2); + `) + + const s2 = COMMANDS.calltree.click( + s, + root_calltree_node(s).children[0].id, + ).state + + // Make code invalid + const invalid = ` + const x = foo => { + return + }; + + x(2); + ` + const s3 = COMMANDS.input(s2, invalid, invalid.indexOf('return')).state + + const edited = ` + const x = foo => { + return foo*3 + }; + + x(2); + ` + + const n = COMMANDS.input(s3, edited, edited.indexOf('return')).state + + const res = find_leaf(active_frame(n), edited.indexOf('*')) + + assert_equal(res.result.value, 6) + assert_equal( + n.calltree_node_by_loc[''][edited.indexOf('foo =>')] == null, + false + ) + }), + + test('edit function 2', () => { + const code = ` + const x = () => { + return 1 + } + [1,2,3].map(x) + ` + const s1 = test_initial_state(code) + + // Go into first call of `x` + const s2 = COMMANDS.calltree.arrow_right(s1).state + const s3 = COMMANDS.calltree.arrow_right(s2).state + const s4 = COMMANDS.calltree.arrow_right(s3).state + + assert_equal(s4.current_calltree_node.code.index, code.indexOf('() =>')) + + const edited = ` + const x = () => { + return 2 + } + [1,2,3].map(x) + ` + + const e = COMMANDS.input(s4, edited, edited.indexOf('2')).state + + const active = active_frame(e) + + assert_equal(active.index, edited.indexOf('() =>')) + }), + + test('edit toplevel', () => { + const code = ` + const x = () => { + return 1 + } + x() + ` + const s1 = test_initial_state(code) + + // Go into call of `x` + const s2 = COMMANDS.calltree.arrow_right(s1).state + const s3 = COMMANDS.calltree.arrow_right(s2).state + + assert_equal(s3.current_calltree_node.code.index, code.indexOf('() =>')) + + const edited = ` + const y = 123 + const x = () => { + return 1 + } + x() + ` + + const e = COMMANDS.input(s3, edited, edited.indexOf('123')).state + + assert_equal(e.active_calltree_node.toplevel, true) + }), + + test('edit module not_loaded', () => { + const s1 = COMMANDS.change_current_module( + test_initial_state({ + '' : '', + "x": 'export const x = 1', + }), + 'x' + ) + const e = COMMANDS.input(s1, 'export const x = 2', 0).state + assert_equal(e.current_calltree_node.module, '') + assert_equal(e.active_calltree_node, null) + }), + + test('edit function unreachable', () => { + const code = ` + const x = () => { + return 1 + } + const y = () => { + return 2 + } + x() + ` + const s1 = test_initial_state(code) + + // Go into call of `x` + const s2 = COMMANDS.calltree.arrow_right(s1).state + const s3 = COMMANDS.calltree.arrow_right(s2).state + + const edited = ` + const x = () => { + return 1 + } + const y = () => { + return 3 + } + x() + ` + + const moved = COMMANDS.move_cursor(s3, code.indexOf('2')).state + const e = COMMANDS.input(moved, edited, edited.indexOf('3')).state + assert_equal(e.active_calltree_node, null) + assert_equal(e.current_calltree_node.toplevel, true) + }), + + test('expand_calltree_node', () => { + // Test expecting MAX_DEPTH = 1 + const s = test_initial_state(` + const countdown = c => c == 0 ? 0 : 1 + countdown(c - 1); + countdown(10) + `) + const first = root_calltree_node(s).children[0] + assert_equal(first.children, undefined) + assert_equal(first.has_more_children, true) + assert_equal(first.value, 10) + const s2 = COMMANDS.calltree.click(s, first.id).state + const first2 = root_calltree_node(s2).children[0] + assert_equal(first2.children[0].value, 9) + assert_equal(first2.children[0].children, undefined) + assert_equal(first2.children[0].has_more_children, true) + assert_equal(first2.code, first2.children[0].code) + }), + + test('expand_calltree_node native', () => { + const s = test_initial_state(`[1,2,3].map(x => x + 1)`) + const map = root_calltree_node(s).children[0] + assert_equal(map.children, null) + const s2 = COMMANDS.calltree.click(s, map.id).state + const map_expanded = root_calltree_node(s2).children[0] + assert_equal(map_expanded.children.length, 3) + }), + + test('jump_calltree_location' , () => { + const code = ` + const x = foo => foo + 1; + const y = arr => { + return arr.map(x) + } + y([1,2,3]) + ` + + const assert_loc = (s, substring, is_assert_node_by_loc) => { + const {state, effects} = COMMANDS.calltree.arrow_right(s) + const index = code.indexOf(substring) + assert_equal( + effects[0], + {type: 'set_caret_position', args: [index]} + ) + if(is_assert_node_by_loc) { + assert_equal( + state.calltree_node_by_loc[''][index] == null, + false + ) + } + assert_equal(active_frame(state) != null, true) + + return state + } + + + const s1 = test_initial_state(code) + + // Select call of `y()` + const s2 = assert_loc(s1, 'y([') + + // Expand call of `y()` + const s3 = assert_loc(s2, 'arr =>', true) + + // Select call of arr.map + const s4 = assert_loc(s3, 'arr.map') + + // Expand call of arr.map + // native call is not expandable + const s5 = assert_loc(s4, 'arr.map') + + // Select call of x + const s6 = assert_loc(s5, 'foo =>', true) + + }), + + // Test very specific case + test('jump_calltree_location after error', () => { + const code = ` + const fail = () => { + throw new Error('fail') + } + const good = () => {/*good*/} + [good, fail].forEach(fn => fn()) + ` + const s = test_initial_state(code) + const call_fn = root_calltree_node(s).children[0].children[0] + const s2 = COMMANDS.calltree.click(s, call_fn.id).state + const good = s2.current_calltree_node.children[0] + assert_equal(good.code.index, code.indexOf('() => {/*good')) + }), + + + test('unwind_stack', () => { + const s = test_initial_state(` + const y = () => 1 + const deep_error = x => { + if(x == 10) { + throw new Error('deep_error') + } else { + y() + deep_error(x + 1) + } + } + deep_error(0) + `) + + assert_equal(s.active_calltree_node.toplevel, true) + assert_equal(s.current_calltree_node.id, s.active_calltree_node.id) + + const first = root_calltree_node(s).children[0] + + const depth = (node, i = 0) => { + if(node.children == null) { + return i + } + assert_equal(s.calltree_node_is_expanded[node.id], true) + assert_equal(node.children.length, 2) + return depth(node.children[1], i + 1) + } + + assert_equal(depth(first), 10) + assert_equal(first.ok, false) + assert_equal(first.error.message, 'deep_error') + }), + + /* Test when node where error occured has subcalls */ + test('unwind_stack 2', () => { + const code = ` + const x = () => 1 + const error = () => { + x() + null.y + } + error() + ` + const s = test_initial_state(code) + assert_equal(s.current_calltree_node.toplevel, true) + }), + + //TODO this test is fine standalone, but it breaks self-hosted + /* + test('unwind_stack overflow', () => { + const s = test_initial_state(` + const overflow = x => overflow(x + 1); + overflow(0) + `) + assert_equal(s.current_calltree_node.error.message, 'Maximum call stack size exceeded') + assert_equal(s.current_calltree_node.toplevel, true) + assert_equal(s.calltree_node_is_expanded[s.current_calltree_node.id], true) + }), + */ + + test('eval_selection', () => { + const code = ` + const x = () => () => 1 + x() + 2*2 + false && 4 + if(true) { + } + ` + const s0 = test_initial_state(code) + const s1 = COMMANDS.eval_selection(s0, code.indexOf('2'), true).state + assert_equal(s1.selection_state.result.value, 2) + + // Expand selection + const s2 = COMMANDS.eval_selection(s1, code.indexOf('2'), true).state + assert_equal(s2.selection_state.result.value, 4) + + const s3 = COMMANDS.eval_selection(s2, code.indexOf('2'), true).state + // Selection is not expanded beyond expression to statement + assert_equal(s3.selection_state.result.value, 4) + assert_equal(s3.selection_state.node.index, code.indexOf('2')) + assert_equal(s3.selection_state.node.length, 3) + + const s4 = COMMANDS.step_into(s0, code.indexOf('x()')).state + const s5 = COMMANDS.eval_selection(s4, code.indexOf('2')) + assert_equal(s5.effects, {type: 'set_status', args: ['out of scope']}) + + const s6 = COMMANDS.eval_selection(s4, code.indexOf('1')) + assert_equal( + s6.effects, + { + type: 'set_status', + args: ['cannot eval inside function: first step into it'] + } + ) + + const s7 = COMMANDS.eval_selection(s0, code.indexOf('4')) + assert_equal( + s7.effects, + { + type: 'set_status', + args: ['expression was not reached during program execution'], + } + ) + + const s8 = COMMANDS.eval_selection(s0, code.indexOf('if')) + assert_equal( + s8.effects, + { + type: 'set_status', + args: ['can only evaluate expression, not statement'], + } + ) + }), + + test('find_call', () => { + const code = ` + const y = () => y2() + const z = () => z2() + const y2 = () => 1 + const z2 = () => 2 + const target = () => target2() + const target2 = () => target3() + const target3 = () => 3 + const deep_call = x => { + if(x == 10) { + target(x) + } else { + y() + deep_call(x + 1) + z() + } + } + deep_call(0) + ` + const s1 = test_initial_state(code) + const {state: s2} = COMMANDS.move_cursor(s1, code.indexOf('target2()')) + + assert_equal(s2.current_calltree_node.id, s2.active_calltree_node.id) + + assert_equal(s2.current_calltree_node.args, [10]) + assert_equal(s2.current_calltree_node.code.index, code.indexOf('() => target2')) + + const root = root_calltree_node(s2) + const first = root.children[0] + + assert_equal(first.ok, true) + + const find_target = (node, i = 0) => { + if(node.children.length == 1) { + return [i, node.children[0]] + } + + assert_equal(s2.calltree_node_is_expanded[node.id], true) + assert_equal(node.children.length, 3) + assert_equal(node.code != null, true) + + // Siblings are not expanded + assert_equal(node.children[0].has_more_children, true) + assert_equal(node.children[2].has_more_children, true) + + return find_target(node.children[1], i + 1) + } + + const [depth, target] = find_target(first) + assert_equal(depth, 10) + assert_equal(target.args, [10]) + + const target2 = target.children[0] + // Target is expanded, but only one level deep + assert_equal(target2.has_more_children, true) + }), + + test('find_call error', () => { + const code = ` + const unreachable = () => { + 1 + } + + const throws = () => { + throw new Error('bad') + } + + throws() + ` + + const s1 = test_initial_state(code) + const {state, effects} = COMMANDS.move_cursor(s1, code.indexOf('1')) + assert_equal(state.active_calltree_node, null) + assert_equal(state.current_calltree_node.toplevel, true) + assert_equal(effects.type, 'unembed_value_explorer') + + }), + + test('find_call with native call', () => { + const code = ` + [1,2,3].map(x => x + 1) + ` + const s1 = test_initial_state(code) + const {state: s2, effects} = COMMANDS.move_cursor(s1, code.indexOf('x + 1')) + assert_equal(s2.current_calltree_node.code.index, code.indexOf('x =>')) + }), + + test('select_return_value not expanded', () => { + const code = ` + const x = (a) => 1 + x() + ` + const s1 = test_initial_state(code) + const s2 = COMMANDS.calltree.arrow_right(s1).state + const {state: s3, effects} = COMMANDS.calltree.select_return_value(s2) + assert_equal(s3.selection_state.result.value, 1) + assert_equal(s3.selection_state.node.index, code.indexOf('x()')) + assert_equal( + effects, + {type: 'set_caret_position', args: [code.indexOf('x()'), true]} + ) + }), + + test('select_return_value expanded', () => { + const code = ` + const x = (a) => 1 + x() + ` + const s1 = test_initial_state(code) + const s2_0 = COMMANDS.calltree.arrow_right(s1).state + // Expand + const s2 = COMMANDS.calltree.arrow_right(s2_0).state + const {state: s3, effects} = COMMANDS.calltree.select_return_value(s2) + assert_equal(s3.selection_state.result.value, 1) + assert_equal(s3.selection_state.node.index, code.indexOf('1')) + assert_equal( + effects, + {type: 'set_caret_position', args: [code.indexOf('1'), true]} + ) + }), + + test('select_return_value fn curly braces', () => { + const code = ` + const x = (a) => {return 1} + x() + ` + const s1 = test_initial_state(code) + const s2_0 = COMMANDS.calltree.arrow_right(s1).state + // Expand + const s2 = COMMANDS.calltree.arrow_right(s2_0).state + const {state: s3, effects} = COMMANDS.calltree.select_return_value(s2) + assert_equal(s3.selection_state.result.value, 1) + assert_equal(s3.selection_state.node.index, code.indexOf('1')) + assert_equal( + effects, + {type: 'set_caret_position', args: [code.indexOf('1'), true]} + ) + }), + + test('select_return_value fn curly braces no return', () => { + const code = ` + const x = (a) => { 1 } + x() + ` + const s1 = test_initial_state(code) + const s2_0 = COMMANDS.calltree.arrow_right(s1).state + // Expand + const s2 = COMMANDS.calltree.arrow_right(s2_0).state + const {state: s3, effects} = COMMANDS.calltree.select_return_value(s2) + assert_equal(s3.selection_state, null) + assert_equal( + effects, + {type: 'set_caret_position', args: [code.indexOf('{'), true]} + ) + }), + + test('select_return_value native', () => { + const code = ` + [1,2,3].map(() => 1) + ` + const s1 = test_initial_state(code) + // Select map + const s2 = COMMANDS.calltree.arrow_right(s1).state + const {state: s3, effects} = COMMANDS.calltree.select_return_value(s2) + assert_equal(s3.selection_state.result.value, [1, 1, 1]) + }), + + test('select_arguments not_expanded', () => { + const code = ` + const x = (a) => { 1 } + x(1) + ` + const s1 = test_initial_state(code) + // focus call + const s2 = COMMANDS.calltree.arrow_right(s1).state + const s3 = COMMANDS.calltree.select_arguments(s2) + assert_equal(s3.state.selection_state.result, {ok: true, value: [1]}) + assert_equal( + s3.effects, + {type: 'set_caret_position', args: [code.indexOf('(1)'), true]} + ) + }), + + test('select_arguments expanded', () => { + const code = ` + const x = (a) => { 1 } + x(1) + ` + const s1 = test_initial_state(code) + // focus call + const s2_0 = COMMANDS.calltree.arrow_right(s1).state + // expand call + const s2 = COMMANDS.calltree.arrow_right(s2_0).state + const s3 = COMMANDS.calltree.select_arguments(s2) + assert_equal(s3.state.selection_state.result, {ok: true, value: {a: 1}}) + assert_equal( + s3.effects, + {type: 'set_caret_position', args: [code.indexOf('(a)'), true]} + ) + }), + + test('move_cursor arguments', () => { + const code = ` + const x = (a, b)/*args*/ => { } + x(1, 2) + ` + const s1 = test_initial_state(code) + // focus call + const s2 = COMMANDS.calltree.arrow_right(s1).state + // expand call + const s3 = COMMANDS.calltree.arrow_right(s2).state + const s4 = COMMANDS.move_cursor(s3, code.indexOf('a')) + assert_equal(s4.effects.type, 'embed_value_explorer') + assert_equal(s4.effects.args, [{ + index: code.indexOf('/*args*/'), + result: {ok: true, value: {a: 1, b: 2}}, + }]) + }), + + test('move_cursor concise fn', () => { + const code = ` + const x = y => y*2 + x(2) + ` + const s1 = test_initial_state(code) + const s2 = COMMANDS.move_cursor(s1, code.indexOf('2')) + assert_equal(s2.effects.type, 'embed_value_explorer') + assert_equal(s2.effects.args, [{ + index: code.indexOf('2') + 1, + result: {ok: true, value: 4}, + }]) + }), + + test('move_cursor let', () => { + const code = ` + let x + x = 1 + ` + const s1 = test_initial_state(code) + const s2 = COMMANDS.move_cursor(s1, code.indexOf('x')) + assert_equal(s2.effects.type, 'embed_value_explorer') + assert_equal(s2.effects.args, [{ + index: code.indexOf('x') + 1, + result: {ok: true, value: {x: 1}}, + }]) + }), + + test('move_cursor after type toplevel', () => { + const code = `1` + const s1 = test_initial_state(code) + const s2 = COMMANDS.move_cursor(s1, code.indexOf('1') + 1) + assert_equal(s2.effects.type, 'embed_value_explorer') + assert_equal(s2.effects.args[0].result.value, 1) + }), + + test('move_cursor after type fn', () => { + const code = ` + const x = () => { 1 } + x() + ` + const s1 = test_initial_state(code) + const s2 = COMMANDS.step_into(s1, code.indexOf('x()')).state + const s3 = COMMANDS.move_cursor(s2, code.indexOf('1') + 1) + assert_equal(s3.effects.type, 'embed_value_explorer') + assert_equal(s3.effects.args[0].result.value, 1) + }), + + test('move_cursor between statements', () => { + const code = ` + 1 + + /*marker*/ + 1 + ` + const s1 = test_initial_state(code) + const s2 = COMMANDS.move_cursor(s1, code.indexOf('/') - 1) + assert_equal(s2.effects.type, 'unembed_value_explorer') + }), + + test('move_cursor step_into fn', () => { + const code = ` + const x = () => { + 1 + } + ` + const s1 = test_initial_state(code) + const s2 = COMMANDS.move_cursor(s1, code.indexOf('1')) + assert_equal(s2.effects.type, 'unembed_value_explorer') + }), + + test('move_cursor brace', () => { + const code = ` + if(true) { + 1 + } + ` + const s1 = test_initial_state(code) + const s2 = COMMANDS.move_cursor(s1, code.indexOf('{')) + assert_equal(s2.effects.type, 'unembed_value_explorer') + }), + + test('frame follows cursor toplevel', () => { + const code = ` + const x = () => { + 1 + } + x() + ` + const s1 = test_initial_state(code) + const s2 = COMMANDS.move_cursor(s1, code.indexOf('const')).state + assert_equal(s2.current_calltree_node.toplevel, true) + assert_equal(s2.active_calltree_node.toplevel, true) + }), + + test('frame follows cursor fn', () => { + const code = ` + const x = () => { + 1 + 2 + } + x() + ` + const s1 = test_initial_state(code) + const s2 = COMMANDS.move_cursor(s1, code.indexOf('1')).state + assert_equal(s2.current_calltree_node.code.index, code.indexOf('() =>')) + // Move within current node + const s3 = COMMANDS.move_cursor(s2, code.indexOf('2')).state + assert_equal(s3.current_calltree_node.code.index, code.indexOf('() =>')) + }), + + test('frame follows cursor return back to fn', () => { + const code = ` + const x = () => { + 1 + } + x() + ` + const s1 = test_initial_state(code) + const s2 = COMMANDS.move_cursor(s1, code.indexOf('1')).state + + // Go back toplevel + const s3 = COMMANDS.move_cursor(s2, code.indexOf('const')).state + assert_equal(s3.current_calltree_node.toplevel, true) + + // Go back to fn + assert_equal(s3.calltree_actions == null, false) + const s4 = COMMANDS.move_cursor( + {...s3, + // Set calltree_actions to null, ensure it would not be called again + calltree_actions: null + }, + code.indexOf('1') + ).state + assert_equal(s4.current_calltree_node.code.index, code.indexOf('() =>')) + }), + + // Tests for one specific bug + test('frame follows cursor change fn', () => { + const code = ` + const x = () => { + 1 + } + const y = () => {/*y*/ + 2 + z() + } + const z = () => { + 3 + } + x() + y() + ` + const s1 = test_initial_state(code) + + // goto x() + const s2 = COMMANDS.move_cursor(s1, code.indexOf('1')).state + + // goto y() + const s3 = COMMANDS.move_cursor(s2, code.indexOf('2')).state + + assert_equal(s3.active_calltree_node.code.index, code.indexOf('() => {/*y')) + }), + + test('frame follows cursor deep nested fn', () => { + const code = ` + const y = () => { + 1 + } + const x = i => i == 0 ? y() : x(i - 1) + x(5) + ` + const s1 = test_initial_state(code) + const s2 = COMMANDS.move_cursor(s1, code.indexOf('1')).state + assert_equal(s2.current_calltree_node.code.index, code.indexOf('() =>')) + }), + + test('frame follows cursor intermediate fn', () => { + const code = ` + const y = () => { + z() + } + const z = () => { + 1 + } + const x = i => i == 0 ? y() : x(i - 1) + x(5) + ` + const s1 = test_initial_state(code) + const s2 = COMMANDS.move_cursor(s1, code.indexOf('1')).state + const s3 = COMMANDS.move_cursor(s2, code.indexOf('z()')).state + assert_equal(s3.current_calltree_node.code.index, code.indexOf('() =>')) + // Check that node for `y` call was reused + assert_equal( + find_node(s2.calltree[''].calls, n => n == s3.current_calltree_node) + == null, + false + ) + }), + + test('frame follows cursor unreachable fn', () => { + const code = ` + const x = () => { + 1 + 2 + } + ` + const s1 = test_initial_state(code) + const s2 = COMMANDS.move_cursor(s1, code.indexOf('1')).state + assert_equal(s2.current_calltree_node.toplevel, true) + assert_equal(s2.active_calltree_node, null) + + // Check that when we move cursor inside unreachable function, find_call + // not called again + const s3 = COMMANDS.move_cursor( + // Set calltree_actions to null, ensure it would not be called again + {...s2, calltree_actions: null}, + code.indexOf('2') + ) + assert_equal(s3.active_calltree_node, null) + }), + + test('frame follows cursor only find_call in entrypoint module', () => { + const scratch = `import {x} from 'x'; x()` + const x_code = `export const x = () => 1; x()` + const s1 = test_initial_state({ + '' : scratch, + 'x' : x_code, + }) + const s2 = COMMANDS.move_cursor( + {...s1, current_module: 'x'}, + x_code.indexOf('1') + ).state + assert_equal(root_calltree_node(s2).module, '') + }), + + test('stale id in frame function_call.result.calls bug', () => { + const code = ` + const x = () => {/*x*/ + y() + } + + const y = () => { + 1 + } + + x() + ` + + // Eval toplevel frame, id of call (x) will be saved in frame + const s1 = test_initial_state(code) + + // Expand call of x(), id will be changed (bug) + const s2 = COMMANDS.move_cursor(s1, code.indexOf('y()')).state + + // Step into from toplevel to call of x(), the stale id will be used + const s3 = COMMANDS.move_cursor(s2, code.indexOf('x()')).state + const s4 = COMMANDS.step_into(s3, code.indexOf('x()')).state + + assert_equal(s4.active_calltree_node.code.index, code.indexOf('() => {/*x')) + }), + + test('get_initial_state toplevel not entrypoint', () => { + const s = get_initial_state({ + files: { + '' : `import {x} from 'x'; x()`, + 'x' : `export const x = () => 1; x()`, + }, + entrypoint: '', + current_module: 'x', + }) + assert_equal(s.current_calltree_node.toplevel, true) + assert_equal(s.active_calltree_node, null) + }), + + test('module not evaluated because of error in module it depends on', () => { + const s = test_initial_state({ + '' : `import {x} from 'x'`, + 'x' : ` + const has_child_calls = i => i == 0 ? 0 : has_child_calls(i - 1) + has_child_calls(10) + throw new Error('fail') + `, + }) + assert_equal(root_calltree_node(s).module, 'x') + + const s2 = COMMANDS.move_cursor( + COMMANDS.change_current_module(s, 'x'), + s.files['x'].indexOf('throw') + ) + assert_equal(s2.effects.type, 'embed_value_explorer') + + const s3 = COMMANDS.calltree.arrow_right(s).state + assert_equal(s3.current_calltree_node.fn.name, 'has_child_calls') + + }), + +] diff --git a/test/utils.js b/test/utils.js new file mode 100644 index 0000000..d1089d6 --- /dev/null +++ b/test/utils.js @@ -0,0 +1,141 @@ +import {parse, print_debug_node, load_modules} from '../src/parse_js.js' +import {eval_tree, eval_frame} from '../src/eval.js' +import {get_initial_state} from '../src/cmd.js' + +Object.assign(globalThis, {log: console.log}) + +export const parse_modules = (entry, modules) => + load_modules(entry, module_name => modules[module_name]) + +export const assert_code_evals_to = (codestring, expected) => { + const parse_result = parse(codestring) + assert_equal(parse_result.ok, true) + const tree = eval_tree(parse_result.node) + const frame = eval_frame(tree) + const result = frame.children[frame.children.length - 1].result + assert_equal({ok: result.ok, value: result.value}, {ok: true, value: expected}) + return frame +} + +export const assert_code_error = (codestring, error) => { + const parse_result = parse(codestring) + assert_equal(parse_result.ok, true) + const tree = eval_tree(parse_result.node) + const frame = eval_frame(tree) + const result = frame.children[frame.children.length - 1].result + assert_equal(result.ok, false) + assert_equal(result.error, error) +} + +export const test_initial_state = code => { + return get_initial_state({ + files: typeof(code) == 'object' ? code : { '' : code}, + entrypoint: '', + current_module: '', + }) +} + +export const stringify = val => + JSON.stringify(val, (key, value) => { + // TODO do not use instanceof because currently not implemented in parser + if(value?.constructor == Set){ + return [...value] + } else { + return value + } + }, 2) + +export const assert_equal = (exp, actual) => { + if(typeof(exp) == 'object' && typeof(actual) == 'object'){ + const exp_json = stringify(exp) + const act_json = stringify(actual) + if(exp_json != act_json){ + throw new Error(`FAIL: ${exp_json} != ${act_json}`) + } + } else { + if(exp != actual){ + throw new Error(`FAIL: ${exp} != ${actual}`) + } + } +} + +export const print_debug_ct_node = node => { + const do_print = node => { + const {id, fn, ok, value, error, args, has_more_children} = node + const res = {id, fn: fn?.name, ok, value, error, args, has_more_children} + if(node.children == null) { + return res + } else { + const next_children = node.children.map(do_print) + return {...res, children: next_children} + } + } + return stringify(do_print(node)) +} + +export const test = (message, test, only = false) => { + return { + message, + test: Object.defineProperty(test, 'name', {value: message}), + only, + } +} + +export const test_only = (message, t) => test(message, t, true) + +// Wrap to Function constructor to hide from calltree view +// TODO in calltree view, hide fn which has special flag set (see +// filter_calltree) +export const run = Object.defineProperty(new Function('tests', ` + const run_test = t => { + try { + t.test() + } catch(e) { + if(globalThis.process != null) { + // In node.js runner, fail fast + console.error('Failed: ' + t.message) + throw e + } else { + return e + } + } + } + + // If not run in node, then dont apply filter + const filter = globalThis.process && globalThis.process.argv[2] + + if(filter == null) { + + const only = tests.find(t => t.only) + const tests_to_run = only == null ? tests : [only] + + // Exec each test. After all tests are done, we rethrow first failer if + // any. So we will mark root calltree node if one of tests failed + const failure = tests_to_run.reduce( + (failure, t) => { + const next_failure = run_test(t) + return failure ?? next_failure + }, + null + ) + + if(failure != null) { + throw failure + } else { + if(globalThis.process != null) { + console.log('Ok') + } + } + + } else { + const test = tests.find(t => t.message.includes(filter)) + if(test == null) { + throw new Error('test not found') + } else { + run_test(test) + if(globalThis.process != null) { + console.log('Ok') + } + } + } +`), 'name', {value: 'run'})

_31wQGdBwFsrW zR2$pkAg_Zov<1mhz7bJ8WkTKlJ$v`aMWL^sdo7^Tp?dnRNf(lq-G=xltKVfTE$Kh5 zc0}_#ZyPQ(+7WSE#yN2D(RO5aNt@=speGE;zjV)?Ic=+GORRIU3-zPoIRM!y62sIg zo`hG6Y-A-(A&nCtpTb!zS*M(yU{mPbF# zyD=Z|(M@$lEV`eQtSGXxqB9E5$WrQpsa`DYoP1a1tJb~O@u>oE8k1YxeggmiNTY39 zTp=nReXfrzx%_h(23H55OiNtIRRs0X5c#y7s(S3#WHJ2RJs(_YpqFDQjV{R{Uweur z#CjMO{Q@_9;(X1ol)UWMgYQc?ncSG+sop;yJ6oX>DjofH9fo9&+fx9mUQ194i_XU7 z-qh~ucW6D&`Vsft$jPTk$G3v1m;2*Qao_xYP=o6dfzWH_BMjYKpcvf)Ew4 zX$<@}D~Zd?BymEgM{ks`S#nP`K!M*g_~)TB29FV!8wzs_UQ~EmA}@&9)u8d?M2%t5!{A`HxiLW&3rg>fo86>0?Yvj zQQ}p)I(H5C)l1d+`uckOIWIEwIIP)OUxxz%fw&(f3F2SiQw%eC;@zkY7~rq=1bB;4-81L953r_(0tcnr|_%(&cFEr5PBIe_x4FL-E=|=v^2Z!FS$B{ zI;-UL7NMS)B^Ntm1;$dSAR8O)Hj$&dt(un*WPb&-R+Jb6!$n;0rg}HJ=N;id4-cOu zln%99ZW0Uk?^U}(#uHgfAnCHOQN~Y|MDo+yg88IV7Ja~49wt?HcV9!$!_9gRa=qP> zCai(~5CVY=&d~xqhHIZ4dWJGM(eF{7zzmeZ8=GjxDmRSYvH3`SDG_HW_@IWOf8v8k z*wo!1tyF5uBGoc19vqeIoV$2PP|DfB!8!92{Rq5W?D7Cpb6U<<11j~~BVb&&UNDWlVqNEcs-9rAL0shj7-1eAV1x-pM84L+ags(x&Fho z@6x@vOzs(yJR{3>6-2D|cy|>nU=Nf02FRvqe`W^0KukdlR*4norXZRzbInug=v+1K zG7BTMU*a~>LqCb9Z2vJ_H?>RAzrDY=A;R_Et+}N64?R3EC&^j&M%%_}xQ_m=0~mbU zIMu$O;7oEKnELa#tH4prC~@N;T(Pa-7#85cy)N4$#Ohzv8EP`(u3jJlSAZ3lkf_2= zt4zoAp;kCvj*Zml9gho;e7QBymJF>_ukWe_51SMNMn^;b8!$Rjh}?EKSrIPRZa{^3 zSLXL{@|AX6$x9$n?!m@Vn=~RjNr4DBG5(Ix{fV}|U5PgMTk{{{uUlcqhoI3`mRaHq-{ z@8o)$95?F|{~z>7;1l@M&=-5l-f>gnbr2d*3p#bRd-_5IB%!9=$!*2R*2gxn4#Owf ze1wL?&A&f5zs6pO9(UI*zxcz|LD2cO7UfaK9(t_--&-&^v8i&9?iNS|BB6 zcJLRyebn442JawJY-t5MWvv<`OQv1oC#4^*oAZ{c8)MBI* zMScOakw=@?*6Qx-det~ffKs%(9KdlV^>2Oxs}rfPz!oF2NVEG3S~~GwW8x3!K&yzf zL{mkE4WFc}f9Hkwcj?RYKoCLOP-+9sh!?GV6lc-nH(7(-%#iVX7XZ)DH?jYyRTT$* zFM^*TUC;<*T06vl@A|8H=Xm_iY25nf;jqRNeh5%^u$p!0w940e0YApiFe4-{(k6xyq5 S6-LiDNXSYlNmhy*2K*28HW73H literal 0 HcmV?d00001 diff --git a/docs/images/inspect.gif b/docs/images/inspect.gif new file mode 100644 index 0000000000000000000000000000000000000000..82597dd76cceabcc03543781c7ae3988ee11d7a8 GIT binary patch literal 21725 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 literal 0 HcmV?d00001 diff --git a/docs/images/nav.gif b/docs/images/nav.gif new file mode 100644 index 0000000000000000000000000000000000000000..e70d176ed4d3469e3a5e69cc428ecf2ac9bc62be GIT binary patch literal 55681 zcmZVFWl$W!yD<8}-JReNoB#<)(BO-^!xA8PaDrPFx5eFUaS0)~1$Rww3GOZlwy>A~ zIp@9Sy>+L0s;j2vL-*6u)6?C*ky8K(3YiHYqab?%03!lNRaRR|T2fv1^(#IUB;fhd z9V$TZoO3^)z<+KFf6nnp2}#MxkudmanV7iIkzcZNa`W=PdL!^gKmdhM1)bs(CaoL# zD-9%Gd!Y{!+^>B2`Fv?W{5WGePtAcYSyAbtf+A$>(|kgK?vrZOR>$}3FySNs-~ z_zo`!-DruuIY=a5DQK%;E6DMCC==VM@Ozr^%PJ^>RMeHVbaiy~bd1eqZ1h#VEDg=A zHT-RT6%>6HzIZvSe6q1Kw|D;h#nac@+}+&+g)4?qc%1da6ovv6P=nE!CE=OXlYXk8 zv~QtxZRfO!Wp}IRmY94cIV}kK#iaP~PW3@l{eji5Pg5sE#vxwHwaV5r;){QvwDOFy z*1SG=L00=g8~gw^TLgcCf3jM(cV7PDxn%hn?&z}a=C$tS1J@38FoJq~jQ6&J`tpPg zD~D8CWe0l)hxWtNgSGfm%&3#B`HQvaI&@hIZD~v0=&IehW9?L+F6PC4 z%E5kFjUoJrAsR{H4sD65wW)RkLHtw6>V0{xbA_7Yuunr}9%FSrOI6;#>wWg>zJy0a z1jQtTC#5B3MW>~uL9@ydb6|-{?V-gjsYMl;6+aRi+e`C;D$`&MWiiFY#f8=NB@J!O zm9WOGnm4~njct!njW@pDpbHe!bx300Ofu)Atk=Bvlom0!@ zqdWN%e~Xvyn}>E=dT*M4@3$`Aly5#ZA3S!PKmKlwm~5-uYlRMUPRtKv&Wu!FjVGVa zmF;Y{4-F0VP0aQDTKqjRHnT9iyu92!eml6dJv4X!d--5$?Qv;iY+`+X@bF>u3O=`U zJb!Sra`~{g{AXi-c=Kp}<9rT&IB>teg!nu0bU$}|e6o3bzHxc5aSgve*?W38etLSs zL;wgZ8u{A%?qEz3PVi7|L2o!AvtqXV_rm^Y$~T`^hQ1dK#xY1o(J0ixhLhN}D!{{a z#iMC_<|Ek(KT5{41iu`j4u311%##Slrd6yjn=X=1!Y3=MFaKStUZj|#*ibQBssH2i z>d0*Ac#Uaq6s=NY)#4AE-xbD{GqgW5?eki3C?={WozEbgR&DqvTUGX$vZ;buegbkORM_fAh#|Ps7s1 z9EjF4%u)qsL{MeWGXTe&Pm)>8y4EPM>;MBq$S4pQf&}EpOT=o72gz`Mz%Jh}gmTKl zK%iIXF_6!@XuByI$X@v3226pBqB`~kj9)&aV2<;W{kt6Hr6fn2^1$&^r$4PdC%|m9E?=E5O-m-PFqtAhRulM_DQ>Tsl zqnaPSv5ABq!M7*PC?3r+cj=!-USd_5j<9a4^H`?;yx#0jITQ855!m!exZ6H^ch=8a zsw?lL_Ol%qx}YpKeAmfmRmdlv-a)9y8Xww|vMPp$r*jh?miO>@8`t0~b5~`W?GmK{ zPPU<7@VMBb(G&d5r8t9A<$WTC3f8Rj+kDL#!fTQftlaB{Muoav$aTJjfv4ToS_DVd zxKk>?o~{#5fp6QG7Nu&gPycv3T+1a;zlQBOBrV&(_fibEkPs0*luln55+Sc#NId?j zFNymiQXN`oBQKrA@FX3jKgOh;X+z8tYsqGcTSPgSPW&phFZvT>5%v7gz&oivD2t@I z{)+sd@KOTQSy?{dodykcIukwp6|Mk`5RLh~M?(!WTs`pumG)_ew(dMs?^J$R(eU!6 zx6DugF$87(f`Mf*?wX zr(hcP{6Jp%Um2b>k{GDMgG3&tZ3R_zDU#mB%y*mEwE84CNn^$Dnub-vk6jrbrMvlP ze^J@&=i`V8g}-$OOtx+%PR;M`A<8F0v;POnx*aS1@Ut8d|F~|NjmHrcJyrn4K#fwf zN(jX_v<$UtOiDScUlY-;kEPf@2)5=J6j^sc_3f0+W56rtxr>Z{ddUDmropxXLIE;> zLD-7l@}rl_1haBM$ZC*{z(xk0gycXWpw43WM`O}H>bgwcl34-o(=Qzch2nUA6u+^2 z;liq5{k}~M-Edjjf+6i3O|Nj$l5=$%WZBFt6bSZ8P*elfOMRoa7^0h>V{3$~%5Ib^ zKHgvt6cfYBcNp{V{D`FrvI|Vnd@(*@?S3e9+rT{A55k{7B50@X&k;!}LxLB-yTO$; zjrQ*mmU;*oC>gBtQ>p%JyQvqLPFh@WoNbLW`lbjmJJtBst%|53L$UDBHG8@kms+4D z;9oFV-O%rl?98PxQ}eH7N=L!&Dlj<75XOGOXs;6<6xA|Zt($-DxFX6$YNVf(iZLTe zK0-Y`zQNfh6PV>CWL9*ScvGWaX6be_x)xvm&gJ{dHTx#6WcBO`w`;N513qC=_d^C( zcv%TcV5Qc^=YJhTXi=|8!NQ)-x45|PqP{#RZ4#Tn8nz0$U+T7hg1km;vn#6BXE}=c zl1@=~JYMBn`Nib>xfFTrR3MQBBaUhM?T~x`Ga3KuTm=7UKThBUvG*0HOSYeh1ptMCDp0q{RFQtKbZ0A|F_qnut$ zo1m{Ix`;v$EPA|;s+jrk1D8|lOnSBbP!KKVInhK=60p1vg4}=RM>#-^U%w z#>m#CLAR$~wqK%x{dQ0wcb|kX5Zop4mU=U+6*H5Mzn`)R)?38(^3N1rnTAAJSRfa` zy}I{xDNKg+*GUgB$oC`yKq@w2jTgo0}&4lM$ZpsrevXHV}}R2U$99Hrje5Fb05Fa|7`ZLlR-<$Oe2So ze8oD{D>yXd7lm<`vIJ6?ioD<%x@aYX=o>R^9t!pI3*_-lMvYG>er3$!{8H!6%uO0h zrwqcs_|?(e)xp!u@byq$1UtaDL(>8Y6n6>t)@Ry1NA|M;Ur0*@vFnIwL?AQJ3VdP~ z+zdB!3Hh~wA3qf0(99oZO|;eR;>zxY`yJVbSpC%wYwHC*=ei~;2nEwrgB-$qw82)Q zL(9FRnJ`2aOG%ou{*FM$5A;3Sv5;z`i#zajU@s=n@AX0~5GuLB*8Ps%5R*KyUv-K- z=35#6?@;8;8F97+;z|hel?@?09;ZMZT91r}U8=*fGK3R*yD#h(KF5QtJXL z5lD3;X=Y_fdOs9bupVb>4zOH@BU1@in8$BnQjPR*e*uvRpz9DV#!_zSomd-R>JulV zY2v;iy`R^CH!@uyt`bm7-tDoQQx9O}6DH>a0j)dCj6v_EC8f^^@xhH?dHy8Pq6Ctm z*hSrVkw`wk`2$l(vUCED6xGKWeNr|dQaOV}&V!Kef<##%D1z!VTvH0}?@8bkq&j!u z@&;*(|KbR!%=I|HXuVigizN7WB$fuG;bewt!zo0~312v*gv-;!iKN8YNwXpPGE}7P zI;5fAsjX?L#FF^jji0VPurM*awFEPSY?HjM@G;dx?>*zq$YcGz$$|}NIXFm1oNNh`Y^#7RqTdP>}Ywqj+wFrn!qu8&Z1P# z%>q%vpc6VI$7ooX+!8&VLHj-ps{j(ML>Yz4MtdI0_d|$mO2VRa8@nz)_V;v@(Ypk> zjoi*4EZ^yTg3MrI;V22lj9Ue=!+N7Hd_~5lB2^2}C!w5NTOwW#5w<(&4gkD_>DG*;Qj(<}BjjEcrGBj?7tZfc%8~o3 zW?|#bH`OJz*e*hZgV@zeBjsoN7F^ENDf6UVt<~F{Ilmi_EC1mgQYWD%RPWr^oOsnB zDXLCjfBPpKba`l_5?FP!^exr1X2S(*?p|AwzvjuOHo~I@5sZ8sRju0n4fDl!!@hu; ze-_$W--xrm>nFSRPuCJglhRjyXNs0de&^ItN~mU5%iLBcBVhd1(rul(4#fC_+vo=e z;@afjE#6-*cMhG}cMm^AE$k3qJSf_}N%+>kZ!2nl(iyBSrl?(401Bt`I|LH8(3 z3rB|1w*lOiXy7ZOv)u4$w8Z2{#@x5@wzmo`q0VNxQL3=!1Jo}>cH&8Z@kjk-=`-HmC> zEjfXou-3KbUpD0$wFXWbrZK2SBv7i1wv;@y1_ZWdUyCDP%?cVVwOMTzjBN!E1b2K+ zSD&klD%<)-Wh`-2XLnpX?cy47>iQqr2ik~+-w}!_D)-`aEVPkj94W2OwI^qFtRqIr z;vN*X`RL^4e<&2xZM1c2^%2cj(r~SRZ{{Ms8twe&YcP03sH{|b;QRBbP4@1E9PHsI zD)gtbO9xtZ*D6sLGf^`(ylb_miwUWlRFv$`YfsATZtC`Knw4(1Gy(=FcG)^U3%G~X zuZKOmhqJwh`xu`A-or=J`&zVD0Nne|uU9a;SGc`bbfxzLyjOyzPfD~;2HXeo>yyv! z6Z7k)Tj^6>>E`3^;SufE2KTd9_33B#8@Bg@SNcD~`%P&EK7sp`;eA&20~(?|EcW=r z=UMKuJtOKAtbRJ$V*^g@JucZj=Iw)iD}w>>K?u!I&~d+|-@um}yex_8UWBx}YW4sN z)G?u8ApJWVD;ycC7N462KN%ZhH-;_CP+Tq1gZ>xD2KNN}jg)1NRJ4y&t&E6(hr+<_ zsvgd2$3qTZfC31%RX(m=yMgC1KCdZKdR5OA#`8iOwyQnKdmVS;RBx1*yPr1^mxG&|jb^MD+Oq+$TRHb^4`Q>l<4>CQ z3`3Z6Oh=YiCZFJw0PU11?&u$Ach?o(Hcbz+{qWDRo@4MN8}17M=blN1;uC1kmE7_M33-B;UEq(?9!Ys%)w$bJ63hu$~ z$KkXks4xdJLRV zch7OFy0AOrCpz1w<#Ogecg)$V^eNDeg2Jb4z!PaxSO%+D8x6mAO@TMY!zaDJgz?6Z zyGB3q6kAxKQK+H2(3E@HDUh#2>nm!LGR z;~#Zlmxc6nyzWU@U8;FpVh~$Y6OI1vx2WUa<6FJR0-tJoT)d}PVu7L^>h$cYqh9;< z9QQ8OcC3u8uFP^TtAc4=hi7kt|Lh!fY%AAvt3GXOWk))_j^sY}N6sH$JKb@7+D*XQHH+;w zSKZah##NU9Y&v`1og?Q@O*zx;2i45Ee%QM}@2y01?Rs?Xt9{syecGot-Vcl2uk6}S z{n#I$dysiL>9OpU>*$j6bWk|qSn%Pno7bVu?jhtwB`jZcSl zxksg}-DYk_ot=lRbjPbQM^qO_l{M%j0P`o{xaZHY#kB^WQ)2FA;#>!WVdlO22%9|RLFr^yv#_hsYt(I)_~?K-4BKYK@iO&fTX z2D=iSJTw8WrG8#hN?xa4AK{vydjsfiCa-l(h*V7!20o%Y5(9RSOFjC3>lPOeog`Ge zxOVXvCX>gX*8Z8FsaSp^p>jHMG`aDS`G+ljQ{#B!XF_P8rr`7Q#$WvQtN3jgujU%v z&8zwWx7piR#BDtNU84A1vdLZQ*Sqw*yUd?=*=u*Xh`W6H`$F-1BiWv*2||jvxcl0J zsz4&`iEnhMepNw+~_5r4l z^2%~)=0K}Vqgb`raQ0BA%Amn8$tajeEm z*S0g|I^V2T@7=Z^FvOi@O z2m82s?|!`4;I#K=^}#dtdv_e0$sf4)^}+17(pR~UzPA@UlcgqWof0=Uf6w;T))0ut zOB81bWE_EW2~;*>KBhuyw{uBM=459nY_9rqDcndy!a`h;>vL&BX;K#%VkNh!9QU#E zAsKQbw+mTH^JEtgsSd16N)nhN!YpK+CIZka4$5Burx1-?oOHlehBt{H`myZuBU{1qAtenGyBoRmi!~+lpb^+4qbaX0H>Xd%~BnS^!2LKUd z9d{jFF&ekR^mZf&Udp8cYnrvHE1QNha~HC61iFZ zobf_JWCA@|{>#Ng`*B&SFPg~K6wYd!jRuzaJXkr-W0G?$2DUoGITnfDtc(6q5;Jpd zDw(Bm^xj^LIzc$^yvp>Ldj^B)U*tBxoLsw8BP`U1(G2asvM^~d4G&QQOsbjIC~wp_ zi#OgY{*p#AQ$lW@c2J!Cj^TcX)M%OX&rDw-y-|p98Km^OZzKP%1!P6L%08^6A$7~Y zU-aT*P#z+Jt>$*q5zAIk$qCze(>(KTm@P%ieOod!__waFLnd*oykWSzTOz&KCY^+m zhJOU>uFze=wwwTIM*XBir;LIjU3#RDQUH2JBkbq$x?GlmE!E&?q1>xG7A7S1`(Gi^`QaL+@6&@cRZ@;$$EdBNlpKeqt$oLOYR@R(E7orqT|1lvN$ z(tQaAloA{Fhety^2nWofRpI;8g~?5T;BdK3Xt1`TcHrCeY-GA1iJ7-kRzC(^@Btr1 z1;jicf$o+34dZbuu)*|(BLL>)f8t9a4(Ns_$>C zkyto?6mpjSmE+*?{)(83oV3^ zkoHbq9BY~p4*ArJYCtT6SIZ)wNWr?dEt91FDgZu}Jp>9zCdvoUSiFiZK@mJcQ-lDS zdNC*C)N3wcOL}@P#+UPYZ<4&Qwb?kpC5pcqG^{S2Jw&aLKng7&Db38^&_tFO2;>&~ zzqYp6lqGP{v>yZ(wi>b|v&eYX#5=~9EZ4UZ_)!{=+C?Zv*L4~beR7-zsi`3o%(_#M zvU>0Y#WWMu^u1CL&y%-ik{!%Sn)Z;%?sZ>0!&JhydL0J(bv%8)09K>TEC%nXxlK_B zEwHPbnBa1#uQx;VzLdS+vAoi`Tya?Rog_}qF*7xrWM4ffY$%E0%}dOe#bsc{Ug)bN zn36dY=$D6c1V4Ppvu=h{ zPf4?RCPRt{jW0~xq_ka1QK!BrhERtr@du$F{>$WtY2faiSnS&>Btc`gUbmSpM+S#R zPgH~Pe;eWScmUoZ@l9y4WHmdn-ls&06iTXP382$n&CUvA z9w#C-!9v+L&U|R$>*x&>j1mXZPYix$xYi3g9Cey%Bc+;n;re~dAj)v8og@ozd>@yU zOZ2kUC;b-vfj1@J!%VXoX!i66MRqTISXRs#FbsyIS?i<%z&Qc&2xj_w26@q2NusaY z!Hjoat_jtCmfT0TLrfPK&h7#b56qAkmQ0ul(C_h%GVjNbTR_xUUC18rEjr=PQrT}3 ztpG5D++g=h-s4K{3*SK(X<+c3u!bd5Ou-mbGXkbr3JsLE1FYn?G7#VKKJ1r~Q-1G* zIp!A$!wqJNSQ~5#m%)jyD2P6i@P6A=V7)|dYejxGT1+Al?A`D!I=rgYgn6NgMajcu; zd#h_TH2^Afg@#^ILMugZzP6)&Jta0DK&(76k-PM_aBDqI+n$N^OmHYYh3Du>7Pf#zf@nJAtTg zakIA!s3gZLgc9%}Dq%L?MMUpa_^qFv@5BvyzGHkbL5RGT+-+LnDH2`Rs{Oe{bHyE< z8+;Yaw7_6qjOpmn$M*4qjc3Ht*1$jQFW@t0{pG(6 z|BhM*c<4_O&J(PYG{wRtBd$FH32l!N=V5=3?VTqGSng8)$zhT^-yfr_@7Pa-N<+ot zKdZIfU6qQ<=l&#YAOK1YN*@bpoqu23A!`q%Z#{(bqacrGC4(t3G_V@-E3;05g>1|t z_0j$^~&;>9LklqHzlQWfx?Px`S zM^k;aBxqNWvVba9>V3oG78x;AvQ8m4B=np0eP5=>amPc zHl{KvpaShv<(8F(%S2+zYOKg;+4oDx^hc=o>#)e`RrL#p$VSBX8`R5wOqK@wVH!VA z;%NrB;IiSEATt(_<+g;mJ*I{7fF*Qb*A5h>-jAv;8sqFu4NKCWs-@f$R*2Cn#BJFb>S=?A!@P*kY_wW%Jg)Wls^ z=cm+CAKRR*)P@_`+OE`r8`rp^^bUmP7FAjq8~?td@&~SnSc8vOFdv^-Wruz&!(sgE@3$PKb6V(NOz>S%9e(H+#)#*{H<$1rlH6spv5jAd}gr({;t z@p)tj9;ft@)rlUJiFq`pMKwryRLG1qX6!X6j8!OOH0HB4sAE)KbZ9J%Y0!44(4A}*LZ4g#Iz8X%35#5)ZRI0{q@rlbWjt@(YmeD63I~$9oKqT(fTm1CjO}PgsUz2 zs3ygujU=Wm!=o;1tc~iREoZDQAES+tqpcV-HPSxAJg%*xqp5l_!}_SL9;&H9JIleN zqt&3Ptuo7PtfRZ5spmh-8>3@Dre#EV|td^C-+y{SM8#Ha(oH@yAUAwp1_TzIhtGbSs+D?yia(H?!DbHWq^NM16Zv8Xv z#>0dT^K`y?UaS1xIrB7?dcL8GO5^kQy?Oy}3BNw-b!qDbzU+hWEc{s33(@HaHr9W# z(GQ;`h=|cg^s(qib@WDdEZhz0$5<*ypDYM&>&IIXB+wcR!S$2KdJ|O^uk;O4i^tMv z=hLfY({dKi$_%nBWkSanKlK{q?u_L;8kk)f6m;Mh@+=(+8p3F?ij581aScoV{wRrA zdL3d|FYM zL$#5pj8VI>VC(8~@V?Pc9?UL0uz8zN51M|j*h-)dI7J0KprYU5zmnhv9`@HCsRl=O zfXAvA#%H^`#a1R?u1w*rO#fZ}wYvPfe|e^Qc{XKv&VPB{a(O{zdGYP?67BLb+VaZD z((3Gz=bw(Hwc@4qn57N(rA_0dE!m}Qo~0eKrQOHHy`9DV@x_CN#lxJ%qnO2G|HTu_ z#Z#5Vv$u=qw2K#LiLPbqx)z9U(Py$t4rnbrad0dqu4i)pY~k2IdFq8unU~Z{~|1 zp3`!5@66iV;?namwsAUf^MtsXK-|nB9_IGWp3ZKb&K{l+4`-K`mp6}yrzga7ng8Dd zy<1|zbb8U9JUT}+wU#}P17lm#=TsX&Dh>s2C%-{86=m)7$PB*y)E|pR0y&D5_C_Y2 z8g%om0Vo|T02~01Sy)W~i%M5bKQJyhG!$S|jJA)}g9KS517vU0u`*-hbIn6vzSGUf z%8p4iM`r`FzGdm7(J(3MqcV$F#0p^7#d2E^MShJ`Y^weBTX%Y9K5K4axp!rS7vTLf zFJx@8Rf~fALgWQ5%KpXW)%D+hH@A295Aet5TA*M*8!(1ehW{0k?7$j;1&{zC&(#wa z7DgphLM7G|68rdnH-?gul7@!HGgg$eh*I%PeQto~h(Curq_E>T#KoPn<-M~F{YwqM z_nvLrb3p$)eE%Ig1mb^Uho)r;k)RD>FmBBmO6{bCbgX`I2Ue*hl73?V$X)5qn%x`D z3>!4aSQ1P?8C{`{?Cix1CuV{&8&NTun^u~|`UPmCaEs=Y+#dhz9RkA3_`mf) z0Z;&bWHO}xNYDRao{UVq|6!gS|6!i5|BHDND4-H5q7rNTH}=HjQ$ynY{9Z(gm)D0@ zfuBspSwvcnU*U@?A(kp1mL?y+4HdpS2eBfbqKX`*hCIKM8li^@zpo{~to;9?PEA8g zBTHKsC8g)^e6qE-uyb~B`(*3t>1Y4xi{%%0PcLkiaAfXeBt9s>m-;`hQ!y4r9Y$v! zM{ZF;YST>X+QMxc$KqPd;?>UYQqAw(@=QC0K);`9=UdeWF^vZBv-#6Y2{fZ&3OakB{`jY4Wm0_vt{t7yH8fD_Reb-wm1JxJKa40+68&>2X*j< z537aOI)ns!heY^9X1FGQS4{h@Q8;IxJ@#LI^RGkMqDSMN-@xB+7V;=Q@)UNeZ2lKX zid11b{F$F#B-!v6YtU8eG89|V)jP3f7-_}YsXY_U5+8-6D4)_0h2kj9j&Q}M5Y4t! zjhaN~hC=fWn9pD^?_`qNNT&I-<(w;Z*sCxj7&~XjtWT*%1%#&rlqAu zL93!O%cAn0H)>$e!s4*P*8gzM^1ABG?bY%;FzqaU~@s1<#_hzOA9GxTUVT zxuqpIZ!Gjbobw8rum?@JOv*S&&bUad84qjQ&n`O3D!h2^{>3#D&!V%mW469?sG)VP zsPd$+{Jf&!w4(m}N9Sp6+j+-eN8;Gkv*j!woUebjoTD?(ma}+xw{+rf$>M$6&~Z!u zWz+Ay)`fq~`|yFxkg0~Kfx_Z}nugKFlKzI4x%Tq8&W6MGh`r9@|Dv5~^JA4)<0)IC zu;a0Y-Cq?4^X<3u#W(W}kNd5IgM-5pbG^To=0-;rW+tAc=fLD%_r&#oVb6aHO9#)) zbNCQG_V;mm>uBNN@5s($d!M@Xr3+#`z5VXz1~D4)Jf|>2Ch$=;&E`ZvL0_ zyg501x<7t=e0-Lk!~aKm66_i^*XI0xr6(-iX{IdZ|1UjHZXdJmcnhAT=P>^m#*b39 z_#%l%n*WiWoGP4OtR_m;-Cu)+U$1;K*|BmBvX3bnpD zX|O@|7B-PI>VCX%1*rx-=~DwrE?Gu7Gb89QM5~M9BzudDm9@;Y=Ov^cc?=VvB#c(d z_cQAeN<;-Duzv<>D?|5YZMI^@-j@9F*>09Ia8Esv3*jgsHB$_`HYmU*m8MyY<&x$T zLi0BegefMMCWu!5Nbg5riEVZqDcS-#>j!ul-Tbxqe-)|l$G+Gb)N@HhI1x` zG64nVSO_|&jncsddwg8eh1)2hZbXKeh+bhLy??)`LEhIx8UFs@1)=>Zo<_d%D4xc3 z*J+_NKH@ISwEBugX9r<~K(-0kA4#H$BnM@zrv3D=OvZf^ZBqzS{k&49pQX~ij`~#3 zv^W^VbyENBz{V!-Y)3$kTv`Gr!7-DkBC5DXG`XJ?AFCWYX8kg(GOHOs9HLii7!pZ* zyBmF$hmSV;yr@7avYTciTyElT;H7lZgR5p#RuF-_sNP1HgVJ9@K=vjChVt3NF~EQB zeP|D<9c;C&?vEjLJGt%t)36Cv-0KxL z3-Y==TOZz_@}=1S*tHaXjc zZiZOPhb-s6E~iS?ivKJ-sb;d!jAQ~|o^WPW|HL)V?&|0<&bX+V$1&4Z^K@_C{iL7U zpg^AXCzbYir}>0b+T`%ltK930Luc}@e^OuZk}>*I)#b`qp#g#XwK92L3X1?Ma=m3A z*}i!m`gelW^div8<&4-_t9d z>em$O#iAKL!dt$NsqxHF9F3PV!Vm+=uZ<`g7% zaw5W)3Gq-E3!8!*$nY{TeGJC>et1~bhd3@8&O*tdFrt}xnOs6z%&9j#qT70zQiHog ze|3>c%D{k@J0!=f;jL&cSb!y2)=x885aL{QL80i3!J9Tr;0fC#w+<;5C{-B$Z1^R! z?wVPMpi6e8w4o*2SV!WW!cnF*OLCvRF#sZg@J@=enqHtc2l8 zGKi2cIgTt8#%}{bdsB!~R2@-9yi`8m$@!)@5f(%UokopWB7sTZRj7xL$R(h=X7LIh z(5-sK67ORpdkJHx-X&mD@Ap78hsu;~GeKDc)3lsGsPHKl7-6L)Kjv&ZTnymU4Isu_FCh~veQnpR$tYTo>y&Jx!f_AsT*2b?oE|mETKpX| z^0zL1{Fv)tNiLDeloaAt^wCLYk{6YM)j@P)T%a#*Hgzf{$iJLqWg~R(5%qMP^tp@j-KZarW2vWm!?DA|@}*YQmr0`DHI4{lzwP z&3Yi7SG?A4v5pST7D<&LB!nY z^5R*5);>0mNPD=d5gl#5^7U@vquY8XCMl1~mEP^xC$r1PhUHmBh4^CSu%%>c`us?c zX3~7*O~-lkQLQfwr?%o(WkZXKaD$~($i3NW?ndWv;+WFd zzIe6Rt75g4RFu8rHOE9&nlDMHnSgD~eLq`!YE#rJm~+e61q-OJr<#Upd4iFO1kz80 zQvlq5r|a1GUN4 zIdN+DOy$A-8Ti1+6?@xPc4Xf8h1R9{35A$FX@>abm%n)o-1!qxc-;}7uqUpWC<1d% zAOxa}Z#&1ABtD&1jSX&J*4(@i5~T;^+t%6Cypag}U}AN}OoVar1HKx2xi_1C)II{k zdQaD780PcVQkvi*8eo0J9NSMd=~wB~zb2DMWhQBJ<*+CEJ9U|}YSo8~h3A)1Y5S?s zq_@U9dgzav&5I;8|3`YKd*ddhT%7Peydl{6O%HGuFN zl7`sL;B!ML!osx9)N!f-{VoUvrKW~YfZrE_zgo7KTmph zkY_>ky9JA?A<&64o4{IWx2~JmL$b+>%YCwvF+uu0<1rzMUIIGK1;`rrcFJ=r6mI{<*qsU)(`@ zJl2879|3HZ_1KzitXe(WzZS?TxA+k|_}sM#-0?;ne8^`IW7ykZ6hc5{PFsykr#%FJ z1Qz#s1|Nwq+{B&9RXc$qQr`pdJ%NceoPi_J1fqYUo~VM3&3SJA>Q};rjL}vEh>s%) z`!4zLHrh{sHtQxnM;pT8%$fpXvT`*)RP ziJxV#0{QI?Fy+9utX*XIO<`=6`l)y!sW>I6pX=X>m9qUCQr;oc`eKl#ewVI9>B?xT z$%2+pEr88vnqf(blkS|F4#7&x$9H84zS>m*}Y{fpD=7W88{8BIOX(JlCl5Wnx8*=2f;kUr2=9vW+q zxgKd7?2To(pX*49vxjBjS)MDPj_ptnMW)WdKMcgx^Wr^6W|>#Hu~tE9&DI;t!D}sm zFJ{$vTWuVe-7{g0wt$YjLAXAJR`tezb@Hljvnm$~*0Bn=g;McGK#5((2g4vrQ25Dk zA%QULio76^+_njZ8D6SD7NIFvQ2;BCIdujqh6oZDGKU-Om=zT{4y~Isb34v)Zi2A7 z&T%l7Kuh~Uw?ai!3dLkXk+ywy#Ti8~ZJomq(?$iD&u3>#YX&sM8FemScrP#UyzY> zxo>O5iIhCEucCz`sgT5DWW9p+p1NGJr$z&7@cppeR3nX94VK-cGeZS3-{bWZ9d z=S4#wRyo*VmS+!Uw6j+0Naf6JB`Zh809kd?wI+ow`eqc`dUKWPaK*llV~wFo_H=+Z zEc7k|WD-Gf`SzPvH)@M)+RLucp8K+R8T~O3$_p#dS$qm0Y@d1$qNggtfKUioeFGrh zY+&EO?4>xqieJcUaoj;@qi+xHzaMg@+-nDtQ7RBLX0yCT#>#SBCuCz~fX#Z;*(KL; zMLY5!Z~$JMI$>X3E==uFR9$@Ek~MOC6z6Yz%T5wpY?q*VP}>jHEKRXdSj3Rh#yJ`q zL;dVPT60v8j&FlfG+^{l|LKLAh6waodfH?)mT5OyRW@2b5IDYQa_?(Yl9k(LX!6Qx z@@Z3cd#G_oZSsB593;}*%TkwXA?K;o9M#qw{lYc(yg6P3o8nN`1GO3I+mg=JlxS0-37dhXJtiJlTwJ*2r z>$fsasU(UR*B`YF__lNCw_cDStK7G=MYm7A=%AI4;PAA|Z3}cyZvNHQv0?-ZTQ+D! z%(PdvwXPa!yMJq*4Z*EO#@(JLyG1 zDIz`Wew{D5K^!YRH0?cRq&=@hdk1iOi|V@tvU?ltdM&lPh2gyoZL#t3Y|R4QY`A^$ zqOBomY^$WmIYvLfz&aE}`=Kvf>&@MqN?Tn7I<;5&17Cb`eJ}s|xZfhXiS#|~ub1+2 z-~s!p77T7sl&L0w7D_VK@66KgkUeOva_w~mFJmy-uVylJ=MPa7d$f$qa({SZHL`SM{Q*@yK z>wDT7iY|?nkw)Ac$GyP@=FUn#xhD9i+M@eEx%LL!v4NFnQRVJ`zGGuFDKi2C<22)} z>0=XZW54{yU&@a!M31jz$1bgmUXllHwmYt62X6UIOzTd(!VG@R9%3sK@{kguyp!h` zI`OZ{CKjh9zO9qN4`dfX;cy$acOPdg_$_P~znCxDlbVe*KKBMb#b-Tas_oTC{xu*g zB6=Yrj=frkv&{ZFs%%zWKmyH@5LHTDt?OJY(qNKs^%wBYtt`4V8vJt}ksiDlQT}Eq z#zqG1K&EzwGxt?p>MOAsUY=<$QqRrGP+I@;2-&!z1Q74rT06I}*9tSb?_!#eVyYEKy3vnRYtr&l z2!2)LciZHszcX`Tw0a@>n(eqvtyDlBRi-sdQMY$yb#W#0X6|1#Rf9Zf5047M?F_8QOPZUl6ItLKdyPc+9kp*aoMn zBU!9GYo+d+Q6ns02ewmuJFhgZ+%4kUvG(Np`M7W1jXC zPvsIm9Hi#Tr34&g(t$EM4{|?{JWJ0ky2HYN1K7vIq=3V+r~Qh~!{}%18L(eVcNFsB zs2+d6G2qBQ_oy{@?O2`cCHy-^a8G!;`Qdc?3;6%Vdv@bpVQN)({sAB%MWMQAJ6^;oZaT0 z-FKeB|C~KNo!#Ltb$mESH91HBdXAZQj{Wl-ckLV>aZX5oK`ed|{AZk8ycNj1p#FJ5 zvvxs;xL}~aWD>t*F}d9Blx5Gm2MO1ndl_pKpgx-YE zd#_>xM6jTX-bGN9A}SzVL_nljvL~{ZYrW=#@w7*)O{d)4+SDT`*<|o$e-+w(r`RX9B<)ppka(2t@+LlMr zmgiYSND3?`9T_qVeD=Xl0)WSm`ByApk2Q$F0KLUqajy|{EsRmKpb+3_uI5VIPfLd5h`QEL&h7nWSj!FnX4g!vOa5`*Pzjt~E08S`_pBTpXK8$BZ zm=uSZW&lP95d=NOXYZ^M<7?~>#c8JE+m`EV3=% zj1B=mr-&4#Ve}po>ibWI?^((APs8Ap5E#awr0wd=(+bwbiwyKve|C^8Vwo5LvNBOq z#P+|No~rAv!1%qY_G@cbA<&@@Z|>MaDa@Z}TreuY>1^oOi(wtc)c&wkt}(Gz^{7h# z>RZ(_o##Bph(1SPt3ewboFYHl*l)^?wha$nCZ|R*&L$ehJNupE>A;FDE^MVQd3fZ?lCvy8gY^yxaNHh zNY&?mSbUrNYe2;CJ2+8~8Lu^Uv)lUo#sULPJCr8Q+53mNAlG9Io;T>bxh}!+i+#^< z44Q=?n84y-(d)|DMl{vCd4J2!`<@j;XCc2RzDxF_ARvLcA7R|==eZ&~u?j~zMxb;S zi%(KNU%77jMj}?_9kOk5Q|Vfz@jVkdvW$_O@{>stroV<8IT>U3(XTj~rZma!yyEL% z=OlGy$)jZ1u<9hZYys-D<`Lu_e7N^FdE@Z(%`L$&C2}h_bkM#(I_)f&y$q37;ArZ%@B_nf!Yj4HMZF4if(8DV*C z(+~YRl4dZy_$pid?MKJPy$H|iA=omJFol!~v1>2PJ;)`G{WHts1#%w^tZox~Jk#=)2?#q2ZRr9M6 z1gpcQiNtgXIhQb8xw`kU=&VgTd+8nVs>i$i-#1Aekin106Ih)?7ttsHHX;C6cHeqL z)B_xA+3}^XB!Qh`v3G0q6nwCcWLR^ncz{CWEL)opS!CMSAP+@BmSz-cO!2*4=NMQC z(&e2uJGC}7qPtPTl#0<4lu3v~oqoZj$~WwzN-{ShBlR*x;G)_xam<&3^<~`Fqc2UR za6H-3my0$}lv^64?+P|hsx-fD4S&u3cE>=q%RI@y+?nrFw(iwg^W@93&H_Jn46)P% za)gMBAVUaVPmGX~;Nl_-nx1$ALTXyMi|8RWqgVEXw7gjtam`&LvuHwknTV^TbWX2M zqcHD+Pd9)2dXoP92i^#m3d!>!$L!|`S&wI35A(zs<5q>k0UHbc`>7F{cDm}}4be9N zGQH-}G8pKf(!^3)nL;LMxl+=_00}Jh*=URW4BzK#uvN9yo57D*-n#LMfmaiYV<2=23(F{+u}8I(;-8%2({OB-2;i8DeB>3gBMUk@$;5d>T{kaAaQ*@ z0EYMKO0^cv4U^P8Ux6swMSktn5$&H4pvSwM=S5p`(z}tWQ*&O{PbT_V*G1p}`s0ZW z2`0K&QgXi>gwB#k&=g|lzZ2Rbx9LH+z3j`+5eqTRutQgGIP-Jav>c%ckxG@aK%8~; zcINwLLou!~sBu0djgPGxeWIEm5L4V@JHl-ZWD@~scBR`c1OY*FG&qgLh;zutWo-?Y z8$2sB;vwMCp^io}QQjA?d^MYM*uf;0H#-sZW^CUC*aL)AQq7PcbHQd#8=YvZ7aa0@im$$p+hxIPex% zQYvO*&(-&tR4yUCXrr%wzt_s8S-&Ha1 zsKzg_)c1y_o21_ibJti<^Q;&awjIA^$hU2t!{h*$Tup$R#6G_msxhB>JeO$oy$z;e zAnRb*yok%S1a2Y`=G;DRnlW}GjMQSl%G4b8i#d-6$u+O?VFNe5z=&*q72_KsX7GqN1K=Hi>}C(*d4h5UMTf*RhgP7hD>! zOcOu1{3B0)zRV=dVC%G%Y7-euE3da^>X%RVv|N4n!{rZrpO1tUW30u^Q^$S^GH^6c zQQckSkzW>ULrmVVmsv@fJ}$KL;1j%8+V=a0)0EI;-z(6k7@E;5LJEVSjTi0El=Ghc zmIx#LC-B4MNOcpPf}BrG&YJyLsAWrJYwMZ4m)dMiTdY5xX$X5f;n9~FfwI@(Tx+09 zy1}t-a^0Ugt?wVswp){bR|qpD(H5$I{dA3T{@K}9_-qmtTKmQtjQEhmvNT3hs1|p1 z5l-I8YZ^;=k`s5nhjFo0oAwrVxc2E2Oz~>11`wcj*f+L7t}LC*%pgRAXr>vthh?{K z&27QHCzdkE(5!uFAvxr%){;`3(Evs>9H*V&S;_ zw9-@=8NDCH#75i1(oipz3Qp?C&N9L#8Z?i!#Sr5WL^w1&e#w#crsqS-i)oT=Fg2rO zPFY+Ahf_=XgJ^hdNuAE=KPLK#6k#lRh-)1dhiIXT>PeboO+YU{+>pi{ z=Hkx4>yfA8wI@3;n+Pv}nK~{WyB-s)icGDI@%UJBEjuRAhbE#JX_}~S%X>W(tzxwj zdjuJGDqsK1N+(MlwZ8j-x zM=S5iaVyd2E^4#hY3D#rC)Mh?8x82rNW9QGuvoRMEI z4J)UK@9i8BzO`o&_fA4D$J=->MRTGoheE?O-SdPjf_*1^s5yjNVwRD?hE)$^9AWYl zwx{ZcMwFt_Rrbfe)jdVDXlV{>L8r7ne`|Tl^~W^{?R8|Urh3whMDr;b;q3_R%(0?c z$73B~#y?I0IB!kSX5(sf3zt$$HycX}eKTu5O(ZeeNIkFPyGhT>KMIFh8d7mR4SG;` zD?JMLSg?{611TvXGW6sQc;gsQTtfrLZ~NlNNElk?Sz9-Ki+COGr!lwdkjArPa;!e2 zuoZ2ATX7$VN8jcTo|9}7ZlGlpY57iyUs$6Sw@pPI}W2L=b+cVaD^ryfyl#dAscO z7{3OX^F*mSuyqwmb~!hj3uMF*{~^su0Pnz$3iK~&4vj`jQ$s~WM1QH#O50;43UOYZc)9sEVmIV{+#g9aA z>+o5^*rkvOhZRsdatxN7ieiA6qN%PZKrN!E1SsX4(2-|E2bAW}>4{6$l$jOZG*c>R zYP701QaS=0saI+5=m0u)(I=4+Z{R>4O*4DOdn2=f!1Cm*nfo=9G&tSbIqD%g zxsoslgqfKti<*fIMcu)gE5`u9S%l;ds>~1m_hgO$pFj_i{V(Ydlt5XH1OCl81PhAO zcLl9F3;WoA>W0;iM?lf=dGG62V_?N5T3*bwjm;mJn_#g(_3%L3{PG=4y`xZ_Ef!01 z@hqIHy5s$^v2{9Z(6^!BO29=b%fsv#32#@9R3T{#fL^w}0)oNj3Kg45LrKPErI^4yqxht;3Uc@P{zO< zTwS0JYrshTyCh(|q^m5Wvm8UHDC;G;eI=1#w4XCcFp~GiqulWF&Q|i5jpPH&<@Yze z5y9NTT;IZpV0GEp)!*99&mthy&%^|*Wsony)7#J0H{d`|1Oq2SfzZ zktg0wKHpV7-&elEh`+*WKWDP|Jl}0s40w}!5+WaKqMLp4c!Z;QM1WDcD3aUUXXJU$ zi-~vLU9VsEPmGO&CSvdS(#XVo@A9{2Uw^!r{W!Y3JG%8_?oIc?o5|_-);+uc*nD#7{&%A$MZ2#qY%B?*lLhpz?V{)JE!F=OHK|ng zhbE9p?I4cgAqv4;AyfBe6l}V@!UHTwxVb%4Nl{V zc(YT4)9`x`Gqcxc7Oxeg@;_b_huHYQBYh5{CRsE;pI7BB`9l?$WTS^WWVIbT;mO1t zdokj|)PB_DYMSng&+prjl;$d&2F_DCV6nE-+U7|YQ#^yEWz-NVM^45iBMYj^$VLx_P1!fovO^ zGU`JU5_;2kiZYL5%o(qbw;z7M5_q@y6WVz|;##)b6W$!le|Kwwk+krjay2 zGR>^v*@yd4lbpLSLxOYUu5@uAt;nm~X%`=??bQL>q5BSdUr5k_TpnlK(B#Ze!>gap zG>wzgGHWdeP2;-{iZ0Lq@Zuh)yKFc0X2!6lI4iOzV$#W!?+8c3`&?*A4X5;?#@fz6#j)3dPg((Ekl zi6;V*bS)gatpS53@bUJTK1+(?33b%2|Df8k-tDak@57c%NTVO9#w$G#OwgO)h1*RA zqaqZA*2#drp-#EWoELVcf6ZMds;utJeAkoRolUpCusfISerI<+KWKG#p*Ti%Z?Qb< z!roGK)t$ZNTTQEb^Qb4X-&Pt%FMRv-VByZU)#mMYAuH52Yc$$LHV&k@Pvo>D^|Z7v zgNwW6_jWg)T3`I}b=D zKejpBlQo=|F79bnwY>k~GW-O}y+%Zu6hp6Vqk2W**co>+^%{q4*w;Gh=j-~i#e#ruVF zG@EX~yj?ymO%L!`PY~O4;!7*jBSe}X6_6^4`(v$B&ZnnSHgr9~ene0^*hWpjkLg;8$aH$tANhs)hq~zEWv<-PA1D&S%rZ$<-#HfarNNHl0k4$SVpS z(zyX9$;Z7z(MQvx>)z=!l5BOAiydm}`wd=)+1_D%)j$620Z zAuns}zSi9QR;Wi6N34cgRd3FEaEms@%>o(axgV(k1tT>9*;fHX55|)V#-ooEh6GdI z7z)B~^z^!>`|*65k`-EDpy!<`4XUl4=f;gNDwF(fXX_iO#o)6hKmqaoO~$wGLygq0 z{8s&2#O-k>B+_-5rPC+(jJ;xnC!N@1kn_fGdJ=jmIE#whvM$I|A3DqCA#x7G9iNLe z?Y;np!F4lzZX}mYP~&jndrzXQgdqYbCi#T`$*^iEwJ>gy-#{nTLiV=;Mf&aLMc2jc zHcpL=Ud9xl8pr9fq&r?R$M%YaVf-b9}SrQKmwjwIcoTLQC*w=fjD<736nb%}7g7sax?T5eeSC~~(3 z43``_CM>nx(%ruq!VH9C<8-WZwSVSV>N)A&Gy9f%z7PUXg$mxIB~@8-O_;@Kv6Wt; ziPVd&97Gt;(wr(T+9fh`9f(7>LB;ZjqxXGJ8|J&jks#bner zkUW@Y&uaU>p6t-8QYi2gtTv{t=|1k0m67LpZ_VoNCw8gJOL5biKhxS|DnCa^EZeg6 z8fq0Xzl5`Y{{UB44R*j4_)6ZIrclW7{wr2Bp*-bGQ7I6*<^U3k=#9D4ht$$qb0dGV zKP7ackMqGimtg|!Tzb;=I*o{1;Uc=4%W;R4 zANFvE)6hMrRS#u?_PF{tb^`t7OD#e`E2>MWZc|M@zzBlUB6VmO2FMGbloS+6Q3ULuoxC2!M z8lQ1DG36=b3v@T;Ds+*<*^M*U@v!@rJ9UYh_ZE{M7-UCA8aXQYCm=st+j&Ngd5>CF)? z$SriDpIS(0!+Vv0`r^a*3~a-q=<2&9CpehD)7on8Neq=D=~o$({val>+APP~k1osavzQc9cifeF2uqc~E{ci8 zKV~n*pWT<~-SFXzo%odCI6WP|0-?a-9!}}*xI+stdS)(IjK2mt?j0nw)+UjWIRKCg z5Oq%|>WXVG4d{l3e@KCp;l;U85!ly?H{25^t3&E-&<^g`2RvdwIR-Ab$$G}3Qb>Nt z*u#rmsApr>HzX9Zs)NGZ{lZ%17~A7e{_#KRU7pTR&B`%JrX{Jy#>47@>04>qGLdHP zRP8Fs>A@j6_~g7;Mdc46MkR_G9~9#@4!y@gC}OB8711}rsAFIFS|w6yk(cYO1shaQ zyFSV;7O2K11vn+;vdqIYALg*BuCPwd6b-fX^Ce;JqhS%c>BbM!O~%trchk+dG6-rJ z=^IzHl&|U-WZ2QT;OnkNj(QH-uv-gWGv`S9rjqJk0N{4-@vY;bI&<|K2U^UdYw@v6!W;m=&>Dl(>|o(8bx<*vzGrn9*40 znTw3fKETJdgl7-0yqAzQ_vNena6^AF3 z>s)NMLCJ9f3Wom5qf*jbyc*k5yCGK=Bm?wfk|Xfh9rXd+Ljmyh05kDRmJ0>kDVLbM z3jJ7;`WJ&-V#w|>NwsRIiiIE_@gVx6MZ(5czCH+2&@I_2O(rcQv%S2E7%oVUBMaWs zNn8jfi-#Pkxw1@1ajb`M?((U?_<6ZP`He!q*rvV?Nu{m}eJ`(cEcZ%X5X(K4Y?yDF zV_6!*G}GfCMmO$C^`*3d5Y!GT-6yn)&M|#pAuL!b5(4>~9H|2904>1siyVOu{NOYE z0g($7V8vpwx(4{;$B%FGoEB){+q=mre%T%?f?lLAh^Nx zpMNvA&AGX+pZ9^=FC=sTdj7Bfq;|)mB-mIO6WWPHp;9CqZ@wV87@OEekBK-E4fL$4 zm;l)ffKoBDeARnmpBsS00I`6sMC)Tt4jo=Nga)8tv|+tS%W1<;<-v3sgZAJ~7eJjl zO)$2y#t1oK-JzXu3e1KEK_PSV0OG{f@TM%7<#6rzI9;`J8;lOg^(*6a-#XHJ_ zkRa`hb&`im!r92bVQ9uaZvr3jK_psS)38rP>zf;&Hs{oIL_D6k+cg4SA@I3;{~|5_ ziApS_P_hoHR?Z+Cd5q~sWxrsQRCQBi(MU2X6%#cP ztpOm_BMD|KBLqUk31*=MYFdsX(sXp6!nJjyEROGRDCH{(niqalvh zvI0D&f&=0(`M_MbJGojboJ}p&#V}3W+>Ra!AZd9eZkQFzO~a!ZL>MeR%%k*40H@_i zN2eJm3H$dB)d7A2^nbE+K0dw!wyUnL4l=j{ml6wyTub{% z|I1Ohv_I)>rqd~K^0|yy00P{GzKQ2OufPl5{buoBxa}`!OZol*MB8l6XZd;d*j>ViM6yfblv6fO_$P=#~L3;sU3o zV?xouFN$(io%+W|l>gxU;7B{nt2Is|p4~v77 z;@~9yjkXaGd)K#*{~i|qPjtKe{og0<|Ly(%pZ`kj*>WA!*oa9z<$k^1;cz4p8IG0E zw2F+0gE-_9%iSDt(J9<8A{J7RoC|Y!7aTF;kAt>UhpqYnm;GrSg8^t1EtHYy4+ zULO*KHIR!6#(XW1kMkPl^x0!JR;P?YnJ`Q=(1YszqTa>;5`qL!zo<93_`sD1lXn5D z_q%8y?>->iiFdj{YM5Qy2^I}3*Q4II&4W|mIs>B#_LtP&KHB~tia@1bEXo#N!4~Ce z?t!~e1INqJk0_gHEWd?C#6Ac23q8=oWUC<;9}b%u%4UNgu@#&)meEOvnB7x`9b`t1 zx!`SBsBy@@ca93M2K<18{WrF)dQ^R%Z6D0k^9Ru!Hu@*nmOX4FcQ_P<|1VUVAh#d& zaBy@I$hObRqW1B&IBS3$i~eCFGeepKyzPl+I&bhN+Xgr1F-tci_e<8^ewKlumyYcp zpaddqcQ-#bzrX{e9U2%6^6cLe_elIc&t@=BJ3!j-Ur3wNwFXR+IN;gxzKOzqH-!HU zX}iV$8`3@>nEVTA_sYlgfjpZK|74$M=idFVFxxx7&$;sL<KYkt4|+Ysm3G0BjIl*Z9fb_Z0%^HOQ?&Xq_Hn9Cyj`TE<9eU(pN-GAEkq^tQi)lUCKwQu%}Kj|B2?tfkR z7uA09d;y%MZyw#c_2I|kUne7V8wA_^1O2_vU-!No+Xvgv-@Sf0I59Q>vhBX{#dmKO zdYAUu_QZ#kS4%si+kdg`h2F(^kZr%-XWO4%9~`5!IKRBO&$d5;-?z5^PuO;<>mUBR zo6L#b$)$gU(SLd6-Fxp(wtaNCh!?=aYFRxPh^X*)z@pt41J#R)H`s!SP_L0k*S5*Z zyP?BHQg=={Gylo9)#f2)dXo*N>ScB$DXS8ZaX z59{apvro;m7dtGpRa-DS>Bc8uDuBm>ajcw!U;Z%0C)iGg=^gnPkmLUmWZOY)&o1+X z8!Vmxzt>R-3kFvWrMw(Rx9t>~K6&&tV@Fj_c0hkhlm0D@4kgdAom%E;%krT>Iq#_> zps_3EURbLNIKl4;lb`wA+x!SnOH2`2^y^Q1C+i2c5Hc(QTh1_Z5N3;l^J%t$@RlM^ z;Fd$X*eWKS0cfRB;s%_RB9o~RJ#w8g@GglDiKDk4oMxfyv?of!>04=~>w`I7afYc` zy~F_crc%Z`GXTu*Ws6P<#eMZS(>hZj$6Ht&B=Dz6`D)XPeH3+6K=V$jE0e?4?no zAA7Bxy&3fbbJ3A;hhWA7q??oZqBSwKSiF~=izmIlYc`s7)Z0JtCkp=j5#|+aoc+!& zE0YQJxFQ0eU6UEo_=HV=uC}}x`enrOjr|EE{!_8iy)H=crB@Cyhqm-zZ8EpM-hD#W zmve6VwDrcP`_T4e!07p)vG23Dx8H?rQ$B6KCn98brXv4^ZGRwxL7*VpmJQL%{5Q5u zmlQJnDG_AWmy^E?&g_;e?krdQX4{X829qId_HEBa+02T!wS3ts9pCk#Z>SuJp*i!6 zrf&TSt@z69p=6tO4J{^&2ms(%|5&^5b9b@o?$5o*Z-dENofgH<-vt5K4%u5CshZkD z)^#eIO~`y9@=WCEX48u=YR%*~yW-hKdVOi^Tj&jlY!0=b!_fo9)GDfK+w0D}0J{6# zq9cTACHdm5Z)Z1uW@3Tn(ug(@GXE@Y4#LrMSW9<2LR#Fn-pn8b{Xss*VE^tx%@g63Yl%b z)DpuvRO4to>gl8cS^+5PDGVii(FchYGJHS+P%!XtrBl$fY{T-f5}$92REK{~-Ip@h z$ZDZ?Ly12`g*vpPN@1beTO?WnJqCFL8zl{%3uCasB&pML1{3OG!n@eUzjpTcyT=(TPoF3&HO;A^^PurHg$hHL`exXA_#MviR2F+ADa4 ze8}3fbF_jNldwej?~P2#>59IeJi4V!h@GL}a6N`WSZ{~9{g_Z^KHSRDI4ip;GL;Rs zILXrsErznw0{|-uC%fl19H@}Q&!b8_p=&%+%FXV(ZGwNt(R%{OCzo^Jmw2rowT1B` zYUt~UP({X} zulZqX1}S1rkBSx$UAxZy(uCLSaNp~$qm6|ZG-Kc8Ho=8UNA3U~EuwbjW`L3)8!;I3 zCI7|HlNA5zh!K5(6liBFyAJdY%HWWO*;qGaVykf@@fI!#0adg)d9f?q>s>=^x$3Ka*M@5@t6!!4%pxV% zGH-*6Kx(i@AI=VE33GuFi#epf-I?Q}@Yuf0794%a^h+4j}-V@?XJHxA8; zsnz)=1`T{jMeB!L?&CbGlSZzwpA&c%i-UOV#gQUA?@5>8$J?w)V%s}?He$bkwz4Gc zN#s7z7A7AFyU&F89oJ^_Kb*kpO`(#<`)4i;e0UaMpn8Rw!4s*IRDeHb44@PQzOqym%^0?X8)w%3ObTpd_6jbIRvLq+R6g~^i=t27pJEJI(v z+YYyC0Z;wN;a=zCA@P;m79s-P?Po&i|s<1uy@`m`EqO$i;=8r1!tDT4MCXZ{77 zE(Cx&9Fd4O7dK|sTNZ2&U*CJf@`eTA1vBxlEod zIvZqZaAv(D)RVyBtOqIKL@&Ay?Lnaz?Bs>#pxM&rry(>u=9_hv(NUY!F7YAAR)*RR6IO zIY9vInI&o-)1BEUDXa% zCwot_gCSd?|$R@A*c|T!IFH%i1gE@tmMGWA5=at-C(uf{V_`)N_hiqc>-Bjr<~x2-K4|6{g9|xL!kQbxxHkV!fg;cAMF=n+`X=e!d9H69uC(jXzS*(PY+O`T zQYn;CpK~w77~KP?Av`*qzK7kJW2isvIE}5Il*%@-!yQ412 zor`&J2#yQ9up`s?;Ch0N!MV}ErXKmvg!ATtLFc!aE(M7Ja#S(yu;lJY8*vngGpclm zruPd_NTiAGxo*9KMyw_6mdFn(gjgdK6c+rlwelr2I@$97*4iG1XO}+PWkt z_+;gbYE((#@8x*3aHP3O;;BliKuD^de3)~5+YSDJ!anv!jra!A@!itm*p zjaSs7)3k1&W}1R#vplWEQ>ap|9!qgKRtY^x&EZs+%q;H;n7L}-i2Xk5N^!pmQFViP zxXBRRauiT>J-%$~ZoV9uR^!R}q!j6%=*!BeD;$S7iM|*Q=ICe-d{(CDqDQb>`WiAq zTsKtVK?HA$XDH1T4OMUxMa~LF))+*tO!GftIX5yEbbl-IGz+tN$+?)_Fk7_ufP#1R zi>Pku=w9XMfvzAp%n5l_^1?QoR1FguADEsi|_4h-)Bqtv1$oX6z2Fod_fu^ z-rP4HoU>xuVR|bWGvP~~ip!g!0q$4(msMvx>PY|-(DV%B8u9r;cm*!iqGv&g7Mw|8 zt%)|lRW;<0mF>>toUU;UDnJQ9Mkf@tvPuBjx`6F7&nv>MrMH zcuC5ALyqb zxX+BqnlnfDMGK-HNnnZvGpBBCAoD0g(dNO7^A1QM&)X1p{{W8*&2cdwU;8Vt=3kMx zND99xrYJyAh_x!sXY`fB4;OAsc-})7G^!R{M6;8s#YTJO_k?OEL&{Cln4Yzm>piS3 zJXv%nuINEWw-U5);Pk2IdA&J;JZ(LRHM3k=Xa81gJ0l zCp=Ep3}%2XMvtQgr?XTNT#L|`XeLS~Y;O5Iy!63~dvUpXa^{dC9n|(sgXztZDT(_6 zp_k@kZ!Bh4AxL#H9(huaP{|lb{Sf0T;t@$?qwRd~ALeC62!P*$tQHy~7J*79-qG2U z*9%2uJE2{OO@*1E$3jyW1uJ-sDpZt}7RU`rZ^En}rJj29P;s~7kKxqf{;+>`CX4|D zgb}nY_k%YN=(;#RAE*(F%7btnOyJyiT0y!FGEid_(m+(`w?^!zzYool8{yM$iFeiIQN=1uyoHW}u{ww43e^F1J3=Jz@X@&^gg+kX$O5vun!SCR z8q9+l{r%J|qMD*C)SCaGqbC452nuwE_q!Me?y!Kk?C(Z~oT9RdhPH;fipDRGSW4OZ z!1Vmx&N%1~foSV|K`;L13DTo!FvjrD2Ga5m&=Z^( zEPwy17UU#gdjjN#2c3xJsjdT)8?=n~72~x}2R(>imhnEb{-5dM{{SBUfAUv|TSWEn za1|7oz@rWTT;WP6?zls2>OI%xQ6rYAhME~J-W(itGAx$Ah#v_l_HPyx#)imEk$OG~pVl{w) z#qi~oPoE>OV9+WS*xuXP{kE6;^CuOXD)}rfg36bOhhPnG0s>Ha?3%L!6h3|EXy>3O43c6^ZBWJX2m6W#A-Nzm2HRa= zuM5=9Eo}lo5(*fUA1o9Q@R8FpK}ZKe5-5^dIVnKq~)#BJWfL2T@Qn&$X=qHFMgiR7w4kGnahpSTGL(Yq4q}4MN8NIMk?@ z%2C+@5UaB-=SlK#BqLEb;sq53$Uf&lGIHZxD!I9RYTE1Zh*F9X8qOv7Ygzm<%T<6q zkiO^t2Yr`44E+avcSiCD{ijy`i@sm_Pp91C@IHP2r&bPf_XDlmz+hi1cQ#`1H)8pX z-gR~L^bH9FO9GzYrtjnkm9{FId^MOjt=%-0@$i zznqww`3uJHH=IGCJU_h#B=J$D&3WaG73pN~2H#W~2Qv6yTKWAal@*PR<^KlYLHZ8% zB0>5NqW9R|ubI6c577Iq-Zzi?Usd!i9N6T)xckyRcmLZaPwal2148%SN9CRO8b_O} zf2-u3PY1?+L-&7E$)8nBzW`P8{ZQNQA8vo2dD7M0)j9a;Ux@qoK5_4vSQ?xB%O?M@ zvTu`b|CpcX*|*6T`xf_Y@>ky%yT1K9abNx?asTH%2#mJf{?raHc4!6K;j3jaC5de@ z6F?#f*@Dm_F^j)=iJC3xzOrk|?()U_EH8XftH%C@91ky`AzPnsbgvSOw)J10{7v8Y zqiypxmC^9pIl*>0DMdm@g`CjHb!{&N*pS{_Z#wSlLkM}Tdi`kz-eOO=Zj%B>5%+d3y zjpPsgf+^>s0W6c5^R(>665KWDB@XY?_omP9Q=7zWM!DM0jRE|@p;62LyHz}G8$p$U zn35cvIb_U%Z1GHXGL)t?D8Hz@4=a0A@(2Lv*S6O_^cM+eE9SIw>j)oKEq{nZGzYUG z0MFotZUR&Byt$zLr=W!6%!gd5udto;n2tg-b~5^UcDD0##xK1bRQ(zz@|+KlXqndi zT%Km3`60W^CR*t=7;URc%l;fe1*t1F-b|z-CaZCH&ZgkSxYCuv_0~Q(Dg>-2q*|Wz zoXfCryD^t(AGie4_h`xaY?n;W`5ceR8}qr|Cv%wMwlqct6IGWigpPk58lNu=+geJ~ z3PiI3Hm^>LPn=P7_1D2&qA91BRCs1VW~2S7cS1-Q07&euJ4;JdXZ9dOmUmdzc$2!N zBNn1mR&@!6v%{1MvXVa@VR;0QsfE!{Wl$~OZ4v4vLqo4p1Eo^av@H<@l2I+-*{WaD zG-f4SV$Zd@-MoFBzW1bsUQf6Rhmin|Fytd}->uq=aQ@@!<4n=}BZSpYicHjBrA7uA z)K^e+`cFG7Zo&#^^^QAArHJbZKhIRklrud~B;HkJE*EGnp0Ogok)!qStPq@=NNW|tbT^ld8U!cPeHn%8y_py`68vg_T7?kc`x=3=Wn-bWb1 zwlLP8*Y#RQ0oZ^v)(Q`gLp3jByUb;n9<4>mjGHI_R8|&brioS^a6FYgTb?r{Y;5tO z1VxDfqiwm@WAP?VDQm4AVqmnbSz;+$6~0r-Zav-xjJ9n$pzpt;ZSh?SxnQ*IEg`!X zJzdKGh_;yV9zV2^%O$9sLIUG0kY|mMT((U5+Qy*vWT_7mr=~E9m?uo zDoi^=Cs*H2N7ZSlL_HK?-S(vv{jA!6Q}RR@Fcr6xKhLhadqUz}I}EUau`iL$#QA5^ zTq0wrHy;k?PHa}H@_n!+yOG&|ma4N3rRp+3v^aM=l}ar{raFfXY!ySEc$BKeIhafI zu|Yb5XN;2PI)cDH1;bk>i5s~u>vO-}^3d-;c6sk*S93e`%h49OHODxbmLv2dVPK!a zryqulhzmesZHiQrPS*;-;PItu`h6Y5B*%o+769-ez3#Kys{gDp6!>xLfmI*JPikx=}EJ=X8H63OFkWy^@-|S_nw>efp`p(Jwd{$}{kOo?` za?o!j2%|;E;cGtYy>F!$@3(J${mk)sJ=IPQr0=G6a(rP-6+3L@U+>GE%R?LY&3q`n z>RQSR^?5@X%+5U#>?BQ4e<5&lrw6YkE22pgmHcA#sS-67raDdg(U`B-^WPZpE)908^QB{i$ce0TA#n*ZGkVeWH7xj<5n`D=Z$tjlI(Be z&_oCErycaB-s=PrxiPUej(pQi#nn5=sgRtk!R)~X^%&c+&_>^C;DL@_jz`kP;0W@G zux>GSvQ=BD-OJjfueLF^1IL8YuCGjClkE=a2Nwt6sWR`^#+*KhSIA1u$CDtFW3;?_ zn8A}#5RPEnir1-cm3&Vc8=Ibe^7jAsW-94EOZV|rzr1gg?x7Z%Gv#EpuN|gGdRZSW z+?L1E#GAb~w<_fjoxalZflU!Z1XM*)Mi3%FuQytpi2EGvZ)91nz+RJG`Z=SP7P!OG z!_({!>*z{6*+^?#F*?7ND(z`=h;nPkFuhZT#1=6PHFxVrytrAUdKc56_;B$0$n8Ah zInn9iB4Z^%`{e46;$JXCRANe2fqH?~W-(;I+V61c=bL9KEXP}@4Vojk+{6&v1v+i8 zx;i77%UCAEPkui)8^1*h0%W2rBWwM`@<o<2IRuawz7X^8Z@p95bNe~Ngz`Bo?_ zBAE2H^ZBXHZyQ;Y+8rMy4NWM0f&qI=dDjlLF||mrrTv&VenR851!_wxHD;Zw|MHZg z=F0Qu*UHwEfV)`nPn^sjU-GW9`hAnrHWjqBnNnAu3WYNBJ2f%wI3hIcsu!@xn z38d(#sz%xf>FRvYRo2thdl31*h@e;h zFe)ry^8Bk=-Ci5o#Z@}iRqaP;HlCk$Q!t(OQ(C8| zml(Vl2kz#3= zqPsj7oLRs%Im+Xj=BB*%Npga5N}@+fa!N{SOG)MBw7u_xMf}Cu9~3b^T^6U*M*XdkHX;smf=v} zaN{`|(}8e;wWoq`H$!7LHz&723a@RICu5?|GPIvnAtODMBDt(1G4`JcFt`Ui69`fY z#qJi6OUb+{QCO$&u)ZJlGAW8V#p8=;f@v=ztBCD`VRV6E4!QV~3p`&J0f|}>Cr@iH zPG7IrwO)}uNSc;h#lu+a{TLzqnD{{NZ^hoJgHhbRG1Oael8bqK_Rr^&5=a?h->JB; zZ9P9SrdU&oo*2m2P*vCxiGPjEmoIrL>LDeOLPfD4C1Xr|_M>3OJ^@1EY15hjcS1+7 z-#TqX0~6>@c|XJnjI8-3MX~Q){2~>>L^u1y^Q#;gj^;$@Oya#CeuPu>u44Y_fk`1@ z3f?XLbQsCELga4LmfTE9)*4J!QZ7xTOmP!SDLpH#rYfryFRM2xYaEu$T6mm;Pn$P{ zDDWr~2}$+OEqWvx!abSFkwaA4rzSlQQ-nS z^my2ovSCJC9@|KJf6es=70RTcD=A469I#b-WI;~s+btxRfiIQ=26`(k!XOy+h-O|iDw$qXe$*4`mnPD?Lx`^>H!tGCO`5{7;tTFJB_j@)U)#A26eHoWHN+#5kh2Iz z>+I=yn%VhhgsFuX`y}gVqU-3ez$AfpS0Tv#m^(<(+Vc3EkIEjK?jCx>QC~%K>1v#+ zFcaAxkRK0><78E$fkHtLu*0mpF{n1-6^Dsf8$g+kK?vT&EJV9F)_ z9QLAQt(KO7+#!jxZmn>|J|`qi^h%^?!k^r2n?}Q9%%xyHe%(FwY=0g z?wmCky3Zc_y}Zz$BUR4vdz<*YxYJT<()ntI-}d#Vmg!A#Tx~iokaE$li*b7n>GNvOI6&YT?Vm%PQUZMy?;7Z^(mXrJ6jtWj39;%oFEuBz0DUKo7TRcDhaP7_Y+9G)YilNA0ksPT50olA{St4#?l_+Y0 z`oy9rdXxISO}Kd-^a$zsQ`K`KtoK3u>&5T+KaC{8eP)P916C-_bN^UTPSF5s(UA3i zlV!eJoN;!h5~TKIx5KWd6-|p}A;rxJo1~n?L-7WEteV^<(5_|$&%@)|*U?=}l6?Zr zUq%o^@2IXOwJvMB=bZX~x0$&`mW4j#B7p}c9 zmh;!PP6_Fq@JCIAhD^zUZFZzcc&f!|7zKbsAI zqJV$!i=z+^s22g_=pY#YPNQxNB%Fu-V`*FD0W881ApZ2E<^9MTD~h)PnpxatQ&-#Q5nM;aPMM zF~u?Teu~5lffD2;#llKNb-3}I1a$z7mL~5FOe(&c0=NC^Fhu>cSRz1E?>I421XpoO z=GzDjXbfXu)?5VGZV+EziO_^G=fhc1{-{I0Te1--971kw?rYr5BAf(BU&3SsO8r4x zfR2b<79zu&n;nW(WVbw6!-S5am)AUHuia3NXVlIiQgJR&N}@OI(TkHS9ATjZT$>>- zst61S1}Mz8F7U;t;H1Da=`J9}2MAEbDEdE6oh`rtA^I41n>%1-#k#!DGto+gQ}V&8*>mb#k@=eL+EAgqcwx`zjEkr zej$Y4{9s^t>!0xcZ%GZvj*id&H{taESHD3V7nwc<1@16$0PQpcHXU*&i`j*uaDoU* ztau|dEgVB-Zv?(!gLe5VVlF;DIpx8f-udCU*)7I$z{Y?J!0FJw_$ovIHS2wbP#~NL zi##eMEbfH`=)#MK0El!#5)udmgCfb7v>2Q68Zo9NJpqjB(H{W84&Z?h{OzgvJFyQ{ z{TpDPc)Z8iUk0RKOghu=s6d{{^SdRW*dtDvXG*wYRK2yFyI>ryJY&QE)4C}UdC zdh59axg=-|Y}-S60OeP38bCmbCMYH7k|T##f}2^&f@T2b#DW}VjOH|Na=nzs=*skY zg``1XN({8(|{lW zuJTm)wwltvv^1JG@&64WF#n3~|7oWAjS$?`_`EIoKz;yfX+VCUgtGbNqyhPX%P)Rl ztNm{X0Sxp1LI_TOBLvUCdVFh8k&#J?y)0r)B;2PuMc(|@7};F{hq zQH_>ffbt&{LD$J2wA4I&8g1+639jSu2LDA70utPlYyKZ8Lc#K16k#6B^Sd|wjS#>v ze*z!nzflD1Ulbw0i7)Mc0tsNMzr~5E{f|_Cn6q_=$Ftu;nvT%_#u7XlldRg(p0?yW zfFNPu50LOX&p%Y~bpDr<=D$EfLc%YE5ElPSOY@r|fO-D3yyk+JQ6NRAYD@#e{QvUP z`~?#Jit)$(it+yv()>vgLWh27X?|0LhN1cVkzYcZg6VJI9Ns?^q3pv&+uu%_(6P3- zU%CCd|8Aq1>;KQW{SRY>U}*o#^xp{Ke7y}s2%wN=XnJ9BXz<@c`-@v(Xn%2SW_AV}E$yzom)v-xk){jIMjYv2D@AYtookkE6?k$>M8 z1PKH+5E!QR2NG{M8;BOVar>grzh`h3n%8nJ+( zuZ0kGmnSIi=k%ExK$JfY_7?I3>IS)b9C~!r0DkP>Ai;5cI73ZuwNnEJ8e?uJ%c)#S z23hq~j(Mv{D1EPS6vqNjIY^Qe_X}n=`O064n$ecJ&oAAMDmW-US`%3c`Yxt}{W?({=KOvoFd$Uuk+mGiO)#I*rXP}}j!=krmbN#Al6){m* z%(N_ZQP@`)z2qdnSveb<7|d30 zEL_0OyIx5b+IJkwV1aKG!y`g$hoU@ty15oiA9NBg4Xc?pGu@~@|5Wu@lv7L5UBm5q3mBFD!BIawxUELCY7O!7|D ze*g)MTc6S#`#C)Evjn>kF2mMFmH(VV$~|D-E1 zKK7Ra7=PZVpq8w*G9IZ^SO5TE=>z_oCB?a0xPXe|IuW~o%GDuhzM#GijI6~wKl2V$ zmI>EQRs*vOLo@`1GAUs#D^DQekYRruTgl7~P^9*gVi+R=uA#n%9854Y@o;@@mf;sH z(?HyQ_|BNc7fVHU)YoPyPadN9wd17rrJ0VpkS*-_`KUFd3(BL5Ng~>XFuJ*av5hVv zP??@r-Ns(SYh=wJBhsU!M>}X@VJCkZWPVYKWVxhbCX)It^qPwmIr!O7(TE6!F8=tX z4);-^6B@-z;h+Dmr!@lr^OL1s85+^Mcph?p;(0F@(3F zxb62Uy@t}}0t{ta4uo7Ra*Na`fFQnvd8I!3h&^1O+7YwQ(RA+^)mYMYe!PCH8E=;_ zCgN?tsMeSIQ0&bypK?79W1qv(HThf&?)>L>vvS2&))A2okLBl?Sk- zPFSm%$NeXeU^%KQb$l2jeTsz=rX;2M93t|ZeVab=gQi72Zk&q#1G>RvkO(+pXiM7Y z0-H0aY(6|#*LaL;M1HB!M@}Q#0K5K&p%nm{E3h5{aKaR1jhdl%A%yI1YTZPN976_C zCC0axt>+7St}vq`;ABO?%s?Bn9Z47!D1{fYs~S4-m9v|*(1TDW$bEB*Z7LI zatiXx=>a4~H>nkG0EdGRF=kgUEhFDRy$#2a#GC%rw>3w$c2+YH_kB=qV=o)HZ*uyk zjAH0s)uqKM$w|0;mVO5(v33CeIG6$DDpvIweR&V+;)@i1=nB0s=Xq$lvpCmN7+daG z}sWfsd-rNdVfh4n1jubLV+Mc`VZng2$=?dG+cjBC3PX* zgZFg-uf_w%a{HJ!Qf#ii-KvV}!Q!c_wrS9km5XE@xdP84fmck?1!qc<#+>=Q!N#;2 zpR^&bWnX*NT)gvpa5~%i7{?o6A2S_Div7+9dyde_`X+uRy|VWyBe$;1im&e0zO0h? zOwBmQ58tjPw;bwkc75A#pJj%K@3AHUXe^wyb}nA0nqnzcTn$Y685mx`huu=SYctuw zSE~*52+=KR13L!tV;)-tjS9zDKY7v;Wqt_)r6}nSy;Q!;A-$26DGBp}T;lunQ)7=) zibGbooK@OZiL2ZP)ZTs9!Kd5QsPg;;5?X(B>_t|2e^z^cw)ms-WUR{P$H@E3UmJNO z)o9#{yKi78U3i)xNEltkkvQpwMOFI|tG{=3wWirdJrQ}E^WHN;zLO%cIz$On)TDtR z;SO)$x))UZg1F=LiJfN_1Z~nsPL&`>C_OAoKu!cEuII5mSGqYYuqdd~CvJx&jc%|? zoDQkqse!O|;d?t;VIY-n(t#o;v+7*rrp(RAhU`0_VzRq-5<{ha=vXj$4aiWiYZ0Sa~Er0%c7qd6-0ghcG zrJ06rWq8ZG7q<@DpFf7=*CkDp2R~U#>%7}M{c}Gi+S`jGediu|z&D>aVyi+oPt4vM zPu{y<)%@nMD*;94ep*udw&AU(1pbQvJ0P>el4*$vY!T^fZc3aJqrU>N~vJIF$z4 z8k0|@?qlr;p;KA!LX!CXie6AP`?AhaZhs`+*?WP@`UtSV{w#C%+o}}-ulEia30=Q0 zFNOa=;)Alc5Agd*sL;&Zn|Jn54>fw+`6&YAj2!$8?2Ll!2>J0GX4YC>Z{q!`*E;;A{1>=K0MS?X&DTtCE!tkL{ z@B>Sw@HnMIgpBtg+y@Kr%7K=}a0K^pv>qYBtMOMB!4Y_fva2c1Dg+ndOZf8>SlWyV zL5@PVuIeit8F|a6MzbML@zlQQh2C~yfI;NJnh9MF55^H&-lS75dsx3-nAGbVbo+RC zLbykHus4Uu171KDW*sUNK6M+)Ume1eqd_;RfnUeFCa4L=)bh?HIgi2Z2oa*{<)d{$ zp6wBf+eWOthULEGDs*(HQ0Hu_A|Y~(E|UJNRDUv@2-ObnYMR31s#f{?f6 zkYb2MrkIeW@B<14SSe&WWHNf#aSNiR-LH|X9&zDUFXJ>Ou^sy2f~^fOeI@Pn6&Ow_ zi1A59LgU>E;vw_|acl9A4a3g|RK8@<^f|cYA=G4OlqxITD@^vqeohEN?NPE;-f(}*LhuEIiz!anrLXSyQ_?+0#{s|wGAA~Ob=j9 zV5eGzC|KfSq5wp8M4z!?w2?|&h>D*!SJRbM)Z(5vH|)MVFS2kWRJMkbuv)dVAw%_c z*d`*ATUHGgiwigke)iR?3`r=Pr@703{4SPt%~6)ySAECoAuN`0%0|Ph8Tx7y`EBaP zB0>+_Q*p33gR46NwifX|0Zz2eJEN;f$G}$ywoX)&fND*`Nlo`H90-j1qcKb=KF3ud z3Skk2@{O_*g6)V(A||!I6~iD$@VHeu#IK%;+0h_MIF&Snff|Cw4hYPn8jilSGc`fR zP|wC$W9r-&(4m8yG}BWFEaDzvQikQ|pz%d0Rw?f0U@tlr7?~)F;{)WU2EiT$*BC-2 zJ{mybCf#U$Vx0uJ0)1|>qOq%55*3dki-aPanm8?629cvU1Uz1u05F>{sMU@SOGOef zK%P22rp7OE-$qL;#J@B#7^X}Z@~4pI=fP@%Q?8mlVNn-%LSV;Y-*3n&exRtnmEaXf zrBeb!-!9mZj}i$ZCuimg3PiFaZ#G%K?50w*Qb~*oq_(4!!4x!hIEAreVts;Hzg;xm za!L|n;Ke&4`Shu5PF2z0I2ko*(!6iNqzA+6Np8S~uR6op0Yv4 zgX?z3f+FEVME3%s_v*BE$~L_$FIZ*>@q!}6znCH*T}6rzku;c> zYR9n?s&@+#rW{^$jb7u(KJ4TaR+{{>?J!Ik8SduUa91zf)GM5b0N%Pu(7q{(G|}r( zj<^@DK;3G9IURv}5V5L|yP**I$R;x6f$7qq=1NG?>Phj_HYxGpJjeCCo5=i&ji@V| z{I{uD0;l-|PSFE;jo}Y(aV$h%%@EGVPnYi6G6<~%qWY@+fa;K-=y_OGSW6Y_OclX?G7db2fUg=y zr#joW8Yeb|M4g|6i#)5PI``C!+O%itW6cU#?Tzvv<~9*liC)q4Uh(!`$>m<@(Gb4# zAc2RpLL&%~^WKX5x(L5?ui|X3{kn5{Xb}wamH{ULUp;X-QZc;mM_zp*smy9hiq?+G zhBl^Czku#}=zQPnW%(?jwZ7w!FsLliVvDWoQ5KV2q~6=O(S7_*H_f22wM zhDU4B>~xXH>o(s-1Xhj#E2Kk$uYJUfy+0f^N2q_pSbVGvfn^!P<2zRSaAe7weRiaD zXr~BW-cd_{_(-bujxc+>eSBH6v(H58n|FCdPUoC^OXWibQxBu>=P%FN-{9s{ydJJ_ z8G04>@zt6q1>lH1?vEK5T1lK=`97};m`HljGEu}|_1UJXgG{d4w%d3%`DQAA=*Mm* ztRBUy6n3yu;w+#w1=7vHIruXHY9h*>Lhyi|H59nGv9fTaSF&(NPzj?SMQ`tbVwLOmT{|M{LuPM<14Y=5yH ztW;s{!PvO*d72|p!F~(0DWOv#a6o!ZtxIs!OM}fv9r>anGN4_(o2*F|u3_9UKN=U| z9tYLMxt1A-%RvsrM*J%Bbk1PUp|1#+^}b$XFX;F(XUyl@avTto_`T zS-iNV-X-;l-PG7%cn76#NmDnOu#>(O02z?93+lfxLzKYc^I>Uj9=&`BSH@$>bN&He4pHEYp~B(-nAT%tIgUhFB1UoSy*ThHBM;O?{HZWsJqH8a=fp5;8s=XsUN zGtk5HE*G|HmFTC*5*fMp(w%nr5caJ$mri!!gl0=2cOi0gA!c_W;i4%gqw?Bxc)_D) zV$Jb`oh@0$;ixuP0a1R@a@3{ZQj%#!4vWg!sqtJEpDk{PienY-QYqL~)tN$(M>lppT`9Ko!-#FiN zr$6Xd`CSzHXZ2wequiON|+p@n4STp&({tu4Q23Cfieb4QczQsm5Qj6G~q{Z z5w$e|wAv`Xo7gnJG-m!XJs4sItm&zUvZ4a!w*Yr(M?mIsOsW<#lqqn1MOz9Wkl2B4 zfQN&WB}NTC3mVPx>BZ=k@!)zoFhM)Mg4_N$fHpk!!-gd$n=Z360S0}DqK*!raACy0 zG04fTTWS`H07jB{&3n>QbXdodLm!XVm&CKY$>e;oZ4(DkBFhm;k-^)8biuOO(~6s6 z^Z?!xc`Fsrv6;&OW+04}GIDC`ei(=$N&AN&Ung@BGOP;o}jqRPdq3pR-U zAy=U83HI!aE0#=4Vzgf%ZyMK7!Z`k)6UTy8|gUIi9E9U>) zuN~(}SCr#?HxNaV3u?N=v-;lLXD2hRfM6?NX|q?(#Tddd`~}bv3q(eBE33lGoaB$F zlA50S0~GA8N{m$0_(}lgHAZLpz+fe!r%}-a00F`+C;>pyq(o!E?Y&a5$!M)@sc9?=zS9j=a=w0p}hW&?AqL zYP4ROeH1(SqY^@!}ia;jU@@XmaIcUM0)%m=v`BYTZ zK)k1}YhYktsAYKH*zOT1=K^7#-2(^P2Tu3@RS5$3Cfwbg5itLkpNm3#j8%F9M>QG~ z_4n8W!nT3NsZClfkn4UlyIbQ8*-0V!DUjiz^!!yGMX9-#*|`PVddE9?hq*W<$g9n2 z=+2p#Et*>{S=lZ-IKF@EwEFbf>U}>C5bSaI5AuZ!^T&;A1y4 z5R}`RlvkQsR9ljmP?(-yklN9aT2NOSTT)VzS5aS7*V0s4&{A6gMsUHdUuek3@Yv6> z;h*A@w_+>C1KT#!^L9Y6mz%a(P&r=OGEmY!+tA+M(E7Hhc&DUsx3XogwtTmx{%dvH zUdKSk%khKa*E0=0!)?PeofAv{j8K5UuchyM>-1LJ{Bg_X1?cLUYz*(uE$FXo7;h?i zUDx#6)wSIg`nj`UejsVAuXyw?SJ&I2rnhqq2V)8ABl)|d4IigUz|IgjKLOT;etvEn z92giHpY5Gocsnu#0>Am$;kmbSU}vaz_+VghW8m%a)SIKZh0W!~mGWQBq3dr2DeG6On3cWTb5-)G<;)Zo$u#DpNXtu%>K?2RxNeS>)ZCkJ z|6q+%61)+zDc8)&Y54rrFssv##>$m8cRtV8i(dyK?w$?*%+}T{Hfem^6qMSXtnviN^tU_>j?w5KrM zqNT(au%V2*dT1*#J#(=0zN+cSFkl|yh;43&)io}+6_dB>N3h*X?~lvLoOw^BK0W~P z>UmIFQmek(`WuDohCm zi+C(w)UE6b^jTdAtX;5$<&l)zr_A~|6yNWM5Pqz+FG%UUT2wA#N)5`)ZT{3smWM4y zuqBsZ!LVCxBsfJ<)5lp9b59^bV8Y69t>upF7mt+f(t6qi!rI>2-iqpBa9O-^BXJ2? zHJ?jq?=BFaGhTE%QT0nE>W)NA9#@B47`woU3;{=53fEp2Z;sc^GR&WgIue?^!t#N3 z@K{2}uSY45)igwR_l&Wg?e44Koa>Db!eiaH(>9jR_J_HdsGLW52e=RPZoY9i7!z&N za~YTXvFq|e_$T+_go18;o$Ok@&GeMI$d|)uloHR;jGp16qgkW-6-RH)o_#r*`{nJL zw|V&7Rrabt58R~q!`nrCynw|r7Ps<;x65f=3bnY{itcg?PQQSy{q5~~+%g-qlh-6i zKXb1SXegnX{P_1KMHFZ%pgvT7{)Il~lS1ilZ zK=JV9<;9P0uWl_r#C!Bf>DC$1hSb@476$pC%nD01!+Z;d0t&!5q~G%<{>$6d0^A6= zu83zS&u-WK&}lD#UEOkpb`a(!s>Q%8nT@ai*Cxe7TD?J5xgRkUo%TT@M7dydXjAYS zrwwA%i$M-W?}s=G4M9bGAa*H^d0ZaOr~@{KMC=qA9_@!)Y|xQuBf#bmpO-oFI_2D; zBJNqyQwjS#n$OANRW>{{t`}C54)+Em&-m=T(v9h=f|Qy9nP`4km@qaqDt8MxKMwZZ zkfIG0QoS6Db0o?iz~N}V-Nz=qRIT!vz!*VFFZ1AsBZU1_n9!J;hi0E6U|I5X2z9nj zyI`5hp2byrVUpm;I{U!Ef+YeIp#X7>9B;M27YTd*B8oErnuvV_M_kB1=ur|G zHe^O}%da!`{kR{;KhnLJ}3X70e=>kCwE>(n-s?Aj`sBJ!^u;9`X@aVSvF z75mM;)P8l055s%`aOp1HsJ|j;za%11@>i$ zX2bk*Ev}KJl7=49+h^;oosrQ}raO(VBR<%#Vn23t5;F6weNc7> zHMQHSeSV}BU%n;o`bJiLd(F#YEY7)G$3F}nsk%Tl+pK$ z?yU_CweyGgLRwm1XxAI4qKIYe0-Rg>>R*-#)m;cptAA;VrJc`*N9cwY9@-yq^)V87 zjNSImtrO;ZSSX}+U)zf(xoVG)JUD`wCR^r}_E88=4Frpik55hm34)~X&(|Mgtu6Vk23D3(UW0kUDnjK2@^&N1=$BneJ#;7*Y-}b zaT+vce$~sR4*=fwPkpL-JA$D80{t|2BKr~RKXW~n6qeYou9hs7x>h@%&VDF1^%yxl z{vIBkzQM!qvF#bE*&T=}O?vbC8*SRAtO1=AQSuv>6^e)5fq5_-yR#)D35O*qscmT` znc3J(*UK9}qg{7BD_u#Bxx-d=%w8ye8y`Pze8U|17zBRW{QWIUKfhA>O1%3q{w%dw zi}B&NwpHA#)K}3_dm&ohvfGs>{qN1cMMbwSQQkZq4!{0A@r`#oN7d>0G{r$Cv_o0! z=Ghc3;;>MwV?w#=?Ck;3QDt-oJux)4Yvl4+#9!*`vnTf!%QAj+Wj$ABa6VY2zN?)g z(fR#W|Jg^0Tk5SZIuCzLUu>CXiBG=jJl56y`Niu6f9EshtNmA6K5eeAE;c`_9#6mV zNez6((D>xl#q5<&P{fPNlewYOgEv=Ab1xWv%)P*vN1ThGaf%T;&(H)E2<&Dw$sip6 z1dYHG^gZ%Iy8GgtydZ$1Ddv6ca(waOFK9*muEBko-TnA5{MeiQXk)!qb=^SV=d$kS z#pEyS?r*Eh`elN6C59hMmSpDxNt88ALNovq5`gFHui6}7&cqa4ZB)Sv+g-iBYN@Kq z9LNcyTbm-uL0wbr;zNRI6M8v{zJPn~LE6^W%c`%ZqX~l@sc+3lVz0^L#S-rGLDFCh zetekf6WG#wn69yeQ}Rr9{y{|ndu*GqL^y?uONQ4}v2rOkDM zLgqu&?5-Qk%aaMhat{K8bYQ7YZ1|SJ@0~<5Pr_82$z8QE$TmneWl31FF*s$Uu(}n# zIx=DS(eCmBkUi!NI4=Q%)TiFi>iGzZCi0aUqw*=@ir4ZT?!W*acVvXx!Kpd&J zjbc2o!oUvOK{5YPFMdY|)12#VC4Nl9HIj=SN}T-wMynW_1x36qNkXyUJW&|D1Ug3= zjT6h4>?CvP42$mKyiOT^?=be09dI}w&UCdvf=eHa(GranOHFgYdJC2SRf*yENHA51 zSFnr6k(I@=#KVZ=1*-9JW5YJ#*C;rm_X47n7hY=TCt&Z>0*-h=Fe(fWyo3qkoNkhR z7tY>8tdBCZ`#LbKdA!Qam+q7b+3xX{9>9JqtMQ47B0zgn1tWKw!c;CC@<^cG%ImE3lPtaWy;3#%=Wd;#%s;?&dVk`%XVJRhKc7qV#*=)%(1r4 zp=iyylb1ttmSeo0Loc4I$CS(LnX6@;%ifwBx|zX!mTTKfa_P$`Xp$%FnJ1c>C*GO| zHiV?l@?@y;<;3$9O!5^y^OaNcRa^7b2?B7fkXB>`I^qR-CItqb1xBd_Canc#iv@Si z3M{A!|IORgTIjG?Xm*y&OI747UgT<0h zZ7nTdEUo>L1 z=HopT(Fx&zJr$x=63cjEU=O=M0E)$nt&POPpeNcdl^Nj0w*i1V6T-85c;KbR(V0;4 zDoFsUdK5KAN5~HV2(Bi; z9UBOcjrnvMYJslRpT@=B5wr&Y1PTIJKz8kHV(n+BZ7be(Vdn(%1g2yNbvQ4nB z+Qd zm*gC(ZDgl*KNdS}sYaNgPJJC0Kw)l7w0=Lwxo3*_!P!io1~dUs!nXD(!d6YpW}q5d z53`v71;GHoKjwj1mnu0Kk{>YQ(CXUbHlQq~+YzYySzQgR0u5-$={EF68jt{xEO6CY z(MJOGz?nEy*%W&N22J6`x&&&!?GTa00JL6J2vmfp+_hP;cAT(5rDG`J=_r-*t6C1Cpufj2{R=|Mc~|97Q8sa zsM~?A5CZzE&@8S_dQ(gq$@)uPCXQtq|) zXE&;Pi(iytAEUu#gV)+b^(+i+YVrd_)p$YKc-PPkw%pB3lJz&ZfN**T+KE?}sMnU$ zP}{CvHGwLC9;*vB+S)ES(lsEwM*L;9E?~DVp?m-`B8aALb)?3@x2V2^^}j7ACg-io zD3_prNO&>aWk>`hd3C+LXu$w5r~nN5E=ZR{?}wdQ0kr`n@Mez)VjMpFXd0UKu=DJ! z6v26ED;)UW)TCmoQs54(PL4KkV{p2Pt8W{4XPUkgKOrM^Iq z)n+K9BpsIes+Xairju<%0N$4YGK=9$Si|+}bTTWG)aAcnHlAxQ~!FF+FPLk^s6k2MmD3;47z%n~q_I0EBni zswMaEGbSKQ50S@h^@-rU_bR@U!|NMdkT4X10U;n#AwA2lSQCW8&!v}X=KJHZliQ4l=@&Ci+x8*ji>u2(^|Bgf zZP=HFR%$v7^s;bG>;Bc+l&klONgnY>YC1`o;bRm|xKJJ1Vou$9aGwwBYywBnyg$oz zChuH@WR)aKVhZfz^goxRsSxt<5;}K;rY{SgXTP<~8`N}Jy^-orT4UR&}^qFjhu zhya^i=upfErVPfWDRiF!OLj$QCT0ZLwaicAe=&l&yhjx6D1EX0{)%|g`T0h?DZ-t% z*Dz)ThlY6jdhK18D*OqIH$OLQf3&zu30;(aoV`v5Bd*OeLmZ-lzMj7|_Q%nR=w~1M zWHI+%ANg6!zd8A8Wkvj};PKAX^UNs$p3N7e{jVP)N3tH+qU&E?zDLObVD}xEm@QQs#P7iVIe{OJ z=Fr5fHTv31eqBh~8{6t)y=GkTCz^=&`a;%T<50#91U&K4VQP5**toPzoyvCt>O&KMGemHkmdXM;pBJ`W!N#?};(a9`R%yhfn zYW3IGZ*B8kjc?xb84j2JPI4Cl%UV9ZeBV_@EGs$C(>W`i0lAqqVe}O`Tuq>F{YvT4 zE9a<#yL#W<%zDDRmM_8qD*Qy$hSJxs#=5&>Z!StF&QYWv zb?q;>UQj2B0wpPMG zBh@h>=4!Z{48gM0Ato@O7-y>Rbz@=rvsSijAPI}fOb+<^PPn08`q83;KofaGcdZAz zG=SY}j0>|%mN#G;m^Y$uDU?qH0$3DEEgtoyD}Ed=FrE8q4t8cRtcLX{hC1=zo)QY? zU;rh!+Hwr^XiPNLHc2IXPuP+kU^WwcFo!B1s#fh#R!F4}gd2G3SKV7#JbKune2%es zwN^z}tB&RFeO9kZCzlZVGpGKP8VY16+g=!iq}Y=MF()zAUFgUx@bWNd93#kB<#0(I@vvA~bn2@`(%vq2OLul#MAty}vSo zM6_>SSEUB;Ww;&XBE?knt*EJ5B3YO`sZ-w`p0O%#W3H8*6doHhH_Hp3r*DIOIsE5ab1J$`l7V)XX;uS+L zsf#*4SC6A_-MCkb9PTxaKsg4{1$ho#xi%FBL3cZBN>Tb=lAQWfNoDRN=2TY5l}h8# zMzzq0>!G%?3OB!0BX4$sRKXxs6bG)G_U5Zego*$3Ex354u)4W-NOM7R$f3TGHP2p# zpx1W(0K)=Jk7Q z+XIFnUpeOQ22lsqXIZ>Npl{WD%}416Rqo4hkU&*~5TCZSRYPjyQjG&)UdZ>`mMtys zA?T@SJ>wMAcrl(BU9tagtG6*V5wA||sL||6=RI9Q-a-_2g!VCo%jlb-VjC|1VJv&I zeQtbWp#} z#cPR$0a##A!ARvMlCp`gh;V#a3= znv$V$3U@hgvJ%e+I#UJp&M|Dahv;W)E??9s z6D1ov8jz#M4+tRwm=BbjX$2q_Jvu43!WKp!xYeasL^6!S{oY($G2lS^WjTt!4@_+K z!R2CCv6js4iODhx$u`<~8mWbdBp)#Ig45B|DZxzdfkVnK)V#Y6$_KK#^ z#s4(@$F=F?fx#Glp$H|>D834&+8bfHHG`6II$d!%PuWSvVBcJOso$?cbwzo{;}Udv z9i&m7aPK=$D|O)u6dJ{**Hw?tnxqcdhkU-Y7+-Gm#`t&0hsrdJK?HQ7^X*=ix%>>h z(3vS-UAgJaH$|tQKEvL0M?p9<_o3yB4>E(U5h1&jW#QZu-B*;dSe*AYw55NZ&>^V| z>S(odelUj2vA{`!P(38XKerb&KE|ja@Za4tKZi3ga^&vvF{W=Ej>*pQ-!|SB7V z>Mz457#N0kj~NzBObdyvvc0j}g%azOGjtb8tu(}Y*d>55tgIG`KGf82cp=iJJ z6W(+5zwTh9oBN%_ofA@>9mxNykQM15)4i-NVqc@U0?s9WTkD zYYI1EW@}--9CcWt<;VL#rPuU?MTR)U_ais%%i`JdG&xprP=oh1H^hIi7`?5%?N~p2 za@t=QmHsI%v;HOrF_9Yax(*O>qi{ZDOa8J;F@r=T3U1Gn9jH39vi7O?l`dyMkfCI! zi9zOSZ|nh<&FnRi{Ha8eQbUb_j?&1NGke{DExBLHV6IR#g|SeX$^*k|ny3t~h6%yo z&oSnA^XEG6v0E`T&uiXQ&m=FGseJYTQ}$B`)5yJJX^C@sJKe!RDXI!0jc_(01C0g- z;zvzQR7-7~C5_7MUl1;)O?Vh+JZe{2P5-4h3{`E$tDnVvOnx5$WoE|NuXhT`W3l?b zhSs#&s^b-N&WZ$jH$^&XbLcvc?%5X3vF(gmS8tTT&iu?i!n?mQ=JmdRIbg;FNn~cR z^>Io6Z1!2=ex$VbrAs!h`KCOZ=VYXhYd)L#mfC&K>5NO)VkPr!-6GG~3ZJLt_d7P} zr#$C6E}w!Psa$?<7Uk5AN06WD^YIkpUuB{efE0)^U}3} zPKpkGUi#+E=uDP86N^%GfB($)18<`qxbqJ&NyTdsWlHO?wiB<_(`C-yC<-v8qB&WZ;s-Z}58 zIl)@HpzVXQgY+Ip867);llBY-4T27hEIbVfC)&9=cC!uPB7J;X!kwQ`(OG&i?0T&;1Wl@ z5S!T%w$>c>Pn#J9MRsY*?6MI#Sh0amBxS!2i?g$hi^~?Pb*JTwT^yf2K6FIeXCyGQSW5L+BKTg@;{hGwkOd=DC0Ph%Jv*^dHN}DOO2$Tr=mm$%O2F zFU*@z;+Du`m1J@(yJ6BB<>pftT;3>K9c6A>@SDXV#VT9FC9B50LTCR0>&>zS?Kxj| zhRV3Dw_phfa8g{*Vzr@vzV)8e5;mQH7KTksbv_3(E01c6cu4rPxcz9THECI*(c|88 z#^VC_p6|b#mR@l4__DL?jL6Q#jz&cu^MCW}aahTvbP2HRvcA%|K-zPP&aR3VJC?5S z?7ibT?}+uK&ulw)yRYqbV324M^4V2ku+#C&&Vm)Y=hb+vu(A6hY_;&puJRevaw1PH zn9ROr4ddD#uMIrj7oF|quRgWzcZ+C4!!vI?VGX8p!rnW2PWR3^wZPbW=N|7pHSU|< zura)7+w;f!z@4KFkcB%oz~u@$)eK(1)klJ`)klys+JPs9m&ys%DvH351_vF%KKlyj zhEmw2vA}~nfTwl#Uf^>$>JZV(1wui>I9v mmVcPQI=LyOlYvbj>F5T9E*0VBC0=X0^lq#vo6XC}U=08mh?S85 literal 0 HcmV?d00001 diff --git a/docs/images/self-hosted.png b/docs/images/self-hosted.png new file mode 100644 index 0000000000000000000000000000000000000000..cd4fa16e061583e19eff84dc97fbedb9e143c038 GIT binary patch literal 238095 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