Skip to content
20 changes: 14 additions & 6 deletions src/autocomplete.js
Original file line number Diff line number Diff line change
Expand Up @@ -1029,7 +1029,6 @@ class FilteredList {

filterCompletions(items, needle) {
var results = [];
var upper = needle.toUpperCase();
var lower = needle.toLowerCase();
loop: for (var i = 0, item; item = items[i]; i++) {
var caption = (!this.ignoreCaption && item.caption) || item.value || item.snippet;
Expand All @@ -1043,23 +1042,32 @@ class FilteredList {
if (needle !== caption.substr(0, needle.length))
continue loop;
} else {
var captionLower = caption.toLowerCase();
/**
* It is for situation then, for example, we find some like 'tab' in item.value="Check the table"
* and want to see "Check the TABle" but see "Check The tABle".
*/
var fullMatchIndex = caption.toLowerCase().indexOf(lower);
var fullMatchIndex = captionLower.indexOf(lower);
if (fullMatchIndex > -1) {
penalty = fullMatchIndex;
for (var j = 0; j < needle.length; j++) {
index = fullMatchIndex + j;
// Adding a penalty on case mismatch
if ((lower[j] == needle[j]) != (captionLower[index] == caption[index])) {
penalty += 3;
}
}
} 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;
index = captionLower.indexOf(lower[j], lastIndex + 1);
if (index < 0)
continue loop;
distance = index - lastIndex - 1;
// Adding a penalty on case mismatch
if ((lower[j] == needle[j]) != (captionLower[index] == caption[index])) {
penalty += 3;
}
if (distance > 0) {
// first char mismatch should be more sensitive
if (lastIndex === -1)
Expand Down
43 changes: 43 additions & 0 deletions src/autocomplete_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"use strict";

var sendKey = require("./test/user").type;
var {buildDom} = require("./lib/dom");

Check warning on line 8 in src/autocomplete_test.js

View workflow job for this annotation

GitHub Actions / build (16.x)

'buildDom' is assigned a value but never used
var ace = require("./ace");
var assert = require("./test/assertions");
var user = require("./test/user");
Expand Down Expand Up @@ -1542,6 +1542,49 @@

// Popup should be closed now
assert.equal(completer.popup.isOpen, false);
},
"test: penalty on case mismatch": function (done) {
var editor = initEditor("");
editor.completers = [
{
getCompletions: function (editor, session, pos, prefix, callback) {
var completions = [
{
caption: "array",
value: "array"
}, {
caption: "aRray",
value: "aRray"
}
];
callback(null, completions);
}
}
];

sendKey("R");
var popup = editor.completer.popup;

check(function() {
assert.equal(popup.data.length, 2);
assert.equal(popup.container.querySelector(".ace_selected").textContent.trim(), "aRray");

sendKey("y");

check(function() {
assert.equal(popup.container.querySelector(".ace_selected").textContent.trim(), "aRray");

editor.destroy();
editor.container.remove();
done();
});
});

function check(callback) {
setTimeout(function wait() {
callback();
}, 10);
}
}
};

Expand Down
Loading