Skip to content

Instantly share code, notes, and snippets.

@jbrechtel
Created May 15, 2025 00:40
Show Gist options
  • Save jbrechtel/0760530561554931748d6e4e2b394fea to your computer and use it in GitHub Desktop.
Save jbrechtel/0760530561554931748d6e4e2b394fea to your computer and use it in GitHub Desktop.
Switch Run
[ { name: "Firefox - Personal"
, app_id: "firefox_personal"
, exec: "/usr/lib/firefox/firefox"
, args: ["--class=firefox", "-P", "personal", "--name=firefox_personal"]
}
, { name: "Firefox - Work"
, app_id: "firefox_work"
, exec: "/usr/lib/firefox/firefox"
, args: ["--class=firefox", "-P", "flipstone", "--name=firefox_work"]
}
, { name: "Slack"
, app_id: "Slack"
, exec: "/usr/bin/slack"
, args: ["--ozone-platform=wayland", "-s", "%U"]
}
, { name: "Emacs"
, app_id: "emacs"
, exec: "emacsclient"
, args: ["--alternate-editor=", "--create-frame"]
}
# These details were extracted from the .desktop file created after using Chromium's "install as app" feature on the Gather site
, { name: "Gather"
, app_id: "chrome-lomadbaljkledafpiopomkmeoccppjpk-Default"
, exec: "/opt/google/chrome/google-chrome"
, args: ["--ozone-platform=wayland", "--profile-directory=Default", "--app-id=lomadbaljkledafpiopomkmeoccppjpk"]
}
, { name: "Signal"
, app_id: "signal"
, exec: "signal-desktop"
, args: ["--ozone-platform=wayland", "--", "%u"]
}
, { name: "Chromium"
, app_id: "chromium"
, exec: "chromium"
, args: ["--ozone-platform=wayland"]
}
, { name: "Thunar (file manager)"
, app_id: "thunar"
, exec: "thunar"
, args: []
}
, { name: "Obsidian"
, app_id: "obsidian"
, exec: "/usr/bin/obsidian"
, args: []
}
, { name: "WezTerm"
, app_id: "org.wezfurlong.wezterm"
, exec: "/usr/bin/wezterm"
, args: []
}
]
#!/usr/bin/nu
def switch_to [target_window_id: string] {
let focus_cmd = {Action: { FocusWindow: { id: ($target_window_id | into int ) } } }
$focus_cmd | to json -r | socat STDIO $env.NIRI_SOCKET
}
def launch [target_app_id: string] {
let launcher_apps = open $"($env.HOME)/.config/switchrun/apps.nuon"
let app = (
$launcher_apps |
where app_id == $target_app_id |
first
)
if $app != null { run-external $app.exec ...$app.args} else { print "no exec found" }
}
def main [target_app_id: string] {
let running_apps = niri msg --json windows | from json
let matches = $running_apps | where app_id == $target_app_id
print $matches
if ($matches | is-empty) {
launch $target_app_id
} else {
let focused_matches = $matches | enumerate | where item.is_focused == true | get index
if ($focused_matches | is-empty) {
switch_to (($matches | first | get id) | into string)
} else {
# In the event of multiple matches, switch to the one after the focused one - wrapping around
# That way we will cycle through them
let target_index = ($focused_matches | first) - 1
print $target_index
print ($matches | length)
let target_window = if ($target_index < 0) { $matches | last } else { ($matches | get $target_index) }
switch_to ($target_window.id | into string)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment