Buat skrip penyelesaian bash ke lintasan lengkapi otomatis setelah tanda sama dengan?

11

Saya ingin membuat skrip penyelesaian bash yang mengakui argumen formulir --argdan --some-arg=file.

Setelah membaca tutorial ini dan beberapa contoh /usr/share/bash_completion/completions/, saya telah menulis skrip berikut (untuk menghemat waktu mengetik beberapa flag dengan Chromium):

_chromium() 
{
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"

    # Some interesting options
    opts="
--disable-web-security
--easy-off-store-extension-install
--incognito
--load-extension=
--pack-extension=
--pack-extension-key=
--user-data-dir=
"
    # Handle --xxxxxx=file
    if [[ ${cur} == "--"*"=" ]] ; then
        # Removed failures (is my logic OK?)
        return 0
    fi

    # Handle other options
    if [[ ${cur} == -* ]] ; then
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
        return 0
    fi
}
complete -F _chromium chromium

Saya menyimpannya ~/bash_completions/chromium, dan membuat symlink menggunakan sudo ln -s ~/bash_completions/chromium /usr/share/bash_completion/completions/chromium.
Lalu saya memuatnya menggunakan . /usr/share/bash_completions/completions/chromium.

Sekarang, saya mengalami dua masalah:

  • chromium --u<TAB>mengembang ke chromium --user-data-dir=<SPACE>(Saya tidak ingin ruang).
  • Jalur (direktori dan file) tidak selesai lagi.

Bagaimana saya bisa menyelesaikan masalah ini?

Rob W
sumber
Apakah beralih ke zsh merupakan opsi?
Gilles 'SANGAT berhenti menjadi jahat'

Jawaban:

11

Saya telah menemukan solusi untuk kedua masalah tersebut!

  1. Untuk tidak menambahkan spasi, gunakan nospaceopsi. Ini dapat dilakukan dengan dua cara:

    • Serahkan ke complete:
      complete -o nospace -F _chromium chromium
    • Gunakan compoptbuilt-in:
      compopt -o nospace(untuk mengaktifkan opsi)
      compopt +o nospace(untuk menonaktifkan opsi)

    Saya menemukannya di dokumentasi Bash di gnu.org, 8.7 Programmable Completion Builtins .

  2. Penyelesaian file.
    • peterph menyarankan untuk menggunakan -fflag dengan compgen. Saya mengikuti saran itu, dan menerapkannya sebagai COMPREPLY=( $(compgen -f "$cur") ). Ini bekerja dengan baik, sampai saya mencoba menyelesaikan jalur yang berisi spasi.
      Pada Stack Overflow, saya menemukan jawaban ini yang merekomendasikan pembuatan daftar penyelesaian secara manual (tanpa menggunakan compgen). Pendekatan ini bekerja dengan baik.
    • Gunakan filenamesopsi untuk memberi tahu Readline bahwa compspec menghasilkan nama file, sehingga ia dapat:
      • melakukan pemrosesan nama file spesifik (seperti menambahkan garis miring ke nama direktori, mengutip karakter khusus, atau menekan spasi tambahan)
      • menggunakan warna berbeda untuk menunjukkan jenis file (dengan colored-statsdiaktifkan)

Dengan bantuan manipulasi string Bash (untuk memperluas ~dan menangani spasi), saya membuat skrip penyelesaian bash yang memenuhi semua kriteria yang dinyatakan dalam pertanyaan.

_chromium() 
{
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"

    # Some interesting options
    opts="
--disable-web-security
--easy-off-store-extension-install
--incognito
--load-extension=
--pack-extension=
--pack-extension-key=
--user-data-dir=
"
    # Handle --xxxxxx=
    if [[ ${prev} == "--"* && ${cur} == "=" ]] ; then
        compopt -o filenames
        COMPREPLY=(*)
        return 0
    fi
    # Handle --xxxxx=path
    if [[ ${prev} == '=' ]] ; then
        # Unescape space
        cur=${cur//\\ / }
        # Expand tilder to $HOME
        [[ ${cur} == "~/"* ]] && cur=${cur/\~/$HOME}
        # Show completion if path exist (and escape spaces)
        compopt -o filenames
        local files=("${cur}"*)
        [[ -e ${files[0]} ]] && COMPREPLY=( "${files[@]// /\ }" )
        return 0
    fi

    # Handle other options
    COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
    if [[ ${#COMPREPLY[@]} == 1 && ${COMPREPLY[0]} != "--"*"=" ]] ; then
        # If there's only one option, without =, then allow a space
        compopt +o nospace
    fi
    return 0
}
complete -o nospace -F _chromium chromium
Rob W
sumber
Jawaban yang luar biasa, terima kasih banyak. Anda telah menghemat banyak waktu saya. Saya menggunakan -fswitch untuk penyelesaian path file, tetapi tidak menyelesaikan /char jika itu adalah direktori ... itu adalah hal yang kecil sekalipun.
Jiri Kremser
1

Untuk nama file lengkap coba lewat -funtuk compgen.

Saya khawatir Anda tidak akan bisa menghilangkan ruang setelah opsi, karena itulah cara penyelesaiannya - setelah menemukan kecocokan yang unik, ia menyelesaikannya sepenuhnya.

peterph
sumber
Terima kasih atas sarannya -f. Saya mencobanya, tetapi tidak dengan benar berurusan dengan spasi: Path /tmp/foo barmenghasilkan dua entri penyelesaian /tmp/foodan bar. Tentang yang tidak diinginkan --arg=<SPACE>: Saya telah menemukan solusi untuk itu, dan mempostingnya di jawaban di bawah ini .
Rob W