Search code examples
zshpromptpwd

Collapse directories in zsh prompt in a unique way


Is there a way to collapse the current working directory in the zsh prompt in a unique way, so that I could copy and paste it to another terminal, hit TAB and get the original path?

Let's say we have following directories:

/adam/devl
/alice/devl
/alice/docs
/bob/docs

If the prompt is programmed to show the first characters, and I'm in /b/d, then it is unique. On the other hand, /a/d is not unique, so I would need /ad/d, /al/de and /al/do. And even /ali/… as soon as the user alex appears.

Is it possible to hack this directly in zsh or do I need to write a script, that finds the shortest unique beginning of each parent directory?

Thank you for your ideas!


Solution

  • I'm not aware that zsh has a built-in function of this sort, but it should be pretty easy to script without resorting to a single subshell or slow pipe:

    #!/bin/zsh
    
    paths=(${(s:/:)PWD})
    
    cur_path='/'
    cur_short_path='/'
    for directory in ${paths[@]}
    do
      cur_dir=''
      for (( i=0; i<${#directory}; i++ )); do
        cur_dir+="${directory:$i:1}"
        matching=("$cur_path"/"$cur_dir"*/)
        if [[ ${#matching[@]} -eq 1 ]]; then
          break
        fi
      done
      cur_short_path+="$cur_dir/"
      cur_path+="$directory/"
    done
    
    printf %q "${cur_short_path: : -1}"
    echo
    

    This script will output the shortest path needed for auto-completion to work.

    You can throw it in your .zshrc as a function and then run it from any directory.

    function spwd {
      paths=(${(s:/:)PWD})
    
      cur_path='/'
      cur_short_path='/'
      for directory in ${paths[@]}
      do
        cur_dir=''
        for (( i=0; i<${#directory}; i++ )); do
          cur_dir+="${directory:$i:1}"
          matching=("$cur_path"/"$cur_dir"*/)
          if [[ ${#matching[@]} -eq 1 ]]; then
            break
          fi
        done
        cur_short_path+="$cur_dir/"
        cur_path+="$directory/"
      done
    
      printf %q "${cur_short_path: : -1}"
      echo
    }
    

    Here's a video of it in action:

    https://asciinema.org/a/0TyL8foqvQ8ec5ZHS3c1mn5LH

    Or if you prefer, some sample output:

    ~/t $ ls
    adam  alice  bob  getshortcwd.zsh
    
    ~/t $ ls adam
    devl
    
    ~/t $ ls alice
    devl  docs
    
    ~/t $ spwd
    /h/v/t
    
    ~/t $ cd adam/devl
    
    ~/t/adam/devl $ spwd
    /h/v/t/ad/d
    
    ~/t/adam/devl $ cd ../../alice/devl
    
    ~/t/alice/devl $ spwd
    /h/v/t/al/de
    
    ~/t/alice/devl $ cd ../docs
    
    ~/t/alice/docs $ spwd
    /h/v/t/al/do
    
    ~/t/alice/docs $ `spwd` [TAB]
    ~/t/alice/docs $ /h/v/t/al/do [TAB]
    ~/t/alice/docs $ /home/vsimonian/t/alice/docs