├── Bash_auto-completion.bash ├── LICENSE ├── README.md ├── codes_in_.bashrc.bash └── codes_in_.zshrc.zsh /Bash_auto-completion.bash: -------------------------------------------------------------------------------- 1 | dircomp(){ 2 | shopt -s extglob 3 | local -n CWidx=COMP_CWORD words=COMP_WORDS 4 | local now=$2 pre=$3 5 | IFS=$'\n' 6 | if [[ $now = ../* ]] ;then 7 | COMPREPLY=( $(compgen -W '$(compgen -d ../)' $now) ) 8 | elif [[ $now =~ ^([^1-9]*/)?([1-9][0-9]?)(.*) ]] ;then 9 | f=${BASH_REMATCH[1]} 10 | n=${BASH_REMATCH[2]} 11 | b=${BASH_REMATCH[3]} 12 | if [[ $b ]] ;then 13 | [[ -e ${now%/*} ]] && 14 | COMPREPLY=( $(compgen -W "$(compgen -d ${now%/*})" -- "$now") ) 15 | else 16 | ((n<${#DIRSTACK[@]})) && 17 | COMPREPLY=( "$f${DIRSTACK[n]// /\\ }$b" $(compgen -d $f${DIRSTACK[n]}$b/) ) 18 | fi 19 | elif [[ $now ]] ;then 20 | COMPREPLY=( $(compgen -d "$now") ) 21 | else 22 | exec 3< <(dirs -l -p) 23 | compopt -o nosort 24 | COMPREPLY=( $(read -u3;while read -u3 d; F=$?;read w || ((!F)) ;do echo ${d// /\\ }${d:+/};echo ${w// /\\ }${w:+/} ;done< <(compgen -d) 25 | ((CWidx==1)) &&T=-c; compgen -d) ) 26 | exec 3>&- 27 | fi 28 | }; complete -o nospace -o plusdirs -o default -F dircomp g 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2023, abdulbadii 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bash smart directories navigation 2 | Go or get into a directory, keeping every previous directory saved, listed neatly right off on shell 3 | It must be inside ~/.bashrc to get the executable g (stand for get in) functioning, working directly, nicely and fast in shell terminal and no _DIRS and _DRS shell variable writing else 4 | Simply rename function name g with whatever you like; j, stand for jump into or b, stand for be in, etc 5 | 6 | # Usage 7 | Note on explanation below, each usage that means: *go to a directory* (i.e. not its removal from dir. stack, etc), the first step *save the current directory onto top of dir. stack* is implied before the first one explicitly written, except the `g 1` usage 8 | 9 | g 10 | go to $HOME dir. 11 | 12 | g - 13 | go back to the last dir. from where previously working directory, if top of the list was not just removed, simply it'd be it and will be identical to `g .` behavour 14 | 15 | g . 16 | go to directory on top of stack which is the first of dir. list (as opposed to g 1 below) 17 | 18 | g 1 19 | like above, go to directory pointed by top of list, but will not have current directory retained 20 | 21 | g , 22 | go to the last of dir. stack which has the greatest index 23 | 24 | g {nth} 25 | go to the nth index of dir. stack, exception is index 1 explained above, and 0 explained below 26 | 27 | g {directory} 28 | go to the "directory_name" dir. For numerical name, suffix it with / to prevail over existing same index number of dir. stack 29 | 30 | g foo \[bar baz ...\] 31 | 32 | g . | - | , \[foo bar baz ...\] 33 | 34 | likewise go to given directory namedly foo performing the first `g {directory}` usage, only now to be clearer that it may be in repetition form, withg all the rest put in dir. stack 35 | it may optionally be started with . or - or , options mentioned above which'd be accomplished first (the second form) 36 | 37 | g 0{nth} 0{nth} ... 38 | remove every given nth index of dir. stack 39 | 40 | g 0{nth}- 41 | remove the nth index and every dir. greater than it of dir. stack 42 | 43 | g 0{nth}-{Nth} 44 | remove every dir. index in the range nth to Nth index of dir. stack 45 | 46 | g -c 47 | clean up all dir. stack 48 | 49 | g -r 50 | reverse the dir. index order and go to the last of dir. stack 51 | 52 | g ,, 53 | refresh i.e. update the prompt string of dir. stack which is cleaned up from any duplicate and inexistant directory 54 | 55 | g [a g option/command] 0 56 | toggle hiding or showing the directory stack list ouput on the prompt string 57 | if an optional command given, execute it first before the toggling, if it is to hide it'd still lastly be shown the list after which it'd be hidden on the next command prompt 58 | so naturally, `g 0` is merely to toggle hide or show the directory stack list, not at all going into $HOME directory first 59 | 60 | g --[n] 61 | retrieve any directory path written within the last 49 (or a specified n number of) lines of command history, or if it's non directory then get its directory in which it is, so to push them repetitively in the way already described above i.e. the most recent one being the current directory 62 | 63 | g \ 64 | argument is any CLI with an executable whose argument(s) can be obtained from the dir. stack by which it is referenced 65 | on purpose of get more its various selection and navigation, append // to the argument. This won't make it immediately executed, instead it'd get into readline which will be ready to do what Bash command prompt will, e.g: modify argument path or string, making use of auto completion, etc 66 | 67 | ## This'd be the most useful feature which would be perfected with its auto completion capability by copying file Bash_auto-completion into ~/.bashrc 68 | -------------------------------------------------------------------------------- /codes_in_.bashrc.bash: -------------------------------------------------------------------------------- 1 | PS1='`echo -e "$DIRS"`\[\e[41;1;37m\]\w\[\e[40;1;33m\]\n\$\[\e[m\] ' 2 | g(){ 3 | local C DNO F D arg args d f b m n i o x 4 | exec 3>&1 5 | { 6 | [[ ${!#} = 0 ]] &&{ ((HIDIRF=1-HIDIRF));(($#>1)) &&set -- ${@:1:(($#-1))};} 7 | case $1 in 8 | 0[1-9]*-) n=${1%-}; while popd +$n ;do :;done;; 9 | 0[1-9]*-[1-9]*) m=${1%-*};n=${1#*-}; for((i=n-m;i>=0;--i)) ;{ popd +$m ;};; 10 | 0[1-9]*) i=;for n;{ [[ $n = 0[1-9]* ]] ||break; popd +$((n-i++)) ||break;};; 11 | 0)if ((HIDIRF)) ;then echo NOW DIRECTORY STACK LIST IS HIDDEN>&3;_DIRS= 12 | else _DIRS=$_DRS ;fi;return;; 13 | -c) dirs -c;_DIRS=; shift;(($#))&&m "$@";return;; 14 | --?([1-9]*)) n=${1#--} 15 | C=$PWD 16 | while read -r m 17 | do eval set -- $m 18 | for i;{ 19 | [[ $i =~ /?[a-z]+(/[a-z]+)* ]] &&{ 20 | [[ $i = /* ]] || i=$C/$i 21 | if [[ -d $i && $i != $C ]] ;then pushd -n "$i" 22 | else i=${i%/*}; [[ -d $i && $i != $C ]] &&pushd -n "$i" ;fi 23 | };} 24 | done< <(history $((${n:=49}+1))); pushd;; 25 | ,,);; 26 | -r) pushd;n=${#DIRSTACK[@]};for((i=2;i&3 2>&3 60 | elif (($#==1)) &&[[ $1 =~ ^[1-9][0-9]?(/)?$ ]] ;then 61 | if [[ ${BASH_REMATCH[1]} ]] ;then pushd $1 ||echo $1/ is not a directory>&3 62 | elif (($1==1)) ;then popd 63 | else 64 | m=;[[ -d $1 ]]&&{ 65 | m="Directory $1/ exists, to mean it instead, append character / on CLI: $1/\n" 66 | n="Into directory $1/ since no index $1 in directory list\n";} 67 | u=${DIRSTACK[$1]} 68 | if [[ $u ]] ;then pushd "$u";popd +$(($1+1)) 69 | elif [[ $m ]] ;then pushd $1;m=$n 70 | else m="No index $1 in directory list nor the directory $1/ exists\n";fi 71 | echo -en "$m">&3 72 | fi 73 | else 74 | F=;D=1; C=$PWD; i=$# 75 | if [[ $1 = [-.,] ]] ;then n= 76 | if [[ $1 = - ]] ;then n=-;elif [[ $1 = , ]] ;then n=-0;fi 77 | pushd $n;pushd +1 78 | else F=1;fi 79 | while n=${!i}; ((i--)) ;do 80 | n=${n%/} 81 | : ${n:=/} 82 | [[ $n != /* ]] && n="${C%/}/$n" 83 | [[ $n = $C ]] &&continue 84 | [[ -d $n ]] ||{ ((F || i )) &&{ 85 | echo "'$n' is not a directory" 86 | n=${n%/*} 87 | [[ ! -d $n ]] &&{ echo "Neither is '$n'";continue;} 88 | [[ $n = $C ]] &&continue 89 | 2>&3 read -N1 -t 2.5 -p "But under existing directory '$n', put it on stack? (n: No. ELSE/DEFAULT: Yes) " o && 90 | [[ $o = n ]] &&{ echo;continue;} 91 | echo 92 | }>&3 93 | } 94 | if ((i)) ;then pushd -n "$n" 95 | else 96 | if ((F)) ;then pushd "$n" ;else pushd -0 ;fi; D=;break 97 | fi 98 | done 99 | ((D&&!F)) &&pushd 100 | fi;; 101 | *) [[ $HOME = $PWD ]] ||pushd ~ 102 | esac 103 | IFS=$'\n' 104 | d=`dirs -l -p` 105 | d=$'\n'${d//$'\n'/$'\n\n'}$'\n' 106 | o= 107 | while : 108 | do set -- $d 109 | d=${d//$'\n'$1$'\n'} 110 | [[ $d ]] || break 111 | o="'$1' $o" 112 | done 113 | pushd "$1" 114 | dirs -c 115 | unset IFS C d 116 | eval set -- $o 117 | for o;{ pushd "$o" 2>&3 ||C="$C, '$o'";} 118 | }&>/dev/null 119 | exec 3>&- 120 | [[ $C ]]&&echo "Supposedly, but not being kept in dir. stack:${C#,}" 121 | { 122 | read l; while read l 123 | do [[ $l =~ ^([1-9][0-9]?)[[:space:]]+(.+) ]] 124 | d="$d\e[41;1;37m${BASH_REMATCH[1]}\e[40;1;32m${BASH_REMATCH[2]}\e[m " 125 | done 126 | }< <(dirs -v) 127 | _DRS=$(echo -e "${d:+${d% }\n\r}") 128 | _DIRS=$_DRS 129 | ((HIDIRF)) &&{ echo -n "${_DRS@P}"; _DIRS=;} 130 | } 131 | -------------------------------------------------------------------------------- /codes_in_.zshrc.zsh: -------------------------------------------------------------------------------- 1 | PS1="$_DRS%F{015}%K{001}%B%~%b$N%F{011}%K{004}%%%f%k " 2 | g(){ 3 | [[ ${@: -1} = 0 ]] &&{ ((HIDIRF=1-HIDIRF));((#>1)) &&set -- ${@:1:-1} } 4 | IFS=$'\n' 5 | d=(`dirs -pl`);DIRST=(${d:1}) 6 | { 7 | case $1 in 8 | 0[1-9]*-) n=${1%-}; while popd +$n;do :;done;; 9 | 0[1-9]*-[1-9]*) m=${1%-*};n=${1#*-}; for ((i=n-m;i>=0;--i)) ;{ popd -q +$m };; 10 | 0[1-9]*) i=;for n;{ [[ $n = 0[1-9]* ]] ||break; popd -q +$((n-i++)) ||break };; 11 | -c) dirs -c;PS1="%F{015}%K{001}%B%~%b$N%F{011}%K{004}%%%f%k ";return;; 12 | -r) for m in $DIRST ;{ pushd -q "$m"};; 13 | 0) if ((HIDIRF)) ;then echo NOW DIRECTORY STACK LIST IS HIDDEN 14 | PS1="%F{015}%K{001}%B%~%b$N%F{011}%K{004}%%%f%k " 15 | else PS1="$_DRS%F{015}%K{001}%B%~%b$N%F{011}%K{004}%%%f%k ";fi;return;; 16 | ,,);; 17 | ?*) 18 | if [[ `whence $1` && $1 != . && $2 ]] || ([[ $1 = . && -f $2 ]]) ;then 19 | F=1 20 | [[ -d $1 ]] &&{ 21 | echo "'$1' is a directory in the working dir. but it's a name of an executable too" 22 | read -k1 "?Is it meant as executable or directory name which should've had suffix / on CLI? (x / ELSE KEY) " o 23 | [[ $o = [xX] ]] ||{ pushd -q $1;F= }} 24 | ((F)) &&{ 25 | x=$1;shift 26 | args=;DNO= 27 | for m;{ 28 | if [[ $m != -* ]] || ((DNO)) && [[ $m =~ '^([^1-9]*/)?([1-9][0-9]*)(.*)' ]] ;then 29 | f=$match[1] 30 | n=$match[2] 31 | b=$match[3] 32 | if [[ $b =~ '^/$|^//[^/]' ]] ;then args=$args\ $f$n${b/\/\//\/} 33 | else 34 | if ((n<=$#DIRST)) ;then 35 | args=$args\ $f$DIRST[n]${b%/} 36 | [[ $b = *// ]] && vared -p $x args 37 | else echo "$n is out of range. Aborted. To mean it as literal name, append '/' on CLI: '$f$n/$b'";return 38 | fi 39 | fi 40 | else [[ $m = -- ]] &&DNO=1; args=$args\ $m;fi 41 | } 42 | echo -e "\e[1;37m$x$args\e[m" 43 | eval "$x$args" 44 | } 45 | elif unset match; [[ $1 =~ '^[1-9][0-9]?(/)?$' ]] &&(($#==1)) ;then 46 | if [[ $match[1] ]] ;then pushd -q $1 ||echo $1 is not a directory 47 | elif (($1==1)) ;then popd -q 48 | else 49 | m=;[[ -d $1 ]]&&{ 50 | m="Directory $1/ exists, if it's meant instead, append character '/' on CLI: m $1/\n" 51 | n="Into directory $1/, since no index $1 in directory list" 52 | } 53 | u=$DIRST[$1] 54 | if [[ $u ]] ;then pushd -q "$u";popd -q +$(($1+1)) 55 | elif [[ $m ]] ;then pushd -q $1;m=$n 56 | else m="No index $1 in directory list nor the directory $1/ exists";fi 57 | echo "$m" 58 | fi 59 | else 60 | F=;D=1;C=$PWD; i=$# 61 | if [[ $1 = [-.,] ]] ;then n= 62 | if [[ $1 = - ]] ;then n=- 63 | elif [[ $1 = , ]] ;then n=-0;fi 64 | pushd -q $n 65 | pushd -q +1 66 | else F=1 ;fi 67 | pushd -q +1 68 | while n=${(P)i}; ((i--)) ;do 69 | n=${n%/} 70 | : ${n:=/} 71 | [[ $n != /* ]] && n="${C%/}/$n" 72 | [[ $n = $C ]] &&continue 73 | [[ -d $n ]] ||{ ((F || i )) &&{ 74 | echo "'$n' is not a directory" 75 | n=${n%/*} 76 | [[ -d $n ]] ||{ echo "Neither is '$n'";continue;} 77 | [[ $n = $C ]] &&continue 78 | read -k1 -t 2.5 "?But written under existing directory '$n', put it on stack? (n: No. ELSE KEY: Yes) " o;echo 79 | [[ $o = [nN] ]] &&continue 80 | } 81 | } 82 | if (( i )) ;then pushd -q "$n" 83 | else 84 | pushd -q -0 85 | if ((F)) ;then pushd -q "$n" ;else pushd -q -0 ;fi 86 | D=;break 87 | fi 88 | done 89 | ((D)) &&{ pushd -q -0;pushd -q } 90 | fi;; 91 | *) [[ $HOME = $PWD ]] ||pushd -q ~ 92 | esac 93 | l=`dirs -pl` 94 | l=$'\n'${l//$'\n'/$'\n\n'}$'\n' 95 | o= 96 | while : 97 | do set -- $=l 98 | l=${l//$'\n'$1$'\n'} 99 | [[ $l ]] || break 100 | o="'$1' $o" 101 | done 102 | pushd -q $1 103 | dirs -c 104 | eval set -- $=o 105 | } 2>/dev/null 106 | C=;for o;{ pushd -q "$o" ||C="$C, '$o'" } 107 | [[ $C ]]&&echo "Supposedly, but not being kept in dir. stack:${C/,/}" 108 | { 109 | read l 110 | d=;while read l 111 | do [[ $l =~ "^([1-9]+)\h+(.+)" ]] 112 | d="$d%F{015}%K{001}${match[1]}%F{010}%K{000}${match[2]}%f%k " 113 | done 114 | }< <(dirs -v) 115 | N=$'\n' 116 | _DRS=${d:+${d% }$N} 117 | if ((HIDIRF)) ;then echo ${(%%)d} 118 | PS1="%F{015}%K{001}%B%~%b$N%F{011}%K{004}%%%f%k " 119 | else PS1="$_DRS%F{015}%K{001}%B%~%b$N%F{011}%K{004}%%%f%k " 120 | fi 121 | } 122 | --------------------------------------------------------------------------------