Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bash tab completion doesn't handle backslashes correctly #100

Open
JeffFaer opened this issue Apr 18, 2024 · 3 comments
Open

Bash tab completion doesn't handle backslashes correctly #100

JeffFaer opened this issue Apr 18, 2024 · 3 comments

Comments

@JeffFaer
Copy link

JeffFaer commented Apr 18, 2024

I have some bash completions which end up including special characters, but it looks like the tab completion here doesn't quite handle them correctly.

I was able to reproduce the issue I've been running into:

generate_suggestions() {
  local suggestions=(
    abcd
    efgh
    ijkl
    '\\@today'
  )
  local i
  for ((i=0; i < ${#suggestions[@]}; i++)); do
    # compgen -W respects shell quoting, so we need to escape special
    # characters.
    suggestions[i]="$(printf "%q" "${suggestions[i]}")"
  done

  local cur="${COMP_WORDS[COMP_CWORD]}"
  # compgen -W respects shell quoting _after_ checking to make sure elements of
  # the wordlist start with ${cur}, so we need to escape it, too.
  cur="$(printf "%q" "${cur}")"

  mapfile -t COMPREPLY < <(compgen -W "${suggestions[*]}" -- "${cur}")
}

complete -F generate_suggestions complete.bash

The goal of this is to put the string \\@today on the command line so that it passes \@today to the program when executed.


With regular bash completion:

  • complete.bash <TAB> generates abcd efgh ijkl \\@today
  • complete.bash \<TAB> autofills \\@today
  • complete.bash \\<TAB> autofills \\@today

With fzf_bash_completion:

  • complete.bash <TAB> generates abcd efgh ijkl \\@today, if I select \\@today it's entered onto the command line correctly
  • complete.bash \<TAB> autofills \\@today
  • complete.bash \\<TAB> autofills \@today, losing a backslash

If you add another entry with a similar prefix, say \\@tomorrow and set FZF_COMPLETION_AUTO_COMMON_PREFIX and FZF_COMPLETION_AUTO_COMMON_PREFIX_PART:

  • complete.bash \<TAB> autofills \\@to
  • complete.bash \\@to<TAB> generates \@today \@tomorrow, losing a backslash
  • complete.bash \\<TAB> autofills \@to, losing a backslash
@lincheney
Copy link
Owner

I can't reproduce this, but I think it is possible this is fixed as a result of #91 (comment)

@JeffFaer
Copy link
Author

JeffFaer commented May 1, 2024

I can't reproduce my example anymore either, so it looks something about this problem has changed, but now I've found a new issue:

Tab completion seems to be processing escape sequences and splitting words as a result

#!/usr/bin/env bash

generate_suggestions() {
  local suggestions=(
    'foo\>bar1'
    'foo\>bar2'
  )
  local i
  for ((i=0; i < ${#suggestions[@]}; i++)); do
    # compgen -W respects shell quoting, so we need to escape special
    # characters.
    suggestions[i]="$(printf "%q" "${suggestions[i]}")"
  done

  local cur="${COMP_WORDS[COMP_CWORD]}"
  # compgen -W respects shell quoting _after_ checking to make sure elements of
  # the wordlist start with ${cur}, so we need to escape it, too.
  cur="$(printf "%q" "${cur}")"

  mapfile -t COMPREPLY < <(compgen -W "${suggestions[*]}" -- "${cur}")

  local log="completion.log"
  {
    echo "COMP_WORDS"
    local i
    for ((i=0; i < "${#COMP_WORDS[@]}"; i++)); do
      local cur=" "
      if ((i == COMP_CWORD)); then
        cur="*"
      fi
      echo "${cur}${i}: ${COMP_WORDS[i]}"
    done
    echo "COMPREPLY"
    local i
    for i in "${COMPREPLY[@]}"; do
      echo "${i}"
    done
  } >> "${log}"
}

complete -F generate_suggestions complete.bash

With regular bash completion:

  • complete.bash <TAB> autofills foo\>bar and logs
    COMPWORDS
     0: complete.bash
    *1: 
    COMPREPLY
    foo\>bar1
    foo\>bar2
    
  • complete.bash foo\>bar<TAB> displays foo\>bar1 foo\>bar2 and logs
    COMPWORDS
     0: complete.bash
    *1: foo\>bar
    COMPREPLY
    foo\>bar1
    foo\>bar2
    

With fzf_bash_completion

  • complete.bash <TAB> autofills foo\>bar and logs the same as regular bash completion
  • complete.bash foo\>bar<TAB> displays nothing and logs
    COMPWORDS
     0: complete.bash
     1: foo>
    *2: bar
    COMPREPLY
    

@KGoodacre
Copy link

@lincheney
Is there a way to enable tab completion for directories without using “cd”? I have autocd enabled (“shopt -s autocd”) and it fzf will not invoke unless I type either “cd” or “./“ before I tab.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants