Có cách nào để truy cập theo chương trình và lưu danh sách các ứng cử viên hoàn thành trong Zsh không?


4

Trong Zsh theo mặc định, tabkhóa được ràng buộc expand-or-complete. Tôi muốn truy cập theo chương trình danh sách các ứng cử viên hoàn thành sẽ được tạo ra bằng cách nhấn tab, để tôi có thể tự viết chức năng của mình và tự lọc danh sách. Tôi hiểu rằng có một "khung hoàn thành" đi kèm với Zsh nhưng tôi muốn tự mình làm điều đó.

Ngoài ra còn có list-choiceschức năng / widget tạo ra đầu ra giống như expand-or-completenhưng không cung cấp chức năng quay vòng tab.

Tôi đã thực hiện một tìm kiếm hợp lý trên Google và cũng tìm kiếm thông qua nguồn Zsh nhưng đã bị khô. Bất kỳ trợ giúp sẽ được đánh giá cao.


1
Câu hỏi thú vị. Bạn đã xem Bash thực hiện cùng một khái niệm này chưa?
JakeGould

Câu trả lời:


3

Một cách gián tiếp nhờ JakeGould tôi tình cờ tìm thấy một giải pháp : zsh-capture-completion. Trên thực tế có hai khác câu hỏi gần như giống hệt trên các trang web Unix stack Exchange, cả với câu trả lời tôi đã đưa ra ở đây.

Mã nguồn script zsh-capture-completioncó thể được tìm thấy ở đây:

#!/bin/zsh

zmodload zsh/zpty || { echo 'error: missing module zsh/zpty' >&2; exit 1 }

# spawn shell
zpty z zsh -f -i

# line buffer for pty output
local line

setopt rcquotes
() {
    zpty -w z source $1
    repeat 4; do
        zpty -r z line
        [[ $line == ok* ]] && return
    done
    echo 'error initializing.' >&2
    exit 2
} =( <<< '
# no prompt!
PROMPT=
# load completion system
autoload compinit
compinit -d ~/.zcompdump_capture
# never run a command
bindkey ''^M'' undefined
bindkey ''^J'' undefined
bindkey ''^I'' complete-word
# send a line with null-byte at the end before and after completions are output
null-line () {
    echo -E - $''\0''
}
compprefuncs=( null-line )
comppostfuncs=( null-line exit )
# never group stuff!
zstyle '':completion:*'' list-grouped false
# don''t insert tab when attempting completion on empty line
zstyle '':completion:*'' insert-tab false
# no list separator, this saves some stripping later on
zstyle '':completion:*'' list-separator ''''
# we use zparseopts
zmodload zsh/zutil
# override compadd (this our hook)
compadd () {
    # check if any of -O, -A or -D are given
    if [[ ${@[1,(i)(-|--)]} == *-(O|A|D)\ * ]]; then
        # if that is the case, just delegate and leave
        builtin compadd "$@"
        return $?
    fi
    # ok, this concerns us!
    # echo -E - got this: "$@"
    # be careful with namespacing here, we don''t want to mess with stuff that
    # should be passed to compadd!
    typeset -a __hits __dscr __tmp
    # do we have a description parameter?
    # note we don''t use zparseopts here because of combined option parameters
    # with arguments like -default- confuse it.
    if (( $@[(I)-d] )); then # kind of a hack, $+@[(r)-d] doesn''t work because of line noise overload
        # next param after -d
        __tmp=${@[$[${@[(i)-d]}+1]]}
        # description can be given as an array parameter name, or inline () array
        if [[ $__tmp == \(* ]]; then
            eval "__dscr=$__tmp"
        else
            __dscr=( "${(@P)__tmp}" )
        fi
    fi
    # capture completions by injecting -A parameter into the compadd call.
    # this takes care of matching for us.
    builtin compadd -A __hits -D __dscr "$@"
    setopt localoptions norcexpandparam extendedglob
    # extract prefixes and suffixes from compadd call. we can''t do zsh''s cool
    # -r remove-func magic, but it''s better than nothing.
    typeset -A apre hpre hsuf asuf
    zparseopts -E P:=apre p:=hpre S:=asuf s:=hsuf
    # append / to directories? we are only emulating -f in a half-assed way
    # here, but it''s better than nothing.
    integer dirsuf=0
    # don''t be fooled by -default- >.>
    if [[ -z $hsuf && "${${@//-default-/}% -# *}" == *-[[:alnum:]]#f* ]]; then
        dirsuf=1
    fi
    # just drop
    [[ -n $__hits ]] || return
    # this is the point where we have all matches in $__hits and all
    # descriptions in $__dscr!
    # display all matches
    local dsuf dscr
    for i in {1..$#__hits}; do
        # add a dir suffix?
        (( dirsuf )) && [[ -d $__hits[$i] ]] && dsuf=/ || dsuf=
        # description to be displayed afterwards
        (( $#__dscr >= $i )) && dscr=" -- ${${__dscr[$i]}##$__hits[$i] #}" || dscr=
        echo -E - $IPREFIX$apre$hpre$__hits[$i]$dsuf$hsuf$asuf$dscr
    done
}
# signal success!
echo ok')

zpty -w z "$*"$'\t'

integer tog=0
# read from the pty, and parse linewise
while zpty -r z; do :; done | while IFS= read -r line; do
    if [[ $line == *$'\0\r' ]]; then
        (( tog++ )) && return 0 || continue
    fi
    # display between toggles
    (( tog )) && echo -E - $line
done

return 2

Dưới đây là một ví dụ về việc sử dụng tập lệnh:

══► % cd ~/.zsh_plugins
══► % zsh ./zsh-capture-completion/capture.zsh 'cd '
zaw/
zsh-capture-completion/
zsh-syntax-highlighting/
zsh-vimode-visual/

Lưu ý ký tự khoảng trắng trong lệnh trên. Với không gian, tập lệnh cung cấp danh sách các thư mục mà bạn có thể cdnhập từ thư mục hiện tại. Không có nó, kịch bản sẽ cung cấp tất cả các hoàn thành cho một lệnh bắt đầu bằng cd.

Tôi cũng nên lưu ý rằng ngay cả tác giả của tập lệnh / plugin được cung cấp cũng coi giải pháp của mình là "hacky". Nếu bất cứ ai biết về giải pháp ngắn hơn hoặc thẳng hơn, tôi sẽ rất vui lòng chấp nhận nó như là câu trả lời.


1
Công việc tuyệt vời Đã thêm mã nguồn cho chính tập lệnh bởi vì vào cuối ngày, mã của đoạn mã này đủ ngắn, tốt hơn là nên đăng nó trong câu trả lời vì các liên kết (và nội dung của chúng) thường có thể biến mất.
JakeGould

Cảm ơn, tôi đã sắp xếp hàng rào về việc thêm nó. Tôi nghĩ rằng đó chỉ là kết thúc của việc "đủ ngắn" hoặc "quá dài". Với kinh nghiệm của bạn, tôi sẽ trì hoãn phán xét của bạn.
John Lunzer

Không vấn đề gì. Lưu ý cách mã nguồn được đặt trong phần tử cuộn. Vì vậy, độ dài không phải là một mối quan tâm hoàn toàn trừ khi nó thực sự dài và ngoài tầm kiểm soát.
JakeGould

1
Ngoài ra, có khả năng ngôn ngữ gây khó chịu / không nhạy cảm trong mã nguồn.
John Lunzer

Rất tiếc! Ít nhất nó chỉ là một bình luận và tôi đã gỡ bỏ nó.
JakeGould
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.