From e688eca823f805bc24e6210d44c2b5030cb6d26e Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Tue, 4 Jul 2017 13:53:06 +0100 Subject: [PATCH] Improve the sorting applied to the sorting of autocomplete results QueryMatcher: sort results based on the position of the query within the matching value. The closer to the beginning of the word, the higher the result apears. UserProvider: perf improvement (slice early) and refactor onUserSpoke --- src/autocomplete/QueryMatcher.js | 19 +++++++++++++++---- src/autocomplete/UserProvider.js | 15 +++++++++------ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/autocomplete/QueryMatcher.js b/src/autocomplete/QueryMatcher.js index 1b2ee1bc0d..37ea169c29 100644 --- a/src/autocomplete/QueryMatcher.js +++ b/src/autocomplete/QueryMatcher.js @@ -80,13 +80,24 @@ export default class QueryMatcher { if (this.options.shouldMatchWordsOnly) { query = query.replace(/[^\w]/g, ''); } - const results = _sortedUniq(_sortBy(_flatMap(this.keyMap.keys, (key) => { + const results = []; + this.keyMap.keys.forEach((key) => { let resultKey = key.toLowerCase(); if (this.options.shouldMatchWordsOnly) { resultKey = resultKey.replace(/[^\w]/g, ''); } - return resultKey.indexOf(query) !== -1 ? this.keyMap.objectMap[key] : []; - }), (candidate) => this.keyMap.priorityMap.get(candidate))); - return results; + const index = resultKey.indexOf(query); + if (index !== -1) { + results.push({key, index}); + } + }); + + return _sortedUniq(_flatMap(_sortBy(results, (candidate) => { + return candidate.index; + }).map((candidate) => { + // return an array of objects (those given to setObjects) that have the given + // key as a property. + return this.keyMap.objectMap[candidate.key]; + }))); } } diff --git a/src/autocomplete/UserProvider.js b/src/autocomplete/UserProvider.js index 4e0c0f5ea7..b6be106a93 100644 --- a/src/autocomplete/UserProvider.js +++ b/src/autocomplete/UserProvider.js @@ -50,7 +50,7 @@ export default class UserProvider extends AutocompleteProvider { let completions = []; let {command, range} = this.getCurrentCommand(query, selection, force); if (command) { - completions = this.matcher.match(command[0]).map(user => { + completions = this.matcher.match(command[0]).slice(0, 4).map((user) => { let displayName = (user.name || user.userId || '').replace(' (IRC)', ''); // FIXME when groups are done let completion = displayName; if (range.start === 0) { @@ -68,7 +68,7 @@ export default class UserProvider extends AutocompleteProvider { ), range, }; - }).slice(0, 4); + }); } return completions; } @@ -90,7 +90,9 @@ export default class UserProvider extends AutocompleteProvider { if (member.userId !== currentUserId) return true; }); - this.users = _sortBy(this.users, (user) => 1E20 - lastSpoken[user.userId] || 1E20); + this.users = _sortBy(this.users, (completion) => + 1E20 - lastSpoken[completion.user.userId] || 1E20, + ); this.matcher.setObjects(this.users); } @@ -98,9 +100,10 @@ export default class UserProvider extends AutocompleteProvider { onUserSpoke(user: RoomMember) { if(user.userId === MatrixClientPeg.get().credentials.userId) return; - // Probably unsafe to compare by reference here? - _pull(this.users, user); - this.users.splice(0, 0, user); + this.users = this.users.splice( + this.users.findIndex((user2) => user2.userId === user.userId), 1); + this.users = [user, ...this.users]; + this.matcher.setObjects(this.users); }