bitwarden / clients

Bitwarden client apps (web, browser extension, desktop, and cli).
https://bitwarden.com
Other
8.69k stars 1.14k forks source link

ZSH completion error 🧑‍💻 #2730

Open latipun7 opened 2 years ago

latipun7 commented 2 years ago

Describe the Bug

ZSH completion not working, error when evaluated. Tried to load it through fpath but the result compinit (.zcompdump) not contain _bw file.

Steps To Reproduce

  1. Run the following command, eval "$(bw completion --shell zsh); compdef _bw bw;" get parsing error.

Tried another method:

  1. Create _bw file and place it in fpath
  2. Content of _bw copied from the result of bw completion --shell zsh
  3. Run command autoload -Uz compinit && compinit to rebuild the .zcomdump

Completion not loaded, cat ~/.zcompdump | grep bw not producing the result, which mean the file has some error then not loaded.

Expected Result

No error and completion working.

Actual Result

Parse error, completion not loaded.

Screenshots or Videos

step

Environment

MGibson1 commented 2 years ago

I can't reproduce this on 64bit x86, maybe it's ARM specific for some reason?

Let's try and get more specific about the offending ')'. Can you provide the output of bw completion --shell zsh | grep \)? Here is mine:

    '--cleanexit[Exit with a success exit code (0) unless an error is thrown.]' \
    '(-v --version)'{-v,--version}'[output the version number]' \
    '(-h --help)'{-h,--help}'[output usage information]' \
    cmnds)
      )
    login)
    logout)
    lock)
    unlock)
    sync)
    generate)
    encode)
    config)
    update)
    completion)
    status)
    list)
    get)
    create)
    edit)
    delete)
    restore)
    move)
    confirm)
    import)
    export)
    share)
    send)
    receive)
    '(-h --help)'{-h,--help}'[output usage information]' \
    '(-h --help)'{-h,--help}'[output usage information]' \
    '(-f --force)'{-f,--force}'[Force a full sync.]' \
    '(-h --help)'{-h,--help}'[output usage information]' \
    '(-u --uppercase)'{-u,--uppercase}'[Include uppercase characters.]' \
    '(-l --lowercase)'{-l,--lowercase}'[Include lowercase characters.]' \
    '(-n --number)'{-n,--number}'[Include numeric characters.]' \
    '(-s --special)'{-s,--special}'[Include special characters.]' \
    '(-p --passphrase)'{-p,--passphrase}'[Generate a passphrase.]' \
    '(-c --capitalize)'{-c,--capitalize}'[Title case passphrase.]' \
    '(-h --help)'{-h,--help}'[output usage information]' \
    '(-h --help)'{-h,--help}'[output usage information]' \
    '(-h --help)'{-h,--help}'[output usage information]' \
    '(-h --help)'{-h,--help}'[output usage information]' \
    '(-h --help)'{-h,--help}'[output usage information]' \
    '(-h --help)'{-h,--help}'[output usage information]' \
    '(-h --help)'{-h,--help}'[output usage information]' \
    '(-p --permanent)'{-p,--permanent}'[Permanently deletes the item instead of soft-deleting it (item only).]' \
    '(-h --help)'{-h,--help}'[output usage information]' \
    '(-h --help)'{-h,--help}'[output usage information]' \
    '(-h --help)'{-h,--help}'[output usage information]' \
    '(-h --help)'{-h,--help}'[output usage information]' \
    '(-f --file)'{-f,--file}'[Specifies that <data> is a filepath]' \
    '(-d --deleteInDays)'{-d,--deleteInDays}'[The number of days in the future to set deletion date, defaults to 7]' \
    '(-a --maxAccessCount)'{-a,--maxAccessCount}'[The amount of max possible accesses.]' \
    '(-n --name)'{-n,--name}'[The name of the Send. Defaults to a guid for text Sends and the filename for files.]' \
    '(-h --help)'{-h,--help}'[output usage information]' \
    cmnds)
      )
    list)
    template)
    get)
    receive)
    create)
    edit)
    remove-password)
    delete)
    '(-h --help)'{-h,--help}'[output usage information]' \
    '(-h --help)'{-h,--help}'[output usage information]' \
    '(-h --help)'{-h,--help}'[output usage information]' \
    '(-h --help)'{-h,--help}'[output usage information]' \
    '(-h --help)'{-h,--help}'[output usage information]' \
latipun7 commented 2 years ago

Thanks for the follow up, @MGibson1 .

I don't know, I still have some error in my main laptop which is x86_64 arch.

Here's the result of bw completion --shell zsh | grep \):

Logs ```log ❯ bw completion --shell zsh | grep \) '--cleanexit[Exit with a success exit code (0) unless an error is thrown.]' \ '(-v --version)'{-v,--version}'[output the version number]' \ '(-h --help)'{-h,--help}'[output usage information]' \ cmnds) ) login) logout) lock) unlock) sync) generate) encode) config) update) completion) status) list) get) create) edit) delete) restore) move) confirm) import) export) share) send) receive) '(-h --help)'{-h,--help}'[output usage information]' \ '(-h --help)'{-h,--help}'[output usage information]' \ '(-f --force)'{-f,--force}'[Force a full sync.]' \ '(-h --help)'{-h,--help}'[output usage information]' \ '(-u --uppercase)'{-u,--uppercase}'[Include uppercase characters.]' \ '(-l --lowercase)'{-l,--lowercase}'[Include lowercase characters.]' \ '(-n --number)'{-n,--number}'[Include numeric characters.]' \ '(-s --special)'{-s,--special}'[Include special characters.]' \ '(-p --passphrase)'{-p,--passphrase}'[Generate a passphrase.]' \ '(-c --capitalize)'{-c,--capitalize}'[Title case passphrase.]' \ '(-h --help)'{-h,--help}'[output usage information]' \ '(-h --help)'{-h,--help}'[output usage information]' \ '(-h --help)'{-h,--help}'[output usage information]' \ '(-h --help)'{-h,--help}'[output usage information]' \ '(-h --help)'{-h,--help}'[output usage information]' \ '(-h --help)'{-h,--help}'[output usage information]' \ '(-h --help)'{-h,--help}'[output usage information]' \ '(-p --permanent)'{-p,--permanent}'[Permanently deletes the item instead of soft-deleting it (item only).]' \ '(-h --help)'{-h,--help}'[output usage information]' \ '(-h --help)'{-h,--help}'[output usage information]' \ '(-h --help)'{-h,--help}'[output usage information]' \ '(-h --help)'{-h,--help}'[output usage information]' \ '(-f --file)'{-f,--file}'[Specifies that is a filepath]' \ '(-d --deleteInDays)'{-d,--deleteInDays}'[The number of days in the future to set deletion date, defaults to 7]' \ '(-a --maxAccessCount)'{-a,--maxAccessCount}'[The amount of max possible accesses.]' \ '(-n --name)'{-n,--name}'[The name of the Send. Defaults to a guid for text Sends and the filename for files.]' \ '(-h --help)'{-h,--help}'[output usage information]' \ cmnds) ) list) template) get) receive) create) edit) remove-password) delete) '(-h --help)'{-h,--help}'[output usage information]' \ '(-h --help)'{-h,--help}'[output usage information]' \ '(-h --help)'{-h,--help}'[output usage information]' \ '(-h --help)'{-h,--help}'[output usage information]' \ '(-h --help)'{-h,--help}'[output usage information]' \ ```

New Environments

Operating system: Arch Linux x86_64 Shell: zsh 5.8 (x86_64-pc-linux-gnu) Build Version (run bw --version): 1.20.0

MGibson1 commented 2 years ago

Well swing and a miss, I guess. Those logs are the same.

Can you try again with just bw completion --shell zsh?

latipun7 commented 2 years ago

It's print out normally, but error when I eval it.

Here's the logs ```zsh ❯ bw completion --shell zsh #compdef _bw bw function _bw { local -a commands _arguments -C \ '--pretty[Format output. JSON is tabbed with two spaces.]' \ '--raw[Return raw output instead of a descriptive message.]' \ '--response[Return a JSON formatted version of response output.]' \ '--cleanexit[Exit with a success exit code (0) unless an error is thrown.]' \ '--quiet[Don'"'"'t return anything to stdout.]' \ '--nointeraction[Do not prompt for interactive user input.]' \ '--session[Pass session key instead of reading from env.]' \ '(-v --version)'{-v,--version}'[output the version number]' \ '(-h --help)'{-h,--help}'[output usage information]' \ "1: :->cmnds" \ "*::arg:->args" case $state in cmnds) commands=( "login:Log into a user account." "logout:Log out of the current user account." "lock:Lock the vault and destroy active session keys." "unlock:Unlock the vault and return a new session key." "sync:Pull the latest vault data from server." "generate:Generate a password/passphrase." "encode:Base 64 encode stdin." "config:Configure CLI settings." "update:Check for updates." "completion:Generate shell completions." "status:Show server, last sync, user information, and vault status." "list:List an array of objects from the vault." "get:Get an object from the vault." "create:Create an object in the vault." "edit:Edit an object from the vault." "delete:Delete an object from the vault." "restore:Restores an object from the trash." "move:Move an item to an organization." "confirm:Confirm an object to the organization." "import:Import vault data from a file." "export:Export vault data to a CSV or JSON file." "share:--DEPRECATED-- Move an item to an organization." "send:Work with Bitwarden sends. A Send can be quickly created using this command or subcommands can be used to fine-tune the Send" "receive:Access a Bitwarden Send from a url" ) _describe "command" commands ;; esac case "$words[1]" in login) _bw_login ;; logout) _bw_logout ;; lock) _bw_lock ;; unlock) _bw_unlock ;; sync) _bw_sync ;; generate) _bw_generate ;; encode) _bw_encode ;; config) _bw_config ;; update) _bw_update ;; completion) _bw_completion ;; status) _bw_status ;; list) _bw_list ;; get) _bw_get ;; create) _bw_create ;; edit) _bw_edit ;; delete) _bw_delete ;; restore) _bw_restore ;; move) _bw_move ;; confirm) _bw_confirm ;; import) _bw_import ;; export) _bw_export ;; share) _bw_share ;; send) _bw_send ;; receive) _bw_receive ;; esac } function _bw_login { _arguments -C \ '--method[Two-step login method.]' \ '--code[Two-step login code.]' \ '--sso[Log in with Single-Sign On.]' \ '--apikey[Log in with an Api Key.]' \ '--passwordenv[Environment variable storing your password]' \ '--passwordfile[Path to a file containing your password as its first line]' \ '--check[Check login status.]' \ '(-h --help)'{-h,--help}'[output usage information]' \ "*::arg:->args" } function _bw_logout { } function _bw_lock { } function _bw_unlock { _arguments -C \ '--check[Check lock status.]' \ '--passwordenv[Environment variable storing your password]' \ '--passwordfile[Path to a file containing your password as its first line]' \ '(-h --help)'{-h,--help}'[output usage information]' \ "*::arg:->args" } function _bw_sync { _arguments -C \ '(-f --force)'{-f,--force}'[Force a full sync.]' \ '--last[Get the last sync date.]' \ '(-h --help)'{-h,--help}'[output usage information]' \ "*::arg:->args" } function _bw_generate { _arguments -C \ '(-u --uppercase)'{-u,--uppercase}'[Include uppercase characters.]' \ '(-l --lowercase)'{-l,--lowercase}'[Include lowercase characters.]' \ '(-n --number)'{-n,--number}'[Include numeric characters.]' \ '(-s --special)'{-s,--special}'[Include special characters.]' \ '(-p --passphrase)'{-p,--passphrase}'[Generate a passphrase.]' \ '--length[Length of the password.]' \ '--words[Number of words.]' \ '--separator[Word separator.]' \ '(-c --capitalize)'{-c,--capitalize}'[Title case passphrase.]' \ '--includeNumber[Passphrase includes number.]' \ '(-h --help)'{-h,--help}'[output usage information]' \ "*::arg:->args" } function _bw_encode { } function _bw_config { _arguments -C \ '--web-vault[Provides a custom web vault URL that differs from the base URL.]' \ '--api[Provides a custom API URL that differs from the base URL.]' \ '--identity[Provides a custom identity URL that differs from the base URL.]' \ '--icons[Provides a custom icons service URL that differs from the base URL.]' \ '--notifications[Provides a custom notifications URL that differs from the base URL.]' \ '--events[Provides a custom events URL that differs from the base URL.]' \ '--key-connector[Provides the URL for your Key Connector server.]' \ '(-h --help)'{-h,--help}'[output usage information]' \ "*::arg:->args" } function _bw_update { } function _bw_completion { _arguments -C \ '--shell[Shell to generate completions for.]' \ '(-h --help)'{-h,--help}'[output usage information]' \ "*::arg:->args" } function _bw_status { } function _bw_list { _arguments -C \ '--search[Perform a search on the listed objects.]' \ '--url[Filter items of type login with a url-match search.]' \ '--folderid[Filter items by folder id.]' \ '--collectionid[Filter items by collection id.]' \ '--organizationid[Filter items or collections by organization id.]' \ '--trash[Filter items that are deleted and in the trash.]' \ '(-h --help)'{-h,--help}'[output usage information]' \ "*::arg:->args" } function _bw_get { _arguments -C \ '--itemid[Attachment'"'"'s item id.]' \ '--output[Output directory or filename for attachment.]' \ '--organizationid[Organization id for an organization object.]' \ '(-h --help)'{-h,--help}'[output usage information]' \ "*::arg:->args" } function _bw_create { _arguments -C \ '--file[Path to file for attachment.]' \ '--itemid[Attachment'"'"'s item id.]' \ '--organizationid[Organization id for an organization object.]' \ '(-h --help)'{-h,--help}'[output usage information]' \ "*::arg:->args" } function _bw_edit { _arguments -C \ '--organizationid[Organization id for an organization object.]' \ '(-h --help)'{-h,--help}'[output usage information]' \ "*::arg:->args" } function _bw_delete { _arguments -C \ '--itemid[Attachment'"'"'s item id.]' \ '--organizationid[Organization id for an organization object.]' \ '(-p --permanent)'{-p,--permanent}'[Permanently deletes the item instead of soft-deleting it (item only).]' \ '(-h --help)'{-h,--help}'[output usage information]' \ "*::arg:->args" } function _bw_restore { } function _bw_move { } function _bw_confirm { _arguments -C \ '--organizationid[Organization id for an organization object.]' \ '(-h --help)'{-h,--help}'[output usage information]' \ "*::arg:->args" } function _bw_import { _arguments -C \ '--formats[List formats]' \ '--organizationid[ID of the organization to import to.]' \ '(-h --help)'{-h,--help}'[output usage information]' \ "*::arg:->args" } function _bw_export { _arguments -C \ '--output[Output directory or filename.]' \ '--format[Export file format.]' \ '--organizationid[Organization id for an organization.]' \ '(-h --help)'{-h,--help}'[output usage information]' \ "*::arg:->args" } function _bw_share { } function _bw_send { local -a commands _arguments -C \ '(-f --file)'{-f,--file}'[Specifies that is a filepath]' \ '(-d --deleteInDays)'{-d,--deleteInDays}'[The number of days in the future to set deletion date, defaults to 7]' \ '(-a --maxAccessCount)'{-a,--maxAccessCount}'[The amount of max possible accesses.]' \ '--hidden[Hide in web by default. Valid only if --file is not set.]' \ '(-n --name)'{-n,--name}'[The name of the Send. Defaults to a guid for text Sends and the filename for files.]' \ '--notes[Notes to add to the Send.]' \ '--fullObject[Specifies that the full Send object should be returned rather than just the access url.]' \ '(-h --help)'{-h,--help}'[output usage information]' \ "1: :->cmnds" \ "*::arg:->args" case $state in cmnds) commands=( "list:List all the Sends owned by you" "template:Get json templates for send objects" "get:Get Sends owned by you." "receive:Access a Bitwarden Send from a url" "create:create a Send" "edit:edit a Send" "remove-password:removes the saved password from a Send." "delete:delete a Send" ) _describe "command" commands ;; esac case "$words[1]" in list) _bw_send_list ;; template) _bw_send_template ;; get) _bw_send_get ;; receive) _bw_send_receive ;; create) _bw_send_create ;; edit) _bw_send_edit ;; remove-password) _bw_send_remove-password ;; delete) _bw_send_delete ;; esac } function _bw_send_list { } function _bw_send_template { } function _bw_send_get { _arguments -C \ '--output[Output directory or filename for attachment.]' \ '--text[Specifies to return the text content of a Send]' \ '(-h --help)'{-h,--help}'[output usage information]' \ "*::arg:->args" } function _bw_send_receive { _arguments -C \ '--password[Password needed to access the Send.]' \ '--passwordenv[Environment variable storing the Send'"'"'s password]' \ '--passwordfile[Path to a file containing the Sends password as its first line]' \ '--obj[Return the Send'"'"'s json object rather than the Send's content]' \ '--output[Specify a file path to save a File-type Send to]' \ '(-h --help)'{-h,--help}'[output usage information]' \ "*::arg:->args" } function _bw_send_create { _arguments -C \ '--file[file to Send. Can also be specified in parent'"'"'s JSON.]' \ '--text[text to Send. Can also be specified in parent'"'"'s JSON.]' \ '--hidden[text hidden flag. Valid only with the --text option.]' \ '--password[optional password to access this Send. Can also be specified in JSON]' \ '(-h --help)'{-h,--help}'[output usage information]' \ "*::arg:->args" } function _bw_send_edit { _arguments -C \ '--itemid[Overrides the itemId provided in [encodedJson]]' \ '(-h --help)'{-h,--help}'[output usage information]' \ "*::arg:->args" } function _bw_send_remove-password { } function _bw_send_delete { } function _bw_receive { _arguments -C \ '--password[Password needed to access the Send.]' \ '--passwordenv[Environment variable storing the Send'"'"'s password]' \ '--passwordfile[Path to a file containing the Sends password as its first line]' \ '--obj[Return the Send'"'"'s json object rather than the Send's content]' \ '--output[Specify a file path to save a File-type Send to]' \ '(-h --help)'{-h,--help}'[output usage information]' \ "*::arg:->args" } ❯ eval "$(bw completion --shell zsh)" zsh: parse error near `)' ❯ eval "$(bw completion --shell zsh); compdef _bw bw;" zsh: parse error near `)' ```
MGibson1 commented 2 years ago

I'm not sure what the difference is, I've tested completion in both mac and linux against zsh 5.8 and see no issues.

The output diffs are identical too. Do you have any extensions that may be altering expectations for completion?

latipun7 commented 2 years ago

This is weird, indeed. I don't know what extensions might cause this. Is this zsh extensions? Then I tried evaluating the completion from root with clean zsh profile but still no luck:

ROG# eval "$(cat /home/latipun/.local/share/omz-custom/plugins/zsh-latipun/_bw)" 
zsh: parse error near `)'

I don't know if this problem only on my end. But this is occurring in my 2 (all) of my machines ...

latipun7 commented 1 year ago

Found the Issue

This command is producing ANSI codes to the output. Here is what I meant: run this: bw completion --shell zsh > _bw so that command redirected and outputting it in _bw file. Here's what I got when I tried to edit that file in nvim: image That was what caused the zsh parse error.

My workaround

For now, I need to strip the ANSI myself.

bw completion --shell zsh | sed -r "s/\x1B\[([0-9]{1,3}(;[0-9]{1,2})?)?[mGK]//g" > _bw

_bw file is in fpath, now the completion is works. image

Ideal

I hope I don't need to strip this manually. The output of bw completion should not produce color format / ANSI codes.

BachoSeven commented 6 months ago

@latipun7 On my system the completions don't seem to work even though the ANSI codes are not generated by the commmand anymore, is it just me?

reedjosh commented 4 months ago

@BachoSeven Same issue here 😢

reedjosh commented 4 months ago
#compdef bw
compdef _bw bw

Added this to the top of teh completions, and it is now working for me.

I noticed another working completion file used this pattern. Don't understand it much, but gonna run with it since it's working 🤷

reedjosh commented 4 months ago
compdef _bw bw
source <(bw completion --shell zsh 2>/dev/null)

Those two lines in my zshrc seem sufficient.

valorisa commented 2 months ago
#compdef bw
compdef _bw bw

Added this to the top of teh completions, and it is now working for me.

I noticed another working completion file used this pattern. Don't understand it much, but gonna run with it since it's working 🤷

Hello, Could you please precise this : 'Added this to the top of teh completions, and it is now working for me.' ? Because when I # run the command, eval "$(bw completion --shell zsh); compdef _bw bw;" I obtain "zsh: command not found: compdef" from zsh shell in macOS Sonoma (arch arm64). Thanks.

BachoSeven commented 2 months ago

@valorisa You need compinit enabled in your zsh config; i.e. autoload -U compinit; compinit in your .zshrc:

https://wiki.archlinux.org/title/Zsh#Simple_.zshrc

valorisa commented 2 months ago

@valorisa You need compinit enabled in your zsh config; i.e. autoload -U compinit; compinit in your .zshrc:

https://wiki.archlinux.org/title/Zsh#Simple_.zshrc

Thanks