Improve emoji and mention matching (#24255)
Prioritize matches that start with the given text, then matches that contain the given text. I wanted to add a heart emoji on a pull request comment so I started writing `:`, `h`, `e`, `a`, `r` (at this point I still couldn't find the heart), `t`... The heart was not on the list, that's weird - it feels like I made a typo or a mistake. This fixes that. This also feels more like GitHub's emoji auto-complete. # Before  # After  --------- Signed-off-by: Yarden Shoham <git@yardenshoham.com> Co-authored-by: silverwind <me@silverwind.io>wip
parent
ce9c1ddc4c
commit
3cc87370c3
@ -0,0 +1,43 @@
|
|||||||
|
import emojis from '../../../assets/emoji.json';
|
||||||
|
|
||||||
|
const maxMatches = 6;
|
||||||
|
|
||||||
|
function sortAndReduce(map) {
|
||||||
|
const sortedMap = new Map([...map.entries()].sort((a, b) => a[1] - b[1]));
|
||||||
|
return Array.from(sortedMap.keys()).slice(0, maxMatches);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function matchEmoji(queryText) {
|
||||||
|
const query = queryText.toLowerCase().replaceAll('_', ' ');
|
||||||
|
if (!query) return emojis.slice(0, maxMatches).map((e) => e.aliases[0]);
|
||||||
|
|
||||||
|
// results is a map of weights, lower is better
|
||||||
|
const results = new Map();
|
||||||
|
for (const {aliases} of emojis) {
|
||||||
|
const mainAlias = aliases[0];
|
||||||
|
for (const [aliasIndex, alias] of aliases.entries()) {
|
||||||
|
const index = alias.replaceAll('_', ' ').indexOf(query);
|
||||||
|
if (index === -1) continue;
|
||||||
|
const existing = results.get(mainAlias);
|
||||||
|
const rankedIndex = index + aliasIndex;
|
||||||
|
results.set(mainAlias, existing ? existing - rankedIndex : rankedIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sortAndReduce(results);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function matchMention(queryText) {
|
||||||
|
const query = queryText.toLowerCase();
|
||||||
|
|
||||||
|
// results is a map of weights, lower is better
|
||||||
|
const results = new Map();
|
||||||
|
for (const obj of window.config.tributeValues) {
|
||||||
|
const index = obj.key.toLowerCase().indexOf(query);
|
||||||
|
if (index === -1) continue;
|
||||||
|
const existing = results.get(obj);
|
||||||
|
results.set(obj, existing ? existing - index : index);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sortAndReduce(results);
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
import {test, expect} from 'vitest';
|
||||||
|
import {matchEmoji, matchMention} from './match.js';
|
||||||
|
|
||||||
|
test('matchEmoji', () => {
|
||||||
|
expect(matchEmoji('')).toEqual([
|
||||||
|
'+1',
|
||||||
|
'-1',
|
||||||
|
'100',
|
||||||
|
'1234',
|
||||||
|
'1st_place_medal',
|
||||||
|
'2nd_place_medal',
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(matchEmoji('hea')).toEqual([
|
||||||
|
'headphones',
|
||||||
|
'headstone',
|
||||||
|
'health_worker',
|
||||||
|
'hear_no_evil',
|
||||||
|
'heard_mcdonald_islands',
|
||||||
|
'heart',
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(matchEmoji('hear')).toEqual([
|
||||||
|
'hear_no_evil',
|
||||||
|
'heard_mcdonald_islands',
|
||||||
|
'heart',
|
||||||
|
'heart_decoration',
|
||||||
|
'heart_eyes',
|
||||||
|
'heart_eyes_cat',
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(matchEmoji('poo')).toEqual([
|
||||||
|
'poodle',
|
||||||
|
'hankey',
|
||||||
|
'spoon',
|
||||||
|
'bowl_with_spoon',
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(matchEmoji('1st_')).toEqual([
|
||||||
|
'1st_place_medal',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('matchMention', () => {
|
||||||
|
expect(matchMention('')).toEqual(window.config.tributeValues.slice(0, 6));
|
||||||
|
expect(matchMention('user4')).toEqual([window.config.tributeValues[3]]);
|
||||||
|
});
|
Loading…
Reference in New Issue