Skip to content

Commit

Permalink
web: command palette fixes
Browse files Browse the repository at this point in the history
* core: add getIdentifier in fuzzy; this allows the caller to provide a custom indentifier instead of relying on id field in the items list
* fix crashing when hitting enter when no results found
* fix commands list not refreshing when removing recent command
* fix recent command not showing up in the commands list
* fix searched commands showing up under wrong group label

Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
  • Loading branch information
01zulfi committed Feb 25, 2025
1 parent efa73a1 commit 230d6d7
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 8 deletions.
32 changes: 29 additions & 3 deletions apps/web/src/dialogs/command-palette/command-palette-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,9 @@ export const CommandPaletteDialog = DialogManager.register(

const commands = usePromise(async () => {
select(0);
if (!defaultCommands.current)
defaultCommands.current = await getDefaultCommands();
defaultCommands.current = await getDefaultCommands();
const commands = props.isCommandMode
? commandSearch(query, defaultCommands.current)
? sortCommands(commandSearch(query, defaultCommands.current))
: await dbSearch(query);
const groups = commands.reduce(
(acc, command) => {
Expand Down Expand Up @@ -120,6 +119,7 @@ export const CommandPaletteDialog = DialogManager.register(
if (e.key == "Enter") {
e.preventDefault();
const command = commands.value.commands[selected];
if (!command) return;
command.action?.(command, {
openInNewTab: e.ctrlKey || e.metaKey
});
Expand Down Expand Up @@ -350,6 +350,7 @@ function commandSearch(query: string, commands: Command[]) {
return fuzzy(
query,
commands,
(command) => command.id + command.group,
{
title: 10,
group: 5
Expand Down Expand Up @@ -419,6 +420,7 @@ function useDatabaseFuzzySearch() {
for (const item of fuzzy(
query,
items,
(item) => item.id,
{
title: 10
},
Expand Down Expand Up @@ -529,3 +531,27 @@ function getCommandPaletteHelp(isCommandMode: boolean) {
])
];
}

/**
* commands need to be sorted wrt groups,
* meaning commands of same group should be next to each other,
* and recent commands should be at the top
*/
function sortCommands(commands: Command[]) {
const recent: Command[] = [];
const sortedWrtGroups: Command[][] = [];
for (const command of commands) {
const group = command.group;
if (group === "recent") {
recent.push(command);
continue;
}
const index = sortedWrtGroups.findIndex((c) => c[0].group === group);
if (index === -1) {
sortedWrtGroups.push([command]);
} else {
sortedWrtGroups[index].push(command);
}
}
return recent.concat(sortedWrtGroups.flat());
}
4 changes: 3 additions & 1 deletion apps/web/src/dialogs/command-palette/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,9 @@ export async function getDefaultCommands(): Promise<Command[]> {
}

export function getCommandById(id: string): Command | undefined {
return staticCommands.find((command) => command.id === id);
return staticCommands
.concat(getEditorCommands())
.find((command) => command.id === id);
}

export async function resolveRecentCommand(
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/api/lookup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ export default class Lookup {
return fuzzy(
query,
items,
(item) => item.id,
Object.fromEntries(
fields.filter((f) => !f.ignore).map((f) => [f.name, f.weight || 1])
) as Record<keyof T, number>,
Expand Down
6 changes: 5 additions & 1 deletion packages/core/src/utils/__tests__/fuzzy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ describe("lookup.fuzzy", () => {
}
];
const query = "ems";
expect(fuzzy(query, items, { title: 1 })).toStrictEqual([items[2]]);
expect(fuzzy(query, items, (item) => item.id, { title: 1 })).toStrictEqual([
items[2]
]);
});
describe("opts.prefix", () => {
test("should prefix matched field with provided value when given", () => {
Expand All @@ -56,6 +58,7 @@ describe("lookup.fuzzy", () => {
fuzzy(
query,
items,
(item) => item.id,
{ title: 1 },
{
prefix: "prefix-"
Expand All @@ -81,6 +84,7 @@ describe("lookup.fuzzy", () => {
fuzzy(
query,
items,
(item) => item.id,
{ title: 1 },
{
suffix: "-suffix"
Expand Down
9 changes: 6 additions & 3 deletions packages/core/src/utils/fuzzy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { match, surround } from "fuzzyjs";
import { clone } from "./clone";

export function fuzzy<T extends { id: string }>(
export function fuzzy<T>(
query: string,
items: T[],
getIdentifier: (item: T) => string,
fields: Partial<Record<keyof T, number>>,
options: {
limit?: number;
Expand All @@ -41,11 +42,13 @@ export function fuzzy<T extends { id: string }>(
for (const item of items) {
if (options.limit && results.size >= options.limit) break;

const identifier = getIdentifier(item);

for (const field in fields) {
const result = match(query, `${item[field]}`);
if (!result.match) continue;

const oldMatch = results.get(item.id);
const oldMatch = results.get(identifier);
const clonedItem = oldMatch?.item || clone(item);

if (options.suffix || options.prefix) {
Expand All @@ -58,7 +61,7 @@ export function fuzzy<T extends { id: string }>(
if (oldMatch) {
oldMatch.score += result.score * (fields[field] || 1);
} else {
results.set(item.id, {
results.set(identifier, {
item: clonedItem,
score: result.score * (fields[field] || 1)
});
Expand Down

0 comments on commit 230d6d7

Please sign in to comment.