mirror of
https://github.com/arthur-pbty/arthur-os.git
synced 2026-08-01 20:28:16 +02:00
822 lines
20 KiB
Bash
Executable File
822 lines
20 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# omarchy:summary=Launch the Quickshell Omarchy menu or jump straight to a submenu/action
|
|
# omarchy:args=[menu-or-action|--json|--provider <provider> [menu-id]]
|
|
# omarchy:examples=omarchy menu | omarchy menu setup | omarchy menu style.theme | omarchy menu --json | omarchy menu --provider fonts style.font
|
|
|
|
set -o pipefail
|
|
|
|
OMARCHY_PATH=${OMARCHY_PATH:-$HOME/.local/share/omarchy}
|
|
DEFAULT_MENU="$OMARCHY_PATH/default/omarchy/omarchy-menu.jsonc"
|
|
USER_MENU="$HOME/.config/omarchy/extensions/omarchy-menu.jsonc"
|
|
|
|
# Menu hooks users may edit
|
|
# Menu rows live in default/omarchy/omarchy-menu.jsonc.
|
|
# Keep Bash here only for multi-step actions or truly runtime-generated lists.
|
|
|
|
# Action helpers available to omarchy-menu.jsonc
|
|
|
|
terminal() {
|
|
xdg-terminal-exec --app-id=org.omarchy.terminal "$@"
|
|
}
|
|
|
|
present_terminal() {
|
|
omarchy-launch-floating-terminal-with-presentation "$*"
|
|
}
|
|
|
|
open_in_editor() {
|
|
omarchy-notification-send -u low "Editing config file" "$1"
|
|
omarchy-launch-editor "$1"
|
|
}
|
|
|
|
hypr_config_file() {
|
|
local name="$1"
|
|
printf '%s/.config/hypr/%s.lua' "$HOME" "$name"
|
|
}
|
|
|
|
install() {
|
|
present_terminal "echo 'Installing $1...'; omarchy-pkg-add $2"
|
|
}
|
|
|
|
install_and_launch() {
|
|
present_terminal "echo 'Installing $1...'; omarchy-pkg-add $2 && setsid gtk-launch $3"
|
|
}
|
|
|
|
install_font() {
|
|
present_terminal "echo 'Installing $1...'; omarchy-pkg-add $2 && sleep 2 && omarchy-font-set '$3'"
|
|
}
|
|
|
|
install_terminal() {
|
|
present_terminal "omarchy-install-terminal $1"
|
|
}
|
|
|
|
show_custom_reminder_input() {
|
|
local minutes
|
|
minutes=$(omarchy-menu-input "Remind in minutes")
|
|
|
|
if [[ $minutes =~ ^[0-9]+$ ]] && (( minutes > 0 )); then
|
|
show_reminder_message_input "$minutes"
|
|
elif [[ -n $minutes ]]; then
|
|
omarchy-notification-send -g "Invalid reminder" "Enter the number of minutes" -u critical
|
|
show_custom_reminder_input
|
|
fi
|
|
}
|
|
|
|
show_reminder_message_input() {
|
|
local minutes="$1"
|
|
local message
|
|
message=$(omarchy-menu-input "Reminder message")
|
|
|
|
if [[ -n $message ]]; then
|
|
omarchy-reminder "$minutes" "$message"
|
|
else
|
|
omarchy-reminder "$minutes"
|
|
fi
|
|
}
|
|
|
|
get_webcam_list() {
|
|
v4l2-ctl --list-devices 2>/dev/null | while IFS= read -r line; do
|
|
if [[ $line != $'\t'* && -n $line ]]; then
|
|
local name="$line"
|
|
local device
|
|
IFS= read -r device || break
|
|
device=$(tr -d '\t' <<<"$device" | head -1)
|
|
[[ -n $device ]] && echo "$device $name"
|
|
fi
|
|
done
|
|
}
|
|
|
|
show_webcam_select_menu() {
|
|
local devices
|
|
local count
|
|
devices=$(get_webcam_list)
|
|
if [[ -z $devices ]]; then
|
|
count=0
|
|
else
|
|
count=$(grep -c . <<<"$devices")
|
|
fi
|
|
|
|
if [[ -z $devices ]] || (( count == 0 )); then
|
|
omarchy-notification-send "No webcam devices found" -u critical -t 3000
|
|
return 1
|
|
fi
|
|
|
|
if (( count == 1 )); then
|
|
printf '%s\n' "${devices%%[[:space:]]*}"
|
|
else
|
|
local selection
|
|
selection=$(omarchy-menu-select "Select Webcam" "$devices") || return 1
|
|
printf '%s\n' "${selection%%[[:space:]]*}"
|
|
fi
|
|
}
|
|
|
|
stop_active_screenrecording() {
|
|
omarchy-capture-screenrecording --stop-recording
|
|
}
|
|
|
|
screenrecord_with_webcam() {
|
|
local device
|
|
device=$(show_webcam_select_menu) || return 1
|
|
omarchy-capture-screenrecording --with-desktop-audio --with-microphone-audio --with-webcam --webcam-device="$device"
|
|
}
|
|
|
|
|
|
# Runtime-generated providers users may edit
|
|
# Use provider:"fonts" only when a submenu calls provider_fonts (or a command)
|
|
# to return JSON. Normal submenus are inferred from dotted JSONC ids.
|
|
|
|
provider_fonts() {
|
|
local menu_id="$1"
|
|
local current_font
|
|
local index=0
|
|
local font
|
|
local label
|
|
current_font=$(omarchy-font-current 2>/dev/null)
|
|
|
|
while IFS= read -r font; do
|
|
[[ -n $font ]] || continue
|
|
(( index++ ))
|
|
label="$font$(current_marker "$font" "$current_font")"
|
|
json_item "$menu_id.$index-$(slugify "$font")" "" "$label" "omarchy-font-set $(shell_quote "$font")" "$font typeface"
|
|
done < <(omarchy-font-list 2>/dev/null)
|
|
}
|
|
|
|
provider_power_profiles() {
|
|
local menu_id="$1"
|
|
local current_profile
|
|
local profile
|
|
current_profile=$(powerprofilesctl get 2>/dev/null)
|
|
|
|
while IFS= read -r profile; do
|
|
[[ -n $profile ]] || continue
|
|
json_item "$menu_id.$(slugify "$profile")" "" "$profile$(current_marker "$profile" "$current_profile")" "powerprofilesctl set $(shell_quote "$profile")" "$profile power profile"
|
|
done < <(omarchy-powerprofiles-list 2>/dev/null)
|
|
}
|
|
|
|
|
|
# Framework helpers below this line
|
|
# Most menu changes should not require editing below here.
|
|
|
|
# Generic helpers
|
|
|
|
shell_quote() {
|
|
printf "'%s'" "${1//\'/\'\\\'\'}"
|
|
}
|
|
|
|
slugify() {
|
|
local value="${1,,}"
|
|
value="${value//[^a-z0-9]/-}"
|
|
|
|
while [[ $value == *--* ]]; do
|
|
value="${value//--/-}"
|
|
done
|
|
|
|
while [[ $value == -* ]]; do
|
|
value="${value#-}"
|
|
done
|
|
|
|
while [[ $value == *- ]]; do
|
|
value="${value%-}"
|
|
done
|
|
|
|
printf '%s' "${value:-item}"
|
|
}
|
|
|
|
current_marker() {
|
|
if [[ $1 == $2 ]]; then
|
|
printf ' ✓'
|
|
fi
|
|
}
|
|
|
|
declare -A CMD_PRESENT_CACHE=()
|
|
declare -A STATUS_CACHE=()
|
|
|
|
cached_status() {
|
|
local key="$1"
|
|
shift
|
|
|
|
if [[ -z ${STATUS_CACHE[$key]+x} ]]; then
|
|
"$@" >/dev/null 2>&1
|
|
STATUS_CACHE[$key]=$?
|
|
fi
|
|
|
|
return "${STATUS_CACHE[$key]}"
|
|
}
|
|
|
|
omarchy-cmd-present() {
|
|
local cmd
|
|
|
|
for cmd in "$@"; do
|
|
if [[ -z ${CMD_PRESENT_CACHE[$cmd]+x} ]]; then
|
|
if command -v "$cmd" >/dev/null 2>&1; then
|
|
CMD_PRESENT_CACHE[$cmd]=0
|
|
else
|
|
CMD_PRESENT_CACHE[$cmd]=1
|
|
fi
|
|
fi
|
|
|
|
(( CMD_PRESENT_CACHE[$cmd] == 0 )) || return 1
|
|
done
|
|
|
|
return 0
|
|
}
|
|
|
|
omarchy-toggle-enabled() {
|
|
cached_status "toggle:$*" command omarchy-toggle-enabled "$@"
|
|
}
|
|
|
|
omarchy-hibernation-available() {
|
|
cached_status hibernation command omarchy-hibernation-available
|
|
}
|
|
|
|
omarchy-hw-hybrid-gpu() {
|
|
cached_status hw-hybrid-gpu command omarchy-hw-hybrid-gpu
|
|
}
|
|
|
|
omarchy-hw-touchpad() {
|
|
cached_status hw-touchpad command omarchy-hw-touchpad
|
|
}
|
|
|
|
omarchy-hw-touchscreen() {
|
|
cached_status hw-touchscreen command omarchy-hw-touchscreen
|
|
}
|
|
|
|
omarchy-hw-dell-xps-haptic-touchpad() {
|
|
cached_status hw-dell-xps-haptic-touchpad command omarchy-hw-dell-xps-haptic-touchpad
|
|
}
|
|
|
|
default_browser_is() {
|
|
if [[ -z ${DEFAULT_BROWSER_CACHE+x} ]]; then
|
|
DEFAULT_BROWSER_CACHE=$(command omarchy-default-browser 2>/dev/null || true)
|
|
fi
|
|
|
|
[[ $DEFAULT_BROWSER_CACHE == "$1" ]]
|
|
}
|
|
|
|
default_terminal_is() {
|
|
if [[ -z ${DEFAULT_TERMINAL_CACHE+x} ]]; then
|
|
DEFAULT_TERMINAL_CACHE=$(command omarchy-default-terminal 2>/dev/null || true)
|
|
fi
|
|
|
|
[[ $DEFAULT_TERMINAL_CACHE == "$1" ]]
|
|
}
|
|
|
|
default_editor_is() {
|
|
if [[ -z ${DEFAULT_EDITOR_CACHE+x} ]]; then
|
|
DEFAULT_EDITOR_CACHE=$(command omarchy-default-editor 2>/dev/null || true)
|
|
fi
|
|
|
|
[[ $DEFAULT_EDITOR_CACHE == "$1" ]]
|
|
}
|
|
|
|
haptic_touchpad_is() {
|
|
if [[ -z ${HAPTIC_TOUCHPAD_CACHE+x} ]]; then
|
|
HAPTIC_TOUCHPAD_CACHE=$(command dell-xps-touchpad-haptics get 2>/dev/null || true)
|
|
fi
|
|
|
|
[[ $HAPTIC_TOUCHPAD_CACHE == "$1" ]]
|
|
}
|
|
|
|
json_string() {
|
|
local value="${1-}"
|
|
value="${value//\\/\\\\}"
|
|
value="${value//\"/\\\"}"
|
|
value="${value//$'\t'/\\t}"
|
|
value="${value//$'\r'/\\r}"
|
|
value="${value//$'\n'/\\n}"
|
|
printf '"%s"' "$value"
|
|
}
|
|
|
|
json_item() {
|
|
local id="$1"
|
|
local icon="$2"
|
|
local label="$3"
|
|
local action="${4:-}"
|
|
local keywords="${5:-}"
|
|
local description="${6:-}"
|
|
local target="${7:-}"
|
|
local provider="${8:-}"
|
|
|
|
printf '{"id": '
|
|
json_string "$id"
|
|
printf ', "icon": '
|
|
json_string "$icon"
|
|
printf ', "label": '
|
|
json_string "$label"
|
|
|
|
if [[ -n $action ]]; then
|
|
printf ', "action": '
|
|
json_string "$action"
|
|
fi
|
|
|
|
if [[ -n $keywords ]]; then
|
|
printf ', "keywords": '
|
|
json_string "$keywords"
|
|
fi
|
|
|
|
if [[ -n $description ]]; then
|
|
printf ', "description": '
|
|
json_string "$description"
|
|
fi
|
|
|
|
if [[ -n $target ]]; then
|
|
printf ', "target": '
|
|
json_string "$target"
|
|
fi
|
|
|
|
if [[ -n $provider ]]; then
|
|
printf ', "provider": '
|
|
json_string "$provider"
|
|
fi
|
|
|
|
printf '}\n'
|
|
}
|
|
|
|
|
|
# Menu definition loading
|
|
menu_sources() {
|
|
local path
|
|
|
|
for path in "$DEFAULT_MENU" "$USER_MENU"; do
|
|
[[ -f $path ]] || continue
|
|
jq -Rrs '
|
|
# Our menu files are JSONC: full-line // comments plus trailing commas.
|
|
# Keep parsing in jq so the menu build path stays fast and dependency-free.
|
|
gsub("(?m)^\\s*//[^\\n]*(\\n|$)"; "") |
|
|
gsub(",(?<tail>\\s*[}\\]])"; "\(.tail)") |
|
|
fromjson |
|
|
if type == "object" then
|
|
(if has("items") and (.items | type) == "object" then .items else . end)
|
|
else
|
|
{}
|
|
end |
|
|
to_entries[] |
|
|
select(.value | type == "object") |
|
|
.value + { id: .key }
|
|
' "$path"
|
|
done
|
|
}
|
|
|
|
normalize_menu_json() {
|
|
jq -sc '
|
|
def aliases_array:
|
|
if ((.aliases // []) | type) == "array" then (.aliases // [])
|
|
elif ((.aliases // "") != "") then [(.aliases // "")]
|
|
else [] end;
|
|
|
|
def normalize_item:
|
|
def inferred_parent:
|
|
if has("parent") then .parent
|
|
elif (.id | contains(".")) then (.id | split(".")[:-1] | join("."))
|
|
else "root" end;
|
|
|
|
def inferred_kind:
|
|
if ((.action // "") != "") then "action"
|
|
elif ((.target // "") != "") then "link"
|
|
else "menu" end;
|
|
|
|
def id_keywords:
|
|
.id | gsub("[._-]+"; " ");
|
|
|
|
def alias_keywords:
|
|
aliases_array | map(gsub("[._-]+"; " ")) | join(" ");
|
|
|
|
def keyword_string:
|
|
([id_keywords, alias_keywords, (.keywords // "")] | join(" ") | split(" ") | map(select(. != ""))) as $terms |
|
|
reduce $terms[] as $term ([]; if index($term) then . else . + [$term] end) |
|
|
join(" ");
|
|
|
|
{
|
|
id,
|
|
parent: (if .id == "root" then "" else inferred_parent end),
|
|
kind: inferred_kind,
|
|
icon: (.icon // ""),
|
|
label: (.label // .id),
|
|
target: (.target // ""),
|
|
keywords: keyword_string,
|
|
description: (.description // ""),
|
|
action: (.action // ""),
|
|
provider: (.provider // ""),
|
|
aliases: aliases_array,
|
|
when: (.when // ""),
|
|
checked: (.checked // "")
|
|
};
|
|
|
|
reduce (.[] | select(.id)) as $item ({ order: [], by_id: {} };
|
|
if .by_id[$item.id] == null then .order += [$item.id] else . end |
|
|
.by_id[$item.id] = ((.by_id[$item.id] // {}) + $item)
|
|
) |
|
|
{ items: [ .order[] as $id | (.by_id[$id] + { id: $id }) | normalize_item ] }
|
|
'
|
|
}
|
|
|
|
menu_all_json() {
|
|
if [[ -z ${MENU_ALL_JSON_CACHE+x} ]]; then
|
|
MENU_ALL_JSON_CACHE=$(menu_sources | normalize_menu_json) || return
|
|
fi
|
|
|
|
printf '%s\n' "$MENU_ALL_JSON_CACHE"
|
|
}
|
|
|
|
menu_static_json() {
|
|
if [[ -z ${MENU_STATIC_JSON_CACHE+x} ]]; then
|
|
MENU_STATIC_JSON_CACHE=$(menu_all_json | jq '
|
|
(.items | map({ key: .id, value: . }) | from_entries) as $by_id |
|
|
def ancestor_ids($id):
|
|
($id | split(".")) as $parts |
|
|
[range(1; $parts | length) | $parts[0:.] | join(".")];
|
|
def has_provider_ancestor($id):
|
|
any(ancestor_ids($id)[]; (($by_id[.] // {}).provider // "") != "");
|
|
|
|
{ items: [.items[] | select(has_provider_ancestor(.id) | not)] }
|
|
') || return
|
|
fi
|
|
|
|
printf '%s\n' "$MENU_STATIC_JSON_CACHE"
|
|
}
|
|
|
|
emit_config_items() {
|
|
local fields
|
|
local id
|
|
local icon
|
|
local label
|
|
local action
|
|
local keywords
|
|
local description
|
|
local target
|
|
local provider
|
|
local when
|
|
local checked
|
|
|
|
while IFS= read -r fields; do
|
|
eval "set -- $fields"
|
|
id="$1"
|
|
icon="$2"
|
|
label="$3"
|
|
action="$4"
|
|
keywords="$5"
|
|
description="$6"
|
|
target="$7"
|
|
provider="$8"
|
|
when="$9"
|
|
checked="${10}"
|
|
|
|
[[ -n $id ]] || continue
|
|
if [[ -n $when ]] && ! eval "$when" >/dev/null 2>&1; then
|
|
continue
|
|
fi
|
|
|
|
if [[ -n $checked ]] && eval "$checked" >/dev/null 2>&1; then
|
|
label="$label ✓"
|
|
fi
|
|
|
|
json_item "$id" "$icon" "$label" "$action" "$keywords" "$description" "$target" "$provider"
|
|
done < <(jq -r '.items[] | [
|
|
(.id // ""),
|
|
(.icon // ""),
|
|
(.label // .id // ""),
|
|
(.action // ""),
|
|
(.keywords // ""),
|
|
(.description // ""),
|
|
(.target // ""),
|
|
(.provider // ""),
|
|
(.when // ""),
|
|
(.checked // "")
|
|
] | @sh')
|
|
}
|
|
|
|
menu_evaluated_json() {
|
|
if [[ -z ${MENU_EVALUATED_JSON_CACHE+x} ]]; then
|
|
MENU_EVALUATED_JSON_CACHE=$(menu_all_json | emit_config_items | normalize_menu_json) || return
|
|
fi
|
|
|
|
printf '%s\n' "$MENU_EVALUATED_JSON_CACHE"
|
|
}
|
|
|
|
menu_json() {
|
|
if [[ -z ${MENU_JSON_CACHE+x} ]]; then
|
|
MENU_JSON_CACHE=$(menu_static_json | emit_config_items | normalize_menu_json) || return
|
|
fi
|
|
|
|
printf '%s\n' "$MENU_JSON_CACHE"
|
|
}
|
|
|
|
# Provider dispatch
|
|
provider_mount_id() {
|
|
local provider="$1"
|
|
|
|
menu_all_json | jq -r --arg provider "$provider" '.items[] | select(.provider == $provider) | .id' | head -n 1
|
|
}
|
|
|
|
provider_json() {
|
|
local provider="$1"
|
|
local menu_id="${2:-}"
|
|
local provider_function
|
|
|
|
[[ -n $provider ]] || return 1
|
|
menu_id=${menu_id:-$(provider_mount_id "$provider")}
|
|
[[ -n $menu_id ]] || return 1
|
|
|
|
if [[ $provider =~ ^[a-z0-9-]+$ ]]; then
|
|
provider_function="provider_${provider//-/_}"
|
|
case "$provider_function" in
|
|
provider_mount_id | provider_json) ;;
|
|
*)
|
|
if declare -F "$provider_function" >/dev/null; then
|
|
"$provider_function" "$menu_id" | normalize_menu_json
|
|
return
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
if omarchy-cmd-present "$provider"; then
|
|
"$provider" "$menu_id" | normalize_menu_json
|
|
return
|
|
fi
|
|
fi
|
|
|
|
echo "omarchy-menu: unknown provider '$provider'" >&2
|
|
return 1
|
|
}
|
|
|
|
|
|
# Routes and actions
|
|
route_target() {
|
|
local route="${1,,}"
|
|
local target
|
|
local all_json
|
|
route="${route//_/-}"
|
|
|
|
if [[ -z $route || $route == "go" || $route == "menu" ]]; then
|
|
printf 'root'
|
|
return
|
|
fi
|
|
|
|
all_json=$(menu_all_json) || return
|
|
target=$(jq -r --arg route "$route" '
|
|
def aliases:
|
|
if (.aliases | type) == "array" then .aliases
|
|
elif (.aliases | type) == "string" then [.aliases]
|
|
else [] end;
|
|
|
|
first(.items[] | select(any(aliases[]?; (ascii_downcase | gsub("_"; "-")) == $route)) | .id) // empty
|
|
' <<<"$all_json") || return
|
|
|
|
printf '%s' "${target:-$route}"
|
|
}
|
|
|
|
route_field() {
|
|
local target="$1"
|
|
local field="$2"
|
|
local all_json
|
|
local fields
|
|
local when
|
|
local value
|
|
|
|
all_json=$(menu_all_json) || return
|
|
fields=$(jq -r --arg id "$target" --arg field "$field" '
|
|
first(.items[] | select(.id == $id) | [(.when // ""), (.[$field] // "")] | @sh) // empty
|
|
' <<<"$all_json") || return
|
|
[[ -n $fields ]] || return
|
|
|
|
eval "set -- $fields"
|
|
when="$1"
|
|
value="$2"
|
|
|
|
if [[ -n $when ]] && ! eval "$when" >/dev/null 2>&1; then
|
|
return
|
|
fi
|
|
|
|
printf '%s' "$value"
|
|
}
|
|
|
|
route_kind() {
|
|
local target="$1"
|
|
|
|
if [[ $target == "root" ]]; then
|
|
printf 'menu'
|
|
return
|
|
fi
|
|
|
|
route_field "$target" kind
|
|
}
|
|
|
|
route_link_target() {
|
|
route_field "$1" target
|
|
}
|
|
|
|
route_action() {
|
|
route_field "$1" action
|
|
}
|
|
|
|
run_action() {
|
|
local id="$1"
|
|
local action="${2:-}"
|
|
|
|
if [[ -z $action ]]; then
|
|
action=$(route_action "$id") || return 0
|
|
fi
|
|
|
|
[[ -n $action ]] || return 0
|
|
eval "$action"
|
|
}
|
|
|
|
|
|
# Quickshell launcher
|
|
ensure_menu_style_file() {
|
|
local toggles_dir="$HOME/.local/state/omarchy/toggles"
|
|
local style_file="$toggles_dir/quickshell-menu.json"
|
|
local radius=0
|
|
|
|
[[ -f $style_file ]] && return
|
|
|
|
mkdir -p "$toggles_dir"
|
|
if [[ -f $toggles_dir/walker.css ]] && grep -q 'border-radius: 6px;' "$toggles_dir/walker.css"; then
|
|
radius=6
|
|
fi
|
|
|
|
printf '{ "radius": %s }\n' "$radius" >"$style_file"
|
|
}
|
|
|
|
usage() {
|
|
cat <<USAGE
|
|
Usage: omarchy-menu [menu-or-action]
|
|
omarchy-menu --json
|
|
omarchy-menu --provider <provider> [menu-id]
|
|
|
|
Launch the Quickshell Omarchy menu. Pass a menu name (install, style, system,
|
|
capture, toggle, etc.) to open there, or an action id to run it directly.
|
|
|
|
Options:
|
|
--json Print the static menu JSON used by Quickshell
|
|
--provider <provider> [id] Print JSON rows from a runtime provider
|
|
-h, --help Show this help
|
|
USAGE
|
|
}
|
|
|
|
menu_layer_visible() {
|
|
hyprctl layers -j 2>/dev/null | jq -e '.. | objects | select(.namespace? == "omarchy-menu")' >/dev/null
|
|
}
|
|
|
|
menu_lock_path() {
|
|
printf '%s/omarchy-menu.lock' "${XDG_RUNTIME_DIR:-/run/user/$UID}"
|
|
}
|
|
|
|
menu_payload_json() {
|
|
local menu_file="$1"
|
|
local initial_menu="$2"
|
|
local selection_file="$3"
|
|
local done_file="$4"
|
|
local colors_payload_base64="$5"
|
|
local font_family="$6"
|
|
|
|
jq -nc \
|
|
--arg menu_file "$menu_file" \
|
|
--arg initial_menu "$initial_menu" \
|
|
--arg selection_file "$selection_file" \
|
|
--arg done_file "$done_file" \
|
|
--arg colors_payload_base64 "$colors_payload_base64" \
|
|
--arg font_family "$font_family" \
|
|
'{
|
|
menuJsonFile: $menu_file,
|
|
initialMenu: $initial_menu,
|
|
selectionFile: $selection_file,
|
|
doneFile: $done_file,
|
|
colorsRawBase64: $colors_payload_base64,
|
|
fontFamily: $font_family
|
|
}'
|
|
}
|
|
|
|
close_visible_quickshell_menu() {
|
|
menu_layer_visible || return 1
|
|
omarchy-shell-ipc shell hide omarchy.menu >/dev/null 2>&1 || return 1
|
|
}
|
|
|
|
open_quickshell_menu() {
|
|
local initial_menu="$1"
|
|
local menu_payload
|
|
local colors_file="$HOME/.config/omarchy/current/theme/colors.toml"
|
|
local colors_payload_base64=""
|
|
local font_family
|
|
local menu_file=""
|
|
local selection_file
|
|
local done_file
|
|
local selected_id
|
|
local selected_action
|
|
local menu_started=false
|
|
local lock_path
|
|
local lock_fd
|
|
local summon_result
|
|
local payload
|
|
|
|
lock_path=$(menu_lock_path)
|
|
exec {lock_fd}>"$lock_path" || return 1
|
|
if ! flock -n "$lock_fd"; then
|
|
close_visible_quickshell_menu && return 0
|
|
flock "$lock_fd" || return 1
|
|
fi
|
|
|
|
if close_visible_quickshell_menu; then
|
|
return 0
|
|
fi
|
|
|
|
ensure_menu_style_file
|
|
|
|
selection_file=$(mktemp)
|
|
done_file=$(mktemp)
|
|
rm -f "$done_file"
|
|
trap "rm -f $(shell_quote "$selection_file") $(shell_quote "$done_file")" EXIT
|
|
|
|
menu_payload=$(menu_json) || return
|
|
if [[ $initial_menu != "root" ]] && ! jq -e --arg id "$initial_menu" '.items[] | select(.id == $id)' <<<"$menu_payload" >/dev/null; then
|
|
menu_payload=$(menu_evaluated_json) || return
|
|
fi
|
|
|
|
if [[ -f $colors_file ]]; then
|
|
colors_payload_base64=$(base64 -w0 "$colors_file")
|
|
fi
|
|
|
|
font_family=$(omarchy-font-current 2>/dev/null || true)
|
|
font_family=${font_family:-monospace}
|
|
|
|
menu_file=$(mktemp)
|
|
printf '%s' "$menu_payload" >"$menu_file"
|
|
trap "rm -f $(shell_quote "$menu_file") $(shell_quote "$selection_file") $(shell_quote "$done_file")" EXIT
|
|
payload=$(menu_payload_json "$menu_file" "$initial_menu" "$selection_file" "$done_file" "$colors_payload_base64" "$font_family") || return
|
|
|
|
summon_result=$(omarchy-shell-ipc shell summon omarchy.menu "$payload" 2>/dev/null || true)
|
|
if [[ $summon_result != "ok" ]]; then
|
|
echo "omarchy-menu: Omarchy shell did not accept the menu request" >&2
|
|
return 1
|
|
fi
|
|
|
|
for (( i = 0; i < 500; i++ )); do
|
|
if [[ -e $done_file ]] || menu_layer_visible; then
|
|
menu_started=true
|
|
break
|
|
fi
|
|
sleep 0.01
|
|
done
|
|
|
|
if [[ $menu_started != true ]]; then
|
|
omarchy-shell-ipc shell hide omarchy.menu >/dev/null 2>&1 || true
|
|
echo "omarchy-menu: Quickshell menu did not open" >&2
|
|
return 1
|
|
fi
|
|
|
|
while [[ ! -e $done_file ]]; do
|
|
menu_layer_visible || break
|
|
sleep 0.01
|
|
done
|
|
|
|
if [[ -s $selection_file ]]; then
|
|
IFS=$'\t' read -r selected_id selected_action <"$selection_file"
|
|
exec {lock_fd}>&-
|
|
run_action "$selected_id" "$selected_action"
|
|
fi
|
|
}
|
|
|
|
# CLI dispatch
|
|
case "${1:-}" in
|
|
--help | -h)
|
|
usage
|
|
exit 0
|
|
;;
|
|
--json)
|
|
menu_json || exit $?
|
|
exit 0
|
|
;;
|
|
--provider)
|
|
provider_json "${2:-}" "${3:-}"
|
|
exit $?
|
|
;;
|
|
screenrecord | screenrecording | screen-record)
|
|
close_visible_quickshell_menu || true
|
|
stop_active_screenrecording && exit 0
|
|
;;
|
|
esac
|
|
|
|
if [[ -z ${1:-} ]]; then
|
|
open_quickshell_menu root
|
|
exit $?
|
|
fi
|
|
|
|
target=$(route_target "${1:-}") || exit $?
|
|
kind=$(route_kind "$target") || exit $?
|
|
|
|
case "$kind" in
|
|
action)
|
|
close_visible_quickshell_menu || true
|
|
run_action "$target"
|
|
;;
|
|
menu)
|
|
open_quickshell_menu "$target"
|
|
;;
|
|
link)
|
|
open_quickshell_menu "$(route_link_target "$target")"
|
|
;;
|
|
*)
|
|
open_quickshell_menu root
|
|
;;
|
|
esac
|