diff --git a/bin/omarchy-bar b/bin/omarchy-bar index d354645b..17c0a099 100755 --- a/bin/omarchy-bar +++ b/bin/omarchy-bar @@ -1,9 +1,9 @@ #!/bin/bash -# omarchy:summary=Mutate the user shell.json bar layout, active bar option, and bar settings +# omarchy:summary=Set the active bar option, position, and transparency # omarchy:group=bar -# omarchy:args=show | layout [--json] | list [--json] [--all] | options [--json] | use | reset | defaults | add [plugin] [placement] | move [placement] | remove [plugin] [placement] | set [--json] [placement] | replace | position | transparent | settings -# omarchy:examples=omarchy bar show | omarchy bar list | omarchy bar add omarchy.tailscale | omarchy bar add omarchy.clock --section center --before omarchy.weather | omarchy bar move omarchy.clock --section center --index 0 | omarchy bar remove omarchy.tailscale | omarchy bar set omarchy.clock format HH:mm | omarchy bar use local.neon-bar | omarchy bar position top | omarchy bar transparent true +# omarchy:args=use | reset | defaults | position | transparent | settings +# omarchy:examples=omarchy bar use local.neon-bar | omarchy bar reset | omarchy bar defaults | omarchy bar position top | omarchy bar transparent true set -euo pipefail @@ -15,58 +15,16 @@ usage() { cat < [args...] -Inspect: - show Current bar JSON - layout [--json] Current bar layout (section/index/widget) - list [--json] [--all] Addable bar widgets (alias: available, widgets) - options [--json] Bar replacement options - -Select: use Use a bar option as the active bar reset Return to the built-in Omarchy bar defaults Restore the default bar and service widgets - -Edit layout: - add [placement] Add a bar widget - move [placement] [--from-section S --from-index N] - Move a widget within/between sections - remove [placement] (alias: rm, drop) - Remove a widget - set [--json] [placement] - Set a per-widget option - -Other: - replace Replace the first instance of a widget id position Bar position transparent Bar transparency settings Open the inline bar config panel -Placement (for add/move/remove/set): - --section Target section - --index Insert/remove at index in the target section - --before Insert before the first matching widget - --after Insert after the first matching widget - --from-section
Source section (move/remove/set) - --from-index Source index (move/remove/set) - --duplicate add: allow a second instance of the widget - --all remove: remove every matching instance - -Without placement flags, 'add' inserts after the section anchor (workspaces on -left, weather on center, tray on right) and dedupes across sections; 'move' -preserves the source section; 'remove' drops the first match (or every match -with --all). +Bar widgets are added, moved, removed, and configured with 'omarchy bar plugin'. Examples: - omarchy bar show - omarchy bar layout - omarchy bar list - omarchy bar add omarchy.tailscale - omarchy bar add omarchy.clock --section center --before omarchy.weather - omarchy bar move omarchy.clock --section center --index 0 - omarchy bar remove omarchy.tailscale - omarchy bar remove omarchy.tailscale --all - omarchy bar set omarchy.clock format HH:mm - omarchy bar set omarchy.indicators items '["Dnd","NightLight"]' --json omarchy bar use local.neon-bar omarchy bar reset omarchy bar defaults @@ -80,14 +38,6 @@ fail() { exit 1 } -require_command() { - command -v "$1" >/dev/null 2>&1 || fail "$1 is required" -} - -require_omarchy_path() { - [[ -n $OMARCHY_ROOT ]] || fail "OMARCHY_PATH is not set" -} - refresh_shell_config() { if ! omarchy-shell shell reloadConfig >/dev/null 2>&1; then omarchy-shell -q shell rescanPlugins >/dev/null 2>&1 || true @@ -95,80 +45,18 @@ refresh_shell_config() { } source_file() { - local source="$CONFIG_FILE" - - if [[ ! -s $source ]]; then - require_omarchy_path - source="$DEFAULTS_FILE" + if [[ -s $CONFIG_FILE ]]; then + printf '%s\n' "$CONFIG_FILE" + else + printf '%s\n' "$DEFAULTS_FILE" fi - - [[ -s $source ]] || fail "could not find shell config or defaults" - printf '%s\n' "$source" } -# jq defs shared across mutations. All `def`s come first so the pipeline that -# follows them stays valid jq. `entry_id` and the shape helpers are used by both -# the normalize pipeline and the resolve_target/resolve_source helpers. -JQ_DEFS=' +# jq pipeline that normalizes shell.json into a well-shaped object with +# version=1, bar.layout.{left,center,right} arrays, and plugins array. +NORMALIZE=' def object_or_empty: if type == "object" then . else {} end; def array_or_empty: if type == "array" then . else [] end; - def entry_id: if type == "object" then (.id // "" | tostring) else tostring end; - def anchor_for($section): { left: "omarchy.workspaces", center: "omarchy.weather", right: "omarchy.tray" }[$section]; - def find_all($id; $only): - [ ["left","center","right"][] as $section - | ((.bar.layout[$section] // []) | to_entries[]) - | select((($only == "" or $section == $only)) and ((.value | entry_id) == $id)) - | {section: $section, index: .key, entry: .value} ]; - def entry_at($section; $index): - if $index < 0 or $index >= (.bar.layout[$section] | length) then - error("no widget at " + $section + "[" + ($index | tostring) + "]") - else .bar.layout[$section][$index] end; - def resolve_target($defaultSection): - . as $root - | (if $before != "" or $after != "" then - ($root | find_all($before + $after; $targetSection) | .[0] - // error("could not find target widget " + ($before + $after) + ($targetSection | if . == "" then "" else " in " + . end))) - | .section as $section | (.index + (if $after == "" then 0 else 1 end)) as $index - | {section: $section, index: $index, anchor: false} - elif $targetSection != "" or $targetIndex != "" then - { section: ($targetSection | if . == "" then $defaultSection else . end), - index: (if $targetIndex == "" then null else ($targetIndex | tonumber) end), - anchor: false } - else - { section: $defaultSection, index: null, anchor: true } - end) - | .section as $section - | .index as $rawIndex - | (if $rawIndex == null then - if .anchor then - ($root.bar.layout[$section] | map(entry_id) | index(anchor_for($section))) as $anchorIndex - | if $anchorIndex == null then ($root.bar.layout[$section] | length) else ($anchorIndex + 1) end - else ($root.bar.layout[$section] | length) end - elif $rawIndex > ($root.bar.layout[$section] | length) then ($root.bar.layout[$section] | length) - else $rawIndex end) as $index - | {section: $section, index: $index}; - def resolve_source: - if $fromIndex != "" then - if $fromSection == "" then error("--from-index requires --from-section") - else - ($fromIndex | tonumber) as $index - | entry_at($fromSection; $index) as $entry - | if $widgetId != "" and ($entry | entry_id) != $widgetId then - error("widget at " + $fromSection + "[" + ($index | tostring) + "] is not " + $widgetId) - else {section: $fromSection, index: $index, entry: $entry} end - end - else - (find_all($widgetId; $fromSection) - | if length == 0 then - error("could not find widget " + $widgetId + ($fromSection | if . == "" then "" else " in " + . end)) - else .[0] end) - end; -' - -# jq pipeline that normalizes shell.json into a well-shaped object with -# version=1, bar.layout.{left,center,right} arrays, and plugins array. Every -# mutation pipes through this so downstream jq can assume structure. -NORMALIZE=' object_or_empty | .version = 1 | .bar = (.bar | object_or_empty) @@ -193,295 +81,21 @@ commit() { shift mkdir -p "$(dirname "$CONFIG_FILE")" _BAR_TMP=$(mktemp) - if ! jq -S -e "$@" "$program" "$(source_file)" >"$_BAR_TMP"; then - rm -f "$_BAR_TMP" - _BAR_TMP="" - fail "could not update shell config" - fi + jq -S -e "$@" "$program" "$(source_file)" >"$_BAR_TMP" || fail "could not update shell config" mv "$_BAR_TMP" "$CONFIG_FILE" _BAR_TMP="" refresh_shell_config } -section_valid() { - [[ $1 =~ ^(left|center|right)$ ]] -} +# ------------------------------------------------------------------ validation -validate_section() { - section_valid "$1" || fail "section must be left, center, or right" -} - -validate_index() { - [[ $1 =~ ^[0-9]+$ ]] || fail "index must be a non-negative integer" -} - -# --------------------------------------------------------------------- catalog - -catalog_json() { - require_omarchy_path - require_command jq - omarchy-plugin-catalog -} - -widget_is_known() { - local id="$1" - catalog_json | jq -e --arg id "$id" ' - any(.[]; (.kinds | index("bar-widget")) and .id == $id) +bar_option_exists() { + omarchy-plugin-catalog | jq -e --arg id "$1" ' + any(.[]; (.kinds | index("bar")) and .barPath != null and .id == $id) ' >/dev/null } -current_bar_ids_json() { - jq -c ' - def array_or_empty: if type == "array" then . else [] end; - def entry_id: if type == "object" then (.id // "" | tostring) else tostring end; - - ["left", "center", "right"] as $sections | - [ $sections[] as $section | - ((.bar.layout[$section] // []) | array_or_empty)[] | - entry_id | - select(length > 0) - ] - ' "$(source_file)" -} - -current_bar_entries_json() { - jq -c ' - def array_or_empty: if type == "array" then . else [] end; - def entry_id($entry): if ($entry | type) == "object" then ($entry.id // "" | tostring) else ($entry | tostring) end; - - ["left", "center", "right"] as $sections | - [ $sections[] as $section | - ((.bar.layout[$section] // []) | array_or_empty | to_entries[]) | - { section: $section, index: .key, id: entry_id(.value) } | - select(.id | length > 0) - ] - ' "$(source_file)" -} - -available_widgets_json() { - local include_all="$1" - local current_ids - current_ids=$(current_bar_ids_json) - - catalog_json | jq --argjson currentIds "$current_ids" --argjson includeAll "$include_all" ' - map(select((.kinds | index("bar-widget")) and .barWidgetPath != null)) - | map({ - id: .id, - name: (.barWidget.displayName // .name // .id), - description: (.barWidget.description // .description // ""), - category: (.barWidget.category // "Plugin"), - allowMultiple: ((.barWidget.allowMultiple // false) == true) - }) - | unique_by(.id) - | map(. as $widget | - $widget + { - inBar: (($currentIds | index($widget.id)) != null), - addable: ($widget.allowMultiple or (($currentIds | index($widget.id)) == null)) - }) - | map(select($includeAll or .addable)) - | sort_by(.category, .name, .id) - ' -} - -print_available_widgets() { - local include_all="false" - local json="false" - - while (( $# > 0 )); do - case "$1" in - --all) include_all="true" ;; - --json) json="true" ;; - -h | --help) usage; exit 0 ;; - *) fail "unknown list option: $1" ;; - esac - shift - done - - if [[ $json == "true" ]]; then - available_widgets_json "$include_all" - return - fi - - available_widgets_json "$include_all" | jq -r ' - .[] | - [ - .id, - (if .inBar and .allowMultiple then "addable*" elif .inBar then "in-bar" else "addable" end), - .category, - .name, - .description - ] | @tsv - ' | awk -F '\t' ' - BEGIN { printf "%-28s %-10s %-14s %-22s %s\n", "ID", "STATUS", "CATEGORY", "NAME", "DESCRIPTION" } - { printf "%-28s %-10s %-14s %-22s %s\n", $1, $2, $3, $4, $5 } - ' -} - -# ------------------------------------------------------------------- bar options - -current_bar_option_id() { - jq -r '(.bar.id // "omarchy.bar") | tostring' "$(source_file)" -} - -available_bar_options_json() { - local current_id - current_id=$(current_bar_option_id) - - catalog_json | jq --arg currentId "$current_id" ' - map(select((.kinds | index("bar")) and .barPath != null)) - | map({ - id: .id, - name: (.name // .id), - description: (.description // ""), - firstParty: .firstParty, - active: (.id == $currentId) - }) - | unique_by(.id) - | sort_by((if .id == "omarchy.bar" then 0 else 1 end), .name, .id) - ' -} - -print_bar_options() { - local json="false" - - while (( $# > 0 )); do - case "$1" in - --json) json="true" ;; - -h | --help) usage; exit 0 ;; - *) fail "unknown options option: $1" ;; - esac - shift - done - - if [[ $json == "true" ]]; then - available_bar_options_json - return - fi - - available_bar_options_json | jq -r ' - .[] | - [ - .id, - (if .active then "active" else "available" end), - (if .firstParty then "built-in" else "plugin" end), - .name, - .description - ] | @tsv - ' | awk -F '\t' ' - BEGIN { printf "%-32s %-10s %-8s %-22s %s\n", "ID", "STATUS", "SOURCE", "NAME", "DESCRIPTION" } - { printf "%-32s %-10s %-8s %-22s %s\n", $1, $2, $3, $4, $5 } - ' -} - -bar_option_exists() { - available_bar_options_json | jq -e --arg id "$1" 'any(.[]; .id == $id)' >/dev/null -} - -# --------------------------------------------------------------------- placement - -# Parse placement flags shared by add/move/remove/set. Sets the globals below. -PLACEMENT_SECTION="" -PLACEMENT_INDEX="" -PLACEMENT_BEFORE="" -PLACEMENT_AFTER="" -PLACEMENT_FROM_SECTION="" -PLACEMENT_FROM_INDEX="" -PLACEMENT_DUPLICATE="false" -PLACEMENT_ALL="false" - -parse_placement() { - while (( $# > 0 )); do - case "$1" in - --section) - PLACEMENT_SECTION="${2:-}" - validate_section "$PLACEMENT_SECTION" - shift 2 - ;; - --index) - PLACEMENT_INDEX="${2:-}" - validate_index "$PLACEMENT_INDEX" - shift 2 - ;; - --before) - PLACEMENT_BEFORE="${2:-}" - [[ -n $PLACEMENT_BEFORE ]] || fail "--before requires a widget id" - shift 2 - ;; - --after) - PLACEMENT_AFTER="${2:-}" - [[ -n $PLACEMENT_AFTER ]] || fail "--after requires a widget id" - shift 2 - ;; - --from-section) - PLACEMENT_FROM_SECTION="${2:-}" - validate_section "$PLACEMENT_FROM_SECTION" - shift 2 - ;; - --from-index) - PLACEMENT_FROM_INDEX="${2:-}" - validate_index "$PLACEMENT_FROM_INDEX" - shift 2 - ;; - --duplicate) - PLACEMENT_DUPLICATE="true" - shift - ;; - --all) - PLACEMENT_ALL="true" - shift - ;; - -h | --help) - usage - exit 0 - ;; - *) - fail "unknown option: $1" - ;; - esac - done - - [[ -z $PLACEMENT_BEFORE || -z $PLACEMENT_AFTER ]] || fail "use only one of --before or --after" -} - -# --------------------------------------------------------------- commands: inspect - -cmd_show() { - (( $# == 0 )) || fail "show does not take arguments" - jq '.bar // {}' "$(source_file)" -} - -cmd_layout() { - local json="false" - while (( $# > 0 )); do - case "$1" in - --json) json="true" ;; - -h | --help) usage; exit 0 ;; - *) fail "unknown layout option: $1" ;; - esac - shift - done - - if [[ $json == "true" ]]; then - jq '.bar.layout // { left: [], center: [], right: [] }' "$(source_file)" - return - fi - - jq -r ' - (.bar.layout // { left: [], center: [], right: [] }) as $layout | - ["left", "center", "right"][] as $section | - ($layout[$section] // []) as $entries | - if ($entries | length) == 0 then - "\($section)\t-\t-" - else - $entries | to_entries[] | "\($section)\t\(.key)\t\(.value.id // "")" - end - ' "$(source_file)" | awk ' - BEGIN { printf "%-8s %-5s %s\n", "SECTION", "INDEX", "WIDGET" } - { printf "%-8s %-5s %s\n", $1, $2, $3 } - ' -} - -# --------------------------------------------------------------- commands: select +# -------------------------------------------------------------------- commands cmd_use() { local plugin="${1:-}" @@ -490,309 +104,36 @@ cmd_use() { if [[ $plugin == "default" || $plugin == "built-in" ]]; then plugin="omarchy.bar" fi - bar_option_exists "$plugin" || fail "$plugin is not a known bar option; run 'omarchy bar options'" + bar_option_exists "$plugin" || fail "$plugin is not a known bar option; run 'omarchy plugin list'" if [[ $plugin == "omarchy.bar" ]]; then - commit "$JQ_DEFS $NORMALIZE | del(.bar.id)" + commit "$NORMALIZE | del(.bar.id)" else - commit "$JQ_DEFS $NORMALIZE | .bar.id = \$plugin" --arg plugin "$plugin" + commit "$NORMALIZE | .bar.id = \$plugin" --arg plugin "$plugin" fi echo "Using $plugin as the active bar" } -cmd_reset() { - (( $# == 0 )) || fail "reset does not take arguments" - commit "$JQ_DEFS $NORMALIZE | del(.bar.id)" - echo "Reset to the built-in Omarchy bar" -} - cmd_defaults() { - local service - local services=(dropbox tailscale) - (( $# == 0 )) || fail "defaults does not take arguments" - require_omarchy_path - [[ -s $DEFAULTS_FILE ]] || fail "could not find bar defaults" - - commit "$JQ_DEFS $NORMALIZE | .bar = \$defaults[0].bar" --slurpfile defaults "$DEFAULTS_FILE" - - for service in "${services[@]}"; do + # Restore the whole default bar, then re-add widgets for services the user + # actually has installed (they aren't in the shipped default layout). + commit "$NORMALIZE | .bar = \$defaults[0].bar" --slurpfile defaults "$DEFAULTS_FILE" + local service + for service in dropbox tailscale; do if "omarchy-installed-service-$service"; then - cmd_add "omarchy.$service" + omarchy-bar-plugin add "omarchy.$service" fi done - echo "Restored the default Omarchy bar" } -# --------------------------------------------------------------- commands: edit - -cmd_add() { - local id="${1:-}" - [[ -n $id ]] || fail "bar add requires a widget id" - shift - - local positional_section="" - while (( $# > 0 )); do - if [[ $1 == --* ]]; then - break - fi - [[ -z $positional_section ]] || fail "unexpected argument: $1" - positional_section="$1" - shift - done - - parse_placement "$@" - [[ -z $positional_section || -z $PLACEMENT_SECTION ]] || fail "specify a section positionally or with --section, not both" - [[ -z $positional_section || -z $PLACEMENT_INDEX ]] || fail "specify a section positionally or use --index, not both" - [[ -z $positional_section || -z $PLACEMENT_BEFORE ]] || fail "specify a section positionally or use --before, not both" - [[ -z $positional_section || -z $PLACEMENT_AFTER ]] || fail "specify a section positionally or use --after, not both" - [[ -z $positional_section || ( $PLACEMENT_DUPLICATE == false ) ]] || fail "--duplicate needs explicit placement flags" - if [[ -n $positional_section ]]; then - validate_section "$positional_section" - PLACEMENT_SECTION="$positional_section" - fi - - require_omarchy_path - widget_is_known "$id" || fail "$id is not a known bar widget; run 'omarchy bar list' to see valid ids" - - local explicit="false" - if [[ -n $PLACEMENT_INDEX || -n $PLACEMENT_BEFORE || -n $PLACEMENT_AFTER || $PLACEMENT_DUPLICATE == true ]]; then - explicit="true" - fi - - if [[ $explicit == "false" ]]; then - # Anchor-based dedupe insert: remove any existing instance across sections, - # then insert after the section anchor (workspaces/weather/tray) — or append - # when the anchor is absent. - local default_section="${PLACEMENT_SECTION:-right}" - commit "$JQ_DEFS $NORMALIZE - | .bar.layout.left = (.bar.layout.left | map(select(entry_id != \$id))) - | .bar.layout.center = (.bar.layout.center | map(select(entry_id != \$id))) - | .bar.layout.right = (.bar.layout.right | map(select(entry_id != \$id))) - | (.bar.layout[\$section] | map(entry_id) | index(\$anchor)) as \$anchorIndex - | .bar.layout[\$section] = ( - if \$anchorIndex == null then .bar.layout[\$section] + [{id: \$id}] - else .bar.layout[\$section][0:\$anchorIndex+1] + [{id: \$id}] + .bar.layout[\$section][\$anchorIndex+1:] end) - " \ - --arg id "$id" \ - --arg section "$default_section" \ - --arg anchor "$(anchor_for_section "$default_section")" - else - local default_section="${PLACEMENT_SECTION:-right}" - local prog - prog=$(cat < 0 )) && [[ $1 != --* ]]; then - id="$1" - shift - fi - parse_placement "$@" - - local prog - prog=$(cat <= 3 )) || fail "bar set requires a value" - shift 3 - local value_is_json="false" - while (( $# > 0 )); do - case "$1" in - --json) value_is_json="true" ;; - -h | --help) usage; exit 0 ;; - *) break ;; - esac - shift - done - parse_placement "$@" - - if [[ $value_is_json == "true" ]]; then - jq -e . <<<"$value" >/dev/null 2>&1 || fail "invalid JSON value: $value" - fi - - local value_arg - if [[ $value_is_json == "true" ]]; then - value_arg=(--argjson value "$value") - else - value_arg=(--arg value "$value") - fi - - local prog - prog=$(cat < [placement] | move [placement] | remove [placement] | set [--json] [placement] | replace +# omarchy:examples=omarchy bar plugin add omarchy.tailscale | omarchy bar plugin add omarchy.clock --section center --before omarchy.weather | omarchy bar plugin move omarchy.clock --section center --index 0 | omarchy bar plugin remove omarchy.tailscale | omarchy bar plugin set omarchy.clock format HH:mm + +set -euo pipefail + +CONFIG_FILE="$HOME/.config/omarchy/shell.json" +OMARCHY_ROOT="${OMARCHY_PATH:-}" +DEFAULTS_FILE="$OMARCHY_ROOT/config/omarchy/shell.json" + +usage() { + cat < [args...] + + add [placement] Add a bar widget + move [placement] [--from-section S --from-index N] + Move a widget within/between sections + remove [placement] (alias: rm, drop) + Remove a widget + set [--json] [placement] + Set a per-widget option + replace Replace the first instance of a widget id + +Placement (for add/move/remove/set): + --section Target section + --index Insert/remove at index in the target section + --before Insert before the first matching widget + --after Insert after the first matching widget + --from-section
Source section (move/remove/set) + --from-index Source index (move/remove/set) + --duplicate add: allow a second instance of the widget + --all remove: remove every matching instance + +Without placement flags, 'add' inserts after the section anchor (workspaces on +left, weather on center, tray on right) and dedupes across sections; 'move' +preserves the source section; 'remove' drops the first match (or every match +with --all). + +Widget ids are listed by 'omarchy plugin list'. + +Examples: + omarchy bar plugin add omarchy.tailscale + omarchy bar plugin add omarchy.clock --section center --before omarchy.weather + omarchy bar plugin move omarchy.clock --section center --index 0 + omarchy bar plugin remove omarchy.tailscale + omarchy bar plugin remove omarchy.tailscale --all + omarchy bar plugin set omarchy.clock format HH:mm + omarchy bar plugin set omarchy.indicators items '["Dnd","NightLight"]' --json +USAGE +} + +fail() { + echo "omarchy-bar-plugin: $*" >&2 + exit 1 +} + +refresh_shell_config() { + if ! omarchy-shell shell reloadConfig >/dev/null 2>&1; then + omarchy-shell -q shell rescanPlugins >/dev/null 2>&1 || true + fi +} + +source_file() { + if [[ -s $CONFIG_FILE ]]; then + printf '%s\n' "$CONFIG_FILE" + else + printf '%s\n' "$DEFAULTS_FILE" + fi +} + +# jq defs shared across mutations. All `def`s come first so the pipeline that +# follows them stays valid jq. `entry_id` and the shape helpers are used by both +# the normalize pipeline and the resolve_target/resolve_source helpers. +JQ_DEFS=' + def object_or_empty: if type == "object" then . else {} end; + def array_or_empty: if type == "array" then . else [] end; + def entry_id: if type == "object" then (.id // "" | tostring) else tostring end; + def anchor_for($section): { left: "omarchy.workspaces", center: "omarchy.weather", right: "omarchy.tray" }[$section]; + def find_all($id; $only): + [ ["left","center","right"][] as $section + | ((.bar.layout[$section] // []) | to_entries[]) + | select((($only == "" or $section == $only)) and ((.value | entry_id) == $id)) + | {section: $section, index: .key, entry: .value} ]; + def entry_at($section; $index): + if $index < 0 or $index >= (.bar.layout[$section] | length) then + error("no widget at " + $section + "[" + ($index | tostring) + "]") + else .bar.layout[$section][$index] end; + def resolve_target($defaultSection): + . as $root + | (if $before != "" or $after != "" then + ($root | find_all($before + $after; $targetSection) | .[0] + // error("could not find target widget " + ($before + $after) + ($targetSection | if . == "" then "" else " in " + . end))) + | .section as $section | (.index + (if $after == "" then 0 else 1 end)) as $index + | {section: $section, index: $index, anchor: false} + elif $targetSection != "" or $targetIndex != "" then + { section: ($targetSection | if . == "" then $defaultSection else . end), + index: (if $targetIndex == "" then null else ($targetIndex | tonumber) end), + anchor: false } + else + { section: $defaultSection, index: null, anchor: true } + end) + | .section as $section + | .index as $rawIndex + | (if $rawIndex == null then + if .anchor then + ($root.bar.layout[$section] | map(entry_id) | index(anchor_for($section))) as $anchorIndex + | if $anchorIndex == null then ($root.bar.layout[$section] | length) else ($anchorIndex + 1) end + else ($root.bar.layout[$section] | length) end + elif $rawIndex > ($root.bar.layout[$section] | length) then ($root.bar.layout[$section] | length) + else $rawIndex end) as $index + | {section: $section, index: $index}; + def resolve_source: + if $fromIndex != "" then + if $fromSection == "" then error("--from-index requires --from-section") + else + ($fromIndex | tonumber) as $index + | entry_at($fromSection; $index) as $entry + | if $widgetId != "" and ($entry | entry_id) != $widgetId then + error("widget at " + $fromSection + "[" + ($index | tostring) + "] is not " + $widgetId) + else {section: $fromSection, index: $index, entry: $entry} end + end + else + (find_all($widgetId; $fromSection) + | if length == 0 then + error("could not find widget " + $widgetId + ($fromSection | if . == "" then "" else " in " + . end)) + else .[0] end) + end; +' + +# jq pipeline that normalizes shell.json into a well-shaped object with +# version=1, bar.layout.{left,center,right} arrays, and plugins array. Every +# mutation pipes through this so downstream jq can assume structure. +NORMALIZE=' + object_or_empty + | .version = 1 + | .bar = (.bar | object_or_empty) + | .bar.layout = (.bar.layout | object_or_empty) + | .bar.layout.left = (.bar.layout.left | array_or_empty) + | .bar.layout.center = (.bar.layout.center | array_or_empty) + | .bar.layout.right = (.bar.layout.right | array_or_empty) + | .plugins = (.plugins | array_or_empty) +' + +# Apply a jq program to the source file and atomically write the result to the +# user config, then refresh the running shell. Extra args after the program are +# forwarded to jq (e.g. --arg/--argjson). +_BAR_TMP="" +cleanup_bar_tmp() { + if [[ -n ${_BAR_TMP:-} ]]; then rm -f "$_BAR_TMP"; fi +} +trap cleanup_bar_tmp EXIT + +commit() { + local program="$1" + shift + mkdir -p "$(dirname "$CONFIG_FILE")" + _BAR_TMP=$(mktemp) + jq -S -e "$@" "$program" "$(source_file)" >"$_BAR_TMP" || fail "could not update shell config" + mv "$_BAR_TMP" "$CONFIG_FILE" + _BAR_TMP="" + refresh_shell_config +} + +validate_section() { + [[ $1 =~ ^(left|center|right)$ ]] || fail "section must be left, center, or right" +} + +validate_index() { + [[ $1 =~ ^[0-9]+$ ]] || fail "index must be a non-negative integer" +} + +widget_is_known() { + omarchy-plugin-catalog | jq -e --arg id "$1" ' + any(.[]; (.kinds | index("bar-widget")) and .id == $id) + ' >/dev/null +} + +# --------------------------------------------------------------------- placement + +# Parse placement flags shared by add/move/remove/set. Sets the globals below. +PLACEMENT_SECTION="" +PLACEMENT_INDEX="" +PLACEMENT_BEFORE="" +PLACEMENT_AFTER="" +PLACEMENT_FROM_SECTION="" +PLACEMENT_FROM_INDEX="" +PLACEMENT_DUPLICATE="false" +PLACEMENT_ALL="false" + +parse_placement() { + while (( $# > 0 )); do + case "$1" in + --section) + PLACEMENT_SECTION="${2:-}" + validate_section "$PLACEMENT_SECTION" + shift 2 + ;; + --index) + PLACEMENT_INDEX="${2:-}" + validate_index "$PLACEMENT_INDEX" + shift 2 + ;; + --before) + PLACEMENT_BEFORE="${2:-}" + [[ -n $PLACEMENT_BEFORE ]] || fail "--before requires a widget id" + shift 2 + ;; + --after) + PLACEMENT_AFTER="${2:-}" + [[ -n $PLACEMENT_AFTER ]] || fail "--after requires a widget id" + shift 2 + ;; + --from-section) + PLACEMENT_FROM_SECTION="${2:-}" + validate_section "$PLACEMENT_FROM_SECTION" + shift 2 + ;; + --from-index) + PLACEMENT_FROM_INDEX="${2:-}" + validate_index "$PLACEMENT_FROM_INDEX" + shift 2 + ;; + --duplicate) + PLACEMENT_DUPLICATE="true" + shift + ;; + --all) + PLACEMENT_ALL="true" + shift + ;; + -h | --help) + usage + exit 0 + ;; + *) + fail "unknown option: $1" + ;; + esac + done + + [[ -z $PLACEMENT_BEFORE || -z $PLACEMENT_AFTER ]] || fail "use only one of --before or --after" +} + +# --------------------------------------------------------------------- commands + +cmd_add() { + local id="${1:-}" + [[ -n $id ]] || fail "add requires a widget id" + shift + + local positional_section="" + while (( $# > 0 )); do + if [[ $1 == --* ]]; then + break + fi + [[ -z $positional_section ]] || fail "unexpected argument: $1" + positional_section="$1" + shift + done + + parse_placement "$@" + [[ -z $positional_section || -z $PLACEMENT_SECTION ]] || fail "specify a section positionally or with --section, not both" + [[ -z $positional_section || -z $PLACEMENT_INDEX ]] || fail "specify a section positionally or use --index, not both" + [[ -z $positional_section || -z $PLACEMENT_BEFORE ]] || fail "specify a section positionally or use --before, not both" + [[ -z $positional_section || -z $PLACEMENT_AFTER ]] || fail "specify a section positionally or use --after, not both" + [[ -z $positional_section || ( $PLACEMENT_DUPLICATE == false ) ]] || fail "--duplicate needs explicit placement flags" + if [[ -n $positional_section ]]; then + validate_section "$positional_section" + PLACEMENT_SECTION="$positional_section" + fi + + widget_is_known "$id" || fail "$id is not a known bar widget; run 'omarchy plugin list' to see valid ids" + + local default_section="${PLACEMENT_SECTION:-right}" + local explicit="false" + if [[ -n $PLACEMENT_INDEX || -n $PLACEMENT_BEFORE || -n $PLACEMENT_AFTER || $PLACEMENT_DUPLICATE == true ]]; then + explicit="true" + fi + + if [[ $explicit == "false" ]]; then + # Anchor-based dedupe insert: remove any existing instance across sections, + # then insert after the section anchor (workspaces/weather/tray) — or append + # when the anchor is absent. + commit "$JQ_DEFS $NORMALIZE + | .bar.layout.left = (.bar.layout.left | map(select(entry_id != \$id))) + | .bar.layout.center = (.bar.layout.center | map(select(entry_id != \$id))) + | .bar.layout.right = (.bar.layout.right | map(select(entry_id != \$id))) + | (.bar.layout[\$section] | map(entry_id) | index(anchor_for(\$section))) as \$anchorIndex + | .bar.layout[\$section] = ( + if \$anchorIndex == null then .bar.layout[\$section] + [{id: \$id}] + else .bar.layout[\$section][0:\$anchorIndex+1] + [{id: \$id}] + .bar.layout[\$section][\$anchorIndex+1:] end) + " \ + --arg id "$id" \ + --arg section "$default_section" + else + local prog + prog=$(cat < 0 )) && [[ $1 != --* ]]; then + id="$1" + shift + fi + parse_placement "$@" + + local prog + prog=$(cat <= 3 )) || fail "set requires a value" + shift 3 + local value_is_json="false" + while (( $# > 0 )); do + case "$1" in + --json) value_is_json="true" ;; + -h | --help) usage; exit 0 ;; + *) break ;; + esac + shift + done + parse_placement "$@" + + if [[ $value_is_json == "true" ]]; then + jq -e . <<<"$value" >/dev/null 2>&1 || fail "invalid JSON value: $value" + fi + + local value_arg + if [[ $value_is_json == "true" ]]; then + value_arg=(--argjson value "$value") + else + value_arg=(--arg value "$value") + fi + + local prog + prog=$(cat < -# omarchy:examples=omarchy-bar-position top | omarchy bar position bottom - -set -e - -CONFIG_FILE="$HOME/.config/omarchy/shell.json" -DEFAULTS_FILE="$OMARCHY_PATH/config/omarchy/shell.json" -position=$1 - -if [[ ! $position =~ ^(top|bottom|left|right)$ ]]; then - echo "Usage: omarchy-bar-position top|bottom|left|right" >&2 - exit 1 -fi - -mkdir -p "$(dirname "$CONFIG_FILE")" -tmp=$(mktemp) - -# Seed from the default shell.json when the user has no shell.json yet (or it's -# malformed). Writing just `{ bar: { position } }` would leave the bar with -# no layout, since the shell treats any valid user config as authoritative -# and does not deep-merge defaults. -if [[ -s $CONFIG_FILE ]] && jq -e 'type == "object"' "$CONFIG_FILE" >/dev/null 2>&1; then - source="$CONFIG_FILE" -else - source="$DEFAULTS_FILE" -fi - -jq --arg position "$position" ' - .version = 1 | - .bar = ((.bar // {}) | if type == "object" then . else {} end) | - .bar.position = $position -' "$source" >"$tmp" - -mv "$tmp" "$CONFIG_FILE" diff --git a/bin/omarchy-install-service-dropbox b/bin/omarchy-install-service-dropbox index fd5b647d..169c0623 100755 --- a/bin/omarchy-install-service-dropbox +++ b/bin/omarchy-install-service-dropbox @@ -6,7 +6,7 @@ echo "Installing all dependencies..." omarchy-pkg-add dropbox dropbox-cli libappindicator-gtk3 python-gpgme nautilus-dropbox echo "Adding Dropbox to the bar..." -omarchy-bar add omarchy.dropbox +omarchy-bar-plugin add omarchy.dropbox echo "Starting Dropbox..." uwsm-app -- dropbox-cli start &>/dev/null & diff --git a/bin/omarchy-install-service-tailscale b/bin/omarchy-install-service-tailscale index b1b84ecf..8adffc53 100755 --- a/bin/omarchy-install-service-tailscale +++ b/bin/omarchy-install-service-tailscale @@ -14,6 +14,6 @@ echo -e "\nAllowing $USER to manage Tailscale..." sudo tailscale set --operator="$USER" echo -e "\nAdding Tailscale to the bar..." -omarchy-bar add omarchy.tailscale +omarchy-bar-plugin add omarchy.tailscale omarchy-webapp-install "Tailscale" "https://login.tailscale.com/admin/machines" https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/tailscale-light.png diff --git a/bin/omarchy-plugin b/bin/omarchy-plugin index 4bcac55a..339a7d01 100755 --- a/bin/omarchy-plugin +++ b/bin/omarchy-plugin @@ -2,8 +2,8 @@ # omarchy:summary=Manage Omarchy shell plugins and bar widgets # omarchy:group=plugin -# omarchy:args= [...] -# omarchy:examples=omarchy plugin list | omarchy plugin add https://github.com/acme/omarchy-weather.git | omarchy plugin update --all | omarchy plugin clone omarchy.clock local.clock | omarchy plugin bar settings +# omarchy:args= [...] +# omarchy:examples=omarchy plugin list | omarchy plugin add https://github.com/acme/omarchy-weather.git | omarchy plugin update --all | omarchy plugin clone omarchy.clock local.clock set -euo pipefail @@ -36,10 +36,7 @@ Make your own: edit [id] Open a user plugin directory in a shell validate Check a plugin's manifest (for authors) -Bar commands (delegate to 'omarchy bar'; run 'omarchy bar --help' for details): - bar settings Open the inline bar config panel - bar list|layout|options|use|reset|add|move|remove|set|position|transparent - widget|widgets Alias of 'bar list' +Bar widgets are placed in the layout with 'omarchy bar plugin'. Examples: omarchy plugin add https://github.com/acme/omarchy-weather.git --enable @@ -169,7 +166,7 @@ plugin_enabled() { [[ $result == "ok" ]] || fail "plugin '$id' is not known; run: omarchy plugin rescan" if [[ $enabled == "true" && $# -gt 0 ]]; then - omarchy-bar move "$id" "$@" + omarchy-bar-plugin move "$id" "$@" echo "Enabled and moved $id" elif [[ $enabled == "true" ]]; then echo "Enabled $id" @@ -460,26 +457,6 @@ plugin_edit() { printf '%s\n' "$dir" } -# ---------------------------------------------------------------- bar - -bar_command() { - local command="${1:-list}" - [[ $# -gt 0 ]] && shift || true - - case "$command" in - edit | settings) - (( $# == 0 )) || fail "bar settings does not take arguments" - exec omarchy-launch-bar-settings - ;; - -h | --help | help) - usage - ;; - *) - exec omarchy-bar "$command" "$@" - ;; - esac -} - command="${1:-}" case "$command" in list | ls) @@ -522,10 +499,6 @@ validate) shift exec omarchy-plugin-validate "$@" ;; -bar | widget | widgets) - shift - bar_command "$@" - ;; -h | --help | help | "") usage ;; diff --git a/bin/omarchy-plugin-catalog b/bin/omarchy-plugin-catalog index f9e7148d..c526be21 100755 --- a/bin/omarchy-plugin-catalog +++ b/bin/omarchy-plugin-catalog @@ -7,9 +7,10 @@ # Walks $OMARCHY_PATH/shell/plugins and ~/.config/omarchy/plugins, reads every # manifest.json / *.manifest.json, and emits one JSON object per plugin with # computed fields (sourceDir, barWidgetPath, barPath, firstParty). This is the -# single source of truth that omarchy-bar (widget/option enumeration and add -# validation) and omarchy-plugin-clone (source enumeration) read, so the bar -# and plugin commands never re-implement manifest walking. +# single source of truth that omarchy-bar (widget/option enumeration), +# omarchy-bar-plugin (add validation), and omarchy-plugin-clone (source +# enumeration) read, so the bar and plugin commands never re-implement +# manifest walking. set -o pipefail diff --git a/bin/omarchy-plugin-clone b/bin/omarchy-plugin-clone index 959bbc8d..7ed4f7b9 100755 --- a/bin/omarchy-plugin-clone +++ b/bin/omarchy-plugin-clone @@ -341,10 +341,10 @@ clone_command() { omarchy-shell -q shell rescanPlugins >/dev/null 2>&1 || true if [[ $replace == "true" ]]; then - omarchy-bar replace "$source_id" "$new_id" + omarchy-bar-plugin replace "$source_id" "$new_id" echo "Cloned $source_id to $new_id and replaced the first bar instance" elif [[ $add == "true" ]]; then - omarchy-bar add "$new_id" "${placement[@]}" + omarchy-bar-plugin add "$new_id" "${placement[@]}" echo "Cloned $source_id to $new_id" elif [[ $use_bar == "true" ]]; then omarchy-bar use "$new_id" diff --git a/bin/omarchy-remove-service-dropbox b/bin/omarchy-remove-service-dropbox index c7922ad6..0480017e 100644 --- a/bin/omarchy-remove-service-dropbox +++ b/bin/omarchy-remove-service-dropbox @@ -4,7 +4,7 @@ # omarchy:requires-sudo=true dropbox-cli stop 2>/dev/null || true -omarchy-bar drop omarchy.dropbox +omarchy-bar-plugin remove omarchy.dropbox omarchy-pkg-drop dropbox dropbox-cli libappindicator-gtk3 python-gpgme nautilus-dropbox echo "" diff --git a/bin/omarchy-remove-service-tailscale b/bin/omarchy-remove-service-tailscale index f484d5e6..acda106e 100644 --- a/bin/omarchy-remove-service-tailscale +++ b/bin/omarchy-remove-service-tailscale @@ -5,7 +5,7 @@ tailscale down 2>/dev/null || true sudo systemctl disable --now tailscaled.service 2>/dev/null || true -omarchy-bar drop omarchy.tailscale +omarchy-bar-plugin remove omarchy.tailscale omarchy-webapp-remove "Tailscale" 2>/dev/null || true omarchy-pkg-drop tailscale diff --git a/default/hypr/bindings/utilities.lua b/default/hypr/bindings/utilities.lua index f04ff2b1..ca6e95ff 100644 --- a/default/hypr/bindings/utilities.lua +++ b/default/hypr/bindings/utilities.lua @@ -12,10 +12,10 @@ o.bind("SUPER + ALT + K", "Show Tmux key bindings", "omarchy-menu-tmux-keybindin o.bind("XF86Calculator", "Calculator", "gnome-calculator") o.bind_toggle("SUPER + SHIFT + SPACE", "Toggle top bar", "bar") -o.bind("SUPER + SHIFT + CTRL + UP", "Move bar to top", "omarchy-bar-position top") -o.bind("SUPER + SHIFT + CTRL + DOWN", "Move bar to bottom", "omarchy-bar-position bottom") -o.bind("SUPER + SHIFT + CTRL + LEFT", "Move bar to left", "omarchy-bar-position left") -o.bind("SUPER + SHIFT + CTRL + RIGHT", "Move bar to right", "omarchy-bar-position right") +o.bind("SUPER + SHIFT + CTRL + UP", "Move bar to top", "omarchy-bar position top") +o.bind("SUPER + SHIFT + CTRL + DOWN", "Move bar to bottom", "omarchy-bar position bottom") +o.bind("SUPER + SHIFT + CTRL + LEFT", "Move bar to left", "omarchy-bar position left") +o.bind("SUPER + SHIFT + CTRL + RIGHT", "Move bar to right", "omarchy-bar position right") o.bind("SUPER + CTRL + SPACE", "Background switcher", "omarchy-menu toggle background") o.bind("SUPER + SHIFT + CTRL + SPACE", "Theme menu", "omarchy-menu toggle theme") o.bind("SUPER + BACKSPACE", "Toggle window transparency", "omarchy-hyprland-window-transparency-toggle") diff --git a/default/omarchy/omarchy-menu.jsonc b/default/omarchy/omarchy-menu.jsonc index c58993fb..cea78914 100644 --- a/default/omarchy/omarchy-menu.jsonc +++ b/default/omarchy/omarchy-menu.jsonc @@ -95,10 +95,10 @@ "style.screensaver": {"icon":"󱄄","label":"Screensaver","keywords":"branding"}, "style.about": {"icon":"","label":"About","keywords":"branding"}, "style.install": {"icon":"󰉉","label":"Install","keywords":"theme background font"}, - "style.bar.top": {"icon":"󰁝","label":"Top","keywords":"position","action":"omarchy-bar-position top"}, - "style.bar.bottom": {"icon":"󰁅","label":"Bottom","keywords":"position","action":"omarchy-bar-position bottom"}, - "style.bar.left": {"icon":"󰁍","label":"Left","keywords":"position","action":"omarchy-bar-position left"}, - "style.bar.right": {"icon":"󰁔","label":"Right","keywords":"position","action":"omarchy-bar-position right"}, + "style.bar.top": {"icon":"󰁝","label":"Top","keywords":"position","action":"omarchy-bar position top"}, + "style.bar.bottom": {"icon":"󰁅","label":"Bottom","keywords":"position","action":"omarchy-bar position bottom"}, + "style.bar.left": {"icon":"󰁍","label":"Left","keywords":"position","action":"omarchy-bar position left"}, + "style.bar.right": {"icon":"󰁔","label":"Right","keywords":"position","action":"omarchy-bar position right"}, "style.about.text": {"icon":"","label":"Edit Text","keywords":"branding","action":"omarchy-branding-about text"}, "style.about.image": {"icon":"","label":"Set From Image","keywords":"branding","action":"omarchy-branding-about image"}, "style.about.default": {"icon":"","label":"Restore Default","keywords":"branding","action":"omarchy-branding-about reset"}, diff --git a/docs/omarchy-shell.md b/docs/omarchy-shell.md index 0b27413f..c1c7ae0d 100644 --- a/docs/omarchy-shell.md +++ b/docs/omarchy-shell.md @@ -60,7 +60,7 @@ arguments — add `--yes` to skip every prompt (the path for scripts and agents) You can still install by hand: drop a plugin into `~/.config/omarchy/plugins//`, run `omarchy plugin rescan`, then -`omarchy plugin enable ` (bar widgets also need `omarchy bar add `; +`omarchy plugin enable ` (bar widgets also need `omarchy bar plugin add `; full bar replacements are selected with `omarchy bar use `). The lower-level IPC methods remain available through `omarchy-shell shell ...`. diff --git a/shell/README.md b/shell/README.md index 1917e7e8..b2c76d17 100644 --- a/shell/README.md +++ b/shell/README.md @@ -131,7 +131,7 @@ You can still drop a plugin in without git: 1. Put it in `~/.config/omarchy/plugins//` with a `manifest.json` plus the QML referenced from its `entryPoints`. 2. `omarchy plugin rescan`. -3. `omarchy plugin enable ` (bar widgets also need `omarchy bar add `; full bar replacements are selected with `omarchy bar use `). +3. `omarchy plugin enable ` (bar widgets also need `omarchy bar plugin add `; full bar replacements are selected with `omarchy bar use `). The lower-level IPC equivalents remain available via `omarchy-shell shell rescanPlugins`, `omarchy-shell shell setPluginEnabled true`, and `omarchy-shell shell listPlugins`. diff --git a/shell/plugins/bar/README.md b/shell/plugins/bar/README.md index 723f5ee7..df26874c 100644 --- a/shell/plugins/bar/README.md +++ b/shell/plugins/bar/README.md @@ -10,13 +10,13 @@ the shell for its whole session. - `widgets/` holds simple first-party bar widgets with sibling manifests. - Feature plugins such as `../panels/audio/`, `../panels/network/`, `../panels/power/`, and `../model-usage/` provide richer popup bar plugins. - The bar receives its config from the host shell as a `barConfig` property; the host loads it from `~/.config/omarchy/shell.json` (or `config/omarchy/shell.json` when the user has no file). -- `omarchy-bar-position` updates only the user shell.json file. +- `omarchy bar position` updates only the user shell.json file. ## Customizing 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 inline bar config panel, `omarchy bar ...`, or by editing shell.json directly, your file is canonical — there is no deep-merge. -Open quick position and transparency controls with `omarchy bar settings` (or run `omarchy-launch-bar-settings`). You can also hover the centered clock module to reveal the inline bar config button. For scriptable widget changes, use `omarchy bar list`, `omarchy bar add`, `omarchy bar move`, `omarchy bar remove`, and `omarchy bar set`. Double-left-click empty center-bar space to toggle bar transparency. +Open quick position and transparency controls with `omarchy bar settings` (or run `omarchy-launch-bar-settings`). You can also hover the centered clock module to reveal the inline bar config button. 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`). Double-left-click empty center-bar space to toggle bar transparency. Example `shell.json` (bar subtree only shown): @@ -181,4 +181,4 @@ Third-party widgets ship as separate plugins under 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 plugin rescan`, and `omarchy bar add`. +`omarchy plugin rescan`, and `omarchy bar plugin add`. diff --git a/shell/plugins/panels/tailscale/README.md b/shell/plugins/panels/tailscale/README.md index aca6139f..cb54f50a 100644 --- a/shell/plugins/panels/tailscale/README.md +++ b/shell/plugins/panels/tailscale/README.md @@ -35,4 +35,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 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 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. diff --git a/test/shell.d/config-test.sh b/test/shell.d/config-test.sh index ae6f2316..1ec97c9f 100755 --- a/test/shell.d/config-test.sh +++ b/test/shell.d/config-test.sh @@ -208,11 +208,10 @@ cat >"$TMPDIR/home/.config/omarchy/plugins/local.demo-bar/manifest.json" <<'JSON JSON touch "$TMPDIR/home/.config/omarchy/plugins/local.demo-bar/Bar.qml" -HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-bar options --json | jq -e ' - any(.[]; .id == "omarchy.bar" and .active == true) and - any(.[]; .id == "local.demo-bar" and .active == false) -' >/dev/null -pass "shell config lists bar options" +if HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-bar use local.nonexistent-bar 2>/dev/null; then + fail "bar use accepted an unknown bar option" +fi +pass "bar use rejects an unknown bar option" HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-bar use local.demo-bar jq -e '.bar.id == "local.demo-bar"' "$TMPDIR/home/.config/omarchy/shell.json" >/dev/null @@ -222,52 +221,38 @@ HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-bar reset jq -e '.bar.id == null' "$TMPDIR/home/.config/omarchy/shell.json" >/dev/null pass "shell config resets to built-in bar option" -HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-bar add omarchy.tailscale +HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-bar-plugin add omarchy.tailscale jq -e ' def ids: map(.id // .); .bar.layout.right | ids == ["omarchy.tray", "omarchy.tailscale", "omarchy.bluetooth"] ' "$TMPDIR/home/.config/omarchy/shell.json" >/dev/null pass "shell config appends widgets to right by default" -HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-bar add omarchy.active-window left +HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-bar-plugin add omarchy.active-window left jq -e ' def ids: map(.id // .); .bar.layout.left | ids == ["omarchy.menu", "omarchy.workspaces", "omarchy.active-window"] ' "$TMPDIR/home/.config/omarchy/shell.json" >/dev/null pass "shell config appends left widgets after workspaces" -HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-bar add omarchy.system-update center +HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-bar-plugin add omarchy.system-update center jq -e ' def ids: map(.id // .); .bar.layout.center | ids == ["omarchy.clock", "omarchy.weather", "omarchy.system-update"] ' "$TMPDIR/home/.config/omarchy/shell.json" >/dev/null pass "shell config appends center widgets after weather" -HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-bar add omarchy.microphone right +HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-bar-plugin add omarchy.microphone right jq -e ' def ids: map(.id // .); .bar.layout.right | ids == ["omarchy.tray", "omarchy.microphone", "omarchy.tailscale", "omarchy.bluetooth"] ' "$TMPDIR/home/.config/omarchy/shell.json" >/dev/null pass "shell config moves existing widgets without duplicates" -HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-bar show | jq -e ' - def ids: map(.id // .); - (.layout.right | ids == ["omarchy.tray", "omarchy.microphone", "omarchy.tailscale", "omarchy.bluetooth"]) and - has("version") | not -' >/dev/null -pass "shell config shows only bar json" - -HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-bar list --json | jq -e ' - any(.[]; .id == "omarchy.keyboard-layout" and .addable == true and .inBar == false) and - all(.[]; .id != "omarchy.tailscale") -' >/dev/null -pass "shell config lists addable bar widgets" - -HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-bar list --json --all | jq -e ' - any(.[]; .id == "omarchy.tailscale" and .inBar == true and .addable == false) and - any(.[]; .id == "omarchy.indicators" and .addable == true) -' >/dev/null -pass "shell config list --all includes current widget status" +if HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-bar-plugin add local.nonexistent-widget 2>/dev/null; then + fail "bar plugin add accepted an unknown widget" +fi +pass "bar plugin add rejects an unknown widget" HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-bar position bottom jq -e ' @@ -284,7 +269,7 @@ jq -e ' ' "$TMPDIR/home/.config/omarchy/shell.json" >/dev/null pass "shell config sets bar transparency" -HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-bar drop omarchy.active-window +HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-bar-plugin drop omarchy.active-window jq -e ' def ids: map(.id // .); (.bar.layout.left | ids == ["omarchy.menu", "omarchy.workspaces"]) and @@ -293,7 +278,7 @@ jq -e ' ' "$TMPDIR/home/.config/omarchy/shell.json" >/dev/null pass "shell config drops widgets from any section" -HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-bar remove omarchy.system-update +HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-bar-plugin remove omarchy.system-update jq -e ' def ids: map(.id // .); .bar.layout.center | ids == ["omarchy.clock", "omarchy.weather"] diff --git a/test/shell.d/runtime-smoke-test.sh b/test/shell.d/runtime-smoke-test.sh index 998b85b5..d2b38c4b 100755 --- a/test/shell.d/runtime-smoke-test.sh +++ b/test/shell.d/runtime-smoke-test.sh @@ -220,7 +220,7 @@ for panel_id in omarchy.audio omarchy.bluetooth omarchy.monitor omarchy.network done pass "direct panel IPC opens and closes default panels" -HOME="$test_home" OMARCHY_PATH="$test_root" PATH="$ROOT/bin:$PATH" "$ROOT/bin/omarchy-bar" remove omarchy.audio +HOME="$test_home" OMARCHY_PATH="$test_root" PATH="$ROOT/bin:$PATH" "$ROOT/bin/omarchy-bar-plugin" remove omarchy.audio for _ in {1..80}; do shell_config=$(shell_ipc shell listShellConfig 2>/dev/null || true)