Merge pull request #2007 from matrix-org/t3chguy/accent_insensitive_userprovider

accent insensitive autocomplete
pull/21833/head
David Baker 2018-06-25 12:13:20 +01:00 committed by GitHub
commit 7ef4377e57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 20 additions and 18 deletions

View File

@ -1,6 +1,7 @@
//@flow //@flow
/* /*
Copyright 2017 Aviral Dasgupta Copyright 2017 Aviral Dasgupta
Copyright 2018 Michael Telatynski <7t3chguy@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -27,6 +28,10 @@ class KeyMap {
priorityMap = new Map(); priorityMap = new Map();
} }
function stripDiacritics(str: string): string {
return str.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
}
export default class QueryMatcher { export default class QueryMatcher {
/** /**
* @param {object[]} objects the objects to perform a match on * @param {object[]} objects the objects to perform a match on
@ -46,10 +51,11 @@ export default class QueryMatcher {
objects.forEach((object, i) => { objects.forEach((object, i) => {
const keyValues = _at(object, keys); const keyValues = _at(object, keys);
for (const keyValue of keyValues) { for (const keyValue of keyValues) {
if (!map.hasOwnProperty(keyValue)) { const key = stripDiacritics(keyValue).toLowerCase();
map[keyValue] = []; if (!map.hasOwnProperty(key)) {
map[key] = [];
} }
map[keyValue].push(object); map[key].push(object);
} }
keyMap.priorityMap.set(object, i); keyMap.priorityMap.set(object, i);
}); });
@ -82,7 +88,7 @@ export default class QueryMatcher {
} }
match(query: String): Array<Object> { match(query: String): Array<Object> {
query = query.toLowerCase(); query = stripDiacritics(query).toLowerCase();
if (this.options.shouldMatchWordsOnly) { if (this.options.shouldMatchWordsOnly) {
query = query.replace(/[^\w]/g, ''); query = query.replace(/[^\w]/g, '');
} }
@ -91,7 +97,7 @@ export default class QueryMatcher {
} }
const results = []; const results = [];
this.keyMap.keys.forEach((key) => { this.keyMap.keys.forEach((key) => {
let resultKey = key.toLowerCase(); let resultKey = key;
if (this.options.shouldMatchWordsOnly) { if (this.options.shouldMatchWordsOnly) {
resultKey = resultKey.replace(/[^\w]/g, ''); resultKey = resultKey.replace(/[^\w]/g, '');
} }

View File

@ -27,9 +27,9 @@ import FuzzyMatcher from './FuzzyMatcher';
import _sortBy from 'lodash/sortBy'; import _sortBy from 'lodash/sortBy';
import MatrixClientPeg from '../MatrixClientPeg'; import MatrixClientPeg from '../MatrixClientPeg';
import type {Room, RoomMember} from 'matrix-js-sdk'; import type {MatrixEvent, Room, RoomMember, RoomState} from 'matrix-js-sdk';
import {makeUserPermalink} from "../matrix-to"; import {makeUserPermalink} from "../matrix-to";
import type {SelectionRange} from "./Autocompleter"; import type {Completion, SelectionRange} from "./Autocompleter";
const USER_REGEX = /\B@\S*/g; const USER_REGEX = /\B@\S*/g;
@ -45,7 +45,7 @@ export default class UserProvider extends AutocompleteProvider {
this.matcher = new FuzzyMatcher([], { this.matcher = new FuzzyMatcher([], {
keys: ['name', 'userId'], keys: ['name', 'userId'],
shouldMatchPrefix: true, shouldMatchPrefix: true,
shouldMatchWordsOnly: false shouldMatchWordsOnly: false,
}); });
this._onRoomTimelineBound = this._onRoomTimeline.bind(this); this._onRoomTimelineBound = this._onRoomTimeline.bind(this);
@ -62,7 +62,7 @@ export default class UserProvider extends AutocompleteProvider {
} }
} }
_onRoomTimeline(ev, room, toStartOfTimeline, removed, data) { _onRoomTimeline(ev: MatrixEvent, room: Room, toStartOfTimeline: boolean, removed: boolean, data: Object) {
if (!room) return; if (!room) return;
if (removed) return; if (removed) return;
if (room.roomId !== this.room.roomId) return; if (room.roomId !== this.room.roomId) return;
@ -78,7 +78,7 @@ export default class UserProvider extends AutocompleteProvider {
this.onUserSpoke(ev.sender); this.onUserSpoke(ev.sender);
} }
_onRoomStateMember(ev, state, member) { _onRoomStateMember(ev: MatrixEvent, state: RoomState, member: RoomMember) {
// ignore members in other rooms // ignore members in other rooms
if (member.roomId !== this.room.roomId) { if (member.roomId !== this.room.roomId) {
return; return;
@ -88,7 +88,7 @@ export default class UserProvider extends AutocompleteProvider {
this.users = null; this.users = null;
} }
async getCompletions(query: string, selection: SelectionRange, force?: boolean = false) { async getCompletions(query: string, selection: SelectionRange, force?: boolean = false): Array<Completion> {
const MemberAvatar = sdk.getComponent('views.avatars.MemberAvatar'); const MemberAvatar = sdk.getComponent('views.avatars.MemberAvatar');
// Disable autocompletions when composing commands because of various issues // Disable autocompletions when composing commands because of various issues
@ -129,7 +129,7 @@ export default class UserProvider extends AutocompleteProvider {
return completions; return completions;
} }
getName() { getName(): string {
return '👥 ' + _t('Users'); return '👥 ' + _t('Users');
} }
@ -142,13 +142,9 @@ export default class UserProvider extends AutocompleteProvider {
} }
const currentUserId = MatrixClientPeg.get().credentials.userId; const currentUserId = MatrixClientPeg.get().credentials.userId;
this.users = this.room.getJoinedMembers().filter((member) => { this.users = this.room.getJoinedMembers().filter(({userId}) => userId !== currentUserId);
if (member.userId !== currentUserId) return true;
});
this.users = _sortBy(this.users, (member) => this.users = _sortBy(this.users, (member) => 1E20 - lastSpoken[member.userId] || 1E20);
1E20 - lastSpoken[member.userId] || 1E20,
);
this.matcher.setObjects(this.users); this.matcher.setObjects(this.users);
} }