| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226 | ace.define("ace/snippets",[], 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);            s.endRe = guardedRegexp(s.endTrigger, s.endGuard, true);            s.endTriggerRe = new RegExp(s.endTrigger);        }        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);});ace.define("ace/ext/emmet",[], 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(/<!DOCTYPE[^>]+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;};});                (function() {                    ace.require(["ace/ext/emmet"], function(m) {                        if (typeof module == "object" && typeof exports == "object" && module) {                            module.exports = m;                        }                    });                })();            
 |