improve command and completions
This commit is contained in:
8
.editorconfig
Normal file
8
.editorconfig
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
361
a.patch
Normal file
361
a.patch
Normal file
@@ -0,0 +1,361 @@
|
|||||||
|
diff --git a/.editorconfig b/.editorconfig
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..dc0bd83
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/.editorconfig
|
||||||
|
@@ -0,0 +1,8 @@
|
||||||
|
+root = true
|
||||||
|
+
|
||||||
|
+[*]
|
||||||
|
+charset = utf-8
|
||||||
|
+indent_size = 2
|
||||||
|
+indent_style = space
|
||||||
|
+insert_final_newline = true
|
||||||
|
+trim_trailing_whitespace = true
|
||||||
|
\ No newline at end of file
|
||||||
|
diff --git a/completion.bash b/completion.bash
|
||||||
|
index a96fc8c..68a370b 100644
|
||||||
|
--- a/completion.bash
|
||||||
|
+++ b/completion.bash
|
||||||
|
@@ -4,41 +4,85 @@ _comp_cmd_goto() {
|
||||||
|
local cur prev words cword comp_args
|
||||||
|
_comp_initialize -- "$@" || return
|
||||||
|
|
||||||
|
- # echo "[$cur] [$prev] [${words[@]}] [$cword] [$comp_args]"
|
||||||
|
+ # the list of valid options with their argument requirement
|
||||||
|
+ # it is updated as the command is parsed
|
||||||
|
+ local -A valid_opts=([-a]=true [-r]=true [-g]=true [-e]=false [-l]=false [-t]=false)
|
||||||
|
+ # how many positional arguments are expected
|
||||||
|
+ local -i expected_positional_args=1
|
||||||
|
+ # optionals and positionals read up to, not including ${cword} (current word index)
|
||||||
|
+ local -i opt_args=0 positional_args=0
|
||||||
|
+ # holds an option that requires its argument to be read next
|
||||||
|
+ local expected_optarg
|
||||||
|
|
||||||
|
- local -A opts=([-e]="" [-l]="" [-t]="")
|
||||||
|
+ local i word
|
||||||
|
+ for (( i = 1; i < cword; i++ )); do
|
||||||
|
+ word="${words[${i}]}"
|
||||||
|
|
||||||
|
- local i
|
||||||
|
- for i in "${!words[@]}"; do
|
||||||
|
- [[ ${words[i]} && $i -ne $cword ]] && unset -v "opts[${words[i]}]"
|
||||||
|
- case "${words[i]}" in
|
||||||
|
- -e)
|
||||||
|
- unset -v 'opts[-l]' 'opts[-t]'
|
||||||
|
- ;;
|
||||||
|
- -l)
|
||||||
|
- unset -v 'opts[-e]' 'opts[-t]'
|
||||||
|
- ;;
|
||||||
|
- -t)
|
||||||
|
- unset -v 'opts[-e]' 'opts[-l]'
|
||||||
|
- ;;
|
||||||
|
- esac
|
||||||
|
+ if [[ "${word:0:1}" == '-' ]]; then # reading an option
|
||||||
|
+
|
||||||
|
+ # any option is invalid if...
|
||||||
|
+ if \
|
||||||
|
+ (( positional_args > 0 )) || # a positional parameter has been specified \
|
||||||
|
+ [[ -n "${expected_optarg}" ]] || # a previous option is expecting an argument \
|
||||||
|
+ ! [[ -v valid_opts["${word}"] ]] # the option is invalid given the previously provided ones \
|
||||||
|
+ then
|
||||||
|
+ return
|
||||||
|
+ fi
|
||||||
|
+
|
||||||
|
+ local arg_required=${valid_opts["${word}"]}
|
||||||
|
+
|
||||||
|
+ case "${word:1}" in
|
||||||
|
+ a|r)
|
||||||
|
+ unset -v 'valid_opts[-g]' 'valid_opts[-e]' 'valid_opts[-l]' 'valid_opts[-t]'
|
||||||
|
+ ;;
|
||||||
|
+ g|e|l|t)
|
||||||
|
+ valid_opts=()
|
||||||
|
+ ;;
|
||||||
|
+ *)
|
||||||
|
+ return
|
||||||
|
+ ;;
|
||||||
|
+ esac
|
||||||
|
+
|
||||||
|
+ if ${arg_required}; then
|
||||||
|
+ expected_optarg="${word}"
|
||||||
|
+ else
|
||||||
|
+ expected_optarg=
|
||||||
|
+ fi
|
||||||
|
+
|
||||||
|
+ expected_positional_args=0
|
||||||
|
+
|
||||||
|
+ (( opt_args++ ))
|
||||||
|
+ elif [[ -n "${expected_optarg}" ]]; then
|
||||||
|
+ expected_optarg=
|
||||||
|
+ else
|
||||||
|
+ (( positional_args++ ))
|
||||||
|
+
|
||||||
|
+ if (( positional_args > expected_positional_args )); then
|
||||||
|
+ return
|
||||||
|
+ fi
|
||||||
|
+ fi
|
||||||
|
done
|
||||||
|
|
||||||
|
- if [[ $cur == -* ]]; then
|
||||||
|
- _comp_compgen -- -W '"${!opts[@]}"'
|
||||||
|
+ if [[ "${cur:0:1}" == '-' ]]; then
|
||||||
|
+ if [[ -z "${expected_optarg}" ]] && (( positional_args == 0 )); then
|
||||||
|
+ _comp_compgen -- -W '"${!valid_opts[@]}"'
|
||||||
|
+ fi
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
- case $prev in
|
||||||
|
- -e)
|
||||||
|
- [[ -v 'opts[-e]' ]] && __goto_comp_keys
|
||||||
|
- return
|
||||||
|
- ;;
|
||||||
|
- esac
|
||||||
|
+ if [[ "${prev:0:1}" == '-' ]]; then
|
||||||
|
+ case "${prev:1}" in
|
||||||
|
+ r|g)
|
||||||
|
+ __goto_comp_keys
|
||||||
|
+ ;;
|
||||||
|
+ esac
|
||||||
|
+ return
|
||||||
|
+ fi
|
||||||
|
|
||||||
|
- # do goto keys only if we did not have -[elt]
|
||||||
|
- [[ ${words[*]} == *\ -* ]] || __goto_comp_keys
|
||||||
|
+ if (( opt_args == 0 && positional_args == 0 )); then
|
||||||
|
+ __goto_comp_keys
|
||||||
|
+ fi
|
||||||
|
} &&
|
||||||
|
complete -F _comp_cmd_goto goto
|
||||||
|
|
||||||
|
-# ex: filetype=sh
|
||||||
|
\ No newline at end of file
|
||||||
|
+# ex: filetype=sh
|
||||||
|
diff --git a/goto.bash b/goto.bash
|
||||||
|
index 9a32e11..5076aa2 100644
|
||||||
|
--- a/goto.bash
|
||||||
|
+++ b/goto.bash
|
||||||
|
@@ -6,14 +6,14 @@
|
||||||
|
readonly __GOTO_ROOT_DIR=~/.goto
|
||||||
|
# goto configuration file that contains the directory mappings
|
||||||
|
readonly __GOTO_FILE=${__GOTO_ROOT_DIR}/goto.yaml
|
||||||
|
-# path to yq executable
|
||||||
|
+# path to yq executable used by goto
|
||||||
|
readonly __GOTO_YQ=/usr/local/bin/yq
|
||||||
|
|
||||||
|
__goto_exists() {
|
||||||
|
[[ -f ${__GOTO_FILE} ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
-__goto_load() {
|
||||||
|
+__goto_load_entries() {
|
||||||
|
# load the directory mappings from the configuration file into the variable reference passed as parameter
|
||||||
|
# $1: name of the result associative array to create
|
||||||
|
|
||||||
|
@@ -24,7 +24,8 @@ __goto_load() {
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
- local entries entry key value
|
||||||
|
+ local -a entries
|
||||||
|
+ local entry key value
|
||||||
|
|
||||||
|
mapfile entries < <(${__GOTO_YQ} 'explode(.) | to_entries[] | "\(.key) \(.value)"' ${__GOTO_FILE})
|
||||||
|
|
||||||
|
@@ -43,13 +44,27 @@ __goto_load() {
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
+__goto_load_keys() {
|
||||||
|
+ # load the directory keys from the configuration file into the variable reference passed as parameter
|
||||||
|
+ # $1: name of the result array to create
|
||||||
|
+
|
||||||
|
+ local -n data_ref=$1
|
||||||
|
+ data_ref=()
|
||||||
|
+
|
||||||
|
+ if ! __goto_exists; then
|
||||||
|
+ return
|
||||||
|
+ fi
|
||||||
|
+
|
||||||
|
+ mapfile data_ref < <(${__GOTO_YQ} 'keys[]' ${__GOTO_FILE})
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
__goto_comp_keys() {
|
||||||
|
# loads and initializes directory aliases completions for the goto command
|
||||||
|
|
||||||
|
- local -A data
|
||||||
|
- __goto_load data
|
||||||
|
+ local -a data
|
||||||
|
+ __goto_load_keys data
|
||||||
|
|
||||||
|
- _comp_compgen -- -W '"${!data[@]}"'
|
||||||
|
+ _comp_compgen -- -W '"${data[@]}"'
|
||||||
|
}
|
||||||
|
|
||||||
|
__goto_resolve_path() {
|
||||||
|
@@ -63,7 +78,7 @@ __goto_prompt() {
|
||||||
|
# prompt string for the terminal
|
||||||
|
|
||||||
|
local -A data
|
||||||
|
- __goto_load data
|
||||||
|
+ __goto_load_entries data
|
||||||
|
|
||||||
|
local entry_key entry_value best_match="" best_key=""
|
||||||
|
|
||||||
|
@@ -71,7 +86,7 @@ __goto_prompt() {
|
||||||
|
entry_value=$(__goto_resolve_path "${data[${entry_key}]}")
|
||||||
|
|
||||||
|
# select the closest ancestor of the current working directory
|
||||||
|
- if [[ "${PWD}" == "${entry_value}"* ]] && [[ ${#entry_value} -gt ${#best_match} ]]; then
|
||||||
|
+ if [[ "${PWD}" == "${entry_value}"?(/*) ]] && [[ ${#entry_value} -gt ${#best_match} ]]; then
|
||||||
|
best_match="${entry_value}"
|
||||||
|
best_key="${entry_key}"
|
||||||
|
fi
|
||||||
|
@@ -91,7 +106,7 @@ __goto_test() {
|
||||||
|
# command: goto -t
|
||||||
|
|
||||||
|
local -A data
|
||||||
|
- __goto_load data
|
||||||
|
+ __goto_load_entries data
|
||||||
|
|
||||||
|
local entry_key entry_value
|
||||||
|
local -i ret_code=0
|
||||||
|
@@ -119,7 +134,7 @@ __goto_edit() {
|
||||||
|
# edits the goto configuration file
|
||||||
|
# command: goto -e
|
||||||
|
|
||||||
|
- nano ${__GOTO_FILE}
|
||||||
|
+ ${EDITOR:-nano} ${__GOTO_FILE}
|
||||||
|
}
|
||||||
|
|
||||||
|
__goto_list() {
|
||||||
|
@@ -127,7 +142,7 @@ __goto_list() {
|
||||||
|
# command: goto -l
|
||||||
|
|
||||||
|
local -A data
|
||||||
|
- __goto_load data
|
||||||
|
+ __goto_load_entries data
|
||||||
|
|
||||||
|
local -a sorted_keys
|
||||||
|
mapfile -d '' sorted_keys < <(printf '%s\0' "${!data[@]}" | sort -z)
|
||||||
|
@@ -146,16 +161,17 @@ __goto_add() {
|
||||||
|
# $1: directory alias and optional path
|
||||||
|
|
||||||
|
local dir_alias dir_path
|
||||||
|
+
|
||||||
|
IFS=':' read dir_alias dir_path <<< "$1"
|
||||||
|
|
||||||
|
if [[ -n "${dir_path}" ]]; then
|
||||||
|
- dir_path=$(__goto_resolve_path "${dir_path}")
|
||||||
|
+ dir_path="$(__goto_resolve_path "${dir_path}")"
|
||||||
|
else
|
||||||
|
dir_path="${PWD}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if __goto_exists; then
|
||||||
|
- dir_alias="${dir_alias}" dir_path="${dir_path}" ${__GOTO_YQ} -i '. | (.[env(dir_alias)] = env(dir_path))' ${__GOTO_FILE}
|
||||||
|
+ dir_alias="${dir_alias}" dir_path="${dir_path}" ${__GOTO_YQ} -i '.[env(dir_alias)] |= env(dir_path)' ${__GOTO_FILE}
|
||||||
|
else
|
||||||
|
dir_alias="${dir_alias}" dir_path="${dir_path}" ${__GOTO_YQ} '.[env(dir_alias)] = env(dir_path)' ${__GOTO_FILE}
|
||||||
|
fi
|
||||||
|
@@ -179,32 +195,35 @@ __goto_get() {
|
||||||
|
# $1: directory alias
|
||||||
|
|
||||||
|
if ! __goto_exists; then
|
||||||
|
- return 11
|
||||||
|
+ echo "goto: $1: configuration file not found" >&2
|
||||||
|
+ return 10
|
||||||
|
fi
|
||||||
|
|
||||||
|
- local dir_path="$(dir_alias="$1" ${__GOTO_YQ} '.[env(dir_alias)] // ""' ${__GOTO_FILE})"
|
||||||
|
+ local dir_path=$(dir_alias="$1" ${__GOTO_YQ} 'explode(.)[env(dir_alias)] // ""' ${__GOTO_FILE})
|
||||||
|
|
||||||
|
if [[ -z "${dir_path}" ]]; then
|
||||||
|
- return 10
|
||||||
|
+ echo "goto: $1: no such entry" >&2
|
||||||
|
+ return 11
|
||||||
|
fi
|
||||||
|
-
|
||||||
|
+
|
||||||
|
__goto_resolve_path "${dir_path}"
|
||||||
|
}
|
||||||
|
|
||||||
|
goto() {
|
||||||
|
# the goto command
|
||||||
|
|
||||||
|
- local OPTIND OPT
|
||||||
|
+ local can_run_main=true
|
||||||
|
+ local OPTIND OPT OPTARG
|
||||||
|
|
||||||
|
- while getopts 'a:r:g:elt' OPT; do
|
||||||
|
+ while getopts ':a:r:g:elt' OPT; do
|
||||||
|
case "${OPT}" in
|
||||||
|
a)
|
||||||
|
__goto_add "${OPTARG}"
|
||||||
|
- return
|
||||||
|
+ can_run_main=false
|
||||||
|
;;
|
||||||
|
r)
|
||||||
|
__goto_remove "${OPTARG}"
|
||||||
|
- return
|
||||||
|
+ can_run_main=false
|
||||||
|
;;
|
||||||
|
g)
|
||||||
|
__goto_get "${OPTARG}"
|
||||||
|
@@ -222,8 +241,12 @@ goto() {
|
||||||
|
__goto_test
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
+ :)
|
||||||
|
+ echo "goto: missing argument for option '${OPTARG}'" >&2
|
||||||
|
+ return 1
|
||||||
|
+ ;;
|
||||||
|
*)
|
||||||
|
- echo "goto: invalid option ${OPTARG}" >&2
|
||||||
|
+ echo "goto: invalid option '${OPTARG}'" >&2
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
@@ -236,25 +259,30 @@ goto() {
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- if (( $# == 0 )); then
|
||||||
|
- cd
|
||||||
|
+ if ! ${can_run_main}; then
|
||||||
|
+ if (( $# > 0 )); then
|
||||||
|
+ echo 'goto: too many arguments' >&2
|
||||||
|
+ return 1
|
||||||
|
+ fi
|
||||||
|
+
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
- if ! __goto_exists; then
|
||||||
|
- echo "goto: $1: configuration file not found" >&2
|
||||||
|
- return 3
|
||||||
|
+ if (( $# == 0 )); then
|
||||||
|
+ echo 'goto: not enough arguments' >&2
|
||||||
|
+ return
|
||||||
|
fi
|
||||||
|
|
||||||
|
- local dir_path="$(dir_alias="$1" ${__GOTO_YQ} '.[env(dir_alias)] // ""' ${__GOTO_FILE})"
|
||||||
|
+ local dir_path
|
||||||
|
+ dir_path=$(__goto_get "$1")
|
||||||
|
+ local -i ret_code=$?
|
||||||
|
|
||||||
|
- if [[ -z "${dir_path}" ]]; then
|
||||||
|
- echo "goto: $1: no such entry" >&2
|
||||||
|
- return 2
|
||||||
|
+ if (( ret_code != 0 )); then
|
||||||
|
+ return ${ret_code}
|
||||||
|
fi
|
||||||
|
|
||||||
|
- cd $(__goto_resolve_path "${dir_path}")
|
||||||
|
+ cd ${dir_path}
|
||||||
|
}
|
||||||
|
|
||||||
|
# complete -F __goto_completions goto
|
||||||
|
-source ${__GOTO_ROOT_DIR}/completion.bash
|
||||||
|
\ No newline at end of file
|
||||||
|
+source ${__GOTO_ROOT_DIR}/completion.bash
|
||||||
@@ -4,40 +4,84 @@ _comp_cmd_goto() {
|
|||||||
local cur prev words cword comp_args
|
local cur prev words cword comp_args
|
||||||
_comp_initialize -- "$@" || return
|
_comp_initialize -- "$@" || return
|
||||||
|
|
||||||
# echo "[$cur] [$prev] [${words[@]}] [$cword] [$comp_args]"
|
# the list of valid options with their argument requirement
|
||||||
|
# it is updated as the command is parsed
|
||||||
|
local -A valid_opts=([-a]=true [-r]=true [-g]=true [-e]=false [-l]=false [-t]=false)
|
||||||
|
# how many positional arguments are expected
|
||||||
|
local -i expected_positional_args=1
|
||||||
|
# optionals and positionals read up to, not including ${cword} (current word index)
|
||||||
|
local -i opt_args=0 positional_args=0
|
||||||
|
# holds an option that requires its argument to be read next
|
||||||
|
local expected_optarg
|
||||||
|
|
||||||
local -A opts=([-e]="" [-l]="" [-t]="")
|
local i word
|
||||||
|
for (( i = 1; i < cword; i++ )); do
|
||||||
|
word="${words[${i}]}"
|
||||||
|
|
||||||
local i
|
if [[ "${word:0:1}" == '-' ]]; then # reading an option
|
||||||
for i in "${!words[@]}"; do
|
|
||||||
[[ ${words[i]} && $i -ne $cword ]] && unset -v "opts[${words[i]}]"
|
# any option is invalid if...
|
||||||
case "${words[i]}" in
|
if \
|
||||||
-e)
|
(( positional_args > 0 )) || # a positional parameter has been specified \
|
||||||
unset -v 'opts[-l]' 'opts[-t]'
|
[[ -n "${expected_optarg}" ]] || # a previous option is expecting an argument \
|
||||||
;;
|
! [[ -v valid_opts["${word}"] ]] # the option is invalid given the previously provided ones \
|
||||||
-l)
|
then
|
||||||
unset -v 'opts[-e]' 'opts[-t]'
|
return
|
||||||
;;
|
fi
|
||||||
-t)
|
|
||||||
unset -v 'opts[-e]' 'opts[-l]'
|
local arg_required=${valid_opts["${word}"]}
|
||||||
;;
|
|
||||||
esac
|
case "${word:1}" in
|
||||||
|
a|r)
|
||||||
|
unset -v 'valid_opts[-g]' 'valid_opts[-e]' 'valid_opts[-l]' 'valid_opts[-t]'
|
||||||
|
;;
|
||||||
|
g|e|l|t)
|
||||||
|
valid_opts=()
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if ${arg_required}; then
|
||||||
|
expected_optarg="${word}"
|
||||||
|
else
|
||||||
|
expected_optarg=
|
||||||
|
fi
|
||||||
|
|
||||||
|
expected_positional_args=0
|
||||||
|
|
||||||
|
(( opt_args++ ))
|
||||||
|
elif [[ -n "${expected_optarg}" ]]; then
|
||||||
|
expected_optarg=
|
||||||
|
else
|
||||||
|
(( positional_args++ ))
|
||||||
|
|
||||||
|
if (( positional_args > expected_positional_args )); then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ $cur == -* ]]; then
|
if [[ "${cur:0:1}" == '-' ]]; then
|
||||||
_comp_compgen -- -W '"${!opts[@]}"'
|
if [[ -z "${expected_optarg}" ]] && (( positional_args == 0 )); then
|
||||||
|
_comp_compgen -- -W '"${!valid_opts[@]}"'
|
||||||
|
fi
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
case $prev in
|
if [[ "${prev:0:1}" == '-' ]]; then
|
||||||
-e)
|
case "${prev:1}" in
|
||||||
[[ -v 'opts[-e]' ]] && __goto_comp_keys
|
r|g)
|
||||||
return
|
__goto_comp_keys
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
# do goto keys only if we did not have -[elt]
|
if (( opt_args == 0 && positional_args == 0 )); then
|
||||||
[[ ${words[*]} == *\ -* ]] || __goto_comp_keys
|
__goto_comp_keys
|
||||||
|
fi
|
||||||
} &&
|
} &&
|
||||||
complete -F _comp_cmd_goto goto
|
complete -F _comp_cmd_goto goto
|
||||||
|
|
||||||
|
|||||||
90
goto.bash
90
goto.bash
@@ -6,14 +6,14 @@
|
|||||||
readonly __GOTO_ROOT_DIR=~/.goto
|
readonly __GOTO_ROOT_DIR=~/.goto
|
||||||
# goto configuration file that contains the directory mappings
|
# goto configuration file that contains the directory mappings
|
||||||
readonly __GOTO_FILE=${__GOTO_ROOT_DIR}/goto.yaml
|
readonly __GOTO_FILE=${__GOTO_ROOT_DIR}/goto.yaml
|
||||||
# path to yq executable
|
# path to yq executable used by goto
|
||||||
readonly __GOTO_YQ=/usr/local/bin/yq
|
readonly __GOTO_YQ=/usr/local/bin/yq
|
||||||
|
|
||||||
__goto_exists() {
|
__goto_exists() {
|
||||||
[[ -f ${__GOTO_FILE} ]]
|
[[ -f ${__GOTO_FILE} ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
__goto_load() {
|
__goto_load_entries() {
|
||||||
# load the directory mappings from the configuration file into the variable reference passed as parameter
|
# load the directory mappings from the configuration file into the variable reference passed as parameter
|
||||||
# $1: name of the result associative array to create
|
# $1: name of the result associative array to create
|
||||||
|
|
||||||
@@ -24,7 +24,8 @@ __goto_load() {
|
|||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local entries entry key value
|
local -a entries
|
||||||
|
local entry key value
|
||||||
|
|
||||||
mapfile entries < <(${__GOTO_YQ} 'explode(.) | to_entries[] | "\(.key) \(.value)"' ${__GOTO_FILE})
|
mapfile entries < <(${__GOTO_YQ} 'explode(.) | to_entries[] | "\(.key) \(.value)"' ${__GOTO_FILE})
|
||||||
|
|
||||||
@@ -43,13 +44,27 @@ __goto_load() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__goto_load_keys() {
|
||||||
|
# load the directory keys from the configuration file into the variable reference passed as parameter
|
||||||
|
# $1: name of the result array to create
|
||||||
|
|
||||||
|
local -n data_ref=$1
|
||||||
|
data_ref=()
|
||||||
|
|
||||||
|
if ! __goto_exists; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
mapfile data_ref < <(${__GOTO_YQ} 'keys[]' ${__GOTO_FILE})
|
||||||
|
}
|
||||||
|
|
||||||
__goto_comp_keys() {
|
__goto_comp_keys() {
|
||||||
# loads and initializes directory aliases completions for the goto command
|
# loads and initializes directory aliases completions for the goto command
|
||||||
|
|
||||||
local -A data
|
local -a data
|
||||||
__goto_load data
|
__goto_load_keys data
|
||||||
|
|
||||||
_comp_compgen -- -W '"${!data[@]}"'
|
_comp_compgen -- -W '"${data[@]}"'
|
||||||
}
|
}
|
||||||
|
|
||||||
__goto_resolve_path() {
|
__goto_resolve_path() {
|
||||||
@@ -63,7 +78,7 @@ __goto_prompt() {
|
|||||||
# prompt string for the terminal
|
# prompt string for the terminal
|
||||||
|
|
||||||
local -A data
|
local -A data
|
||||||
__goto_load data
|
__goto_load_entries data
|
||||||
|
|
||||||
local entry_key entry_value best_match="" best_key=""
|
local entry_key entry_value best_match="" best_key=""
|
||||||
|
|
||||||
@@ -71,7 +86,7 @@ __goto_prompt() {
|
|||||||
entry_value=$(__goto_resolve_path "${data[${entry_key}]}")
|
entry_value=$(__goto_resolve_path "${data[${entry_key}]}")
|
||||||
|
|
||||||
# select the closest ancestor of the current working directory
|
# select the closest ancestor of the current working directory
|
||||||
if [[ "${PWD}" == "${entry_value}"* ]] && [[ ${#entry_value} -gt ${#best_match} ]]; then
|
if [[ "${PWD}" == "${entry_value}"?(/*) ]] && [[ ${#entry_value} -gt ${#best_match} ]]; then
|
||||||
best_match="${entry_value}"
|
best_match="${entry_value}"
|
||||||
best_key="${entry_key}"
|
best_key="${entry_key}"
|
||||||
fi
|
fi
|
||||||
@@ -91,7 +106,7 @@ __goto_test() {
|
|||||||
# command: goto -t
|
# command: goto -t
|
||||||
|
|
||||||
local -A data
|
local -A data
|
||||||
__goto_load data
|
__goto_load_entries data
|
||||||
|
|
||||||
local entry_key entry_value
|
local entry_key entry_value
|
||||||
local -i ret_code=0
|
local -i ret_code=0
|
||||||
@@ -119,7 +134,7 @@ __goto_edit() {
|
|||||||
# edits the goto configuration file
|
# edits the goto configuration file
|
||||||
# command: goto -e
|
# command: goto -e
|
||||||
|
|
||||||
nano ${__GOTO_FILE}
|
${EDITOR:-nano} ${__GOTO_FILE}
|
||||||
}
|
}
|
||||||
|
|
||||||
__goto_list() {
|
__goto_list() {
|
||||||
@@ -127,7 +142,7 @@ __goto_list() {
|
|||||||
# command: goto -l
|
# command: goto -l
|
||||||
|
|
||||||
local -A data
|
local -A data
|
||||||
__goto_load data
|
__goto_load_entries data
|
||||||
|
|
||||||
local -a sorted_keys
|
local -a sorted_keys
|
||||||
mapfile -d '' sorted_keys < <(printf '%s\0' "${!data[@]}" | sort -z)
|
mapfile -d '' sorted_keys < <(printf '%s\0' "${!data[@]}" | sort -z)
|
||||||
@@ -146,16 +161,17 @@ __goto_add() {
|
|||||||
# $1: directory alias and optional path
|
# $1: directory alias and optional path
|
||||||
|
|
||||||
local dir_alias dir_path
|
local dir_alias dir_path
|
||||||
|
|
||||||
IFS=':' read dir_alias dir_path <<< "$1"
|
IFS=':' read dir_alias dir_path <<< "$1"
|
||||||
|
|
||||||
if [[ -n "${dir_path}" ]]; then
|
if [[ -n "${dir_path}" ]]; then
|
||||||
dir_path=$(__goto_resolve_path "${dir_path}")
|
dir_path="$(__goto_resolve_path "${dir_path}")"
|
||||||
else
|
else
|
||||||
dir_path="${PWD}"
|
dir_path="${PWD}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if __goto_exists; then
|
if __goto_exists; then
|
||||||
dir_alias="${dir_alias}" dir_path="${dir_path}" ${__GOTO_YQ} -i '. | (.[env(dir_alias)] = env(dir_path))' ${__GOTO_FILE}
|
dir_alias="${dir_alias}" dir_path="${dir_path}" ${__GOTO_YQ} -i '.[env(dir_alias)] |= env(dir_path)' ${__GOTO_FILE}
|
||||||
else
|
else
|
||||||
dir_alias="${dir_alias}" dir_path="${dir_path}" ${__GOTO_YQ} '.[env(dir_alias)] = env(dir_path)' ${__GOTO_FILE}
|
dir_alias="${dir_alias}" dir_path="${dir_path}" ${__GOTO_YQ} '.[env(dir_alias)] = env(dir_path)' ${__GOTO_FILE}
|
||||||
fi
|
fi
|
||||||
@@ -179,13 +195,15 @@ __goto_get() {
|
|||||||
# $1: directory alias
|
# $1: directory alias
|
||||||
|
|
||||||
if ! __goto_exists; then
|
if ! __goto_exists; then
|
||||||
return 11
|
echo "goto: $1: configuration file not found" >&2
|
||||||
|
return 10
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local dir_path="$(dir_alias="$1" ${__GOTO_YQ} '.[env(dir_alias)] // ""' ${__GOTO_FILE})"
|
local dir_path=$(dir_alias="$1" ${__GOTO_YQ} 'explode(.)[env(dir_alias)] // ""' ${__GOTO_FILE})
|
||||||
|
|
||||||
if [[ -z "${dir_path}" ]]; then
|
if [[ -z "${dir_path}" ]]; then
|
||||||
return 10
|
echo "goto: $1: no such entry" >&2
|
||||||
|
return 11
|
||||||
fi
|
fi
|
||||||
|
|
||||||
__goto_resolve_path "${dir_path}"
|
__goto_resolve_path "${dir_path}"
|
||||||
@@ -194,17 +212,18 @@ __goto_get() {
|
|||||||
goto() {
|
goto() {
|
||||||
# the goto command
|
# the goto command
|
||||||
|
|
||||||
local OPTIND OPT
|
local can_run_main=true
|
||||||
|
local OPTIND OPT OPTARG
|
||||||
|
|
||||||
while getopts 'a:r:g:elt' OPT; do
|
while getopts ':a:r:g:elt' OPT; do
|
||||||
case "${OPT}" in
|
case "${OPT}" in
|
||||||
a)
|
a)
|
||||||
__goto_add "${OPTARG}"
|
__goto_add "${OPTARG}"
|
||||||
return
|
can_run_main=false
|
||||||
;;
|
;;
|
||||||
r)
|
r)
|
||||||
__goto_remove "${OPTARG}"
|
__goto_remove "${OPTARG}"
|
||||||
return
|
can_run_main=false
|
||||||
;;
|
;;
|
||||||
g)
|
g)
|
||||||
__goto_get "${OPTARG}"
|
__goto_get "${OPTARG}"
|
||||||
@@ -222,8 +241,12 @@ goto() {
|
|||||||
__goto_test
|
__goto_test
|
||||||
return
|
return
|
||||||
;;
|
;;
|
||||||
|
:)
|
||||||
|
echo "goto: missing argument for option '${OPTARG}'" >&2
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
echo "goto: invalid option ${OPTARG}" >&2
|
echo "goto: invalid option '${OPTARG}'" >&2
|
||||||
return 1
|
return 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@@ -236,24 +259,29 @@ goto() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if (( $# == 0 )); then
|
if ! ${can_run_main}; then
|
||||||
cd
|
if (( $# > 0 )); then
|
||||||
|
echo 'goto: too many arguments' >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! __goto_exists; then
|
if (( $# == 0 )); then
|
||||||
echo "goto: $1: configuration file not found" >&2
|
echo 'goto: not enough arguments' >&2
|
||||||
return 3
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local dir_path="$(dir_alias="$1" ${__GOTO_YQ} '.[env(dir_alias)] // ""' ${__GOTO_FILE})"
|
local dir_path
|
||||||
|
dir_path=$(__goto_get "$1")
|
||||||
|
local -i ret_code=$?
|
||||||
|
|
||||||
if [[ -z "${dir_path}" ]]; then
|
if (( ret_code != 0 )); then
|
||||||
echo "goto: $1: no such entry" >&2
|
return ${ret_code}
|
||||||
return 2
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cd $(__goto_resolve_path "${dir_path}")
|
cd ${dir_path}
|
||||||
}
|
}
|
||||||
|
|
||||||
# complete -F __goto_completions goto
|
# complete -F __goto_completions goto
|
||||||
|
|||||||
Reference in New Issue
Block a user