diff options
| -rw-r--r-- | desktop/modules/sbbuilder/README.md | 6 | ||||
| -rw-r--r-- | desktop/modules/sbbuilder/SbbVmModule.qml | 1 | ||||
| -rw-r--r-- | desktop/modules/sbbuilder/Store.qml | 26 | ||||
| -rw-r--r-- | desktop/modules/sbbuilder/Toml.js | 3 | ||||
| -rw-r--r-- | desktop/modules/sbbuilder/test_toml.js | 7 |
5 files changed, 37 insertions, 6 deletions
diff --git a/desktop/modules/sbbuilder/README.md b/desktop/modules/sbbuilder/README.md index 73bfe51..ddb5b75 100644 --- a/desktop/modules/sbbuilder/README.md +++ b/desktop/modules/sbbuilder/README.md @@ -19,7 +19,11 @@ Both follow the settings window's draft rules (`desktop/README.md`). A field is typed after its default: lists are words split on spaces (a list entry holding a space is a `ponytail:` ceiling: edit the file), numbers are range-checked. An emptied manifest URL holds Save back rather than unsetting -the key, which would remove the row being typed in. The desktop defaults are +the key, which would remove the row being typed in. The helper takes a +`[manifests]` table whole, in place of its default one, so a file without +one lists the helper's default rows, and the first add, remove or edit +writes them all first: adding one row once silently dropped the default +neovim manifest. The desktop defaults are copied from sb-builder's `config.py`, a `ponytail:` ceiling in `Sbb.qml`; the VM ones come from the helper. diff --git a/desktop/modules/sbbuilder/SbbVmModule.qml b/desktop/modules/sbbuilder/SbbVmModule.qml index 45c7216..97e7983 100644 --- a/desktop/modules/sbbuilder/SbbVmModule.qml +++ b/desktop/modules/sbbuilder/SbbVmModule.qml @@ -114,6 +114,7 @@ Module { width: col.width wrapMode: Text.Wrap text: "A package's upstream deps list; {VERSION} is the new version. A hint update moves the package's extra downloads to the versions listed there." + + (col.st.manifestsDefault ? " These are the helper's defaults, not in the file: the first change writes them all, then adds or removes its own." : "") color: Theme.subtext font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 } } diff --git a/desktop/modules/sbbuilder/Store.qml b/desktop/modules/sbbuilder/Store.qml index c2afa5d..7036f36 100644 --- a/desktop/modules/sbbuilder/Store.qml +++ b/desktop/modules/sbbuilder/Store.qml @@ -32,20 +32,35 @@ QtObject { // Assigned only when the set changes, as Qtm does: a Repeater bound to a // fresh array per keystroke rebuilds the row being typed in. property var manifests: [] + // The helper takes a [manifests] table whole, in place of its default + // one, so with none in the file the default rows are the ones in effect + // and are listed; the first edit writes them all before its own. + readonly property bool manifestsDefault: !T.sections(st.draft).includes("manifests") onDraftChanged: { - const k = T.entries(st.draft, "manifests").map(e => e.key); + const k = st.manifestsDefault ? Object.keys(st.fallback("manifests") ?? {}) + : T.entries(st.draft, "manifests").map(e => e.key); if (JSON.stringify(k) !== JSON.stringify(st.manifests)) st.manifests = k; } + function seedManifests(section) { + if (section !== "manifests" || !st.manifestsDefault) return; + const d = st.fallback("manifests") ?? {}; + for (const k in d) st.draft = T.set(st.draft, "manifests", k, d[k]); + } - function fallback(section, key) { return (st.defaults[section] || {})[key]; } + function fallback(section, key) { return key === undefined ? st.defaults[section] : (st.defaults[section] || {})[key]; } function show(v) { return v === undefined ? undefined : Array.isArray(v) ? v.join(" ") : String(v); } function placeholder(section, key) { return st.show(st.fallback(section, key)) ?? ""; } - function get(section, key) { return st.show(T.get(st.draft, section, key)); } + function get(section, key) { + const v = T.get(st.draft, section, key); + // A listed default manifest shows its URL, so editing starts from it. + return st.show(v === undefined && section === "manifests" && st.manifestsDefault ? st.fallback(section, key) : v); + } // The effective value, typed: the file's, else the default. function value(section, key) { return T.get(st.draft, section, key) ?? st.fallback(section, key); } function entries(section) { return T.entries(st.draft, section); } function put(section, key, v) { + st.seedManifests(section); try { st.draft = T.set(st.draft, section, key, v); } catch (e) { st.error = e.message; st.markInvalid(section + "/" + key, true); // hold Save back @@ -63,7 +78,10 @@ QtObject { : typeof d === "number" ? Number(t) : typeof d === "boolean" ? t === "true" : t); } - function remove(section, key) { st.draft = T.remove(st.draft, section, key); } + function remove(section, key) { + st.seedManifests(section); + st.draft = T.remove(st.draft, section, key); + } function markInvalid(id, bad) { if (!!st.invalid[id] === bad) return; diff --git a/desktop/modules/sbbuilder/Toml.js b/desktop/modules/sbbuilder/Toml.js index 46b9914..dddb6f7 100644 --- a/desktop/modules/sbbuilder/Toml.js +++ b/desktop/modules/sbbuilder/Toml.js @@ -92,6 +92,9 @@ function ranges(lines) { return out; } +// The [section] names present, in file order; "" is not one. +function sections(text) { return ranges(text.split("\n")).slice(1).map(r => r.name); } + // [{key, value}] for the active keys of a section, in file order. function entries(text, section) { const lines = text.split("\n"); diff --git a/desktop/modules/sbbuilder/test_toml.js b/desktop/modules/sbbuilder/test_toml.js index 8378519..c86741d 100644 --- a/desktop/modules/sbbuilder/test_toml.js +++ b/desktop/modules/sbbuilder/test_toml.js @@ -18,7 +18,7 @@ const assert = require("assert"); const src = fs.readFileSync(__dirname + "/Toml.js", "utf8") .replace(/^\.pragma library$/m, ""); -const T = new Function(src + "\nreturn { entries, get, set, remove };")(); +const T = new Function(src + "\nreturn { sections, entries, get, set, remove };")(); const file = [ "# helper config", @@ -97,4 +97,9 @@ t = T.remove(file, "manifests", "gtk+3"); assert.deepStrictEqual(T.entries(t, "manifests").map(e => e.key), ["neovim"]); assert.strictEqual(T.remove(file, "manifests", "nope"), file); +// sections tells a missing table from an empty one, which entries cannot. +assert.deepStrictEqual(T.sections(file), ["manifests", "refresh"]); +assert.deepStrictEqual(T.sections("a = 1\n[manifests]\n"), ["manifests"]); +assert.deepStrictEqual(T.sections("a = 1\n"), []); + console.log("test_toml: ok"); |
