szermatt / emacs-bash-completion

Add programmable bash completion to Emacs shell-mode
GNU General Public License v2.0
281 stars 33 forks source link

Bad interaction with process substitution in completion scripts? #74

Closed jwhitbeck closed 1 week ago

jwhitbeck commented 1 week ago

Thanks for bash-completion.el. I've been using M-x shell for years, and bash-completion.el has been a key part of that workflow.

Recently, I noticed what appears to be a small bug with completion scripts that use Bash process substitution. I originally noticed it when using LXC, whose bash completion script invokes the following idiom

mapfile -t names ... < <(...)

For LXC, bash completion (e.g., lxc-info <tab>) works as expected from Gnome Terminal, but doesn't work in Emacs's shell.el.

Here is a minimal reproduction case.

_mycmd() {  
  readarray -t opts < <(printf "foo\nbar")
  COMPREPLY=($(compgen -W "${opts[*]}" -- "${COMP_WORDS[$COMP_CWORD]}"))
}

complete -F _mycmd mycmd

In Gnome Terminal, mycmd <tab> proposes foo and bar completions as expected, but bash-completion.el returns with No completion found.

Here is the output of M-x bash-completion-debug. I'm using bash-completion.el from master (0f4f7ab45648d5fed0f8a67526c1a6902754f84c).

commandline: <<EOF
if type __ebcpre &>/dev/null; then   __ebcpre; __EBCWRAPPER='COMP_LINE='\''mycmd '\''; COMP_POINT=$(( 1 + ${#COMP_LINE} )); COMP_CWORD=1; COMP_WORDS=( mycmd '\'''\'' ); _mycmd mycmd '\'''\'' mycmd' __ebcompgen -F __ebcwrapper -- ''; else   echo ==emacs==nopre=${BASH_VERSION}==.;   __ebcp=("$PS1" "$PROMPT_COMMAND");  unset PS1 PROMPT_COMMAND;fi;
EOF

status: 0
process: #<process shell>
output-buffer: <<EOF
EOF

emacs-version: "28.2"
bash-version: "5.2.15(1)-release"
bash-version: "5.2.15(1)-release"
context: #s(completion "mycmd "
          ("mycmd" "")
          1 "" 8546 "" nil
          ("-F" "_mycmd")
          "\"'><=;|&(:" nil)

Note that both work as expected if I change the completion script above as follows.

_mycmd() {  
  opts=$(printf "foo\nbar")
  COMPREPLY=($(compgen -W "${opts}" -- "${COMP_WORDS[$COMP_CWORD]}"))
}

complete -F _mycmd mycmd
szermatt commented 1 week ago

Thank you for the bug and especially thank you for the minimal reproduction case! That really made things much easier!

The good news is that I can reproduce the issue. The bad news is that I have no idea what's going on at this point. This is very puzzling.

This is an issue with bash 5.2.15 but not with bash 5.2.37 (which I have installed on my laptop.) My best guess at this point is that bash-completion.el does something that confuses some versions of bash when running functions that use this particular idiom. I'm trying to understand what that is.

For now, as a workaround, you can do one of the following:

szermatt commented 1 week ago

Actually, after more tests, it seems now that there are intermittent failures, no matter the version of bash, so switching to a more recent version of bash might not work.

szermatt commented 1 week ago

This should work now, with the latest git version. A new version with a fix should be on available on melpa tomorrow. Please let me know if you're still having issues.

jwhitbeck commented 1 week ago

I just upgraded this morning and the new release works like a charm. Thanks for the fix and the fast turnaround!