【问题标题】:Collapse directories in zsh prompt in a unique way以独特的方式折叠 zsh 提示符中的目录
【发布时间】:2017-12-29 01:09:43
【问题描述】:

有没有办法以独特的方式折叠 zsh 提示符中的当前工作目录,以便我可以将其复制并粘贴到另一个终端,点击 TAB 并获取原始路径?

假设我们有以下目录:

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

如果提示被编程为显示第一个字符,并且我在 /b/d 中,那么它是唯一的。另一方面,/a/d 不是唯一的,所以我需要 /ad/d、/al/de 和 /al/do。甚至 /ali/... 只要用户 alex 出现。

是否可以直接在 zsh 中破解它,还是我需要编写一个脚本来找到每个父目录的最短唯一开头?

感谢您的想法!

【问题讨论】:

    标签: zsh prompt pwd


    【解决方案1】:

    我不知道zsh 有这种内置函数,但它应该很容易编写脚本,而无需求助于单个子shell 或慢速管道:

    #!/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
    

    此脚本将输出自动完成工作所需的最短路径。

    您可以将它作为函数放入您的.zshrc,然后从任何目录运行它。

    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
    }
    

    这是一个实际操作的视频:

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

    或者,如果您愿意,可以提供一些示例输出:

    ~/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
    

    【讨论】:

    • 谢谢你,它在我的提示中很有用。您会推荐什么资源来全面了解 zsh 语法?
    • 你能找到的最全面的资源可能是The Z Shell Manual,官方参考。每当我想深入研究语法时,我都会去那里,我经常浏览它以更好地理解某些语法。还有user guide,它更像是一种学习体验而不是参考,尽管我很遗憾地说它还没有完成。但它是一个很好的入门资源,如果不是有点罗嗦和未格式化。
    【解决方案2】:

    是的,可以将目录折叠到首个唯一字母路径,并在按下 [Tab] 时让 Z Shell 展开该路径。我只是使用 compinstall(与 Zsh 一起安装的 zsh 实用程序脚本)来生成以下代码。扩展路径元素需要注意的重要部分是在第六个zstyle 命令,靠近末尾,其中分隔完成点的字符括号包括/,即,当然是目录分隔符。这样,您建议的唯一路径只需按一下 [Tab] 即可完全填写,就好像 * 位于每个路径名唯一字母的末尾一样。

    # The following lines were added by compinstall
    
    zstyle ':completion:*' add-space true
    zstyle ':completion:*' completer _list _expand _complete _ignored _match _correct _approximate _prefix
    zstyle ':completion:*' completions 1
    zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS}
    zstyle ':completion:*' matcher-list 'm:{[:lower:]}={[:upper:]} r:|[._-]=* r:|=*' 'm:{[:lower:]}={[:upper:]} m:{[:lower:][:upper:]}={[:upper:][:lower:]} r:|[._-]=* r:|=*' 'r:|[._-/]=* r:|=*' 'l:|=* r:|=*'
    zstyle ':completion:*' match-original both
    zstyle :compinstall filename '/home/micah/.zsh/.zshrc'
    
    autoload -Uz compinit
    compinit
    # End of lines added by compinstall
    

    至于首先创建唯一路径并将其插入到提示符中,可以使用 zsh 脚本或函数,因此 应该 也可以用于完成者或行编辑器,但只要遵守提示,您将向 $precmd_functions 数组添加一个函数,该函数修改或添加到 PS1 变量。这个特殊数组是在每个提示之前运行的函数名称列表。

    function precmd_unique_pwd {
      local pwd_string="$(upwd)"
      PS1="%B%n@%m $pwd_string => %b"
    }
    precmd_functions+=( precmd_unique_pwd )
    

    为了以缩短的形式获取当前 PWD,我认为此功能清晰易懂,但不一定针对低资源使用进行优化。

    #!/bin/zsh
    function upwd {
            emulate -LR zsh -o nullglob
            local dir Path
            local -a newpwd tmp stack
            local -i length=1 Flag=0
            newpwd=( ${(s./.)PWD} )
            foreach dir ( $newpwd )
                    (( length=0, Flag=0 ))
                    repeat $#dir
                    do
                            (( length += 1 ))
                            tmp=( ${(j.*/.)~stack}/$dir[1,$length]*(/) )
                            if
                                    (( $#tmp == 1 ))
                            then
                                    Path=$Path/$dir[1,$length]
                                    stack+=( /$dir )
                                    (( Flag=1 ))
                                    break
                            fi
                    done
                    if
                            (( Flag ))
                    then
                            continue
                    else
                            Path=$Path/$dir
                    fi
            end
            print -- $Path
    }
    upwd
    

    请注意,由于 Zsh 功能 (/) 在 globbing 的末尾,它会找到具有目录名称的唯一路径。在最后一个目录(当前)上,这意味着如果有同名文件加上扩展名,您可能会匹配其他内容。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-17
      • 2021-01-13
      • 1970-01-01
      • 2016-03-22
      • 2012-12-31
      相关资源
      最近更新 更多