Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Use "frequently used emojis" for autocompletion in composer (#8998)
Browse files Browse the repository at this point in the history
Co-authored-by: grimhilt <[email protected]>
  • Loading branch information
grimhilt and grimhilt authored Jul 21, 2022
1 parent 9edd498 commit 35ba389
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 3 deletions.
19 changes: 16 additions & 3 deletions src/autocomplete/EmojiProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ import QueryMatcher from './QueryMatcher';
import { PillCompletion } from './Components';
import { ICompletion, ISelectionRange } from './Autocompleter';
import SettingsStore from "../settings/SettingsStore";
import { EMOJI, IEmoji } from '../emoji';
import { EMOJI, IEmoji, getEmojiFromUnicode } from '../emoji';
import { TimelineRenderingType } from '../contexts/RoomContext';
import * as recent from '../emojipicker/recent';

const LIMIT = 20;

Expand Down Expand Up @@ -73,6 +74,7 @@ function colonsTrimmed(str: string): string {
export default class EmojiProvider extends AutocompleteProvider {
matcher: QueryMatcher<ISortedEmoji>;
nameMatcher: QueryMatcher<ISortedEmoji>;
private readonly recentlyUsed: IEmoji[];

constructor(room: Room, renderingType?: TimelineRenderingType) {
super({ commandRegex: EMOJI_REGEX, renderingType });
Expand All @@ -87,6 +89,8 @@ export default class EmojiProvider extends AutocompleteProvider {
// For removing punctuation
shouldMatchWordsOnly: true,
});

this.recentlyUsed = Array.from(new Set(recent.get().map(getEmojiFromUnicode).filter(Boolean)));
}

async getCompletions(
Expand All @@ -109,7 +113,7 @@ export default class EmojiProvider extends AutocompleteProvider {
// Do second match with shouldMatchWordsOnly in order to match against 'name'
completions = completions.concat(this.nameMatcher.match(matchedString));

const sorters = [];
let sorters = [];
// make sure that emoticons come first
sorters.push(c => score(matchedString, c.emoji.emoticon || ""));

Expand All @@ -130,6 +134,15 @@ export default class EmojiProvider extends AutocompleteProvider {
sorters.push(c => c._orderBy);
completions = sortBy(uniq(completions), sorters);

completions = completions.slice(0, LIMIT);

// Do a second sort to place emoji matching with frequently used one on top
sorters = [];
this.recentlyUsed.forEach(emoji => {
sorters.push(c => score(emoji.shortcodes[0], c.emoji.shortcodes[0]));
});
completions = sortBy(uniq(completions), sorters);

completions = completions.map(c => ({
completion: c.emoji.unicode,
component: (
Expand All @@ -138,7 +151,7 @@ export default class EmojiProvider extends AutocompleteProvider {
</PillCompletion>
),
range,
})).slice(0, LIMIT);
}));
}
return completions;
}
Expand Down
22 changes: 22 additions & 0 deletions test/autocomplete/EmojiProvider-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ limitations under the License.

import EmojiProvider from '../../src/autocomplete/EmojiProvider';
import { mkStubRoom } from '../test-utils/test-utils';
import { add } from "../../src/emojipicker/recent";
import { stubClient } from "../test-utils";
import { MatrixClientPeg } from '../../src/MatrixClientPeg';

const EMOJI_SHORTCODES = [
":+1",
Expand All @@ -42,6 +45,8 @@ const TOO_SHORT_EMOJI_SHORTCODE = [

describe('EmojiProvider', function() {
const testRoom = mkStubRoom(undefined, undefined, undefined);
stubClient();
MatrixClientPeg.get();

it.each(EMOJI_SHORTCODES)('Returns consistent results after final colon %s', async function(emojiShortcode) {
const ep = new EmojiProvider(testRoom);
Expand All @@ -64,4 +69,21 @@ describe('EmojiProvider', function() {

expect(completions[0].completion).toEqual(expectedEmoji);
});

it('Returns correct autocompletion based on recently used emoji', async function() {
add("😘"); //kissing_heart
add("😘");
add("😚"); //kissing_closed_eyes
const emojiProvider = new EmojiProvider(null);

let completionsList = await emojiProvider.getCompletions(":kis", { beginning: true, end: 3, start: 3 });
expect(completionsList[0].component.props.title).toEqual(":kissing_heart:");
expect(completionsList[1].component.props.title).toEqual(":kissing_closed_eyes:");

completionsList = await emojiProvider.getCompletions(":kissing_c", { beginning: true, end: 3, start: 3 });
expect(completionsList[0].component.props.title).toEqual(":kissing_closed_eyes:");

completionsList = await emojiProvider.getCompletions(":so", { beginning: true, end: 2, start: 2 });
expect(completionsList[0].component.props.title).toEqual(":sob:");
});
});

0 comments on commit 35ba389

Please sign in to comment.