Integrate omarchy menu into shell

This commit is contained in:
Ryan Hughes
2026-05-14 02:25:05 -04:00
parent 7d2745b6a6
commit 0e135bbb75
20 changed files with 2087 additions and 925 deletions
+14 -26
View File
@@ -29,40 +29,28 @@ if [[ -n $font_name ]]; then
sed -i "s/font_family = .*/font_family = $font_name/g" ~/.config/hypr/hyprlock.conf
sed -i "s/font-family: .*/font-family: '$font_name';/g" ~/.config/waybar/style.css
mkdir -p "$HOME/.config/omarchy"
python3 - "$HOME/.config/omarchy/shell.json" "$font_name" <<'PY'
import json
import sys
shell_config="$HOME/.config/omarchy/shell.json"
tmp=$(mktemp)
path, font_name = sys.argv[1], sys.argv[2]
try:
with open(path) as file:
data = json.load(file)
if not isinstance(data, dict):
data = {}
except (FileNotFoundError, json.JSONDecodeError):
data = {}
if [[ -s $shell_config ]] && jq -e 'type == "object"' "$shell_config" >/dev/null 2>&1; then
jq --arg font_name "$font_name" '
.version = 1 |
.bar = ((.bar // {}) | if type == "object" then . else {} end) |
.bar.fontFamily = $font_name
' "$shell_config" >"$tmp"
else
jq -n --arg font_name "$font_name" '{ version: 1, bar: { fontFamily: $font_name } }' >"$tmp"
fi
data.setdefault("version", 1)
bar = data.get("bar")
if not isinstance(bar, dict):
bar = {}
data["bar"] = bar
bar["fontFamily"] = font_name
with open(path, "w") as file:
json.dump(data, file, indent=2)
file.write("\n")
PY
mv "$tmp" "$shell_config"
sed -i "s/font-family: .*/font-family: '$font_name';/g" ~/.config/swayosd/style.css
xmlstarlet ed -L \
-u '//match[@target="pattern"][test/string="monospace"]/edit[@name="family"]/string' \
-v "$font_name" \
~/.config/fontconfig/fonts.conf
omarchy-restart-waybar
OMARCHY_PATH=${OMARCHY_PATH:-$HOME/.local/share/omarchy}
if quickshell list -p "$OMARCHY_PATH/default/quickshell/omarchy-shell" 2>/dev/null | grep -q '^Instance '; then
omarchy-restart-bar
if pgrep -x waybar >/dev/null; then
omarchy-restart-waybar
fi
omarchy-restart-swayosd
+728 -829
View File
File diff suppressed because it is too large Load Diff
+2 -5
View File
@@ -7,14 +7,11 @@ set -e
USER_CONFIG="$HOME/.config/omarchy/shell.json"
# Removing the user file lets the shell fall back to shell-defaults.json on
# its next reload. omarchy-restart-bar (which is now an alias for restarting
# omarchy-shell) reloads the shell so the change takes effect immediately.
# Removing the user file lets the running shell fall back to shell-defaults.json
# via its FileView watcher. The next shell start will also use the defaults.
if [[ -f $USER_CONFIG ]]; then
backup="$USER_CONFIG.bak.$(date +%s)"
cp "$USER_CONFIG" "$backup"
echo "Backed up user shell config to $backup"
rm -f "$USER_CONFIG"
fi
omarchy-restart-bar
@@ -1,7 +1,7 @@
#!/bin/bash
# omarchy:summary=Restart the bar
# omarchy:examples=omarchy restart bar
# omarchy:summary=Restart Omarchy Quickshell
# omarchy:examples=omarchy restart quickshell | omarchy-restart-quickshell
OMARCHY_PATH=${OMARCHY_PATH:-$HOME/.local/share/omarchy}
CONFIG_DIR="$OMARCHY_PATH/default/quickshell/omarchy-shell"
+11 -24
View File
@@ -15,29 +15,16 @@ if [[ ! $position =~ ^(top|bottom|left|right)$ ]]; then
fi
mkdir -p "$(dirname "$CONFIG_FILE")"
python3 - "$CONFIG_FILE" "$position" <<'PY'
import json
import sys
tmp=$(mktemp)
path, position = sys.argv[1], sys.argv[2]
try:
with open(path) as file:
data = json.load(file)
if not isinstance(data, dict):
data = {}
except (FileNotFoundError, json.JSONDecodeError):
data = {}
if [[ -s $CONFIG_FILE ]] && jq -e 'type == "object"' "$CONFIG_FILE" >/dev/null 2>&1; then
jq --arg position "$position" '
.version = 1 |
.bar = ((.bar // {}) | if type == "object" then . else {} end) |
.bar.position = $position
' "$CONFIG_FILE" >"$tmp"
else
jq -n --arg position "$position" '{ version: 1, bar: { position: $position } }' >"$tmp"
fi
data.setdefault("version", 1)
bar = data.get("bar")
if not isinstance(bar, dict):
bar = {}
data["bar"] = bar
bar["position"] = position
with open(path, "w") as file:
json.dump(data, file, indent=2)
file.write("\n")
PY
omarchy-restart-bar
mv "$tmp" "$CONFIG_FILE"
-4
View File
@@ -53,10 +53,6 @@ fi
if pgrep -x waybar >/dev/null; then
omarchy-restart-waybar
fi
OMARCHY_PATH=${OMARCHY_PATH:-$HOME/.local/share/omarchy}
if quickshell list -p "$OMARCHY_PATH/default/quickshell/omarchy-shell" 2>/dev/null | grep -q '^Instance '; then
omarchy-restart-bar
fi
omarchy-restart-swayosd
omarchy-restart-terminal
omarchy-restart-hyprctl
+3 -4
View File
@@ -20,10 +20,9 @@ if gum confirm "Install Voxtype + AI model (~150MB) to enable dictation?"; then
fi
voxtype setup systemd
omarchy-restart-waybar
OMARCHY_PATH=${OMARCHY_PATH:-$HOME/.local/share/omarchy}
if quickshell list -p "$OMARCHY_PATH/default/quickshell/omarchy-shell" 2>/dev/null | grep -q '^Instance '; then
omarchy-restart-bar
if pgrep -x waybar >/dev/null; then
omarchy-restart-waybar
fi
omarchy-restart-quickshell
notify-send " Voxtype Dictation Ready" "Hold F9 to dictate (or toggle with Super + Ctrl + X)." -t 10000
fi
+3 -4
View File
@@ -5,8 +5,7 @@
set -e
omarchy-launch-floating-terminal-with-presentation "voxtype setup model"
omarchy-restart-waybar
OMARCHY_PATH=${OMARCHY_PATH:-$HOME/.local/share/omarchy}
if quickshell list -p "$OMARCHY_PATH/default/quickshell/omarchy-shell" 2>/dev/null | grep -q '^Instance '; then
omarchy-restart-bar
if pgrep -x waybar >/dev/null; then
omarchy-restart-waybar
fi
omarchy-restart-quickshell
-20
View File
@@ -1,20 +0,0 @@
# Overwrite parts of the omarchy-menu with user-specific submenus.
# See $OMARCHY_PATH/bin/omarchy-menu for functions that can be overwritten.
#
# WARNING: Overwritten functions will obviously not be updated when Omarchy changes.
#
# Example of minimal system menu:
#
# show_system_menu() {
# case $(menu "System" " Lock\n󰐥 Shutdown") in
# *Lock*) omarchy-system-lock ;;
# *Shutdown*) omarchy-system-shutdown ;;
# *) back_to show_main_menu ;;
# esac
# }
#
# Example of overriding just the about menu action: (Using zsh instead of bash (default))
#
# show_about() {
# exec omarchy-launch-or-focus-tui "zsh -c 'fastfetch; read -k 1'"
# }
@@ -0,0 +1,31 @@
{
// Extend the Quickshell Omarchy menu with JSONC.
//
// IDs are object keys. The parent is inferred from the dotted id, so
// "personal.notes" appears under "personal", and "personal" appears on the
// root menu. Reuse an existing id to override/extend it.
//
// Fields:
// icon Nerd Font glyph shown in the icon column.
// label Visible row title.
// action Shell command to run. If omitted, the row is a submenu.
// target Existing submenu id to open. Use for links/aliases.
// provider Runtime provider function/command returning JSON rows.
// aliases Alternate `omarchy-menu <name>` routes; also searchable.
// keywords Extra search terms beyond id/label/aliases.
// description Optional subtitle and extra search text.
// when Shell condition; hide row when it fails.
// checked Shell condition; append ✓ when it succeeds.
//
// Examples:
// "personal": {"icon":"","label":"Personal","keywords":"notes projects"},
// "personal.notes": {"icon":"󰎞","label":"Notes","action":"omarchy-launch-editor ~/notes","keywords":"notes"},
// "personal.files": {"icon":"","label":"Files","action":"uwsm-app -- nautilus ~/Documents","keywords":"files documents"},
//
// Only use provider when a provider_name function or command named "name"
// returns JSON rows. Static submenus only need dotted ids.
//
// Example: replace the default About action by reusing the same id. Existing
// fields are kept unless overridden.
// "about": {"icon":"","label":"About","action":"omarchy-launch-or-focus-tui \"zsh -c 'fastfetch; read -k 1'\""},
}
+1 -1
View File
@@ -1,2 +1,2 @@
-- Remove 1px border around hyprshot screenshots.
hl.layer_rule({ match = { namespace = "selection" }, no_anim = true })
hl.layer_rule({ match = { namespace = "selection" }, no_anim = true, animation = "none" })
+2
View File
@@ -0,0 +1,2 @@
-- Keep the menu instant: no layer-shell fade/slide animation.
hl.layer_rule({ match = { namespace = "omarchy-menu" }, no_anim = true, animation = "none" })
+1 -1
View File
@@ -23,4 +23,4 @@ hl.window_rule({ match = { tag = "pop" }, rounding = 8 })
hl.window_rule({ match = { tag = "noidle" }, idle_inhibit = "always" })
-- Image selector.
hl.layer_rule({ match = { namespace = "omarchy-image-selector" }, no_anim = true })
hl.layer_rule({ match = { namespace = "omarchy-image-selector" }, no_anim = true, animation = "none" })
+1 -1
View File
@@ -1,2 +1,2 @@
-- Application-specific animation.
hl.layer_rule({ match = { namespace = "walker" }, no_anim = true })
hl.layer_rule({ match = { namespace = "walker" }, no_anim = true, animation = "none" })
+1 -1
View File
@@ -1,7 +1,7 @@
hl.on("hyprland.start", function()
hl.exec_cmd("uwsm-app -- hypridle")
hl.exec_cmd("uwsm-app -- mako")
hl.exec_cmd("! omarchy-toggle-enabled bar-off && uwsm-app -- env OMARCHY_PATH=$HOME/.local/share/omarchy quickshell -p $HOME/.local/share/omarchy/default/quickshell/omarchy-shell")
hl.exec_cmd("! omarchy-toggle-enabled bar-off && omarchy-restart-quickshell")
hl.exec_cmd("uwsm-app -- fcitx5 --disable notificationitem")
hl.exec_cmd("uwsm-app -- swaybg -i ~/.config/omarchy/current/background -m fill")
hl.exec_cmd("/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1")
+333
View File
@@ -0,0 +1,333 @@
{
// Omarchy menu definition.
// JSONC is used for Neovim-friendly highlighting, comments, and trailing commas.
// IDs are object keys. Dotted IDs imply hierarchy: trigger.share.file belongs
// under trigger.share.
// Kind is inferred: action -> action, target -> link, otherwise submenu.
// Dotted IDs define the tree. Use provider:"name" only when the submenu
// calls provider_name() or a command named "name" to return JSON rows.
// Optional fields:
// aliases alternate `omarchy-menu <name>` routes; also searchable
// keywords extra search terms beyond id/label/aliases
// when shell condition; hide row when it fails
// checked shell condition; append ✓ when it succeeds
// Root Menu
"apps": {"icon":"󰀻","label":"Apps","aliases":["app","applications"],"keywords":"launch launcher","action":"omarchy-launch-walker -p 'Launch…'"},
"learn": {"icon":"󰧑","label":"Learn","keywords":"manual docs help reference"},
"trigger": {"icon":"󱓞","label":"Trigger","keywords":"actions capture share toggle hardware reminder"},
"style": {"icon":"","label":"Style","keywords":"theme background font bar quickshell hyprland appearance"},
"setup": {"icon":"","label":"Setup","aliases":["settings"],"keywords":"configure defaults wifi bluetooth audio"},
"install": {"icon":"󰉉","label":"Install","keywords":"package app service browser editor terminal development gaming"},
"remove": {"icon":"󰭌","label":"Remove","aliases":["uninstall"],"keywords":"package app browser development gaming"},
"update": {"icon":"","label":"Update","aliases":["restart","refresh"],"keywords":"upgrade channel firmware timezone"},
"about": {"icon":"","label":"About","keywords":"omarchy system information","action":"omarchy-launch-about"},
"system": {"icon":"","label":"System","aliases":["power-menu"],"keywords":"lock logout restart shutdown suspend hibernate"},
// System
"system.screensaver": {"icon":"󱄄","label":"Screensaver","action":"omarchy-launch-screensaver force"},
"system.lock": {"icon":"","label":"Lock","keywords":"screen","action":"omarchy-system-lock"},
"system.suspend": {"icon":"󰒲","label":"Suspend","keywords":"sleep","when":"! omarchy-toggle-enabled suspend-off","action":"systemctl suspend"},
"system.hibernate": {"icon":"󰤁","label":"Hibernate","keywords":"sleep","when":"omarchy-hibernation-available","action":"systemctl hibernate"},
"system.logout": {"icon":"󰍃","label":"Logout","keywords":"sign out","action":"omarchy-system-logout"},
"system.restart": {"icon":"󰜉","label":"Restart","keywords":"reboot","action":"omarchy-system-reboot"},
"system.shutdown": {"icon":"󰐥","label":"Shutdown","keywords":"power off","action":"omarchy-system-shutdown"},
// Learn
"learn.keybindings": {"icon":"","label":"Keybindings","keywords":"keyboard shortcuts bindings","action":"omarchy-menu-keybindings"},
"learn.tmux-keybindings": {"icon":"","label":"Tmux keybindings","keywords":"keyboard shortcuts bindings terminal","action":"omarchy-menu-tmux-keybindings"},
"learn.omarchy": {"icon":"","label":"Omarchy","keywords":"manual documentation","action":"omarchy-launch-webapp 'https://learn.omacom.io/2/the-omarchy-manual'"},
"learn.hyprland": {"icon":"","label":"Hyprland","keywords":"wiki docs","action":"omarchy-launch-webapp 'https://wiki.hypr.land/'"},
"learn.arch": {"icon":"󰣇","label":"Arch","keywords":"linux wiki docs","action":"omarchy-launch-webapp 'https://wiki.archlinux.org/title/Main_page'"},
"learn.neovim": {"icon":"","label":"Neovim","keywords":"lazyvim keymaps docs","action":"omarchy-launch-webapp 'https://www.lazyvim.org/keymaps'"},
"learn.bash": {"icon":"󱆃","label":"Bash","keywords":"shell cheatsheet","action":"omarchy-launch-webapp 'https://devhints.io/bash'"},
// Trigger
"trigger.reminder": {"icon":"󰔛","label":"Reminder","aliases":["reminder"],"keywords":"timer notification remind"},
"trigger.capture": {"icon":"","label":"Capture","aliases":["capture","screenshot","screenrecord","screen-record","screenrecording"],"keywords":"color text extraction"},
"trigger.capture.screenshot": {"icon":"","label":"Screenshot","keywords":"picture","action":"omarchy-capture-screenshot"},
"trigger.capture.screenrecord.stop": {"icon":"","label":"Stop Screenrecording","keywords":"recording video","when":"pgrep -f '^gpu-screen-recorder' >/dev/null","action":"stop_active_screenrecording"},
"trigger.capture.screenrecord": {"icon":"","label":"Screenrecord","keywords":"record screen video"},
"trigger.capture.text": {"icon":"󰴑","label":"Text Extraction","keywords":"ocr","action":"omarchy-capture-text-extraction"},
"trigger.capture.color": {"icon":"󰃉","label":"Color","keywords":"picker hyprpicker","action":"pkill hyprpicker || hyprpicker -a"},
"trigger.capture.screenrecord.no-audio": {"icon":"","label":"With no audio","action":"omarchy-capture-screenrecording"},
"trigger.capture.screenrecord.desktop-audio": {"icon":"","label":"With desktop audio","action":"omarchy-capture-screenrecording --with-desktop-audio"},
"trigger.capture.screenrecord.microphone": {"icon":"","label":"With desktop + microphone audio","keywords":"mic","action":"omarchy-capture-screenrecording --with-desktop-audio --with-microphone-audio"},
"trigger.capture.screenrecord.webcam": {"icon":"","label":"With desktop + microphone audio + webcam","keywords":"camera","action":"screenrecord_with_webcam"},
"trigger.transcode": {"icon":"󰧸","label":"Transcode","keywords":"convert image video","action":"omarchy-transcode"},
"trigger.share": {"icon":"","label":"Share","aliases":["share"],"keywords":"clipboard file folder localsend"},
"trigger.toggle": {"icon":"󰔎","label":"Toggle","aliases":["toggle","toggles"],"keywords":"screensaver nightlight idle notifications bar quickshell"},
"trigger.hardware": {"icon":"","label":"Hardware","aliases":["hardware","hw"],"keywords":"monitor touchpad touchscreen gpu"},
"trigger.hardware.laptop-display": {"icon":"󰛧","label":"Laptop Display","keywords":"monitor","action":"omarchy-hyprland-monitor-internal toggle"},
"trigger.hardware.mirror-display": {"icon":"󰍹","label":"Mirror Display","keywords":"monitor","action":"omarchy-hyprland-monitor-internal-mirror toggle"},
"trigger.hardware.hybrid-gpu": {"icon":"","label":"Hybrid GPU","keywords":"graphics","when":"omarchy-hw-hybrid-gpu >/dev/null","action":"present_terminal omarchy-toggle-hybrid-gpu"},
"trigger.hardware.touchpad": {"icon":"󰟸","label":"Touchpad","keywords":"trackpad","when":"omarchy-hw-touchpad >/dev/null","action":"omarchy-toggle-touchpad"},
"trigger.hardware.touchpad-haptics": {"icon":"󰌌","label":"Touchpad Haptics","when":"omarchy-hw-dell-xps-haptic-touchpad >/dev/null && omarchy-cmd-present dell-xps-touchpad-haptics"},
"trigger.hardware.touchpad-haptics.low": {"icon":"󰌌","label":"low","when":"omarchy-hw-dell-xps-haptic-touchpad >/dev/null && omarchy-cmd-present dell-xps-touchpad-haptics","checked":"haptic_touchpad_is low","action":"dell-xps-touchpad-haptics set low"},
"trigger.hardware.touchpad-haptics.mid": {"icon":"󰌌","label":"mid","keywords":"medium","when":"omarchy-hw-dell-xps-haptic-touchpad >/dev/null && omarchy-cmd-present dell-xps-touchpad-haptics","checked":"haptic_touchpad_is mid","action":"dell-xps-touchpad-haptics set mid"},
"trigger.hardware.touchpad-haptics.high": {"icon":"󰌌","label":"high","when":"omarchy-hw-dell-xps-haptic-touchpad >/dev/null && omarchy-cmd-present dell-xps-touchpad-haptics","checked":"haptic_touchpad_is high","action":"dell-xps-touchpad-haptics set high"},
"trigger.hardware.touchscreen": {"icon":"󰆽","label":"Touchscreen","keywords":"tablet","when":"omarchy-hw-touchscreen >/dev/null","action":"omarchy-toggle-touchscreen"},
"trigger.reminder.set": {"icon":"󰔛","label":"Set one","aliases":["reminder-set","remind"],"keywords":"timer","action":"show_custom_reminder_input"},
"trigger.reminder.show": {"icon":"󰔛","label":"Show all","keywords":"list","action":"omarchy-reminder show"},
"trigger.reminder.clear": {"icon":"󰔛","label":"Clear all","keywords":"delete","action":"omarchy-reminder clear"},
"trigger.share.clipboard": {"icon":"","label":"Clipboard","action":"omarchy-menu-share clipboard"},
"trigger.share.file": {"icon":"","label":"File","action":"terminal bash -c 'omarchy-menu-share file'"},
"trigger.share.folder": {"icon":"","label":"Folder","keywords":"directory","action":"terminal bash -c 'omarchy-menu-share folder'"},
"trigger.share.receive": {"icon":"󰥦","label":"Receive","keywords":"localsend","action":"uwsm-app -- localsend"},
"trigger.toggle.screensaver": {"icon":"󱄄","label":"Screensaver","action":"omarchy-toggle-screensaver"},
"trigger.toggle.nightlight": {"icon":"󰔎","label":"Nightlight","keywords":"night light hyprsunset","action":"omarchy-toggle-nightlight"},
"trigger.toggle.idle-lock": {"icon":"󱫖","label":"Idle Lock","keywords":"hypridle","action":"omarchy-toggle-idle"},
"trigger.toggle.notifications": {"icon":"󰂛","label":"Notifications","keywords":"mako silence","action":"omarchy-toggle-notification-silencing"},
"trigger.toggle.top-bar": {"icon":"󰍜","label":"Bar","keywords":"top bar quickshell","action":"omarchy-toggle-bar"},
"trigger.toggle.workspace-layout": {"icon":"󱂬","label":"Workspace Layout","action":"omarchy-hyprland-workspace-layout-toggle"},
"trigger.toggle.window-gaps": {"icon":"","label":"Window Gaps","action":"omarchy-hyprland-window-gaps-toggle"},
"trigger.toggle.one-window-ratio": {"icon":"","label":"1-Window Ratio","keywords":"square","action":"omarchy-hyprland-window-single-square-aspect-toggle"},
"trigger.toggle.monitor-scaling": {"icon":"󰍹","label":"Monitor Scaling","keywords":"display","action":"omarchy-hyprland-monitor-scaling-cycle"},
"trigger.toggle.direct-boot": {"icon":"","label":"Direct Boot","action":"present_terminal omarchy-config-direct-boot"},
"trigger.toggle.passwordless-sudo": {"icon":"󰟵","label":"Passwordless Sudo","action":"present_terminal omarchy-sudo-passwordless"},
// Style
"style.theme": {"icon":"󰸌","label":"Theme","aliases":["theme","themes"],"keywords":"colors","action":"theme=$(omarchy-theme-switcher); [[ -n $theme ]] && omarchy-theme-set \"$theme\""},
"style.unlock": {"icon":"󰟵","label":"Unlock","keywords":"themes","action":"omarchy-launch-walker -m menus:omarchyunlocks --width 800 --minheight 400"},
"style.font": {"icon":"","label":"Font","keywords":"typeface","provider":"fonts"},
"style.background": {"icon":"","label":"Background","aliases":["background","wallpaper"],"action":"background=$(omarchy-theme-bg-switcher); [[ -n $background ]] && omarchy-theme-bg-set \"$background\""},
"style.bar": {"icon":"󰍜","label":"Bar","keywords":"quickshell top bottom left right settings"},
"style.corners": {"icon":"󰘇","label":"Corners","keywords":"sharp round rounded"},
"style.hyprland": {"icon":"","label":"Hyprland","keywords":"look feel","action":"open_in_editor \"$(hypr_config_file looknfeel)\""},
"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-style-bar-position top"},
"style.bar.bottom": {"icon":"󰁅","label":"Bottom","keywords":"position","action":"omarchy-style-bar-position bottom"},
"style.bar.left": {"icon":"󰁍","label":"Left","keywords":"position","action":"omarchy-style-bar-position left"},
"style.bar.right": {"icon":"󰁔","label":"Right","keywords":"position","action":"omarchy-style-bar-position right"},
"style.corners.sharp": {"icon":"󰝣","label":"Sharp","keywords":"square","action":"omarchy-style-corners sharp"},
"style.corners.round": {"icon":"󰘇","label":"Round","keywords":"rounded","action":"omarchy-style-corners round"},
"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"},
"style.screensaver.text": {"icon":"","label":"Edit Text","keywords":"branding","action":"omarchy-branding-screensaver text"},
"style.screensaver.image": {"icon":"","label":"Set From Image","keywords":"branding","action":"omarchy-branding-screensaver image"},
"style.screensaver.default": {"icon":"","label":"Restore Default","keywords":"branding","action":"omarchy-branding-screensaver reset"},
"style.install.theme": {"icon":"󰸌","label":"Theme","action":"present_terminal omarchy-theme-install"},
"style.install.background": {"icon":"","label":"Background","keywords":"wallpaper","action":"omarchy-theme-bg-install"},
"style.install.font": {"icon":"","label":"Font"},
"style.install.font.cascadia": {"icon":"","label":"Cascadia Mono","action":"install_font 'Cascadia Mono' ttf-cascadia-mono-nerd 'CaskaydiaMono Nerd Font'"},
"style.install.font.meslo": {"icon":"","label":"Meslo LG Mono","action":"install_font 'Meslo LG Mono' ttf-meslo-nerd 'MesloLGL Nerd Font'"},
"style.install.font.fira": {"icon":"","label":"Fira Code","action":"install_font 'Fira Code' ttf-firacode-nerd 'FiraCode Nerd Font'"},
"style.install.font.victor": {"icon":"","label":"Victor Code","action":"install_font 'Victor Code' ttf-victor-mono-nerd 'VictorMono Nerd Font'"},
"style.install.font.bitstream": {"icon":"","label":"Bitstream Vera Mono","action":"install_font 'Bitstream Vera Code' ttf-bitstream-vera-mono-nerd 'BitstromWera Nerd Font'"},
"style.install.font.iosevka": {"icon":"","label":"Iosevka","action":"install_font Iosevka ttf-iosevka-nerd 'Iosevka Nerd Font Mono'"},
// Setup
"setup.audio": {"icon":"","label":"Audio","keywords":"sound","action":"omarchy-launch-audio"},
"setup.wifi": {"icon":"","label":"Wifi","keywords":"wireless network","action":"omarchy-launch-wifi"},
"setup.bluetooth": {"icon":"󰂯","label":"Bluetooth","action":"omarchy-launch-bluetooth"},
"setup.power": {"icon":"󱐋","label":"Power Profile","aliases":["power","power-profile","power-profiles"],"keywords":"performance battery","provider":"power-profiles"},
"setup.sleep": {"icon":"","label":"System Sleep","keywords":"suspend hibernate"},
"setup.sleep.suspend-enable": {"icon":"󰒲","label":"Enable Suspend","when":"omarchy-toggle-enabled suspend-off","action":"omarchy-toggle-suspend"},
"setup.sleep.suspend-disable": {"icon":"󰒲","label":"Disable Suspend","when":"! omarchy-toggle-enabled suspend-off","action":"omarchy-toggle-suspend"},
"setup.sleep.hibernate-enable": {"icon":"󰤁","label":"Enable Hibernate","when":"! omarchy-hibernation-available","action":"present_terminal omarchy-hibernation-setup"},
"setup.sleep.hibernate-disable": {"icon":"󰤁","label":"Disable Hibernate","when":"omarchy-hibernation-available","action":"present_terminal omarchy-hibernation-remove"},
"setup.monitors": {"icon":"󰍹","label":"Monitors","keywords":"monitor display hyprland","action":"open_in_editor \"$(hypr_config_file monitors)\""},
"setup.keybindings": {"icon":"","label":"Keybindings","keywords":"keyboard shortcuts","when":"[[ -f $(hypr_config_file bindings) ]]","action":"open_in_editor \"$(hypr_config_file bindings)\""},
"setup.input": {"icon":"","label":"Input","keywords":"keyboard touchpad mouse","when":"[[ -f $(hypr_config_file input) ]]","action":"open_in_editor \"$(hypr_config_file input)\""},
"setup.default": {"icon":"","label":"Defaults","aliases":["default","defaults"],"keywords":"browser terminal editor"},
"setup.default.browser": {"icon":"","label":"Browser"},
"setup.default.browser.chromium": {"icon":"","label":"Chromium","when":"omarchy-cmd-present chromium","checked":"default_browser_is chromium","action":"omarchy-default-browser chromium"},
"setup.default.browser.chrome": {"icon":"󰊯","label":"Chrome","keywords":"google","when":"omarchy-cmd-present google-chrome-stable","checked":"default_browser_is chrome","action":"omarchy-default-browser chrome"},
"setup.default.browser.brave": {"icon":"󰖟","label":"Brave","when":"omarchy-cmd-present brave","checked":"default_browser_is brave","action":"omarchy-default-browser brave"},
"setup.default.browser.brave-origin": {"icon":"󰖟","label":"Brave Origin","when":"omarchy-cmd-present brave-origin-beta","checked":"default_browser_is brave-origin","action":"omarchy-default-browser brave-origin"},
"setup.default.browser.edge": {"icon":"󰇩","label":"Edge","when":"omarchy-cmd-present microsoft-edge-stable","checked":"default_browser_is edge","action":"omarchy-default-browser edge"},
"setup.default.browser.firefox": {"icon":"󰈹","label":"Firefox","when":"omarchy-cmd-present firefox","checked":"default_browser_is firefox","action":"omarchy-default-browser firefox"},
"setup.default.browser.zen": {"icon":"󰖟","label":"Zen","when":"omarchy-cmd-present zen-browser","checked":"default_browser_is zen","action":"omarchy-default-browser zen"},
"setup.default.terminal": {"icon":"","label":"Terminal"},
"setup.default.terminal.alacritty": {"icon":"","label":"Alacritty","when":"omarchy-cmd-present alacritty","checked":"default_terminal_is alacritty","action":"omarchy-default-terminal alacritty"},
"setup.default.terminal.foot": {"icon":"","label":"Foot","when":"omarchy-cmd-present foot","checked":"default_terminal_is foot","action":"omarchy-default-terminal foot"},
"setup.default.terminal.ghostty": {"icon":"","label":"Ghostty","when":"omarchy-cmd-present ghostty","checked":"default_terminal_is ghostty","action":"omarchy-default-terminal ghostty"},
"setup.default.terminal.kitty": {"icon":"","label":"Kitty","when":"omarchy-cmd-present kitty","checked":"default_terminal_is kitty","action":"omarchy-default-terminal kitty"},
"setup.default.editor": {"icon":"","label":"Editor"},
"setup.default.editor.neovim": {"icon":"","label":"Neovim","keywords":"nvim","when":"omarchy-cmd-present nvim","checked":"default_editor_is nvim","action":"omarchy-default-editor nvim"},
"setup.default.editor.vscode": {"icon":"","label":"VSCode","keywords":"code","when":"omarchy-cmd-present code","checked":"default_editor_is code","action":"omarchy-default-editor code"},
"setup.default.editor.cursor": {"icon":"","label":"Cursor","when":"omarchy-cmd-present cursor","checked":"default_editor_is cursor","action":"omarchy-default-editor cursor"},
"setup.default.editor.zed": {"icon":"","label":"Zed","when":"omarchy-cmd-present zeditor","checked":"default_editor_is zeditor","action":"omarchy-default-editor zed"},
"setup.default.editor.sublime": {"icon":"","label":"Sublime Text","when":"omarchy-cmd-present sublime_text","checked":"default_editor_is sublime_text","action":"omarchy-default-editor sublime_text"},
"setup.default.editor.helix": {"icon":"","label":"Helix","when":"omarchy-cmd-present helix","checked":"default_editor_is helix","action":"omarchy-default-editor helix"},
"setup.default.editor.vim": {"icon":"","label":"Vim","when":"omarchy-cmd-present vim","checked":"default_editor_is vim","action":"omarchy-default-editor vim"},
"setup.default.editor.emacs": {"icon":"","label":"Emacs","when":"omarchy-cmd-present emacs","checked":"default_editor_is emacs","action":"omarchy-default-editor emacs"},
"setup.dns": {"icon":"󰱔","label":"DNS","keywords":"network","action":"present_terminal omarchy-setup-dns"},
"setup.security": {"icon":"","label":"Security","keywords":"fingerprint fido2"},
"setup.config": {"icon":"","label":"Config","keywords":"files hyprland bar quickshell walker waybar"},
"setup.security.fingerprint": {"icon":"󰈷","label":"Fingerprint","action":"present_terminal omarchy-setup-security-fingerprint"},
"setup.security.fido2": {"icon":"","label":"Fido2","keywords":"key","action":"present_terminal omarchy-setup-security-fido2"},
"setup.config.hyprland": {"icon":"","label":"Hyprland","action":"open_in_editor \"$(hypr_config_file hyprland)\""},
"setup.config.hypridle": {"icon":"","label":"Hypridle","keywords":"idle","action":"open_in_editor ~/.config/hypr/hypridle.conf && omarchy-restart-hypridle"},
"setup.config.hyprlock": {"icon":"","label":"Hyprlock","keywords":"lock","action":"open_in_editor ~/.config/hypr/hyprlock.conf"},
"setup.config.hyprsunset": {"icon":"","label":"Hyprsunset","keywords":"night light","action":"open_in_editor ~/.config/hypr/hyprsunset.conf && omarchy-restart-hyprsunset"},
"setup.config.swayosd": {"icon":"","label":"Swayosd","action":"open_in_editor ~/.config/swayosd/config.toml && omarchy-restart-swayosd"},
"setup.config.walker": {"icon":"󰌧","label":"Walker","keywords":"launcher","action":"open_in_editor ~/.config/walker/config.toml && omarchy-restart-walker"},
"setup.config.bar": {"icon":"󰍜","label":"Bar","keywords":"quickshell shell config","action":"omarchy-launch-bar-settings"},
"setup.config.xcompose": {"icon":"󰞅","label":"XCompose","keywords":"compose key","action":"open_in_editor ~/.XCompose && omarchy-restart-xcompose"},
// Install
"install.package": {"icon":"󰣇","label":"Package","keywords":"pacman aur","action":"terminal omarchy-pkg-install"},
"install.aur": {"icon":"󰣇","label":"AUR","keywords":"package","action":"terminal omarchy-pkg-aur-install"},
"install.webapp": {"icon":"","label":"Web App","keywords":"pwa","action":"present_terminal omarchy-webapp-install"},
"install.tui": {"icon":"","label":"TUI","keywords":"terminal app","action":"present_terminal omarchy-tui-install"},
"install.service": {"icon":"","label":"Service","keywords":"dropbox tailscale vpn"},
"install.style": {"icon":"","label":"Style","keywords":"theme background font","target":"style.install"},
"install.development": {"icon":"󰵮","label":"Development","keywords":"languages programming"},
"install.editor": {"icon":"","label":"Editor","keywords":"ide"},
"install.terminal": {"icon":"","label":"Terminal","keywords":"emulator"},
"install.browser": {"icon":"","label":"Browser","keywords":"web"},
"install.ai": {"icon":"󱚤","label":"AI","keywords":"dictation ollama lm studio crush"},
"install.gaming": {"icon":"","label":"Gaming","keywords":"steam retroarch minecraft lutris heroic"},
"install.windows": {"icon":"󰍲","label":"Windows","keywords":"vm","action":"present_terminal 'omarchy-windows-vm install'"},
"install.browser.chrome": {"icon":"","label":"Chrome","action":"present_terminal 'omarchy-install-browser chrome'"},
"install.browser.edge": {"icon":"","label":"Edge","action":"present_terminal 'omarchy-install-browser edge'"},
"install.browser.brave": {"icon":"","label":"Brave","action":"present_terminal 'omarchy-install-browser brave'"},
"install.browser.brave-origin": {"icon":"","label":"Brave Origin","action":"present_terminal 'omarchy-install-browser brave-origin'"},
"install.browser.firefox": {"icon":"","label":"Firefox","action":"present_terminal 'omarchy-install-browser firefox'"},
"install.browser.zen": {"icon":"󰖟","label":"Zen","action":"present_terminal 'omarchy-install-browser zen'"},
"install.service.dropbox": {"icon":"","label":"Dropbox","action":"present_terminal omarchy-install-dropbox"},
"install.service.tailscale": {"icon":"","label":"Tailscale","keywords":"vpn","action":"present_terminal omarchy-install-tailscale"},
"install.service.nordvpn": {"icon":"󱇱","label":"NordVPN [AUR]","keywords":"vpn","action":"present_terminal omarchy-install-nordvpn"},
"install.service.once": {"icon":"󰏖","label":"ONCE","action":"present_terminal omarchy-install-once"},
"install.service.bitwarden": {"icon":"󰟵","label":"Bitwarden","keywords":"password","action":"install_and_launch Bitwarden 'bitwarden bitwarden-cli' bitwarden"},
"install.service.chromium-account": {"icon":"","label":"Chromium Account","keywords":"google","action":"present_terminal omarchy-install-chromium-google-account"},
"install.editor.vscode": {"icon":"","label":"VSCode","keywords":"code","action":"present_terminal omarchy-install-vscode"},
"install.editor.cursor": {"icon":"","label":"Cursor","action":"install_and_launch Cursor cursor-bin cursor"},
"install.editor.zed": {"icon":"","label":"Zed","action":"present_terminal omarchy-install-zed"},
"install.editor.sublime": {"icon":"","label":"Sublime Text","action":"install_and_launch 'Sublime Text' sublime-text-4 sublime_text"},
"install.editor.helix": {"icon":"","label":"Helix","action":"present_terminal omarchy-install-helix"},
"install.editor.vim": {"icon":"","label":"Vim","action":"install Vim vim"},
"install.editor.emacs": {"icon":"","label":"Emacs","action":"install Emacs emacs-wayland && systemctl --user enable --now emacs.service"},
"install.terminal.alacritty": {"icon":"","label":"Alacritty","action":"install_terminal alacritty"},
"install.terminal.foot": {"icon":"","label":"Foot","action":"install_terminal foot"},
"install.terminal.ghostty": {"icon":"","label":"Ghostty","action":"install_terminal ghostty"},
"install.terminal.kitty": {"icon":"","label":"Kitty","action":"install_terminal kitty"},
"install.ai.dictation": {"icon":"","label":"Dictation","keywords":"voice","action":"present_terminal omarchy-voxtype-install"},
"install.ai.lm-studio": {"icon":"󱚤","label":"LM Studio","action":"install 'LM Studio' lmstudio-bin"},
"install.ai.ollama": {"icon":"󱚤","label":"Ollama","action":"if omarchy-cmd-present nvidia-smi; then ollama_pkg=ollama-cuda; elif omarchy-cmd-present rocminfo; then ollama_pkg=ollama-rocm; else ollama_pkg=ollama; fi; install Ollama \"$ollama_pkg\""},
"install.ai.crush": {"icon":"󱚤","label":"Crush","action":"install Crush crush-bin"},
"install.gaming.steam": {"icon":"","label":"Steam","action":"present_terminal omarchy-install-gaming-steam"},
"install.gaming.retroarch": {"icon":"󰯉","label":"RetroArch","action":"present_terminal omarchy-install-gaming-retroarch"},
"install.gaming.minecraft": {"icon":"󰍳","label":"Minecraft","action":"install_and_launch Minecraft minecraft-launcher minecraft-launcher"},
"install.gaming.geforce-now": {"icon":"󰢹","label":"NVIDIA GeForce NOW","action":"present_terminal omarchy-install-gaming-geforce-now"},
"install.gaming.xbox-cloud": {"icon":"","label":"Xbox Cloud Gaming","action":"present_terminal omarchy-install-gaming-xbox-cloud"},
"install.gaming.xbox-controller": {"icon":"󰂯","label":"Xbox Controller","action":"present_terminal omarchy-install-gaming-xbox-controllers"},
"install.gaming.moonlight": {"icon":"󰍹","label":"Moonlight (GameStream)","action":"present_terminal omarchy-install-gaming-moonlight"},
"install.gaming.lutris": {"icon":"","label":"Lutris (Battle.net)","action":"present_terminal omarchy-install-gaming-lutris"},
"install.gaming.heroic": {"icon":"󱓟","label":"Heroic (Epic Games)","action":"present_terminal omarchy-install-gaming-heroic"},
"install.gaming.retro-launcher": {"icon":"󰯉","label":"RetroArch Game Launcher","action":"omarchy-games-retro-install"},
"install.development.rails": {"icon":"󰫏","label":"Ruby on Rails","action":"present_terminal 'omarchy-install-dev-env ruby'"},
"install.development.docker-dbs": {"icon":"","label":"Docker DB","keywords":"databases","action":"present_terminal omarchy-install-docker-dbs"},
"install.development.javascript": {"icon":"","label":"JavaScript","keywords":"node bun deno"},
"install.development.go": {"icon":"","label":"Go","keywords":"golang","action":"present_terminal 'omarchy-install-dev-env go'"},
"install.development.php": {"icon":"","label":"PHP","keywords":"laravel symfony"},
"install.development.python": {"icon":"","label":"Python","action":"present_terminal 'omarchy-install-dev-env python'"},
"install.development.elixir": {"icon":"","label":"Elixir","keywords":"phoenix"},
"install.development.zig": {"icon":"","label":"Zig","action":"present_terminal 'omarchy-install-dev-env zig'"},
"install.development.rust": {"icon":"","label":"Rust","action":"present_terminal 'omarchy-install-dev-env rust'"},
"install.development.java": {"icon":"","label":"Java","action":"present_terminal 'omarchy-install-dev-env java'"},
"install.development.dotnet": {"icon":"","label":".NET","action":"present_terminal 'omarchy-install-dev-env dotnet'"},
"install.development.ocaml": {"icon":"","label":"OCaml","action":"present_terminal 'omarchy-install-dev-env ocaml'"},
"install.development.clojure": {"icon":"","label":"Clojure","action":"present_terminal 'omarchy-install-dev-env clojure'"},
"install.development.scala": {"icon":"","label":"Scala","action":"present_terminal 'omarchy-install-dev-env scala'"},
"install.development.javascript.node": {"icon":"","label":"Node.js","action":"present_terminal 'omarchy-install-dev-env node'"},
"install.development.javascript.bun": {"icon":"","label":"Bun","action":"present_terminal 'omarchy-install-dev-env bun'"},
"install.development.javascript.deno": {"icon":"","label":"Deno","action":"present_terminal 'omarchy-install-dev-env deno'"},
"install.development.php.php": {"icon":"","label":"PHP","action":"present_terminal 'omarchy-install-dev-env php'"},
"install.development.php.laravel": {"icon":"","label":"Laravel","action":"present_terminal 'omarchy-install-dev-env laravel'"},
"install.development.php.symfony": {"icon":"","label":"Symfony","action":"present_terminal 'omarchy-install-dev-env symfony'"},
"install.development.elixir.elixir": {"icon":"","label":"Elixir","action":"present_terminal 'omarchy-install-dev-env elixir'"},
"install.development.elixir.phoenix": {"icon":"","label":"Phoenix","action":"present_terminal 'omarchy-install-dev-env phoenix'"},
// Remove
"remove.package": {"icon":"󰣇","label":"Package","keywords":"uninstall","action":"terminal omarchy-pkg-remove"},
"remove.webapp": {"icon":"","label":"Web App","keywords":"uninstall","action":"present_terminal omarchy-webapp-remove"},
"remove.tui": {"icon":"","label":"TUI","keywords":"uninstall terminal app","action":"present_terminal omarchy-tui-remove"},
"remove.development": {"icon":"󰵮","label":"Development","keywords":"uninstall languages"},
"remove.theme": {"icon":"󰸌","label":"Theme","keywords":"uninstall","action":"present_terminal omarchy-theme-remove"},
"remove.browser": {"icon":"","label":"Browser","keywords":"uninstall"},
"remove.dictation": {"icon":"","label":"Dictation","keywords":"uninstall voice","action":"present_terminal omarchy-voxtype-remove"},
"remove.gaming": {"icon":"","label":"Gaming","keywords":"uninstall steam retroarch minecraft"},
"remove.windows": {"icon":"󰍲","label":"Windows","keywords":"uninstall vm","action":"present_terminal 'omarchy-windows-vm remove'"},
"remove.preinstalls": {"icon":"󰏓","label":"Preinstalls","action":"present_terminal omarchy-remove-preinstalls"},
"remove.security": {"icon":"","label":"Security","keywords":"fingerprint fido2"},
"remove.security.fingerprint": {"icon":"󰈷","label":"Fingerprint","action":"present_terminal omarchy-remove-security-fingerprint"},
"remove.security.fido2": {"icon":"","label":"Fido2","action":"present_terminal omarchy-remove-security-fido2"},
"remove.browser.chrome": {"icon":"","label":"Chrome","action":"present_terminal 'omarchy-remove-browser chrome'"},
"remove.browser.edge": {"icon":"","label":"Edge","action":"present_terminal 'omarchy-remove-browser edge'"},
"remove.browser.brave": {"icon":"","label":"Brave","action":"present_terminal 'omarchy-remove-browser brave'"},
"remove.browser.brave-origin": {"icon":"","label":"Brave Origin","action":"present_terminal 'omarchy-remove-browser brave-origin'"},
"remove.browser.firefox": {"icon":"","label":"Firefox","action":"present_terminal 'omarchy-remove-browser firefox'"},
"remove.browser.zen": {"icon":"","label":"Zen","action":"present_terminal 'omarchy-remove-browser zen'"},
"remove.gaming.steam": {"icon":"","label":"Steam","action":"present_terminal omarchy-remove-gaming-steam"},
"remove.gaming.retroarch": {"icon":"","label":"RetroArch","action":"present_terminal omarchy-remove-gaming-retroarch"},
"remove.gaming.minecraft": {"icon":"󰍳","label":"Minecraft","action":"present_terminal omarchy-remove-gaming-minecraft"},
"remove.gaming.geforce-now": {"icon":"󰢹","label":"NVIDIA GeForce NOW","action":"present_terminal omarchy-remove-gaming-geforce-now"},
"remove.gaming.xbox-cloud": {"icon":"","label":"Xbox Cloud Gaming","action":"present_terminal omarchy-remove-gaming-xbox-cloud"},
"remove.gaming.xbox-controller": {"icon":"󰖺","label":"Xbox Controller (󰂯)","action":"present_terminal omarchy-remove-gaming-xbox-controllers"},
"remove.gaming.moonlight": {"icon":"󰍹","label":"Moonlight (GameStream)","action":"present_terminal omarchy-remove-gaming-moonlight"},
"remove.gaming.lutris": {"icon":"","label":"Lutris (Battle.net)","action":"present_terminal omarchy-remove-gaming-lutris"},
"remove.gaming.heroic": {"icon":"󱓟","label":"Heroic (Epic Games)","action":"present_terminal omarchy-remove-gaming-heroic"},
"remove.development.rails": {"icon":"󰫏","label":"Ruby on Rails","action":"present_terminal 'omarchy-remove-dev-env ruby'"},
"remove.development.javascript": {"icon":"","label":"JavaScript","keywords":"node bun deno"},
"remove.development.go": {"icon":"","label":"Go","keywords":"golang","action":"present_terminal 'omarchy-remove-dev-env go'"},
"remove.development.php": {"icon":"","label":"PHP","keywords":"laravel symfony"},
"remove.development.python": {"icon":"","label":"Python","action":"present_terminal 'omarchy-remove-dev-env python'"},
"remove.development.elixir": {"icon":"","label":"Elixir","keywords":"phoenix"},
"remove.development.zig": {"icon":"","label":"Zig","action":"present_terminal 'omarchy-remove-dev-env zig'"},
"remove.development.rust": {"icon":"","label":"Rust","action":"present_terminal 'omarchy-remove-dev-env rust'"},
"remove.development.java": {"icon":"","label":"Java","action":"present_terminal 'omarchy-remove-dev-env java'"},
"remove.development.dotnet": {"icon":"","label":".NET","action":"present_terminal 'omarchy-remove-dev-env dotnet'"},
"remove.development.ocaml": {"icon":"","label":"OCaml","action":"present_terminal 'omarchy-remove-dev-env ocaml'"},
"remove.development.clojure": {"icon":"","label":"Clojure","action":"present_terminal 'omarchy-remove-dev-env clojure'"},
"remove.development.scala": {"icon":"","label":"Scala","action":"present_terminal 'omarchy-remove-dev-env scala'"},
"remove.development.javascript.node": {"icon":"","label":"Node.js","action":"present_terminal 'omarchy-remove-dev-env node'"},
"remove.development.javascript.bun": {"icon":"","label":"Bun","action":"present_terminal 'omarchy-remove-dev-env bun'"},
"remove.development.javascript.deno": {"icon":"","label":"Deno","action":"present_terminal 'omarchy-remove-dev-env deno'"},
"remove.development.php.php": {"icon":"","label":"PHP","action":"present_terminal 'omarchy-remove-dev-env php'"},
"remove.development.php.laravel": {"icon":"","label":"Laravel","action":"present_terminal 'omarchy-remove-dev-env laravel'"},
"remove.development.php.symfony": {"icon":"","label":"Symfony","action":"present_terminal 'omarchy-remove-dev-env symfony'"},
"remove.development.elixir.elixir": {"icon":"","label":"Elixir","action":"present_terminal 'omarchy-remove-dev-env elixir'"},
"remove.development.elixir.phoenix": {"icon":"","label":"Phoenix","action":"present_terminal 'omarchy-remove-dev-env phoenix'"},
// Update
"update.omarchy": {"icon":"","label":"Omarchy","keywords":"system","action":"present_terminal omarchy-update"},
"update.channel": {"icon":"󰔫","label":"Channel","keywords":"stable rc edge dev"},
"update.config": {"icon":"","label":"Config","keywords":"refresh default"},
"update.themes": {"icon":"󰸌","label":"Extra Themes","action":"present_terminal omarchy-theme-update"},
"update.process": {"icon":"","label":"Process","keywords":"restart services"},
"update.hardware": {"icon":"󰇅","label":"Hardware","keywords":"restart audio wifi bluetooth trackpad"},
"update.firmware": {"icon":"","label":"Firmware","keywords":"fwupd","action":"present_terminal omarchy-update-firmware"},
"update.password": {"icon":"","label":"Password","keywords":"drive user"},
"update.timezone": {"icon":"","label":"Timezone","keywords":"time zone","action":"present_terminal omarchy-tz-select"},
"update.time": {"icon":"","label":"Time","keywords":"clock ntp","action":"present_terminal omarchy-update-time"},
"update.channel.stable": {"icon":"🟢","label":"Stable","action":"present_terminal 'omarchy-channel-set stable'"},
"update.channel.rc": {"icon":"🟡","label":"RC","keywords":"release candidate","action":"present_terminal 'omarchy-channel-set rc'"},
"update.channel.edge": {"icon":"🟠","label":"Edge","action":"present_terminal 'omarchy-channel-set edge'"},
"update.channel.dev": {"icon":"🔴","label":"Dev","keywords":"development","action":"present_terminal 'omarchy-channel-set dev'"},
"update.process.hypridle": {"icon":"","label":"Hypridle","keywords":"restart","action":"omarchy-restart-hypridle"},
"update.process.hyprsunset": {"icon":"","label":"Hyprsunset","keywords":"restart","action":"omarchy-restart-hyprsunset"},
"update.process.mako": {"icon":"󰎟","label":"Mako","keywords":"restart notifications","action":"omarchy-restart-mako"},
"update.process.swayosd": {"icon":"","label":"Swayosd","keywords":"restart","action":"omarchy-restart-swayosd"},
"update.process.walker": {"icon":"󰌧","label":"Walker","keywords":"restart launcher","action":"omarchy-restart-walker"},
"update.process.quickshell": {"icon":"󰍜","label":"Quickshell","keywords":"restart bar shell","action":"omarchy-restart-quickshell"},
"update.config.hyprland": {"icon":"","label":"Hyprland","keywords":"refresh","action":"present_terminal omarchy-refresh-hyprland"},
"update.config.hypridle": {"icon":"","label":"Hypridle","keywords":"refresh","action":"present_terminal omarchy-refresh-hypridle"},
"update.config.hyprlock": {"icon":"","label":"Hyprlock","keywords":"refresh","action":"present_terminal omarchy-refresh-hyprlock"},
"update.config.hyprsunset": {"icon":"","label":"Hyprsunset","keywords":"refresh","action":"present_terminal omarchy-refresh-hyprsunset"},
"update.config.plymouth": {"icon":"󱣴","label":"Plymouth","keywords":"refresh","action":"present_terminal omarchy-refresh-plymouth"},
"update.config.swayosd": {"icon":"","label":"Swayosd","keywords":"refresh","action":"present_terminal omarchy-refresh-swayosd"},
"update.config.tmux": {"icon":"","label":"Tmux","keywords":"refresh","action":"present_terminal omarchy-refresh-tmux"},
"update.config.walker": {"icon":"󰌧","label":"Walker","keywords":"refresh","action":"present_terminal omarchy-refresh-walker"},
"update.config.bar": {"icon":"󰍜","label":"Bar","keywords":"refresh quickshell","action":"present_terminal omarchy-refresh-bar"},
"update.hardware.audio": {"icon":"","label":"Audio","keywords":"restart pipewire","action":"present_terminal omarchy-restart-pipewire"},
"update.hardware.wifi": {"icon":"󱚾","label":"Wi-Fi","keywords":"restart wireless","action":"present_terminal omarchy-restart-wifi"},
"update.hardware.bluetooth": {"icon":"󰂯","label":"Bluetooth","keywords":"restart","action":"present_terminal omarchy-restart-bluetooth"},
"update.hardware.trackpad": {"icon":"󰟸","label":"Trackpad","keywords":"restart touchpad","action":"present_terminal omarchy-restart-trackpad"},
"update.password.drive": {"icon":"","label":"Drive Encryption","action":"present_terminal omarchy-drive-password"},
"update.password.user": {"icon":"","label":"User","keywords":"passwd","action":"present_terminal passwd"},
}
+7 -1
View File
@@ -30,6 +30,7 @@ default/quickshell/omarchy-shell/
bar/ first-party plugins (see plugins/README.md)
bar-settings/
image-picker/
menu/
```
The plugin discovery path is documented in [plugins/README.md](plugins/README.md).
@@ -98,7 +99,9 @@ are discovered the same way and cannot be disabled.
The shell exposes a single `shell` IPC target plus whatever extra targets
individual plugins register (e.g. the bar's `bar` target for refresh
hooks, the background switcher's `image-selector` target).
hooks, the image picker's `image-selector` target). `omarchy-menu` uses the
shell target to summon the first-party `omarchy.menu` plugin instead of
running a separate Quickshell instance.
| Method | Returns | Effect |
|------------------------------------------|---------|-------------------------------------------------------|
@@ -116,6 +119,9 @@ Direct invocation:
quickshell ipc -p $OMARCHY_PATH/default/quickshell/omarchy-shell call shell ping
```
Hyprland starts the shell through `omarchy-restart-quickshell` on boot.
Use `omarchy restart quickshell` to reload the long-running shell process.
A convenience wrapper, [`omarchy-shell-ipc`](../../../bin/omarchy-shell-ipc),
starts the shell if it is not already running, then forwards a `call`. It
is the canonical way for other Omarchy CLIs to talk to the shell.
@@ -13,6 +13,7 @@ User-installed plugins live alongside these conceptually but on disk under
| Bar | `omarchy.bar` | `bar` | persistent | `bar/Bar.qml` |
| Bar settings | `omarchy.bar-settings` | `panel` | on-demand | `bar-settings/BarSettingsPanel.qml` |
| Image picker | `omarchy.image-picker` | `overlay` | on-demand | `image-picker/ImagePicker.qml` |
| Omarchy menu | `omarchy.menu` | `menu` | on-demand | `menu/Menu.qml` |
## Bar
@@ -62,8 +63,23 @@ clears it without writing a selection.
The plugin has `keepLoaded: true` so the layer-shell window survives
between summons within a single shell session.
## Omarchy menu
Quickshell-powered replacement for the legacy Walker-driven `omarchy-menu`.
The menu UI lives in `menu/Menu.qml` as a first-party `menu` plugin and is
summoned through the shell (`omarchy-shell-ipc shell summon omarchy.menu ...`),
so it shares the long-running `omarchy-shell` process instead of starting a
second Quickshell instance.
The menu definition lives outside the shell host code:
- defaults: `default/omarchy/omarchy-menu.jsonc`
- user extensions: `~/.config/omarchy/extensions/omarchy-menu.jsonc`
`bin/omarchy-menu` still owns the Bash action helpers and dynamic providers;
it builds the menu JSON, summons `omarchy.menu`, waits for the selection, and
runs the selected action.
## Coming soon
- `omarchy.menu` — folds the existing `omarchy-menu` (currently on another
branch) into the shell as a `menu` plugin. Not present on this branch.
- `omarchy.theme-switcher` — folds theme switching into the shell.
@@ -0,0 +1,914 @@
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import QtQuick
Item {
id: root
// Injected by omarchy-shell when this plugin is summoned.
property string omarchyPath: Quickshell.env("OMARCHY_PATH") || (Quickshell.env("HOME") + "/.local/share/omarchy")
property var shell: null
property var manifest: null
property var pluginRegistry: null
// Plugin lifecycle hooks. The host calls open(payloadJson) after
// `omarchy-shell-ipc shell summon omarchy.menu ...` and close() when hidden.
property string menuJsonFile: ""
property string pendingInitialMenu: "root"
property string pendingSelectionFile: ""
property string pendingDoneFile: ""
property string pendingColorsRaw: ""
function decodeBase64(value) {
var s = String(value || "")
if (!s) return ""
try { return Qt.atob(s) } catch (e) { return s }
}
function open(payloadJson) {
var payload = ({})
try { payload = JSON.parse(payloadJson || "{}") } catch (e) { payload = ({}) }
root.pendingInitialMenu = payload.initialMenu || "root"
root.pendingSelectionFile = payload.selectionFile || ""
root.pendingDoneFile = payload.doneFile || ""
root.pendingColorsRaw = payload.colorsRawBase64 ? root.decodeBase64(payload.colorsRawBase64) : (payload.colorsRaw || "")
if (payload.fontFamily) root.fontFamily = payload.fontFamily
var menuJson = payload.menuJsonBase64 ? root.decodeBase64(payload.menuJsonBase64) : (payload.menuJson || "")
if (menuJson) {
root.openMenu(menuJson, root.pendingInitialMenu, root.pendingSelectionFile, root.pendingDoneFile, root.pendingColorsRaw)
return
}
root.menuJsonFile = payload.menuJsonFile || ""
if (root.menuJsonFile) menuJsonFileView.reload()
}
function close() {
root.closeMenu("")
}
property string menuBin: omarchyPath + "/bin/omarchy-menu"
property string fontFamily: Quickshell.env("OMARCHY_MENU_FONT") || "monospace"
property string colorsFile: Quickshell.env("OMARCHY_MENU_COLORS_FILE") || (Quickshell.env("HOME") + "/.config/omarchy/current/theme/colors.toml")
property string styleFile: Quickshell.env("OMARCHY_MENU_STYLE_FILE") || (Quickshell.env("HOME") + "/.local/state/omarchy/toggles/quickshell-menu.json")
property string selectionFile: ""
property string doneFile: ""
property bool requestActive: false
property bool opened: false
property bool rowsLoaded: false
property string activeMenu: "root"
property string filterText: ""
property int selectedIndex: 0
property int requestSerial: 0
property int applySerial: 0
property var items: ({})
property var itemOrder: []
property var navStack: []
property var providersLoaded: ({})
property var providerQueue: []
property var doneFilesToRelease: []
property color accent: "#89b4fa"
property color background: "#101315"
property color foreground: "#cacccc"
property color border: foreground
property int cornerRadius: 0
property int contentMargin: 18
property int headerHeight: 34
property int contentSpacing: 6
property int baseRowHeight: 50
property int detailRowHeight: 58
property int rowSpacing: 3
property int dividerHeight: 17
property bool searchDivider: false
property int layoutSerial: 0
property int cardWidth: Math.min(300, panel.width - 48)
property int visibleRowsHeight: rowListHeight(layoutSerial, displayModel.count, filterText, searchDivider)
property int cardHeight: Math.min(Math.max(220, contentMargin * 2 + headerHeight + contentSpacing + visibleRowsHeight), panel.height - 48)
function shellQuote(value) {
return "'" + String(value).replace(/'/g, "'\\''") + "'"
}
function decodeField(value) {
return String(value || "").replace(/\v/g, "\n").replace(/\f/g, "\t")
}
function withAlpha(color, alpha) {
return Qt.rgba(color.r, color.g, color.b, alpha)
}
function rowHeightForDetail(detail) {
return root.filterText && detail ? root.detailRowHeight : root.baseRowHeight
}
function rowListHeight(_serial, _count, _filter, _divider) {
if (displayModel.count === 0) return root.baseRowHeight
var count = Math.min(displayModel.count, 10)
var total = 0
var previousSection = ""
for (var i = 0; i < count; i++) {
var row = displayModel.get(i)
if (i > 0) total += root.rowSpacing
if (row.section === "drilldown" && previousSection !== "drilldown") total += root.dividerHeight
total += root.rowHeightForDetail(row.detail)
previousSection = row.section
}
return total
}
function item(id) {
return root.items[id] || null
}
function loadMenuJson(raw) {
var nextItems = ({})
var nextOrder = []
var payload = JSON.parse(raw || "{}")
var rows = payload.items || []
for (var i = 0; i < rows.length; i++) {
var entry = rows[i]
var id = entry.id || ""
if (!id) continue
var order = nextItems[id] ? nextItems[id].order : nextOrder.length
if (!nextItems[id]) nextOrder.push(id)
nextItems[id] = {
id: id,
parent: entry.parent || "",
kind: entry.kind || "action",
icon: entry.icon || "",
label: entry.label || id,
target: entry.target || "",
keywords: entry.keywords || "",
description: entry.description || "",
action: entry.action || "",
provider: entry.provider || "",
order: order
}
}
if (!nextItems.root) {
nextItems.root = { id: "root", parent: "", kind: "menu", icon: "", label: "Go", target: "", keywords: "", description: "", order: -1 }
}
root.items = nextItems
root.itemOrder = nextOrder
root.rowsLoaded = true
}
function mergeProviderJson(raw, menuId) {
var payload = ({})
try {
payload = JSON.parse(raw || "{}")
} catch (e) {
return
}
var rows = payload.items || []
var changed = false
for (var i = 0; i < rows.length; i++) {
var entry = rows[i]
var id = entry.id || ""
if (!id) continue
if (!root.items[id]) root.itemOrder.push(id)
root.items[id] = {
id: id,
parent: entry.parent || menuId,
kind: entry.kind || "action",
icon: entry.icon || "",
label: entry.label || id,
target: entry.target || "",
keywords: entry.keywords || "",
description: entry.description || "",
action: entry.action || "",
provider: entry.provider || "",
order: root.itemOrder.indexOf(id)
}
changed = true
}
if (changed) root.rebuildDisplay()
}
function startProviderForMenu(id) {
var entry = root.item(id)
if (!entry || !entry.provider || root.providersLoaded[id]) return
root.providersLoaded[id] = true
providerProc.menuId = id
providerProc.output = ""
providerProc.command = [root.menuBin, "--provider", entry.provider, id]
providerProc.running = true
}
function startNextProvider() {
if (providerProc.running) return
while (root.providerQueue.length > 0) {
var id = root.providerQueue.shift()
var entry = root.item(id)
if (!entry || !entry.provider || root.providersLoaded[id]) continue
root.startProviderForMenu(id)
return
}
}
function loadProviderForMenu(id) {
var entry = root.item(id)
if (!entry || !entry.provider || root.providersLoaded[id]) return
if (providerProc.running) {
if (root.providerQueue.indexOf(id) < 0) root.providerQueue = root.providerQueue.concat([id])
return
}
root.startProviderForMenu(id)
}
function loadProvidersForSearch() {
var active = root.item(root.activeMenu) ? root.activeMenu : "root"
for (var i = 0; i < root.itemOrder.length; i++) {
var entry = root.item(root.itemOrder[i])
if (!entry || !entry.provider || root.providersLoaded[entry.id]) continue
if (active !== "root" && entry.id !== active && !root.isDescendantOf(entry.id, active)) continue
root.loadProviderForMenu(entry.id)
}
}
function depthFor(id) {
var depth = 0
var current = root.item(id)
var guard = 0
while (current && current.parent && current.parent !== "root" && guard < 32) {
depth += 1
current = root.item(current.parent)
guard += 1
}
return depth
}
function pathFor(id) {
var labels = []
var current = root.item(id)
var guard = 0
while (current && current.id !== "root" && guard < 32) {
labels.unshift(current.label)
current = root.item(current.parent)
guard += 1
}
return labels.join(" ")
}
function parentPathFor(id) {
var entry = root.item(id)
if (!entry || !entry.parent || entry.parent === "root") return ""
return root.pathFor(entry.parent)
}
function breadcrumbFor(id) {
var path = root.pathFor(id)
return path ? ("Go " + path) : "Go"
}
function isDescendantOf(id, ancestorId) {
if (ancestorId === "root") return id !== "root"
var current = root.item(id)
var guard = 0
while (current && current.parent && guard < 32) {
if (current.parent === ancestorId) return true
current = root.item(current.parent)
guard += 1
}
return false
}
function childCount(id) {
var count = 0
for (var i = 0; i < root.itemOrder.length; i++) {
var entry = root.item(root.itemOrder[i])
if (entry && entry.parent === id) count += 1
}
return count
}
function matchesQuery(entry, query) {
if (!entry || entry.id === "root") return false
var haystack = (entry.label + " " + root.pathFor(entry.id) + " " + entry.keywords + " " + entry.description).toLowerCase()
var terms = query.toLowerCase().trim().split(/\s+/)
for (var i = 0; i < terms.length; i++) {
if (terms[i] && haystack.indexOf(terms[i]) === -1) return false
}
return true
}
function searchScore(entry, query) {
var needle = query.toLowerCase().trim()
var label = entry.label.toLowerCase()
var path = root.pathFor(entry.id).toLowerCase()
var keywords = entry.keywords.toLowerCase()
var parent = root.item(entry.parent)
var parentLabel = parent ? parent.label.toLowerCase() : ""
var score = 80
if (label === needle) score = entry.parent === "root" ? 2 : 0
else if (label.indexOf(needle) === 0) score = 10
else if (path.indexOf(needle) === 0) score = entry.kind === "action" ? 12 : 14
else if (parentLabel === needle) score = entry.kind === "action" ? 18 : 20
else if (label.indexOf(needle) >= 0) score = 30
else if (path.indexOf(needle) >= 0) score = 40
else if (keywords.indexOf(needle) >= 0) score = 50
if (entry.kind === "menu" || entry.kind === "link") score -= 2
return score * 1000 + root.depthFor(entry.id) * 25 + entry.order
}
function displayRow(entry, detail, score, section) {
var target = entry.kind === "link" ? entry.target : entry.id
return {
itemId: entry.id,
kind: entry.kind,
icon: entry.icon,
label: entry.label,
target: target,
detail: detail || "",
path: root.pathFor(entry.id),
childCount: (entry.kind === "menu" || entry.kind === "link") ? root.childCount(target) : 0,
action: entry.action || "",
provider: entry.provider || "",
score: score || 0,
section: section || ""
}
}
function rebuildDisplay() {
displayModel.clear()
if (!root.rowsLoaded) return
var active = root.item(root.activeMenu) ? root.activeMenu : "root"
root.activeMenu = active
var rows = []
var query = root.filterText.trim()
root.searchDivider = false
if (query) {
var currentRows = []
var drilldownRows = []
for (var i = 0; i < root.itemOrder.length; i++) {
var entry = root.item(root.itemOrder[i])
if (!entry || entry.id === "root") continue
if (!root.isDescendantOf(entry.id, active)) continue
if (!root.matchesQuery(entry, query)) continue
var detail = root.parentPathFor(entry.id)
var row = root.displayRow(entry, detail, root.searchScore(entry, query))
if (entry.parent === active) currentRows.push(row)
else drilldownRows.push(row)
}
var searchSort = function(a, b) {
if (a.score !== b.score) return a.score - b.score
return a.path.localeCompare(b.path)
}
currentRows.sort(searchSort)
drilldownRows.sort(searchSort)
root.searchDivider = currentRows.length > 0 && drilldownRows.length > 0
if (root.searchDivider) {
for (var d = 0; d < drilldownRows.length; d++) drilldownRows[d].section = "drilldown"
}
rows = currentRows.concat(drilldownRows)
} else {
if (active !== "root") {
var parentTarget = root.item(active).parent || "root"
var backTarget = root.navStack.length > 0 ? root.navStack[root.navStack.length - 1] : parentTarget
rows.push({ itemId: "__back", kind: "back", icon: "", label: "Back", target: backTarget, detail: root.breadcrumbFor(backTarget), path: "", childCount: 0, action: "", score: -1, section: "" })
}
for (var j = 0; j < root.itemOrder.length; j++) {
var child = root.item(root.itemOrder[j])
if (!child || child.parent !== active) continue
rows.push(root.displayRow(child, child.description, child.order))
}
}
for (var k = 0; k < rows.length; k++) displayModel.append(rows[k])
layoutSerial += 1
if (displayModel.count === 0) selectedIndex = 0
else if (selectedIndex >= displayModel.count) selectedIndex = displayModel.count - 1
else if (selectedIndex < 0) selectedIndex = 0
Qt.callLater(function() {
if (displayModel.count > 0) resultList.positionViewAtIndex(root.selectedIndex, ListView.Contain)
})
}
function select(delta) {
if (displayModel.count === 0) return
selectedIndex += delta
if (selectedIndex < 0) selectedIndex = 0
if (selectedIndex >= displayModel.count) selectedIndex = displayModel.count - 1
resultList.positionViewAtIndex(selectedIndex, ListView.Contain)
}
function setFilter(nextFilter) {
root.filterText = nextFilter
root.selectedIndex = 0
if (root.filterText.trim()) root.loadProvidersForSearch()
root.rebuildDisplay()
}
function setActiveMenu(id, pushHistory) {
if (!root.item(id)) id = "root"
if (pushHistory && id !== root.activeMenu) root.navStack = root.navStack.concat([root.activeMenu])
root.activeMenu = id
root.filterText = ""
root.selectedIndex = 0
root.rebuildDisplay()
root.loadProviderForMenu(id)
}
function goBack() {
if (root.activeMenu === "root") return false
if (root.navStack.length > 0) {
var previous = root.navStack[root.navStack.length - 1]
root.navStack = root.navStack.slice(0, root.navStack.length - 1)
root.setActiveMenu(previous, false)
return true
}
var active = root.item(root.activeMenu)
root.setActiveMenu((active && active.parent) ? active.parent : "root", false)
return true
}
function activateIndex(index) {
if (index < 0 || index >= displayModel.count) return
var row = displayModel.get(index)
if (row.kind === "back") {
root.goBack()
} else if (row.kind === "menu" || row.kind === "link") {
root.setActiveMenu(row.target || row.itemId, true)
} else {
root.applySelected(row.itemId, row.action)
}
}
function releaseNextDoneFile() {
if (releaseProc.running || doneFilesToRelease.length === 0) return
var path = doneFilesToRelease.shift()
releaseProc.command = ["bash", "-lc", ": > " + shellQuote(path)]
releaseProc.running = true
}
function finishDoneFile(path) {
if (!path) return
doneFilesToRelease.push(path)
releaseNextDoneFile()
}
function resetRequest() {
requestActive = false
selectionFile = ""
doneFile = ""
}
function applySelected(id, action) {
if (!id || !selectionFile || !doneFile) {
cancel()
return
}
var activeSelectionFile = selectionFile
var activeDoneFile = doneFile
applySerial = requestSerial
resetRequest()
opened = false
applyProc.command = ["bash", "-lc", "printf '%s\\t%s\\n' " + shellQuote(id) + " " + shellQuote(action || "") + " > " + shellQuote(activeSelectionFile) + "; : > " + shellQuote(activeDoneFile)]
applyProc.running = true
}
function cancel() {
if (requestActive) finishDoneFile(doneFile)
resetRequest()
opened = false
filterText = ""
}
function closeMenu(nextDoneFile) {
requestSerial += 1
if (requestActive) finishDoneFile(doneFile)
if (nextDoneFile && nextDoneFile !== doneFile) finishDoneFile(nextDoneFile)
resetRequest()
opened = false
filterText = ""
}
function openExistingMenu(initialMenu, nextSelectionFile, nextDoneFile) {
requestSerial += 1
if (requestActive && doneFile && doneFile !== nextDoneFile) finishDoneFile(doneFile)
selectionFile = nextSelectionFile
doneFile = nextDoneFile
requestActive = !!doneFile
activeMenu = root.item(initialMenu) ? initialMenu : "root"
navStack = []
filterText = ""
selectedIndex = 0
opened = true
rebuildDisplay()
loadProviderForMenu(activeMenu)
Qt.callLater(function() { keyCatcher.forceActiveFocus() })
}
function openMenu(menuJson, initialMenu, nextSelectionFile, nextDoneFile, colorsRaw) {
loadMenuJson(menuJson)
if (colorsRaw) loadColors(colorsRaw)
providersLoaded = ({})
providerQueue = []
openExistingMenu(initialMenu, nextSelectionFile, nextDoneFile)
}
function loadColors(raw) {
var lines = String(raw || "").split("\n")
for (var i = 0; i < lines.length; i++) {
var match = lines[i].match(/^\s*([A-Za-z0-9_-]+)\s*=\s*["']?(#[0-9A-Fa-f]{6})/)
if (!match) continue
if (match[1] === "foreground") foreground = match[2]
else if (match[1] === "background") background = match[2]
else if (match[1] === "color4" || match[1] === "accent") accent = match[2]
}
border = foreground
}
function loadStyle(raw) {
try {
var style = JSON.parse(raw || "{}")
root.cornerRadius = Number(style.radius || 0)
} catch (e) {}
}
ListModel { id: displayModel }
Process {
id: providerProc
property string menuId: ""
property string output: ""
stdout: SplitParser {
onRead: function(data) {
providerProc.output += data + "\n"
}
}
onExited: {
root.mergeProviderJson(output, menuId)
if (root.filterText.trim()) root.loadProvidersForSearch()
root.startNextProvider()
}
}
FileView {
id: menuJsonFileView
path: root.menuJsonFile
printErrors: false
onLoaded: root.openMenu(text(), root.pendingInitialMenu, root.pendingSelectionFile, root.pendingDoneFile, root.pendingColorsRaw)
}
FileView {
path: root.colorsFile
watchChanges: true
onLoaded: root.loadColors(text())
onFileChanged: { reload(); root.loadColors(text()) }
}
FileView {
path: root.styleFile
watchChanges: true
onLoaded: root.loadStyle(text())
onFileChanged: { reload(); root.loadStyle(text()) }
}
Process {
id: applyProc
onExited: {
if (root.applySerial === root.requestSerial) root.opened = false
}
}
Process {
id: releaseProc
onExited: root.releaseNextDoneFile()
}
PanelWindow {
id: panel
visible: root.opened && root.rowsLoaded
anchors { top: true; bottom: true; left: true; right: true }
color: "transparent"
WlrLayershell.namespace: "omarchy-menu"
WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
exclusionMode: ExclusionMode.Ignore
MouseArea {
anchors.fill: parent
onClicked: root.cancel()
}
Rectangle {
id: card
width: root.cardWidth
height: root.cardHeight
radius: root.cornerRadius
anchors.centerIn: parent
color: root.background
border.color: root.withAlpha(root.border, 0.36)
border.width: 1
MouseArea { anchors.fill: parent; onClicked: {} }
Item {
id: keyCatcher
anchors.fill: parent
focus: true
Keys.priority: Keys.BeforeItem
Keys.onPressed: function(event) {
if (event.key === Qt.Key_Escape) {
if (root.filterText) root.setFilter("")
else root.cancel()
event.accepted = true
} else if (event.key === Qt.Key_Backspace) {
if (root.filterText.length > 0) root.setFilter(root.filterText.slice(0, -1))
else root.goBack()
event.accepted = true
} else if (event.key === Qt.Key_Up) {
root.select(-1)
event.accepted = true
} else if (event.key === Qt.Key_Down) {
root.select(1)
event.accepted = true
} else if (event.key === Qt.Key_PageUp) {
root.select(-6)
event.accepted = true
} else if (event.key === Qt.Key_PageDown) {
root.select(6)
event.accepted = true
} else if (event.key === Qt.Key_Left) {
if (!root.filterText) root.goBack()
event.accepted = true
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter || event.key === Qt.Key_Right) {
root.activateIndex(root.selectedIndex)
event.accepted = true
} else if (event.text && event.text.length === 1 && event.text.charCodeAt(0) >= 32 && event.text.charCodeAt(0) !== 127 && (event.modifiers === Qt.NoModifier || event.modifiers === Qt.ShiftModifier)) {
root.setFilter(root.filterText + event.text)
event.accepted = true
}
}
}
Column {
anchors.fill: parent
anchors.margins: root.contentMargin
spacing: root.contentSpacing
Rectangle {
width: parent.width
height: root.headerHeight
radius: root.cornerRadius
color: "transparent"
border.width: 0
Text {
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
text: root.filterText || ((root.item(root.activeMenu) ? root.item(root.activeMenu).label : "Go") + "…")
color: root.foreground
opacity: root.filterText ? 1 : 0.58
font.family: root.fontFamily
font.pixelSize: 16
elide: Text.ElideRight
}
}
Item {
width: parent.width
height: root.visibleRowsHeight
ListView {
id: resultList
anchors.fill: parent
model: displayModel
clip: true
spacing: root.rowSpacing
boundsBehavior: Flickable.StopAtBounds
section.property: "section"
section.criteria: ViewSection.FullString
section.delegate: Item {
required property string section
width: ListView.view.width
height: section === "drilldown" ? root.dividerHeight : 0
visible: section === "drilldown"
Rectangle {
anchors.left: parent.left
anchors.leftMargin: 4
anchors.right: parent.right
anchors.rightMargin: 4
anchors.verticalCenter: parent.verticalCenter
height: 1
color: root.withAlpha(root.foreground, 0.2)
}
}
delegate: Rectangle {
id: row
required property int index
required property string itemId
required property string kind
required property string icon
required property string label
required property string target
required property string detail
required property string path
required property string action
required property int childCount
width: ListView.view.width
height: root.rowHeightForDetail(row.detail)
radius: root.cornerRadius
color: index === root.selectedIndex ? root.withAlpha(root.foreground, 0.08) : root.withAlpha(root.foreground, mouseArea.containsMouse ? 0.045 : 0)
border.color: "transparent"
border.width: 0
Rectangle {
visible: false
width: 4
height: parent.height - 18
radius: Math.min(root.cornerRadius, 4)
color: root.accent
anchors.left: parent.left
anchors.leftMargin: 8
anchors.verticalCenter: parent.verticalCenter
}
Text {
id: iconText
text: row.icon
color: index === root.selectedIndex ? root.accent : root.foreground
opacity: row.kind === "back" ? 0.7 : 1
font.family: root.fontFamily
font.pixelSize: 18
width: 36
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
anchors.left: parent.left
anchors.leftMargin: 8
y: contentColumn.y + labelText.y + (labelText.height - height) / 2
}
Column {
id: contentColumn
anchors.left: iconText.right
anchors.leftMargin: 6
anchors.right: trail.left
anchors.rightMargin: 6
anchors.verticalCenter: parent.verticalCenter
spacing: 3
Text {
id: labelText
width: parent.width
text: row.label
color: index === root.selectedIndex ? root.accent : root.foreground
font.family: root.fontFamily
font.pixelSize: 16
font.weight: Font.Medium
elide: Text.ElideRight
}
Text {
width: parent.width
text: row.detail
visible: root.filterText && row.detail.length > 0
color: root.foreground
opacity: 0.52
font.family: root.fontFamily
font.pixelSize: 11
elide: Text.ElideRight
}
}
Row {
id: trail
width: 14
anchors.right: parent.right
anchors.rightMargin: 8
y: contentColumn.y + labelText.y + (labelText.height - height) / 2
spacing: 0
Text {
visible: false
text: row.childCount
color: root.foreground
opacity: 0.45
font.family: root.fontFamily
font.pixelSize: 12
anchors.verticalCenter: parent.verticalCenter
}
Text {
text: row.kind === "menu" || row.kind === "link" ? "" : (row.kind === "back" ? "" : "↵")
color: index === root.selectedIndex ? root.accent : root.foreground
opacity: row.kind === "back" ? 0 : 0.36
font.family: root.fontFamily
font.pixelSize: 16
font.weight: Font.Normal
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: root.activateIndex(row.index)
}
}
}
Column {
anchors.centerIn: parent
spacing: 8
visible: displayModel.count === 0
Text {
text: "󰈉"
color: root.accent
opacity: 0.8
font.family: root.fontFamily
font.pixelSize: 28
horizontalAlignment: Text.AlignHCenter
width: 320
}
Text {
text: root.filterText ? "No matches for “" + root.filterText + "”" : "Nothing here yet"
color: root.foreground
opacity: 0.7
font.family: root.fontFamily
font.pixelSize: 14
horizontalAlignment: Text.AlignHCenter
width: 320
}
}
}
Item {
width: parent.width
height: 0
}
}
}
}
}
@@ -0,0 +1,15 @@
{
"schemaVersion": 1,
"id": "omarchy.menu",
"name": "Omarchy menu",
"version": "1.0.0",
"author": "Omarchy",
"description": "Quickshell-powered Omarchy command menu",
"kinds": ["menu"],
"activation": "on-demand",
"keepLoaded": true,
"entryPoints": { "menu": "Menu.qml" },
"ipc": {
"summon": "menu"
}
}