This commit is contained in:
ge 2022-10-05 23:27:24 +03:00
parent 1eed56422a
commit 19860fe8db
2 changed files with 109 additions and 104 deletions

85
README
View File

@ -1,31 +1,23 @@
********
G (GOTO)
********
A faster way to cd to commonly used directories. Inspired by commacd. Tested on
Bash 5.1, but should work on most versions.
Bash and Dash.
Installation
************
============
On most operatin systems with Bash run::
$ curl -o ~/.goto.sh \
-sSL https://gitea.gch.icu/ge/goto/raw/branch/master/goto.sh
$ echo '[ -f ~/.goto.sh ] && . ~/.goto.sh' >> ~/.bashrc
Reread ~/.bashrc by command::
On most operatin systems with Bash run:
$ curl -o ~/.g.sh -sSL https://git.nxhs.cloud/ge/g/raw/branch/master/g.sh
$ echo '[ -f ~/.g.sh ] && . ~/.g.sh' >> ~/.bashrc
$ source ~/.bashrc
Usage
*****
=====
Available commands (actually is aliases to functions)::
Available commands (actually is aliases to functions):
g [<pattern>] goto directory. If you have single bookmark dir will be
changed without prompt. Type dir number in prompt to cd.
g-save [<path>] bookmark $PWD or <path> (save into ~/.goto_saved).
g_save [<path>] bookmark $PWD or <path> (save into ~/.g).
Run `g` to show the entire list of bookmarks and select the one you need.
@ -34,10 +26,10 @@ the bookmark number. The exception is when you have a two-digit number (or more)
and you select a bookmark whose number is less than 10. Then you have to press
`Enter`.
You can pass the Perl regular expression (processed by grep -Pi) as an for 'g'.
You can pass the Perl regular expression (processed by grep -Pi) as an for `g`.
At the same time, if only one bookmark is found, then the directory will be
changed directly to it. If there are several bookmarks, you will be prompted to
choose the appropriate one. Also you can use autocompletion by pressing `Tab`.
choose the appropriate one. Also you can use autocompletion by pressing Tab.
It works in a similar way.
Examples
@ -45,60 +37,65 @@ Examples
Previously set up your commonly used dirs. Specify dir as argument::
$ g-save ~/Documents
$ g-save ~/Downloads
$ g_save ~/Documents
$ g_save ~/Downloads
or cd into dir and simply run::
$ g-save
$ g_save
Go to directory by number::
Go to directory by number:
$ g
0 ~/Documents/
1 ~/Downloads/
: <type number here, e.g. 1>
=> cd /home/user/Downloads
=> cd /home/ge/Downloads
Goto '~/Downloads' directory by regex::
Goto '~/Downloads' directory by regex:
$ g w
=> cd /home/user/Downloads
=> cd /home/ge/Downloads
Another way :)::
Another way:
$ g 'do[^c]'
=> cd /home/gd/Downloads
=> cd /home/ge/Downloads
and etc.
Changelog
*********
=========
06 Feb 2022
- `~/.gotosave` renamed to `~/.goto_saved`
- Alias `s` changed to `g-save`
v0.3 (05 Oct 2022)
07 Jan 2022
Initial release.
* Refactored, added POSIX-compatibility
* Script renamed to `g.sh`
* ~/.goto_saved renamed to ~/.g
* Alias `g-save` changed to `g_save`
* Functions renamed
v0.2 (06 Feb 2022)
* ~/.gotosave renamed to ~/.goto_saved
* Alias `s` changed to `g-save`
v0.1 (07 Jan 2022)
Initial release.
Tips
****
====
Combining `commacd`, `g` and Bash ``autocd`` option gives a great experience!
Add to you ~/.bashrc following line::
shopt -s autocd
Now you can type just directory name without 'cd' to change directory.
Combining `commacd`, `g` and Bash ``shopt -s autocd`` option gives a great
experience!
Get `commacd` here: https://github.com/shyiko/commacd
Alternatives?
*************
=============
Some `g` alternatives:
- aliases (yep, Bash builtin aliases)
- https://github.com/huyng/bashmarks
* aliases (yep, Bash builtin aliases)
* https://github.com/huyng/bashmarks

View File

@ -1,5 +1,5 @@
# * g (goto directory) - bookmark directories in Bash.
# * versuion: 0.2
# * g (goto directory) - bookmark directories in shell.
# * version: 0.3
# This is free and unencumbered software released into the public domain.
#
@ -26,52 +26,63 @@
#
# For more information, please refer to <http://unlicense.org/>
_goto_cd() {
##### cd into directory #####
_g_file=~/.g
_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
if [ ! -d "$1" ]; then
echo "goto: no such directory $1" >&2
printf 'g: no such directory %s\n' "$1" >&2
return 1
fi
if cd -- "$1" > /dev/null; then
echo "$1"
else
echo -e "\bgoto: cannot cd into $1" >&2
printf '\bg: cannot cd into %s\n' "$1" >&2
fi
return "$?"
}
_goto_prompt() {
##### Prompt and cd #####
_g_prompt() {
# Prompt and cd
# Exit if no dirs in ~/.goto_saved
if [ "${#dirs[@]}" -eq 0 ] || [[ "${dirs[@]}" == '' ]]; then
# Exit if no dirs in $_g_file
if [ "$#" -eq 0 ] || [ "$*" = '' ]; then
echo goto: nothing to do; return 1
fi
# cd into dir without prompt if you have single directory
# in ~/.goto_saved
if [ "${#dirs[@]}" -eq 1 ]; then
_goto_cd "${dirs[@]}" && return 0
# in $_g_file
if [ "$(echo "$*" | wc -l)" -eq 1 ]; then
_g_cd "$*" && return 0
fi
# Print directory list
for i in "${!dirs[@]}"; do
echo -e "$i\t${dirs[$i]%%+(/)}/" | sed "s%${HOME}%~%"
i=0
echo "$*" | while read -r dir; do
dir="$(echo "$dir" | sed "s%$HOME%~%")"
printf '%s\t%s\n' "$i" "$dir"
i=$((i+1))
done
# Count digits in number of dirs for 'read'
local dirscount="$((${#dirs[@]}-1))"
local numlen="${#dirscount}"
# Read input to 'num' and set 'target' directory
read -r -n "$numlen" -p ': ' num
if [[ "$num" =~ [0-9]+ ]]; then
target="${dirs[$num]}";
# 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}')"
# Print new line to prevent line concatenation
[ "${#num}" -eq "$numlen" ] && echo
elif [[ "$num" == '' ]]; then
[ "${#_num}" -eq "$num_len" ] && echo
elif [ "$_num" = '' ]; then
return 1 # Just exit if you press Enter.
else
# Print new line and exit if printable chars passed.
@ -80,63 +91,60 @@ _goto_prompt() {
fi
# cd into directory
_goto_cd "$target"
_g_cd "$_target_dir"
}
_goto_search() {
grep -iP "$1" ~/.goto_saved
_g_search() {
grep -iP "$1" "$_g_file"
}
_goto() {
##### Main function #####
_g() {
# Main function
# Get directory list ('dirs' array)
dirs=()
if [ -f ~/.goto_saved ]; then
if [ -f "$_g_file" ]; then
if [ "$1" ]; then
# Search dirs with Perl regex
_source="$(_goto_search "$1")"
_dirs="$(_g_search "$1")"
else
# Load all directories
_source="$(<~/.goto_saved)"
_dirs="$(cat "$_g_file")"
fi
while read -r dir; do
dirs+=("$dir")
done <<< "$_source"
fi
_goto_prompt # prompt and cd
_g_prompt "$_dirs" # prompt and cd
}
_goto_save() {
##### Save PWD or 1 to ~/.goto_saved file #####
_g_save() {
# Save dir in $_g_file
local dir
if [ "$1" ]; then
dir="$1"
if [ -n "$1" ]; then
_dir="$1"
else
dir="$PWD"
_dir="$PWD"
fi
# Exit if directory is already in ~/.goto_saved
if grep "^${dir%%+(/)}\$" ~/.goto_saved > /dev/null; then
# Exit if directory is already in $_g_file
if grep "^${_dir%%+(/)}\$" "$_g_file" >/dev/null 2>&1; then
return 1
fi
# Save directory
if echo "${dir%%+(/)}" >> ~/.goto_saved; then
echo "$dir"
if echo "${_dir%%+(/)}" >> "$_g_file"; then
echo "$_dir"
fi
}
_goto_complete() {
# Autocomplete directory by pattern
local pattern=${COMP_WORDS[COMP_CWORD]}
local IFS=$'\n'
COMPREPLY=($(compgen -W "$(printf "%s\n" "$(_goto_search "$pattern")")" -- ''))
}
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
complete -F _goto_complete g
alias g='_goto'
alias g-save='_goto_save'
alias g='_g'
alias g_save='_g_save'