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.left = pos.left + "px";
|
||||||
el.style.display = "";
|
el.style.display = "";
|
||||||
|
|
||||||
|
renderer.updateText();
|
||||||
};
|
};
|
||||||
|
|
||||||
this.detach = function() {
|
this.detach = function() {
|
||||||
|
|
@ -173,10 +175,15 @@ var Autocomplete = function() {
|
||||||
|
|
||||||
if (this.popup)
|
if (this.popup)
|
||||||
this.popup.container.style.display = "none";
|
this.popup.container.style.display = "none";
|
||||||
|
|
||||||
|
this.editor.Autocomplete.activated = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.changeListener = function(e) {
|
this.changeListener = function(e) {
|
||||||
//console.log(e)
|
if (this.editor.Autocomplete.activated)
|
||||||
|
Autocomplete.startCommand.exec(this.editor);
|
||||||
|
else
|
||||||
|
this.detach();
|
||||||
};
|
};
|
||||||
|
|
||||||
this.blurListener = function() {
|
this.blurListener = function() {
|
||||||
|
|
@ -215,6 +222,8 @@ var Autocomplete = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.insertMatch = function(row) {
|
this.insertMatch = function(row) {
|
||||||
|
this.detach();
|
||||||
|
|
||||||
if (row == undefined)
|
if (row == undefined)
|
||||||
row = this.popup.getRow();
|
row = this.popup.getRow();
|
||||||
var text = this.completions.filtered[row];
|
var text = this.completions.filtered[row];
|
||||||
|
|
@ -224,7 +233,6 @@ var Autocomplete = function() {
|
||||||
// should be good enough, otherwise we can use getDocument().removeInLine
|
// should be good enough, otherwise we can use getDocument().removeInLine
|
||||||
this.editor.removeWordLeft();
|
this.editor.removeWordLeft();
|
||||||
this.editor.insert(text);
|
this.editor.insert(text);
|
||||||
this.detach();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.commands = {
|
this.commands = {
|
||||||
|
|
@ -237,16 +245,7 @@ var Autocomplete = function() {
|
||||||
"space": function(editor) { editor.Autocomplete.detach(); editor.insert(" ");},
|
"space": function(editor) { editor.Autocomplete.detach(); editor.insert(" ");},
|
||||||
"Return": function(editor) { editor.Autocomplete.insertMatch(); },
|
"Return": function(editor) { editor.Autocomplete.insertMatch(); },
|
||||||
"Shift-Return": function(editor) { editor.Autocomplete.insertMatch(true); },
|
"Shift-Return": function(editor) { editor.Autocomplete.insertMatch(true); },
|
||||||
"Tab": function(editor) { editor.Autocomplete.insertMatch(); },
|
"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);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.complete = function(editor) {
|
this.complete = function(editor) {
|
||||||
|
|
@ -266,15 +265,19 @@ var Autocomplete = function() {
|
||||||
editor.on("blur", this.$blurListener);
|
editor.on("blur", this.$blurListener);
|
||||||
editor.on("mousedown", this.$mousedownListener);
|
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) {
|
worker.on("complete", function(data) {
|
||||||
var matches = data.data.matches;
|
var matches = data.data.matches;
|
||||||
_self.completions = new FilteredList(matches);
|
|
||||||
_self.completions.setFilter("a");
|
|
||||||
|
|
||||||
if (matches.length) {
|
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)
|
if (!editor.Autocomplete)
|
||||||
editor.Autocomplete = new Autocomplete();
|
editor.Autocomplete = new Autocomplete();
|
||||||
editor.Autocomplete.complete(editor);
|
editor.Autocomplete.complete(editor);
|
||||||
|
editor.Autocomplete.activated = true;
|
||||||
},
|
},
|
||||||
bindKey: "Ctrl-Space|Shift-Space|Alt-Space"
|
bindKey: "Ctrl-Space|Shift-Space|Alt-Space"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,29 +45,6 @@ var AutocompleteWorker = exports.AutocompleteWorker = function(sender) {
|
||||||
oop.inherits(AutocompleteWorker, Mirror);
|
oop.inherits(AutocompleteWorker, Mirror);
|
||||||
|
|
||||||
(function() {
|
(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() {
|
this.onUpdate = function() {
|
||||||
var _self = this;
|
var _self = this;
|
||||||
|
|
||||||
|
|
@ -75,43 +52,25 @@ oop.inherits(AutocompleteWorker, Mirror);
|
||||||
var pos = this.data.cursor;
|
var pos = this.data.cursor;
|
||||||
|
|
||||||
var currentPos = { line: pos.row, col: pos.column };
|
var currentPos = { line: pos.row, col: pos.column };
|
||||||
var matches = [];
|
|
||||||
|
|
||||||
completer.complete(_self.doc, this.data.cursor, this.data.keywords, function(identifier, completions) {
|
completer.complete(_self.doc, this.data.cursor, this.data.keywords, function(identifier, completions) {
|
||||||
if (completions)
|
if (!identifier) {
|
||||||
matches = matches.concat(completions);
|
_self.sender.emit("complete", {
|
||||||
removeDuplicateMatches(matches);
|
matches: []
|
||||||
// Sort by priority, score
|
});
|
||||||
matches.sort(function(a, b) {
|
}
|
||||||
if (a.priority < b.priority)
|
|
||||||
return 1;
|
else {
|
||||||
else if (a.priority > b.priority)
|
_self.sender.emit("complete", {
|
||||||
return -1;
|
startRow: pos.row,
|
||||||
else if (a.score < b.score)
|
startColumn: pos.column - identifier.length,
|
||||||
return 1;
|
endRow: pos.row,
|
||||||
else if (a.score > b.score)
|
endColumn: Infinity,
|
||||||
return -1;
|
matches: completions,
|
||||||
else if (a.id && a.id === b.id) {
|
line: _self.doc.getLine(pos.row)
|
||||||
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)
|
|
||||||
});
|
|
||||||
return;
|
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) {
|
define(function(require, exports, module) {
|
||||||
|
|
||||||
var ID_REGEX = /[a-zA-Z_0-9\$]/;
|
var ID_REGEX = /[a-zA-Z_0-9\$]/;
|
||||||
|
|
@ -26,36 +56,71 @@ function retrieveFollowingIdentifier(text, pos, regex) {
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
function prefixBinarySearch(items, prefix) {
|
// filched from jQuery
|
||||||
var startIndex = 0;
|
function grep( elems, callback, inv ) {
|
||||||
var stopIndex = items.length - 1;
|
var retVal,
|
||||||
var middle = Math.floor((stopIndex + startIndex) / 2);
|
ret = [],
|
||||||
|
i = 0,
|
||||||
while (stopIndex > startIndex && middle >= 0 && items[middle].indexOf(prefix) !== 0) {
|
length = elems.length;
|
||||||
if (prefix < items[middle]) {
|
inv = !!inv;
|
||||||
stopIndex = middle - 1;
|
|
||||||
}
|
// Go through the array, only saving the items
|
||||||
else if (prefix > items[middle]) {
|
// that pass the validator function
|
||||||
startIndex = middle + 1;
|
for ( ; i < length; i++ ) {
|
||||||
}
|
retVal = !!callback( elems[ i ], i );
|
||||||
middle = Math.floor((stopIndex + stopIndex) / 2);
|
if ( inv !== retVal ) {
|
||||||
}
|
ret.push( elems[ i ] );
|
||||||
|
}
|
||||||
// Look back to make sure we haven't skipped any
|
}
|
||||||
while (middle > 0 && items[middle-1].indexOf(prefix) === 0)
|
|
||||||
middle--;
|
return ret;
|
||||||
return middle >= 0 ? middle : 0; // ensure we're not returning a negative index
|
};
|
||||||
}
|
|
||||||
|
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;
|
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.retrievePrecedingIdentifier = retrievePrecedingIdentifier;
|
||||||
exports.retrieveFollowingIdentifier = retrieveFollowingIdentifier;
|
exports.retrieveFollowingIdentifier = retrieveFollowingIdentifier;
|
||||||
exports.findCompletions = findCompletions;
|
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) {
|
define(function(require, exports, module) {
|
||||||
var completeUtil = require("./complete_util");
|
var completeUtil = require("./complete_util");
|
||||||
var SPLIT_REGEX = /[^a-zA-Z_0-9\$]+/;
|
var SPLIT_REGEX = /[^a-zA-Z_0-9\$]+/;
|
||||||
|
|
@ -10,7 +40,7 @@ define(function(require, exports, module) {
|
||||||
var text = doc.getValue().trim();
|
var text = doc.getValue().trim();
|
||||||
|
|
||||||
// Determine cursor's word index
|
// 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);
|
var currentLine = doc.getLine(pos.row);
|
||||||
textBefore += currentLine.substr(0, pos.column);
|
textBefore += currentLine.substr(0, pos.column);
|
||||||
var prefixPosition = textBefore.trim().split(SPLIT_REGEX).length - 1;
|
var prefixPosition = textBefore.trim().split(SPLIT_REGEX).length - 1;
|
||||||
|
|
@ -27,11 +57,11 @@ define(function(require, exports, module) {
|
||||||
if (ident.length === 0)
|
if (ident.length === 0)
|
||||||
continue;
|
continue;
|
||||||
var distance = Math.max(prefixPosition, i) - Math.min(prefixPosition, i);
|
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))
|
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
|
else
|
||||||
identDict[ident] = MAX_SCORE-distance;
|
identDict[ident] = MAX_SCORE - distance;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,14 +72,6 @@ define(function(require, exports, module) {
|
||||||
return identDict;
|
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) {
|
completer.complete = function(doc, pos, keywords, callback) {
|
||||||
var line = doc.getLine(pos.row);
|
var line = doc.getLine(pos.row);
|
||||||
var identifier = completeUtil.retrievePrecedingIdentifier(line, pos.column);
|
var identifier = completeUtil.retrievePrecedingIdentifier(line, pos.column);
|
||||||
|
|
@ -58,15 +80,17 @@ define(function(require, exports, module) {
|
||||||
if (identifier === "")
|
if (identifier === "")
|
||||||
return callback(null);
|
return callback(null);
|
||||||
|
|
||||||
var identDict = analyze(doc, pos, keywords);
|
var identDict = wordDistanceAnalyzer(doc, pos, identifier, keywords);
|
||||||
|
|
||||||
var allIdentifiers = [];
|
var allIdentifiers = [];
|
||||||
for (var ident in identDict) {
|
for (var ident in identDict) {
|
||||||
allIdentifiers.push(ident);
|
allIdentifiers.push(ident);
|
||||||
}
|
}
|
||||||
|
|
||||||
// find matches based on text in doc
|
allIdentifiers = completeUtil.removeDuplicateWords(allIdentifiers);
|
||||||
var matches = completeUtil.findCompletions(identifier, allIdentifiers);
|
|
||||||
|
// find fuzzy matches based on text in doc, as well as mode keywords
|
||||||
|
var matches = completeUtil.findCompletions(identifier, identDict, allIdentifiers);
|
||||||
|
|
||||||
callback(identifier, matches);
|
callback(identifier, matches);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue