Skip to content

Commit 1526ae0

Browse files
claudefullstackjam
authored andcommitted
fix(editor): key selected packages by type+name to avoid sync collision
Packages with the same name but different types (e.g. "ghostty" cask vs "ghostty" npm) collided in the selection map, so toggling one would visually toggle both. Switch the map key to "type:name" so each variant is tracked independently.
1 parent f7b3324 commit 1526ae0

2 files changed

Lines changed: 52 additions & 37 deletions

File tree

src/lib/components/ConfigEditor.svelte

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@
5252
let selectedPackages = $state(new Map<string, string>());
5353
let packageDescs = $state(new Map<string, string>());
5454
55+
function pkgKey(name: string, type: string): string {
56+
return `${type}:${name}`;
57+
}
58+
5559
interface MacOSPref {
5660
domain: string;
5761
key: string;
@@ -63,11 +67,10 @@
6367
let expandedPrefCats = $state<Set<string>>(new Set());
6468
6569
const packages = $derived(
66-
Array.from(selectedPackages.entries()).map(([name, type]) => ({
67-
name,
68-
type,
69-
desc: packageDescs.get(name) || '',
70-
}))
70+
Array.from(selectedPackages.entries()).map(([key, type]) => {
71+
const name = key.slice(type.length + 1);
72+
return { name, type, desc: packageDescs.get(key) || '' };
73+
})
7174
);
7275
7376
const sections = [
@@ -139,9 +142,9 @@
139142
const p = PRESET_PACKAGES[preset];
140143
if (!p) return;
141144
const newMap = new Map<string, string>();
142-
for (const pkg of p.cli) newMap.set(pkg, 'formula');
143-
for (const pkg of p.cask) newMap.set(pkg, 'cask');
144-
if (p.npm) for (const pkg of p.npm) newMap.set(pkg, 'npm');
145+
for (const pkg of p.cli) newMap.set(pkgKey(pkg, 'formula'), 'formula');
146+
for (const pkg of p.cask) newMap.set(pkgKey(pkg, 'cask'), 'cask');
147+
if (p.npm) for (const pkg of p.npm) newMap.set(pkgKey(pkg, 'npm'), 'npm');
145148
selectedPackages = newMap;
146149
}
147150
@@ -151,14 +154,15 @@
151154
}
152155
153156
function togglePackage(name: string, type: string, desc: string = '') {
157+
const key = pkgKey(name, type);
154158
const newMap = new Map(selectedPackages);
155159
const newDescs = new Map(packageDescs);
156-
if (newMap.has(name)) {
157-
newMap.delete(name);
158-
newDescs.delete(name);
160+
if (newMap.has(key)) {
161+
newMap.delete(key);
162+
newDescs.delete(key);
159163
} else {
160-
newMap.set(name, type);
161-
if (desc) newDescs.set(name, desc);
164+
newMap.set(key, type);
165+
if (desc) newDescs.set(key, desc);
162166
}
163167
selectedPackages = newMap;
164168
packageDescs = newDescs;
@@ -200,10 +204,12 @@
200204
const descs = new Map<string, string>();
201205
for (const pkg of data.packages) {
202206
if (typeof pkg === 'string') {
203-
map.set(pkg, 'formula');
207+
map.set(pkgKey(pkg, 'formula'), 'formula');
204208
} else {
205-
map.set(pkg.name, pkg.type || 'formula');
206-
if (pkg.desc) descs.set(pkg.name, pkg.desc);
209+
const t = pkg.type || 'formula';
210+
const k = pkgKey(pkg.name, t);
211+
map.set(k, t);
212+
if (pkg.desc) descs.set(k, pkg.desc);
207213
}
208214
}
209215
selectedPackages = map;
@@ -265,10 +271,12 @@
265271
const newDescs = new Map<string, string>();
266272
for (const pkg of savedPkgs) {
267273
if (typeof pkg === 'string') {
268-
newMap.set(pkg, 'formula');
274+
newMap.set(pkgKey(pkg, 'formula'), 'formula');
269275
} else {
270-
newMap.set(pkg.name, pkg.type || 'formula');
271-
if (pkg.desc) newDescs.set(pkg.name, pkg.desc);
276+
const t = pkg.type || 'formula';
277+
const k = pkgKey(pkg.name, t);
278+
newMap.set(k, t);
279+
if (pkg.desc) newDescs.set(k, pkg.desc);
272280
}
273281
}
274282
selectedPackages = newMap;
@@ -293,11 +301,10 @@
293301
return {
294302
...formData,
295303
alias: formData.alias.trim() || null,
296-
packages: Array.from(selectedPackages.entries()).map(([name, type]) => ({
297-
name,
298-
type,
299-
desc: packageDescs.get(name) || '',
300-
})),
304+
packages: Array.from(selectedPackages.entries()).map(([key, type]) => {
305+
const name = key.slice(type.length + 1);
306+
return { name, type, desc: packageDescs.get(key) || '' };
307+
}),
301308
snapshot: updatedSnapshot,
302309
};
303310
}
@@ -316,10 +323,12 @@
316323
const newDescs = new Map<string, string>();
317324
for (const pkg of parsed.packages || []) {
318325
if (typeof pkg === 'string') {
319-
newMap.set(pkg, 'formula');
326+
newMap.set(pkgKey(pkg, 'formula'), 'formula');
320327
} else {
321-
newMap.set(pkg.name, pkg.type || 'formula');
322-
if (pkg.desc) newDescs.set(pkg.name, pkg.desc);
328+
const t = pkg.type || 'formula';
329+
const k = pkgKey(pkg.name, t);
330+
newMap.set(k, t);
331+
if (pkg.desc) newDescs.set(k, pkg.desc);
323332
}
324333
}
325334
selectedPackages = newMap;

src/lib/components/PackageManager.svelte

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
onPresetChange: (preset: string) => void;
2222
} = $props();
2323
24+
function pkgKey(name: string, type: string): string {
25+
return `${type}:${name}`;
26+
}
27+
2428
let searchQuery = $state('');
2529
let searchResults = $state<SearchResult[]>([]);
2630
let searchLoading = $state(false);
@@ -89,11 +93,12 @@
8993
const cli: string[] = [];
9094
const npm: string[] = [];
9195
const taps: string[] = [];
92-
for (const [pkg, type] of selectedPackages) {
93-
if (type === 'cask') apps.push(pkg);
94-
else if (type === 'npm') npm.push(pkg);
95-
else if (type === 'tap') taps.push(pkg);
96-
else cli.push(pkg);
96+
for (const [key, type] of selectedPackages) {
97+
const name = key.slice(type.length + 1);
98+
if (type === 'cask') apps.push(name);
99+
else if (type === 'npm') npm.push(name);
100+
else if (type === 'tap') taps.push(name);
101+
else cli.push(name);
97102
}
98103
return { apps, cli, npm, taps };
99104
});
@@ -128,8 +133,9 @@
128133
}
129134
const caskSet = new Set<string>(data.casks || []);
130135
for (const pkg of data.packages) {
131-
if (!selectedPackages.has(pkg)) {
132-
togglePackage(pkg, caskSet.has(pkg) ? 'cask' : 'formula');
136+
const type = caskSet.has(pkg) ? 'cask' : 'formula';
137+
if (!selectedPackages.has(pkgKey(pkg, type))) {
138+
togglePackage(pkg, type);
133139
}
134140
}
135141
showImport = false;
@@ -185,14 +191,14 @@
185191
<button
186192
type="button"
187193
class="result-item"
188-
class:selected={selectedPackages.has(result.name)}
194+
class:selected={selectedPackages.has(pkgKey(result.name, result.type))}
189195
onclick={() => togglePackage(result.name, result.type, result.desc)}
190196
>
191197
<span
192198
class="result-check"
193-
class:checked={selectedPackages.has(result.name)}
199+
class:checked={selectedPackages.has(pkgKey(result.name, result.type))}
194200
>
195-
{selectedPackages.has(result.name) ? '' : ''}
201+
{selectedPackages.has(pkgKey(result.name, result.type)) ? '' : ''}
196202
</span>
197203
<div class="result-info">
198204
<div class="result-top">

0 commit comments

Comments
 (0)