176 lines
5.9 KiB
Bash
Executable File
176 lines
5.9 KiB
Bash
Executable File
#!/usr/bin/env sh
|
|
|
|
# Dmenu for opening a program with a specific directory.
|
|
|
|
# MIT License
|
|
#
|
|
# Copyright (c) 2020 Alexander Chaplin Braz
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
# in the Software without restriction, including without limitation the rights
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
# furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in all
|
|
# copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
# SOFTWARE.
|
|
|
|
ScriptName=${0##*/}
|
|
Version=1.0.0
|
|
|
|
# Set default bookmark if there is none:
|
|
BlankMark='---'
|
|
|
|
# Compose the help message:
|
|
HelpMessage="$ScriptName - Version: $Version
|
|
Creator: Alexander Chaplin Braz (https://alexchaplinbraz.com)
|
|
License: MIT
|
|
|
|
Usage: $ScriptName {dirpath | filepath} {programs} [mark]
|
|
|
|
This script lets the user open a directory with a program
|
|
using dmenu to select them. For this, it requires two arguments.
|
|
|
|
The first one can either be a directory from which it will find all the
|
|
subdirectories, or a file that holds a list of directories acting as bookmarks.
|
|
It's highly recommended to use absolute paths, but relative paths also work.
|
|
|
|
The second one has to be a comma separated list of programs which can be
|
|
unquoted, but quoting it gives the user the ability to specify options
|
|
for the programs.
|
|
|
|
An optional third argument lets the user change the default bookmark name
|
|
when no bookmark name was set in the bookmark file. Default: $BlankMark
|
|
|
|
The bookmark file must have a format where the path is at the start of a line.
|
|
One optional bookmark name can be set after the path by separating them with a
|
|
tab. Nothing from column 3+ is parsed. So you can use it freely to add comments
|
|
or whatever. You can also comment out lines with any character (other than \"),
|
|
thus breaking the path, so it won't show up as an option.
|
|
|
|
In the case where there's only one program and/or directory, they will be
|
|
selected automatically.
|
|
|
|
Usage examples:
|
|
$ScriptName \$HOME vifm,lf,sxiv
|
|
$ScriptName \ ranger,vifm
|
|
$ScriptName \"\$HOME/Pictures\" \"sxiv -t,sxiv -arf\"
|
|
$ScriptName \"\$HOME/Documents/dir-bookmarks.txt\" lf
|
|
$ScriptName \"\$HOME/Documents/dir-bookmarks.txt\" lf ###
|
|
|
|
Example bookmarks file (keep in mind the tab separation):
|
|
|
|
\$HOME HM
|
|
\"\$HOME/Pictures/Art References\" AR
|
|
\"\$XDG_CONFIG_HOME\" CNF
|
|
#\$COMMENT CM COMMENT: this can be whatever since it's not parsed.
|
|
/mnt MNT
|
|
/etc ETC
|
|
/backup BU
|
|
"
|
|
|
|
suggest_help_and_exit() {
|
|
printf "Try '%s --help' for more information.\n" "$ScriptName"
|
|
exit 1
|
|
}
|
|
|
|
case $1 in
|
|
'') printf '%s' "$HelpMessage"; exit 1;;
|
|
-h|--help) printf '%s' "$HelpMessage"; exit 0;;
|
|
-v|--version) printf '%s - Version: %s\n' "$ScriptName" "$Version"; exit 0;;
|
|
esac
|
|
|
|
# Set custom blank mark if it was set by the user:
|
|
[ "$3" ] && BlankMark=$3
|
|
|
|
# Set a location for the temporary file that holds the found directories:
|
|
TempFile="/tmp/$ScriptName-dirs"
|
|
|
|
# Set up a function that can be called to run in the background:
|
|
find_directories() {
|
|
find "$1" -type d 2>/dev/null > "$TempFile"
|
|
printf '%s' "$ScriptName ENDofSEARCH" >> "$TempFile"
|
|
}
|
|
|
|
# Parse the passed programs:
|
|
Parsed=$(printf '%s' "$2" | tr -s ',' '\n')
|
|
|
|
# Count the amount of programs:
|
|
ProgramAmount=$(printf '%s\n' "$Parsed" | wc -l)
|
|
|
|
# Determine whether the first argument is a directory or a file:
|
|
if [ -d "$1" ]; then
|
|
Directory=$1
|
|
elif [ "$(file -i "$1" | awk '{printf $2}')" = 'text/plain;' ]; then
|
|
cat "$1" | while IFS= read -r line; do
|
|
line=$(printf '%s' "$line" \
|
|
| awk -F '\t' -v blank=$BlankMark \
|
|
'{print match($2, /[^ ]/) ? $2 : blank, $1}' OFS='\t')
|
|
path=$(printf '%s' "$line" | awk -F '\t' '{printf $2}')
|
|
eval [ -d "$path" ] 2>/dev/null \
|
|
&& printf '%s\n' "$line" >> "$TempFile"
|
|
done
|
|
if [ ! -s "$TempFile" ]; then
|
|
printf 'ERROR: no valid directories in the specified file.\n'
|
|
suggest_help_and_exit
|
|
fi
|
|
[ $ProgramAmount = 1 ] && pn="[$Parsed] "
|
|
Directory=$(printf '%s' "$(cat "$TempFile")" \
|
|
| dmenu -i -l 30 -p "${pn}Select parent directory:" \
|
|
| awk -F '\t' '{printf $2}')
|
|
else
|
|
printf 'ERROR: invalid first argument.\n'
|
|
suggest_help_and_exit
|
|
fi
|
|
|
|
# Delete the temporary file:
|
|
rm "$TempFile" 2>/dev/null
|
|
|
|
# Exit if no directory was selected:
|
|
[ -z "$Directory" ] && exit 1
|
|
|
|
# Do the directory search in the background:
|
|
eval find_directories "$Directory" &
|
|
|
|
# If there's only one program, skip selecting it:
|
|
if [ $ProgramAmount = 1 ]; then
|
|
Program=$Parsed
|
|
# Else, select the program first to hide the time taken to find the directories:
|
|
else
|
|
Program=$(printf '%s' "$Parsed" \
|
|
| dmenu -i -l 30 -p 'Select program:')
|
|
[ -z "$Program" ] && exit 1
|
|
fi
|
|
|
|
# Wait until all directories have been found:
|
|
until [ "$(tail -n 1 "$TempFile")" = "$ScriptName ENDofSEARCH" ]; do
|
|
sleep 0.1
|
|
done
|
|
|
|
# If there's only the result of the directory itself, select it:
|
|
if [ $(wc -l "$TempFile" | awk '{printf $1}') = 1 ]; then
|
|
Chosen=$(sed '$d' "$TempFile")
|
|
# Else, choose a directory:
|
|
else
|
|
Chosen=$(sed '$d' "$TempFile" \
|
|
| dmenu -i -l 30 -p "[$Program] Select directory:")
|
|
fi
|
|
|
|
# Delete the temporary file:
|
|
rm "$TempFile" 2>/dev/null
|
|
|
|
# Exit if no directory was chosen:
|
|
[ -z "$Chosen" ] && exit 1
|
|
|
|
# Launch the selected program with the selected directory:
|
|
eval "$Program" \""$Chosen"\"
|