added library reordering & prefix rename

This commit is contained in:
olcxja 2026-10-02 14:05:49 +02:00
commit aca9f839e3
13 changed files with 374 additions and 20 deletions

View file

@ -5,6 +5,7 @@ const fsp = fs.promises
const path = require('path')
const { DIRS, readJson, writeJson, toPortablePath, resolvePortablePath } = require('./paths')
const { dedupeDir } = require('./fsutil')
const { normalizeLabel } = require('./names')
const { rewireSymlinks, restoreExecutableBits, EXEC_NAMES } = require('./symlinks')
const WINES_DIR = DIRS.WINES
@ -125,7 +126,14 @@ async function refreshWines() {
}
}
const disabled = new Set(prev.filter(w => w.disabled).map(w => w.id))
for (const w of found) if (disabled.has(w.id)) w.disabled = true
// a display name the user gave the build has to survive every rescan, just
// like the disabled flag (both live in the registry, not in the folder)
const renamed = new Map(prev.filter(w => w.displayName).map(w => [w.id, w.displayName]))
for (const w of found) {
if (disabled.has(w.id)) w.disabled = true
if (renamed.has(w.id)) w.displayName = renamed.get(w.id)
applyDisplayName(w)
}
writeJson(REGISTRY, found.map(wineRel))
return found
}
@ -133,7 +141,7 @@ async function refreshWines() {
// Stored relative to FILES (portable), resolved to absolute for use - same
// scheme as the game registry. `id`, `name`, `label`, `version`, `type` pass through.
function wineAbs(w) {
return { ...w, path: resolvePortablePath(w.path), wineBin: resolvePortablePath(w.wineBin) }
return applyDisplayName({ ...w, path: resolvePortablePath(w.path), wineBin: resolvePortablePath(w.wineBin) })
}
function wineRel(w) {
@ -148,6 +156,29 @@ function getWine(id) {
return getWines().find(w => w.id === id) || null
}
// What the user typed wins over the folder-derived label everywhere the
// build is shown (library config, settings, Open with popup). Every registry
// read goes through here, so a stale stored label can never leak out.
function applyDisplayName(w) {
if (w && w.displayName) w.label = w.displayName
return w
}
// A build keeps its folder and id (apps point at the id, and prefix symlinks
// point inside the folder), so "renaming" only changes the shown label.
function setWineDisplayName(id, name) {
const wines = getWines()
const w = wines.find(x => x.id === id)
if (!w) return { ok: false, error: 'notFound' }
if (w.type === 'system') return { ok: false, error: 'isSystem' }
const clean = normalizeLabel(name)
if (!clean) return { ok: false, error: 'invalidName' }
w.displayName = clean
applyDisplayName(w)
writeJson(REGISTRY, wines.map(wineRel))
return { ok: true, displayName: clean }
}
function setWineDisabled(id, disabled) {
const wines = getWines()
const w = wines.find(x => x.id === id)
@ -273,4 +304,4 @@ async function importWineFolder(srcDir) {
return { ok: true, path: toPortablePath(dst), symlinksFixed: healed.links, executablesFixed: healed.executables }
}
module.exports = { refreshWines, getWines, getWine, resolveWine, setWineDisabled, getDefaultWine, setDefaultWine, deleteWine, importWineFolder, findWineBinary, detectType, fixBuildSymlinks, healBuild }
module.exports = { refreshWines, getWines, getWine, resolveWine, setWineDisabled, setWineDisplayName, getDefaultWine, setDefaultWine, deleteWine, importWineFolder, findWineBinary, detectType, fixBuildSymlinks, healBuild }