forked from forgejo/forgejo
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>
This commit is contained in:
parent
ce9c1ddc4c
commit
3cc87370c3
4 changed files with 103 additions and 18 deletions
43
web_src/js/utils/match.js
Normal file
43
web_src/js/utils/match.js
Normal file
|
@ -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);
|
||||
}
|
47
web_src/js/utils/match.test.js
Normal file
47
web_src/js/utils/match.test.js
Normal file
|
@ -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…
Add table
Add a link
Reference in a new issue