Fix rerender on text insertion
This commit is contained in:
parent
cd19233b31
commit
b811f1dc3f
4 changed files with 167 additions and 115 deletions
|
|
@ -163,6 +163,8 @@ var Autocomplete = function() {
|
|||
|
||||
el.style.left = pos.left + "px";
|
||||
el.style.display = "";
|
||||
|
||||
renderer.updateText();
|
||||
};
|
||||
|
||||
this.detach = function() {
|
||||
|
|
@ -173,10 +175,15 @@ var Autocomplete = function() {
|
|||
|
||||
if (this.popup)
|
||||
this.popup.container.style.display = "none";
|
||||
|
||||
this.editor.Autocomplete.activated = false;
|
||||
};
|
||||
|
||||
this.changeListener = function(e) {
|
||||
//console.log(e)
|
||||
if (this.editor.Autocomplete.activated)
|
||||
Autocomplete.startCommand.exec(this.editor);
|
||||
else
|
||||
this.detach();
|
||||
};
|
||||
|
||||
this.blurListener = function() {
|
||||
|
|
@ -215,6 +222,8 @@ var Autocomplete = function() {
|
|||
};
|
||||
|
||||
this.insertMatch = function(row) {
|
||||
this.detach();
|
||||
|
||||
if (row == undefined)
|
||||
row = this.popup.getRow();
|
||||
var text = this.completions.filtered[row];
|
||||
|
|
@ -224,7 +233,6 @@ var Autocomplete = function() {
|
|||
// should be good enough, otherwise we can use getDocument().removeInLine
|
||||
this.editor.removeWordLeft();
|
||||
this.editor.insert(text);
|
||||
this.detach();
|
||||
};
|
||||
|
||||
this.commands = {
|
||||
|
|
@ -237,16 +245,7 @@ var Autocomplete = function() {
|
|||
"space": function(editor) { editor.Autocomplete.detach(); editor.insert(" ");},
|
||||
"Return": function(editor) { editor.Autocomplete.insertMatch(); },
|
||||
"Shift-Return": function(editor) { editor.Autocomplete.insertMatch(true); },
|
||||
"Tab": function(editor) { editor.Autocomplete.insertMatch(); },
|
||||
"backspace": function(editor) {
|
||||
var doc = editor.session.getDocument(),
|
||||
cursor = editor.getCursorPosition();
|
||||
|
||||
editor.Autocomplete.detach();
|
||||
// delete one char, and reevaluate
|
||||
editor.remove("left");
|
||||
editor.Autocomplete.complete(editor);
|
||||
}
|
||||
"Tab": function(editor) { editor.Autocomplete.insertMatch(); }
|
||||
};
|
||||
|
||||
this.complete = function(editor) {
|
||||
|
|
@ -266,15 +265,19 @@ var Autocomplete = function() {
|
|||
editor.on("blur", this.$blurListener);
|
||||
editor.on("mousedown", this.$mousedownListener);
|
||||
|
||||
worker.attachToDocument(editor.session.getDocument(), {cursor: editor.getCursorPosition(), keywords: editor.session.getMode().getKeywords(true)}, true);
|
||||
worker.attachToDocument(editor.session.getDocument(), {cursor: editor.getCursorPosition(), keywords: editor.session.getMode().getKeywords()}, true);
|
||||
|
||||
worker.on("complete", function(data) {
|
||||
var matches = data.data.matches;
|
||||
_self.completions = new FilteredList(matches);
|
||||
_self.completions.setFilter("a");
|
||||
|
||||
if (matches.length) {
|
||||
_self.openPopup(editor); }
|
||||
_self.completions = new FilteredList(matches);
|
||||
_self.completions.setFilter("a");
|
||||
_self.openPopup(editor);
|
||||
}
|
||||
else {
|
||||
_self.detach();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -377,6 +380,7 @@ Autocomplete.startCommand = {
|
|||
if (!editor.Autocomplete)
|
||||
editor.Autocomplete = new Autocomplete();
|
||||
editor.Autocomplete.complete(editor);
|
||||
editor.Autocomplete.activated = true;
|
||||
},
|
||||
bindKey: "Ctrl-Space|Shift-Space|Alt-Space"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,29 +45,6 @@ var AutocompleteWorker = exports.AutocompleteWorker = function(sender) {
|
|||
oop.inherits(AutocompleteWorker, Mirror);
|
||||
|
||||
(function() {
|
||||
// For code completion
|
||||
function removeDuplicateMatches(matches) {
|
||||
// First sort
|
||||
matches.sort(function(a, b) {
|
||||
if (a.name < b.name)
|
||||
return 1;
|
||||
else if (a.name > b.name)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
});
|
||||
|
||||
for(var i = 1; i < matches.length; ){
|
||||
if (matches[i - 1] == matches[i]){
|
||||
matches.splice(i, 1);
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
};
|
||||
|
||||
this.onUpdate = function() {
|
||||
var _self = this;
|
||||
|
||||
|
|
@ -75,43 +52,25 @@ oop.inherits(AutocompleteWorker, Mirror);
|
|||
var pos = this.data.cursor;
|
||||
|
||||
var currentPos = { line: pos.row, col: pos.column };
|
||||
var matches = [];
|
||||
|
||||
completer.complete(_self.doc, this.data.cursor, this.data.keywords, function(identifier, completions) {
|
||||
if (completions)
|
||||
matches = matches.concat(completions);
|
||||
removeDuplicateMatches(matches);
|
||||
// Sort by priority, score
|
||||
matches.sort(function(a, b) {
|
||||
if (a.priority < b.priority)
|
||||
return 1;
|
||||
else if (a.priority > b.priority)
|
||||
return -1;
|
||||
else if (a.score < b.score)
|
||||
return 1;
|
||||
else if (a.score > b.score)
|
||||
return -1;
|
||||
else if (a.id && a.id === b.id) {
|
||||
if (a.isFunction)
|
||||
return -1;
|
||||
else if (b.isFunction)
|
||||
return 1;
|
||||
}
|
||||
if (a.name < b.name)
|
||||
return -1;
|
||||
else if(a.name > b.name)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
});
|
||||
_self.sender.emit("complete", {
|
||||
startRow: pos.row,
|
||||
startColumn: pos.column - identifier.length,
|
||||
endRow: pos.row,
|
||||
endColumn: Infinity,
|
||||
matches: matches,
|
||||
line: _self.doc.getLine(pos.row)
|
||||
});
|
||||
if (!identifier) {
|
||||
_self.sender.emit("complete", {
|
||||
matches: []
|
||||
});
|
||||
}
|
||||
|
||||
else {
|
||||
_self.sender.emit("complete", {
|
||||
startRow: pos.row,
|
||||
startColumn: pos.column - identifier.length,
|
||||
endRow: pos.row,
|
||||
endColumn: Infinity,
|
||||
matches: completions,
|
||||
line: _self.doc.getLine(pos.row)
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,33 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2012, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var ID_REGEX = /[a-zA-Z_0-9\$]/;
|
||||
|
|
@ -26,36 +56,71 @@ function retrieveFollowingIdentifier(text, pos, regex) {
|
|||
return buf;
|
||||
}
|
||||
|
||||
function prefixBinarySearch(items, prefix) {
|
||||
var startIndex = 0;
|
||||
var stopIndex = items.length - 1;
|
||||
var middle = Math.floor((stopIndex + startIndex) / 2);
|
||||
|
||||
while (stopIndex > startIndex && middle >= 0 && items[middle].indexOf(prefix) !== 0) {
|
||||
if (prefix < items[middle]) {
|
||||
stopIndex = middle - 1;
|
||||
}
|
||||
else if (prefix > items[middle]) {
|
||||
startIndex = middle + 1;
|
||||
}
|
||||
middle = Math.floor((stopIndex + stopIndex) / 2);
|
||||
}
|
||||
|
||||
// Look back to make sure we haven't skipped any
|
||||
while (middle > 0 && items[middle-1].indexOf(prefix) === 0)
|
||||
middle--;
|
||||
return middle >= 0 ? middle : 0; // ensure we're not returning a negative index
|
||||
}
|
||||
// filched from jQuery
|
||||
function grep( elems, callback, inv ) {
|
||||
var retVal,
|
||||
ret = [],
|
||||
i = 0,
|
||||
length = elems.length;
|
||||
inv = !!inv;
|
||||
|
||||
// Go through the array, only saving the items
|
||||
// that pass the validator function
|
||||
for ( ; i < length; i++ ) {
|
||||
retVal = !!callback( elems[ i ], i );
|
||||
if ( inv !== retVal ) {
|
||||
ret.push( elems[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
function sortByScore(items, identDict) {
|
||||
|
||||
return items.sort(function(a, b) {
|
||||
var scoreA = identDict[a],
|
||||
scoreB = identDict[b];
|
||||
|
||||
if (a < b)
|
||||
return 1;
|
||||
else if (a > b)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
});
|
||||
};
|
||||
|
||||
function findCompletions(prefix, identDict, allIdentifiers) {
|
||||
var _self = this,
|
||||
fuzzyMatcher = function (prefix, item) {
|
||||
return ~item.toLowerCase().indexOf(prefix.toLowerCase());
|
||||
};
|
||||
|
||||
var matches = grep(allIdentifiers, function (item) {
|
||||
return fuzzyMatcher(prefix, item);
|
||||
});
|
||||
|
||||
matches = sortByScore(matches, identDict);
|
||||
|
||||
function findCompletions(prefix, allIdentifiers) {
|
||||
allIdentifiers.sort();
|
||||
var startIdx = prefixBinarySearch(allIdentifiers, prefix);
|
||||
var matches = [];
|
||||
for (var i = startIdx; i < allIdentifiers.length && allIdentifiers[i].indexOf(prefix) === 0; i++)
|
||||
matches.push(allIdentifiers[i]);
|
||||
return matches;
|
||||
}
|
||||
|
||||
exports.removeDuplicateWords = function(matches) {
|
||||
// First, sort
|
||||
matches = matches.sort();
|
||||
|
||||
for (var i = 1; i < matches.length; ){
|
||||
if (matches[i - 1] == matches[i]){
|
||||
matches.splice(i, 1);
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
};
|
||||
|
||||
exports.retrievePrecedingIdentifier = retrievePrecedingIdentifier;
|
||||
exports.retrieveFollowingIdentifier = retrieveFollowingIdentifier;
|
||||
exports.findCompletions = findCompletions;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,33 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2012, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
var completeUtil = require("./complete_util");
|
||||
var SPLIT_REGEX = /[^a-zA-Z_0-9\$]+/;
|
||||
|
|
@ -10,7 +40,7 @@ define(function(require, exports, module) {
|
|||
var text = doc.getValue().trim();
|
||||
|
||||
// Determine cursor's word index
|
||||
var textBefore = doc.getLines(0, pos.row-1).join("\n") + "\n";
|
||||
var textBefore = doc.getLines(0, pos.row - 1).join("\n") + "\n";
|
||||
var currentLine = doc.getLine(pos.row);
|
||||
textBefore += currentLine.substr(0, pos.column);
|
||||
var prefixPosition = textBefore.trim().split(SPLIT_REGEX).length - 1;
|
||||
|
|
@ -27,11 +57,11 @@ define(function(require, exports, module) {
|
|||
if (ident.length === 0)
|
||||
continue;
|
||||
var distance = Math.max(prefixPosition, i) - Math.min(prefixPosition, i);
|
||||
// Score substracted from 100000 to force descending ordering
|
||||
// Score substracted from MAX to force descending ordering
|
||||
if (Object.prototype.hasOwnProperty.call(identDict, ident))
|
||||
identDict[ident] = Math.max(MAX_SCORE-distance, identDict[ident]);
|
||||
identDict[ident] = Math.max(MAX_SCORE - distance, identDict[ident]);
|
||||
else
|
||||
identDict[ident] = MAX_SCORE-distance;
|
||||
identDict[ident] = MAX_SCORE - distance;
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -42,14 +72,6 @@ define(function(require, exports, module) {
|
|||
return identDict;
|
||||
}
|
||||
|
||||
function analyze(doc, pos, keywords) {
|
||||
var line = doc.getLine(pos.row);
|
||||
var identifier = completeUtil.retrievePrecedingIdentifier(line, pos.column);
|
||||
|
||||
var analysisCache = wordDistanceAnalyzer(doc, pos, identifier, keywords);
|
||||
return analysisCache;
|
||||
}
|
||||
|
||||
completer.complete = function(doc, pos, keywords, callback) {
|
||||
var line = doc.getLine(pos.row);
|
||||
var identifier = completeUtil.retrievePrecedingIdentifier(line, pos.column);
|
||||
|
|
@ -58,15 +80,17 @@ define(function(require, exports, module) {
|
|||
if (identifier === "")
|
||||
return callback(null);
|
||||
|
||||
var identDict = analyze(doc, pos, keywords);
|
||||
var identDict = wordDistanceAnalyzer(doc, pos, identifier, keywords);
|
||||
|
||||
var allIdentifiers = [];
|
||||
for (var ident in identDict) {
|
||||
allIdentifiers.push(ident);
|
||||
}
|
||||
|
||||
// find matches based on text in doc
|
||||
var matches = completeUtil.findCompletions(identifier, allIdentifiers);
|
||||
allIdentifiers = completeUtil.removeDuplicateWords(allIdentifiers);
|
||||
|
||||
// find fuzzy matches based on text in doc, as well as mode keywords
|
||||
var matches = completeUtil.findCompletions(identifier, identDict, allIdentifiers);
|
||||
|
||||
callback(identifier, matches);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue