From b47903bc3e9bf4256feb6b1f4ca0da70824f159b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20Mei=C3=9Felbach?= Date: Thu, 28 Nov 2019 12:43:30 +0100 Subject: Turn hardcoded list generation into an array containing list & launch commands. This will make it more flexible and easy to extend - for example via a separate config file --- sway-launcher-desktop.sh | 79 ++++++++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 36 deletions(-) diff --git a/sway-launcher-desktop.sh b/sway-launcher-desktop.sh index eb146d9..79ff1f2 100755 --- a/sway-launcher-desktop.sh +++ b/sway-launcher-desktop.sh @@ -7,6 +7,7 @@ set -o pipefail # shellcheck disable=SC2154 trap 's=$?; echo "$0: Error on line "$LINENO": $BASH_COMMAND"; exit $s' ERR IFS=$'\n\t' +DEL=$'\34' # Defaulting terminal to urxvt, but feel free to either change # this or override with an environment variable in your sway config @@ -16,10 +17,18 @@ GLYPH_COMMAND=" " GLYPH_DESKTOP=" " HIST_FILE="${XDG_CACHE_HOME:-$HOME/.cache}/${0##*/}-history.txt" -# 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}" +# Provider config entries are separated by the field separator \034 and have the following structure: +# list_cmd,launch_cmd +declare -A PROVIDERS +PROVIDERS['desktop']="${0} list-entries${DEL}${0} generate-command" +PROVIDERS['command']="${0} list-commands${DEL}${0} command-line" +touch "$HIST_FILE" +readarray HIST_LINES <"$HIST_FILE" + +function command-line() { + echo "${TERMINAL_COMMAND} ${1}" +} function describe() { if [[ $2 == 'command' ]]; then title=$1 @@ -34,6 +43,28 @@ function describe() { echo "${description:-No description}" } +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= ' @@ -134,14 +165,12 @@ function generate-command() { } case "$1" in -describe | entries | generate-command) +describe | entries | list-entries | list-commands | command-line | generate-command | purge) "$@" exit ;; esac -touch "$HIST_FILE" -readarray HIST_LINES <"$HIST_FILE" FZFPIPE=$(mktemp -u) mkfifo "$FZFPIPE" trap 'rm "$FZFPIPE"' EXIT INT @@ -149,28 +178,11 @@ trap 'rm "$FZFPIPE"' EXIT INT # Append Launcher History, removing usage count (printf '%s' "${HIST_LINES[@]#* }" >>"$FZFPIPE") & -# Load and append Desktop entries -( -for i in "${!DIRS[@]}"; do - if [[ ! -d "${DIRS[i]}" ]]; then - unset -v 'DIRS[$i]' - else - DIRS[$i]="${DIRS[i]}/applications/**/*.desktop" - fi +# Iterate over providers and run their list-command +for PROVIDER in "${PROVIDERS[@]}"; do + readarray -d ${DEL} -t PROVIDER_ARGS <<<${PROVIDER} + (bash -c "${PROVIDER_ARGS[0]}" >>"$FZFPIPE") & done -# shellcheck disable=SC2068 -entries ${DIRS[@]} >>"$FZFPIPE" -) & - -# Load and append command list -( - 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 >>"$FZFPIPE" -) & COMMAND_STR=$( fzf +s -x -d '\034' --nth ..3 --with-nth 3 \ @@ -200,13 +212,8 @@ command='echo "nope"' # shellcheck disable=SC2086 readarray -d $'\034' -t PARAMS <<<${COMMAND_STR} # COMMAND_STR is "\034" -case ${PARAMS[1]} in -desktop) - command=$(generate-command "${PARAMS[0]}" "${PARAMS[3]}") - ;; -command) - command="$TERMINAL_COMMAND ${PARAMS[0]}" - ;; -esac - +# shellcheck disable=SC2086 +readarray -d ${DEL} -t PROVIDER_ARGS <<<${PROVIDERS[${PARAMS[1]}]} +# shellcheck disable=SC2086 +command=$(eval ${PROVIDER_ARGS[1]} ${PARAMS[0]} ${PARAMS[3]}) (exec setsid /bin/sh -c "$command" &) -- cgit v1.2.3 From 22182d980a2ebde89fe2970e11c39fbf8e4d6628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20Mei=C3=9Felbach?= Date: Thu, 28 Nov 2019 14:50:22 +0100 Subject: Run list command in separate function for testability and interoperability --- sway-launcher-desktop.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sway-launcher-desktop.sh b/sway-launcher-desktop.sh index 79ff1f2..4b21c7d 100755 --- a/sway-launcher-desktop.sh +++ b/sway-launcher-desktop.sh @@ -43,6 +43,10 @@ function describe() { echo "${description:-No description}" } +function provide() { + 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 @@ -165,7 +169,7 @@ function generate-command() { } case "$1" in -describe | entries | list-entries | list-commands | command-line | generate-command | purge) +describe | entries | list-entries | list-commands | command-line | generate-command | provide) "$@" exit ;; @@ -179,10 +183,7 @@ trap 'rm "$FZFPIPE"' EXIT INT (printf '%s' "${HIST_LINES[@]#* }" >>"$FZFPIPE") & # Iterate over providers and run their list-command -for PROVIDER in "${PROVIDERS[@]}"; do - readarray -d ${DEL} -t PROVIDER_ARGS <<<${PROVIDER} - (bash -c "${PROVIDER_ARGS[0]}" >>"$FZFPIPE") & -done +for PROVIDER_NAME in "${!PROVIDERS[@]}"; do (bash -c "${0} provide ${PROVIDER_NAME}" >>"$FZFPIPE") & done COMMAND_STR=$( fzf +s -x -d '\034' --nth ..3 --with-nth 3 \ -- cgit v1.2.3 From 3835562c5325c279809bb41c34c6afca6288a1cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20Mei=C3=9Felbach?= Date: Fri, 29 Nov 2019 21:28:24 +0100 Subject: [WIP] Read custom providers from a ~/.config/sway-launcher-desktop/providers.conf file. --- sway-launcher-desktop.sh | 74 +++++++++++++++++----- .../config/0/sway-launcher-desktop/providers.conf | 7 ++ tests/describe.bats | 6 +- tests/providers.bats | 36 +++++++++++ 4 files changed, 103 insertions(+), 20 deletions(-) create mode 100644 tests/data/config/0/sway-launcher-desktop/providers.conf create mode 100644 tests/providers.bats diff --git a/sway-launcher-desktop.sh b/sway-launcher-desktop.sh index 4b21c7d..3f00794 100755 --- a/sway-launcher-desktop.sh +++ b/sway-launcher-desktop.sh @@ -16,13 +16,44 @@ TERMINAL_COMMAND="${TERMINAL_COMMAND:="urxvt -e"}" GLYPH_COMMAND=" " GLYPH_DESKTOP=" " HIST_FILE="${XDG_CACHE_HOME:-$HOME/.cache}/${0##*/}-history.txt" +CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/sway-launcher-desktop" # Provider config entries are separated by the field separator \034 and have the following structure: -# list_cmd,launch_cmd +# list_cmd,preview_cmd,launch_cmd declare -A PROVIDERS -PROVIDERS['desktop']="${0} list-entries${DEL}${0} generate-command" -PROVIDERS['command']="${0} list-commands${DEL}${0} command-line" +if [ -f "${CONFIG_DIR}/providers.conf" ]; then + PARSED=$( awk -F= ' + BEGINFILE{ provider=""; } + /^\[.*\]/{sub("^\\[", "");sub("\\]$", "");provider=$0} + /^(launch|list|preview)_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;} + for (entry in providers[key]){ + # gsub(/\$/,"\\$", providers[key][entry]) + # gsub(/"/,"\\\"", providers[key][entry]) + # gsub("\047",sq, providers[key][entry]) + # gsub("\x27",sq, providers[key][entry]) + # gsub(/\047/,sq, providers[key][entry]) + gsub(/[\x27,\047]/,"\x27\"\x27\"\x27", providers[key][entry]) + # gsub(/\047/,"DURR", providers[key][entry]) + } + print "PROVIDERS[\x27" key "\x27]=\x27" providers[key]["list_cmd"] "\034" providers[key]["preview_cmd"] "\034" providers[key]["launch_cmd"] "\x27\n" + } + }' "${CONFIG_DIR}/providers.conf") + echo "$PARSED" + eval "$PARSED" +else + PROVIDERS['desktop']="${0} list-entries${DEL}${0} describe-desktop${DEL}${0} generate-command" + PROVIDERS['command']="${0} list-commands${DEL}${0} describe-command${DEL}${0} command-line" +fi +#for i in "${!PROVIDERS[@]}"; do +# echo "${i}=${PROVIDERS[$i]}" +#done +#exit touch "$HIST_FILE" readarray HIST_LINES <"$HIST_FILE" @@ -30,20 +61,27 @@ function command-line() { echo "${TERMINAL_COMMAND} ${1}" } function describe() { - if [[ $2 == 'command' ]]; then - title=$1 - readarray arr < <(whatis -l "$1" 2>/dev/null) - description="${arr[0]}" - description="${description%*-}" - else - title=$(sed -ne '/^Name=/{s/^Name=//;p;q}' "$1") - description=$(sed -ne '/^Comment=/{s/^Comment=//;p;q}' "$1") - fi + # shellcheck disable=SC2086 + readarray -d ${DEL} -t PROVIDER_ARGS <<<${PROVIDERS[${1}]} + # shellcheck disable=SC2086 + [ -n "${PROVIDER_ARGS[1]}" ] && eval "${PROVIDER_ARGS[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() { + title=$1 + readarray arr < <(whatis -l "$1" 2>/dev/null) + description="${arr[0]}" + description="${description%*-}" echo -e "\033[33m$title\033[0m" echo "${description:-No description}" } function provide() { + # shellcheck disable=SC2086 readarray -d ${DEL} -t PROVIDER_ARGS <<<${PROVIDERS[$1]} eval "${PROVIDER_ARGS[0]}" } @@ -128,7 +166,7 @@ function generate-command() { # 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_command="${TERMINAL_COMMAND}" -F= ' + awk -v pattern="${PATTERN}" -v terminal_cmd="${TERMINAL_COMMAND}" -F= ' BEGIN{a=0;exec=0;path=0} /^\[Desktop/{ if(a){ @@ -162,14 +200,14 @@ function generate-command() { printf "cd " path " && " } if (terminal){ - printf terminal_command " " + printf terminal_cmd " " } print exec }' "$1" } case "$1" in -describe | entries | list-entries | list-commands | command-line | generate-command | provide) +describe | describe-desktop | describe-command | entries | list-entries | list-commands | command-line | generate-command | provide) "$@" exit ;; @@ -183,11 +221,13 @@ trap 'rm "$FZFPIPE"' EXIT INT (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 +for PROVIDER_NAME in "${!PROVIDERS[@]}"; do + (bash -c "${0} provide ${PROVIDER_NAME}" >>"$FZFPIPE") & +done COMMAND_STR=$( fzf +s -x -d '\034' --nth ..3 --with-nth 3 \ - --preview "$0 describe {1} {2}" \ + --preview "$0 describe {2} {1}" \ --preview-window=up:3:wrap --ansi \ <"$FZFPIPE" ) || exit 1 diff --git a/tests/data/config/0/sway-launcher-desktop/providers.conf b/tests/data/config/0/sway-launcher-desktop/providers.conf new file mode 100644 index 0000000..4e82b2b --- /dev/null +++ b/tests/data/config/0/sway-launcher-desktop/providers.conf @@ -0,0 +1,7 @@ +[foo] +list_cmd=printf "foo\034foo" +launch_cmd=printf 'printf "{1}"' +preview_cmd=printf 'printf "{1}"' + +[incomplete] +list_cmd=echo 'nope' diff --git a/tests/describe.bats b/tests/describe.bats index d02ee96..1541974 100644 --- a/tests/describe.bats +++ b/tests/describe.bats @@ -1,13 +1,13 @@ @test "Name and description of firefox desktop file are properly extracted" { - run ../sway-launcher-desktop.sh describe data/desktop-files/0/applications/firefox.desktop desktop + run env XDG_CONFIG_HOME=./data/config ../sway-launcher-desktop.sh describe desktop ./data/desktop-files/0/applications/firefox.desktop [ "$status" -eq 0 ] [[ ${lines[0]} =~ "Firefox" ]] [[ ${lines[1]} =~ "Browse the World Wide Web" ]] } @test "Name and description of ls command should be given" { - run ../sway-launcher-desktop.sh describe ls command + run env XDG_CONFIG_HOME=./data/config ../sway-launcher-desktop.sh describe command ls [ "$status" -eq 0 ] [[ ${lines[0]} =~ "ls" ]] [[ ${lines[1]} =~ "list directory contents" ]] -} \ No newline at end of file +} diff --git a/tests/providers.bats b/tests/providers.bats new file mode 100644 index 0000000..1c11f0d --- /dev/null +++ b/tests/providers.bats @@ -0,0 +1,36 @@ +@test "Builtin desktop provider works" { + run env XDG_CONFIG_HOME=./data/config XDG_DATA_HOME=./data/desktop-files/1 XDG_DATA_DIRS=./data/desktop-files/0 ../sway-launcher-desktop.sh provide desktop + echo "OUTPUT:$output" + echo "LINES:${#lines[@]}" + [ "$status" -eq 0 ] + [[ ${#lines[@]} -gt 2 ]] +} + +@test "Builtin command provider works" { + run env XDG_CONFIG_HOME=./data/config XDG_DATA_HOME=./data/desktop-files/1 XDG_DATA_DIRS=./data/desktop-files/0 ../sway-launcher-desktop.sh provide command + echo "OUTPUT:$output" + echo "LINES:${#lines[@]}" + [ "$status" -eq 0 ] + [[ ${#lines[@]} -gt 2 ]] +} + +@test "Reads custom provider from providers.conf" { + run printf %q "$(env XDG_CONFIG_HOME=./data/config/0 ../sway-launcher-desktop.sh provide foo)" + echo "OUTPUT:$output" + [ "$status" -eq 0 ] + [[ ${output} == "$'foo\034foo'" ]] +} + +@test "Skips incomplete custom provider from providers.conf" { + run printf %q "$(env XDG_CONFIG_HOME=./data/config/0 ../sway-launcher-desktop.sh provide incomplete)" + echo "OUTPUT:$output" + [ "$status" -eq 0 ] + [[ ${output} == "''" ]] +} + +@test "Does not use builtin providers when reading from providers.conf" { + run printf %q "$(env XDG_CONFIG_HOME=./data/config/0 ../sway-launcher-desktop.sh provide desktop)" + echo "OUTPUT:$output" + [ "$status" -eq 0 ] + [[ ${output} == "''" ]] +} -- cgit v1.2.3 From 2a8f989214a02d4dbed9f59539eb9bae6454f900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20Mei=C3=9Felbach?= Date: Fri, 29 Nov 2019 22:00:58 +0100 Subject: Remove unwanted output --- sway-launcher-desktop.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/sway-launcher-desktop.sh b/sway-launcher-desktop.sh index 3f00794..c6f6bd2 100755 --- a/sway-launcher-desktop.sh +++ b/sway-launcher-desktop.sh @@ -43,8 +43,6 @@ if [ -f "${CONFIG_DIR}/providers.conf" ]; then print "PROVIDERS[\x27" key "\x27]=\x27" providers[key]["list_cmd"] "\034" providers[key]["preview_cmd"] "\034" providers[key]["launch_cmd"] "\x27\n" } }' "${CONFIG_DIR}/providers.conf") - echo "$PARSED" - eval "$PARSED" else PROVIDERS['desktop']="${0} list-entries${DEL}${0} describe-desktop${DEL}${0} generate-command" -- cgit v1.2.3 From 069e8c7964e084df65c153109daf1f5a5d80f8d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20Mei=C3=9Felbach?= Date: Fri, 29 Nov 2019 22:10:50 +0100 Subject: Remove unneeded commented-out awk code --- sway-launcher-desktop.sh | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/sway-launcher-desktop.sh b/sway-launcher-desktop.sh index c6f6bd2..7e2861b 100755 --- a/sway-launcher-desktop.sh +++ b/sway-launcher-desktop.sh @@ -28,19 +28,13 @@ if [ -f "${CONFIG_DIR}/providers.conf" ]; then /^(launch|list|preview)_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;} - for (entry in providers[key]){ - # gsub(/\$/,"\\$", providers[key][entry]) - # gsub(/"/,"\\\"", providers[key][entry]) - # gsub("\047",sq, providers[key][entry]) - # gsub("\x27",sq, providers[key][entry]) - # gsub(/\047/,sq, providers[key][entry]) - gsub(/[\x27,\047]/,"\x27\"\x27\"\x27", providers[key][entry]) - # gsub(/\047/,"DURR", providers[key][entry]) - } - print "PROVIDERS[\x27" key "\x27]=\x27" providers[key]["list_cmd"] "\034" providers[key]["preview_cmd"] "\034" providers[key]["launch_cmd"] "\x27\n" + if(!("list_cmd" in providers[key])){continue;} + if(!("launch_cmd" in providers[key])){continue;} + if(!("preview_cmd" in providers[key])){continue;} + 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"] "\x27\n" } }' "${CONFIG_DIR}/providers.conf") eval "$PARSED" -- cgit v1.2.3 From e1456dd0c3d2da1d64014a5062b3a1a1272e1154 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20Mei=C3=9Felbach?= Date: Fri, 29 Nov 2019 22:57:39 +0100 Subject: Document usage of custom providers --- README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.md b/README.md index 94ffe1f..4af6352 100644 --- a/README.md +++ b/README.md @@ -32,3 +32,22 @@ bindsym $mod+d exec $menu ### Setup a Terminal command Some of your desktop entries will probably be TUI programs that expect to be launched in a new terminal window. Those entries have the `Terminal=true` flag set and you need to tell the launcher which terminal emulator to use. Pass the `TERMINAL_COMMAND` environment variable with your terminal startup command to the script to use your preferred terminal emulator. The script will default to `urxvt -e` + +## Extending the launcher + +In addition to desktop application entries and binaries, you can extend `sway-launcher-desktop` with custom item providers. +If will read the configuration of custom item providers from `$HOME/.config/sway-launcher-desktop/providers.conf` +The structure looks like this: + +``` +[my-provider] +list_cmd=echo 'my-custom-entry\034 \034My custom provider' +preview_cmd=echo 'This is the preview of {1}' +launch_cmd=notify-send 'I am not launching {1}' +``` + +The `list_cmd` generated the list of entries. For each entry, it has to print the following columns, separated by the `\034` field separator character: +1. The item to launch. This will get passed to `preview_cmd` and `launch_cmd` as `{1}` +2. A glyph or any kind of prefix to differentiate your provider from others. Feel free to use ANSI escape codes for coloring it +3. The text that appears in the `fzf` window +4. (optional) Metadata that you can pass to `preview_cmd` and `launch_cmd` as `{2}`. For example, this is used to specify a specific Desktop Action inside a .desktop file \ No newline at end of file -- cgit v1.2.3 From d3a3657a0f21e87acce072deaf1d30095b447b24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20Mei=C3=9Felbach?= Date: Fri, 29 Nov 2019 23:13:30 +0100 Subject: typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4af6352..8f2ae8e 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ The structure looks like this: [my-provider] list_cmd=echo 'my-custom-entry\034 \034My custom provider' preview_cmd=echo 'This is the preview of {1}' -launch_cmd=notify-send 'I am not launching {1}' +launch_cmd=notify-send 'I am now launching {1}' ``` The `list_cmd` generated the list of entries. For each entry, it has to print the following columns, separated by the `\034` field separator character: -- cgit v1.2.3 From 4e58f614e28cd23106101b303dccc526febf16b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20Mei=C3=9Felbach?= Date: Fri, 29 Nov 2019 23:58:24 +0100 Subject: Implement template variable substitution in provider commands --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8f2ae8e..d3a07af 100644 --- a/README.md +++ b/README.md @@ -41,13 +41,13 @@ The structure looks like this: ``` [my-provider] -list_cmd=echo 'my-custom-entry\034 \034My custom provider' +list_cmd=echo 'my-custom-entry\034my-provider\034 \034My custom provider' preview_cmd=echo 'This is the preview of {1}' launch_cmd=notify-send 'I am now launching {1}' ``` The `list_cmd` generated the list of entries. For each entry, it has to print the following columns, separated by the `\034` field separator character: 1. The item to launch. This will get passed to `preview_cmd` and `launch_cmd` as `{1}` -2. A glyph or any kind of prefix to differentiate your provider from others. Feel free to use ANSI escape codes for coloring it -3. The text that appears in the `fzf` window +2. The name of your provider (the same as what what you put inside the brackets, so `my-provider` in this example) +3. The text that appears in the `fzf` window. You might want to prepend it with a glyph and add some color via ANSI escape codes 4. (optional) Metadata that you can pass to `preview_cmd` and `launch_cmd` as `{2}`. For example, this is used to specify a specific Desktop Action inside a .desktop file \ No newline at end of file -- cgit v1.2.3 From bf4c34f708eb355bbeca87bb296b0a2d42c23fc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20Mei=C3=9Felbach?= Date: Fri, 29 Nov 2019 23:58:40 +0100 Subject: Implement template variable substitution in provider commands --- sway-launcher-desktop.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sway-launcher-desktop.sh b/sway-launcher-desktop.sh index 7e2861b..df538d9 100755 --- a/sway-launcher-desktop.sh +++ b/sway-launcher-desktop.sh @@ -39,13 +39,10 @@ if [ -f "${CONFIG_DIR}/providers.conf" ]; then }' "${CONFIG_DIR}/providers.conf") eval "$PARSED" else - PROVIDERS['desktop']="${0} list-entries${DEL}${0} describe-desktop${DEL}${0} generate-command" - PROVIDERS['command']="${0} list-commands${DEL}${0} describe-command${DEL}${0} command-line" + PROVIDERS['desktop']="${0} list-entries${DEL}${0} describe-desktop '{1}'${DEL}${0} generate-command {1} {2}" + PROVIDERS['command']="${0} list-commands${DEL}${0} describe-command {1}${DEL}${0} command-line {1}" fi -#for i in "${!PROVIDERS[@]}"; do -# echo "${i}=${PROVIDERS[$i]}" -#done -#exit + touch "$HIST_FILE" readarray HIST_LINES <"$HIST_FILE" @@ -56,7 +53,7 @@ function describe() { # shellcheck disable=SC2086 readarray -d ${DEL} -t PROVIDER_ARGS <<<${PROVIDERS[${1}]} # shellcheck disable=SC2086 - [ -n "${PROVIDER_ARGS[1]}" ] && eval "${PROVIDER_ARGS[1]} ${2}" + [ -n "${PROVIDER_ARGS[1]}" ] && eval "${PROVIDER_ARGS[1]//\{1\}/${2}}" } function describe-desktop() { description=$(sed -ne '/^Comment=/{s/^Comment=//;p;q}' "$1") @@ -247,6 +244,9 @@ readarray -d $'\034' -t PARAMS <<<${COMMAND_STR} # COMMAND_STR is "\034" # 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]}} # shellcheck disable=SC2086 -command=$(eval ${PROVIDER_ARGS[1]} ${PARAMS[0]} ${PARAMS[3]}) +command=$(bash -c ${COMMAND}) (exec setsid /bin/sh -c "$command" &) -- cgit v1.2.3 From 9827852e967849714b9497c74543eb14a17606d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20Mei=C3=9Felbach?= Date: Fri, 29 Nov 2019 23:59:53 +0100 Subject: Fix example provider --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d3a07af..70fbac9 100644 --- a/README.md +++ b/README.md @@ -41,8 +41,8 @@ The structure looks like this: ``` [my-provider] -list_cmd=echo 'my-custom-entry\034my-provider\034 \034My custom provider' -preview_cmd=echo 'This is the preview of {1}' +list_cmd=echo -e 'my-custom-entry\034my-provider\034 My custom provider' +preview_cmd=echo -e 'This is the preview of {1}' launch_cmd=notify-send 'I am now launching {1}' ``` -- cgit v1.2.3 From 3429a175db5eb6a9ca9ab93c808b6ed102ab7393 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20Mei=C3=9Felbach?= Date: Sat, 30 Nov 2019 00:38:56 +0100 Subject: Fix and improve usage of launch_cmd in providers --- README.md | 8 ++++++-- sway-launcher-desktop.sh | 18 ++++++++---------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 70fbac9..e92a677 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Some of your desktop entries will probably be TUI programs that expect to be lau ## Extending the launcher In addition to desktop application entries and binaries, you can extend `sway-launcher-desktop` with custom item providers. -If will read the configuration of custom item providers from `$HOME/.config/sway-launcher-desktop/providers.conf` +If will read the configuration of custom item providers from `$HOME/.config/sway-launcher-desktop/providers.conf`. The structure looks like this: ``` @@ -50,4 +50,8 @@ The `list_cmd` generated the list of entries. For each entry, it has to print th 1. The item to launch. This will get passed to `preview_cmd` and `launch_cmd` as `{1}` 2. The name of your provider (the same as what what you put inside the brackets, so `my-provider` in this example) 3. The text that appears in the `fzf` window. You might want to prepend it with a glyph and add some color via ANSI escape codes -4. (optional) Metadata that you can pass to `preview_cmd` and `launch_cmd` as `{2}`. For example, this is used to specify a specific Desktop Action inside a .desktop file \ No newline at end of file +4. (optional) Metadata that you can pass to `preview_cmd` and `launch_cmd` as `{2}`. For example, this is used to specify a specific Desktop Action inside a .desktop file + +The `preview_cmd` renders the contents of the `fzf` preview panel. You can use the template variable `{1}` in your command, which will be substituted with the value of the selected item. + +The `launch_cmd` is fired when the user has selected one of the provider's entries. \ No newline at end of file diff --git a/sway-launcher-desktop.sh b/sway-launcher-desktop.sh index df538d9..0eb588a 100755 --- a/sway-launcher-desktop.sh +++ b/sway-launcher-desktop.sh @@ -22,7 +22,7 @@ CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/sway-launcher-desktop" # list_cmd,preview_cmd,launch_cmd declare -A PROVIDERS if [ -f "${CONFIG_DIR}/providers.conf" ]; then - PARSED=$( awk -F= ' + PARSED=$(awk -F= ' BEGINFILE{ provider=""; } /^\[.*\]/{sub("^\\[", "");sub("\\]$", "");provider=$0} /^(launch|list|preview)_cmd/{st = index($0,"=");providers[provider][$1] = substr($0,st+1)} @@ -39,8 +39,8 @@ if [ -f "${CONFIG_DIR}/providers.conf" ]; then }' "${CONFIG_DIR}/providers.conf") eval "$PARSED" else - PROVIDERS['desktop']="${0} list-entries${DEL}${0} describe-desktop '{1}'${DEL}${0} generate-command {1} {2}" - PROVIDERS['command']="${0} list-commands${DEL}${0} describe-command {1}${DEL}${0} command-line {1}" + PROVIDERS['desktop']="${0} list-entries${DEL}${0} describe-desktop '{1}'${DEL}${0} run-desktop '{1}' {2}" + PROVIDERS['command']="${0} list-commands${DEL}${0} describe-command {1}${DEL}${TERMINAL_COMMAND} {1}" fi touch "$HIST_FILE" @@ -143,7 +143,9 @@ function entries() { $@ "$HIST_FILE" -command='echo "nope"' # shellcheck disable=SC2086 readarray -d $'\034' -t PARAMS <<<${COMMAND_STR} -# COMMAND_STR is "\034" # 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]}} -# shellcheck disable=SC2086 -command=$(bash -c ${COMMAND}) -(exec setsid /bin/sh -c "$command" &) +(exec setsid /bin/sh -c "${COMMAND}" &) -- cgit v1.2.3 From cde8acce5af493dd6306eb7c4f0cefb5622ef401 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20Mei=C3=9Felbach?= Date: Sat, 30 Nov 2019 00:48:30 +0100 Subject: remove obsolete function --- sway-launcher-desktop.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sway-launcher-desktop.sh b/sway-launcher-desktop.sh index 0eb588a..4cd68ee 100755 --- a/sway-launcher-desktop.sh +++ b/sway-launcher-desktop.sh @@ -46,9 +46,6 @@ fi touch "$HIST_FILE" readarray HIST_LINES <"$HIST_FILE" -function command-line() { - echo "${TERMINAL_COMMAND} ${1}" -} function describe() { # shellcheck disable=SC2086 readarray -d ${DEL} -t PROVIDER_ARGS <<<${PROVIDERS[${1}]} @@ -198,7 +195,7 @@ function generate-command() { } case "$1" in -describe | describe-desktop | describe-command | entries | list-entries | list-commands | command-line | generate-command | run-desktop | provide) +describe | describe-desktop | describe-command | entries | list-entries | list-commands | generate-command | run-desktop | provide) "$@" exit ;; -- cgit v1.2.3 From fe8b4d83521f802aa791861093036fb327ab23be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20Mei=C3=9Felbach?= Date: Sat, 30 Nov 2019 01:06:07 +0100 Subject: gentle golfing --- sway-launcher-desktop.sh | 42 ++++++++++-------------------------------- 1 file changed, 10 insertions(+), 32 deletions(-) diff --git a/sway-launcher-desktop.sh b/sway-launcher-desktop.sh index 4cd68ee..f861177 100755 --- a/sway-launcher-desktop.sh +++ b/sway-launcher-desktop.sh @@ -22,7 +22,7 @@ CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/sway-launcher-desktop" # list_cmd,preview_cmd,launch_cmd declare -A PROVIDERS if [ -f "${CONFIG_DIR}/providers.conf" ]; then - PARSED=$(awk -F= ' + eval "$(awk -F= ' BEGINFILE{ provider=""; } /^\[.*\]/{sub("^\\[", "");sub("\\]$", "");provider=$0} /^(launch|list|preview)_cmd/{st = index($0,"=");providers[provider][$1] = substr($0,st+1)} @@ -36,8 +36,7 @@ if [ -f "${CONFIG_DIR}/providers.conf" ]; then } print "PROVIDERS[\x27" key "\x27]=\x27" providers[key]["list_cmd"] "\034" providers[key]["preview_cmd"] "\034" providers[key]["launch_cmd"] "\x27\n" } - }' "${CONFIG_DIR}/providers.conf") - eval "$PARSED" + }' "${CONFIG_DIR}/providers.conf")" else PROVIDERS['desktop']="${0} list-entries${DEL}${0} describe-desktop '{1}'${DEL}${0} run-desktop '{1}' {2}" PROVIDERS['command']="${0} list-commands${DEL}${0} describe-command {1}${DEL}${TERMINAL_COMMAND} {1}" @@ -58,11 +57,10 @@ function describe-desktop() { echo "${description:-No description}" } function describe-command() { - title=$1 readarray arr < <(whatis -l "$1" 2>/dev/null) description="${arr[0]}" description="${description%*-}" - echo -e "\033[33m$title\033[0m" + echo -e "\033[33m${1}\033[0m" echo "${description:-No description}" } @@ -82,7 +80,6 @@ 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]' @@ -122,13 +119,7 @@ function entries() { a++; actions[a,"key"]=$0 } - /^Name=/{ - if(block=="action") { - actions[a,"name"]=$2; - } else { - name=$2 - } - } + /^Name=/{ (block=="action")? actions[a,"name"]=$2 : name=$2 } ENDFILE{ if (application){ print FILENAME "\034desktop\034\033[33m" pre name "\033[0m"; @@ -157,18 +148,12 @@ function generate-command() { awk -v pattern="${PATTERN}" -v terminal_cmd="${TERMINAL_COMMAND}" -F= ' BEGIN{a=0;exec=0;path=0} /^\[Desktop/{ - if(a){ - a=0 - } + if(a){ a=0 } } - $0 ~ pattern{ - a=1 - } + $0 ~ pattern{ a=1 } /^Terminal=/{ sub("^Terminal=", ""); - if ($0 == "true") { - terminal=1 - } + if ($0 == "true") { terminal=1 } } /^Exec=/{ if(a && !exec){ @@ -178,18 +163,11 @@ function generate-command() { } } /^Path=/{ - if(a && !path){ - path=$2 - } + if(a && !path){ path=$2 } } - END{ - if(path){ - printf "cd " path " && " - } - if (terminal){ - printf terminal_cmd " " - } + if(path){ printf "cd " path " && " } + if (terminal){ printf terminal_cmd " " } print exec }' "$1" } -- cgit v1.2.3 From bd5bfc49309a49c09d97be8530b166507342ba07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20Mei=C3=9Felbach?= Date: Tue, 3 Dec 2019 20:06:21 +0100 Subject: Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e92a677..5e0de3e 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Some of your desktop entries will probably be TUI programs that expect to be lau ## Extending the launcher In addition to desktop application entries and binaries, you can extend `sway-launcher-desktop` with custom item providers. -If will read the configuration of custom item providers from `$HOME/.config/sway-launcher-desktop/providers.conf`. +It will read the configuration of custom item providers from `$HOME/.config/sway-launcher-desktop/providers.conf`. The structure looks like this: ``` -- cgit v1.2.3