Simplify bar plugin management (#6435)
This commit is contained in:
+7
-7
@@ -133,12 +133,12 @@ You can still drop a plugin in without git:
|
||||
2. `omarchy-shell shell rescanPlugins`.
|
||||
3. `omarchy plugin enable <id>`. Bar widgets start in
|
||||
`barWidget.defaultSection`, or in the center when it is omitted, and can be
|
||||
moved with `omarchy bar plugin move`; a full bar replaces the one in use.
|
||||
moved with `omarchy bar move`; a full bar replaces the one in use.
|
||||
|
||||
The lower-level IPC equivalents remain available via `omarchy-shell shell rescanPlugins`,
|
||||
`omarchy-shell shell setPluginEnabled <id> true`, and `omarchy-shell shell listPlugins`.
|
||||
The `omarchy plugin` commands wrap those calls and can also edit the persisted
|
||||
bar layout in `shell.json`.
|
||||
`omarchy-shell shell enablePlugin <id> '{}'`, and `omarchy-shell shell listPlugins`.
|
||||
The `omarchy plugin` commands wrap those calls. `omarchy bar move` and
|
||||
`omarchy bar set` edit the persisted widget layout in `shell.json`.
|
||||
|
||||
To hack on a built-in plugin safely, clone it into user config instead of
|
||||
editing the built-in source. The complete plugin directory is copied, including
|
||||
@@ -265,9 +265,9 @@ becomes the authoritative file — we do **not** deep-merge defaults back in.
|
||||
like `Clock` and `AudioPanel` forward.
|
||||
5. **Third-party enabled ⇔ present.** A third-party plugin is enabled iff
|
||||
its id appears somewhere in shell.json. For full bar options, that means
|
||||
`bar.id`; for bar widgets, `omarchy bar plugin` adds/removes layout entries;
|
||||
other plugin kinds are enabled with the shell IPC. First-party non-bar
|
||||
plugins are always enabled.
|
||||
`bar.id`; for bar widgets, plugin enable/disable adds/removes layout entries;
|
||||
other plugin kinds are enabled the same way. First-party non-bar plugins
|
||||
are enabled unless listed in `disabledPlugins[]`.
|
||||
6. **Multiple instances** are allowed when a manifest sets
|
||||
`allowMultiple: true`. Each instance is independent — e.g. two clock
|
||||
widgets in different timezones are just two `{"id":"omarchy.clock", "timezone": ...}`
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
These plugins ship with Omarchy and are discovered by the shell at startup.
|
||||
They use the same `manifest.json` contract as third-party plugins; the
|
||||
only difference is that the shell flags them with `__isFirstParty: true`.
|
||||
First-party non-bar plugins are always enabled; `omarchy.bar` is the default
|
||||
bar option and becomes inactive only while a third-party `kind: "bar"` plugin is
|
||||
selected. Services and keep-loaded panels are mounted at startup; other panels,
|
||||
overlays, and menus are loaded on demand.
|
||||
First-party non-bar plugins are enabled unless listed in `disabledPlugins[]`;
|
||||
`omarchy.bar` is the default bar option and becomes inactive only while another
|
||||
`kind: "bar"` plugin is selected. Services and keep-loaded panels are mounted
|
||||
at startup; other panels, overlays, and menus are loaded on demand.
|
||||
|
||||
User-installed plugins live alongside these conceptually but on disk under
|
||||
`~/.config/omarchy/plugins/<plugin-id>/` rather than in this directory.
|
||||
|
||||
@@ -16,7 +16,7 @@ the shell for its whole session.
|
||||
|
||||
The bar config lives under the `bar:` key of [`~/.config/omarchy/shell.json`](../../README.md#shelljson-shape). Out of the box the shell uses [`config/omarchy/shell.json`](../../../config/omarchy/shell.json). Once you customize anything via the bar gestures, `omarchy bar ...`, or by editing shell.json directly, your file is canonical — there is no deep-merge.
|
||||
|
||||
The bar is configured directly on the bar itself: drag empty bar space (or click-and-hold) to move the bar to another screen edge, double-left-click empty center-bar space to toggle transparency, and drag widgets to reorder them. The `omarchy bar position` and `omarchy bar transparent` commands do the same from scripts. For scriptable widget changes, use `omarchy bar plugin add`, `omarchy bar plugin move`, `omarchy bar plugin remove`, and `omarchy bar plugin set` (widget ids come from `omarchy plugin list`).
|
||||
The bar is configured directly on the bar itself: drag empty bar space (or click-and-hold) to move the bar to another screen edge, double-left-click empty center-bar space to toggle transparency, and drag widgets to reorder them. The `omarchy bar position`, `omarchy bar transparent`, `omarchy bar move`, and `omarchy bar set` commands do the same from scripts. Enable or disable widgets with `omarchy plugin enable` and `omarchy plugin disable` (widget ids come from `omarchy plugin list`).
|
||||
|
||||
Example `shell.json` (bar subtree only shown):
|
||||
|
||||
@@ -178,6 +178,6 @@ namespaced ids.
|
||||
Third-party widgets ship as separate plugins under
|
||||
`~/.config/omarchy/plugins/<plugin-id>/` with their own `manifest.json`
|
||||
declaring `kinds: ["bar-widget"]` and a `barWidget` entry point. See
|
||||
[../../README.md](../../README.md) for the manifest schema. Enable,
|
||||
rescan, and place third-party plugins with `omarchy plugin enable`,
|
||||
`omarchy-shell shell rescanPlugins`, and `omarchy bar plugin add`.
|
||||
[../../README.md](../../README.md) for the manifest schema. Rescan, enable,
|
||||
and place third-party plugins with `omarchy-shell shell rescanPlugins`,
|
||||
`omarchy plugin enable`, and `omarchy bar move`.
|
||||
|
||||
@@ -29,7 +29,7 @@ shows up at the next refresh, so nothing polls the disk waiting for it.
|
||||
That self-hiding is why the widget ships in the default bar layout: a machine
|
||||
that has never run Claude Code or Codex draws nothing, and the icon arrives on
|
||||
its own the first time a scan finds usage. Drop it with
|
||||
`omarchy bar plugin remove omarchy.model-usage`.
|
||||
`omarchy plugin disable omarchy.model-usage`.
|
||||
|
||||
## Providers
|
||||
|
||||
@@ -52,7 +52,7 @@ falls back to local stats only.
|
||||
|
||||
Settings live in the widget's entry in `~/.config/omarchy/shell.json`. The
|
||||
top-level keys can be set with
|
||||
`omarchy bar plugin set omarchy.model-usage <key> <value>`:
|
||||
`omarchy bar set omarchy.model-usage <key> <value>`:
|
||||
|
||||
| Key | Default | What it does |
|
||||
|---|---|---|
|
||||
@@ -65,8 +65,8 @@ top-level keys can be set with
|
||||
Numbers need `--json`, or they land in `shell.json` as strings:
|
||||
|
||||
```bash
|
||||
omarchy bar plugin set omarchy.model-usage refreshIntervalSec 300 --json
|
||||
omarchy bar plugin set omarchy.model-usage syncDir '~/Sync/model-usage'
|
||||
omarchy bar set omarchy.model-usage refreshIntervalSec 300 --json
|
||||
omarchy bar set omarchy.model-usage syncDir '~/Sync/model-usage'
|
||||
```
|
||||
|
||||
Per-provider settings are nested, and `set` writes its key literally rather
|
||||
@@ -74,7 +74,7 @@ than walking a dotted path — so pass the whole `providers` object as JSON (or
|
||||
edit `shell.json` directly):
|
||||
|
||||
```bash
|
||||
omarchy bar plugin set omarchy.model-usage providers '{
|
||||
omarchy bar set omarchy.model-usage providers '{
|
||||
"claude": {
|
||||
"enabled": true,
|
||||
"statsPath": "~/.claude/stats-cache.json",
|
||||
|
||||
@@ -46,4 +46,4 @@ Renders the Tailscale mark natively as a theme-colored 3×3 dot grid, matching t
|
||||
|
||||
## Add to the bar
|
||||
|
||||
This widget ships as first-party plugin `omarchy.tailscale`. Add it with `omarchy bar plugin add omarchy.tailscale`, or add an entry such as `{ "id": "omarchy.tailscale" }` to one of the `bar.layout` sections in `~/.config/omarchy/shell.json`; the shell reloads `shell.json` automatically.
|
||||
This widget ships as first-party plugin `omarchy.tailscale`. Add it with `omarchy plugin enable omarchy.tailscale`, then place it with `omarchy bar move omarchy.tailscale` if desired.
|
||||
|
||||
@@ -24,6 +24,7 @@ QtObject {
|
||||
property var installedPlugins: ({})
|
||||
property int registryRevision: 0
|
||||
property bool scanning: false
|
||||
property string lastEnableError: ""
|
||||
|
||||
signal pluginsChanged()
|
||||
signal scanFinished()
|
||||
@@ -171,6 +172,27 @@ QtObject {
|
||||
return ["left", "center", "right"].indexOf(section) !== -1 ? section : "center"
|
||||
}
|
||||
|
||||
function barEntryId(entry) {
|
||||
return Util.canonicalWidgetId(String(Util.isPlainObject(entry) ? entry.id : entry || ""))
|
||||
}
|
||||
|
||||
function findBarLocation(config, id, section) {
|
||||
if (!Util.isPlainObject(config) || !Util.isPlainObject(config.bar)
|
||||
|| !Util.isPlainObject(config.bar.layout)) return { found: false }
|
||||
var key = Util.canonicalWidgetId(String(id))
|
||||
var sections = ["left", "center", "right"]
|
||||
for (var s = 0; s < sections.length; s++) {
|
||||
if (section && sections[s] !== section) continue
|
||||
var entries = config.bar.layout[sections[s]]
|
||||
if (!Array.isArray(entries)) continue
|
||||
for (var i = 0; i < entries.length; i++) {
|
||||
if (barEntryId(entries[i]) === key)
|
||||
return { found: true, kind: "bar", section: sections[s], index: i }
|
||||
}
|
||||
}
|
||||
return { found: false }
|
||||
}
|
||||
|
||||
function findEntryLocation(config, id) {
|
||||
if (!Util.isPlainObject(config)) return { found: false }
|
||||
var key = Util.canonicalWidgetId(String(id))
|
||||
@@ -179,14 +201,8 @@ QtObject {
|
||||
if (selectedBar === key) return { found: true, kind: "bar-option" }
|
||||
}
|
||||
if (Util.isPlainObject(config.bar) && Util.isPlainObject(config.bar.layout)) {
|
||||
var sections = ["left", "center", "right"]
|
||||
for (var s = 0; s < sections.length; s++) {
|
||||
var arr = config.bar.layout[sections[s]]
|
||||
if (!Array.isArray(arr)) continue
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
if (arr[i] && Util.canonicalWidgetId(arr[i].id) === key) return { found: true, kind: "bar", section: sections[s], index: i }
|
||||
}
|
||||
}
|
||||
var barLocation = findBarLocation(config, key, "")
|
||||
if (barLocation.found) return barLocation
|
||||
}
|
||||
if (Array.isArray(config.plugins)) {
|
||||
for (var j = 0; j < config.plugins.length; j++) {
|
||||
@@ -196,13 +212,210 @@ QtObject {
|
||||
return { found: false }
|
||||
}
|
||||
|
||||
function barTarget(config, placement, fallbackSection) {
|
||||
var target = placement || {}
|
||||
var section = ["left", "center", "right"].indexOf(String(target.section || "")) !== -1
|
||||
? String(target.section) : fallbackSection
|
||||
var relativeId = String(target.before || target.after || "")
|
||||
if (relativeId) {
|
||||
var relative = findBarLocation(config, relativeId, section && target.section ? section : "")
|
||||
if (!relative.found) return { error: "could not find target widget " + relativeId }
|
||||
return {
|
||||
section: relative.section,
|
||||
index: relative.index + (target.after ? 1 : 0)
|
||||
}
|
||||
}
|
||||
|
||||
if (!Array.isArray(config.bar.layout[section])) config.bar.layout[section] = []
|
||||
if (target.index !== undefined && target.index !== null) {
|
||||
var requested = Math.max(0, Math.floor(Number(target.index)))
|
||||
return { section: section, index: Math.min(requested, config.bar.layout[section].length) }
|
||||
}
|
||||
|
||||
var anchors = { left: "omarchy.workspaces", center: "omarchy.weather", right: "omarchy.tray" }
|
||||
var anchor = findBarLocation(config, anchors[section], section)
|
||||
return {
|
||||
section: section,
|
||||
index: anchor.found ? anchor.index + 1 : config.bar.layout[section].length
|
||||
}
|
||||
}
|
||||
|
||||
function moveBarEntry(config, id, placement) {
|
||||
var key = Util.canonicalWidgetId(String(id))
|
||||
var source
|
||||
if (placement.fromIndex !== undefined && placement.fromIndex !== null) {
|
||||
var fromSection = String(placement.fromSection || "")
|
||||
if (!fromSection) return "from-index requires from-section"
|
||||
var entries = config.bar.layout[fromSection]
|
||||
var fromIndex = Math.floor(Number(placement.fromIndex))
|
||||
if (!Array.isArray(entries) || fromIndex < 0 || fromIndex >= entries.length)
|
||||
return "no widget at " + fromSection + "[" + fromIndex + "]"
|
||||
if (barEntryId(entries[fromIndex]) !== key)
|
||||
return "widget at " + fromSection + "[" + fromIndex + "] is not " + key
|
||||
source = { found: true, section: fromSection, index: fromIndex }
|
||||
} else {
|
||||
source = findBarLocation(config, key, String(placement.fromSection || ""))
|
||||
if (!source.found) return "could not find widget " + key
|
||||
}
|
||||
|
||||
var entry = config.bar.layout[source.section][source.index]
|
||||
config.bar.layout[source.section].splice(source.index, 1)
|
||||
var target = barTarget(config, placement, source.section)
|
||||
if (target.error) {
|
||||
config.bar.layout[source.section].splice(source.index, 0, entry)
|
||||
return target.error
|
||||
}
|
||||
config.bar.layout[target.section].splice(target.index, 0, entry)
|
||||
return ""
|
||||
}
|
||||
|
||||
function moveBarWidget(id, placement) {
|
||||
var error = ""
|
||||
shellConfigMutator(function(config) {
|
||||
ensureConfigShape(config)
|
||||
error = moveBarEntry(config, id, placement || {})
|
||||
})
|
||||
if (error) return error
|
||||
registryRevision++
|
||||
pluginsChanged()
|
||||
return ""
|
||||
}
|
||||
|
||||
function setBarWidget(id, key, value, selector) {
|
||||
var error = ""
|
||||
shellConfigMutator(function(config) {
|
||||
ensureConfigShape(config)
|
||||
var location
|
||||
var requested = selector || {}
|
||||
var section = String(requested.fromSection || requested.section || "")
|
||||
var index = requested.fromIndex !== undefined && requested.fromIndex !== null
|
||||
? requested.fromIndex : requested.index
|
||||
if (index !== undefined && index !== null) {
|
||||
if (!section) {
|
||||
error = "index requires section"
|
||||
return
|
||||
}
|
||||
var entries = config.bar.layout[section]
|
||||
var numericIndex = Math.floor(Number(index))
|
||||
if (!Array.isArray(entries) || numericIndex < 0 || numericIndex >= entries.length) {
|
||||
error = "no widget at " + section + "[" + numericIndex + "]"
|
||||
return
|
||||
}
|
||||
location = { found: true, section: section, index: numericIndex }
|
||||
} else {
|
||||
location = findBarLocation(config, id, section)
|
||||
}
|
||||
if (!location.found) {
|
||||
error = "could not find widget " + id
|
||||
return
|
||||
}
|
||||
if (barEntryId(config.bar.layout[location.section][location.index]) !== String(id)) {
|
||||
error = "widget at " + location.section + "[" + location.index + "] is not " + id
|
||||
return
|
||||
}
|
||||
var entry = config.bar.layout[location.section][location.index]
|
||||
if (!Util.isPlainObject(entry)) {
|
||||
error = "widget entry must be an object"
|
||||
return
|
||||
}
|
||||
entry[String(key)] = value
|
||||
})
|
||||
if (error) return error
|
||||
registryRevision++
|
||||
pluginsChanged()
|
||||
return ""
|
||||
}
|
||||
|
||||
function ensureConfigShape(config) {
|
||||
if (!Util.isPlainObject(config.bar)) config.bar = { layout: { left: [], center: [], right: [] } }
|
||||
if (!Util.isPlainObject(config.bar.layout)) config.bar.layout = { left: [], center: [], right: [] }
|
||||
var sections = ["left", "center", "right"]
|
||||
for (var i = 0; i < sections.length; i++) {
|
||||
if (!Array.isArray(config.bar.layout[sections[i]])) config.bar.layout[sections[i]] = []
|
||||
}
|
||||
if (!Array.isArray(config.plugins)) config.plugins = []
|
||||
}
|
||||
|
||||
// Bar widgets use the default section declared in their manifest, falling
|
||||
// back to center. Panels/overlays/menus/services go into the plugins[] array.
|
||||
// Built-ins are already loaded, so shell.json only ever records the
|
||||
// deviation: an added third-party plugin in plugins[], a switched-off
|
||||
// built-in in disabledPlugins[].
|
||||
function setEnabled(id, value) {
|
||||
function removeDisabled(config, id) {
|
||||
if (!Array.isArray(config.disabledPlugins)) return
|
||||
config.disabledPlugins = config.disabledPlugins.filter(function(entry) { return entry !== id })
|
||||
if (config.disabledPlugins.length === 0) delete config.disabledPlugins
|
||||
}
|
||||
|
||||
function addDisabled(config, id) {
|
||||
if (isDisabled(config, id)) return
|
||||
if (!Array.isArray(config.disabledPlugins)) config.disabledPlugins = []
|
||||
config.disabledPlugins.push(id)
|
||||
}
|
||||
|
||||
function cloneShouldRestoreSource(config, id) {
|
||||
return Array.isArray(config.cloneSourceRestores) && config.cloneSourceRestores.indexOf(id) !== -1
|
||||
}
|
||||
|
||||
function setCloneShouldRestoreSource(config, id, value) {
|
||||
var restores = Array.isArray(config.cloneSourceRestores) ? config.cloneSourceRestores : []
|
||||
restores = restores.filter(function(entry) { return entry !== id })
|
||||
if (value) restores.push(id)
|
||||
if (restores.length) config.cloneSourceRestores = restores
|
||||
else delete config.cloneSourceRestores
|
||||
}
|
||||
|
||||
function activeCloneFor(config, sourceId) {
|
||||
for (var candidate in installedPlugins) {
|
||||
var candidateManifest = installedPlugins[candidate]
|
||||
var candidateMetadata = candidateManifest && Util.isPlainObject(candidateManifest.omarchy)
|
||||
? candidateManifest.omarchy : null
|
||||
if (!candidateMetadata || String(candidateMetadata.clonedFrom || "") !== sourceId) continue
|
||||
if (Array.isArray(candidateManifest.kinds) && candidateManifest.kinds.indexOf("bar") !== -1) {
|
||||
if (Util.canonicalWidgetId(String(config.bar.id || "")) === candidate) return candidate
|
||||
} else if (findEntryLocation(config, candidate).found) {
|
||||
return candidate
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
function restoreCloneSource(config, cloneId, sourceId) {
|
||||
var cloneManifest = installedPlugins[cloneId]
|
||||
var isBarOption = cloneManifest && Array.isArray(cloneManifest.kinds)
|
||||
&& cloneManifest.kinds.indexOf("bar") !== -1
|
||||
if (isBarOption) {
|
||||
if (sourceId === "omarchy.bar") delete config.bar.id
|
||||
else config.bar.id = sourceId
|
||||
} else {
|
||||
var cloneLocation = findEntryLocation(config, cloneId)
|
||||
if (cloneLocation.kind === "bar") {
|
||||
var cloneEntry = config.bar.layout[cloneLocation.section][cloneLocation.index]
|
||||
var sections = ["left", "center", "right"]
|
||||
for (var s = 0; s < sections.length; s++) {
|
||||
for (var i = config.bar.layout[sections[s]].length - 1; i >= 0; i--) {
|
||||
if (barEntryId(config.bar.layout[sections[s]][i]) === sourceId)
|
||||
config.bar.layout[sections[s]].splice(i, 1)
|
||||
}
|
||||
}
|
||||
cloneLocation = findBarLocation(config, cloneId, "")
|
||||
if (cloneLocation.found) {
|
||||
var restoredEntry = Util.isPlainObject(cloneEntry) ? Util.cloneJson(cloneEntry) : {}
|
||||
restoredEntry.id = sourceId
|
||||
config.bar.layout[cloneLocation.section][cloneLocation.index] = restoredEntry
|
||||
}
|
||||
} else if (cloneLocation.kind === "plugin") {
|
||||
config.plugins.splice(cloneLocation.index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
if (cloneShouldRestoreSource(config, cloneId)) removeDisabled(config, sourceId)
|
||||
setCloneShouldRestoreSource(config, cloneId, false)
|
||||
}
|
||||
|
||||
function setEnabled(id, value, placement) {
|
||||
var key = Util.canonicalWidgetId(String(id))
|
||||
lastEnableError = ""
|
||||
if (!shellConfigMutator) {
|
||||
console.warn("PluginRegistry.setEnabled called before shellConfigMutator wired")
|
||||
return false
|
||||
@@ -216,17 +429,33 @@ QtObject {
|
||||
var isBarWidget = manifest && Array.isArray(manifest.kinds) && manifest.kinds.indexOf("bar-widget") !== -1
|
||||
var hasNonWidgetKind = manifest && Array.isArray(manifest.kinds)
|
||||
&& manifest.kinds.some(function(kind) { return kind !== "bar-widget" })
|
||||
var metadata = manifest && Util.isPlainObject(manifest.omarchy) ? manifest.omarchy : null
|
||||
var clonedFrom = metadata ? Util.canonicalWidgetId(String(metadata.clonedFrom || "")) : ""
|
||||
shellConfigMutator(function(config) {
|
||||
// Ensure shape exists.
|
||||
if (!Util.isPlainObject(config.bar)) config.bar = { layout: { left: [], center: [], right: [] } }
|
||||
if (!Util.isPlainObject(config.bar.layout)) config.bar.layout = { left: [], center: [], right: [] }
|
||||
if (!Array.isArray(config.plugins)) config.plugins = []
|
||||
ensureConfigShape(config)
|
||||
|
||||
if (value && placement && (placement.before || placement.after)) {
|
||||
var relativeId = String(placement.before || placement.after)
|
||||
if (!findBarLocation(config, relativeId, String(placement.section || "")).found) {
|
||||
lastEnableError = "could not find target widget " + relativeId
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (value && manifest && manifest.__isFirstParty) {
|
||||
var activeClone = activeCloneFor(config, key)
|
||||
if (activeClone) {
|
||||
restoreCloneSource(config, activeClone, key)
|
||||
removeDisabled(config, key)
|
||||
}
|
||||
}
|
||||
|
||||
if (isBarOption) {
|
||||
if (value) {
|
||||
config.bar.id = key
|
||||
} else if (Util.canonicalWidgetId(String(config.bar.id || "")) === key) {
|
||||
delete config.bar.id
|
||||
if (clonedFrom && clonedFrom !== "omarchy.bar") config.bar.id = clonedFrom
|
||||
else delete config.bar.id
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -235,33 +464,45 @@ QtObject {
|
||||
var location = findEntryLocation(config, key)
|
||||
|
||||
if (value) {
|
||||
// Leave shell.json without the key once nothing is switched off, so a
|
||||
// config that never disabled anything reads as it always did.
|
||||
if (Array.isArray(config.disabledPlugins)) {
|
||||
config.disabledPlugins = config.disabledPlugins.filter(function(entry) { return entry !== key })
|
||||
if (config.disabledPlugins.length === 0) delete config.disabledPlugins
|
||||
}
|
||||
if (location.found) return
|
||||
removeDisabled(config, key)
|
||||
var entry = { id: key }
|
||||
if (isBarWidget) {
|
||||
var section = defaultBarWidgetSection(manifest)
|
||||
if (!Array.isArray(config.bar.layout[section])) config.bar.layout[section] = []
|
||||
config.bar.layout[section].push(entry)
|
||||
} else if (!isFirstParty) {
|
||||
var insertedWithPlacement = false
|
||||
if (!location.found && isBarWidget) {
|
||||
var sourceLocation = clonedFrom ? findEntryLocation(config, clonedFrom) : { found: false }
|
||||
if (sourceLocation.kind === "bar") {
|
||||
var sourceEntry = config.bar.layout[sourceLocation.section][sourceLocation.index]
|
||||
var replacement = Util.isPlainObject(sourceEntry) ? Util.cloneJson(sourceEntry) : entry
|
||||
replacement.id = key
|
||||
config.bar.layout[sourceLocation.section][sourceLocation.index] = replacement
|
||||
} else {
|
||||
var section = defaultBarWidgetSection(manifest)
|
||||
var target = barTarget(config, placement || {}, section)
|
||||
config.bar.layout[target.section].splice(target.index, 0, entry)
|
||||
insertedWithPlacement = true
|
||||
}
|
||||
} else if (!location.found && !isFirstParty) {
|
||||
config.plugins.push(entry)
|
||||
}
|
||||
|
||||
if (isBarWidget && !insertedWithPlacement && placement && Object.keys(placement).length)
|
||||
moveBarEntry(config, key, placement)
|
||||
|
||||
if (clonedFrom && hasNonWidgetKind && !isDisabled(config, clonedFrom)) {
|
||||
addDisabled(config, clonedFrom)
|
||||
setCloneShouldRestoreSource(config, key, true)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (location.kind === "bar") config.bar.layout[location.section].splice(location.index, 1)
|
||||
if (clonedFrom) restoreCloneSource(config, key, clonedFrom)
|
||||
else if (location.kind === "bar") config.bar.layout[location.section].splice(location.index, 1)
|
||||
else if (location.kind === "plugin") config.plugins.splice(location.index, 1)
|
||||
|
||||
// Dropping the layout entry is the whole story for a widget. Anything
|
||||
// else built-in loads by default, so switching it off has to be stated.
|
||||
if (isFirstParty && (!isBarWidget || hasNonWidgetKind) && !isDisabled(config, key)) {
|
||||
if (!Array.isArray(config.disabledPlugins)) config.disabledPlugins = []
|
||||
config.disabledPlugins.push(key)
|
||||
}
|
||||
if (isFirstParty && !isBarWidget) addDisabled(config, key)
|
||||
})
|
||||
if (lastEnableError) return false
|
||||
registryRevision++
|
||||
pluginsChanged()
|
||||
return true
|
||||
|
||||
+31
-9
@@ -54,7 +54,6 @@ ShellRoot {
|
||||
|
||||
property var defaultsConfig: builtinShellConfig
|
||||
property var shellConfig: builtinShellConfig
|
||||
property bool suppressUserReload: false
|
||||
property bool pluginReloading: false
|
||||
property bool pluginReloadPending: false
|
||||
|
||||
@@ -107,7 +106,6 @@ ShellRoot {
|
||||
}
|
||||
|
||||
function persistShellConfig(nextConfig) {
|
||||
suppressUserReload = true
|
||||
var payload = JSON.parse(JSON.stringify(nextConfig))
|
||||
payload.version = 1
|
||||
shellConfig = payload
|
||||
@@ -135,13 +133,7 @@ ShellRoot {
|
||||
watchChanges: true
|
||||
atomicWrites: true
|
||||
printErrors: false
|
||||
onLoaded: {
|
||||
if (shell.suppressUserReload) {
|
||||
shell.suppressUserReload = false
|
||||
return
|
||||
}
|
||||
shell.applyShellConfig()
|
||||
}
|
||||
onLoaded: shell.applyShellConfig()
|
||||
onLoadFailed: function(error) { shell.applyShellConfig() }
|
||||
onFileChanged: reload()
|
||||
}
|
||||
@@ -908,6 +900,36 @@ ShellRoot {
|
||||
return shell.pluginRegistry.setEnabled(id, enabled === "true") ? "ok" : "unknown"
|
||||
}
|
||||
|
||||
function enablePlugin(id: string, placementJson: string): string {
|
||||
try {
|
||||
var placement = JSON.parse(placementJson || "{}")
|
||||
if (shell.pluginRegistry.setEnabled(id, true, placement)) return "ok"
|
||||
return shell.pluginRegistry.lastEnableError || "unknown"
|
||||
} catch (e) {
|
||||
return "invalid placement: " + e
|
||||
}
|
||||
}
|
||||
|
||||
function moveBarWidget(id: string, placementJson: string): string {
|
||||
try {
|
||||
var error = shell.pluginRegistry.moveBarWidget(id, JSON.parse(placementJson || "{}"))
|
||||
return error ? error : "ok"
|
||||
} catch (e) {
|
||||
return "invalid placement: " + e
|
||||
}
|
||||
}
|
||||
|
||||
function setBarWidget(id: string, key: string, valueJson: string, selectorJson: string): string {
|
||||
try {
|
||||
var value = JSON.parse(valueJson)
|
||||
var selector = JSON.parse(selectorJson || "{}")
|
||||
var error = shell.pluginRegistry.setBarWidget(id, key, value, selector)
|
||||
return error ? error : "ok"
|
||||
} catch (e) {
|
||||
return "invalid widget setting: " + e
|
||||
}
|
||||
}
|
||||
|
||||
function listPlugins(): string {
|
||||
var out = []
|
||||
var plugins = shell.pluginRegistry.installedPlugins
|
||||
|
||||
Reference in New Issue
Block a user