vendor/assets/javascripts/ace/ext-language_tools.js in ace-rails-ap-4.2 vs vendor/assets/javascripts/ace/ext-language_tools.js in ace-rails-ap-4.3

- old
+ new

@@ -1,169 +1,254 @@ -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) { +define("ace/snippets",["require","exports","module","ace/lib/oop","ace/lib/event_emitter","ace/lib/lang","ace/range","ace/range_list","ace/keyboard/hash_handler","ace/tokenizer","ace/clipboard","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 RangeList = require("./range_list").RangeList; var HashHandler = require("./keyboard/hash_handler").HashHandler; var Tokenizer = require("./tokenizer").Tokenizer; -var comparePoints = Range.comparePoints; +var clipboard = require("./clipboard"); +var VARIABLES = { + CURRENT_WORD: function(editor) { + return editor.session.getTextRange(editor.session.getWordRange()); + }, + SELECTION: function(editor, name, indentation) { + var text = editor.session.getTextRange(); + if (indentation) + return text.replace(/\n\r?([ \t]*\S)/g, "\n" + indentation + "$1"); + return text; + }, + CURRENT_LINE: function(editor) { + return editor.session.getLine(editor.getCursorPosition().row); + }, + PREV_LINE: function(editor) { + return editor.session.getLine(editor.getCursorPosition().row - 1); + }, + LINE_INDEX: function(editor) { + return editor.getCursorPosition().row; + }, + LINE_NUMBER: function(editor) { + return editor.getCursorPosition().row + 1; + }, + SOFT_TABS: function(editor) { + return editor.session.getUseSoftTabs() ? "YES" : "NO"; + }, + TAB_SIZE: function(editor) { + return editor.session.getTabSize(); + }, + CLIPBOARD: function(editor) { + return clipboard.getText && clipboard.getText(); + }, + FILENAME: function(editor) { + return /[^/\\]*$/.exec(this.FILEPATH(editor))[0]; + }, + FILENAME_BASE: function(editor) { + return /[^/\\]*$/.exec(this.FILEPATH(editor))[0].replace(/\.[^.]*$/, ""); + }, + DIRECTORY: function(editor) { + return this.FILEPATH(editor).replace(/[^/\\]*$/, ""); + }, + FILEPATH: function(editor) { return "/not implemented.txt"; }, + WORKSPACE_NAME: function() { return "Unknown"; }, + FULLNAME: function() { return "Unknown"; }, + BLOCK_COMMENT_START: function(editor) { + var mode = editor.session.$mode || {}; + return mode.blockComment && mode.blockComment.start || ""; + }, + BLOCK_COMMENT_END: function(editor) { + var mode = editor.session.$mode || {}; + return mode.blockComment && mode.blockComment.end || ""; + }, + LINE_COMMENT: function(editor) { + var mode = editor.session.$mode || {}; + return mode.lineCommentStart || ""; + }, + CURRENT_YEAR: date.bind(null, {year: "numeric"}), + CURRENT_YEAR_SHORT: date.bind(null, {year: "2-digit"}), + CURRENT_MONTH: date.bind(null, {month: "numeric"}), + CURRENT_MONTH_NAME: date.bind(null, {month: "long"}), + CURRENT_MONTH_NAME_SHORT: date.bind(null, {month: "short"}), + CURRENT_DATE: date.bind(null, {day: "2-digit"}), + CURRENT_DAY_NAME: date.bind(null, {weekday: "long"}), + CURRENT_DAY_NAME_SHORT: date.bind(null, {weekday: "short"}), + CURRENT_HOUR: date.bind(null, {hour: "2-digit", hour12: false}), + CURRENT_MINUTE: date.bind(null, {minute: "2-digit"}), + CURRENT_SECOND: date.bind(null, {second: "2-digit"}) +}; + +VARIABLES.SELECTED_TEXT = VARIABLES.SELECTION; + +function date(dateFormat) { + var str = new Date().toLocaleString("en-us", dateFormat); + return str.length == 1 ? "0" + str : str; +} + var SnippetManager = function() { this.snippetMap = {}; this.snippetNameMap = {}; }; (function() { oop.implement(this, EventEmitter); this.getTokenizer = function() { - function TabstopToken(str, _, stack) { + return SnippetManager.$tokenizer || this.createTokenizer(); + }; + + this.createTokenizer = function() { + function TabstopToken(str) { str = str.substr(1); - if (/^\d+$/.test(str) && !stack.inFormatString) + if (/^\d+$/.test(str)) return [{tabstopId: parseInt(str, 10)}]; return [{text: str}]; } function escape(ch) { return "(?:[^\\\\" + ch + "]|\\\\.)"; } + var formatMatcher = { + regex: "/(" + escape("/") + "+)/", + onMatch: function(val, state, stack) { + var ts = stack[0]; + ts.fmtString = true; + ts.guard = val.slice(1, -1); + ts.flag = ""; + return ""; + }, + next: "formatString" + }; + 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) { + } 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); + var t = TabstopToken(str.substr(1)); 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(","); + var choices = val.slice(1, -1).replace(/\\[,|\\]|,/g, function(operator) { + return operator.length == 2 ? operator[1] : "\x00"; + }).split("\x00"); + stack[0].choices = choices; + return [choices[0]]; }, 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"}, + formatMatcher, {regex: "([^:}\\\\]|\\\\.)*:?", token: "", next: "start"} ], formatString: [ - {regex: "/(" + escape("/") + "+)/", token: "regex"}, - {regex: "", onMatch: function(val, state, stack) { - stack.inFormatString = true; + {regex: /:/, onMatch: function(val, state, stack) { + if (stack.length && stack[0].expectElse) { + stack[0].expectElse = false; + stack[0].ifEnd = {elseEnd: stack[0]}; + return [stack[0].ifEnd]; + } + 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 (ch == "n") + val = "\n"; + else if (ch == "t") + val = "\t"; + else if ("ulULE".indexOf(ch) != -1) + val = {changeCase: ch, local: ch > "a"}; + return [val]; + }}, + {regex: "/\\w*}", onMatch: function(val, state, stack) { + var next = stack.shift(); + if (next) + next.flag = val.slice(1, -1); + this.next = next && next.tabstopId ? "start" : ""; + return [next || val]; + }, next: "start"}, + {regex: /\$(?:\d+|\w+)/, onMatch: function(val, state, stack) { + return [{text: val.slice(1)}]; + }}, + {regex: /\${\w+/, onMatch: function(val, state, stack) { + var token = {text: val.slice(2)}; + stack.unshift(token); + return [token]; + }, next: "formatStringVar"}, + {regex: /\n/, token: "newline", merge: false}, + {regex: /}/, onMatch: function(val, state, stack) { + var next = stack.shift(); + this.next = next && next.tabstopId ? "start" : ""; + return [next || val]; }, next: "start"} + ], + formatStringVar: [ + {regex: /:\/\w+}/, onMatch: function(val, state, stack) { + var ts = stack[0]; + ts.formatFunction = val.slice(2, -1); + return [stack.shift()]; + }, next: "formatString"}, + formatMatcher, + {regex: /:[\?\-+]?/, onMatch: function(val, state, stack) { + if (val[1] == "+") + stack[0].ifEnd = stack[0]; + if (val[1] == "?") + stack[0].expectElse = true; + }, next: "formatString"}, + {regex: "([^:}\\\\]|\\\\.)*:?", token: "", next: "formatString"} ] }); - 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]; - } + + this.getVariableValue = function(editor, name, indentation) { + if (/^\d+$/.test(name)) + return (this.variables.__ || {})[name] || ""; + if (/^[A-Z]\d+$/.test(name)) + return (this.variables[name[0] + "__"] || {})[name.substr(1)] || ""; + 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"; - } + if (!this.variables.hasOwnProperty(name)) + return ""; + var value = this.variables[name]; + if (typeof value == "function") + value = this.variables[name](editor, name, indentation); + return value == null ? "" : value; }; - this.variables = {}; - this.getVariableValue = function(editor, varName) { - if (this.variables.hasOwnProperty(varName)) - return this.variables[varName](editor, varName) || ""; - return this.$getDefaultValue(editor, varName) || ""; - }; + + this.variables = VARIABLES; this.tmStrFormat = function(str, ch, editor) { + if (!ch.fmt) return str; var flag = ch.flag || ""; var re = ch.guard; - re = new RegExp(re, flag.replace(/[^gi]/, "")); - var fmtTokens = this.tokenizeTmSnippet(ch.fmt, "formatString"); + re = new RegExp(re, flag.replace(/[^gim]/g, "")); + var fmtTokens = typeof ch.fmt == "string" ? this.tokenizeTmSnippet(ch.fmt, "formatString") : ch.fmt; var _self = this; var formatted = str.replace(re, function() { - _self.variables.__ = arguments; + var oldArgs = _self.variables.__; + _self.variables.__ = [].slice.call(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") { @@ -184,44 +269,67 @@ fmtParts[i] = ch.toUpperCase(); } else if (gChangeCase == "L") { fmtParts[i] = ch.toLowerCase(); } } + _self.variables.__ = oldArgs; return fmtParts.join(""); }); - this.variables.__ = null; return formatted; }; + + this.tmFormatFunction = function(str, ch, editor) { + if (ch.formatFunction == "upcase") + return str.toUpperCase(); + if (ch.formatFunction == "downcase") + return str.toLowerCase(); + return str; + }; this.resolveVariables = function(snippet, editor) { var result = []; + var indentation = ""; + var afterNewLine = true; for (var i = 0; i < snippet.length; i++) { var ch = snippet[i]; if (typeof ch == "string") { result.push(ch); - } else if (typeof ch != "object") { + if (ch == "\n") { + afterNewLine = true; + indentation = ""; + } + else if (afterNewLine) { + indentation = /^\t*/.exec(ch)[0]; + afterNewLine = /\S/.test(ch); + } 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); + } + if (!ch) continue; + afterNewLine = false; + + if (ch.fmtString) { + var j = snippet.indexOf(ch, i + 1); + if (j == -1) j = snippet.length; + ch.fmt = snippet.slice(i + 1, j); + i = j; + } + + if (ch.text) { + var value = this.getVariableValue(editor, ch.text, indentation) + ""; + if (ch.fmtString) + value = this.tmStrFormat(value, ch, editor); + if (ch.formatFunction) + value = this.tmFormatFunction(value, ch, editor); + + if (value && !ch.ifEnd) { + result.push(value); + gotoNext(ch); + } else if (!value && ch.ifEnd) { + gotoNext(ch.ifEnd); } + } else if (ch.elseEnd) { + gotoNext(ch.elseEnd); } else if (ch.tabstopId != null) { result.push(ch); } else if (ch.changeCase != null) { result.push(ch); } @@ -261,13 +369,16 @@ var ts = tabstops[id]; if (!ts) { ts = tabstops[id] = []; ts.index = id; ts.value = ""; + ts.parents = {}; } if (ts.indexOf(p) !== -1) return; + if (p.choices && !ts.choices) + ts.choices = p.choices; ts.push(p); var i1 = tokens.indexOf(p, i + 1); if (i1 === -1) return; @@ -298,23 +409,28 @@ for (var i = 0; i < tokens.length; i++) { var p = tokens[i]; if (typeof p != "object") continue; var id = p.tabstopId; + var ts = tabstops[id]; var i1 = tokens.indexOf(p, i + 1); if (expanding[id]) { - if (expanding[id] === p) - expanding[id] = null; + if (expanding[id] === p) { + delete expanding[id]; + Object.keys(expanding).forEach(function(parentId) { + ts.parents[parentId] = true; + }); + } 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); + var value = ts.value; + if (typeof value !== "string") + value = copyValue(value); + else if (p.fmt) + value = this.tmStrFormat(value, p, editor); + tokens.splice.apply(tokens, [i + 1, Math.max(0, i1 - i)].concat(value, p)); if (ts.indexOf(p) === -1) ts.push(p); } var row = 0, column = 0; @@ -326,11 +442,11 @@ column = lines[lines.length - 1].length; row += lines.length - 1; } else column += t.length; text += t; - } else { + } else if (t) { if (!t.start) t.start = {row: row, column: column}; else t.end = {row: row, column: column}; } @@ -628,70 +744,47 @@ 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; + var parents = this.selectedTabstop && this.selectedTabstop.parents || {}; + var tabstops = (this.tabstops || []).slice(); + for (var i = 0; i < tabstops.length; i++) { + var ts = tabstops[i]; + var active = ts == this.selectedTabstop || parents[ts.index]; + ts.rangeList.$bias = active ? 0 : 1; + + if (delta.action == "remove" && ts !== this.selectedTabstop) { + var parentActive = ts.parents && ts.parents[this.selectedTabstop.index]; + var startIndex = ts.rangeList.pointIndex(delta.start, parentActive); + startIndex = startIndex < 0 ? -startIndex - 1 : startIndex + 1; + var endIndex = ts.rangeList.pointIndex(delta.end, parentActive); + endIndex = endIndex < 0 ? -endIndex - 1 : endIndex - 1; + var toRemove = ts.rangeList.ranges.slice(startIndex, endIndex); + for (var j = 0; j < toRemove.length; j++) + this.removeRange(toRemove[j]); } - - 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); + ts.rangeList.$onChange(delta); } - if (!ranges.length) + var session = this.editor.session; + if (!this.$inChange && isRemove && session.getLength() == 1 && !session.getValue()) this.detach(); }; this.updateLinkedFields = function() { var ts = this.selectedTabstop; - if (!ts || !ts.hasLinkedRanges) + if (!ts || !ts.hasLinkedRanges || !ts.firstNonLinked) return; this.$inChange = true; var session = this.editor.session; var text = session.getTextRange(ts.firstNonLinked); - for (var i = ts.length; i--;) { + for (var i = 0; i < ts.length; i++) { var range = ts[i]; if (!range.linked) continue; - var fmt = exports.snippetManager.tmStrFormat(text, range.original); + var original = range.original; + var fmt = exports.snippetManager.tmStrFormat(text, original, this.editor); session.replace(range, fmt); } this.$inChange = false; }; this.onAfterExec = function(e) { @@ -702,11 +795,11 @@ 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--;) { + for (var i = 0; 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) @@ -736,27 +829,32 @@ ts = this.tabstops[this.index]; if (!ts || !ts.length) return; this.selectedTabstop = ts; - if (!this.editor.inVirtualSelectionMode) { + var range = ts.firstNonLinked || ts; + if (!this.editor.inVirtualSelectionMode) { var sel = this.editor.multiSelect; - sel.toSingleRange(ts.firstNonLinked.clone()); - for (var i = ts.length; i--;) { + sel.toSingleRange(range.clone()); + for (var i = 0; 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.selection.setRange(range); } this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler); + if (this.selectedTabstop && this.selectedTabstop.choices) + this.editor.execCommand("startAutocomplete", {matches: this.selectedTabstop.choices}); }; this.addTabstops = function(tabstops, start, end) { + var useLink = this.useLink || !this.editor.getOption("enableMultiselect"); + if (!this.$openTabstops) this.$openTabstops = []; if (!tabstops[0]) { var p = Range.fromPoints(end, end); moveRelative(p.start, start); @@ -768,24 +866,27 @@ 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--;) { + ts.rangeList = new RangeList(); + ts.rangeList.$bias = 0; + + for (var i = 0; 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); + ts.rangeList.ranges.push(range); if (dest != ts) dest.unshift(range); else dest[i] = range; - if (p.fmtString) { + if (p.fmtString || (dest.firstNonLinked && useLink)) { range.linked = true; dest.hasLinkedRanges = true; } else if (!dest.firstNonLinked) dest.firstNonLinked = range; } @@ -819,13 +920,15 @@ range.markerId = null; }); }; this.removeRange = function(range) { var i = range.tabstop.indexOf(range); - range.tabstop.splice(i, 1); + if (i != -1) range.tabstop.splice(i, 1); i = this.ranges.indexOf(range); - this.ranges.splice(i, 1); + if (i != -1) this.ranges.splice(i, 1); + i = range.tabstop.rangeList.ranges.indexOf(range); + if (i != -1) range.tabstop.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); @@ -855,22 +958,10 @@ }); }).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; }; @@ -1079,10 +1170,12 @@ } addToken(caption.slice(lastIndex, caption.length), ""); if (data.meta) tokens.push({type: "completion-meta", value: data.meta}); + if (data.message) + tokens.push({type: "completion-message", value: data.message}); return tokens; }; bgTokenizer.$updateOnChange = noop; bgTokenizer.start = noop; @@ -1164,10 +1257,25 @@ this._signal("show"); lastMouseEvent = null; popup.isOpen = true; }; + popup.goTo = function(where) { + var row = this.getRow(); + var max = this.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.setRow(row); + }; + + popup.getTextLeftOffset = function() { return this.$borderSize + this.renderer.$padding + this.$imageSize; }; popup.$imageSize = 0; @@ -1197,10 +1305,13 @@ }\ .ace_completion-meta {\ opacity: 0.5;\ margin: 0.9em;\ }\ +.ace_completion-message {\ + color: blue;\ +}\ .ace_editor.ace_autocomplete .ace_completion-highlight{\ color: #2d69c7;\ }\ .ace_dark.ace_editor.ace_autocomplete .ace_completion-highlight{\ color: #93ca12;\ @@ -1222,11 +1333,11 @@ background: #25282c;\ color: #c1c1c1;\ }", "autocompletion.css"); exports.AcePopup = AcePopup; - +exports.$singleLineEditor = $singleLineEditor; }); define("ace/autocomplete/util",["require","exports","module"], function(require, exports, module) { "use strict"; @@ -1285,20 +1396,20 @@ 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) { +define("ace/autocomplete",["require","exports","module","ace/keyboard/hash_handler","ace/autocomplete/popup","ace/autocomplete/util","ace/lib/lang","ace/lib/dom","ace/snippets","ace/config"], 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 config = require("./config"); var Autocomplete = function() { this.autoInsert = false; this.autoSelect = true; this.exactMatch = false; @@ -1418,21 +1529,11 @@ 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.popup.goTo(where); }; this.insertMatch = function(data, options) { if (!data) data = this.popup.getData(this.popup.getRow()); @@ -1502,11 +1603,11 @@ }); }); return true; }; - this.showPopup = function(editor) { + this.showPopup = function(editor, options) { if (this.editor) this.detach(); this.activated = true; @@ -1520,14 +1621,14 @@ editor.on("changeSelection", this.changeListener); editor.on("blur", this.blurListener); editor.on("mousedown", this.mousedownListener); editor.on("mousewheel", this.mousewheelListener); - this.updateCompletions(); + this.updateCompletions(false, options); }; - this.updateCompletions = function(keepPopupPosition) { + this.updateCompletions = function(keepPopupPosition, options) { 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; @@ -1539,10 +1640,18 @@ && !this.completions.filtered[0].snippet) return this.detach(); this.openPopup(this.editor, prefix, keepPopupPosition); return; } + + if (options && options.matches) { + var pos = this.editor.getSelectionRange().start; + this.base = this.editor.session.doc.createAnchor(pos.row, pos.column); + this.base.$insertRight = true; + this.completions = new FilteredList(options.matches); + return this.openPopup(this.editor, "", keepPopupPosition); + } var _id = this.gatherCompletionsId; this.gatherCompletions(this.editor, function(err, results) { var detachIfFinished = function() { if (!results.finished) return; return this.detach(); @@ -1588,11 +1697,11 @@ this.editor.completers.some(function(completer) { if (completer.getDocTooltip) doc = completer.getDocTooltip(selected); return doc; }); - if (!doc) + if (!doc && typeof selected != "string") doc = selected; if (typeof doc == "string") doc = {docText: doc}; if (!doc || !(doc.docHTML || doc.docText)) @@ -1670,21 +1779,51 @@ } a = a.parentNode; } }; + this.destroy = function() { + this.detach(); + if (this.popup) { + this.popup.destroy(); + var el = this.popup.container; + if (el && el.parentNode) + el.parentNode.removeChild(el); + } + if (this.editor && this.editor.completer == this) + this.editor.completer == null; + this.popup = null; + }; + }).call(Autocomplete.prototype); + +Autocomplete.for = function(editor) { + if (editor.completer) { + return editor.completer; + } + if (config.get("sharedPopups")) { + if (!Autocomplete.$shared) + Autocomplete.$sharedInstance = new Autocomplete(); + editor.completer = Autocomplete.$sharedInstance; + } else { + editor.completer = new Autocomplete(); + editor.once("destroy", function(e, editor) { + editor.completer.destroy(); + }); + } + return editor.completer; +}; + 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(); + exec: function(editor, options) { + var completer = Autocomplete.for(editor); + completer.autoInsert = false; + completer.autoSelect = true; + completer.showPopup(editor, options); + completer.cancelContextMenu(); }, bindKey: "Ctrl-Space|Ctrl-Shift-Space|Alt-Space" }; var FilteredList = function(array, filterText) { @@ -1702,11 +1841,11 @@ this.filterText = str; matches = this.filterCompletions(matches, this.filterText); matches = matches.sort(function(a, b) { return b.exactMatch - a.exactMatch || b.$score - a.$score - || (a.caption || a.value) < (b.caption || b.value); + || (a.caption || a.value).localeCompare(b.caption || b.value); }); var prev = null; matches = matches.filter(function(item){ var caption = item.snippet || item.caption || item.value; if (caption === prev) return false; @@ -1932,14 +2071,12 @@ 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 completer = Autocomplete.for(editor); + completer.autoInsert = false; + completer.showPopup(editor); } } }; var Editor = require("../editor").Editor; \ No newline at end of file