Skip to content

Commit

Permalink
[stub] fix(mount): remove problematic reduction of in-word prefix
Browse files Browse the repository at this point in the history
With the current implementation, the originally specified options
vanish on the tab completion when they are quoted.  For example, with
the following example, 'abort' will be removed.

$ mount -o 'abort',a[TAB]

The variable `prev` in this context is originally extracted from
`cur`, which is the word after splitting by COMP_WORDBREAKS.  This
means that an additional splitting should not be needed.  Even if
special characters are included in `prev`, they must be quoted in
order to appear there so should not be considered wordbreaks.

The code was originally introduced in commit db8d3ee (2011-01-19),
where no context is given.
  • Loading branch information
akinomyoga committed May 13, 2024
1 parent 6b117a5 commit 576f23d
Showing 1 changed file with 68 additions and 3 deletions.
71 changes: 68 additions & 3 deletions completions/_mount.linux
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,74 @@ _comp_cmd_mount()
;;&
esac
# COMP_WORDBREAKS is a real pain in the ass
if ((${#COMPREPLY[@]})) && [[ $prefix == *["$COMP_WORDBREAKS"]* ]]; then
local tmp=${prefix%["$COMP_WORDBREAKS"]*}
COMPREPLY=("${COMPREPLY[@]#"$tmp"?}")
#
# TODO: We need to consider many cases for COMP_WORDBREAKS. The
# test cases are the following, where Bash expects the completion
# for the part indicated by ~:
#
# #1 mount -o abort,var=value,auto_[TAB]
# ~~~~~~~~~~~
#
# #2 mount -o 'abort',auto_[TAB]
# ~~~~~~~~~~~~~
#
# #3 mount -o 'var=value',auto_[TAB]
# ~~~~~~~~~~~~~~~~~
#
# #4 mount -o abort,'auto_[TAB]
# ~~~~~
#
# We can think about several solutions, but none seems to work
# currently.
#
# a The current code removes `*[$COMP_WORDBREAKS]` from the prefix.
#
# if ((${#COMPREPLY[@]})) && [[ $prefix == *["$COMP_WORDBREAKS"]* ]]; then
# local tmp=${prefix%[:=]*}
# COMPREPLY=("${COMPREPLY[@]#"$tmp"?}")
# fi
#
# b One possible solution is to remove `*[:=]` instead of
# `*[$COMP_WORDBREAKS]` from the prefix. This will make #1 and
# #2 work correctly, but still #3 does not work in this case.
#
# if ((${#COMPREPLY[@]})) && [[ $prefix == *[:=]* ]]; then
# local tmp=${prefix%["$COMP_WORDBREAKS"]*}
# COMPREPLY=("${COMPREPLY[@]#"$tmp"?}")
# fi
#
# c Then to handle #3, one might consider remove only unquoted
# [:=], but it would be technically difficult to preserve quoted
# [:=]. In addition, even with this can be achieved, #4 will not
# be fixed.
#
# d Or do nothing here for now.
#
# e One can use `comp_args[1]` to see which part Bash thinks is the
# completed part.
#
# However this still has a problem. When the starting point of
# the completion is in the middle of a field after a comma, one
# first needs to generate the candidates and then remove the
# prefix that is not considered the completed part. The problem
# is that the generated candidates do not necessarily match the
# original text because the builtin compgen can remove the quotes
# even if we specify the quoted word as the current word. For
# example, for #4, `${comp_args[1]}` becomes `auto_`. Then we
# attempt `compgen -P abort, -W auto_da_alloc -- "'auto_"` to
# obtain `abort,auto_da_alloc`, where we cannot remove `abort,'`
# because the single quote is missing.
#
# | | #1 | #2 | #3 | #4 |
# |:--|:----:|:----:|:----:|:----:|
# | a | ok | fail | fail | fail |
# | b | ok | ok | fail | fail |
# | c | ok | ok | ok | fail |
# | d | fail | ok | ok | fail |
#
if ((${#COMPREPLY[@]})) && [[ $prefix == *[:=]* ]]; then
local tmp=${prefix%[:=]*}
COMPREPLY=("${COMPREPLY[@]#"$tmp"?}")
fi
[[ ${COMPREPLY-} == *= ]] && compopt -o nospace
return
Expand Down

0 comments on commit 576f23d

Please sign in to comment.