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

Commit 35ba389

Browse files
authored
Use "frequently used emojis" for autocompletion in composer (#8998)
Co-authored-by: grimhilt <[email protected]>
1 parent 9edd498 commit 35ba389

File tree

2 files changed

+38
-3
lines changed

2 files changed

+38
-3
lines changed

src/autocomplete/EmojiProvider.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ import QueryMatcher from './QueryMatcher';
2929
import { PillCompletion } from './Components';
3030
import { ICompletion, ISelectionRange } from './Autocompleter';
3131
import SettingsStore from "../settings/SettingsStore";
32-
import { EMOJI, IEmoji } from '../emoji';
32+
import { EMOJI, IEmoji, getEmojiFromUnicode } from '../emoji';
3333
import { TimelineRenderingType } from '../contexts/RoomContext';
34+
import * as recent from '../emojipicker/recent';
3435

3536
const LIMIT = 20;
3637

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

7779
constructor(room: Room, renderingType?: TimelineRenderingType) {
7880
super({ commandRegex: EMOJI_REGEX, renderingType });
@@ -87,6 +89,8 @@ export default class EmojiProvider extends AutocompleteProvider {
8789
// For removing punctuation
8890
shouldMatchWordsOnly: true,
8991
});
92+
93+
this.recentlyUsed = Array.from(new Set(recent.get().map(getEmojiFromUnicode).filter(Boolean)));
9094
}
9195

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

112-
const sorters = [];
116+
let sorters = [];
113117
// make sure that emoticons come first
114118
sorters.push(c => score(matchedString, c.emoji.emoticon || ""));
115119

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

137+
completions = completions.slice(0, LIMIT);
138+
139+
// Do a second sort to place emoji matching with frequently used one on top
140+
sorters = [];
141+
this.recentlyUsed.forEach(emoji => {
142+
sorters.push(c => score(emoji.shortcodes[0], c.emoji.shortcodes[0]));
143+
});
144+
completions = sortBy(uniq(completions), sorters);
145+
133146
completions = completions.map(c => ({
134147
completion: c.emoji.unicode,
135148
component: (
@@ -138,7 +151,7 @@ export default class EmojiProvider extends AutocompleteProvider {
138151
</PillCompletion>
139152
),
140153
range,
141-
})).slice(0, LIMIT);
154+
}));
142155
}
143156
return completions;
144157
}

test/autocomplete/EmojiProvider-test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ limitations under the License.
1616

1717
import EmojiProvider from '../../src/autocomplete/EmojiProvider';
1818
import { mkStubRoom } from '../test-utils/test-utils';
19+
import { add } from "../../src/emojipicker/recent";
20+
import { stubClient } from "../test-utils";
21+
import { MatrixClientPeg } from '../../src/MatrixClientPeg';
1922

2023
const EMOJI_SHORTCODES = [
2124
":+1",
@@ -42,6 +45,8 @@ const TOO_SHORT_EMOJI_SHORTCODE = [
4245

4346
describe('EmojiProvider', function() {
4447
const testRoom = mkStubRoom(undefined, undefined, undefined);
48+
stubClient();
49+
MatrixClientPeg.get();
4550

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

6570
expect(completions[0].completion).toEqual(expectedEmoji);
6671
});
72+
73+
it('Returns correct autocompletion based on recently used emoji', async function() {
74+
add("😘"); //kissing_heart
75+
add("😘");
76+
add("😚"); //kissing_closed_eyes
77+
const emojiProvider = new EmojiProvider(null);
78+
79+
let completionsList = await emojiProvider.getCompletions(":kis", { beginning: true, end: 3, start: 3 });
80+
expect(completionsList[0].component.props.title).toEqual(":kissing_heart:");
81+
expect(completionsList[1].component.props.title).toEqual(":kissing_closed_eyes:");
82+
83+
completionsList = await emojiProvider.getCompletions(":kissing_c", { beginning: true, end: 3, start: 3 });
84+
expect(completionsList[0].component.props.title).toEqual(":kissing_closed_eyes:");
85+
86+
completionsList = await emojiProvider.getCompletions(":so", { beginning: true, end: 2, start: 2 });
87+
expect(completionsList[0].component.props.title).toEqual(":sob:");
88+
});
6789
});

0 commit comments

Comments
 (0)