如何以不同的方式自動完成每個參數?

如何以不同的方式自動完成每個參數?

我有一個名為 load_pg 的函數,定義如下:

load_pg () {
    pg_restore --verbose --clean --no-acl --no-owner -h localhost -U $1 -d $2 $3
}

我正在嘗試使用以下程式碼自動完成每個參數:

#compdef load_pg
_arguments -s \
  "1::_ldpguser" \
  "2::_ldpgdb" \
  "3::_ldpgfile"

_ldpguser () {
  compadd $USER
}

_ldpgdb () {
  compadd $(cat config/database.yml | grep -i database | awk '{print $2}')
}

_ldpgfile () {
  compadd $(ls *.dump*)
}

不幸的是,當我按 TAB 時什麼也沒有發生。我究竟做錯了什麼?我嘗試使用來自以下答案

答案1

_arguments第一個障礙: is where的參數語法不允許為空。如果您添加訊息,您會看到一些進展:n:message:actionmessage

_arguments -s \
  "1:username:_ldpguser" \
  "2:database:_ldpgdb" \
  "3:dump file:_ldpgfile"

下一個障礙是輔助函數是在_arguments運行後定義的,因此第一次完成參數時,您將收到一條錯誤訊息,抱怨其中一個函數不存在。在使用函數之前先定義它們。更好的是,明確函數的定義_load_pg並在自動載入檔案的末尾呼叫它。這看起來很笨拙,但這是 zsh 附帶的大多數多功能完成函數的編寫方式。

#compdef load_pg

_ldpguser () {
  compadd $USER
}

_ldpgdb () {
  compadd $(cat config/database.yml | grep -i database | awk '{print $2}')
}

_ldpgfile () {
  compadd $(ls *.dump*)
}

_load_pg () {
  _arguments -s \
    "1:user:_ldpguser" \
    "2:database:_ldpgdb" \
    "3:dump file:_ldpgfile"
}

_load_pg "$@"

這為您提供了該功能的核心。然後您需要清理各個函數。最低限度:

  • compadd $USER似乎毫無意義:如果您只想使用您的用戶名呼叫該函數,為什麼不建立它呢?若要完成用戶名,請呼叫_users.
  • 指令替換替換所有空格。要分割線,請使用@f 參數擴展標誌。您還應該使您的grep命令更加精確,並且您可以將其與grep.
  • 當您compadd從 中呼叫操作時_arguments,請將 中的上下文選項傳遞給它$expl
  • 您可能需要提供完成的描述_describe
  • $(ls *.dump*)是一種複雜的書寫方式“ *.dump*,如果沒有匹配,則根據當前 shell 設定執行某些操作”。不解析輸出ls,嗯嗯?你可以使用N 全域限定符當沒有匹配時有一個空的完成列表。但是,您應該調用_files除其他細節外,它還負責完成子目錄中的檔案。
#compdef load_pg

_ldpgdb () {
  compadd $expl[@] -- "${(@f)$(<config/database.yml grep -i database | awk '{print $2}')}"
}

_load_pg () {
  _arguments -s \
    '1:user:_users' \
    '2:database:_ldpgdb' \
    '3:dump file:_files -g "*.dump*"'
}

_load_pg "$@"

相關內容