├── .editorconfig ├── .travis.yml ├── CHANGELOG.md ├── Makefile ├── README.md ├── commacd.sh └── shpec └── commacd_shpec.sh /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [Makefile] 12 | indent_size = 4 13 | indent_style = tab 14 | 15 | [*.md] 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # https://docs.travis-ci.com/user/languages/minimal-and-generic/ 2 | language: generic 3 | install: 4 | - curl -sSL https://raw.github.com/rylnd/shpec/0.3.1/bin/shpec -o shpec.sh && chmod a+x shpec.sh && sudo mv shpec.sh /usr/local/bin/shpec 5 | - curl -sSL https://storage.googleapis.com/shellcheck/shellcheck-v0.6.0.linux-x86_64 -o shellcheck && chmod a+x shellcheck && sudo mv shellcheck /usr/local/bin/ 6 | script: make 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 5 | and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). 6 | 7 | ## [1.0.0] - 2019-02-03 8 | 9 | ### Added 10 | - ZSH support ([#16](https://github.com/shyiko/commacd/pull/16)). 11 | - `COMMACD_MARKER` env variable to control exit condition for `,,` 12 | (by default `,,` stops when it finds parent dir with `.git/`, `.hg/` or `.svn/`) 13 | 14 | ``` 15 | $ tree -A ~ 16 | |- a 17 | |- b 18 | |- c 19 | |- projects # ,, should stop here (contains .git/) 20 | |- .commacdroot 21 | |- project_a # and here (contains .commacdroot) 22 | |- .git 23 | |- x 24 | |- y 25 | |- z # workdir 26 | 27 | $ export COMMACD_MARKER=".git/ .hg/ .svn/ .commacdroot" 28 | 29 | ~/a/b/c/projects/project_a/x/y/z$ ,, 30 | => cd ~/a/b/c/projects/project_a 31 | 32 | ~/a/b/c/projects/project_a$ ,, 33 | => cd ~/a/b/c/projects 34 | ``` 35 | 36 | ### Changed 37 | - Default `COMMACD_CD` to print `commacd: no matches found` & exit with code 1 when there is no match. 38 | 39 | ## [0.4.0] - 2018-01-13 40 | 41 | ### Added 42 | - Selection without Enter (when number of options is less than 10) (to enable `export COMMACD_IMPLICITENTER="on"`) ([#15](https://github.com/shyiko/commacd/issues/15)). 43 | 44 | ## [0.3.4] - 2018-01-05 45 | 46 | ### Fixed 47 | - Error message is printed when `failglob` shell option is set and no matches are found ([#13](https://github.com/shyiko/commacd/pull/13)). 48 | 49 | ## [0.3.3] - 2017-10-07 50 | 51 | ### Fixed 52 | - Terminal in inconsistent state after interrupt signal (`^C`) ([#12](https://github.com/shyiko/commacd/issues/12)). 53 | 54 | ## [0.3.2] - 2016-05-29 55 | 56 | ### Fixed 57 | - COMMACD_CD handling [#10](https://github.com/shyiko/commacd/issues/10) (thanks to [@chilicuil](https://github.com/chilicuil)). 58 | 59 | ## [0.3.1] - 2015-08-29 60 | 61 | ### Fixed 62 | - VCS root lookup (`,,`) in case of nested checkouts (`/.../checkout_1/.../checkout_2`). 63 | 64 | ## [0.3.0] - 2015-07-14 65 | 66 | ### Added 67 | - A way to change enumeration of "multiple choices" to start from 1 (instead of default 0) (use `export COMMACD_SEQSTART=1` to activate) (thanks to [@skorochkin](https://github.com/skorochkin)). 68 | 69 | ## [0.2.1] - 2014-11-08 70 | 71 | ## Fixed 72 | - Order of `,,`'s prefix/substring matching. 73 | 74 | ## [0.2.0] - 2014-11-07 75 | 76 | ## Added 77 | - Substring (fuzzy) matching as a fallback to the default prefix lookup (can be turned off with `export COMMACD_NOFUZZYFALLBACK="on"`). 78 | 79 | ## 0.1.0 - 2014-11-07 80 | 81 | [1.0.0]: https://github.com/shyiko/commacd/compare/v0.4.0...v1.0.0 82 | [0.4.0]: https://github.com/shyiko/commacd/compare/v0.3.4...v0.4.0 83 | [0.3.4]: https://github.com/shyiko/commacd/compare/v0.3.3...v0.3.4 84 | [0.3.3]: https://github.com/shyiko/commacd/compare/v0.3.2...v0.3.3 85 | [0.3.2]: https://github.com/shyiko/commacd/compare/v0.3.1...v0.3.2 86 | [0.3.1]: https://github.com/shyiko/commacd/compare/v0.3.0...v0.3.1 87 | [0.3.0]: https://github.com/shyiko/commacd/compare/v0.2.1...v0.3.0 88 | [0.2.1]: https://github.com/shyiko/commacd/compare/v0.2.0...v0.2.1 89 | [0.2.0]: https://github.com/shyiko/commacd/compare/v0.1.0...v0.2.0 90 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: lint test 2 | 3 | lint: 4 | test -s `which shellcheck` || { echo "shellcheck (https://github.com/koalaman/shellcheck) wasn't found on the PATH. Please install it and try again."; exit 1; } 5 | shellcheck -s bash -e SC1117,SC2206,SC2207,SC2128,SC2162,SC2178 -f gcc commacd.sh 6 | 7 | test: 8 | test -s `which shpec` || { echo "shpec (https://github.com/rylnd/shpec) wasn't found on the PATH. Please install it and try again"; exit 1; } 9 | bash -i -c "shpec" 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # commacd [![Build Status](https://travis-ci.org/shyiko/commacd.svg)](https://travis-ci.org/shyiko/commacd) 2 | 3 | A faster way to move around (Bash 3+/Zsh). 4 | 5 | > `commacd` is NOT an [autojump](https://github.com/joelthelion/autojump)/[z](https://github.com/rupa/z)/[fasd](https://github.com/clvv/fasd) alternative nor they are mutually exclusive. Think of it as an improved `cd`. 6 | 7 | ## Installation 8 | 9 | #### Bash 10 | 11 | ```sh 12 | curl -sSL https://github.com/shyiko/commacd/raw/v1.0.0/commacd.sh -o ~/.commacd.sh && \ 13 | echo "source ~/.commacd.sh" >> ~/.bashrc 14 | ``` 15 | 16 | > macOS users: make sure [~/.bashrc is sourced from ~/.bash_profile](http://ss64.com/osx/syntax-bashrc.html). 17 | 18 | #### Zsh 19 | 20 | ```sh 21 | curl -sSL https://github.com/shyiko/commacd/raw/v1.0.0/commacd.sh -o ~/.commacd.sh && \ 22 | echo "source ~/.commacd.sh" >> ~/.zshrc 23 | ``` 24 | 25 | ## Upgrading to the latest version 26 | 27 | ```sh 28 | curl -sSL https://github.com/shyiko/commacd/raw/v1.0.0/commacd.sh -o ~/.commacd.sh 29 | ``` 30 | 31 | ## Usage 32 | 33 | `commacd` exports three commands: `,` (for jumping forward), `,,` (backward) and `,,,` (backward+forward): 34 | 35 | ```sh 36 | ~$ , des 37 | => cd Desktop 38 | 39 | # move through multiple directories 40 | ~$ , /u/l/ce 41 | => cd /usr/local/Cellar 42 | 43 | # allow me to choose directory in case of ambiguous pattern (= multiple choices) 44 | ~$ , d 45 | => 1 Desktop 46 | 2 Downloads 47 | : 48 | 49 | # given two directories jdk7 and jdk8 on the Desktop, cd into jdk8 without hitting 50 | # interactive mode (the one shown above) 51 | ~/github$ , ~/d/j*8 52 | => cd ~/Desktop/jdk8 53 | 54 | # cd into directory having 'esk' somewhere in its name 55 | ~/github$ , ~/esk # in pre-0.2.0 that would be `, ~/*esk` 56 | => cd ~/Desktop 57 | 58 | # go all the way up to the project root (in this case, the one that has .git in it) 59 | ~/github/lorem/src/public$ ,, 60 | => cd ~/github/lorem 61 | 62 | # cd into to the first (closest) parent directory named g* 63 | ~/github/vimium/src/public$ ,, g 64 | => cd ~/github 65 | 66 | # substitute jekyll with ghost 67 | ~/github/jekyll/test$ ,, jekyll ghost 68 | => cd ~/github/ghost/test 69 | 70 | # jump to some other project (in this case, located in ~/github) 71 | ~/github/rook/src/public$ ,,, binlog # in pre-0.2.0 you would need to use `m*binlog` 72 | => cd ~/github/mysql-binlog-connector-java 73 | ``` 74 | 75 | As a bonus, all three aliases support `` expansion (try `, /u/lo`) and can be combined with other tools (e.g. ``ls `, /u/lo` ``). 76 | 77 | For more information, please refer to http://shyiko.com/2014/10/10/commacd/. 78 | 79 | ## Development 80 | 81 | ```sh 82 | make # lint & test 83 | ``` 84 | 85 | ## License 86 | 87 | [MIT License](http://opensource.org/licenses/mit-license.php) 88 | 89 | -------------------------------------------------------------------------------- /commacd.sh: -------------------------------------------------------------------------------- 1 | # commacd - a faster way to move around (Bash 3+/Zsh). 2 | # https://github.com/shyiko/commacd 3 | # 4 | # ENV variables that can be used to control commacd: 5 | # COMMACD_CD - function to change the directory 6 | # (by default 'builtin cd "$1" && pwd' is used) 7 | # COMMACD_NOTTY - set it to "on" when you want to suppress user input 8 | # (print multiple matches and exit) 9 | # COMMACD_NOFUZZYFALLBACK - set it to "on" if you don't want commacd to use 10 | # "fuzzy matching" as a fallback for "no matches by prefix" 11 | # (introduced in 0.2.0) 12 | # COMMACD_SEQSTART - set it to 1 if you want "multiple choices" to start 13 | # from 1 instead of 0 14 | # (introduced in 0.3.0) 15 | # COMMACD_IMPLICITENTER - set it to "on" to avoid pressing when 16 | # number of options (to select from) is less than 10 17 | # (introduced in 0.4.0) 18 | # COMMACD_MARKER - space-separated project root "marker"s (for ,, to stop at) 19 | # (".git/ .hg/ .svn/" by default) 20 | # (introduced in 1.0.0) 21 | # 22 | # @version 1.0.0 23 | # @author Stanley Shyiko 24 | # @license MIT 25 | 26 | # turn on case-insensitive search by default 27 | 28 | if [ -n "$ZSH_VERSION" ]; then 29 | # CAUTION: if you name local variable "path" (when no_case_glob is set) it 30 | # will override $PATH 31 | setopt no_case_glob 32 | unsetopt nomatch 33 | elif [ -n "$BASH_VERSION" ]; then 34 | shopt -s nocaseglob 35 | else 36 | echo "commacd: unsupported shell" >&2 37 | return 38 | fi 39 | 40 | _commacd_split() { 41 | # shellcheck disable=SC2001 42 | echo "$1" | sed $'s|/|\\\n/|g' 43 | } 44 | _commacd_join() { local IFS="$1"; shift; echo "$*"; } 45 | 46 | _commacd_expand() ( 47 | if [ -n "$ZSH_VERSION" ]; then 48 | setopt extended_glob null_glob 49 | # shellcheck disable=SC2086 50 | print -rl - ${~1} 51 | else 52 | shopt -s extglob nullglob 53 | shopt -u failglob 54 | local ex=($1) 55 | printf "%s\n" "${ex[@]}" 56 | fi 57 | ) 58 | 59 | _command_cd() { 60 | local dir=$1 IFS=$' \t\n' 61 | if [[ -z "$COMMACD_CD" ]]; then 62 | if [[ "$PWD" != "$dir" ]]; then 63 | builtin cd "$dir" && pwd 64 | else 65 | echo "commacd: no matches found" >&2 66 | return 1 67 | fi 68 | else 69 | $COMMACD_CD "$dir" 70 | fi 71 | } 72 | 73 | # show match selection menu 74 | _commacd_choose_match() { 75 | local matches=("$@") 76 | local i=${COMMACD_SEQSTART:-0} 77 | for match in "${matches[@]}"; do 78 | printf "%s\t%s\n" "$((i++))" "$match" >&2 79 | done 80 | local selection 81 | local threshold=$((11-${COMMACD_SEQSTART:-0})) 82 | if [[ "$COMMACD_IMPLICITENTER" == "on" && \ 83 | ${#matches[@]} -lt $threshold ]]; then 84 | if [ -n "$ZSH_VERSION" ]; then 85 | read -k1 "selection?: " >&2 86 | else 87 | read -n1 -e -p ': ' selection >&2 88 | fi 89 | else 90 | if [ -n "$ZSH_VERSION" ]; then 91 | read "selection?: " >&2 92 | else 93 | read -e -p ': ' selection >&2 94 | fi 95 | fi 96 | if [[ "$selection" =~ ^[0-9]+$ ]]; then 97 | local i=$((selection-${COMMACD_SEQSTART:-0})) 98 | if [ -n "$ZSH_VERSION" ]; then 99 | ((i++)) # zsh arrays are 1-based 100 | fi 101 | if [[ "${matches[i]}" != "" ]]; then 102 | echo -n "${matches[i]}" 103 | return 104 | fi 105 | fi 106 | echo -n "$PWD" 107 | } 108 | 109 | _commacd_prefix_glob() ( 110 | set -f 111 | local pth="${*%/}/" IFS=$'\n' 112 | # shellcheck disable=SC2046 113 | echo -n "$(_commacd_join \* $(_commacd_split "$pth"))" 114 | ) 115 | 116 | _commacd_glob() ( 117 | set -f 118 | local pth="${*%/}" IFS=$'\n' 119 | if [[ "${pth/\/}" == "$pth" ]]; then 120 | pth="*$pth*/" 121 | else 122 | # shellcheck disable=SC2046 123 | pth="$(_commacd_join \* $(_commacd_split "$pth") | rev | 124 | sed 's/\//*\//' | rev)*/" 125 | fi 126 | echo -n "$pth" 127 | ) 128 | 129 | _commacd_forward_by_prefix() { 130 | local matches=($(_commacd_expand "$(_commacd_prefix_glob "$*")")) 131 | if [[ "$COMMACD_NOFUZZYFALLBACK" != "on" && ${#matches[@]} -eq 0 ]]; then 132 | matches=($(_commacd_expand "$(_commacd_glob "$*")")) 133 | fi 134 | case ${#matches[@]} in 135 | 0) echo -n "$PWD";; 136 | *) printf "%s\n" "${matches[@]}" 137 | esac 138 | } 139 | 140 | # jump forward (`,`) 141 | _commacd_forward() { 142 | if [[ -z "$*" ]]; then return 1; fi 143 | local IFS=$'\n' 144 | local dir=($(_commacd_forward_by_prefix "$@")) 145 | if [[ "$COMMACD_NOTTY" == "on" ]]; then 146 | printf "%s\n" "${dir[@]}" 147 | return 148 | fi 149 | if [[ ${#dir[@]} -gt 1 ]]; then 150 | # https://github.com/shyiko/commacd/issues/12 151 | trap 'trap - SIGINT; stty '"$(stty -g)" SIGINT 152 | 153 | dir=$(_commacd_choose_match "${dir[@]}") 154 | 155 | # make sure trap is removed regardless of whether read -e ... was 156 | # interrupted or not 157 | trap - SIGINT 158 | if [[ -z "$dir" ]]; then return 1; fi 159 | fi 160 | _command_cd "$dir" 161 | } 162 | 163 | _commacd_marked() { 164 | local dir="${*%/}" 165 | local markers=(${COMMACD_MARKER:-.git/ .hg/ .svn/}) 166 | if [ -n "$ZSH_VERSION" ]; then 167 | markers=("${=markers[1]}") # shwordsplit 168 | fi 169 | for marker in "${markers[@]}"; do 170 | if [[ -e "$dir/$marker" ]]; then 171 | return 0 172 | fi 173 | done 174 | return 1 175 | } 176 | 177 | # search backward for the vcs root (`,,`) 178 | _commacd_backward_vcs_root() { 179 | local dir="${PWD%/*}" 180 | while ! _commacd_marked "$dir"; do 181 | dir="${dir%/*}" 182 | if [[ -z "$dir" ]]; then 183 | echo -n "$PWD" 184 | return 185 | fi 186 | done 187 | echo -n "$dir" 188 | } 189 | 190 | # search backward for the directory whose name begins with $1 (`,, $1`) 191 | _commacd_backward_by_prefix() ( 192 | local prev_dir dir="${PWD%/*}" matches match IFS=$'\n' 193 | while [[ -n "$dir" ]]; do 194 | prev_dir="$dir" 195 | dir="${dir%/*}" 196 | matches=($(_commacd_expand "$dir/${1}*/")) 197 | for match in "${matches[@]}"; do 198 | if [ -n "$ZSH_VERSION" ]; then 199 | if [[ "${match:l}" == "${prev_dir:l}/" ]]; then 200 | echo -n "$prev_dir" 201 | return 202 | fi 203 | else 204 | # ${var,,}/${var^^} are not available in BASH 3.2 (macOS 10.14) 205 | # hence nocasematch & == 206 | shopt -s nocasematch 207 | if [[ "$match" == "$prev_dir/" ]]; then 208 | echo -n "$prev_dir" 209 | return 210 | fi 211 | fi 212 | done 213 | done 214 | # at this point there is still a possibility that $1 is an actual path 215 | # (e.g. passed by "complete"), so let's check that 216 | if [[ -d "$1" ]]; then echo -n "$1"; return; fi 217 | # otherwise fallback to pwd 218 | echo -n "$PWD" 219 | ) 220 | 221 | # replace $1 with $2 in $PWD (`,, $1 $2`) 222 | _commacd_backward_substitute() { 223 | echo -n "${PWD/$1/$2}" 224 | } 225 | 226 | # choose `,,` strategy based on a number of arguments 227 | _commacd_backward() { 228 | local dir= 229 | case $# in 230 | 0) dir=$(_commacd_backward_vcs_root);; 231 | 1) dir=$(_commacd_backward_by_prefix "$*") 232 | if [[ "$COMMACD_NOFUZZYFALLBACK" != "on" && "$dir" == "$PWD" ]]; then 233 | dir=$(_commacd_backward_by_prefix "*$*") 234 | fi;; 235 | 2) dir=$(_commacd_backward_substitute "$@");; 236 | *) return 1 237 | esac 238 | if [[ "$COMMACD_NOTTY" == "on" ]]; then 239 | echo -n "${dir}" 240 | return 241 | fi 242 | _command_cd "$dir" 243 | } 244 | 245 | _commacd_backward_forward_by_prefix() { 246 | local dir="$PWD" pth="${*%/}/" matches match IFS=$'\n' 247 | if [[ "${pth:0:1}" == "/" ]]; then 248 | # assume that we've been brought here by the completion 249 | dir=(${pth%/}*) 250 | printf "%s\n" "${dir[@]}" 251 | return 252 | fi 253 | while [[ -n "$dir" ]]; do 254 | dir="${dir%/*}" 255 | matches=($(_commacd_expand "$dir/$(_commacd_prefix_glob "$*")")) 256 | if [[ "$COMMACD_NOFUZZYFALLBACK" != "on" && ${#matches[@]} -eq 0 ]]; then 257 | matches=($(_commacd_expand "$dir/$(_commacd_glob "$*")")) 258 | fi 259 | case ${#matches[@]} in 260 | 0) ;; 261 | *) printf "%s\n" "${matches[@]}" 262 | return;; 263 | esac 264 | done 265 | echo -n "$PWD" 266 | } 267 | 268 | # combine backtracking with `, $1` (`,,, $1`) 269 | _commacd_backward_forward() { 270 | if [[ -z "$*" ]]; then return 1; fi 271 | local IFS=$'\n' 272 | local dir=($(_commacd_backward_forward_by_prefix "$@")) 273 | if [[ "$COMMACD_NOTTY" == "on" ]]; then 274 | printf "%s\n" "${dir[@]}" 275 | return 276 | fi 277 | if [[ ${#dir[@]} -gt 1 ]]; then 278 | dir=$(_commacd_choose_match "${dir[@]}") 279 | fi 280 | _command_cd "$dir" 281 | } 282 | 283 | _commacd_completion_valid() { 284 | if [[ "$2" == "$PWD" || "${2// /\\ }" == "$1" ]]; then return 1; fi 285 | } 286 | 287 | _commacd_completion() { 288 | local pattern=${COMP_WORDS[COMP_CWORD]} IFS=$'\n' 289 | # shellcheck disable=SC2088 290 | if [[ "${pattern:0:2}" == "~/" ]]; then 291 | # shellcheck disable=SC2116 292 | pattern=$(echo ~/"${pattern:2}") 293 | fi 294 | local completion=($(COMMACD_NOTTY=on $1 "$pattern")) 295 | if ! _commacd_completion_valid "$pattern" "$completion"; then 296 | pattern="$pattern?" 297 | # retry with ? matching 298 | completion=($(COMMACD_NOTTY=on $1 "$pattern")) 299 | if ! _commacd_completion_valid "$pattern" "$completion"; then 300 | return 301 | fi 302 | fi 303 | # remove trailing / (if any) 304 | for i in "${!completion[@]}"; do 305 | completion[$i]="${completion[$i]%/}"; 306 | done 307 | COMPREPLY=($(compgen -W "$(printf "%s\n" "${completion[@]}")" -- '')) 308 | } 309 | 310 | _commacd_forward_completion() { 311 | _commacd_completion _commacd_forward 312 | } 313 | 314 | _commacd_backward_completion() { 315 | _commacd_completion _commacd_backward 316 | } 317 | 318 | _commacd_backward_forward_completion() { 319 | _commacd_completion _commacd_backward_forward 320 | } 321 | 322 | alias ,=_commacd_forward 323 | alias ,,=_commacd_backward 324 | alias ,,,=_commacd_backward_forward 325 | 326 | if [ -n "$BASH_VERSION" ]; then 327 | complete -o filenames -F _commacd_forward_completion , 328 | complete -o filenames -F _commacd_backward_completion ,, 329 | complete -o filenames -F _commacd_backward_forward_completion ,,, 330 | fi 331 | -------------------------------------------------------------------------------- /shpec/commacd_shpec.sh: -------------------------------------------------------------------------------- 1 | shopt -s expand_aliases 2 | . commacd.sh 3 | 4 | ROOT=/tmp/commacd.shpec 5 | rm -rf $ROOT 6 | mkdir -p $ROOT/projects/{jekyll/node_modules/tj/src,ghost,mysql-binlog-connector-java/src/main/java,mappify/{.git,src/test}} 7 | mkdir -p $ROOT/space\ hell/{a\ a,b\ b,a\ b} 8 | 9 | COMMACD_CD=cd # supress pwd 10 | 11 | describe 'commacd' 12 | 13 | describe ',' 14 | it 'does nothing in case of no arguments' 15 | cd $ROOT 16 | , 17 | assert equal "$PWD" $ROOT 18 | end 19 | it 'stays in the same directory in case of no match' 20 | cd $ROOT 21 | , p/nonexisting 22 | assert equal "$PWD" $ROOT 23 | end 24 | it 'changes directory without asking anything in case of single (unique) match' 25 | cd $ROOT 26 | , p/m/s/m 27 | assert equal "$PWD" "$ROOT/projects/mysql-binlog-connector-java/src/main" 28 | end 29 | it 'supports patterns starting with /' 30 | cd $ROOT 31 | , $ROOT/p/j 32 | assert equal "$PWD" "$ROOT/projects/jekyll" 33 | end 34 | it 'asks for user input in case of multiple choices' 35 | cd $ROOT 36 | , $ROOT/p/m 2> /dev/null <<< $(echo 0) 37 | assert equal "$PWD" "$ROOT/projects/mappify" 38 | end 39 | it 'can be used in subshells' 40 | cd $ROOT 41 | commacd_to_restore=$COMMACD_CD 42 | COMMACD_CD= 43 | v=$(, p) 44 | COMMACD_CD=$commacd_to_restore 45 | assert equal "$v" "$ROOT/projects" 46 | end 47 | it 'does not break on spaces' 48 | cd $ROOT 49 | , s/b 50 | assert equal "$PWD" "$ROOT/space hell/b b" 51 | end 52 | it 'switches to fuzzy mode when there are no matches by prefix' 53 | cd $ROOT/projects 54 | , binlog 55 | assert equal "$PWD" "$ROOT/projects/mysql-binlog-connector-java" 56 | end 57 | it 'switches to fuzzy mode when there are no matches by prefix containing /' 58 | cd $ROOT 59 | , p/binlog 60 | assert equal "$PWD" "$ROOT/projects/mysql-binlog-connector-java" 61 | end 62 | end 63 | 64 | describe ',,' 65 | it 'goes to the project root directory in case of no arguments' 66 | cd $ROOT/projects/mappify/src/test 67 | ,, 68 | assert equal "$PWD" "$ROOT/projects/mappify" 69 | end 70 | it 'stays in the same directory in case of no match' 71 | cd $ROOT 72 | ,, 73 | ,, nonexisting 74 | assert equal "$PWD" $ROOT 75 | end 76 | it 'always switches to the closest match' 77 | cd $ROOT/projects/mysql-binlog-connector-java/src/main/java 78 | ,, m 79 | assert equal "$PWD" "$ROOT/projects/mysql-binlog-connector-java/src/main" 80 | end 81 | it 'performs substitution in case of two arguments' 82 | cd $ROOT/projects/jekyll 83 | ,, jekyll ghost 84 | assert equal "$PWD" $ROOT/projects/ghost 85 | end 86 | it 'supports patterns starting with /' 87 | cd $ROOT/projects/mappify/src/test 88 | ,, $ROOT/projects/mappify 89 | assert equal "$PWD" "$ROOT/projects/mappify" 90 | end 91 | it 'can be used in subshells' 92 | cd $ROOT/projects/jekyll 93 | commacd_to_restore=$COMMACD_CD 94 | COMMACD_CD= 95 | v=$(,, pro) 96 | COMMACD_CD=$commacd_to_restore 97 | assert equal "$v" "$ROOT/projects" 98 | end 99 | it 'does not break on spaces' 100 | cd "$ROOT/space hell/b b" 101 | ,, s 102 | assert equal "$PWD" "$ROOT/space hell" 103 | end 104 | it 'switches to fuzzy mode when there are no matches by prefix' 105 | cd $ROOT/projects/mysql-binlog-connector-java/src/main/java 106 | ,, binlog 107 | assert equal "$PWD" "$ROOT/projects/mysql-binlog-connector-java" 108 | end 109 | it 'switches to fuzzy mode only after full path scan' 110 | cd $ROOT/projects/jekyll/node_modules/tj/src 111 | ,, j 112 | assert equal "$PWD" "$ROOT/projects/jekyll" 113 | end 114 | end 115 | 116 | describe ',,,' 117 | it 'does nothing in case of no arguments' 118 | cd $ROOT 119 | ,,, 120 | assert equal "$PWD" $ROOT 121 | end 122 | it 'stays in the same directory in case of no match' 123 | cd $ROOT 124 | ,,, nonexisting 125 | assert equal "$PWD" $ROOT 126 | end 127 | it 'changes directory without asking anything in case of single (unique) match' 128 | cd $ROOT/projects/mappify/src/test 129 | ,,, mysql 130 | assert equal "$PWD" "$ROOT/projects/mysql-binlog-connector-java" 131 | end 132 | it 'supports patterns starting with /' 133 | cd $ROOT/projects/mappify 134 | ,,, $ROOT/projects/mysql 135 | assert equal "$PWD" "$ROOT/projects/mysql-binlog-connector-java" 136 | end 137 | it 'asks for user input in case of multiple choices' 138 | cd $ROOT/projects/jekyll 139 | ,,, m 2> /dev/null <<< $(echo 0) 140 | assert equal "$PWD" "$ROOT/projects/mappify" 141 | end 142 | it 'can be used in subshells' 143 | cd $ROOT/projects/jekyll 144 | commacd_to_restore=$COMMACD_CD 145 | COMMACD_CD= 146 | v=$(,,, mysql) 147 | COMMACD_CD=$commacd_to_restore 148 | assert equal "$v" "$ROOT/projects/mysql-binlog-connector-java" 149 | end 150 | it 'does not break on spaces' 151 | cd "$ROOT/space hell/a a" 152 | ,,, b 153 | assert equal "$PWD" "$ROOT/space hell/b b" 154 | end 155 | it 'switches to fuzzy mode when there are no matches by prefix' 156 | cd $ROOT/projects/mappify 157 | ,,, binlog 158 | assert equal "$PWD" "$ROOT/projects/mysql-binlog-connector-java" 159 | end 160 | end 161 | 162 | end 163 | --------------------------------------------------------------------------------