summaryrefslogtreecommitdiff
path: root/dot_config/sway
diff options
context:
space:
mode:
Diffstat (limited to 'dot_config/sway')
-rw-r--r--dot_config/sway/executable_config244
-rw-r--r--dot_config/sway/executable_launcher.sh350
2 files changed, 594 insertions, 0 deletions
diff --git a/dot_config/sway/executable_config b/dot_config/sway/executable_config
new file mode 100644
index 0000000..7b75619
--- /dev/null
+++ b/dot_config/sway/executable_config
@@ -0,0 +1,244 @@
+# Default config for sway
+#
+# Copy this to ~/.config/sway/config and edit it to your liking.
+#
+# Read `man 5 sway` for a complete reference.
+
+### Variables
+#
+# Logo key. Use Mod1 for Alt.
+set $mod Mod1
+# Home row direction keys, like vim
+set $left h
+set $down j
+set $up k
+set $right l
+# Your preferred terminal emulator
+set $term wezterm
+# Your preferred application launcher
+# Note: pass the final command to swaymsg so that the resulting window can be opened
+# on the original workspace that the command was run on.
+set $menu exec rofi -show drun -theme android_notification
+
+### Output configuration
+#
+# Default wallpaper (more resolutions are available in /usr/share/backgrounds/sway/)
+output * bg ~/Pictures/thumbnail.png center
+#
+# Example configuration:
+#
+# output HDMI-A-1 resolution 1920x1080 position 1920,0
+#
+# You can get the names of your outputs by running: swaymsg -t get_outputs
+
+### Idle configuration
+#
+# Example configuration:
+#
+# exec swayidle -w \
+# timeout 300 'swaylock -f -c 000000' \
+# timeout 600 'swaymsg "output * dpms off"' resume 'swaymsg "output * dpms on"' \
+# before-sleep 'swaylock -f -c 000000'
+#
+# This will lock your screen after 300 seconds of inactivity, then turn off
+# your displays after another 300 seconds, and turn your screens back on when
+# resumed. It will also lock your screen before your computer goes to sleep.
+
+### Input configuration
+#
+# Example configuration:
+#
+# input "2:14:SynPS/2_Synaptics_TouchPad" {
+# dwt enabled
+# tap enabled
+# natural_scroll enabled
+# middle_emulation enabled
+# }
+#
+# You can get the names of your inputs by running: swaymsg -t get_inputs
+# Read `man 5 sway-input` for more information about this section.
+
+### Key bindings
+#
+# Basics:
+#
+ # Start a terminal
+ bindsym $mod+Shift+Return exec $term
+
+ # Kill focused window
+ bindsym $mod+Shift+q kill
+
+ # Start your launcher
+ bindsym $mod+d exec $menu
+
+ # Drag floating windows by holding down $mod and left mouse button.
+ # Resize them with right mouse button + $mod.
+ # Despite the name, also works for non-floating windows.
+ # Change normal to inverse to use left mouse button for resizing and right
+ # mouse button for dragging.
+ floating_modifier $mod normal
+
+ # Reload the configuration file
+ bindsym $mod+Shift+c reload
+
+ # Exit sway (logs you out of your Wayland session)
+ bindsym $mod+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -B 'Yes, exit sway' 'swaymsg exit'
+ # Lock screen
+ bindsym $mod+Shift+m exec lock
+#
+# Moving around:
+#
+ # Move your focus around
+ bindsym $mod+$left focus left
+ bindsym $mod+$down focus down
+ bindsym $mod+$up focus up
+ bindsym $mod+$right focus right
+ # Or use $mod+[up|down|left|right]
+ bindsym $mod+Left focus left
+ bindsym $mod+Down focus down
+ bindsym $mod+Up focus up
+ bindsym $mod+Right focus right
+
+ # Move the focused window with the same, but add Shift
+ bindsym $mod+Shift+$left move left
+ bindsym $mod+Shift+$down move down
+ bindsym $mod+Shift+$up move up
+ bindsym $mod+Shift+$right move right
+ # Ditto, with arrow keys
+ bindsym $mod+Shift+Left move left
+ bindsym $mod+Shift+Down move down
+ bindsym $mod+Shift+Up move up
+ bindsym $mod+Shift+Right move right
+#
+# Workspaces:
+#
+ # Switch to workspace
+ bindsym $mod+1 workspace number 1
+ bindsym $mod+2 workspace number 2
+ bindsym $mod+3 workspace number 3
+ bindsym $mod+4 workspace number 4
+ bindsym $mod+5 workspace number 5
+ bindsym $mod+6 workspace number 6
+ bindsym $mod+7 workspace number 7
+ bindsym $mod+8 workspace number 8
+ bindsym $mod+9 workspace number 9
+ bindsym $mod+0 workspace number 10
+ # Move focused container to workspace
+ bindsym $mod+Shift+1 move container to workspace number 1
+ bindsym $mod+Shift+2 move container to workspace number 2
+ bindsym $mod+Shift+3 move container to workspace number 3
+ bindsym $mod+Shift+4 move container to workspace number 4
+ bindsym $mod+Shift+5 move container to workspace number 5
+ bindsym $mod+Shift+6 move container to workspace number 6
+ bindsym $mod+Shift+7 move container to workspace number 7
+ bindsym $mod+Shift+8 move container to workspace number 8
+ bindsym $mod+Shift+9 move container to workspace number 9
+ bindsym $mod+Shift+0 move container to workspace number 10
+ # Note: workspaces can have any name you want, not just numbers.
+ # We just use 1-10 as the default.
+#
+# Layout stuff:
+#
+ # You can "split" the current object of your focus with
+ # $mod+b or $mod+v, for horizontal and vertical splits
+ # respectively.
+ bindsym $mod+b splith
+ bindsym $mod+v splitv
+
+ # Switch the current container between different layout styles
+ bindsym $mod+s layout stacking
+ bindsym $mod+w layout tabbed
+ bindsym $mod+e layout toggle split
+
+ # Make the current focus fullscreen
+ bindsym $mod+f fullscreen
+
+ # Toggle the current focus between tiling and floating mode
+ bindsym $mod+Shift+space floating toggle
+
+ # Swap focus between the tiling area and the floating area
+ bindsym $mod+space focus mode_toggle
+
+ # Move focus to the parent container
+ # bindsym $mod+a focus parent
+#
+# Scratchpad:
+#
+ # Sway has a "scratchpad", which is a bag of holding for windows.
+ # You can send windows there and get them back later.
+
+ # Move the currently focused window to the scratchpad
+ # bindsym $mod+Shift+minus move scratchpad
+
+ # Show the next scratchpad window or hide the focused scratchpad window.
+ # If there are multiple scratchpad windows, this command cycles through them.
+ # bindsym $mod+minus scratchpad show
+#
+# Resizing containers:
+#
+mode "resize" {
+ # left will shrink the containers width
+ # right will grow the containers width
+ # up will shrink the containers height
+ # down will grow the containers height
+ bindsym $left resize shrink width 10px
+ bindsym $down resize grow height 10px
+ bindsym $up resize shrink height 10px
+ bindsym $right resize grow width 10px
+
+ # Ditto, with arrow keys
+ bindsym Left resize shrink width 10px
+ bindsym Down resize grow height 10px
+ bindsym Up resize shrink height 10px
+ bindsym Right resize grow width 10px
+
+ # Return to default mode
+ bindsym Return mode "default"
+ bindsym Escape mode "default"
+}
+bindsym $mod+r mode "resize"
+
+bar swaybar_command waybar
+
+default_border pixel
+default_floating_border pixel
+gaps inner 10
+
+bindsym XF86AudioRaiseVolume exec pactl set-sink-volume @DEFAULT_SINK@ +5%
+bindsym XF86AudioLowerVolume exec pactl set-sink-volume @DEFAULT_SINK@ -5%
+bindsym XF86AudioMute exec pactl set-sink-mute @DEFAULT_SINK@ toggle
+bindsym XF86AudioMicMute exec pactl set-source-mute @DEFAULT_SOURCE@ toggle
+bindsym XF86MonBrightnessDown exec brightnessctl set 5%-
+bindsym XF86MonBrightnessUp exec brightnessctl set 5%+
+bindsym XF86AudioPlay exec playerctl play-pause
+bindsym XF86AudioNext exec playerctl next
+bindsym XF86AudioPrev exec playerctl previous
+bindsym XF86Search exec $menu
+
+# exec mpd-mpris
+# exec easyeffects --gapplication-service
+exec mako
+# exec mpc clear && mpc add /
+# exec fcitx5 -D
+exec gammastep
+exec kanshi
+exec kdeconnectd
+exec udiskie
+exec keepassxc --minimized
+exec /usr/lib/hyprpolkitagent/hyprpolkitagent
+
+bindsym $mod+Shift+y exec 'swaylock -f -c 000000'
+
+bindsym $mod+tab workspace next
+
+# # capture all screens to clipboard
+bindsym Shift+Print exec flameshot gui -r | rpaste | wl-copy
+
+# capture the specified screen area to clipboard
+bindsym Print exec flameshot gui
+
+seat * hide_cursor 4000
+
+exec dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP=sway
+
+include /etc/sway/config.d/*
diff --git a/dot_config/sway/executable_launcher.sh b/dot_config/sway/executable_launcher.sh
new file mode 100644
index 0000000..2034ed3
--- /dev/null
+++ b/dot_config/sway/executable_launcher.sh
@@ -0,0 +1,350 @@
+#!/usr/bin/env bash
+# terminal application launcher for sway, using fzf
+# Based on: https://gitlab.com/FlyingWombat/my-scripts/blob/master/sway-launcher
+# https://gist.github.com/Biont/40ef59652acf3673520c7a03c9f22d2a
+shopt -s nullglob globstar
+set -o pipefail
+if ! { exec 0>&3; } 1>/dev/null 2>&1; then
+ exec 3>/dev/null # If file descriptor 3 is unused in parent shell, output to /dev/null
+fi
+# shellcheck disable=SC2154
+trap 's=$?; echo "$0: Error on line "$LINENO": $BASH_COMMAND"; exit $s' ERR
+IFS=$'\n\t'
+DEL=$'\34'
+
+TERMINAL_COMMAND="foot"
+GLYPH_COMMAND="${GLYPH_COMMAND- }"
+GLYPH_DESKTOP="${GLYPH_DESKTOP- }"
+CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/sway-launcher-desktop"
+PROVIDERS_FILE="${PROVIDERS_FILE:=providers.conf}"
+if [[ "${PROVIDERS_FILE#/}" == "${PROVIDERS_FILE}" ]]; then
+ # $PROVIDERS_FILE is a relative path, prepend $CONFIG_DIR
+ PROVIDERS_FILE="${CONFIG_DIR}/${PROVIDERS_FILE}"
+fi
+
+# Provider config entries are separated by the field separator \034 and have the following structure:
+# list_cmd,preview_cmd,launch_cmd,purge_cmd
+declare -A PROVIDERS
+if [ -f "${PROVIDERS_FILE}" ]; then
+ eval "$(awk -F= '
+ BEGINFILE{ provider=""; }
+ /^\[.*\]/{sub("^\\[", "");sub("\\]$", "");provider=$0}
+ /^(launch|list|preview|purge)_cmd/{st = index($0,"=");providers[provider][$1] = substr($0,st+1)}
+ ENDFILE{
+ for (key in providers){
+ if(!("list_cmd" in providers[key])){continue;}
+ if(!("launch_cmd" in providers[key])){continue;}
+ if(!("preview_cmd" in providers[key])){continue;}
+ if(!("purge_cmd" in providers[key])){providers[key]["purge_cmd"] = "exit 0";}
+ for (entry in providers[key]){
+ gsub(/[\x27,\047]/,"\x27\"\x27\"\x27", providers[key][entry])
+ }
+ print "PROVIDERS[\x27" key "\x27]=\x27" providers[key]["list_cmd"] "\034" providers[key]["preview_cmd"] "\034" providers[key]["launch_cmd"] "\034" providers[key]["purge_cmd"] "\x27\n"
+ }
+ }' "${PROVIDERS_FILE}")"
+ if [[ ! -v HIST_FILE ]]; then
+ HIST_FILE="${XDG_CACHE_HOME:-$HOME/.cache}/${0##*/}-${PROVIDERS_FILE##*/}-history.txt"
+ fi
+else
+ PROVIDERS['desktop']="${0} list-entries${DEL}${0} describe-desktop \"{1}\"${DEL}${0} run-desktop '{1}' {2}${DEL}test -f '{1}' || exit 43"
+ PROVIDERS['command']="${0} list-commands${DEL}${0} describe-command \"{1}\"${DEL}${TERMINAL_COMMAND} {1}${DEL}command -v '{1}' || exit 43"
+ if [[ ! -v HIST_FILE ]]; then
+ HIST_FILE="${XDG_CACHE_HOME:-$HOME/.cache}/${0##*/}-history.txt"
+ fi
+fi
+PROVIDERS['user']="exit${DEL}exit${DEL}{1}" # Fallback provider that simply executes the exact command if there were no matches
+
+if [[ -n "${HIST_FILE}" ]]; then
+ mkdir -p "${HIST_FILE%/*}" && touch "$HIST_FILE"
+ readarray HIST_LINES <"$HIST_FILE"
+fi
+
+function describe() {
+ # shellcheck disable=SC2086
+ readarray -d ${DEL} -t PROVIDER_ARGS <<<${PROVIDERS[${1}]}
+ # shellcheck disable=SC2086
+ [ -n "${PROVIDER_ARGS[1]}" ] && eval "${PROVIDER_ARGS[1]//\{1\}/${2}}"
+}
+function describe-desktop() {
+ description=$(sed -ne '/^Comment=/{s/^Comment=//;p;q}' "$1")
+ echo -e "\033[33m$(sed -ne '/^Name=/{s/^Name=//;p;q}' "$1")\033[0m"
+ echo "${description:-No description}"
+}
+function describe-command() {
+ readarray arr < <(whatis -l "$1" 2>/dev/null)
+ description="${arr[0]}"
+ description="${description#* - }"
+ echo -e "\033[33m${1}\033[0m"
+ echo "${description:-No description}"
+}
+
+function provide() {
+ # shellcheck disable=SC2086
+ readarray -d ${DEL} -t PROVIDER_ARGS <<<${PROVIDERS[$1]}
+ eval "${PROVIDER_ARGS[0]}"
+}
+function list-commands() {
+ IFS=: read -ra path <<<"$PATH"
+ for dir in "${path[@]}"; do
+ printf '%s\n' "$dir/"* |
+ awk -F / -v pre="$GLYPH_COMMAND" '{print $NF "\034command\034\033[31m" pre "\033[0m" $NF;}'
+ done | sort -u
+}
+function list-entries() {
+ # Get locations of desktop application folders according to spec
+ # https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
+ IFS=':' read -ra DIRS <<<"${XDG_DATA_HOME-${HOME}/.local/share}:${XDG_DATA_DIRS-/usr/local/share:/usr/share}"
+ for i in "${!DIRS[@]}"; do
+ if [[ ! -d "${DIRS[i]}" ]]; then
+ unset -v 'DIRS[$i]'
+ else
+ DIRS[$i]="${DIRS[i]}/applications/**/*.desktop"
+ fi
+ done
+ # shellcheck disable=SC2068
+ entries ${DIRS[@]}
+}
+function entries() {
+ # shellcheck disable=SC2068
+ awk -v pre="$GLYPH_DESKTOP" -F= '
+ function desktopFileID(filename){
+ sub("^.*applications/", "", filename);
+ sub("/", "-", filename);
+ return filename
+ }
+ BEGINFILE{
+ application=0;
+ hidden=0;
+ block="";
+ a=0
+
+ id=desktopFileID(FILENAME)
+ if(id in fileIds){
+ nextfile;
+ }else{
+ fileIds[id]=0
+ }
+ }
+ /^\[Desktop Entry\]/{block="entry"}
+ /^Type=Application/{application=1}
+ /^\[Desktop Action/{
+ sub("^\\[Desktop Action ", "");
+ sub("\\]$", "");
+ block="action";
+ a++;
+ actions[a,"key"]=$0
+ }
+ /^\[X-/{
+ sub("^\\[X-", "");
+ sub("\\]$", "");
+ block="action";
+ a++;
+ actions[a,"key"]=$0
+ }
+ /^Name=/{ (block=="action")? actions[a,"name"]=$2 : name=$2 }
+ /^NoDisplay=true/{ (block=="action")? actions[a,"hidden"]=1 : hidden=1 }
+ ENDFILE{
+ if (application){
+ if (!hidden)
+ print FILENAME "\034desktop\034\033[33m" pre name "\033[0m";
+ if (a>0)
+ for (i=1; i<=a; i++)
+ if (!actions[i, "hidden"])
+ print FILENAME "\034desktop\034\033[33m" pre name "\033[0m (" actions[i, "name"] ")\034" actions[i, "key"]
+ }
+ }' \
+ $@ </dev/null
+ # the empty stdin is needed in case no *.desktop files
+}
+function run-desktop() {
+ CMD="$("${0}" generate-command "$@" 2>&3)"
+ echo "Generated Launch command from .desktop file: ${CMD}" >&3
+ eval "${CMD}"
+}
+function generate-command() {
+ # Define the search pattern that specifies the block to search for within the .desktop file
+ PATTERN="^\\\\[Desktop Entry\\\\]"
+ if [[ -n $2 ]]; then
+ PATTERN="^\\\\[Desktop Action ${2}\\\\]"
+ fi
+ echo "Searching for pattern: ${PATTERN}" >&3
+ # 1. We see a line starting [Desktop, but we're already searching: deactivate search again
+ # 2. We see the specified pattern: start search
+ # 3. We see an Exec= line during search: remove field codes and set variable
+ # 3. We see a Path= line during search: set variable
+ # 4. Finally, build command line
+ awk -v pattern="${PATTERN}" -v terminal_cmd="${TERMINAL_COMMAND}" -F= '
+ BEGIN{a=0;exec=0;path=0}
+ /^\[Desktop/{
+ if(a){ a=0 }
+ }
+ $0 ~ pattern{ a=1 }
+ /^Terminal=/{
+ sub("^Terminal=", "");
+ if ($0 == "true") { terminal=1 }
+ }
+ /^Exec=/{
+ if(a && !exec){
+ sub("^Exec=", "");
+ gsub(" ?%[cDdFfikmNnUuv]", "");
+ exec=$0;
+ }
+ }
+ /^Path=/{
+ if(a && !path){ path=$2 }
+ }
+ END{
+ if(path){ printf "cd " path " && " }
+ printf "exec "
+ if (terminal){ printf terminal_cmd " " }
+ print exec
+ }' "$1"
+}
+
+function autostart() {
+ for application in $(list-autostart); do
+ (exec setsid /bin/sh -c "$(run-desktop "${application}")" &>/dev/null &)
+ done
+}
+
+function list-autostart() {
+ # Get locations of desktop application folders according to spec
+ # https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
+ IFS=':' read -ra DIRS <<<"${XDG_CONFIG_HOME-${HOME}/.config}:${XDG_CONFIG_DIRS-/etc/xdg}"
+ for i in "${!DIRS[@]}"; do
+ if [[ ! -d "${DIRS[i]}" ]]; then
+ unset -v 'DIRS[$i]'
+ else
+ DIRS[$i]="${DIRS[i]}/autostart/*.desktop"
+ fi
+ done
+
+ # shellcheck disable=SC2068
+ awk -v pre="$GLYPH_DESKTOP" -F= '
+ function desktopFileID(filename){
+ sub("^.*autostart/", "", filename);
+ sub("/", "-", filename);
+ return filename
+ }
+ BEGINFILE{
+ application=0;
+ block="";
+ disabled=0;
+ a=0
+
+ id=desktopFileID(FILENAME)
+ if(id in fileIds){
+ nextfile;
+ }else{
+ fileIds[id]=0
+ }
+ }
+ /^\[Desktop Entry\]/{block="entry"}
+ /^Type=Application/{application=1}
+ /^Name=/{ iname=$2 }
+ /^Hidden=true/{disabled=1}
+ ENDFILE{
+ if (application && !disabled){
+ print FILENAME;
+ }
+ }' \
+ ${DIRS[@]} </dev/null
+}
+
+purge() {
+ # shellcheck disable=SC2188
+ > "${HIST_FILE}"
+ declare -A PURGE_CMDS
+ for PROVIDER_NAME in "${!PROVIDERS[@]}"; do
+ readarray -td ${DEL} PROVIDER_ARGS <<<${PROVIDERS[${PROVIDER_NAME}]}
+ PURGE_CMD=${PROVIDER_ARGS[3]}
+ [ -z "${PURGE_CMD}" ] && PURGE_CMD='test -f "{1}" || exit 43'
+ PURGE_CMDS[$PROVIDER_NAME]="${PURGE_CMD%$'\n'}"
+ done
+ for HIST_LINE in "${HIST_LINES[@]#*' '}"; do
+ readarray -td $'\034' HIST_ENTRY <<<${HIST_LINE}
+ ENTRY=${HIST_ENTRY[1]}
+ readarray -td ' ' FILTER <<<${PURGE_CMDS[$ENTRY]//\{1\}/${HIST_ENTRY[0]}}
+ (eval "${FILTER[@]}" 1>/dev/null) # Run filter command discarding output. We only want the exit status
+ if [[ $? -ne 43 ]]; then
+ echo "1 ${HIST_LINE[@]%$'\n'}" >> "${HIST_FILE}"
+ fi
+ done
+}
+
+case "$1" in
+describe | describe-desktop | describe-command | entries | list-entries | list-commands | list-autostart | generate-command | autostart | run-desktop | provide | purge)
+ "$@"
+ exit
+ ;;
+esac
+echo "Starting launcher instance with the following providers:" "${!PROVIDERS[@]}" >&3
+
+FZFPIPE=$(mktemp -u)
+mkfifo "$FZFPIPE"
+trap 'rm "$FZFPIPE"' EXIT INT
+
+# Append Launcher History, removing usage count
+(printf '%s' "${HIST_LINES[@]#* }" >>"$FZFPIPE") &
+
+# Iterate over providers and run their list-command
+for PROVIDER_NAME in "${!PROVIDERS[@]}"; do
+ (bash -c "${0} provide ${PROVIDER_NAME}" >>"$FZFPIPE") &
+done
+
+readarray -t COMMAND_STR <<<$(
+ fzf --ansi +s -x -d '\034' --nth ..3 --with-nth 3 \
+ --print-query \
+ --preview "$0 describe {2} {1}" \
+ --preview-window=up:2:noborder \
+ --no-multi --cycle \
+ --prompt="${GLYPH_PROMPT-# }" \
+ --header='' --no-info --margin='1,2' \
+ --color='16,gutter:-1' \
+ <"$FZFPIPE"
+) || exit 1
+# Get the last line of the fzf output. If there were no matches, it contains the query which we'll treat as a custom command
+# If there were matches, it contains the selected item
+COMMAND_STR=$(printf '%s\n' "${COMMAND_STR[@]: -1}")
+# We still need to format the query to conform to our fallback provider.
+# We check for the presence of field separator character to determine if we're dealing with a custom command
+if [[ $COMMAND_STR != *$'\034'* ]]; then
+ COMMAND_STR="${COMMAND_STR}"$'\034user\034'"${COMMAND_STR}"$'\034'
+ SKIP_HIST=1 # I chose not to include custom commands in the history. If this is a bad idea, open an issue please
+fi
+
+[ -z "$COMMAND_STR" ] && exit 1
+
+if [[ -n "${HIST_FILE}" && ! "$SKIP_HIST" ]]; then
+ # update history
+ for i in "${!HIST_LINES[@]}"; do
+ if [[ "${HIST_LINES[i]}" == *" $COMMAND_STR"$'\n' ]]; then
+ HIST_COUNT=${HIST_LINES[i]%% *}
+ HIST_LINES[$i]="$((HIST_COUNT + 1)) $COMMAND_STR"$'\n'
+ match=1
+ break
+ fi
+ done
+ if ! ((match)); then
+ HIST_LINES+=("1 $COMMAND_STR"$'\n')
+ fi
+
+ printf '%s' "${HIST_LINES[@]}" | sort -nr >"$HIST_FILE"
+fi
+
+# shellcheck disable=SC2086
+readarray -d $'\034' -t PARAMS <<<${COMMAND_STR}
+# shellcheck disable=SC2086
+readarray -d ${DEL} -t PROVIDER_ARGS <<<${PROVIDERS[${PARAMS[1]}]}
+# Substitute {1}, {2} etc with the correct values
+COMMAND=${PROVIDER_ARGS[2]//\{1\}/${PARAMS[0]}}
+COMMAND=${COMMAND//\{2\}/${PARAMS[3]}}
+COMMAND=${COMMAND%%[[:space:]]}
+
+if [ -t 1 ]; then
+ echo "Launching command: ${COMMAND}" >&3
+ setsid /bin/sh -c "${COMMAND}" >&/dev/null </dev/null &
+ sleep 0.01
+else
+ echo "${COMMAND}"
+fi