diff --git a/lib/ace/autocomplete.js b/lib/ace/autocomplete.js index 2544c858..dd04426e 100644 --- a/lib/ace/autocomplete.js +++ b/lib/ace/autocomplete.js @@ -42,6 +42,7 @@ var snippetManager = require("./snippets").snippetManager; var Autocomplete = function() { this.autoInsert = true; this.autoSelect = true; + this.exactMatch = false; this.keyboardHandler = new HashHandler(); this.keyboardHandler.bindKeys(this.commands); @@ -53,7 +54,7 @@ var Autocomplete = function() { this.changeTimer = lang.delayedCall(function() { this.updateCompletions(true); }.bind(this)); - + this.tooltipTimer = lang.delayedCall(this.updateDocTooltip.bind(this), 50); }; @@ -72,7 +73,7 @@ var Autocomplete = function() { this.popup.on("changeHoverMarker", this.tooltipTimer.bind(null, null)); return this.popup; }; - + this.getPopup = function() { return this.popup || this.$init(); }; @@ -118,7 +119,7 @@ var Autocomplete = function() { this.gatherCompletionsId += 1; this.popup.hide(); } - + if (this.base) this.base.detach(); this.activated = false; @@ -141,7 +142,7 @@ var Autocomplete = function() { // on IE preventDefault doesn't stop scrollbar from being focussed var el = document.activeElement; var text = this.editor.textInput.getElement() - if (el != text && el.parentNode != this.popup.container + if (el != text && el.parentNode != this.popup.container && el != this.tooltipNode && e.relatedTarget != this.tooltipNode && e.relatedTarget != text ) { @@ -227,7 +228,7 @@ var Autocomplete = function() { 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) { @@ -297,7 +298,7 @@ var Autocomplete = function() { var prefix = results.prefix; var matches = results && results.matches; - + if (!matches || !matches.length) return detachIfFinished(); @@ -306,6 +307,10 @@ var Autocomplete = function() { return; this.completions = new FilteredList(matches); + + if (this.exactMatch) + this.completions.exactMatch = true; + this.completions.setFilter(prefix); var filtered = this.completions.filtered; @@ -328,7 +333,7 @@ var Autocomplete = function() { this.cancelContextMenu = function() { this.editor.$mouseHandler.cancelContextMenu(); }; - + this.updateDocTooltip = function() { var popup = this.popup; var all = popup.data; @@ -343,14 +348,14 @@ var Autocomplete = function() { }); 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"); @@ -360,21 +365,21 @@ var Autocomplete = function() { this.tooltipNode.tabIndex = -1; this.tooltipNode.onblur = this.blurListener.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); + 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 = ""; @@ -384,7 +389,7 @@ var Autocomplete = function() { } tooltipNode.style.display = "block"; }; - + this.hideDocTooltip = function() { this.tooltipTimer.cancel(); if (!this.tooltipNode) return; @@ -392,7 +397,7 @@ var Autocomplete = function() { if (!this.editor.isFocused() && document.activeElement == el) this.editor.focus(); this.tooltipNode = null; - if (el.parentNode) + if (el.parentNode) el.parentNode.removeChild(el); }; @@ -403,7 +408,7 @@ Autocomplete.startCommand = { exec: function(editor) { if (!editor.completer) editor.completer = new Autocomplete(); - editor.completer.autoInsert = + editor.completer.autoInsert = editor.completer.autoSelect = true; editor.completer.showPopup(editor); // needed for firefox on mac @@ -416,6 +421,7 @@ var FilteredList = function(array, filterText, mutateData) { this.all = array; this.filtered = array; this.filterText = filterText || ""; + this.exactMatch = false; }; (function(){ this.setFilter = function(str) { @@ -452,23 +458,29 @@ var FilteredList = function(array, filterText, mutateData) { var matchMask = 0; var penalty = 0; var index, distance; - // caption char iteration is faster in Chrome but slower in Firefox, so lets use indexOf - for (var j = 0; j < needle.length; j++) { - // TODO add penalty on case mismatch - 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) + + if (this.exactMatch) { + if (needle !== caption.substr(0, needle.length)) continue loop; - distance = index - lastIndex - 1; - if (distance > 0) { - // first char mismatch should be more sensitive - if (lastIndex === -1) - penalty += 10; - penalty += distance; + }else{ + // caption char iteration is faster in Chrome but slower in Firefox, so lets use indexOf + for (var j = 0; j < needle.length; j++) { + // TODO add penalty on case mismatch + 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) { + // first char mismatch should be more sensitive + if (lastIndex === -1) + penalty += 10; + penalty += distance; + } + matchMask = matchMask | (1 << index); + lastIndex = index; } - matchMask = matchMask | (1 << index); - lastIndex = index; } item.matchMask = matchMask; item.exactMatch = penalty ? 0 : 1;