以独特的方式折叠zsh提示符中的目录

9

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

假设我们有以下目录:

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

如果提示被编程为显示第一个字符,并且我在/b/d中,那么它是唯一的。另一方面,/a/d不是唯一的,所以我需要/ad/d,/al/de和/al/do。甚至/ali/...一旦用户alex出现。
是否可以直接在zsh中破解这个问题,还是我需要编写一个脚本来找到每个父目录的最短唯一开头?
感谢您的想法!
2个回答

11

我不知道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

1
谢谢,它在我的提示符中完美运行。您推荐哪些资源可以获得关于zsh语法的良好概述? - eumiro
1
可能是你能找到的最全面的资源是The Z Shell Manual,它是官方参考资料。每当我想深入了解语法时,我都会去那里查阅,我经常浏览它以更好地理解某些语法。还有用户指南,它比参考资料更像是一个学习体验,尽管我很遗憾地说它还没有完成。但如果不介意有点啰嗦和格式不整齐,它是一个很好的入门资源。 - Adaline Simonian

0

是的,可以将目录折叠为首字母路径,并在按下 [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特性中的(/),它会查找具有目录名称的唯一路径。在最后一个目录(当前目录)上,这意味着如果有与同名加扩展名的文件,则可能会匹配其他内容。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接