nix-files/pkgs/additional/sane-open/sane-open
Colin c50a4d1d71 static-nix-shell: fix mkBash scripts to actually be invokable from the CLI
they need the `bash` package! how did this work before?
2024-06-15 07:42:04 +00:00

218 lines
5.5 KiB
Plaintext
Executable File

#!/usr/bin/env nix-shell
#!nix-shell -i bash -p bash -p glib -p jq -p procps -p sway -p util-linux -p xdg-utils
set -e
usage() {
echo "usage: sane-open [options] <org.my.desktop | /path/to/file>"
echo "given some resource, ask the xdg-desktop-portal service to open it"
echo "this could be either the name of an application, or a URI identifying a file"
echo
echo "options:"
echo "--auto-keyboard: toggle the virtual keyboard state to whatever's preferred by the app"
echo "--application <thing.desktop>: open the desktop file (by name, not path)"
echo "--file </path/to/file>: open the file using the default mime handler"
exit $1
}
log() {
if [ -n "$SANE_OPEN_DEBUG" ]; then
printf 'sane-open: %s\n' "$1" >&2
fi
}
configureKeyboardFor_application() {
case "$1" in
Alacritty.desktop)
setKeyboard show
;;
app.drey.Dialect.desktop)
setKeyboard showIfRoom
;;
com.github.hugolabe.Wike.desktop)
setKeyboard showIfRoom
;;
# io.github.lainsce.Notejot.desktop)
# setKeyboard showIfRoom
# ;;
org.gnome.Epiphany.desktop)
setKeyboard showIfRoom
;;
rofi.desktop)
setKeyboard showIfRoom
;;
rofi-applications.desktop)
setKeyboard showIfRoom
;;
rofi-filebrowser.desktop)
setKeyboard showIfRoom
;;
rofi-snippets.desktop)
setKeyboard showIfRoom
;;
sane-screenshot.desktop)
# leave unchanged
;;
xdg-terminal-exec.desktop)
setKeyboard show
;;
*)
setKeyboard hide
;;
esac
}
configureKeyboardFor_file() {
local mime=$(xdg-mime query filetype "$1")
local application=$(xdg-mime query default "$mime")
configureKeyboardFor_application "$application"
}
open_application() {
log "open_application: '$1'"
gdbus call --session --timeout 10 \
--dest org.freedesktop.portal.Desktop \
--object-path /org/freedesktop/portal/desktop \
--method org.freedesktop.portal.DynamicLauncher.Launch \
"$1" {}
}
open_file() {
# open the file, and then pass the fd to dbus
log "open_file: '$1'"
exec 3< "$1"
gdbus call --session --timeout 10 \
--dest org.freedesktop.portal.Desktop \
--object-path /org/freedesktop/portal/desktop \
--method org.freedesktop.portal.OpenURI.OpenFile \
'' 3 "{'ask': <false>}"
}
open_desktopFile() {
log "open_desktopFile: '$1'"
# open_application (i.e. the DynamicLauncher portal) only understands applications by their
# .desktop filename (relative to ~/.local/share/applications) -- not by their full path.
# therefore, see if this .desktop file is equivalent to anything in ~/.local/share/applications.
local path="$1"
if [[ "${path:0:1}" != "/" ]]; then
path="$PWD/$path"
fi
if [[ "$path" == $HOME/.local/share/applications/*.desktop ]]; then
open_application "$(basename "$path")"
return
fi
# the given path doesn't exist in ~/.local/share/applications: check if it's a symlink which
# derefs to an application
local target="$(readlink "$path")"
if [ -z "$target" ]; then
log "open_desktopFile: '$path' does not deref to anything in ~/.local/share/applications: falling back to heuristics"
# assume that the deref'd name matches the application name.
# there's nothing *guaranteeing* this, but i have yet to see it fail.
open_application "$(basename "$path")"
return
fi
if [[ "${target:0:1}" != "/" ]]; then
target="$(dirname "$path")/$target"
fi
open_desktopFile "$target"
}
isLandscape() {
# success if all outputs are landscape
swaymsg -t get_outputs --raw \
| jq --exit-status '. | all(.transform == "90" or .transform == "270")' \
> /dev/null
}
_keyboardPid=
setKeyboard() {
if [ -z "$KEYBOARD" ]; then
log "KEYBOARD is not set"
return
fi
if [ -z "$_keyboardPid" ]; then
_keyboardPid=$(pidof "$KEYBOARD")
if [ -z "$_keyboardPid" ]; then
log "KEYBOARD ($KEYBOARD) instance is not found"
return
fi
fi
_setKeyboard "$1"
}
_setKeyboard() {
case "$1" in
"show")
log "show keyboard $_keyboardPid"
# `env` so that we get the util-linux `kill` binary instead of bash's builtin
env kill -s USR2 "$_keyboardPid"
;;
"showIfRoom")
isLandscape && _setKeyboard "hide" || _setKeyboard "show"
;;
"hide")
log "hide keyboard $_keyboardPid"
env kill -s USR1 "$_keyboardPid"
;;
esac
}
## ARGUMENT PARSING
autoKeyboard=
resource=
resourceType=
while [ $# -gt 0 ]; do
arg="$1"
shift
case "$arg" in
"--auto-keyboard")
autoKeyboard=1
;;
"--help")
usage 0
;;
"--application")
resourceType="application"
;;
"--desktop-file")
resourceType="desktopFile"
;;
"--file")
resourceType="file"
;;
*)
if [ $# -ne 0 ]; then
usage 1
fi
resource="$arg"
;;
esac
done
if [ -z "$resourceType" ]; then
if [ -e "$HOME/.local/share/applications/$resource" ]; then
log "detected resourceType=application"
resourceType=application
elif [ -e "$resource" ]; then
log "detected resourceType=file"
resourceType=file
elif [[ "$resource" == *.desktop ]]; then
log "detected resourceType=application (warning: '$resource' is not visible on disk)"
resourceType=application
else
log "detected resourceType=file (warning: '$resource' is not visible on disk)"
resourceType=file
fi
fi
## TOPLEVEL LOGIC
if [ -n "$autoKeyboard" ]; then
# do in parallel to avoid delaying app launch
configureKeyboardFor_"$resourceType" "$resource" &
fi
open_"$resourceType" "$resource"