define("ace/ext/spellcheck",["require","exports","module","ace/lib/event","ace/editor","ace/config"], function(require, exports, module) { "use strict"; var event = require("../lib/event"); exports.contextMenuHandler = function(e){ var host = e.target; var text = host.textInput.getElement(); if (!host.selection.isEmpty()) return; var c = host.getCursorPosition(); var r = host.session.getWordRange(c.row, c.column); var w = host.session.getTextRange(r); host.session.tokenRe.lastIndex = 0; if (!host.session.tokenRe.test(w)) return; var PLACEHOLDER = "\x01\x01"; var value = w + " " + PLACEHOLDER; text.value = value; text.setSelectionRange(w.length, w.length + 1); text.setSelectionRange(0, 0); text.setSelectionRange(0, w.length); var afterKeydown = false; event.addListener(text, "keydown", function onKeydown() { event.removeListener(text, "keydown", onKeydown); afterKeydown = true; }); host.textInput.setInputHandler(function(newVal) { console.log(newVal , value, text.selectionStart, text.selectionEnd) if (newVal == value) return ''; if (newVal.lastIndexOf(value, 0) === 0) return newVal.slice(value.length); if (newVal.substr(text.selectionEnd) == value) return newVal.slice(0, -value.length); if (newVal.slice(-2) == PLACEHOLDER) { var val = newVal.slice(0, -2); if (val.slice(-1) == " ") { if (afterKeydown) return val.substring(0, text.selectionEnd); val = val.slice(0, -1); host.session.replace(r, val); return ""; } } return newVal; }); }; var Editor = require("../editor").Editor; require("../config").defineOptions(Editor.prototype, "editor", { spellcheck: { set: function(val) { var text = this.textInput.getElement(); text.spellcheck = !!val; if (!val) this.removeListener("nativecontextmenu", exports.contextMenuHandler); else this.on("nativecontextmenu", exports.contextMenuHandler); }, value: true } }); }); define("kitchen-sink/inline_editor",["require","exports","module","ace/line_widgets","ace/editor","ace/virtual_renderer","ace/lib/dom","ace/commands/default_commands"], function(require, exports, module) { "use strict"; var LineWidgets = require("ace/line_widgets").LineWidgets; var Editor = require("ace/editor").Editor; var Renderer = require("ace/virtual_renderer").VirtualRenderer; var dom = require("ace/lib/dom"); require("ace/commands/default_commands").commands.push({ name: "openInlineEditor", bindKey: "F3", exec: function(editor) { var split = window.env.split; var s = editor.session; var inlineEditor = new Editor(new Renderer()); var splitSession = split.$cloneSession(s); var row = editor.getCursorPosition().row; if (editor.session.lineWidgets && editor.session.lineWidgets[row]) { editor.session.lineWidgets[row].destroy(); return; } var rowCount = 10; var w = { row: row, fixedWidth: true, el: dom.createElement("div"), editor: inlineEditor }; var el = w.el; el.appendChild(inlineEditor.container); if (!editor.session.widgetManager) { editor.session.widgetManager = new LineWidgets(editor.session); editor.session.widgetManager.attach(editor); } var h = rowCount*editor.renderer.layerConfig.lineHeight; inlineEditor.container.style.height = h + "px"; el.style.position = "absolute"; el.style.zIndex = "4"; el.style.borderTop = "solid blue 2px"; el.style.borderBottom = "solid blue 2px"; inlineEditor.setSession(splitSession); editor.session.widgetManager.addLineWidget(w); var kb = { handleKeyboard:function(_,hashId, keyString) { if (hashId === 0 && keyString === "esc") { w.destroy(); return true; } } }; w.destroy = function() { editor.keyBinding.removeKeyboardHandler(kb); s.widgetManager.removeLineWidget(w); }; editor.keyBinding.addKeyboardHandler(kb); inlineEditor.keyBinding.addKeyboardHandler(kb); inlineEditor.setTheme("ace/theme/solarized_light"); } }); }); define("ace/test/asyncjs/assert",["require","exports","module","ace/lib/oop"], function(require, exports, module) { var oop = require("ace/lib/oop"); var pSlice = Array.prototype.slice; var assert = exports; assert.AssertionError = function AssertionError(options) { this.name = 'AssertionError'; this.message = options.message; this.actual = options.actual; this.expected = options.expected; this.operator = options.operator; var stackStartFunction = options.stackStartFunction || fail; if (Error.captureStackTrace) { Error.captureStackTrace(this, stackStartFunction); } }; oop.inherits(assert.AssertionError, Error); toJSON = function(obj) { if (typeof JSON !== "undefined") return JSON.stringify(obj); else return obj.toString(); } assert.AssertionError.prototype.toString = function() { if (this.message) { return [this.name + ':', this.message].join(' '); } else { return [this.name + ':', toJSON(this.expected), this.operator, toJSON(this.actual)].join(' '); } }; assert.AssertionError.__proto__ = Error.prototype; function fail(actual, expected, message, operator, stackStartFunction) { throw new assert.AssertionError({ message: message, actual: actual, expected: expected, operator: operator, stackStartFunction: stackStartFunction }); } assert.fail = fail; assert.ok = function ok(value, message) { if (!!!value) fail(value, true, message, '==', assert.ok); }; assert.equal = function equal(actual, expected, message) { if (actual != expected) fail(actual, expected, message, '==', assert.equal); }; assert.notEqual = function notEqual(actual, expected, message) { if (actual == expected) { fail(actual, expected, message, '!=', assert.notEqual); } }; assert.deepEqual = function deepEqual(actual, expected, message) { if (!_deepEqual(actual, expected)) { fail(actual, expected, message, 'deepEqual', assert.deepEqual); } }; function _deepEqual(actual, expected) { if (actual === expected) { return true; } else if (typeof Buffer !== "undefined" && Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) { if (actual.length != expected.length) return false; for (var i = 0; i < actual.length; i++) { if (actual[i] !== expected[i]) return false; } return true; } else if (actual instanceof Date && expected instanceof Date) { return actual.getTime() === expected.getTime(); } else if (typeof actual != 'object' && typeof expected != 'object') { return actual == expected; } else { return objEquiv(actual, expected); } } function isUndefinedOrNull(value) { return value === null || value === undefined; } function isArguments(object) { return Object.prototype.toString.call(object) == '[object Arguments]'; } function objEquiv(a, b) { if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) return false; if (a.prototype !== b.prototype) return false; if (isArguments(a)) { if (!isArguments(b)) { return false; } a = pSlice.call(a); b = pSlice.call(b); return _deepEqual(a, b); } try { var ka = Object.keys(a), kb = Object.keys(b), key, i; } catch (e) {//happens when one is a string literal and the other isn't return false; } if (ka.length != kb.length) return false; ka.sort(); kb.sort(); for (i = ka.length - 1; i >= 0; i--) { if (ka[i] != kb[i]) return false; } for (i = ka.length - 1; i >= 0; i--) { key = ka[i]; if (!_deepEqual(a[key], b[key])) return false; } return true; } assert.notDeepEqual = function notDeepEqual(actual, expected, message) { if (_deepEqual(actual, expected)) { fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); } }; assert.strictEqual = function strictEqual(actual, expected, message) { if (actual !== expected) { fail(actual, expected, message, '===', assert.strictEqual); } }; assert.notStrictEqual = function notStrictEqual(actual, expected, message) { if (actual === expected) { fail(actual, expected, message, '!==', assert.notStrictEqual); } }; function expectedException(actual, expected) { if (!actual || !expected) { return false; } if (expected instanceof RegExp) { return expected.test(actual); } else if (actual instanceof expected) { return true; } else if (expected.call({}, actual) === true) { return true; } return false; } function _throws(shouldThrow, block, expected, message) { var actual; if (typeof expected === 'string') { message = expected; expected = null; } try { block(); } catch (e) { actual = e; } message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + (message ? ' ' + message : '.'); if (shouldThrow && !actual) { fail('Missing expected exception' + message); } if (!shouldThrow && expectedException(actual, expected)) { fail('Got unwanted exception' + message); } if ((shouldThrow && actual && expected && !expectedException(actual, expected)) || (!shouldThrow && actual)) { throw actual; } } assert.throws = function(block, /*optional*/error, /*optional*/message) { _throws.apply(this, [true].concat(pSlice.call(arguments))); }; assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) { _throws.apply(this, [false].concat(pSlice.call(arguments))); }; assert.ifError = function(err) { if (err) {throw err;}}; }); define("ace/test/asyncjs/async",["require","exports","module"], function(require, exports, module) { var STOP = exports.STOP = {} exports.Generator = function(source) { if (typeof source == "function") this.source = { next: source } else this.source = source } ;(function() { this.next = function(callback) { this.source.next(callback) } this.map = function(mapper) { if (!mapper) return this mapper = makeAsync(1, mapper) var source = this.source this.next = function(callback) { source.next(function(err, value) { if (err) callback(err) else { mapper(value, function(err, value) { if (err) callback(err) else callback(null, value) }) } }) } return new this.constructor(this) } this.filter = function(filter) { if (!filter) return this filter = makeAsync(1, filter) var source = this.source this.next = function(callback) { source.next(function handler(err, value) { if (err) callback(err) else { filter(value, function(err, takeIt) { if (err) callback(err) else if (takeIt) callback(null, value) else source.next(handler) }) } }) } return new this.constructor(this) } this.slice = function(begin, end) { var count = -1 if (!end || end < 0) var end = Infinity var source = this.source this.next = function(callback) { source.next(function handler(err, value) { count++ if (err) callback(err) else if (count >= begin && count < end) callback(null, value) else if (count >= end) callback(STOP) else source.next(handler) }) } return new this.constructor(this) } this.reduce = function(reduce, initialValue) { reduce = makeAsync(3, reduce) var index = 0 var done = false var previousValue = initialValue var source = this.source this.next = function(callback) { if (done) return callback(STOP) if (initialValue === undefined) { source.next(function(err, currentValue) { if (err) return callback(err, previousValue) previousValue = currentValue reduceAll() }) } else reduceAll() function reduceAll() { source.next(function handler(err, currentValue) { if (err) { done = true if (err == STOP) return callback(null, previousValue) else return(err) } reduce(previousValue, currentValue, index++, function(err, value) { previousValue = value source.next(handler) }) }) } } return new this.constructor(this) } this.forEach = this.each = function(fn) { fn = makeAsync(1, fn) var source = this.source this.next = function(callback) { source.next(function handler(err, value) { if (err) callback(err) else { fn(value, function(err) { callback(err, value) }) } }) } return new this.constructor(this) } this.some = function(condition) { condition = makeAsync(1, condition) var source = this.source var done = false this.next = function(callback) { if (done) return callback(STOP) source.next(function handler(err, value) { if (err) return callback(err) condition(value, function(err, result) { if (err) { done = true if (err == STOP) callback(null, false) else callback(err) } else if (result) { done = true callback(null, true) } else source.next(handler) }) }) } return new this.constructor(this) } this.every = function(condition) { condition = makeAsync(1, condition) var source = this.source var done = false this.next = function(callback) { if (done) return callback(STOP) source.next(function handler(err, value) { if (err) return callback(err) condition(value, function(err, result) { if (err) { done = true if (err == STOP) callback(null, true) else callback(err) } else if (!result) { done = true callback(null, false) } else source.next(handler) }) }) } return new this.constructor(this) } this.call = function(context) { var source = this.source return this.map(function(fn, next) { fn = makeAsync(0, fn, context) fn.call(context, function(err, value) { next(err, value) }) }) } this.concat = function(generator) { var generators = [this] generators.push.apply(generators, arguments) var index = 0 var source = generators[index++] return new this.constructor(function(callback) { source.next(function handler(err, value) { if (err) { if (err == STOP) { source = generators[index++] if (!source) return callback(STOP) else return source.next(handler) } else return callback(err) } else return callback(null, value) }) }) } this.zip = function(generator) { var generators = [this] generators.push.apply(generators, arguments) return new this.constructor(function(callback) { exports.list(generators) .map(function(gen, next) { gen.next(next) }) .toArray(callback) }) } this.expand = function(inserter, constructor) { if (!inserter) return this var inserter = makeAsync(1, inserter) var constructor = constructor || this.constructor var source = this.source; var spliced = null; return new constructor(function next(callback) { if (!spliced) { source.next(function(err, value) { if (err) return callback(err) inserter(value, function(err, toInsert) { if (err) return callback(err) spliced = toInsert next(callback) }) }) } else { spliced.next(function(err, value) { if (err == STOP) { spliced = null return next(callback) } else if (err) return callback(err) callback(err, value) }) } }) } this.sort = function(compare) { var self = this var arrGen this.next = function(callback) { if (arrGen) return arrGen.next(callback) self.toArray(function(err, arr) { if (err) callback(err) else { arrGen = exports.list(arr.sort(compare)) arrGen.next(callback) } }) } return new this.constructor(this) } this.join = function(separator) { return this.$arrayOp(Array.prototype.join, separator !== undefined ? [separator] : null) } this.reverse = function() { return this.$arrayOp(Array.prototype.reverse) } this.$arrayOp = function(arrayMethod, args) { var self = this var i = 0 this.next = function(callback) { if (i++ > 0) return callback(STOP) self.toArray(function(err, arr) { if (err) callback(err, "") else { if (args) callback(null, arrayMethod.apply(arr, args)) else callback(null, arrayMethod.call(arr)) } }) } return new this.constructor(this) } this.end = function(breakOnError, callback) { if (!callback) { callback = arguments[0] breakOnError = true } var source = this.source var last var lastError source.next(function handler(err, value) { if (err) { if (err == STOP) callback && callback(lastError, last) else if (!breakOnError) { lastError = err source.next(handler) } else callback && callback(err, value) } else { last = value source.next(handler) } }) } this.toArray = function(breakOnError, callback) { if (!callback) { callback = arguments[0] breakOnError = true } var values = [] var errors = [] var source = this.source source.next(function handler(err, value) { if (err) { if (err == STOP) { if (breakOnError) return callback(null, values) else { errors.length = values.length return callback(errors, values) } } else { if (breakOnError) return callback(err) else errors[values.length] = err } } values.push(value) source.next(handler) }) } }).call(exports.Generator.prototype) var makeAsync = exports.makeAsync = function(args, fn, context) { if (fn.length > args) return fn else { return function() { var value var next = arguments[args] try { value = fn.apply(context || this, arguments) } catch(e) { return next(e) } next(null, value) } } } exports.list = function(arr, construct) { var construct = construct || exports.Generator var i = 0 var len = arr.length return new construct(function(callback) { if (i < len) callback(null, arr[i++]) else callback(STOP) }) } exports.values = function(map, construct) { var values = [] for (var key in map) values.push(map[key]) return exports.list(values, construct) } exports.keys = function(map, construct) { var keys = [] for (var key in map) keys.push(key) return exports.list(keys, construct) } exports.range = function(start, stop, step, construct) { var construct = construct || exports.Generator start = start || 0 step = step || 1 if (stop === undefined || stop === null) stop = step > 0 ? Infinity : -Infinity var value = start return new construct(function(callback) { if (step > 0 && value >= stop || step < 0 && value <= stop) callback(STOP) else { var current = value value += step callback(null, current) } }) } exports.concat = function(first, varargs) { if (arguments.length > 1) return first.concat.apply(first, Array.prototype.slice.call(arguments, 1)) else return first } exports.zip = function(first, varargs) { if (arguments.length > 1) return first.zip.apply(first, Array.prototype.slice.call(arguments, 1)) else return first.map(function(item, next) { next(null, [item]) }) } exports.plugin = function(members, constructors) { if (members) { for (var key in members) { exports.Generator.prototype[key] = members[key] } } if (constructors) { for (var key in constructors) { exports[key] = constructors[key] } } } }) define("ace/test/mockrenderer",["require","exports","module"], function(require, exports, module) { "use strict"; var MockRenderer = exports.MockRenderer = function(visibleRowCount) { if (typeof document == "object") { this.container = document.createElement("div"); this.scroller = document.createElement("div"); } this.visibleRowCount = visibleRowCount || 20; this.layerConfig = { firstVisibleRow : 0, lastVisibleRow : this.visibleRowCount }; this.isMockRenderer = true; this.$gutter = {}; }; MockRenderer.prototype.getFirstVisibleRow = function() { return this.layerConfig.firstVisibleRow; }; MockRenderer.prototype.getLastVisibleRow = function() { return this.layerConfig.lastVisibleRow; }; MockRenderer.prototype.getFirstFullyVisibleRow = function() { return this.layerConfig.firstVisibleRow; }; MockRenderer.prototype.getLastFullyVisibleRow = function() { return this.layerConfig.lastVisibleRow; }; MockRenderer.prototype.getContainerElement = function() { return this.container; }; MockRenderer.prototype.getMouseEventTarget = function() { return this.container; }; MockRenderer.prototype.getTextAreaContainer = function() { return this.container; }; MockRenderer.prototype.addGutterDecoration = function() { }; MockRenderer.prototype.removeGutterDecoration = function() { }; MockRenderer.prototype.moveTextAreaToCursor = function() { }; MockRenderer.prototype.setSession = function(session) { this.session = session; }; MockRenderer.prototype.getSession = function(session) { return this.session; }; MockRenderer.prototype.setTokenizer = function() { }; MockRenderer.prototype.on = function() { }; MockRenderer.prototype.updateCursor = function() { }; MockRenderer.prototype.animateScrolling = function(fromValue, callback) { callback && callback(); }; MockRenderer.prototype.scrollToX = function(scrollTop) {}; MockRenderer.prototype.scrollToY = function(scrollLeft) {}; MockRenderer.prototype.scrollToLine = function(line, center) { var lineHeight = 16; var row = 0; for (var l = 1; l < line; l++) { row += this.session.getRowLength(l-1); } if (center) { row -= this.visibleRowCount / 2; } this.scrollToRow(row); }; MockRenderer.prototype.scrollSelectionIntoView = function() { }; MockRenderer.prototype.scrollCursorIntoView = function() { var cursor = this.session.getSelection().getCursor(); if (cursor.row < this.layerConfig.firstVisibleRow) { this.scrollToRow(cursor.row); } else if (cursor.row > this.layerConfig.lastVisibleRow) { this.scrollToRow(cursor.row); } }; MockRenderer.prototype.scrollToRow = function(row) { var row = Math.min(this.session.getLength() - this.visibleRowCount, Math.max(0, row)); this.layerConfig.firstVisibleRow = row; this.layerConfig.lastVisibleRow = row + this.visibleRowCount; }; MockRenderer.prototype.getScrollTopRow = function() { return this.layerConfig.firstVisibleRow; }; MockRenderer.prototype.draw = function() { }; MockRenderer.prototype.onChangeTabSize = function(startRow, endRow) { }; MockRenderer.prototype.updateLines = function(startRow, endRow) { }; MockRenderer.prototype.updateBackMarkers = function() { }; MockRenderer.prototype.updateFrontMarkers = function() { }; MockRenderer.prototype.updateBreakpoints = function() { }; MockRenderer.prototype.onResize = function() { }; MockRenderer.prototype.updateFull = function() { }; MockRenderer.prototype.updateText = function() { }; MockRenderer.prototype.showCursor = function() { }; MockRenderer.prototype.visualizeFocus = function() { }; MockRenderer.prototype.setAnnotations = function() { }; MockRenderer.prototype.setStyle = function() { }; MockRenderer.prototype.unsetStyle = function() { }; MockRenderer.prototype.textToScreenCoordinates = function() { return { pageX: 0, pageY: 0 } }; MockRenderer.prototype.screenToTextCoordinates = function() { return { row: 0, column: 0 } }; MockRenderer.prototype.adjustWrapLimit = function () { }; }); define("kitchen-sink/dev_util",["require","exports","module","ace/lib/dom","ace/range","ace/lib/oop","ace/lib/dom","ace/range","ace/editor","ace/test/asyncjs/assert","ace/test/asyncjs/async","ace/undomanager","ace/edit_session","ace/test/mockrenderer","ace/lib/event_emitter"], function(require, exports, module) { var dom = require("ace/lib/dom"); var Range = require("ace/range").Range; function warn() { var s = (new Error()).stack || ""; s = s.split("\n"); if (s[1] == "Error") s.shift(); // remove error description on chrome s.shift(); // remove warn s.shift(); // remove the getter s = s.join("\n"); if (!/at Object.InjectedScript.|@debugger eval|snippets:\/{3}|:\d+:\d+/.test(s)) { console.error("trying to access to global variable"); } } function def(o, key, get) { try { Object.defineProperty(o, key, { configurable: true, get: get, set: function(val) { delete o[key]; o[key] = val; } }); } catch(e) { console.error(e); } } def(window, "ace", function(){ warn(); return window.env.editor }); def(window, "editor", function(){ warn(); return window.env.editor }); def(window, "session", function(){ warn(); return window.env.editor.session }); def(window, "split", function(){ warn(); return window.env.split }); def(window, "devUtil", function(){ warn(); return exports }); exports.showTextArea = function(argument) { dom.importCssString("\ .ace_text-input {\ position: absolute;\ z-index: 10!important;\ width: 6em!important;\ height: 1em;\ opacity: 1!important;\ background: rgba(0, 92, 255, 0.11);\ border: none;\ font: inherit;\ padding: 0 1px;\ margin: 0 -1px;\ text-indent: 0em;\ }\ "); }; exports.addGlobals = function() { window.oop = require("ace/lib/oop"); window.dom = require("ace/lib/dom"); window.Range = require("ace/range").Range; window.Editor = require("ace/editor").Editor; window.assert = require("ace/test/asyncjs/assert"); window.asyncjs = require("ace/test/asyncjs/async"); window.UndoManager = require("ace/undomanager").UndoManager; window.EditSession = require("ace/edit_session").EditSession; window.MockRenderer = require("ace/test/mockrenderer").MockRenderer; window.EventEmitter = require("ace/lib/event_emitter").EventEmitter; window.getSelection = getSelection; window.setSelection = setSelection; window.testSelection = testSelection; }; function getSelection(editor) { var data = editor.multiSelect.toJSON(); if (!data.length) data = [data]; data = data.map(function(x) { var a, c; if (x.isBackwards) { a = x.end; c = x.start; } else { c = x.end; a = x.start; } return Range.comparePoints(a, c) ? [a.row, a.column, c.row, c.column] : [a.row, a.column]; }); return data.length > 1 ? data : data[0]; } function setSelection(editor, data) { if (typeof data[0] == "number") data = [data]; editor.selection.fromJSON(data.map(function(x) { var start = {row: x[0], column: x[1]}; var end = x.length == 2 ? start : {row: x[2], column: x[3]}; var isBackwards = Range.comparePoints(start, end) > 0; return isBackwards ? { start: end, end: start, isBackwards: true } : { start: start, end: end, isBackwards: true }; })); } function testSelection(editor, data) { assert.equal(getSelection(editor) + "", data + ""); } exports.recordTestCase = function() { exports.addGlobals(); var editor = window.editor; var testcase = window.testcase = []; var assert; testcase.push({ type: "setValue", data: editor.getValue() }, { type: "setSelection", data: getSelection(editor) }); editor.commands.on("afterExec", function(e) { testcase.push({ type: "exec", data: e }); testcase.push({ type: "value", data: editor.getValue() }); testcase.push({ type: "selection", data: getSelection(editor) }); }); editor.on("mouseup", function() { testcase.push({ type: "setSelection", data: getSelection(editor) }); }); testcase.toString = function() { var lastValue = ""; var str = this.map(function(x) { var data = x.data; switch (x.type) { case "exec": return 'editor.execCommand("' + data.command.name + (data.args ? '", ' + JSON.stringify(data.args) : '"') + ')'; case "setSelection": return 'setSelection(editor, ' + JSON.stringify(data) + ')'; case "setValue": if (lastValue != data) { lastValue = data; return 'editor.setValue(' + JSON.stringify(data) + ', -1)'; } return; case "selection": return 'testSelection(editor, ' + JSON.stringify(data) + ')'; case "value": if (lastValue != data) { lastValue = data; return 'assert.equal(' + 'editor.getValue(),' + JSON.stringify(data) + ')'; } return; } }).filter(Boolean).join("\n"); return getSelection + "\n" + testSelection + "\n" + setSelection + "\n" + "\n" + str + "\n"; }; }; }); define("ace/ext/modelist",["require","exports","module"], function(require, exports, module) { "use strict"; var modes = []; function getModeForPath(path) { var mode = modesByName.text; var fileName = path.split(/[\/\\]/).pop(); for (var i = 0; i < modes.length; i++) { if (modes[i].supportsFile(fileName)) { mode = modes[i]; break; } } return mode; } var Mode = function(name, caption, extensions) { this.name = name; this.caption = caption; this.mode = "ace/mode/" + name; this.extensions = extensions; var re; if (/\^/.test(extensions)) { re = extensions.replace(/\|(\^)?/g, function(a, b){ return "$|" + (b ? "^" : "^.*\\."); }) + "$"; } else { re = "^.*\\.(" + extensions + ")$"; } this.extRe = new RegExp(re, "gi"); }; Mode.prototype.supportsFile = function(filename) { return filename.match(this.extRe); }; var supportedModes = { ABAP: ["abap"], ABC: ["abc"], ActionScript:["as"], ADA: ["ada|adb"], Apache_Conf: ["^htaccess|^htgroups|^htpasswd|^conf|htaccess|htgroups|htpasswd"], AsciiDoc: ["asciidoc|adoc"], Assembly_x86:["asm|a"], AutoHotKey: ["ahk"], BatchFile: ["bat|cmd"], Bro: ["bro"], C_Cpp: ["cpp|c|cc|cxx|h|hh|hpp|ino"], C9Search: ["c9search_results"], Cirru: ["cirru|cr"], Clojure: ["clj|cljs"], Cobol: ["CBL|COB"], coffee: ["coffee|cf|cson|^Cakefile"], ColdFusion: ["cfm"], CSharp: ["cs"], CSS: ["css"], Curly: ["curly"], D: ["d|di"], Dart: ["dart"], Diff: ["diff|patch"], Dockerfile: ["^Dockerfile"], Dot: ["dot"], Drools: ["drl"], Dummy: ["dummy"], DummySyntax: ["dummy"], Eiffel: ["e|ge"], EJS: ["ejs"], Elixir: ["ex|exs"], Elm: ["elm"], Erlang: ["erl|hrl"], Forth: ["frt|fs|ldr|fth|4th"], Fortran: ["f|f90"], FTL: ["ftl"], Gcode: ["gcode"], Gherkin: ["feature"], Gitignore: ["^.gitignore"], Glsl: ["glsl|frag|vert"], Gobstones: ["gbs"], golang: ["go"], GraphQLSchema: ["gql"], Groovy: ["groovy"], HAML: ["haml"], Handlebars: ["hbs|handlebars|tpl|mustache"], Haskell: ["hs"], Haskell_Cabal: ["cabal"], haXe: ["hx"], Hjson: ["hjson"], HTML: ["html|htm|xhtml"], HTML_Elixir: ["eex|html.eex"], HTML_Ruby: ["erb|rhtml|html.erb"], INI: ["ini|conf|cfg|prefs"], Io: ["io"], Jack: ["jack"], Jade: ["jade|pug"], Java: ["java"], JavaScript: ["js|jsm|jsx"], JSON: ["json"], JSONiq: ["jq"], JSP: ["jsp"], JSX: ["jsx"], Julia: ["jl"], Kotlin: ["kt|kts"], LaTeX: ["tex|latex|ltx|bib"], LESS: ["less"], Liquid: ["liquid"], Lisp: ["lisp"], LiveScript: ["ls"], LogiQL: ["logic|lql"], LSL: ["lsl"], Lua: ["lua"], LuaPage: ["lp"], Lucene: ["lucene"], Makefile: ["^Makefile|^GNUmakefile|^makefile|^OCamlMakefile|make"], Markdown: ["md|markdown"], Mask: ["mask"], MATLAB: ["matlab"], Maze: ["mz"], MEL: ["mel"], MUSHCode: ["mc|mush"], MySQL: ["mysql"], Nix: ["nix"], NSIS: ["nsi|nsh"], ObjectiveC: ["m|mm"], OCaml: ["ml|mli"], Pascal: ["pas|p"], Perl: ["pl|pm"], pgSQL: ["pgsql"], PHP: ["php|phtml|shtml|php3|php4|php5|phps|phpt|aw|ctp|module"], Pig: ["pig"], Powershell: ["ps1"], Praat: ["praat|praatscript|psc|proc"], Prolog: ["plg|prolog"], Properties: ["properties"], Protobuf: ["proto"], Python: ["py"], R: ["r"], Razor: ["cshtml|asp"], RDoc: ["Rd"], RHTML: ["Rhtml"], RST: ["rst"], Ruby: ["rb|ru|gemspec|rake|^Guardfile|^Rakefile|^Gemfile"], Rust: ["rs"], SASS: ["sass"], SCAD: ["scad"], Scala: ["scala"], Scheme: ["scm|sm|rkt|oak|scheme"], SCSS: ["scss"], SH: ["sh|bash|^.bashrc"], SJS: ["sjs"], Smarty: ["smarty|tpl"], snippets: ["snippets"], Soy_Template:["soy"], Space: ["space"], SQL: ["sql"], SQLServer: ["sqlserver"], Stylus: ["styl|stylus"], SVG: ["svg"], Swift: ["swift"], Tcl: ["tcl"], Tex: ["tex"], Text: ["txt"], Textile: ["textile"], Toml: ["toml"], TSX: ["tsx"], Twig: ["twig|swig"], Typescript: ["ts|typescript|str"], Vala: ["vala"], VBScript: ["vbs|vb"], Velocity: ["vm"], Verilog: ["v|vh|sv|svh"], VHDL: ["vhd|vhdl"], Wollok: ["wlk|wpgm|wtest"], XML: ["xml|rdf|rss|wsdl|xslt|atom|mathml|mml|xul|xbl|xaml"], XQuery: ["xq"], YAML: ["yaml|yml"], Django: ["html"] }; var nameOverrides = { ObjectiveC: "Objective-C", CSharp: "C#", golang: "Go", C_Cpp: "C and C++", coffee: "CoffeeScript", HTML_Ruby: "HTML (Ruby)", HTML_Elixir: "HTML (Elixir)", FTL: "FreeMarker" }; var modesByName = {}; for (var name in supportedModes) { var data = supportedModes[name]; var displayName = (nameOverrides[name] || name).replace(/_/g, " "); var filename = name.toLowerCase(); var mode = new Mode(filename, displayName, data[0]); modesByName[filename] = mode; modes.push(mode); } module.exports = { getModeForPath: getModeForPath, modes: modes, modesByName: modesByName }; }); define("kitchen-sink/file_drop",["require","exports","module","ace/config","ace/lib/event","ace/ext/modelist","ace/editor"], function(require, exports, module) { var config = require("ace/config"); var event = require("ace/lib/event"); var modelist = require("ace/ext/modelist"); module.exports = function(editor) { event.addListener(editor.container, "dragover", function(e) { var types = e.dataTransfer.types; if (types && Array.prototype.indexOf.call(types, 'Files') !== -1) return event.preventDefault(e); }); event.addListener(editor.container, "drop", function(e) { var file; try { file = e.dataTransfer.files[0]; if (window.FileReader) { var reader = new FileReader(); reader.onload = function() { var mode = modelist.getModeForPath(file.name); editor.session.doc.setValue(reader.result); editor.session.setMode(mode.mode); editor.session.modeName = mode.name; }; reader.readAsText(file); } return event.preventDefault(e); } catch(err) { return event.stopEvent(e); } }); }; var Editor = require("ace/editor").Editor; config.defineOptions(Editor.prototype, "editor", { loadDroppedFile: { set: function() { module.exports(this); }, value: true } }); }); 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;\ }\ "; var dom = require("../lib/dom"); dom.importCssString(exports.cssText, exports.cssClass); }); define("ace/ext/whitespace",["require","exports","module","ace/lib/lang"], function(require, exports, module) { "use strict"; var lang = require("../lib/lang"); exports.$detectIndentation = function(lines, fallback) { var stats = []; var changes = []; var tabIndents = 0; var prevSpaces = 0; var max = Math.min(lines.length, 1000); for (var i = 0; i < max; i++) { var line = lines[i]; if (!/^\s*[^*+\-\s]/.test(line)) continue; if (line[0] == "\t") { tabIndents++; prevSpaces = -Number.MAX_VALUE; } else { var spaces = line.match(/^ */)[0].length; if (spaces && line[spaces] != "\t") { var diff = spaces - prevSpaces; if (diff > 0 && !(prevSpaces%diff) && !(spaces%diff)) changes[diff] = (changes[diff] || 0) + 1; stats[spaces] = (stats[spaces] || 0) + 1; } prevSpaces = spaces; } while (i < max && line[line.length - 1] == "\\") line = lines[i++]; } function getScore(indent) { var score = 0; for (var i = indent; i < stats.length; i += indent) score += stats[i] || 0; return score; } var changesTotal = changes.reduce(function(a,b){return a+b}, 0); var first = {score: 0, length: 0}; var spaceIndents = 0; for (var i = 1; i < 12; i++) { var score = getScore(i); if (i == 1) { spaceIndents = score; score = stats[1] ? 0.9 : 0.8; if (!stats.length) score = 0; } else score /= spaceIndents; if (changes[i]) score += changes[i] / changesTotal; if (score > first.score) first = {score: score, length: i}; } if (first.score && first.score > 1.4) var tabLength = first.length; if (tabIndents > spaceIndents + 1) { if (tabLength == 1 || spaceIndents < tabIndents / 4 || first.score < 1.8) tabLength = undefined; return {ch: "\t", length: tabLength}; } if (spaceIndents > tabIndents + 1) return {ch: " ", length: tabLength}; }; exports.detectIndentation = function(session) { var lines = session.getLines(0, 1000); var indent = exports.$detectIndentation(lines) || {}; if (indent.ch) session.setUseSoftTabs(indent.ch == " "); if (indent.length) session.setTabSize(indent.length); return indent; }; exports.trimTrailingSpace = function(session, options) { var doc = session.getDocument(); var lines = doc.getAllLines(); var min = options && options.trimEmpty ? -1 : 0; var cursors = [], ci = -1; if (options && options.keepCursorPosition) { if (session.selection.rangeCount) { session.selection.rangeList.ranges.forEach(function(x, i, ranges) { var next = ranges[i + 1]; if (next && next.cursor.row == x.cursor.row) return; cursors.push(x.cursor); }); } else { cursors.push(session.selection.getCursor()); } ci = 0; } var cursorRow = cursors[ci] && cursors[ci].row; for (var i = 0, l=lines.length; i < l; i++) { var line = lines[i]; var index = line.search(/\s+$/); if (i == cursorRow) { if (index < cursors[ci].column && index > min) index = cursors[ci].column; ci++; cursorRow = cursors[ci] ? cursors[ci].row : -1; } if (index > min) doc.removeInLine(i, index, line.length); } }; exports.convertIndentation = function(session, ch, len) { var oldCh = session.getTabString()[0]; var oldLen = session.getTabSize(); if (!len) len = oldLen; if (!ch) ch = oldCh; var tab = ch == "\t" ? ch: lang.stringRepeat(ch, len); var doc = session.doc; var lines = doc.getAllLines(); var cache = {}; var spaceCache = {}; for (var i = 0, l=lines.length; i < l; i++) { var line = lines[i]; var match = line.match(/^\s*/)[0]; if (match) { var w = session.$getStringScreenWidth(match)[0]; var tabCount = Math.floor(w/oldLen); var reminder = w%oldLen; var toInsert = cache[tabCount] || (cache[tabCount] = lang.stringRepeat(tab, tabCount)); toInsert += spaceCache[reminder] || (spaceCache[reminder] = lang.stringRepeat(" ", reminder)); if (toInsert != match) { doc.removeInLine(i, 0, match.length); doc.insertInLine({row: i, column: 0}, toInsert); } } } session.setTabSize(len); session.setUseSoftTabs(ch == " "); }; exports.$parseStringArg = function(text) { var indent = {}; if (/t/.test(text)) indent.ch = "\t"; else if (/s/.test(text)) indent.ch = " "; var m = text.match(/\d+/); if (m) indent.length = parseInt(m[0], 10); return indent; }; exports.$parseArg = function(arg) { if (!arg) return {}; if (typeof arg == "string") return exports.$parseStringArg(arg); if (typeof arg.text == "string") return exports.$parseStringArg(arg.text); return arg; }; exports.commands = [{ name: "detectIndentation", exec: function(editor) { exports.detectIndentation(editor.session); } }, { name: "trimTrailingSpace", exec: function(editor) { exports.trimTrailingSpace(editor.session); } }, { name: "convertIndentation", exec: function(editor, arg) { var indent = exports.$parseArg(arg); exports.convertIndentation(editor.session, indent.ch, indent.length); } }, { name: "setIndentation", exec: function(editor, arg) { var indent = exports.$parseArg(arg); indent.length && editor.session.setTabSize(indent.length); indent.ch && editor.session.setUseSoftTabs(indent.ch == " "); } }]; }); define("kitchen-sink/doclist",["require","exports","module","ace/edit_session","ace/undomanager","ace/lib/net","ace/ext/modelist"], function(require, exports, module) { "use strict"; var EditSession = require("ace/edit_session").EditSession; var UndoManager = require("ace/undomanager").UndoManager; var net = require("ace/lib/net"); var modelist = require("ace/ext/modelist"); var fileCache = {}; function initDoc(file, path, doc) { if (doc.prepare) file = doc.prepare(file); var session = new EditSession(file); session.setUndoManager(new UndoManager()); doc.session = session; doc.path = path; session.name = doc.name; if (doc.wrapped) { session.setUseWrapMode(true); session.setWrapLimitRange(80, 80); } var mode = modelist.getModeForPath(path); session.modeName = mode.name; session.setMode(mode.mode); return session; } function makeHuge(txt) { for (var i = 0; i < 5; i++) txt += txt; return txt; } var docs = { "docs/javascript.js": {order: 1, name: "JavaScript"}, "docs/latex.tex": {name: "LaTeX", wrapped: true}, "docs/markdown.md": {name: "Markdown", wrapped: true}, "docs/mushcode.mc": {name: "MUSHCode", wrapped: true}, "docs/pgsql.pgsql": {name: "pgSQL", wrapped: true}, "docs/plaintext.txt": {name: "Plain Text", prepare: makeHuge, wrapped: true}, "docs/sql.sql": {name: "SQL", wrapped: true}, "docs/textile.textile": {name: "Textile", wrapped: true}, "docs/c9search.c9search_results": "C9 Search Results", "docs/mel.mel": "MEL", "docs/Nix.nix": "Nix" }; var ownSource = { }; var hugeDocs = require.toUrl ? { "build/src/ace.js": "", "build/src-min/ace.js": "" } : { "src/ace.js": "", "src-min/ace.js": "" }; modelist.modes.forEach(function(m) { var ext = m.extensions.split("|")[0]; if (ext[0] === "^") { path = ext.substr(1); } else { var path = m.name + "." + ext; } path = "docs/" + path; if (!docs[path]) { docs[path] = {name: m.caption}; } else if (typeof docs[path] == "object" && !docs[path].name) { docs[path].name = m.caption; } }); if (window.require && window.require.s) try { for (var path in window.require.s.contexts._.defined) { if (path.indexOf("!") != -1) path = path.split("!").pop(); else path = path + ".js"; ownSource[path] = ""; } } catch(e) {} function sort(list) { return list.sort(function(a, b) { var cmp = (b.order || 0) - (a.order || 0); return cmp || a.name && a.name.localeCompare(b.name); }); } function prepareDocList(docs) { var list = []; for (var path in docs) { var doc = docs[path]; if (typeof doc != "object") doc = {name: doc || path}; doc.path = path; doc.desc = doc.name.replace(/^(ace|docs|demo|build)\//, ""); if (doc.desc.length > 18) doc.desc = doc.desc.slice(0, 7) + ".." + doc.desc.slice(-9); fileCache[doc.name] = doc; list.push(doc); } return list; } function loadDoc(name, callback) { var doc = fileCache[name]; if (!doc) return callback(null); if (doc.session) return callback(doc.session); var path = doc.path; var parts = path.split("/"); if (parts[0] == "docs") path = "demo/kitchen-sink/" + path; else if (parts[0] == "ace") path = "lib/" + path; net.get(path, function(x) { initDoc(x, path, doc); callback(doc.session); }); } function saveDoc(name, callback) { var doc = fileCache[name] || name; if (!doc || !doc.session) return callback("Unknown document: " + name); var path = doc.path; var parts = path.split("/"); if (parts[0] == "docs") path = "demo/kitchen-sink/" + path; else if (parts[0] == "ace") path = "lib/" + path; upload(path, doc.session.getValue(), callback); } function upload(url, data, callback) { var absUrl = net.qualifyURL(url); if (/^file:/.test(absUrl)) absUrl = "http://localhost:8888/" + url; url = absUrl if (!/^https?:/.test(url)) return callback(new Error("Unsupported url scheme")); var xhr = new XMLHttpRequest(); xhr.open("PUT", url, true); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { callback(!/^2../.test(xhr.status)); } }; xhr.send(data); }; module.exports = { fileCache: fileCache, docs: sort(prepareDocList(docs)), ownSource: prepareDocList(ownSource), hugeDocs: prepareDocList(hugeDocs), initDoc: initDoc, loadDoc: loadDoc, saveDoc: saveDoc }; module.exports.all = { "Mode Examples": module.exports.docs, "Huge documents": module.exports.hugeDocs, "own source": module.exports.ownSource }; }); define("ace/ext/themelist",["require","exports","module","ace/lib/fixoldbrowsers"], function(require, exports, module) { "use strict"; require("ace/lib/fixoldbrowsers"); var themeData = [ ["Chrome" ], ["Clouds" ], ["Crimson Editor" ], ["Dawn" ], ["Dreamweaver" ], ["Eclipse" ], ["GitHub" ], ["IPlastic" ], ["Solarized Light"], ["TextMate" ], ["Tomorrow" ], ["XCode" ], ["Kuroir"], ["KatzenMilch"], ["SQL Server" ,"sqlserver" , "light"], ["Ambiance" ,"ambiance" , "dark"], ["Chaos" ,"chaos" , "dark"], ["Clouds Midnight" ,"clouds_midnight" , "dark"], ["Cobalt" ,"cobalt" , "dark"], ["Gruvbox" ,"gruvbox" , "dark"], ["Green on Black" ,"gob" , "dark"], ["idle Fingers" ,"idle_fingers" , "dark"], ["krTheme" ,"kr_theme" , "dark"], ["Merbivore" ,"merbivore" , "dark"], ["Merbivore Soft" ,"merbivore_soft" , "dark"], ["Mono Industrial" ,"mono_industrial" , "dark"], ["Monokai" ,"monokai" , "dark"], ["Pastel on dark" ,"pastel_on_dark" , "dark"], ["Solarized Dark" ,"solarized_dark" , "dark"], ["Terminal" ,"terminal" , "dark"], ["Tomorrow Night" ,"tomorrow_night" , "dark"], ["Tomorrow Night Blue" ,"tomorrow_night_blue" , "dark"], ["Tomorrow Night Bright","tomorrow_night_bright" , "dark"], ["Tomorrow Night 80s" ,"tomorrow_night_eighties" , "dark"], ["Twilight" ,"twilight" , "dark"], ["Vibrant Ink" ,"vibrant_ink" , "dark"] ]; exports.themesByName = {}; exports.themes = themeData.map(function(data) { var name = data[1] || data[0].replace(/ /g, "_").toLowerCase(); var theme = { caption: data[0], theme: "ace/theme/" + name, isDark: data[2] == "dark", name: name }; exports.themesByName[name] = theme; return theme; }); }); define("kitchen-sink/layout",["require","exports","module","ace/lib/dom","ace/lib/event","ace/edit_session","ace/undomanager","ace/virtual_renderer","ace/editor","ace/multi_select","ace/theme/textmate"], function(require, exports, module) { "use strict"; var dom = require("ace/lib/dom"); var event = require("ace/lib/event"); var EditSession = require("ace/edit_session").EditSession; var UndoManager = require("ace/undomanager").UndoManager; var Renderer = require("ace/virtual_renderer").VirtualRenderer; var Editor = require("ace/editor").Editor; var MultiSelect = require("ace/multi_select").MultiSelect; dom.importCssString("\ splitter {\ border: 1px solid #C6C6D2;\ width: 0px;\ cursor: ew-resize;\ z-index:10}\ splitter:hover {\ margin-left: -2px;\ width:3px;\ border-color: #B5B4E0;\ }\ ", "splitEditor"); exports.edit = function(el) { if (typeof(el) == "string") el = document.getElementById(el); var editor = new Editor(new Renderer(el, require("ace/theme/textmate"))); editor.resize(); event.addListener(window, "resize", function() { editor.resize(); }); return editor; }; var SplitRoot = function(el, theme, position, getSize) { el.style.position = position || "relative"; this.container = el; this.getSize = getSize || this.getSize; this.resize = this.$resize.bind(this); event.addListener(el.ownerDocument.defaultView, "resize", this.resize); this.editor = this.createEditor(); }; (function(){ this.createEditor = function() { var el = document.createElement("div"); el.className = this.$editorCSS; el.style.cssText = "position: absolute; top:0px; bottom:0px"; this.$container.appendChild(el); var session = new EditSession(""); var editor = new Editor(new Renderer(el, this.$theme)); this.$editors.push(editor); editor.setFontSize(this.$fontSize); return editor; }; this.$resize = function() { var size = this.getSize(this.container); this.rect = { x: size.left, y: size.top, w: size.width, h: size.height }; this.item.resize(this.rect); }; this.getSize = function(el) { return el.getBoundingClientRect(); }; this.destroy = function() { var win = this.container.ownerDocument.defaultView; event.removeListener(win, "resize", this.resize); }; }).call(SplitRoot.prototype); var Split = function(){ }; (function(){ this.execute = function(options) { this.$u.execute(options); }; }).call(Split.prototype); exports.singleLineEditor = function(el) { var renderer = new Renderer(el); el.style.overflow = "hidden"; renderer.screenToTextCoordinates = function(x, y) { var pos = this.pixelToScreenCoordinates(x, y); return this.session.screenToDocumentPosition( Math.min(this.session.getScreenLength() - 1, Math.max(pos.row, 0)), Math.max(pos.column, 0) ); }; renderer.$maxLines = 4; renderer.setStyle("ace_one-line"); var editor = new Editor(renderer); editor.session.setUndoManager(new UndoManager()); editor.setShowPrintMargin(false); editor.renderer.setShowGutter(false); editor.renderer.setHighlightGutterLine(false); editor.$mouseHandler.$focusWaitTimout = 0; return editor; }; }); define("kitchen-sink/token_tooltip",["require","exports","module","ace/lib/dom","ace/lib/oop","ace/lib/event","ace/range","ace/tooltip"], function(require, exports, module) { "use strict"; var dom = require("ace/lib/dom"); var oop = require("ace/lib/oop"); var event = require("ace/lib/event"); var Range = require("ace/range").Range; var Tooltip = require("ace/tooltip").Tooltip; function TokenTooltip (editor) { if (editor.tokenTooltip) return; Tooltip.call(this, editor.container); editor.tokenTooltip = this; this.editor = editor; this.update = this.update.bind(this); this.onMouseMove = this.onMouseMove.bind(this); this.onMouseOut = this.onMouseOut.bind(this); event.addListener(editor.renderer.scroller, "mousemove", this.onMouseMove); event.addListener(editor.renderer.content, "mouseout", this.onMouseOut); } oop.inherits(TokenTooltip, Tooltip); (function(){ this.token = {}; this.range = new Range(); this.update = function() { this.$timer = null; var r = this.editor.renderer; if (this.lastT - (r.timeStamp || 0) > 1000) { r.rect = null; r.timeStamp = this.lastT; this.maxHeight = window.innerHeight; this.maxWidth = window.innerWidth; } var canvasPos = r.rect || (r.rect = r.scroller.getBoundingClientRect()); var offset = (this.x + r.scrollLeft - canvasPos.left - r.$padding) / r.characterWidth; var row = Math.floor((this.y + r.scrollTop - canvasPos.top) / r.lineHeight); var col = Math.round(offset); var screenPos = {row: row, column: col, side: offset - col > 0 ? 1 : -1}; var session = this.editor.session; var docPos = session.screenToDocumentPosition(screenPos.row, screenPos.column); var token = session.getTokenAt(docPos.row, docPos.column); if (!token && !session.getLine(docPos.row)) { token = { type: "", value: "", state: session.bgTokenizer.getState(0) }; } if (!token) { session.removeMarker(this.marker); this.hide(); return; } var tokenText = token.type; if (token.state) tokenText += "|" + token.state; if (token.merge) tokenText += "\n merge"; if (token.stateTransitions) tokenText += "\n " + token.stateTransitions.join("\n "); if (this.tokenText != tokenText) { this.setText(tokenText); this.width = this.getWidth(); this.height = this.getHeight(); this.tokenText = tokenText; } this.show(null, this.x, this.y); this.token = token; session.removeMarker(this.marker); this.range = new Range(docPos.row, token.start, docPos.row, token.start + token.value.length); this.marker = session.addMarker(this.range, "ace_bracket", "text"); }; this.onMouseMove = function(e) { this.x = e.clientX; this.y = e.clientY; if (this.isOpen) { this.lastT = e.timeStamp; this.setPosition(this.x, this.y); } if (!this.$timer) this.$timer = setTimeout(this.update, 100); }; this.onMouseOut = function(e) { if (e && e.currentTarget.contains(e.relatedTarget)) return; this.hide(); this.editor.session.removeMarker(this.marker); this.$timer = clearTimeout(this.$timer); }; this.setPosition = function(x, y) { if (x + 10 + this.width > this.maxWidth) x = window.innerWidth - this.width - 10; if (y > window.innerHeight * 0.75 || y + 20 + this.height > this.maxHeight) y = y - this.height - 30; Tooltip.prototype.setPosition.call(this, x + 10, y + 20); }; this.destroy = function() { this.onMouseOut(); event.removeListener(this.editor.renderer.scroller, "mousemove", this.onMouseMove); event.removeListener(this.editor.renderer.content, "mouseout", this.onMouseOut); delete this.editor.tokenTooltip; }; }).call(TokenTooltip.prototype); exports.TokenTooltip = TokenTooltip; }); define("kitchen-sink/util",["require","exports","module","ace/lib/dom","ace/lib/event","ace/edit_session","ace/undomanager","ace/virtual_renderer","ace/editor","ace/multi_select"], function(require, exports, module) { "use strict"; var dom = require("ace/lib/dom"); var event = require("ace/lib/event"); var EditSession = require("ace/edit_session").EditSession; var UndoManager = require("ace/undomanager").UndoManager; var Renderer = require("ace/virtual_renderer").VirtualRenderer; var Editor = require("ace/editor").Editor; var MultiSelect = require("ace/multi_select").MultiSelect; var urlOptions = {} try { window.location.search.slice(1).split(/[&]/).forEach(function(e) { var parts = e.split("="); urlOptions[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]); }); } catch(e) { console.error(e); } exports.createEditor = function(el) { return new Editor(new Renderer(el)); }; exports.createSplitEditor = function(el) { if (typeof(el) == "string") el = document.getElementById(el); var e0 = document.createElement("div"); var s = document.createElement("splitter"); var e1 = document.createElement("div"); el.appendChild(e0); el.appendChild(e1); el.appendChild(s); e0.style.position = e1.style.position = s.style.position = "absolute"; el.style.position = "relative"; var split = {$container: el}; split.editor0 = split[0] = new Editor(new Renderer(e0)); split.editor1 = split[1] = new Editor(new Renderer(e1)); split.splitter = s; s.ratio = 0.5; split.resize = function resize(){ var height = el.parentNode.clientHeight - el.offsetTop; var total = el.clientWidth; var w1 = total * s.ratio; var w2 = total * (1- s.ratio); s.style.left = w1 - 1 + "px"; s.style.height = el.style.height = height + "px"; var st0 = split[0].container.style; var st1 = split[1].container.style; st0.width = w1 + "px"; st1.width = w2 + "px"; st0.left = 0 + "px"; st1.left = w1 + "px"; st0.top = st1.top = "0px"; st0.height = st1.height = height + "px"; split[0].resize(); split[1].resize(); }; split.onMouseDown = function(e) { var rect = el.getBoundingClientRect(); var x = e.clientX; var y = e.clientY; var button = e.button; if (button !== 0) { return; } var onMouseMove = function(e) { x = e.clientX; y = e.clientY; }; var onResizeEnd = function(e) { clearInterval(timerId); }; var onResizeInterval = function() { s.ratio = (x - rect.left) / rect.width; split.resize(); }; event.capture(s, onMouseMove, onResizeEnd); var timerId = setInterval(onResizeInterval, 40); return e.preventDefault(); }; event.addListener(s, "mousedown", split.onMouseDown); event.addListener(window, "resize", split.resize); split.resize(); return split; }; exports.stripLeadingComments = function(str) { if(str.slice(0,2)=='/*') { var j = str.indexOf('*/')+2; str = str.substr(j); } return str.trim() + "\n"; }; exports.saveOption = function(el, val) { if (!el.onchange && !el.onclick) return; if ("checked" in el) { if (val !== undefined) el.checked = val; localStorage && localStorage.setItem(el.id, el.checked ? 1 : 0); } else { if (val !== undefined) el.value = val; localStorage && localStorage.setItem(el.id, el.value); } }; exports.bindCheckbox = function(id, callback, noInit) { if (typeof id == "string") var el = document.getElementById(id); else { var el = id; id = el.id; } var el = document.getElementById(id); if (urlOptions[id]) el.checked = urlOptions[id] == "1"; else if (localStorage && localStorage.getItem(id)) el.checked = localStorage.getItem(id) == "1"; var onCheck = function() { callback(!!el.checked); exports.saveOption(el); }; el.onclick = onCheck; noInit || onCheck(); return el; }; exports.bindDropdown = function(id, callback, noInit) { if (typeof id == "string") var el = document.getElementById(id); else { var el = id; id = el.id; } if (urlOptions[id]) el.value = urlOptions[id]; else if (localStorage && localStorage.getItem(id)) el.value = localStorage.getItem(id); var onChange = function() { callback(el.value); exports.saveOption(el); }; el.onchange = onChange; noInit || onChange(); }; exports.fillDropdown = function(el, values) { if (typeof el == "string") el = document.getElementById(el); dropdown(values).forEach(function(e) { el.appendChild(e); }); }; function elt(tag, attributes, content) { var el = dom.createElement(tag); if (typeof content == "string") { el.appendChild(document.createTextNode(content)); } else if (content) { content.forEach(function(ch) { el.appendChild(ch); }); } for (var i in attributes) el.setAttribute(i, attributes[i]); return el; } function optgroup(values) { return values.map(function(item) { if (typeof item == "string") item = {name: item, caption: item}; return elt("option", {value: item.value || item.name}, item.caption || item.desc); }); } function dropdown(values) { if (Array.isArray(values)) return optgroup(values); return Object.keys(values).map(function(i) { return elt("optgroup", {"label": i}, optgroup(values[i])); }); } }); define("ace/ext/elastic_tabstops_lite",["require","exports","module","ace/editor","ace/config"], function(require, exports, module) { "use strict"; var ElasticTabstopsLite = function(editor) { this.$editor = editor; var self = this; var changedRows = []; var recordChanges = false; this.onAfterExec = function() { recordChanges = false; self.processRows(changedRows); changedRows = []; }; this.onExec = function() { recordChanges = true; }; this.onChange = function(delta) { if (recordChanges) { if (changedRows.indexOf(delta.start.row) == -1) changedRows.push(delta.start.row); if (delta.end.row != delta.start.row) changedRows.push(delta.end.row); } }; }; (function() { this.processRows = function(rows) { this.$inChange = true; var checkedRows = []; for (var r = 0, rowCount = rows.length; r < rowCount; r++) { var row = rows[r]; if (checkedRows.indexOf(row) > -1) continue; var cellWidthObj = this.$findCellWidthsForBlock(row); var cellWidths = this.$setBlockCellWidthsToMax(cellWidthObj.cellWidths); var rowIndex = cellWidthObj.firstRow; for (var w = 0, l = cellWidths.length; w < l; w++) { var widths = cellWidths[w]; checkedRows.push(rowIndex); this.$adjustRow(rowIndex, widths); rowIndex++; } } this.$inChange = false; }; this.$findCellWidthsForBlock = function(row) { var cellWidths = [], widths; var rowIter = row; while (rowIter >= 0) { widths = this.$cellWidthsForRow(rowIter); if (widths.length == 0) break; cellWidths.unshift(widths); rowIter--; } var firstRow = rowIter + 1; rowIter = row; var numRows = this.$editor.session.getLength(); while (rowIter < numRows - 1) { rowIter++; widths = this.$cellWidthsForRow(rowIter); if (widths.length == 0) break; cellWidths.push(widths); } return { cellWidths: cellWidths, firstRow: firstRow }; }; this.$cellWidthsForRow = function(row) { var selectionColumns = this.$selectionColumnsForRow(row); var tabs = [-1].concat(this.$tabsForRow(row)); var widths = tabs.map(function(el) { return 0; } ).slice(1); var line = this.$editor.session.getLine(row); for (var i = 0, len = tabs.length - 1; i < len; i++) { var leftEdge = tabs[i]+1; var rightEdge = tabs[i+1]; var rightmostSelection = this.$rightmostSelectionInCell(selectionColumns, rightEdge); var cell = line.substring(leftEdge, rightEdge); widths[i] = Math.max(cell.replace(/\s+$/g,'').length, rightmostSelection - leftEdge); } return widths; }; this.$selectionColumnsForRow = function(row) { var selections = [], cursor = this.$editor.getCursorPosition(); if (this.$editor.session.getSelection().isEmpty()) { if (row == cursor.row) selections.push(cursor.column); } return selections; }; this.$setBlockCellWidthsToMax = function(cellWidths) { var startingNewBlock = true, blockStartRow, blockEndRow, maxWidth; var columnInfo = this.$izip_longest(cellWidths); for (var c = 0, l = columnInfo.length; c < l; c++) { var column = columnInfo[c]; if (!column.push) { console.error(column); continue; } column.push(NaN); for (var r = 0, s = column.length; r < s; r++) { var width = column[r]; if (startingNewBlock) { blockStartRow = r; maxWidth = 0; startingNewBlock = false; } if (isNaN(width)) { blockEndRow = r; for (var j = blockStartRow; j < blockEndRow; j++) { cellWidths[j][c] = maxWidth; } startingNewBlock = true; } maxWidth = Math.max(maxWidth, width); } } return cellWidths; }; this.$rightmostSelectionInCell = function(selectionColumns, cellRightEdge) { var rightmost = 0; if (selectionColumns.length) { var lengths = []; for (var s = 0, length = selectionColumns.length; s < length; s++) { if (selectionColumns[s] <= cellRightEdge) lengths.push(s); else lengths.push(0); } rightmost = Math.max.apply(Math, lengths); } return rightmost; }; this.$tabsForRow = function(row) { var rowTabs = [], line = this.$editor.session.getLine(row), re = /\t/g, match; while ((match = re.exec(line)) != null) { rowTabs.push(match.index); } return rowTabs; }; this.$adjustRow = function(row, widths) { var rowTabs = this.$tabsForRow(row); if (rowTabs.length == 0) return; var bias = 0, location = -1; var expandedSet = this.$izip(widths, rowTabs); for (var i = 0, l = expandedSet.length; i < l; i++) { var w = expandedSet[i][0], it = expandedSet[i][1]; location += 1 + w; it += bias; var difference = location - it; if (difference == 0) continue; var partialLine = this.$editor.session.getLine(row).substr(0, it ); var strippedPartialLine = partialLine.replace(/\s*$/g, ""); var ispaces = partialLine.length - strippedPartialLine.length; if (difference > 0) { this.$editor.session.getDocument().insertInLine({row: row, column: it + 1}, Array(difference + 1).join(" ") + "\t"); this.$editor.session.getDocument().removeInLine(row, it, it + 1); bias += difference; } if (difference < 0 && ispaces >= -difference) { this.$editor.session.getDocument().removeInLine(row, it + difference, it); bias += difference; } } }; this.$izip_longest = function(iterables) { if (!iterables[0]) return []; var longest = iterables[0].length; var iterablesLength = iterables.length; for (var i = 1; i < iterablesLength; i++) { var iLength = iterables[i].length; if (iLength > longest) longest = iLength; } var expandedSet = []; for (var l = 0; l < longest; l++) { var set = []; for (var i = 0; i < iterablesLength; i++) { if (iterables[i][l] === "") set.push(NaN); else set.push(iterables[i][l]); } expandedSet.push(set); } return expandedSet; }; this.$izip = function(widths, tabs) { var size = widths.length >= tabs.length ? tabs.length : widths.length; var expandedSet = []; for (var i = 0; i < size; i++) { var set = [ widths[i], tabs[i] ]; expandedSet.push(set); } return expandedSet; }; }).call(ElasticTabstopsLite.prototype); exports.ElasticTabstopsLite = ElasticTabstopsLite; var Editor = require("../editor").Editor; require("../config").defineOptions(Editor.prototype, "editor", { useElasticTabstops: { set: function(val) { if (val) { if (!this.elasticTabstops) this.elasticTabstops = new ElasticTabstopsLite(this); this.commands.on("afterExec", this.elasticTabstops.onAfterExec); this.commands.on("exec", this.elasticTabstops.onExec); this.on("change", this.elasticTabstops.onChange); } else if (this.elasticTabstops) { this.commands.removeListener("afterExec", this.elasticTabstops.onAfterExec); this.commands.removeListener("exec", this.elasticTabstops.onExec); this.removeListener("change", this.elasticTabstops.onChange); } } } }); }); define("ace/occur",["require","exports","module","ace/lib/oop","ace/range","ace/search","ace/edit_session","ace/search_highlight","ace/lib/dom"], function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); var Range = require("./range").Range; var Search = require("./search").Search; var EditSession = require("./edit_session").EditSession; var SearchHighlight = require("./search_highlight").SearchHighlight; function Occur() {} oop.inherits(Occur, Search); (function() { this.enter = function(editor, options) { if (!options.needle) return false; var pos = editor.getCursorPosition(); this.displayOccurContent(editor, options); var translatedPos = this.originalToOccurPosition(editor.session, pos); editor.moveCursorToPosition(translatedPos); return true; } this.exit = function(editor, options) { var pos = options.translatePosition && editor.getCursorPosition(); var translatedPos = pos && this.occurToOriginalPosition(editor.session, pos); this.displayOriginalContent(editor); if (translatedPos) editor.moveCursorToPosition(translatedPos); return true; } this.highlight = function(sess, regexp) { var hl = sess.$occurHighlight = sess.$occurHighlight || sess.addDynamicMarker( new SearchHighlight(null, "ace_occur-highlight", "text")); hl.setRegexp(regexp); sess._emit("changeBackMarker"); // force highlight layer redraw } this.displayOccurContent = function(editor, options) { this.$originalSession = editor.session; var found = this.matchingLines(editor.session, options); var lines = found.map(function(foundLine) { return foundLine.content; }); var occurSession = new EditSession(lines.join('\n')); occurSession.$occur = this; occurSession.$occurMatchingLines = found; editor.setSession(occurSession); this.$useEmacsStyleLineStart = this.$originalSession.$useEmacsStyleLineStart; occurSession.$useEmacsStyleLineStart = this.$useEmacsStyleLineStart; this.highlight(occurSession, options.re); occurSession._emit('changeBackMarker'); } this.displayOriginalContent = function(editor) { editor.setSession(this.$originalSession); this.$originalSession.$useEmacsStyleLineStart = this.$useEmacsStyleLineStart; } this.originalToOccurPosition = function(session, pos) { var lines = session.$occurMatchingLines; var nullPos = {row: 0, column: 0}; if (!lines) return nullPos; for (var i = 0; i < lines.length; i++) { if (lines[i].row === pos.row) return {row: i, column: pos.column}; } return nullPos; } this.occurToOriginalPosition = function(session, pos) { var lines = session.$occurMatchingLines; if (!lines || !lines[pos.row]) return pos; return {row: lines[pos.row].row, column: pos.column}; } this.matchingLines = function(session, options) { options = oop.mixin({}, options); if (!session || !options.needle) return []; var search = new Search(); search.set(options); return search.findAll(session).reduce(function(lines, range) { var row = range.start.row; var last = lines[lines.length-1]; return last && last.row === row ? lines : lines.concat({row: row, content: session.getLine(row)}); }, []); } }).call(Occur.prototype); var dom = require('./lib/dom'); dom.importCssString(".ace_occur-highlight {\n\ border-radius: 4px;\n\ background-color: rgba(87, 255, 8, 0.25);\n\ position: absolute;\n\ z-index: 4;\n\ -moz-box-sizing: border-box;\n\ -webkit-box-sizing: border-box;\n\ box-sizing: border-box;\n\ box-shadow: 0 0 4px rgb(91, 255, 50);\n\ }\n\ .ace_dark .ace_occur-highlight {\n\ background-color: rgb(80, 140, 85);\n\ box-shadow: 0 0 4px rgb(60, 120, 70);\n\ }\n", "incremental-occur-highlighting"); exports.Occur = Occur; }); define("ace/commands/occur_commands",["require","exports","module","ace/config","ace/occur","ace/keyboard/hash_handler","ace/lib/oop"], function(require, exports, module) { var config = require("../config"), Occur = require("../occur").Occur; var occurStartCommand = { name: "occur", exec: function(editor, options) { var alreadyInOccur = !!editor.session.$occur; var occurSessionActive = new Occur().enter(editor, options); if (occurSessionActive && !alreadyInOccur) OccurKeyboardHandler.installIn(editor); }, readOnly: true }; var occurCommands = [{ name: "occurexit", bindKey: 'esc|Ctrl-G', exec: function(editor) { var occur = editor.session.$occur; if (!occur) return; occur.exit(editor, {}); if (!editor.session.$occur) OccurKeyboardHandler.uninstallFrom(editor); }, readOnly: true }, { name: "occuraccept", bindKey: 'enter', exec: function(editor) { var occur = editor.session.$occur; if (!occur) return; occur.exit(editor, {translatePosition: true}); if (!editor.session.$occur) OccurKeyboardHandler.uninstallFrom(editor); }, readOnly: true }]; var HashHandler = require("../keyboard/hash_handler").HashHandler; var oop = require("../lib/oop"); function OccurKeyboardHandler() {} oop.inherits(OccurKeyboardHandler, HashHandler); (function() { this.isOccurHandler = true; this.attach = function(editor) { HashHandler.call(this, occurCommands, editor.commands.platform); this.$editor = editor; } var handleKeyboard$super = this.handleKeyboard; this.handleKeyboard = function(data, hashId, key, keyCode) { var cmd = handleKeyboard$super.call(this, data, hashId, key, keyCode); return (cmd && cmd.command) ? cmd : undefined; } }).call(OccurKeyboardHandler.prototype); OccurKeyboardHandler.installIn = function(editor) { var handler = new this(); editor.keyBinding.addKeyboardHandler(handler); editor.commands.addCommands(occurCommands); } OccurKeyboardHandler.uninstallFrom = function(editor) { editor.commands.removeCommands(occurCommands); var handler = editor.getKeyboardHandler(); if (handler.isOccurHandler) editor.keyBinding.removeKeyboardHandler(handler); } exports.occurStartCommand = occurStartCommand; }); define("ace/commands/incremental_search_commands",["require","exports","module","ace/config","ace/lib/oop","ace/keyboard/hash_handler","ace/commands/occur_commands"], function(require, exports, module) { var config = require("../config"); var oop = require("../lib/oop"); var HashHandler = require("../keyboard/hash_handler").HashHandler; var occurStartCommand = require("./occur_commands").occurStartCommand; exports.iSearchStartCommands = [{ name: "iSearch", bindKey: {win: "Ctrl-F", mac: "Command-F"}, exec: function(editor, options) { config.loadModule(["core", "ace/incremental_search"], function(e) { var iSearch = e.iSearch = e.iSearch || new e.IncrementalSearch(); iSearch.activate(editor, options.backwards); if (options.jumpToFirstMatch) iSearch.next(options); }); }, readOnly: true }, { name: "iSearchBackwards", exec: function(editor, jumpToNext) { editor.execCommand('iSearch', {backwards: true}); }, readOnly: true }, { name: "iSearchAndGo", bindKey: {win: "Ctrl-K", mac: "Command-G"}, exec: function(editor, jumpToNext) { editor.execCommand('iSearch', {jumpToFirstMatch: true, useCurrentOrPrevSearch: true}); }, readOnly: true }, { name: "iSearchBackwardsAndGo", bindKey: {win: "Ctrl-Shift-K", mac: "Command-Shift-G"}, exec: function(editor) { editor.execCommand('iSearch', {jumpToFirstMatch: true, backwards: true, useCurrentOrPrevSearch: true}); }, readOnly: true }]; exports.iSearchCommands = [{ name: "restartSearch", bindKey: {win: "Ctrl-F", mac: "Command-F"}, exec: function(iSearch) { iSearch.cancelSearch(true); } }, { name: "searchForward", bindKey: {win: "Ctrl-S|Ctrl-K", mac: "Ctrl-S|Command-G"}, exec: function(iSearch, options) { options.useCurrentOrPrevSearch = true; iSearch.next(options); } }, { name: "searchBackward", bindKey: {win: "Ctrl-R|Ctrl-Shift-K", mac: "Ctrl-R|Command-Shift-G"}, exec: function(iSearch, options) { options.useCurrentOrPrevSearch = true; options.backwards = true; iSearch.next(options); } }, { name: "extendSearchTerm", exec: function(iSearch, string) { iSearch.addString(string); } }, { name: "extendSearchTermSpace", bindKey: "space", exec: function(iSearch) { iSearch.addString(' '); } }, { name: "shrinkSearchTerm", bindKey: "backspace", exec: function(iSearch) { iSearch.removeChar(); } }, { name: 'confirmSearch', bindKey: 'return', exec: function(iSearch) { iSearch.deactivate(); } }, { name: 'cancelSearch', bindKey: 'esc|Ctrl-G', exec: function(iSearch) { iSearch.deactivate(true); } }, { name: 'occurisearch', bindKey: 'Ctrl-O', exec: function(iSearch) { var options = oop.mixin({}, iSearch.$options); iSearch.deactivate(); occurStartCommand.exec(iSearch.$editor, options); } }, { name: "yankNextWord", bindKey: "Ctrl-w", exec: function(iSearch) { var ed = iSearch.$editor, range = ed.selection.getRangeOfMovements(function(sel) { sel.moveCursorWordRight(); }), string = ed.session.getTextRange(range); iSearch.addString(string); } }, { name: "yankNextChar", bindKey: "Ctrl-Alt-y", exec: function(iSearch) { var ed = iSearch.$editor, range = ed.selection.getRangeOfMovements(function(sel) { sel.moveCursorRight(); }), string = ed.session.getTextRange(range); iSearch.addString(string); } }, { name: 'recenterTopBottom', bindKey: 'Ctrl-l', exec: function(iSearch) { iSearch.$editor.execCommand('recenterTopBottom'); } }, { name: 'selectAllMatches', bindKey: 'Ctrl-space', exec: function(iSearch) { var ed = iSearch.$editor, hl = ed.session.$isearchHighlight, ranges = hl && hl.cache ? hl.cache .reduce(function(ranges, ea) { return ranges.concat(ea ? ea : []); }, []) : []; iSearch.deactivate(false); ranges.forEach(ed.selection.addRange.bind(ed.selection)); } }, { name: 'searchAsRegExp', bindKey: 'Alt-r', exec: function(iSearch) { iSearch.convertNeedleToRegExp(); } }].map(function(cmd) { cmd.readOnly = true; cmd.isIncrementalSearchCommand = true; cmd.scrollIntoView = "animate-cursor"; return cmd; }); function IncrementalSearchKeyboardHandler(iSearch) { this.$iSearch = iSearch; } oop.inherits(IncrementalSearchKeyboardHandler, HashHandler); (function() { this.attach = function(editor) { var iSearch = this.$iSearch; HashHandler.call(this, exports.iSearchCommands, editor.commands.platform); this.$commandExecHandler = editor.commands.addEventListener('exec', function(e) { if (!e.command.isIncrementalSearchCommand) return iSearch.deactivate(); e.stopPropagation(); e.preventDefault(); var scrollTop = editor.session.getScrollTop(); var result = e.command.exec(iSearch, e.args || {}); editor.renderer.scrollCursorIntoView(null, 0.5); editor.renderer.animateScrolling(scrollTop); return result; }); }; this.detach = function(editor) { if (!this.$commandExecHandler) return; editor.commands.removeEventListener('exec', this.$commandExecHandler); delete this.$commandExecHandler; }; var handleKeyboard$super = this.handleKeyboard; this.handleKeyboard = function(data, hashId, key, keyCode) { if (((hashId === 1/*ctrl*/ || hashId === 8/*command*/) && key === 'v') || (hashId === 1/*ctrl*/ && key === 'y')) return null; var cmd = handleKeyboard$super.call(this, data, hashId, key, keyCode); if (cmd.command) { return cmd; } if (hashId == -1) { var extendCmd = this.commands.extendSearchTerm; if (extendCmd) { return {command: extendCmd, args: key}; } } return false; }; }).call(IncrementalSearchKeyboardHandler.prototype); exports.IncrementalSearchKeyboardHandler = IncrementalSearchKeyboardHandler; }); define("ace/incremental_search",["require","exports","module","ace/lib/oop","ace/range","ace/search","ace/search_highlight","ace/commands/incremental_search_commands","ace/lib/dom","ace/commands/command_manager","ace/editor","ace/config"], function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); var Range = require("./range").Range; var Search = require("./search").Search; var SearchHighlight = require("./search_highlight").SearchHighlight; var iSearchCommandModule = require("./commands/incremental_search_commands"); var ISearchKbd = iSearchCommandModule.IncrementalSearchKeyboardHandler; function IncrementalSearch() { this.$options = {wrap: false, skipCurrent: false}; this.$keyboardHandler = new ISearchKbd(this); } oop.inherits(IncrementalSearch, Search); function isRegExp(obj) { return obj instanceof RegExp; } function regExpToObject(re) { var string = String(re), start = string.indexOf('/'), flagStart = string.lastIndexOf('/'); return { expression: string.slice(start+1, flagStart), flags: string.slice(flagStart+1) } } function stringToRegExp(string, flags) { try { return new RegExp(string, flags); } catch (e) { return string; } } function objectToRegExp(obj) { return stringToRegExp(obj.expression, obj.flags); } (function() { this.activate = function(ed, backwards) { this.$editor = ed; this.$startPos = this.$currentPos = ed.getCursorPosition(); this.$options.needle = ''; this.$options.backwards = backwards; ed.keyBinding.addKeyboardHandler(this.$keyboardHandler); this.$originalEditorOnPaste = ed.onPaste; ed.onPaste = this.onPaste.bind(this); this.$mousedownHandler = ed.addEventListener('mousedown', this.onMouseDown.bind(this)); this.selectionFix(ed); this.statusMessage(true); }; this.deactivate = function(reset) { this.cancelSearch(reset); var ed = this.$editor; ed.keyBinding.removeKeyboardHandler(this.$keyboardHandler); if (this.$mousedownHandler) { ed.removeEventListener('mousedown', this.$mousedownHandler); delete this.$mousedownHandler; } ed.onPaste = this.$originalEditorOnPaste; this.message(''); }; this.selectionFix = function(editor) { if (editor.selection.isEmpty() && !editor.session.$emacsMark) { editor.clearSelection(); } }; this.highlight = function(regexp) { var sess = this.$editor.session, hl = sess.$isearchHighlight = sess.$isearchHighlight || sess.addDynamicMarker( new SearchHighlight(null, "ace_isearch-result", "text")); hl.setRegexp(regexp); sess._emit("changeBackMarker"); // force highlight layer redraw }; this.cancelSearch = function(reset) { var e = this.$editor; this.$prevNeedle = this.$options.needle; this.$options.needle = ''; if (reset) { e.moveCursorToPosition(this.$startPos); this.$currentPos = this.$startPos; } else { e.pushEmacsMark && e.pushEmacsMark(this.$startPos, false); } this.highlight(null); return Range.fromPoints(this.$currentPos, this.$currentPos); }; this.highlightAndFindWithNeedle = function(moveToNext, needleUpdateFunc) { if (!this.$editor) return null; var options = this.$options; if (needleUpdateFunc) { options.needle = needleUpdateFunc.call(this, options.needle || '') || ''; } if (options.needle.length === 0) { this.statusMessage(true); return this.cancelSearch(true); } options.start = this.$currentPos; var session = this.$editor.session, found = this.find(session), shouldSelect = this.$editor.emacsMark ? !!this.$editor.emacsMark() : !this.$editor.selection.isEmpty(); if (found) { if (options.backwards) found = Range.fromPoints(found.end, found.start); this.$editor.selection.setRange(Range.fromPoints(shouldSelect ? this.$startPos : found.end, found.end)); if (moveToNext) this.$currentPos = found.end; this.highlight(options.re); } this.statusMessage(found); return found; }; this.addString = function(s) { return this.highlightAndFindWithNeedle(false, function(needle) { if (!isRegExp(needle)) return needle + s; var reObj = regExpToObject(needle); reObj.expression += s; return objectToRegExp(reObj); }); }; this.removeChar = function(c) { return this.highlightAndFindWithNeedle(false, function(needle) { if (!isRegExp(needle)) return needle.substring(0, needle.length-1); var reObj = regExpToObject(needle); reObj.expression = reObj.expression.substring(0, reObj.expression.length-1); return objectToRegExp(reObj); }); }; this.next = function(options) { options = options || {}; this.$options.backwards = !!options.backwards; this.$currentPos = this.$editor.getCursorPosition(); return this.highlightAndFindWithNeedle(true, function(needle) { return options.useCurrentOrPrevSearch && needle.length === 0 ? this.$prevNeedle || '' : needle; }); }; this.onMouseDown = function(evt) { this.deactivate(); return true; }; this.onPaste = function(text) { this.addString(text); }; this.convertNeedleToRegExp = function() { return this.highlightAndFindWithNeedle(false, function(needle) { return isRegExp(needle) ? needle : stringToRegExp(needle, 'ig'); }); }; this.convertNeedleToString = function() { return this.highlightAndFindWithNeedle(false, function(needle) { return isRegExp(needle) ? regExpToObject(needle).expression : needle; }); }; this.statusMessage = function(found) { var options = this.$options, msg = ''; msg += options.backwards ? 'reverse-' : ''; msg += 'isearch: ' + options.needle; msg += found ? '' : ' (not found)'; this.message(msg); }; this.message = function(msg) { if (this.$editor.showCommandLine) { this.$editor.showCommandLine(msg); this.$editor.focus(); } else { console.log(msg); } }; }).call(IncrementalSearch.prototype); exports.IncrementalSearch = IncrementalSearch; var dom = require('./lib/dom'); dom.importCssString && dom.importCssString("\ .ace_marker-layer .ace_isearch-result {\ position: absolute;\ z-index: 6;\ -moz-box-sizing: border-box;\ -webkit-box-sizing: border-box;\ box-sizing: border-box;\ }\ div.ace_isearch-result {\ border-radius: 4px;\ background-color: rgba(255, 200, 0, 0.5);\ box-shadow: 0 0 4px rgb(255, 200, 0);\ }\ .ace_dark div.ace_isearch-result {\ background-color: rgb(100, 110, 160);\ box-shadow: 0 0 4px rgb(80, 90, 140);\ }", "incremental-search-highlighting"); var commands = require("./commands/command_manager"); (function() { this.setupIncrementalSearch = function(editor, val) { if (this.usesIncrementalSearch == val) return; this.usesIncrementalSearch = val; var iSearchCommands = iSearchCommandModule.iSearchStartCommands; var method = val ? 'addCommands' : 'removeCommands'; this[method](iSearchCommands); }; }).call(commands.CommandManager.prototype); var Editor = require("./editor").Editor; require("./config").defineOptions(Editor.prototype, "editor", { useIncrementalSearch: { set: function(val) { this.keyBinding.$handlers.forEach(function(handler) { if (handler.setupIncrementalSearch) { handler.setupIncrementalSearch(this, val); } }); this._emit('incrementalSearchSettingChanged', {isEnabled: val}); } } }); }); define("ace/split",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/lib/event_emitter","ace/editor","ace/virtual_renderer","ace/edit_session"], function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); var lang = require("./lib/lang"); var EventEmitter = require("./lib/event_emitter").EventEmitter; var Editor = require("./editor").Editor; var Renderer = require("./virtual_renderer").VirtualRenderer; var EditSession = require("./edit_session").EditSession; var Split = function(container, theme, splits) { this.BELOW = 1; this.BESIDE = 0; this.$container = container; this.$theme = theme; this.$splits = 0; this.$editorCSS = ""; this.$editors = []; this.$orientation = this.BESIDE; this.setSplits(splits || 1); this.$cEditor = this.$editors[0]; this.on("focus", function(editor) { this.$cEditor = editor; }.bind(this)); }; (function(){ oop.implement(this, EventEmitter); this.$createEditor = function() { var el = document.createElement("div"); el.className = this.$editorCSS; el.style.cssText = "position: absolute; top:0px; bottom:0px"; this.$container.appendChild(el); var editor = new Editor(new Renderer(el, this.$theme)); editor.on("focus", function() { this._emit("focus", editor); }.bind(this)); this.$editors.push(editor); editor.setFontSize(this.$fontSize); return editor; }; this.setSplits = function(splits) { var editor; if (splits < 1) { throw "The number of splits have to be > 0!"; } if (splits == this.$splits) { return; } else if (splits > this.$splits) { while (this.$splits < this.$editors.length && this.$splits < splits) { editor = this.$editors[this.$splits]; this.$container.appendChild(editor.container); editor.setFontSize(this.$fontSize); this.$splits ++; } while (this.$splits < splits) { this.$createEditor(); this.$splits ++; } } else { while (this.$splits > splits) { editor = this.$editors[this.$splits - 1]; this.$container.removeChild(editor.container); this.$splits --; } } this.resize(); }; this.getSplits = function() { return this.$splits; }; this.getEditor = function(idx) { return this.$editors[idx]; }; this.getCurrentEditor = function() { return this.$cEditor; }; this.focus = function() { this.$cEditor.focus(); }; this.blur = function() { this.$cEditor.blur(); }; this.setTheme = function(theme) { this.$editors.forEach(function(editor) { editor.setTheme(theme); }); }; this.setKeyboardHandler = function(keybinding) { this.$editors.forEach(function(editor) { editor.setKeyboardHandler(keybinding); }); }; this.forEach = function(callback, scope) { this.$editors.forEach(callback, scope); }; this.$fontSize = ""; this.setFontSize = function(size) { this.$fontSize = size; this.forEach(function(editor) { editor.setFontSize(size); }); }; this.$cloneSession = function(session) { var s = new EditSession(session.getDocument(), session.getMode()); var undoManager = session.getUndoManager(); if (undoManager) { var undoManagerProxy = new UndoManagerProxy(undoManager, s); s.setUndoManager(undoManagerProxy); } s.$informUndoManager = lang.delayedCall(function() { s.$deltas = []; }); s.setTabSize(session.getTabSize()); s.setUseSoftTabs(session.getUseSoftTabs()); s.setOverwrite(session.getOverwrite()); s.setBreakpoints(session.getBreakpoints()); s.setUseWrapMode(session.getUseWrapMode()); s.setUseWorker(session.getUseWorker()); s.setWrapLimitRange(session.$wrapLimitRange.min, session.$wrapLimitRange.max); s.$foldData = session.$cloneFoldData(); return s; }; this.setSession = function(session, idx) { var editor; if (idx == null) { editor = this.$cEditor; } else { editor = this.$editors[idx]; } var isUsed = this.$editors.some(function(editor) { return editor.session === session; }); if (isUsed) { session = this.$cloneSession(session); } editor.setSession(session); return session; }; this.getOrientation = function() { return this.$orientation; }; this.setOrientation = function(orientation) { if (this.$orientation == orientation) { return; } this.$orientation = orientation; this.resize(); }; this.resize = function() { var width = this.$container.clientWidth; var height = this.$container.clientHeight; var editor; if (this.$orientation == this.BESIDE) { var editorWidth = width / this.$splits; for (var i = 0; i < this.$splits; i++) { editor = this.$editors[i]; editor.container.style.width = editorWidth + "px"; editor.container.style.top = "0px"; editor.container.style.left = i * editorWidth + "px"; editor.container.style.height = height + "px"; editor.resize(); } } else { var editorHeight = height / this.$splits; for (var i = 0; i < this.$splits; i++) { editor = this.$editors[i]; editor.container.style.width = width + "px"; editor.container.style.top = i * editorHeight + "px"; editor.container.style.left = "0px"; editor.container.style.height = editorHeight + "px"; editor.resize(); } } }; }).call(Split.prototype); function UndoManagerProxy(undoManager, session) { this.$u = undoManager; this.$doc = session; } (function() { this.execute = function(options) { this.$u.execute(options); }; this.undo = function() { var selectionRange = this.$u.undo(true); if (selectionRange) { this.$doc.selection.setSelectionRange(selectionRange); } }; this.redo = function() { var selectionRange = this.$u.redo(true); if (selectionRange) { this.$doc.selection.setSelectionRange(selectionRange); } }; this.reset = function() { this.$u.reset(); }; this.hasUndo = function() { return this.$u.hasUndo(); }; this.hasRedo = function() { return this.$u.hasRedo(); }; }).call(UndoManagerProxy.prototype); exports.Split = Split; }); 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 = CodeMirror.e_stop = function() {}; CodeMirror.keyName = function(e) { if (e.key) return e.key; var key = (KEYS[e.keyCode] || ""); 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 (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 (this.virtualSelectionMode()) return; 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") { 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.containter; }; 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; 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; } 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); }; 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.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; if (dir == 1) { var m = this.ace.session.$findClosingBracket(re.slice(1, 2), toAcePos(pos), /paren|text/); } else { var m = this.ace.session.$findOpeningBracket(re.slice(-2, -1), {row: pos.line, column: pos.ch + 1}, /paren|text/); } return m && {pos: toCmPos(m)}; }; this.refresh = function() { return this.ace.resize(true); }; this.getMode = function() { return { name : this.getOption("mode") }; } }).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: 1px solid red;\ background-color: red;\ opacity: 0.5;\ }\ .normal-mode .ace_hidden-cursors .ace_cursor{\ background-color: transparent;\ }\ .ace_dialog {\ position: absolute;\ left: 0; right: 0;\ background: white;\ z-index: 15;\ padding: .1em .8em;\ overflow: hidden;\ color: #333;\ }\ .ace_dialog-top {\ border-bottom: 1px solid #eee;\ top: 0;\ }\ .ace_dialog-bottom {\ border-top: 1px solid #eee;\ 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; function close(newVal) { if (typeof newVal == 'string') { inp.value = newVal; } else { if (closed) return; 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.select !== 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 == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) { inp.blur(); CodeMirror.e_stop(e); close(); } if (e.keyCode == 13) callback(inp.value); }); 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: '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: '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: '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: '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: '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: 'moveToEol', motionArgs: { inclusive: 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: '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 }}, { 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: '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 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: '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, false); } 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; } 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'}; 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 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) { throw Error('Unknown option: ' + name); } if (option.type == 'boolean') { if (value && value !== true) { throw 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) { throw 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, lastChararacterSearch: {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); }, 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; } 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[name]; 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(0) == '\n') { text = text.slice(1) + '\n'; } 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; 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)) return {type: 'none'}; 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 (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) { cm.scrollTo(originalScrollPos.left, originalScrollPos.top); 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; if (keyName == 'Up' || keyName == 'Down') { up = keyName == 'Up' ? true : false; query = vimGlobalState.searchHistoryController.nextMatch(query, up) || ''; close(query); } 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 == '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; 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') { up = keyName == 'Up' ? true : false; input = vimGlobalState.exCommandHistoryController.nextMatch(input, up) || ''; close(input); } 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}); } 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; } }; 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 mark = vim.marks[motionArgs.selectedCharacter]; if (mark) { var pos = mark.find(); 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) || (line > last && cur.line == last)) { return; } 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); }, 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) { var cur = head; vim.lastHPos = Infinity; var retval= Pos(cur.line + motionArgs.repeat - 1, Infinity); var end=cm.clipPos(retval); end.ch--; 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; do { symbol = lineText.charAt(ch++); if (symbol && isMatchableSymbol(symbol)) { var style = cm.getTokenTypeAt(Pos(line, ch)); if (style !== "string" && style !== "comment") { break; } } } while (symbol); if (symbol) { var matched = cm.findMatchingBracket(Pos(line, ch)); 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}; 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.lastChararacterSearch; 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; vimGlobalState.macroModeState.lastInsertModeChanges.inVisualBlock = vim.visualBlock; if (!vim.visualMode) { var anchor = ranges[0].anchor, head = ranges[0].head; 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 { 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); return clipCursorToContent(cm, finalHead); }, 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); }, 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*1.4; break; case 'top': y = y + lineHeight*0.4; 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; } while(repeat--){ executeMacroRegister(cm, vim, macroModeState, registerName); } }, enterMacroRecordMode: function(cm, actionArgs) { var macroModeState = vimGlobalState.macroModeState; var registerName = actionArgs.selectedCharacter; macroModeState.enterMacroRecordMode(cm, registerName); }, 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.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.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('keyMap', 'vim-insert'); 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.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 (linewise && !blockwise) { 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 { if (blockwise) { text = text.split('\n'); for (var i = 0; i < text.length; i++) { text[i] = (text[i] == '') ? ' ' : text[i]; } } 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 = /-?\d+/g; var match; var start; var end; var numberStr; var token; while ((match = re.exec(lineStr)) !== null) { token = match[0]; start = match.index; end = start + token.length; if (cur.ch < end)break; } if (!actionArgs.backtrack && (end <= cur.ch))return; if (token) { var increment = actionArgs.increase ? 1 : -1; var number = parseInt(token) + (increment * actionArgs.repeat); var from = Pos(cur.line, start); var to = Pos(cur.line, end); numberStr = number.toString(); 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 */); }, 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 getOffset(anchor, head) { return { line: head.line - anchor.line, ch: head.line - anchor.line }; } 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 = /^.*(<[\w\-]+>)$/.exec(keys); var selectedCharacter = match ? match[1] : keys.slice(-1); if (selectedCharacter.length > 1){ switch(selectedCharacter){ case '': selectedCharacter='\n'; break; case '': selectedCharacter=' '; break; default: 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); } primIndex = head.line == lastLine ? selections.length - 1 : 0; 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.lastChararacterSearch.increment = increment; vimGlobalState.lastChararacterSearch.forward = args.forward; vimGlobalState.lastChararacterSearch.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; } throw new Error('The impossible happened.'); } 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 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, null, {'bracketRegex': bracketRegexp}); end = cm.scanForBracket(Pos(cur.line, cur.ch + offset), 1, null, {'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}); } else { onClose(prompt(shortText, '')); } } function splitBySlash(argString) { var slashes = findUnescapedSlashes(argString) || []; 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 findUnescapedSlashes(str) { var escapeNextChar = false; var slashes = []; for (var i = 0; i < str.length; i++) { var c = str.charAt(i); if (!escapeNextChar && c == '/') { 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 = ''; if (prefix) { raw += '' + prefix + ''; } raw += ' ' + ''; if (desc) { raw += ''; raw += desc; raw += ''; } 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() } } 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 cm.getCursor().line; case '$': return cm.lastLine(); case '\'': var mark = cm.state.vim.marks[inputStream.next()]; if (mark && mark.find()) { return mark.find().line; } throw new Error('Mark not set'); default: inputStream.backUp(1); return undefined; } }, 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) }, user: true}; if (ctx) { mapping.context = ctx; } defaultKeymap.unshift(mapping); } else { var mapping = { keys: lhs, type: 'keyToKey', toKeys: rhs, user: true }; 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[i].user) { 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 === true || oldValue === false) { showConfirm(cm, ' ' + (oldValue ? '' : 'no') + optionName); } else { showConfirm(cm, ' ' + optionName + '=' + oldValue); } } else { setOption(optionName, value, cm, setCfg); } }, 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; 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(/[a-z]+/); if (opts) { opts = opts[0]; ignoreCase = opts.indexOf('i') != -1; unique = opts.indexOf('u') != -1; var decimal = opts.indexOf('d') != -1 && 1; var hex = opts.indexOf('x') != -1 && 1; var octal = opts.indexOf('o') != -1 && 1; if (decimal + hex + octal > 1) { return 'Invalid arguments'; } number = decimal && 'decimal' || hex && 'hex' || octal && 'octal'; } if (args.match(/\/.*\//)) { return 'patterns not supported'; } } } 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 = (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) { for (var i = 0; i < text.length; i++) { if (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; } numPart.sort(compareFn); 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 ? splitBySlash(argString) : []; 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 (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 + '/' + 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 { cm.save(); } }, nohlsearch: function(cm) { clearSearchHighlight(cm); }, 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; var text = []; if (!isPlaying) { var selLength = lastChange.inVisualBlock ? vim.lastSelection.visualBlock.height : 1; var changes = lastChange.changes; var text = []; var i = 0; while (i < changes.length) { text.push(changes[i]); if (changes[i] instanceof InsertModeKey) { i++; } else { i+= selLength; } } lastChange.changes = text; 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); lastChange.overwrite = cm.state.overwrite; 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'] = { 'Ctrl-N': 'autocomplete', 'Ctrl-P': 'autocomplete', 'Enter': function(cm) { var fn = CodeMirror.commands.newlineAndIndentContinueComment || CodeMirror.commands.newlineAndIndent; fn(cm); }, 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 (changeObj.origin == '+input' || changeObj.origin == 'paste' || changeObj.origin === undefined /* only in testing */) { var text = changeObj.text.join('\n'); if (lastChange.maybeReset) { lastChange.changes = []; lastChange.maybeReset = false; } 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) { 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) { 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, changeObject.overwrite); } } 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, overwrite) { function keyHandler(binding) { if (typeof binding == 'string') { CodeMirror.commands[binding](cm); } else { binding(cm); } return true; } var head = cm.getCursor('head'); var inVisualBlock = vimGlobalState.macroModeState.lastInsertModeChanges.inVisualBlock; if (inVisualBlock) { var vim = cm.state.vim; var lastSel = vim.lastSelection; var offset = getOffset(lastSel.anchor, lastSel.head); selectForInsert(cm, head, offset.line + 1); repeat = cm.listSelections().length; cm.setCursor(head); } for (var i = 0; i < repeat; i++) { if (inVisualBlock) { 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 { var cur = cm.getCursor(); var end = cur; if (overwrite && !/\n/.test(change)) { end = offsetCursor(cur, 0, change.length); } cm.replaceRange(change, cur, end); } } } if (inVisualBlock) { 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 (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; if (vim.wasInVisualBlock && !cm.ace.inMultiSelectMode) { vim.wasInVisualBlock = false; } else if (cm.ace.inMultiSelectMode && vim.visualBlock) { vim.wasInVisualBlock = true; } if (key == '' && !vim.insertMode && !vim.visualMode && cm.ace.inMultiSelectMode) { cm.ace.exitMultiSelectMode(); } else if (visualBlock || !cm.ace.inMultiSelectMode || 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); } return isHandled; } exports.CodeMirror = CodeMirror; var getVim = Vim.maybeInitVimState_; exports.handler = { $id: "ace/keyboard/vim", drawCursor: function(style, 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; } style.left = left + "px"; style.top = top + "px"; style.width = w + "px"; 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 (key == "c" && hashId == 1) { // key == "ctrl-c" if (!useragent.isMac && editor.getCopyText()) { editor.once("copy", function() { editor.selection.clearSelection(); }); return {command: "null", passEvent: true}; } } else if (!vim.insertMode) { if (useragent.isMac && this.handleMacRepeat(data, hashId, key)) { hashId = -1; key = data.inputChar; } } 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; cm.ace.renderer.setStyle("normal-mode", !getVim(cm).insertMode); cm._signal("changeStatus"); }); cm.ace.renderer.setStyle("normal-mode", !getVim(cm).insertMode); editor.renderer.$cursorLayer.drawCursor = this.drawCursor.bind(cm); this.updateMacCompositionHandlers(editor, true); }, 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); this.updateMacCompositionHandlers(editor, false); }, 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; }, handleMacRepeat: function(data, hashId, key) { if (hashId == -1) { data.inputChar = key; data.lastEvent = "input"; } else if (data.inputChar && data.$lastHash == hashId && data.$lastKey == key) { if (data.lastEvent == "input") { data.lastEvent = "input1"; } else if (data.lastEvent == "input1") { return true; } } else { data.$lastHash = hashId; data.$lastKey = key; data.lastEvent = "keypress"; } }, updateMacCompositionHandlers: function(editor, enable) { var onCompositionUpdateOverride = function(text) { var cm = editor.state.cm; var vim = getVim(cm); if (!vim.insertMode) { var el = this.textInput.getElement(); el.blur(); el.focus(); el.value = text; } else { this.onCompositionUpdateOrig(text); } }; var onCompositionStartOverride = function(text) { var cm = editor.state.cm; var vim = getVim(cm); if (!vim.insertMode) { this.onCompositionStartOrig(text); } }; if (enable) { if (!editor.onCompositionUpdateOrig) { editor.onCompositionUpdateOrig = editor.onCompositionUpdate; editor.onCompositionUpdate = onCompositionUpdateOverride; editor.onCompositionStartOrig = editor.onCompositionStart; editor.onCompositionStart = onCompositionStartOverride; } } else { if (editor.onCompositionUpdateOrig) { editor.onCompositionUpdate = editor.onCompositionUpdateOrig; editor.onCompositionUpdateOrig = null; editor.onCompositionStart = editor.onCompositionStartOrig; editor.onCompositionStartOrig = null; } } } }; var renderVirtualNumbers = { getText: function(session, row) { return (Math.abs(session.selection.lead.row - row) || (row + 1 + (row < 9? "\xb7" : "" ))) + ""; }, getWidth: function(session, lastLineNumber, config) { return session.getLength().toString().length * 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); }, detach: function(editor) { editor.renderer.$gutterLayer.$renderer = null; editor.off("changeSelection", this.update); } }; 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; Vim.map("Y", "yy", "normal"); }); define("ace/ext/statusbar",["require","exports","module","ace/lib/dom","ace/lib/lang"], function(require, exports, module) { "use strict"; var dom = require("ace/lib/dom"); var lang = require("ace/lib/lang"); var StatusBar = function(editor, parentNode) { this.element = dom.createElement("div"); this.element.className = "ace_status-indicator"; this.element.style.cssText = "display: inline-block;"; parentNode.appendChild(this.element); var statusUpdate = lang.delayedCall(function(){ this.updateStatus(editor) }.bind(this)).schedule.bind(null, 100); editor.on("changeStatus", statusUpdate); editor.on("changeSelection", statusUpdate); editor.on("keyboardActivity", statusUpdate); }; (function(){ this.updateStatus = function(editor) { var status = []; function add(str, separator) { str && status.push(str, separator || "|"); } add(editor.keyBinding.getStatusText(editor)); if (editor.commands.recording) add("REC"); var sel = editor.selection; var c = sel.lead; if (!sel.isEmpty()) { var r = editor.getSelectionRange(); add("(" + (r.end.row - r.start.row) + ":" +(r.end.column - r.start.column) + ")", " "); } add(c.row + ":" + c.column, " "); if (sel.rangeCount) add("[" + sel.rangeCount + "]", " "); status.pop(); this.element.textContent = status.join(""); }; }).call(StatusBar.prototype); exports.StatusBar = StatusBar; }); define("ace/snippets",["require","exports","module","ace/lib/oop","ace/lib/event_emitter","ace/lib/lang","ace/range","ace/anchor","ace/keyboard/hash_handler","ace/tokenizer","ace/lib/dom","ace/editor"], function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); var EventEmitter = require("./lib/event_emitter").EventEmitter; var lang = require("./lib/lang"); var Range = require("./range").Range; var Anchor = require("./anchor").Anchor; var HashHandler = require("./keyboard/hash_handler").HashHandler; var Tokenizer = require("./tokenizer").Tokenizer; var comparePoints = Range.comparePoints; var SnippetManager = function() { this.snippetMap = {}; this.snippetNameMap = {}; }; (function() { oop.implement(this, EventEmitter); this.getTokenizer = function() { function TabstopToken(str, _, stack) { str = str.substr(1); if (/^\d+$/.test(str) && !stack.inFormatString) return [{tabstopId: parseInt(str, 10)}]; return [{text: str}]; } function escape(ch) { return "(?:[^\\\\" + ch + "]|\\\\.)"; } SnippetManager.$tokenizer = new Tokenizer({ start: [ {regex: /:/, onMatch: function(val, state, stack) { if (stack.length && stack[0].expectIf) { stack[0].expectIf = false; stack[0].elseBranch = stack[0]; return [stack[0]]; } return ":"; }}, {regex: /\\./, onMatch: function(val, state, stack) { var ch = val[1]; if (ch == "}" && stack.length) { val = ch; }else if ("`$\\".indexOf(ch) != -1) { val = ch; } else if (stack.inFormatString) { if (ch == "n") val = "\n"; else if (ch == "t") val = "\n"; else if ("ulULE".indexOf(ch) != -1) { val = {changeCase: ch, local: ch > "a"}; } } return [val]; }}, {regex: /}/, onMatch: function(val, state, stack) { return [stack.length ? stack.shift() : val]; }}, {regex: /\$(?:\d+|\w+)/, onMatch: TabstopToken}, {regex: /\$\{[\dA-Z_a-z]+/, onMatch: function(str, state, stack) { var t = TabstopToken(str.substr(1), state, stack); stack.unshift(t[0]); return t; }, next: "snippetVar"}, {regex: /\n/, token: "newline", merge: false} ], snippetVar: [ {regex: "\\|" + escape("\\|") + "*\\|", onMatch: function(val, state, stack) { stack[0].choices = val.slice(1, -1).split(","); }, next: "start"}, {regex: "/(" + escape("/") + "+)/(?:(" + escape("/") + "*)/)(\\w*):?", onMatch: function(val, state, stack) { var ts = stack[0]; ts.fmtString = val; val = this.splitRegex.exec(val); ts.guard = val[1]; ts.fmt = val[2]; ts.flag = val[3]; return ""; }, next: "start"}, {regex: "`" + escape("`") + "*`", onMatch: function(val, state, stack) { stack[0].code = val.splice(1, -1); return ""; }, next: "start"}, {regex: "\\?", onMatch: function(val, state, stack) { if (stack[0]) stack[0].expectIf = true; }, next: "start"}, {regex: "([^:}\\\\]|\\\\.)*:?", token: "", next: "start"} ], formatString: [ {regex: "/(" + escape("/") + "+)/", token: "regex"}, {regex: "", onMatch: function(val, state, stack) { stack.inFormatString = true; }, next: "start"} ] }); SnippetManager.prototype.getTokenizer = function() { return SnippetManager.$tokenizer; }; return SnippetManager.$tokenizer; }; this.tokenizeTmSnippet = function(str, startState) { return this.getTokenizer().getLineTokens(str, startState).tokens.map(function(x) { return x.value || x; }); }; this.$getDefaultValue = function(editor, name) { if (/^[A-Z]\d+$/.test(name)) { var i = name.substr(1); return (this.variables[name[0] + "__"] || {})[i]; } if (/^\d+$/.test(name)) { return (this.variables.__ || {})[name]; } name = name.replace(/^TM_/, ""); if (!editor) return; var s = editor.session; switch(name) { case "CURRENT_WORD": var r = s.getWordRange(); case "SELECTION": case "SELECTED_TEXT": return s.getTextRange(r); case "CURRENT_LINE": return s.getLine(editor.getCursorPosition().row); case "PREV_LINE": // not possible in textmate return s.getLine(editor.getCursorPosition().row - 1); case "LINE_INDEX": return editor.getCursorPosition().column; case "LINE_NUMBER": return editor.getCursorPosition().row + 1; case "SOFT_TABS": return s.getUseSoftTabs() ? "YES" : "NO"; case "TAB_SIZE": return s.getTabSize(); case "FILENAME": case "FILEPATH": return ""; case "FULLNAME": return "Ace"; } }; this.variables = {}; this.getVariableValue = function(editor, varName) { if (this.variables.hasOwnProperty(varName)) return this.variables[varName](editor, varName) || ""; return this.$getDefaultValue(editor, varName) || ""; }; this.tmStrFormat = function(str, ch, editor) { var flag = ch.flag || ""; var re = ch.guard; re = new RegExp(re, flag.replace(/[^gi]/, "")); var fmtTokens = this.tokenizeTmSnippet(ch.fmt, "formatString"); var _self = this; var formatted = str.replace(re, function() { _self.variables.__ = arguments; var fmtParts = _self.resolveVariables(fmtTokens, editor); var gChangeCase = "E"; for (var i = 0; i < fmtParts.length; i++) { var ch = fmtParts[i]; if (typeof ch == "object") { fmtParts[i] = ""; if (ch.changeCase && ch.local) { var next = fmtParts[i + 1]; if (next && typeof next == "string") { if (ch.changeCase == "u") fmtParts[i] = next[0].toUpperCase(); else fmtParts[i] = next[0].toLowerCase(); fmtParts[i + 1] = next.substr(1); } } else if (ch.changeCase) { gChangeCase = ch.changeCase; } } else if (gChangeCase == "U") { fmtParts[i] = ch.toUpperCase(); } else if (gChangeCase == "L") { fmtParts[i] = ch.toLowerCase(); } } return fmtParts.join(""); }); this.variables.__ = null; return formatted; }; this.resolveVariables = function(snippet, editor) { var result = []; for (var i = 0; i < snippet.length; i++) { var ch = snippet[i]; if (typeof ch == "string") { result.push(ch); } else if (typeof ch != "object") { continue; } else if (ch.skip) { gotoNext(ch); } else if (ch.processed < i) { continue; } else if (ch.text) { var value = this.getVariableValue(editor, ch.text); if (value && ch.fmtString) value = this.tmStrFormat(value, ch); ch.processed = i; if (ch.expectIf == null) { if (value) { result.push(value); gotoNext(ch); } } else { if (value) { ch.skip = ch.elseBranch; } else gotoNext(ch); } } else if (ch.tabstopId != null) { result.push(ch); } else if (ch.changeCase != null) { result.push(ch); } } function gotoNext(ch) { var i1 = snippet.indexOf(ch, i + 1); if (i1 != -1) i = i1; } return result; }; this.insertSnippetForSelection = function(editor, snippetText) { var cursor = editor.getCursorPosition(); var line = editor.session.getLine(cursor.row); var tabString = editor.session.getTabString(); var indentString = line.match(/^\s*/)[0]; if (cursor.column < indentString.length) indentString = indentString.slice(0, cursor.column); snippetText = snippetText.replace(/\r/g, ""); var tokens = this.tokenizeTmSnippet(snippetText); tokens = this.resolveVariables(tokens, editor); tokens = tokens.map(function(x) { if (x == "\n") return x + indentString; if (typeof x == "string") return x.replace(/\t/g, tabString); return x; }); var tabstops = []; tokens.forEach(function(p, i) { if (typeof p != "object") return; var id = p.tabstopId; var ts = tabstops[id]; if (!ts) { ts = tabstops[id] = []; ts.index = id; ts.value = ""; } if (ts.indexOf(p) !== -1) return; ts.push(p); var i1 = tokens.indexOf(p, i + 1); if (i1 === -1) return; var value = tokens.slice(i + 1, i1); var isNested = value.some(function(t) {return typeof t === "object"}); if (isNested && !ts.value) { ts.value = value; } else if (value.length && (!ts.value || typeof ts.value !== "string")) { ts.value = value.join(""); } }); tabstops.forEach(function(ts) {ts.length = 0}); var expanding = {}; function copyValue(val) { var copy = []; for (var i = 0; i < val.length; i++) { var p = val[i]; if (typeof p == "object") { if (expanding[p.tabstopId]) continue; var j = val.lastIndexOf(p, i - 1); p = copy[j] || {tabstopId: p.tabstopId}; } copy[i] = p; } return copy; } for (var i = 0; i < tokens.length; i++) { var p = tokens[i]; if (typeof p != "object") continue; var id = p.tabstopId; var i1 = tokens.indexOf(p, i + 1); if (expanding[id]) { if (expanding[id] === p) expanding[id] = null; continue; } var ts = tabstops[id]; var arg = typeof ts.value == "string" ? [ts.value] : copyValue(ts.value); arg.unshift(i + 1, Math.max(0, i1 - i)); arg.push(p); expanding[id] = p; tokens.splice.apply(tokens, arg); if (ts.indexOf(p) === -1) ts.push(p); } var row = 0, column = 0; var text = ""; tokens.forEach(function(t) { if (typeof t === "string") { var lines = t.split("\n"); if (lines.length > 1){ column = lines[lines.length - 1].length; row += lines.length - 1; } else column += t.length; text += t; } else { if (!t.start) t.start = {row: row, column: column}; else t.end = {row: row, column: column}; } }); var range = editor.getSelectionRange(); var end = editor.session.replace(range, text); var tabstopManager = new TabstopManager(editor); var selectionId = editor.inVirtualSelectionMode && editor.selection.index; tabstopManager.addTabstops(tabstops, range.start, end, selectionId); }; this.insertSnippet = function(editor, snippetText) { var self = this; if (editor.inVirtualSelectionMode) return self.insertSnippetForSelection(editor, snippetText); editor.forEachSelection(function() { self.insertSnippetForSelection(editor, snippetText); }, null, {keepOrder: true}); if (editor.tabstopManager) editor.tabstopManager.tabNext(); }; this.$getScope = function(editor) { var scope = editor.session.$mode.$id || ""; scope = scope.split("/").pop(); if (scope === "html" || scope === "php") { if (scope === "php" && !editor.session.$mode.inlinePhp) scope = "html"; var c = editor.getCursorPosition(); var state = editor.session.getState(c.row); if (typeof state === "object") { state = state[0]; } if (state.substring) { if (state.substring(0, 3) == "js-") scope = "javascript"; else if (state.substring(0, 4) == "css-") scope = "css"; else if (state.substring(0, 4) == "php-") scope = "php"; } } return scope; }; this.getActiveScopes = function(editor) { var scope = this.$getScope(editor); var scopes = [scope]; var snippetMap = this.snippetMap; if (snippetMap[scope] && snippetMap[scope].includeScopes) { scopes.push.apply(scopes, snippetMap[scope].includeScopes); } scopes.push("_"); return scopes; }; this.expandWithTab = function(editor, options) { var self = this; var result = editor.forEachSelection(function() { return self.expandSnippetForSelection(editor, options); }, null, {keepOrder: true}); if (result && editor.tabstopManager) editor.tabstopManager.tabNext(); return result; }; this.expandSnippetForSelection = function(editor, options) { var cursor = editor.getCursorPosition(); var line = editor.session.getLine(cursor.row); var before = line.substring(0, cursor.column); var after = line.substr(cursor.column); var snippetMap = this.snippetMap; var snippet; this.getActiveScopes(editor).some(function(scope) { var snippets = snippetMap[scope]; if (snippets) snippet = this.findMatchingSnippet(snippets, before, after); return !!snippet; }, this); if (!snippet) return false; if (options && options.dryRun) return true; editor.session.doc.removeInLine(cursor.row, cursor.column - snippet.replaceBefore.length, cursor.column + snippet.replaceAfter.length ); this.variables.M__ = snippet.matchBefore; this.variables.T__ = snippet.matchAfter; this.insertSnippetForSelection(editor, snippet.content); this.variables.M__ = this.variables.T__ = null; return true; }; this.findMatchingSnippet = function(snippetList, before, after) { for (var i = snippetList.length; i--;) { var s = snippetList[i]; if (s.startRe && !s.startRe.test(before)) continue; if (s.endRe && !s.endRe.test(after)) continue; if (!s.startRe && !s.endRe) continue; s.matchBefore = s.startRe ? s.startRe.exec(before) : [""]; s.matchAfter = s.endRe ? s.endRe.exec(after) : [""]; s.replaceBefore = s.triggerRe ? s.triggerRe.exec(before)[0] : ""; s.replaceAfter = s.endTriggerRe ? s.endTriggerRe.exec(after)[0] : ""; return s; } }; this.snippetMap = {}; this.snippetNameMap = {}; this.register = function(snippets, scope) { var snippetMap = this.snippetMap; var snippetNameMap = this.snippetNameMap; var self = this; if (!snippets) snippets = []; function wrapRegexp(src) { if (src && !/^\^?\(.*\)\$?$|^\\b$/.test(src)) src = "(?:" + src + ")"; return src || ""; } function guardedRegexp(re, guard, opening) { re = wrapRegexp(re); guard = wrapRegexp(guard); if (opening) { re = guard + re; if (re && re[re.length - 1] != "$") re = re + "$"; } else { re = re + guard; if (re && re[0] != "^") re = "^" + re; } return new RegExp(re); } function addSnippet(s) { if (!s.scope) s.scope = scope || "_"; scope = s.scope; if (!snippetMap[scope]) { snippetMap[scope] = []; snippetNameMap[scope] = {}; } var map = snippetNameMap[scope]; if (s.name) { var old = map[s.name]; if (old) self.unregister(old); map[s.name] = s; } snippetMap[scope].push(s); if (s.tabTrigger && !s.trigger) { if (!s.guard && /^\w/.test(s.tabTrigger)) s.guard = "\\b"; s.trigger = lang.escapeRegExp(s.tabTrigger); } if (!s.trigger && !s.guard && !s.endTrigger && !s.endGuard) return; s.startRe = guardedRegexp(s.trigger, s.guard, true); s.triggerRe = new RegExp(s.trigger, "", true); s.endRe = guardedRegexp(s.endTrigger, s.endGuard, true); s.endTriggerRe = new RegExp(s.endTrigger, "", true); } if (snippets && snippets.content) addSnippet(snippets); else if (Array.isArray(snippets)) snippets.forEach(addSnippet); this._signal("registerSnippets", {scope: scope}); }; this.unregister = function(snippets, scope) { var snippetMap = this.snippetMap; var snippetNameMap = this.snippetNameMap; function removeSnippet(s) { var nameMap = snippetNameMap[s.scope||scope]; if (nameMap && nameMap[s.name]) { delete nameMap[s.name]; var map = snippetMap[s.scope||scope]; var i = map && map.indexOf(s); if (i >= 0) map.splice(i, 1); } } if (snippets.content) removeSnippet(snippets); else if (Array.isArray(snippets)) snippets.forEach(removeSnippet); }; this.parseSnippetFile = function(str) { str = str.replace(/\r/g, ""); var list = [], snippet = {}; var re = /^#.*|^({[\s\S]*})\s*$|^(\S+) (.*)$|^((?:\n*\t.*)+)/gm; var m; while (m = re.exec(str)) { if (m[1]) { try { snippet = JSON.parse(m[1]); list.push(snippet); } catch (e) {} } if (m[4]) { snippet.content = m[4].replace(/^\t/gm, ""); list.push(snippet); snippet = {}; } else { var key = m[2], val = m[3]; if (key == "regex") { var guardRe = /\/((?:[^\/\\]|\\.)*)|$/g; snippet.guard = guardRe.exec(val)[1]; snippet.trigger = guardRe.exec(val)[1]; snippet.endTrigger = guardRe.exec(val)[1]; snippet.endGuard = guardRe.exec(val)[1]; } else if (key == "snippet") { snippet.tabTrigger = val.match(/^\S*/)[0]; if (!snippet.name) snippet.name = val; } else { snippet[key] = val; } } } return list; }; this.getSnippetByName = function(name, editor) { var snippetMap = this.snippetNameMap; var snippet; this.getActiveScopes(editor).some(function(scope) { var snippets = snippetMap[scope]; if (snippets) snippet = snippets[name]; return !!snippet; }, this); return snippet; }; }).call(SnippetManager.prototype); var TabstopManager = function(editor) { if (editor.tabstopManager) return editor.tabstopManager; editor.tabstopManager = this; this.$onChange = this.onChange.bind(this); this.$onChangeSelection = lang.delayedCall(this.onChangeSelection.bind(this)).schedule; this.$onChangeSession = this.onChangeSession.bind(this); this.$onAfterExec = this.onAfterExec.bind(this); this.attach(editor); }; (function() { this.attach = function(editor) { this.index = 0; this.ranges = []; this.tabstops = []; this.$openTabstops = null; this.selectedTabstop = null; this.editor = editor; this.editor.on("change", this.$onChange); this.editor.on("changeSelection", this.$onChangeSelection); this.editor.on("changeSession", this.$onChangeSession); this.editor.commands.on("afterExec", this.$onAfterExec); this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler); }; this.detach = function() { this.tabstops.forEach(this.removeTabstopMarkers, this); this.ranges = null; this.tabstops = null; this.selectedTabstop = null; this.editor.removeListener("change", this.$onChange); this.editor.removeListener("changeSelection", this.$onChangeSelection); this.editor.removeListener("changeSession", this.$onChangeSession); this.editor.commands.removeListener("afterExec", this.$onAfterExec); this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler); this.editor.tabstopManager = null; this.editor = null; }; this.onChange = function(delta) { var changeRange = delta; var isRemove = delta.action[0] == "r"; var start = delta.start; var end = delta.end; var startRow = start.row; var endRow = end.row; var lineDif = endRow - startRow; var colDiff = end.column - start.column; if (isRemove) { lineDif = -lineDif; colDiff = -colDiff; } if (!this.$inChange && isRemove) { var ts = this.selectedTabstop; var changedOutside = ts && !ts.some(function(r) { return comparePoints(r.start, start) <= 0 && comparePoints(r.end, end) >= 0; }); if (changedOutside) return this.detach(); } var ranges = this.ranges; for (var i = 0; i < ranges.length; i++) { var r = ranges[i]; if (r.end.row < start.row) continue; if (isRemove && comparePoints(start, r.start) < 0 && comparePoints(end, r.end) > 0) { this.removeRange(r); i--; continue; } if (r.start.row == startRow && r.start.column > start.column) r.start.column += colDiff; if (r.end.row == startRow && r.end.column >= start.column) r.end.column += colDiff; if (r.start.row >= startRow) r.start.row += lineDif; if (r.end.row >= startRow) r.end.row += lineDif; if (comparePoints(r.start, r.end) > 0) this.removeRange(r); } if (!ranges.length) this.detach(); }; this.updateLinkedFields = function() { var ts = this.selectedTabstop; if (!ts || !ts.hasLinkedRanges) return; this.$inChange = true; var session = this.editor.session; var text = session.getTextRange(ts.firstNonLinked); for (var i = ts.length; i--;) { var range = ts[i]; if (!range.linked) continue; var fmt = exports.snippetManager.tmStrFormat(text, range.original); session.replace(range, fmt); } this.$inChange = false; }; this.onAfterExec = function(e) { if (e.command && !e.command.readOnly) this.updateLinkedFields(); }; this.onChangeSelection = function() { if (!this.editor) return; var lead = this.editor.selection.lead; var anchor = this.editor.selection.anchor; var isEmpty = this.editor.selection.isEmpty(); for (var i = this.ranges.length; i--;) { if (this.ranges[i].linked) continue; var containsLead = this.ranges[i].contains(lead.row, lead.column); var containsAnchor = isEmpty || this.ranges[i].contains(anchor.row, anchor.column); if (containsLead && containsAnchor) return; } this.detach(); }; this.onChangeSession = function() { this.detach(); }; this.tabNext = function(dir) { var max = this.tabstops.length; var index = this.index + (dir || 1); index = Math.min(Math.max(index, 1), max); if (index == max) index = 0; this.selectTabstop(index); if (index === 0) this.detach(); }; this.selectTabstop = function(index) { this.$openTabstops = null; var ts = this.tabstops[this.index]; if (ts) this.addTabstopMarkers(ts); this.index = index; ts = this.tabstops[this.index]; if (!ts || !ts.length) return; this.selectedTabstop = ts; if (!this.editor.inVirtualSelectionMode) { var sel = this.editor.multiSelect; sel.toSingleRange(ts.firstNonLinked.clone()); for (var i = ts.length; i--;) { if (ts.hasLinkedRanges && ts[i].linked) continue; sel.addRange(ts[i].clone(), true); } if (sel.ranges[0]) sel.addRange(sel.ranges[0].clone()); } else { this.editor.selection.setRange(ts.firstNonLinked); } this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler); }; this.addTabstops = function(tabstops, start, end) { if (!this.$openTabstops) this.$openTabstops = []; if (!tabstops[0]) { var p = Range.fromPoints(end, end); moveRelative(p.start, start); moveRelative(p.end, start); tabstops[0] = [p]; tabstops[0].index = 0; } var i = this.index; var arg = [i + 1, 0]; var ranges = this.ranges; tabstops.forEach(function(ts, index) { var dest = this.$openTabstops[index] || ts; for (var i = ts.length; i--;) { var p = ts[i]; var range = Range.fromPoints(p.start, p.end || p.start); movePoint(range.start, start); movePoint(range.end, start); range.original = p; range.tabstop = dest; ranges.push(range); if (dest != ts) dest.unshift(range); else dest[i] = range; if (p.fmtString) { range.linked = true; dest.hasLinkedRanges = true; } else if (!dest.firstNonLinked) dest.firstNonLinked = range; } if (!dest.firstNonLinked) dest.hasLinkedRanges = false; if (dest === ts) { arg.push(dest); this.$openTabstops[index] = dest; } this.addTabstopMarkers(dest); }, this); if (arg.length > 2) { if (this.tabstops.length) arg.push(arg.splice(2, 1)[0]); this.tabstops.splice.apply(this.tabstops, arg); } }; this.addTabstopMarkers = function(ts) { var session = this.editor.session; ts.forEach(function(range) { if (!range.markerId) range.markerId = session.addMarker(range, "ace_snippet-marker", "text"); }); }; this.removeTabstopMarkers = function(ts) { var session = this.editor.session; ts.forEach(function(range) { session.removeMarker(range.markerId); range.markerId = null; }); }; this.removeRange = function(range) { var i = range.tabstop.indexOf(range); range.tabstop.splice(i, 1); i = this.ranges.indexOf(range); this.ranges.splice(i, 1); this.editor.session.removeMarker(range.markerId); if (!range.tabstop.length) { i = this.tabstops.indexOf(range.tabstop); if (i != -1) this.tabstops.splice(i, 1); if (!this.tabstops.length) this.detach(); } }; this.keyboardHandler = new HashHandler(); this.keyboardHandler.bindKeys({ "Tab": function(ed) { if (exports.snippetManager && exports.snippetManager.expandWithTab(ed)) { return; } ed.tabstopManager.tabNext(1); }, "Shift-Tab": function(ed) { ed.tabstopManager.tabNext(-1); }, "Esc": function(ed) { ed.tabstopManager.detach(); }, "Return": function(ed) { return false; } }); }).call(TabstopManager.prototype); var changeTracker = {}; changeTracker.onChange = Anchor.prototype.onChange; changeTracker.setPosition = function(row, column) { this.pos.row = row; this.pos.column = column; }; changeTracker.update = function(pos, delta, $insertRight) { this.$insertRight = $insertRight; this.pos = pos; this.onChange(delta); }; var movePoint = function(point, diff) { if (point.row == 0) point.column += diff.column; point.row += diff.row; }; var moveRelative = function(point, start) { if (point.row == start.row) point.column -= start.column; point.row -= start.row; }; require("./lib/dom").importCssString("\ .ace_snippet-marker {\ -moz-box-sizing: border-box;\ box-sizing: border-box;\ background: rgba(194, 193, 208, 0.09);\ border: 1px dotted rgba(211, 208, 235, 0.62);\ position: absolute;\ }"); exports.snippetManager = new SnippetManager(); var Editor = require("./editor").Editor; (function() { this.insertSnippet = function(content, options) { return exports.snippetManager.insertSnippet(this, content, options); }; this.expandSnippet = function(options) { return exports.snippetManager.expandWithTab(this, options); }; }).call(Editor.prototype); }); define("ace/ext/emmet",["require","exports","module","ace/keyboard/hash_handler","ace/editor","ace/snippets","ace/range","resources","resources","tabStops","resources","utils","actions","ace/config","ace/config"], function(require, exports, module) { "use strict"; var HashHandler = require("ace/keyboard/hash_handler").HashHandler; var Editor = require("ace/editor").Editor; var snippetManager = require("ace/snippets").snippetManager; var Range = require("ace/range").Range; var emmet, emmetPath; function AceEmmetEditor() {} AceEmmetEditor.prototype = { setupContext: function(editor) { this.ace = editor; this.indentation = editor.session.getTabString(); if (!emmet) emmet = window.emmet; var resources = emmet.resources || emmet.require("resources"); resources.setVariable("indentation", this.indentation); this.$syntax = null; this.$syntax = this.getSyntax(); }, getSelectionRange: function() { var range = this.ace.getSelectionRange(); var doc = this.ace.session.doc; return { start: doc.positionToIndex(range.start), end: doc.positionToIndex(range.end) }; }, createSelection: function(start, end) { var doc = this.ace.session.doc; this.ace.selection.setRange({ start: doc.indexToPosition(start), end: doc.indexToPosition(end) }); }, getCurrentLineRange: function() { var ace = this.ace; var row = ace.getCursorPosition().row; var lineLength = ace.session.getLine(row).length; var index = ace.session.doc.positionToIndex({row: row, column: 0}); return { start: index, end: index + lineLength }; }, getCaretPos: function(){ var pos = this.ace.getCursorPosition(); return this.ace.session.doc.positionToIndex(pos); }, setCaretPos: function(index){ var pos = this.ace.session.doc.indexToPosition(index); this.ace.selection.moveToPosition(pos); }, getCurrentLine: function() { var row = this.ace.getCursorPosition().row; return this.ace.session.getLine(row); }, replaceContent: function(value, start, end, noIndent) { if (end == null) end = start == null ? this.getContent().length : start; if (start == null) start = 0; var editor = this.ace; var doc = editor.session.doc; var range = Range.fromPoints(doc.indexToPosition(start), doc.indexToPosition(end)); editor.session.remove(range); range.end = range.start; value = this.$updateTabstops(value); snippetManager.insertSnippet(editor, value); }, getContent: function(){ return this.ace.getValue(); }, getSyntax: function() { if (this.$syntax) return this.$syntax; var syntax = this.ace.session.$modeId.split("/").pop(); if (syntax == "html" || syntax == "php") { var cursor = this.ace.getCursorPosition(); var state = this.ace.session.getState(cursor.row); if (typeof state != "string") state = state[0]; if (state) { state = state.split("-"); if (state.length > 1) syntax = state[0]; else if (syntax == "php") syntax = "html"; } } return syntax; }, getProfileName: function() { var resources = emmet.resources || emmet.require("resources"); switch (this.getSyntax()) { case "css": return "css"; case "xml": case "xsl": return "xml"; case "html": var profile = resources.getVariable("profile"); if (!profile) profile = this.ace.session.getLines(0,2).join("").search(/]+XHTML/i) != -1 ? "xhtml": "html"; return profile; default: var mode = this.ace.session.$mode; return mode.emmetConfig && mode.emmetConfig.profile || "xhtml"; } }, prompt: function(title) { return prompt(title); }, getSelection: function() { return this.ace.session.getTextRange(); }, getFilePath: function() { return ""; }, $updateTabstops: function(value) { var base = 1000; var zeroBase = 0; var lastZero = null; var ts = emmet.tabStops || emmet.require('tabStops'); var resources = emmet.resources || emmet.require("resources"); var settings = resources.getVocabulary("user"); var tabstopOptions = { tabstop: function(data) { var group = parseInt(data.group, 10); var isZero = group === 0; if (isZero) group = ++zeroBase; else group += base; var placeholder = data.placeholder; if (placeholder) { placeholder = ts.processText(placeholder, tabstopOptions); } var result = '${' + group + (placeholder ? ':' + placeholder : '') + '}'; if (isZero) { lastZero = [data.start, result]; } return result; }, escape: function(ch) { if (ch == '$') return '\\$'; if (ch == '\\') return '\\\\'; return ch; } }; value = ts.processText(value, tabstopOptions); if (settings.variables['insert_final_tabstop'] && !/\$\{0\}$/.test(value)) { value += '${0}'; } else if (lastZero) { var common = emmet.utils ? emmet.utils.common : emmet.require('utils'); value = common.replaceSubstring(value, '${0}', lastZero[0], lastZero[1]); } return value; } }; var keymap = { expand_abbreviation: {"mac": "ctrl+alt+e", "win": "alt+e"}, match_pair_outward: {"mac": "ctrl+d", "win": "ctrl+,"}, match_pair_inward: {"mac": "ctrl+j", "win": "ctrl+shift+0"}, matching_pair: {"mac": "ctrl+alt+j", "win": "alt+j"}, next_edit_point: "alt+right", prev_edit_point: "alt+left", toggle_comment: {"mac": "command+/", "win": "ctrl+/"}, split_join_tag: {"mac": "shift+command+'", "win": "shift+ctrl+`"}, remove_tag: {"mac": "command+'", "win": "shift+ctrl+;"}, evaluate_math_expression: {"mac": "shift+command+y", "win": "shift+ctrl+y"}, increment_number_by_1: "ctrl+up", decrement_number_by_1: "ctrl+down", increment_number_by_01: "alt+up", decrement_number_by_01: "alt+down", increment_number_by_10: {"mac": "alt+command+up", "win": "shift+alt+up"}, decrement_number_by_10: {"mac": "alt+command+down", "win": "shift+alt+down"}, select_next_item: {"mac": "shift+command+.", "win": "shift+ctrl+."}, select_previous_item: {"mac": "shift+command+,", "win": "shift+ctrl+,"}, reflect_css_value: {"mac": "shift+command+r", "win": "shift+ctrl+r"}, encode_decode_data_url: {"mac": "shift+ctrl+d", "win": "ctrl+'"}, expand_abbreviation_with_tab: "Tab", wrap_with_abbreviation: {"mac": "shift+ctrl+a", "win": "shift+ctrl+a"} }; var editorProxy = new AceEmmetEditor(); exports.commands = new HashHandler(); exports.runEmmetCommand = function runEmmetCommand(editor) { try { editorProxy.setupContext(editor); var actions = emmet.actions || emmet.require("actions"); if (this.action == "expand_abbreviation_with_tab") { if (!editor.selection.isEmpty()) return false; var pos = editor.selection.lead; var token = editor.session.getTokenAt(pos.row, pos.column); if (token && /\btag\b/.test(token.type)) return false; } if (this.action == "wrap_with_abbreviation") { return setTimeout(function() { actions.run("wrap_with_abbreviation", editorProxy); }, 0); } var result = actions.run(this.action, editorProxy); } catch(e) { if (!emmet) { load(runEmmetCommand.bind(this, editor)); return true; } editor._signal("changeStatus", typeof e == "string" ? e : e.message); console.log(e); result = false; } return result; }; for (var command in keymap) { exports.commands.addCommand({ name: "emmet:" + command, action: command, bindKey: keymap[command], exec: exports.runEmmetCommand, multiSelectAction: "forEach" }); } exports.updateCommands = function(editor, enabled) { if (enabled) { editor.keyBinding.addKeyboardHandler(exports.commands); } else { editor.keyBinding.removeKeyboardHandler(exports.commands); } }; exports.isSupportedMode = function(mode) { if (!mode) return false; if (mode.emmetConfig) return true; var id = mode.$id || mode; return /css|less|scss|sass|stylus|html|php|twig|ejs|handlebars/.test(id); }; exports.isAvailable = function(editor, command) { if (/(evaluate_math_expression|expand_abbreviation)$/.test(command)) return true; var mode = editor.session.$mode; var isSupported = exports.isSupportedMode(mode); if (isSupported && mode.$modes) { try { editorProxy.setupContext(editor); if (/js|php/.test(editorProxy.getSyntax())) isSupported = false; } catch(e) {} } return isSupported; } var onChangeMode = function(e, target) { var editor = target; if (!editor) return; var enabled = exports.isSupportedMode(editor.session.$mode); if (e.enableEmmet === false) enabled = false; if (enabled) load(); exports.updateCommands(editor, enabled); }; var load = function(cb) { if (typeof emmetPath == "string") { require("ace/config").loadModule(emmetPath, function() { emmetPath = null; cb && cb(); }); } }; exports.AceEmmetEditor = AceEmmetEditor; require("ace/config").defineOptions(Editor.prototype, "editor", { enableEmmet: { set: function(val) { this[val ? "on" : "removeListener"]("changeMode", onChangeMode); onChangeMode({enableEmmet: !!val}, this); }, value: true } }); exports.setCore = function(e) { if (typeof e == "string") emmetPath = e; else emmet = e; }; }); define("ace/autocomplete/popup",["require","exports","module","ace/virtual_renderer","ace/editor","ace/range","ace/lib/event","ace/lib/lang","ace/lib/dom"], function(require, exports, module) { "use strict"; var Renderer = require("../virtual_renderer").VirtualRenderer; var Editor = require("../editor").Editor; var Range = require("../range").Range; var event = require("../lib/event"); var lang = require("../lib/lang"); var dom = require("../lib/dom"); var $singleLineEditor = function(el) { var renderer = new Renderer(el); renderer.$maxLines = 4; var editor = new Editor(renderer); editor.setHighlightActiveLine(false); editor.setShowPrintMargin(false); editor.renderer.setShowGutter(false); editor.renderer.setHighlightGutterLine(false); editor.$mouseHandler.$focusWaitTimout = 0; editor.$highlightTagPending = true; return editor; }; var AcePopup = function(parentNode) { var el = dom.createElement("div"); var popup = new $singleLineEditor(el); if (parentNode) parentNode.appendChild(el); el.style.display = "none"; popup.renderer.content.style.cursor = "default"; popup.renderer.setStyle("ace_autocomplete"); popup.setOption("displayIndentGuides", false); popup.setOption("dragDelay", 150); var noop = function(){}; popup.focus = noop; popup.$isFocused = true; popup.renderer.$cursorLayer.restartTimer = noop; popup.renderer.$cursorLayer.element.style.opacity = 0; popup.renderer.$maxLines = 8; popup.renderer.$keepTextAreaAtCursor = false; popup.setHighlightActiveLine(false); popup.session.highlight(""); popup.session.$searchHighlight.clazz = "ace_highlight-marker"; popup.on("mousedown", function(e) { var pos = e.getDocumentPosition(); popup.selection.moveToPosition(pos); selectionMarker.start.row = selectionMarker.end.row = pos.row; e.stop(); }); var lastMouseEvent; var hoverMarker = new Range(-1,0,-1,Infinity); var selectionMarker = new Range(-1,0,-1,Infinity); selectionMarker.id = popup.session.addMarker(selectionMarker, "ace_active-line", "fullLine"); popup.setSelectOnHover = function(val) { if (!val) { hoverMarker.id = popup.session.addMarker(hoverMarker, "ace_line-hover", "fullLine"); } else if (hoverMarker.id) { popup.session.removeMarker(hoverMarker.id); hoverMarker.id = null; } }; popup.setSelectOnHover(false); popup.on("mousemove", function(e) { if (!lastMouseEvent) { lastMouseEvent = e; return; } if (lastMouseEvent.x == e.x && lastMouseEvent.y == e.y) { return; } lastMouseEvent = e; lastMouseEvent.scrollTop = popup.renderer.scrollTop; var row = lastMouseEvent.getDocumentPosition().row; if (hoverMarker.start.row != row) { if (!hoverMarker.id) popup.setRow(row); setHoverMarker(row); } }); popup.renderer.on("beforeRender", function() { if (lastMouseEvent && hoverMarker.start.row != -1) { lastMouseEvent.$pos = null; var row = lastMouseEvent.getDocumentPosition().row; if (!hoverMarker.id) popup.setRow(row); setHoverMarker(row, true); } }); popup.renderer.on("afterRender", function() { var row = popup.getRow(); var t = popup.renderer.$textLayer; var selected = t.element.childNodes[row - t.config.firstRow]; if (selected == t.selectedNode) return; if (t.selectedNode) dom.removeCssClass(t.selectedNode, "ace_selected"); t.selectedNode = selected; if (selected) dom.addCssClass(selected, "ace_selected"); }); var hideHoverMarker = function() { setHoverMarker(-1) }; var setHoverMarker = function(row, suppressRedraw) { if (row !== hoverMarker.start.row) { hoverMarker.start.row = hoverMarker.end.row = row; if (!suppressRedraw) popup.session._emit("changeBackMarker"); popup._emit("changeHoverMarker"); } }; popup.getHoveredRow = function() { return hoverMarker.start.row; }; event.addListener(popup.container, "mouseout", hideHoverMarker); popup.on("hide", hideHoverMarker); popup.on("changeSelection", hideHoverMarker); popup.session.doc.getLength = function() { return popup.data.length; }; popup.session.doc.getLine = function(i) { var data = popup.data[i]; if (typeof data == "string") return data; return (data && data.value) || ""; }; var bgTokenizer = popup.session.bgTokenizer; bgTokenizer.$tokenizeRow = function(row) { var data = popup.data[row]; var tokens = []; if (!data) return tokens; if (typeof data == "string") data = {value: data}; if (!data.caption) data.caption = data.value || data.name; var last = -1; var flag, c; for (var i = 0; i < data.caption.length; i++) { c = data.caption[i]; flag = data.matchMask & (1 << i) ? 1 : 0; if (last !== flag) { tokens.push({type: data.className || "" + ( flag ? "completion-highlight" : ""), value: c}); last = flag; } else { tokens[tokens.length - 1].value += c; } } if (data.meta) { var maxW = popup.renderer.$size.scrollerWidth / popup.renderer.layerConfig.characterWidth; var metaData = data.meta; if (metaData.length + data.caption.length > maxW - 2) { metaData = metaData.substr(0, maxW - data.caption.length - 3) + "\u2026" } tokens.push({type: "rightAlignedText", value: metaData}); } return tokens; }; bgTokenizer.$updateOnChange = noop; bgTokenizer.start = noop; popup.session.$computeWidth = function() { return this.screenWidth = 0; }; popup.$blockScrolling = Infinity; popup.isOpen = false; popup.isTopdown = false; popup.autoSelect = true; popup.data = []; popup.setData = function(list) { popup.setValue(lang.stringRepeat("\n", list.length), -1); popup.data = list || []; popup.setRow(0); }; popup.getData = function(row) { return popup.data[row]; }; popup.getRow = function() { return selectionMarker.start.row; }; popup.setRow = function(line) { line = Math.max(this.autoSelect ? 0 : -1, Math.min(this.data.length, line)); if (selectionMarker.start.row != line) { popup.selection.clearSelection(); selectionMarker.start.row = selectionMarker.end.row = line || 0; popup.session._emit("changeBackMarker"); popup.moveCursorTo(line || 0, 0); if (popup.isOpen) popup._signal("select"); } }; popup.on("changeSelection", function() { if (popup.isOpen) popup.setRow(popup.selection.lead.row); popup.renderer.scrollCursorIntoView(); }); popup.hide = function() { this.container.style.display = "none"; this._signal("hide"); popup.isOpen = false; }; popup.show = function(pos, lineHeight, topdownOnly) { var el = this.container; var screenHeight = window.innerHeight; var screenWidth = window.innerWidth; var renderer = this.renderer; var maxH = renderer.$maxLines * lineHeight * 1.4; var top = pos.top + this.$borderSize; var allowTopdown = top > screenHeight / 2 && !topdownOnly; if (allowTopdown && top + lineHeight + maxH > screenHeight) { renderer.$maxPixelHeight = top - 2 * this.$borderSize; el.style.top = ""; el.style.bottom = screenHeight - top + "px"; popup.isTopdown = false; } else { top += lineHeight; renderer.$maxPixelHeight = screenHeight - top - 0.2 * lineHeight; el.style.top = top + "px"; el.style.bottom = ""; popup.isTopdown = true; } el.style.display = ""; this.renderer.$textLayer.checkForSizeChanges(); var left = pos.left; if (left + el.offsetWidth > screenWidth) left = screenWidth - el.offsetWidth; el.style.left = left + "px"; this._signal("show"); lastMouseEvent = null; popup.isOpen = true; }; popup.getTextLeftOffset = function() { return this.$borderSize + this.renderer.$padding + this.$imageSize; }; popup.$imageSize = 0; popup.$borderSize = 1; return popup; }; dom.importCssString("\ .ace_editor.ace_autocomplete .ace_marker-layer .ace_active-line {\ background-color: #CAD6FA;\ z-index: 1;\ }\ .ace_editor.ace_autocomplete .ace_line-hover {\ border: 1px solid #abbffe;\ margin-top: -1px;\ background: rgba(233,233,253,0.4);\ }\ .ace_editor.ace_autocomplete .ace_line-hover {\ position: absolute;\ z-index: 2;\ }\ .ace_editor.ace_autocomplete .ace_scroller {\ background: none;\ border: none;\ box-shadow: none;\ }\ .ace_rightAlignedText {\ color: gray;\ display: inline-block;\ position: absolute;\ right: 4px;\ text-align: right;\ z-index: -1;\ }\ .ace_editor.ace_autocomplete .ace_completion-highlight{\ color: #000;\ text-shadow: 0 0 0.01em;\ }\ .ace_editor.ace_autocomplete {\ width: 280px;\ z-index: 200000;\ background: #fbfbfb;\ color: #444;\ border: 1px lightgray solid;\ position: fixed;\ box-shadow: 2px 3px 5px rgba(0,0,0,.2);\ line-height: 1.4;\ }"); exports.AcePopup = AcePopup; }); define("ace/autocomplete/util",["require","exports","module"], function(require, exports, module) { "use strict"; exports.parForEach = function(array, fn, callback) { var completed = 0; var arLength = array.length; if (arLength === 0) callback(); for (var i = 0; i < arLength; i++) { fn(array[i], function(result, err) { completed++; if (completed === arLength) callback(result, err); }); } }; var ID_REGEX = /[a-zA-Z_0-9\$\-\u00A2-\uFFFF]/; exports.retrievePrecedingIdentifier = function(text, pos, regex) { regex = regex || ID_REGEX; var buf = []; for (var i = pos-1; i >= 0; i--) { if (regex.test(text[i])) buf.push(text[i]); else break; } return buf.reverse().join(""); }; exports.retrieveFollowingIdentifier = function(text, pos, regex) { regex = regex || ID_REGEX; var buf = []; for (var i = pos; i < text.length; i++) { if (regex.test(text[i])) buf.push(text[i]); else break; } return buf; }; exports.getCompletionPrefix = function (editor) { var pos = editor.getCursorPosition(); var line = editor.session.getLine(pos.row); var prefix; editor.completers.forEach(function(completer) { if (completer.identifierRegexps) { completer.identifierRegexps.forEach(function(identifierRegex) { if (!prefix && identifierRegex) prefix = this.retrievePrecedingIdentifier(line, pos.column, identifierRegex); }.bind(this)); } }.bind(this)); return prefix || this.retrievePrecedingIdentifier(line, pos.column); }; }); define("ace/autocomplete",["require","exports","module","ace/keyboard/hash_handler","ace/autocomplete/popup","ace/autocomplete/util","ace/lib/event","ace/lib/lang","ace/lib/dom","ace/snippets"], function(require, exports, module) { "use strict"; var HashHandler = require("./keyboard/hash_handler").HashHandler; var AcePopup = require("./autocomplete/popup").AcePopup; var util = require("./autocomplete/util"); var event = require("./lib/event"); var lang = require("./lib/lang"); var dom = require("./lib/dom"); var snippetManager = require("./snippets").snippetManager; var Autocomplete = function() { this.autoInsert = false; this.autoSelect = true; this.exactMatch = false; this.gatherCompletionsId = 0; this.keyboardHandler = new HashHandler(); this.keyboardHandler.bindKeys(this.commands); this.blurListener = this.blurListener.bind(this); this.changeListener = this.changeListener.bind(this); this.mousedownListener = this.mousedownListener.bind(this); this.mousewheelListener = this.mousewheelListener.bind(this); this.changeTimer = lang.delayedCall(function() { this.updateCompletions(true); }.bind(this)); this.tooltipTimer = lang.delayedCall(this.updateDocTooltip.bind(this), 50); }; (function() { this.$init = function() { this.popup = new AcePopup(document.body || document.documentElement); this.popup.on("click", function(e) { this.insertMatch(); e.stop(); }.bind(this)); this.popup.focus = this.editor.focus.bind(this.editor); this.popup.on("show", this.tooltipTimer.bind(null, null)); this.popup.on("select", this.tooltipTimer.bind(null, null)); this.popup.on("changeHoverMarker", this.tooltipTimer.bind(null, null)); return this.popup; }; this.getPopup = function() { return this.popup || this.$init(); }; this.openPopup = function(editor, prefix, keepPopupPosition) { if (!this.popup) this.$init(); this.popup.autoSelect = this.autoSelect; this.popup.setData(this.completions.filtered); editor.keyBinding.addKeyboardHandler(this.keyboardHandler); var renderer = editor.renderer; this.popup.setRow(this.autoSelect ? 0 : -1); if (!keepPopupPosition) { this.popup.setTheme(editor.getTheme()); this.popup.setFontSize(editor.getFontSize()); var lineHeight = renderer.layerConfig.lineHeight; var pos = renderer.$cursorLayer.getPixelPosition(this.base, true); pos.left -= this.popup.getTextLeftOffset(); var rect = editor.container.getBoundingClientRect(); pos.top += rect.top - renderer.layerConfig.offset; pos.left += rect.left - editor.renderer.scrollLeft; pos.left += renderer.gutterWidth; this.popup.show(pos, lineHeight); } else if (keepPopupPosition && !prefix) { this.detach(); } }; this.detach = function() { this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler); this.editor.off("changeSelection", this.changeListener); this.editor.off("blur", this.blurListener); this.editor.off("mousedown", this.mousedownListener); this.editor.off("mousewheel", this.mousewheelListener); this.changeTimer.cancel(); this.hideDocTooltip(); this.gatherCompletionsId += 1; if (this.popup && this.popup.isOpen) this.popup.hide(); if (this.base) this.base.detach(); this.activated = false; this.completions = this.base = null; }; this.changeListener = function(e) { var cursor = this.editor.selection.lead; if (cursor.row != this.base.row || cursor.column < this.base.column) { this.detach(); } if (this.activated) this.changeTimer.schedule(); else this.detach(); }; this.blurListener = function(e) { var el = document.activeElement; var text = this.editor.textInput.getElement(); var fromTooltip = e.relatedTarget && this.tooltipNode && this.tooltipNode.contains(e.relatedTarget); var container = this.popup && this.popup.container; if (el != text && el.parentNode != container && !fromTooltip && el != this.tooltipNode && e.relatedTarget != text ) { this.detach(); } }; this.mousedownListener = function(e) { this.detach(); }; this.mousewheelListener = function(e) { this.detach(); }; this.goTo = function(where) { var row = this.popup.getRow(); var max = this.popup.session.getLength() - 1; switch(where) { case "up": row = row <= 0 ? max : row - 1; break; case "down": row = row >= max ? -1 : row + 1; break; case "start": row = 0; break; case "end": row = max; break; } this.popup.setRow(row); }; this.insertMatch = function(data, options) { if (!data) data = this.popup.getData(this.popup.getRow()); if (!data) return false; if (data.completer && data.completer.insertMatch) { data.completer.insertMatch(this.editor, data); } else { if (this.completions.filterText) { var ranges = this.editor.selection.getAllRanges(); for (var i = 0, range; range = ranges[i]; i++) { range.start.column -= this.completions.filterText.length; this.editor.session.remove(range); } } if (data.snippet) snippetManager.insertSnippet(this.editor, data.snippet); else this.editor.execCommand("insertstring", data.value || data); } this.detach(); }; this.commands = { "Up": function(editor) { editor.completer.goTo("up"); }, "Down": function(editor) { editor.completer.goTo("down"); }, "Ctrl-Up|Ctrl-Home": function(editor) { editor.completer.goTo("start"); }, "Ctrl-Down|Ctrl-End": function(editor) { editor.completer.goTo("end"); }, "Esc": function(editor) { editor.completer.detach(); }, "Return": function(editor) { return editor.completer.insertMatch(); }, "Shift-Return": function(editor) { editor.completer.insertMatch(null, {deleteSuffix: true}); }, "Tab": function(editor) { var result = editor.completer.insertMatch(); if (!result && !editor.tabstopManager) editor.completer.goTo("down"); else return result; }, "PageUp": function(editor) { editor.completer.popup.gotoPageUp(); }, "PageDown": function(editor) { editor.completer.popup.gotoPageDown(); } }; this.gatherCompletions = function(editor, callback) { var session = editor.getSession(); var pos = editor.getCursorPosition(); var prefix = util.getCompletionPrefix(editor); this.base = session.doc.createAnchor(pos.row, pos.column - prefix.length); this.base.$insertRight = true; var matches = []; var total = editor.completers.length; editor.completers.forEach(function(completer, i) { completer.getCompletions(editor, session, pos, prefix, function(err, results) { if (!err && results) matches = matches.concat(results); callback(null, { prefix: util.getCompletionPrefix(editor), matches: matches, finished: (--total === 0) }); }); }); return true; }; this.showPopup = function(editor) { if (this.editor) this.detach(); this.activated = true; this.editor = editor; if (editor.completer != this) { if (editor.completer) editor.completer.detach(); editor.completer = this; } editor.on("changeSelection", this.changeListener); editor.on("blur", this.blurListener); editor.on("mousedown", this.mousedownListener); editor.on("mousewheel", this.mousewheelListener); this.updateCompletions(); }; this.updateCompletions = function(keepPopupPosition) { if (keepPopupPosition && this.base && this.completions) { var pos = this.editor.getCursorPosition(); var prefix = this.editor.session.getTextRange({start: this.base, end: pos}); if (prefix == this.completions.filterText) return; this.completions.setFilter(prefix); if (!this.completions.filtered.length) return this.detach(); if (this.completions.filtered.length == 1 && this.completions.filtered[0].value == prefix && !this.completions.filtered[0].snippet) return this.detach(); this.openPopup(this.editor, prefix, keepPopupPosition); return; } var _id = this.gatherCompletionsId; this.gatherCompletions(this.editor, function(err, results) { var detachIfFinished = function() { if (!results.finished) return; return this.detach(); }.bind(this); var prefix = results.prefix; var matches = results && results.matches; if (!matches || !matches.length) return detachIfFinished(); if (prefix.indexOf(results.prefix) !== 0 || _id != this.gatherCompletionsId) return; this.completions = new FilteredList(matches); if (this.exactMatch) this.completions.exactMatch = true; this.completions.setFilter(prefix); var filtered = this.completions.filtered; if (!filtered.length) return detachIfFinished(); if (filtered.length == 1 && filtered[0].value == prefix && !filtered[0].snippet) return detachIfFinished(); if (this.autoInsert && filtered.length == 1 && results.finished) return this.insertMatch(filtered[0]); this.openPopup(this.editor, prefix, keepPopupPosition); }.bind(this)); }; this.cancelContextMenu = function() { this.editor.$mouseHandler.cancelContextMenu(); }; this.updateDocTooltip = function() { var popup = this.popup; var all = popup.data; var selected = all && (all[popup.getHoveredRow()] || all[popup.getRow()]); var doc = null; if (!selected || !this.editor || !this.popup.isOpen) return this.hideDocTooltip(); this.editor.completers.some(function(completer) { if (completer.getDocTooltip) doc = completer.getDocTooltip(selected); return doc; }); if (!doc) doc = selected; if (typeof doc == "string") doc = {docText: doc}; if (!doc || !(doc.docHTML || doc.docText)) return this.hideDocTooltip(); this.showDocTooltip(doc); }; this.showDocTooltip = function(item) { if (!this.tooltipNode) { this.tooltipNode = dom.createElement("div"); this.tooltipNode.className = "ace_tooltip ace_doc-tooltip"; this.tooltipNode.style.margin = 0; this.tooltipNode.style.pointerEvents = "auto"; this.tooltipNode.tabIndex = -1; this.tooltipNode.onblur = this.blurListener.bind(this); this.tooltipNode.onclick = this.onTooltipClick.bind(this); } var tooltipNode = this.tooltipNode; if (item.docHTML) { tooltipNode.innerHTML = item.docHTML; } else if (item.docText) { tooltipNode.textContent = item.docText; } if (!tooltipNode.parentNode) document.body.appendChild(tooltipNode); var popup = this.popup; var rect = popup.container.getBoundingClientRect(); tooltipNode.style.top = popup.container.style.top; tooltipNode.style.bottom = popup.container.style.bottom; if (window.innerWidth - rect.right < 320) { tooltipNode.style.right = window.innerWidth - rect.left + "px"; tooltipNode.style.left = ""; } else { tooltipNode.style.left = (rect.right + 1) + "px"; tooltipNode.style.right = ""; } tooltipNode.style.display = "block"; }; this.hideDocTooltip = function() { this.tooltipTimer.cancel(); if (!this.tooltipNode) return; var el = this.tooltipNode; if (!this.editor.isFocused() && document.activeElement == el) this.editor.focus(); this.tooltipNode = null; if (el.parentNode) el.parentNode.removeChild(el); }; this.onTooltipClick = function(e) { var a = e.target; while (a && a != this.tooltipNode) { if (a.nodeName == "A" && a.href) { a.rel = "noreferrer"; a.target = "_blank"; break; } a = a.parentNode; } } }).call(Autocomplete.prototype); Autocomplete.startCommand = { name: "startAutocomplete", exec: function(editor) { if (!editor.completer) editor.completer = new Autocomplete(); editor.completer.autoInsert = false; editor.completer.autoSelect = true; editor.completer.showPopup(editor); editor.completer.cancelContextMenu(); }, bindKey: "Ctrl-Space|Ctrl-Shift-Space|Alt-Space" }; var FilteredList = function(array, filterText) { this.all = array; this.filtered = array; this.filterText = filterText || ""; this.exactMatch = false; }; (function(){ this.setFilter = function(str) { if (str.length > this.filterText && str.lastIndexOf(this.filterText, 0) === 0) var matches = this.filtered; else var matches = this.all; this.filterText = str; matches = this.filterCompletions(matches, this.filterText); matches = matches.sort(function(a, b) { return b.exactMatch - a.exactMatch || b.score - a.score; }); var prev = null; matches = matches.filter(function(item){ var caption = item.snippet || item.caption || item.value; if (caption === prev) return false; prev = caption; return true; }); this.filtered = matches; }; this.filterCompletions = function(items, needle) { var results = []; var upper = needle.toUpperCase(); var lower = needle.toLowerCase(); loop: for (var i = 0, item; item = items[i]; i++) { var caption = item.value || item.caption || item.snippet; if (!caption) continue; var lastIndex = -1; var matchMask = 0; var penalty = 0; var index, distance; if (this.exactMatch) { if (needle !== caption.substr(0, needle.length)) continue loop; }else{ for (var j = 0; j < needle.length; j++) { var i1 = caption.indexOf(lower[j], lastIndex + 1); var i2 = caption.indexOf(upper[j], lastIndex + 1); index = (i1 >= 0) ? ((i2 < 0 || i1 < i2) ? i1 : i2) : i2; if (index < 0) continue loop; distance = index - lastIndex - 1; if (distance > 0) { if (lastIndex === -1) penalty += 10; penalty += distance; } matchMask = matchMask | (1 << index); lastIndex = index; } } item.matchMask = matchMask; item.exactMatch = penalty ? 0 : 1; item.score = (item.score || 0) - penalty; results.push(item); } return results; }; }).call(FilteredList.prototype); exports.Autocomplete = Autocomplete; exports.FilteredList = FilteredList; }); define("ace/autocomplete/text_completer",["require","exports","module","ace/range"], function(require, exports, module) { var Range = require("../range").Range; var splitRegex = /[^a-zA-Z_0-9\$\-\u00C0-\u1FFF\u2C00-\uD7FF\w]+/; function getWordIndex(doc, pos) { var textBefore = doc.getTextRange(Range.fromPoints({row: 0, column:0}, pos)); return textBefore.split(splitRegex).length - 1; } function wordDistance(doc, pos) { var prefixPos = getWordIndex(doc, pos); var words = doc.getValue().split(splitRegex); var wordScores = Object.create(null); var currentWord = words[prefixPos]; words.forEach(function(word, idx) { if (!word || word === currentWord) return; var distance = Math.abs(prefixPos - idx); var score = words.length - distance; if (wordScores[word]) { wordScores[word] = Math.max(score, wordScores[word]); } else { wordScores[word] = score; } }); return wordScores; } exports.getCompletions = function(editor, session, pos, prefix, callback) { var wordScore = wordDistance(session, pos, prefix); var wordList = Object.keys(wordScore); callback(null, wordList.map(function(word) { return { caption: word, value: word, score: wordScore[word], meta: "local" }; })); }; }); define("ace/ext/language_tools",["require","exports","module","ace/snippets","ace/autocomplete","ace/config","ace/lib/lang","ace/autocomplete/util","ace/autocomplete/text_completer","ace/editor","ace/config"], function(require, exports, module) { "use strict"; var snippetManager = require("../snippets").snippetManager; var Autocomplete = require("../autocomplete").Autocomplete; var config = require("../config"); var lang = require("../lib/lang"); var util = require("../autocomplete/util"); var textCompleter = require("../autocomplete/text_completer"); var keyWordCompleter = { getCompletions: function(editor, session, pos, prefix, callback) { if (session.$mode.completer) { return session.$mode.completer.getCompletions(editor, session, pos, prefix, callback); } var state = editor.session.getState(pos.row); var completions = session.$mode.getCompletions(state, session, pos, prefix); callback(null, completions); } }; var snippetCompleter = { getCompletions: function(editor, session, pos, prefix, callback) { var snippetMap = snippetManager.snippetMap; var completions = []; snippetManager.getActiveScopes(editor).forEach(function(scope) { var snippets = snippetMap[scope] || []; for (var i = snippets.length; i--;) { var s = snippets[i]; var caption = s.name || s.tabTrigger; if (!caption) continue; completions.push({ caption: caption, snippet: s.content, meta: s.tabTrigger && !s.name ? s.tabTrigger + "\u21E5 " : "snippet", type: "snippet" }); } }, this); callback(null, completions); }, getDocTooltip: function(item) { if (item.type == "snippet" && !item.docHTML) { item.docHTML = [ "", lang.escapeHTML(item.caption), "", "
", lang.escapeHTML(item.snippet) ].join(""); } } }; var completers = [snippetCompleter, textCompleter, keyWordCompleter]; exports.setCompleters = function(val) { completers.length = 0; if (val) completers.push.apply(completers, val); }; exports.addCompleter = function(completer) { completers.push(completer); }; exports.textCompleter = textCompleter; exports.keyWordCompleter = keyWordCompleter; exports.snippetCompleter = snippetCompleter; var expandSnippet = { name: "expandSnippet", exec: function(editor) { return snippetManager.expandWithTab(editor); }, bindKey: "Tab" }; var onChangeMode = function(e, editor) { loadSnippetsForMode(editor.session.$mode); }; var loadSnippetsForMode = function(mode) { var id = mode.$id; if (!snippetManager.files) snippetManager.files = {}; loadSnippetFile(id); if (mode.modes) mode.modes.forEach(loadSnippetsForMode); }; var loadSnippetFile = function(id) { if (!id || snippetManager.files[id]) return; var snippetFilePath = id.replace("mode", "snippets"); snippetManager.files[id] = {}; config.loadModule(snippetFilePath, function(m) { if (m) { snippetManager.files[id] = m; if (!m.snippets && m.snippetText) m.snippets = snippetManager.parseSnippetFile(m.snippetText); snippetManager.register(m.snippets || [], m.scope); if (m.includeScopes) { snippetManager.snippetMap[m.scope].includeScopes = m.includeScopes; m.includeScopes.forEach(function(x) { loadSnippetFile("ace/mode/" + x); }); } } }); }; var doLiveAutocomplete = function(e) { var editor = e.editor; var hasCompleter = editor.completer && editor.completer.activated; if (e.command.name === "backspace") { if (hasCompleter && !util.getCompletionPrefix(editor)) editor.completer.detach(); } else if (e.command.name === "insertstring") { var prefix = util.getCompletionPrefix(editor); if (prefix && !hasCompleter) { if (!editor.completer) { editor.completer = new Autocomplete(); } editor.completer.autoInsert = false; editor.completer.showPopup(editor); } } }; var Editor = require("../editor").Editor; require("../config").defineOptions(Editor.prototype, "editor", { enableBasicAutocompletion: { set: function(val) { if (val) { if (!this.completers) this.completers = Array.isArray(val)? val: completers; this.commands.addCommand(Autocomplete.startCommand); } else { this.commands.removeCommand(Autocomplete.startCommand); } }, value: false }, enableLiveAutocompletion: { set: function(val) { if (val) { if (!this.completers) this.completers = Array.isArray(val)? val: completers; this.commands.on('afterExec', doLiveAutocomplete); } else { this.commands.removeListener('afterExec', doLiveAutocomplete); } }, value: false }, enableSnippets: { set: function(val) { if (val) { this.commands.addCommand(expandSnippet); this.on("changeMode", onChangeMode); onChangeMode(null, this); } else { this.commands.removeCommand(expandSnippet); this.off("changeMode", onChangeMode); } }, value: false } }); }); define("ace/ext/beautify/php_rules",["require","exports","module","ace/token_iterator"], function(require, exports, module) { "use strict"; var TokenIterator = require("ace/token_iterator").TokenIterator; exports.newLines = [{ type: 'support.php_tag', value: '' }, { type: 'paren.lparen', value: '{', indent: true }, { type: 'paren.rparen', breakBefore: true, value: '}', indent: false }, { type: 'paren.rparen', breakBefore: true, value: '})', indent: false, dontBreak: true }, { type: 'comment' }, { type: 'text', value: ';' }, { type: 'text', value: ':', context: 'php' }, { type: 'keyword', value: 'case', indent: true, dontBreak: true }, { type: 'keyword', value: 'default', indent: true, dontBreak: true }, { type: 'keyword', value: 'break', indent: false, dontBreak: true }, { type: 'punctuation.doctype.end', value: '>' }, { type: 'meta.tag.punctuation.end', value: '>' }, { type: 'meta.tag.punctuation.begin', value: '<', blockTag: true, indent: true, dontBreak: true }, { type: 'meta.tag.punctuation.begin', value: '' ){ context = 'php'; } else if( token.type == 'support.php_tag' && token.value == '?>' ){ context = 'html'; } else if( token.type == 'meta.tag.name.style' && context != 'css' ){ context = 'css'; } else if( token.type == 'meta.tag.name.style' && context == 'css' ){ context = 'html'; } else if( token.type == 'meta.tag.name.script' && context != 'js' ){ context = 'js'; } else if( token.type == 'meta.tag.name.script' && context == 'js' ){ context = 'html'; } nextToken = iterator.stepForward(); if (nextToken && nextToken.type.indexOf('meta.tag.name') == 0) { nextTag = nextToken.value; } if ( lastToken.type == 'support.php_tag' && lastToken.value == '' ) { dontBreak = false; } lastTag = tag; lastToken = token; token = nextToken; if (token===null) { break; } } return code; }; }); define("ace/ext/beautify",["require","exports","module","ace/token_iterator","ace/ext/beautify/php_rules"], function(require, exports, module) { "use strict"; var TokenIterator = require("ace/token_iterator").TokenIterator; var phpTransform = require("./beautify/php_rules").transform; exports.beautify = function(session) { var iterator = new TokenIterator(session, 0, 0); var token = iterator.getCurrentToken(); var context = session.$modeId.split("/").pop(); var code = phpTransform(iterator, context); session.doc.setValue(code); }; exports.commands = [{ name: "beautify", exec: function(editor) { exports.beautify(editor.session); }, bindKey: "Ctrl-Shift-B" }] }); define("kitchen-sink/demo",["require","exports","module","ace/lib/fixoldbrowsers","ace/multi_select","ace/ext/spellcheck","kitchen-sink/inline_editor","kitchen-sink/dev_util","kitchen-sink/file_drop","ace/config","ace/lib/dom","ace/lib/net","ace/lib/lang","ace/lib/useragent","ace/lib/event","ace/theme/textmate","ace/edit_session","ace/undomanager","ace/keyboard/hash_handler","ace/virtual_renderer","ace/editor","ace/ext/whitespace","kitchen-sink/doclist","ace/ext/modelist","ace/ext/themelist","kitchen-sink/layout","kitchen-sink/token_tooltip","kitchen-sink/util","ace/ext/elastic_tabstops_lite","ace/incremental_search","ace/worker/worker_client","ace/split","ace/keyboard/vim","ace/ext/statusbar","ace/ext/emmet","ace/snippets","ace/ext/language_tools","ace/ext/beautify","ace/keyboard/keybinding","ace/commands/command_manager"], function(require, exports, module) { "use strict"; require("ace/lib/fixoldbrowsers"); require("ace/multi_select"); require("ace/ext/spellcheck"); require("./inline_editor"); require("./dev_util"); require("./file_drop"); var config = require("ace/config"); config.init(); var env = {}; var dom = require("ace/lib/dom"); var net = require("ace/lib/net"); var lang = require("ace/lib/lang"); var useragent = require("ace/lib/useragent"); var event = require("ace/lib/event"); var theme = require("ace/theme/textmate"); var EditSession = require("ace/edit_session").EditSession; var UndoManager = require("ace/undomanager").UndoManager; var HashHandler = require("ace/keyboard/hash_handler").HashHandler; var Renderer = require("ace/virtual_renderer").VirtualRenderer; var Editor = require("ace/editor").Editor; var whitespace = require("ace/ext/whitespace"); var doclist = require("./doclist"); var modelist = require("ace/ext/modelist"); var themelist = require("ace/ext/themelist"); var layout = require("./layout"); var TokenTooltip = require("./token_tooltip").TokenTooltip; var util = require("./util"); var saveOption = util.saveOption; var fillDropdown = util.fillDropdown; var bindCheckbox = util.bindCheckbox; var bindDropdown = util.bindDropdown; var ElasticTabstopsLite = require("ace/ext/elastic_tabstops_lite").ElasticTabstopsLite; var IncrementalSearch = require("ace/incremental_search").IncrementalSearch; var workerModule = require("ace/worker/worker_client"); if (location.href.indexOf("noworker") !== -1) { workerModule.WorkerClient = workerModule.UIWorkerClient; } var container = document.getElementById("editor-container"); var Split = require("ace/split").Split; var split = new Split(container, theme, 1); env.editor = split.getEditor(0); split.on("focus", function(editor) { env.editor = editor; updateUIEditorOptions(); }); env.split = split; window.env = env; var consoleEl = dom.createElement("div"); container.parentNode.appendChild(consoleEl); consoleEl.style.cssText = "position:fixed; bottom:1px; right:0;\ border:1px solid #baf; z-index:100"; var cmdLine = new layout.singleLineEditor(consoleEl); cmdLine.editor = env.editor; env.editor.cmdLine = cmdLine; env.editor.showCommandLine = function(val) { this.cmdLine.focus(); if (typeof val == "string") this.cmdLine.setValue(val, 1); }; env.editor.commands.addCommands([{ name: "gotoline", bindKey: {win: "Ctrl-L", mac: "Command-L"}, exec: function(editor, line) { if (typeof line == "object") { var arg = this.name + " " + editor.getCursorPosition().row; editor.cmdLine.setValue(arg, 1); editor.cmdLine.focus(); return; } line = parseInt(line, 10); if (!isNaN(line)) editor.gotoLine(line); }, readOnly: true }, { name: "snippet", bindKey: {win: "Alt-C", mac: "Command-Alt-C"}, exec: function(editor, needle) { if (typeof needle == "object") { editor.cmdLine.setValue("snippet ", 1); editor.cmdLine.focus(); return; } var s = snippetManager.getSnippetByName(needle, editor); if (s) snippetManager.insertSnippet(editor, s.content); }, readOnly: true }, { name: "focusCommandLine", bindKey: "shift-esc|ctrl-`", exec: function(editor, needle) { editor.cmdLine.focus(); }, readOnly: true }, { name: "nextFile", bindKey: "Ctrl-tab", exec: function(editor) { doclist.cycleOpen(editor, 1); }, readOnly: true }, { name: "previousFile", bindKey: "Ctrl-shift-tab", exec: function(editor) { doclist.cycleOpen(editor, -1); }, readOnly: true }, { name: "execute", bindKey: "ctrl+enter", exec: function(editor) { try { var r = window.eval(editor.getCopyText() || editor.getValue()); } catch(e) { r = e; } editor.cmdLine.setValue(r + ""); }, readOnly: true }, { name: "showKeyboardShortcuts", bindKey: {win: "Ctrl-Alt-h", mac: "Command-Alt-h"}, exec: function(editor) { config.loadModule("ace/ext/keybinding_menu", function(module) { module.init(editor); editor.showKeyboardShortcuts(); }); } }, { name: "increaseFontSize", bindKey: "Ctrl-=|Ctrl-+", exec: function(editor) { var size = parseInt(editor.getFontSize(), 10) || 12; editor.setFontSize(size + 1); } }, { name: "decreaseFontSize", bindKey: "Ctrl+-|Ctrl-_", exec: function(editor) { var size = parseInt(editor.getFontSize(), 10) || 12; editor.setFontSize(Math.max(size - 1 || 1)); } }, { name: "resetFontSize", bindKey: "Ctrl+0|Ctrl-Numpad0", exec: function(editor) { editor.setFontSize(12); } }]); env.editor.commands.addCommands(whitespace.commands); cmdLine.commands.bindKeys({ "Shift-Return|Ctrl-Return|Alt-Return": function(cmdLine) { cmdLine.insert("\n"); }, "Esc|Shift-Esc": function(cmdLine){ cmdLine.editor.focus(); }, "Return": function(cmdLine){ var command = cmdLine.getValue().split(/\s+/); var editor = cmdLine.editor; editor.commands.exec(command[0], editor, command[1]); editor.focus(); } }); cmdLine.commands.removeCommands(["find", "gotoline", "findall", "replace", "replaceall"]); var commands = env.editor.commands; commands.addCommand({ name: "save", bindKey: {win: "Ctrl-S", mac: "Command-S"}, exec: function(arg) { var session = env.editor.session; var name = session.name.match(/[^\/]+$/); localStorage.setItem( "saved_file:" + name, session.getValue() ); env.editor.cmdLine.setValue("saved "+ name); } }); commands.addCommand({ name: "load", bindKey: {win: "Ctrl-O", mac: "Command-O"}, exec: function(arg) { var session = env.editor.session; var name = session.name.match(/[^\/]+$/); var value = localStorage.getItem("saved_file:" + name); if (typeof value == "string") { session.setValue(value); env.editor.cmdLine.setValue("loaded "+ name); } else { env.editor.cmdLine.setValue("no previuos value saved for "+ name); } } }); var keybindings = { ace: null, // Null = use "default" keymapping vim: require("ace/keyboard/vim").handler, emacs: "ace/keyboard/emacs", custom: new HashHandler({ "gotoright": "Tab", "indent": "]", "outdent": "[", "gotolinestart": "^", "gotolineend": "$" }) }; var consoleHeight = 20; function onResize() { var left = env.split.$container.offsetLeft; var width = document.documentElement.clientWidth - left; container.style.width = width + "px"; container.style.height = document.documentElement.clientHeight - consoleHeight + "px"; env.split.resize(); consoleEl.style.width = width + "px"; cmdLine.resize(); } window.onresize = onResize; onResize(); var docEl = document.getElementById("doc"); var modeEl = document.getElementById("mode"); var wrapModeEl = document.getElementById("soft_wrap"); var themeEl = document.getElementById("theme"); var foldingEl = document.getElementById("folding"); var selectStyleEl = document.getElementById("select_style"); var highlightActiveEl = document.getElementById("highlight_active"); var showHiddenEl = document.getElementById("show_hidden"); var showGutterEl = document.getElementById("show_gutter"); var showPrintMarginEl = document.getElementById("show_print_margin"); var highlightSelectedWordE = document.getElementById("highlight_selected_word"); var showHScrollEl = document.getElementById("show_hscroll"); var showVScrollEl = document.getElementById("show_vscroll"); var animateScrollEl = document.getElementById("animate_scroll"); var softTabEl = document.getElementById("soft_tab"); var navigateWithinSoftTabEl = document.getElementById("navigate_within_soft_tab"); var behavioursEl = document.getElementById("enable_behaviours"); fillDropdown(docEl, doclist.all); fillDropdown(modeEl, modelist.modes); var modesByName = modelist.modesByName; bindDropdown("mode", function(value) { env.editor.session.setMode(modesByName[value].mode || modesByName.text.mode); env.editor.session.modeName = value; }); doclist.history = doclist.docs.map(function(doc) { return doc.name; }); doclist.history.index = 0; doclist.cycleOpen = function(editor, dir) { var h = this.history; h.index += dir; if (h.index >= h.length) h.index = 0; else if (h.index <= 0) h.index = h.length - 1; var s = h[h.index]; docEl.value = s; docEl.onchange(); }; doclist.addToHistory = function(name) { var h = this.history; var i = h.indexOf(name); if (i != h.index) { if (i != -1) h.splice(i, 1); h.index = h.push(name); } }; bindDropdown("doc", function(name) { doclist.loadDoc(name, function(session) { if (!session) return; doclist.addToHistory(session.name); session = env.split.setSession(session); whitespace.detectIndentation(session); updateUIEditorOptions(); env.editor.focus(); }); }); function updateUIEditorOptions() { var editor = env.editor; var session = editor.session; session.setFoldStyle(foldingEl.value); saveOption(docEl, session.name); saveOption(modeEl, session.modeName || "text"); saveOption(wrapModeEl, session.getUseWrapMode() ? session.getWrapLimitRange().min || "free" : "off"); saveOption(selectStyleEl, editor.getSelectionStyle() == "line"); saveOption(themeEl, editor.getTheme()); saveOption(highlightActiveEl, editor.getHighlightActiveLine()); saveOption(showHiddenEl, editor.getShowInvisibles()); saveOption(showGutterEl, editor.renderer.getShowGutter()); saveOption(showPrintMarginEl, editor.renderer.getShowPrintMargin()); saveOption(highlightSelectedWordE, editor.getHighlightSelectedWord()); saveOption(showHScrollEl, editor.renderer.getHScrollBarAlwaysVisible()); saveOption(animateScrollEl, editor.getAnimatedScroll()); saveOption(softTabEl, session.getUseSoftTabs()); saveOption(navigateWithinSoftTabEl, session.getNavigateWithinSoftTabs()); saveOption(behavioursEl, editor.getBehavioursEnabled()); } themelist.themes.forEach(function(x){ x.value = x.theme }); fillDropdown(themeEl, { Bright: themelist.themes.filter(function(x){return !x.isDark}), Dark: themelist.themes.filter(function(x){return x.isDark}) }); event.addListener(themeEl, "mouseover", function(e){ themeEl.desiredValue = e.target.value; if (!themeEl.$timer) themeEl.$timer = setTimeout(themeEl.updateTheme); }); event.addListener(themeEl, "mouseout", function(e){ themeEl.desiredValue = null; if (!themeEl.$timer) themeEl.$timer = setTimeout(themeEl.updateTheme, 20); }); themeEl.updateTheme = function(){ env.split.setTheme((themeEl.desiredValue || themeEl.selectedValue)); themeEl.$timer = null; }; bindDropdown("theme", function(value) { if (!value) return; env.editor.setTheme(value); themeEl.selectedValue = value; }); bindDropdown("keybinding", function(value) { env.editor.setKeyboardHandler(keybindings[value]); }); bindDropdown("fontsize", function(value) { env.split.setFontSize(value); }); bindDropdown("folding", function(value) { env.editor.session.setFoldStyle(value); env.editor.setShowFoldWidgets(value !== "manual"); }); bindDropdown("soft_wrap", function(value) { env.editor.setOption("wrap", value); }); bindCheckbox("select_style", function(checked) { env.editor.setOption("selectionStyle", checked ? "line" : "text"); }); bindCheckbox("highlight_active", function(checked) { env.editor.setHighlightActiveLine(checked); }); bindCheckbox("show_hidden", function(checked) { env.editor.setShowInvisibles(checked); }); bindCheckbox("display_indent_guides", function(checked) { env.editor.setDisplayIndentGuides(checked); }); bindCheckbox("show_gutter", function(checked) { env.editor.renderer.setShowGutter(checked); }); bindCheckbox("show_print_margin", function(checked) { env.editor.renderer.setShowPrintMargin(checked); }); bindCheckbox("highlight_selected_word", function(checked) { env.editor.setHighlightSelectedWord(checked); }); bindCheckbox("show_hscroll", function(checked) { env.editor.setOption("hScrollBarAlwaysVisible", checked); }); bindCheckbox("show_vscroll", function(checked) { env.editor.setOption("vScrollBarAlwaysVisible", checked); }); bindCheckbox("animate_scroll", function(checked) { env.editor.setAnimatedScroll(checked); }); bindCheckbox("soft_tab", function(checked) { env.editor.session.setUseSoftTabs(checked); }); bindCheckbox("navigate_within_soft_tab", function(checked) { env.editor.session.setNavigateWithinSoftTabs(checked); }); bindCheckbox("enable_behaviours", function(checked) { env.editor.setBehavioursEnabled(checked); }); bindCheckbox("fade_fold_widgets", function(checked) { env.editor.setFadeFoldWidgets(checked); }); bindCheckbox("read_only", function(checked) { env.editor.setReadOnly(checked); }); bindCheckbox("scrollPastEnd", function(checked) { env.editor.setOption("scrollPastEnd", checked); }); bindDropdown("split", function(value) { var sp = env.split; if (value == "none") { sp.setSplits(1); } else { var newEditor = (sp.getSplits() == 1); sp.setOrientation(value == "below" ? sp.BELOW : sp.BESIDE); sp.setSplits(2); if (newEditor) { var session = sp.getEditor(0).session; var newSession = sp.setSession(session, 1); newSession.name = session.name; } } }); bindCheckbox("elastic_tabstops", function(checked) { env.editor.setOption("useElasticTabstops", checked); }); var iSearchCheckbox = bindCheckbox("isearch", function(checked) { env.editor.setOption("useIncrementalSearch", checked); }); env.editor.addEventListener('incrementalSearchSettingChanged', function(event) { iSearchCheckbox.checked = event.isEnabled; }); function synchroniseScrolling() { var s1 = env.split.$editors[0].session; var s2 = env.split.$editors[1].session; s1.on('changeScrollTop', function(pos) {s2.setScrollTop(pos)}); s2.on('changeScrollTop', function(pos) {s1.setScrollTop(pos)}); s1.on('changeScrollLeft', function(pos) {s2.setScrollLeft(pos)}); s2.on('changeScrollLeft', function(pos) {s1.setScrollLeft(pos)}); } bindCheckbox("highlight_token", function(checked) { var editor = env.editor; if (editor.tokenTooltip && !checked) { editor.tokenTooltip.destroy(); delete editor.tokenTooltip; } else if (checked) { editor.tokenTooltip = new TokenTooltip(editor); } }); var StatusBar = require("ace/ext/statusbar").StatusBar; new StatusBar(env.editor, cmdLine.container); var Emmet = require("ace/ext/emmet"); net.loadScript("https://cloud9ide.github.io/emmet-core/emmet.js", function() { Emmet.setCore(window.emmet); env.editor.setOption("enableEmmet", true); }); var snippetManager = require("ace/snippets").snippetManager; env.editSnippets = function() { var sp = env.split; if (sp.getSplits() == 2) { sp.setSplits(1); return; } sp.setSplits(1); sp.setSplits(2); sp.setOrientation(sp.BESIDE); var editor = sp.$editors[1]; var id = sp.$editors[0].session.$mode.$id || ""; var m = snippetManager.files[id]; if (!doclist["snippets/" + id]) { var text = m.snippetText; var s = doclist.initDoc(text, "", {}); s.setMode("ace/mode/snippets"); doclist["snippets/" + id] = s; } editor.on("blur", function() { m.snippetText = editor.getValue(); snippetManager.unregister(m.snippets); m.snippets = snippetManager.parseSnippetFile(m.snippetText, m.scope); snippetManager.register(m.snippets); }); sp.$editors[0].once("changeMode", function() { sp.setSplits(1); }); editor.setSession(doclist["snippets/" + id], 1); editor.focus(); }; require("ace/ext/language_tools"); env.editor.setOptions({ enableBasicAutocompletion: true, enableLiveAutocompletion: false, enableSnippets: true }); var beautify = require("ace/ext/beautify"); env.editor.commands.addCommands(beautify.commands); var KeyBinding = require("ace/keyboard/keybinding").KeyBinding; var CommandManager = require("ace/commands/command_manager").CommandManager; var commandManager = new CommandManager(); var kb = new KeyBinding({ commands: commandManager, fake: true }); event.addCommandKeyListener(document.documentElement, kb.onCommandKey.bind(kb)); event.addListener(document.documentElement, "keyup", function(e) { if (e.keyCode === 18) // do not trigger browser menu on windows e.preventDefault(); }); commandManager.addCommands([{ name: "window-left", bindKey: {win: "cmd-alt-left", mac: "ctrl-cmd-left"}, exec: function() { moveFocus("left"); } }, { name: "window-right", bindKey: {win: "cmd-alt-right", mac: "ctrl-cmd-right"}, exec: function() { moveFocus("right"); } }, { name: "window-up", bindKey: {win: "cmd-alt-up", mac: "ctrl-cmd-up"}, exec: function() { moveFocus("up"); } }, { name: "window-down", bindKey: {win: "cmd-alt-down", mac: "ctrl-cmd-down"}, exec: function() { moveFocus("down"); } }]); function moveFocus() { var el = document.activeElement; if (el == env.editor.textInput.getElement()) env.editor.cmdLine.focus(); else env.editor.focus(); } });