fix(app): preserve shadowed command owners (#39044)

This commit is contained in:
Brendan Allan
2026-07-27 11:45:18 +08:00
committed by GitHub
parent de78da8a23
commit 09afffeead
2 changed files with 36 additions and 12 deletions
+22 -7
View File
@@ -1,5 +1,11 @@
import { describe, expect, test } from "bun:test" import { describe, expect, test } from "bun:test"
import { commandPaletteOptions, resolveKeybindOption, upsertCommandRegistration, type CommandOption } from "./command" import {
activeCommandRegistrations,
addCommandRegistration,
commandPaletteOptions,
resolveKeybindOption,
type CommandOption,
} from "./command"
const paletteOptions: CommandOption[] = [ const paletteOptions: CommandOption[] = [
{ id: "settings.open", title: "Open settings" }, { id: "settings.open", title: "Open settings" },
@@ -15,22 +21,31 @@ describe("commandPaletteOptions", () => {
}) })
}) })
describe("upsertCommandRegistration", () => { describe("command registrations", () => {
test("replaces keyed registrations", () => { test("shadows keyed registrations while retaining the previous owner", () => {
const one = () => [{ id: "one", title: "One" }] const one = () => [{ id: "one", title: "One" }]
const two = () => [{ id: "two", title: "Two" }] const two = () => [{ id: "two", title: "Two" }]
const next = upsertCommandRegistration([{ key: "layout", options: one }], { key: "layout", options: two }) const registrations = addCommandRegistration([{ key: "layout", options: one }], {
key: "layout",
options: two,
})
const active = activeCommandRegistrations(registrations)
expect(next).toHaveLength(1) expect(registrations).toHaveLength(2)
expect(next[0]?.options).toBe(two) expect(active).toHaveLength(1)
expect(active[0]?.options).toBe(two)
const restored = activeCommandRegistrations(registrations.filter((entry) => entry.options !== two))
expect(restored).toHaveLength(1)
expect(restored[0]?.options).toBe(one)
}) })
test("keeps unkeyed registrations additive", () => { test("keeps unkeyed registrations additive", () => {
const one = () => [{ id: "one", title: "One" }] const one = () => [{ id: "one", title: "One" }]
const two = () => [{ id: "two", title: "Two" }] const two = () => [{ id: "two", title: "Two" }]
const next = upsertCommandRegistration([{ options: one }], { options: two }) const next = activeCommandRegistrations(addCommandRegistration([{ options: one }], { options: two }))
expect(next).toHaveLength(2) expect(next).toHaveLength(2)
expect(next[0]?.options).toBe(two) expect(next[0]?.options).toBe(two)
+14 -5
View File
@@ -114,9 +114,18 @@ export type CommandRegistration = {
options: Accessor<CommandOption[]> options: Accessor<CommandOption[]>
} }
export function upsertCommandRegistration(registrations: CommandRegistration[], entry: CommandRegistration) { export function addCommandRegistration(registrations: CommandRegistration[], entry: CommandRegistration) {
if (entry.key === undefined) return [entry, ...registrations] return [entry, ...registrations]
return [entry, ...registrations.filter((x) => x.key !== entry.key)] }
export function activeCommandRegistrations(registrations: CommandRegistration[]) {
const keys = new Set<string>()
return registrations.filter((entry) => {
if (entry.key === undefined) return true
if (keys.has(entry.key)) return false
keys.add(entry.key)
return true
})
} }
export function parseKeybind(config: string): Keybind[] { export function parseKeybind(config: string): Keybind[] {
@@ -281,7 +290,7 @@ export const { use: useCommand, provider: CommandProvider } = createSimpleContex
const seen = new Set<string>() const seen = new Set<string>()
const all: CommandOption[] = [] const all: CommandOption[] = []
for (const reg of store.registrations) { for (const reg of activeCommandRegistrations(store.registrations)) {
for (const opt of reg.options()) { for (const opt of reg.options()) {
if (seen.has(opt.id)) { if (seen.has(opt.id)) {
if (import.meta.env.DEV && !warnedDuplicates.has(opt.id)) { if (import.meta.env.DEV && !warnedDuplicates.has(opt.id)) {
@@ -425,7 +434,7 @@ export const { use: useCommand, provider: CommandProvider } = createSimpleContex
key: id, key: id,
options, options,
} }
setStore("registrations", (arr) => upsertCommandRegistration(arr, entry)) setStore("registrations", (arr) => addCommandRegistration(arr, entry))
onCleanup(() => { onCleanup(() => {
setStore("registrations", (arr) => arr.filter((x) => x !== entry)) setStore("registrations", (arr) => arr.filter((x) => x !== entry))
}) })