2022-10-05 23:27:24 +03:00
|
|
|
# * g (goto directory) - bookmark directories in shell.
|
|
|
|
# * version: 0.3
|
2022-01-07 20:10:17 +03:00
|
|
|
|
|
|
|
# This is free and unencumbered software released into the public domain.
|
|
|
|
#
|
|
|
|
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
|
|
# distribute this software, either in source code form or as a compiled
|
|
|
|
# binary, for any purpose, commercial or non-commercial, and by any
|
|
|
|
# means.
|
|
|
|
#
|
|
|
|
# In jurisdictions that recognize copyright laws, the author or authors
|
|
|
|
# of this software dedicate any and all copyright interest in the
|
|
|
|
# software to the public domain. We make this dedication for the benefit
|
|
|
|
# of the public at large and to the detriment of our heirs and
|
|
|
|
# successors. We intend this dedication to be an overt act of
|
|
|
|
# relinquishment in perpetuity of all present and future rights to this
|
|
|
|
# software under copyright law.
|
|
|
|
#
|
|
|
|
# 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 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.
|
|
|
|
#
|
|
|
|
# For more information, please refer to <http://unlicense.org/>
|
|
|
|
|
2022-10-05 23:27:24 +03:00
|
|
|
_g_file=~/.g
|
2022-01-07 20:10:17 +03:00
|
|
|
|
2022-10-05 23:27:24 +03:00
|
|
|
_read_char() {
|
|
|
|
# Read number of chars into variable
|
|
|
|
# Usage: _read_char VAR NUM
|
|
|
|
stty -icanon
|
|
|
|
eval "$1=\$(dd bs=1 count="$2" 2>/dev/null)"
|
|
|
|
stty icanon echo
|
|
|
|
}
|
|
|
|
|
|
|
|
_g_cd() {
|
|
|
|
# cd into directory
|
2022-01-07 20:10:17 +03:00
|
|
|
if [ ! -d "$1" ]; then
|
2022-10-05 23:27:24 +03:00
|
|
|
printf 'g: no such directory %s\n' "$1" >&2
|
2022-01-07 20:10:17 +03:00
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
if cd -- "$1" > /dev/null; then
|
|
|
|
echo "$1"
|
|
|
|
else
|
2022-10-05 23:27:24 +03:00
|
|
|
printf '\bg: cannot cd into %s\n' "$1" >&2
|
2022-01-07 20:10:17 +03:00
|
|
|
fi
|
|
|
|
return "$?"
|
|
|
|
}
|
|
|
|
|
2022-10-05 23:27:24 +03:00
|
|
|
_g_prompt() {
|
|
|
|
# Prompt and cd
|
2022-01-07 20:10:17 +03:00
|
|
|
|
2022-10-05 23:27:24 +03:00
|
|
|
# Exit if no dirs in $_g_file
|
|
|
|
if [ "$#" -eq 0 ] || [ "$*" = '' ]; then
|
2022-01-07 20:10:17 +03:00
|
|
|
echo goto: nothing to do; return 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
# cd into dir without prompt if you have single directory
|
2022-10-05 23:27:24 +03:00
|
|
|
# in $_g_file
|
|
|
|
if [ "$(echo "$*" | wc -l)" -eq 1 ]; then
|
|
|
|
_g_cd "$*" && return 0
|
2022-01-07 20:10:17 +03:00
|
|
|
fi
|
|
|
|
|
|
|
|
# Print directory list
|
2022-10-05 23:27:24 +03:00
|
|
|
i=0
|
|
|
|
echo "$*" | while read -r dir; do
|
|
|
|
dir="$(echo "$dir" | sed "s%$HOME%~%")"
|
|
|
|
printf '%s\t%s\n' "$i" "$dir"
|
|
|
|
i=$((i+1))
|
2022-01-07 20:10:17 +03:00
|
|
|
done
|
|
|
|
|
2022-10-05 23:27:24 +03:00
|
|
|
# Input target dir number
|
|
|
|
dirs_num="$(echo "$*" | wc -l)"
|
|
|
|
num_len="${#dirs_num}"
|
|
|
|
printf '%s' ": "
|
|
|
|
_read_char _num "$num_len"
|
|
|
|
if echo "$_num" | grep -E '[0-9]+' >/dev/null; then
|
|
|
|
_target_dir="$(echo "$*" |
|
|
|
|
awk -v line="$((_num+1))" 'NR==line {print}')"
|
2022-01-07 20:10:17 +03:00
|
|
|
# Print new line to prevent line concatenation
|
2022-10-05 23:27:24 +03:00
|
|
|
[ "${#_num}" -eq "$num_len" ] && echo
|
|
|
|
elif [ "$_num" = '' ]; then
|
2022-01-07 20:10:17 +03:00
|
|
|
return 1 # Just exit if you press Enter.
|
|
|
|
else
|
|
|
|
# Print new line and exit if printable chars passed.
|
|
|
|
# E.g. new line will be printed if you type 'q'.
|
|
|
|
echo; return 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
# cd into directory
|
2022-10-05 23:27:24 +03:00
|
|
|
_g_cd "$_target_dir"
|
2022-01-07 20:10:17 +03:00
|
|
|
}
|
|
|
|
|
2022-10-05 23:27:24 +03:00
|
|
|
_g_search() {
|
|
|
|
grep -iP "$1" "$_g_file"
|
2022-01-07 20:10:17 +03:00
|
|
|
}
|
|
|
|
|
2022-10-05 23:27:24 +03:00
|
|
|
_g() {
|
|
|
|
# Main function
|
2022-01-07 20:10:17 +03:00
|
|
|
# Get directory list ('dirs' array)
|
2022-10-05 23:27:24 +03:00
|
|
|
if [ -f "$_g_file" ]; then
|
2022-01-07 20:10:17 +03:00
|
|
|
if [ "$1" ]; then
|
|
|
|
# Search dirs with Perl regex
|
2022-10-05 23:27:24 +03:00
|
|
|
_dirs="$(_g_search "$1")"
|
2022-01-07 20:10:17 +03:00
|
|
|
else
|
|
|
|
# Load all directories
|
2022-10-05 23:27:24 +03:00
|
|
|
_dirs="$(cat "$_g_file")"
|
2022-01-07 20:10:17 +03:00
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
2022-10-05 23:27:24 +03:00
|
|
|
_g_prompt "$_dirs" # prompt and cd
|
2022-01-07 20:10:17 +03:00
|
|
|
}
|
|
|
|
|
2022-10-05 23:27:24 +03:00
|
|
|
_g_save() {
|
|
|
|
# Save dir in $_g_file
|
2022-01-07 20:10:17 +03:00
|
|
|
|
2022-10-05 23:27:24 +03:00
|
|
|
if [ -n "$1" ]; then
|
|
|
|
_dir="$1"
|
2022-01-07 20:10:17 +03:00
|
|
|
else
|
2022-10-05 23:27:24 +03:00
|
|
|
_dir="$PWD"
|
2022-01-07 20:10:17 +03:00
|
|
|
fi
|
|
|
|
|
2022-10-05 23:27:24 +03:00
|
|
|
# Exit if directory is already in $_g_file
|
|
|
|
if grep "^${_dir%%+(/)}\$" "$_g_file" >/dev/null 2>&1; then
|
2022-01-07 20:10:17 +03:00
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Save directory
|
2022-10-05 23:27:24 +03:00
|
|
|
if echo "${_dir%%+(/)}" >> "$_g_file"; then
|
|
|
|
echo "$_dir"
|
2022-01-07 20:10:17 +03:00
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2022-10-05 23:27:24 +03:00
|
|
|
if type complete >/dev/null 2>&1; then
|
|
|
|
# Bash completion
|
|
|
|
_g_complete_bash() {
|
|
|
|
_pattern=${COMP_WORDS[COMP_CWORD]}
|
|
|
|
COMPREPLY=($(compgen -W \
|
|
|
|
"$(printf "%s\n" "$(_g_search "$_pattern")")" -- ''))
|
|
|
|
}
|
|
|
|
complete -F _g_complete_bash g
|
|
|
|
else
|
|
|
|
:
|
|
|
|
fi
|
|
|
|
|
|
|
|
alias g='_g'
|
|
|
|
alias g_save='_g_save'
|