Add sd
parent
6aaee34153
commit
47c019dbde
|
@ -0,0 +1,314 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# https://github.com/ianthehenry/sd
|
||||
# ecd1ab8d3fc3a829d8abfb8bf1e3722c9c99407b
|
||||
|
||||
__sd_join_path() {
|
||||
echo "$@" | tr ' ' /
|
||||
}
|
||||
|
||||
__sd_which() {
|
||||
echo "$1"
|
||||
}
|
||||
|
||||
__sd_cat() {
|
||||
${SD_CAT:-cat} "$1"
|
||||
}
|
||||
|
||||
__sd_edit() {
|
||||
${SD_EDITOR:-${VISUAL:-${EDITOR:-vi}}} "$1"
|
||||
}
|
||||
|
||||
__sd_directory_help() {
|
||||
local target="$1"
|
||||
local i file helpfile help command
|
||||
local -a commands helps
|
||||
if [[ -d "$target" ]]; then
|
||||
helpfile="$target/help"
|
||||
else
|
||||
helpfile="$target.help"
|
||||
fi
|
||||
# in case you have `sd help` as a command alias, we don't
|
||||
# want to print that when you just run "sd" by itself.
|
||||
# Admittedly we don't check this in any other place, which
|
||||
# could be considered a bug, but whatever it's a weird little
|
||||
# hack and no one uses this.
|
||||
if [[ -e "$helpfile" && ! -x "$helpfile" ]]; then
|
||||
__sd_cat "$helpfile"
|
||||
echo
|
||||
else
|
||||
command=$(basename "$target")
|
||||
echo "$command commands"
|
||||
echo
|
||||
fi
|
||||
commands=()
|
||||
helps=()
|
||||
for file in "$target"/*; do
|
||||
if [[ ! -x "$file" ]]; then
|
||||
continue
|
||||
fi
|
||||
command=$(basename "$file")
|
||||
|
||||
if [[ -d "$file" ]]; then
|
||||
helpfile="$file/help"
|
||||
if [[ -f "$helpfile" ]]; then
|
||||
help=$(head -n1 "$helpfile")
|
||||
else
|
||||
help="$command commands"
|
||||
fi
|
||||
command="$command ..."
|
||||
else
|
||||
helpfile="$file.help"
|
||||
if [[ -f "$helpfile" ]]; then
|
||||
help=$(head -n1 "$helpfile")
|
||||
else
|
||||
help=$(sed -nE -e '/^#!/d' -e '/^#/{s/^# *//; p; q;}' "$file")
|
||||
fi
|
||||
fi
|
||||
|
||||
commands+=("$command")
|
||||
helps+=("$help")
|
||||
done
|
||||
|
||||
if [[ ${#commands[@]} -eq 0 ]]; then
|
||||
echo "(no subcommands found)"
|
||||
else
|
||||
local max_length=0
|
||||
local length
|
||||
for command in "${commands[@]}"; do
|
||||
length=${#command}
|
||||
max_length=$((length > max_length ? length : max_length))
|
||||
done
|
||||
|
||||
if [[ -n ${ZSH_EVAL_CONTEXT+x} ]]; then
|
||||
set -o LOCAL_OPTIONS
|
||||
# we need to ensure we have 0-indexed arrays
|
||||
# in order for this loop to work properly.
|
||||
# zsh doesn't support ${!commands[@]} expansion
|
||||
set -o KSH_ARRAYS
|
||||
fi
|
||||
|
||||
for ((i = 0; i < ${#commands[@]}; i++)); do
|
||||
printf "%-${max_length}s -- %s\n" "${commands[i]}" "${helps[i]}"
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
__sd_help() {
|
||||
local target=$1
|
||||
|
||||
if [[ -d "$target" ]]; then
|
||||
__sd_directory_help "$target"
|
||||
elif [[ -f "$target.help" ]]; then
|
||||
__sd_cat "$target.help"
|
||||
else
|
||||
help=$(sed -nE -e '/^#!/d' -e $':start\n /^#/{ s/^# ?//; p; \nb start\n }' "$target")
|
||||
if [[ -z "$help" ]]; then
|
||||
echo "there is no help for you here" >&2
|
||||
exit 1
|
||||
else
|
||||
echo "$help"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
__sd_print_template() {
|
||||
if [[ -f "$1/template" ]]; then
|
||||
cat "$1/template"
|
||||
else
|
||||
if [[ "$1" = "${SD_ROOT:-$HOME/sd}" ]]; then
|
||||
cat <<EOF
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
EOF
|
||||
else
|
||||
__sd_print_template "$(dirname "$1")"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
__sd_new() {
|
||||
local script dir target body
|
||||
target="$1"
|
||||
shift
|
||||
|
||||
local -a command_path=()
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--new) shift; break ;;
|
||||
*) command_path+=("$arg"); shift ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ ${#command_path[@]} -eq 0 ]]; then
|
||||
echo "error: $target already exists" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -f "$target" ]]; then
|
||||
echo "error: command prefix $target is a regular file" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
body="$*"
|
||||
|
||||
script="$target"/"$(__sd_join_path "${command_path[@]}")"
|
||||
|
||||
if [[ -e "$script" ]]; then
|
||||
echo "$script already exists!" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dir="$(dirname "$script")"
|
||||
mkdir -p "$dir"
|
||||
(
|
||||
__sd_print_template "$dir"
|
||||
if [[ -n "$body" ]]; then
|
||||
printf "\n%s\n" "$body"
|
||||
fi
|
||||
) >"$script"
|
||||
|
||||
chmod +x "$script"
|
||||
|
||||
if [[ -z "$body" ]]; then
|
||||
__sd_edit "$script"
|
||||
fi
|
||||
}
|
||||
|
||||
__sd_new_user_help() {
|
||||
root=$1
|
||||
echo >&2 "error: $root not found"
|
||||
echo >&2
|
||||
echo >&2 "It looks like you don't have a script directory yet!"
|
||||
echo >&2
|
||||
echo >&2 "Get started by creating your first script:"
|
||||
echo >&2
|
||||
echo >&2 " sd hello --new 'echo \"Hello, sd!\"'"
|
||||
echo >&2
|
||||
echo >&2 "And then run it like this:"
|
||||
echo >&2
|
||||
echo >&2 " sd hello"
|
||||
}
|
||||
|
||||
__sd() {
|
||||
set -euo pipefail
|
||||
|
||||
local root=${SD_ROOT:-$HOME/sd}
|
||||
|
||||
if [[ -e "$root" && ! -d "$root" ]]; then
|
||||
echo "error: $root is not a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local target=$root
|
||||
local arg
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
arg="$1"
|
||||
if [[ -d "$target/$arg" ]]; then
|
||||
target="$target/$arg"
|
||||
shift
|
||||
elif [[ -f "$target/$arg" ]]; then
|
||||
target="$target/$arg"
|
||||
shift
|
||||
break
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
local found_help="false"
|
||||
local found_new="false"
|
||||
local found_edit="false"
|
||||
local found_cat="false"
|
||||
local found_which="false"
|
||||
local found_really="false"
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--help) found_help=true ;;
|
||||
--new) found_new=true ;;
|
||||
--edit) found_edit=true ;;
|
||||
--cat) found_cat=true ;;
|
||||
--which) found_which=true ;;
|
||||
--really) found_really=true ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# you're allowed to run --new even if there is no
|
||||
# script directory root, in order to bootstrap it
|
||||
if [[ "$found_really" = "true" || "$found_new" = "false" ]]; then
|
||||
if [[ ! -d "$root" ]]; then
|
||||
__sd_new_user_help "$root"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$found_really" = "true" ]]; then
|
||||
local -a preserved=()
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
'--really') shift; break ;;
|
||||
*) preserved+=("$arg"); shift ;;
|
||||
esac
|
||||
done
|
||||
if [[ ${#preserved[@]} -gt 0 ]]; then
|
||||
set -- "${preserved[@]}" "$@"
|
||||
fi
|
||||
elif [[ "$found_new" = "true" ]]; then
|
||||
__sd_new "$target" "$@"
|
||||
exit 0
|
||||
elif [[ "$found_help" = "true" ]]; then
|
||||
__sd_help "$target"
|
||||
exit 0
|
||||
elif [[ "$found_edit" = "true" ]]; then
|
||||
__sd_edit "$target"
|
||||
exit 0
|
||||
elif [[ "$found_cat" = "true" ]]; then
|
||||
__sd_cat "$target"
|
||||
exit 0
|
||||
elif [[ "$found_which" = "true" ]]; then
|
||||
__sd_which "$target"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ -d "$target" ]]; then
|
||||
__sd_directory_help "$target"
|
||||
if [[ $# -gt 0 ]]; then
|
||||
echo >&2
|
||||
echo "$target/$(__sd_join_path "$@") not found" >&2
|
||||
exit 1
|
||||
fi
|
||||
elif [[ -x "$target" ]]; then
|
||||
SD="$(dirname "$target")" exec "$target" "$@"
|
||||
else
|
||||
__sd_cat "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
# If you source this file and use function-mode sd, we want to
|
||||
# wrap the execution in a subshell so that set -e doesn't kill
|
||||
# the interactive shell, and so that we can exec the subshell
|
||||
# without destroying the interactive shell.
|
||||
sd() (
|
||||
__sd "$@"
|
||||
)
|
||||
|
||||
# If you source this file, it will define the function sd,
|
||||
# which you can use from your shell. If you *run* this file
|
||||
# as an executable, it will just invoke that function. We
|
||||
# have to do some tricks to detect that reliably on bash/zsh.
|
||||
|
||||
if [[ -n ${ZSH_EVAL_CONTEXT+x} ]]; then
|
||||
# we are in zsh
|
||||
if [[ "$ZSH_EVAL_CONTEXT" = toplevel ]]; then
|
||||
__sd "$@"
|
||||
fi
|
||||
elif [[ -n ${BASH_SOURCE[0]+x} ]]; then
|
||||
# we are in bash
|
||||
if [[ "${BASH_SOURCE[0]}" = "$0" ]]; then
|
||||
__sd "$@"
|
||||
fi
|
||||
fi
|
Loading…
Reference in New Issue