g/g.sh

151 lines
4.0 KiB
Bash
Raw Normal View History

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'