Repository navigation
Conversation
Bash 4.3..5.3 may call the completion function of a meta-command for
the command name itself, with COMP_CWORD=0. For example, `A= ./d[TAB]o`
calls the one for `do` (`_comp_command`) with COMP_LINE=./do and
COMP_POINT=3. The offset of 1 then points past the current word:
COMP_POINT becomes negative ("COMP_POINT: substring expression < 0"),
and for `A= ./do[TAB] ;` COMP_WORDS becomes empty, so nothing is
completed (or "COMP_WORDS[0]: unbound variable" under nounset).
Clamp the offset to the current word so that it is completed as a
command name, as Bash does without bash-completion loaded.
Closes scop#1383
Closes scop#768
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bash 4.3..5.3 may call the completion function of a meta-command for the command name itself, with
COMP_CWORD=0(as found in #1383, where it was identified as a Bash bug). ForA= ./d[TAB]o, the function fordo(_comp_command) is called withCOMP_LINE=./do,COMP_POINT=3,COMP_WORDS=(./do)._comp_commandpasses offset 1 to_comp_command_offset, which points past the current word:A= ./d[TAB]o:COMP_POINTbecomes -1, and_comp_get_wordsprintsbash: COMP_POINT: substring expression < 0(COMP_POINT: substring expression < 0 when completing A= ./do #1383).A= ./do[TAB] ;:COMP_WORDSbecomes empty and nothing is completed; withnounsetit printsbash: COMP_WORDS[0]: unbound variable(COMP_WORDS: bad array subscript #768; theCOMP_WORDS[-1]line quoted there has since changed, but the emptyCOMP_WORDSremains).This clamps the offset to the current word, so the word is completed as a command name through the existing
COMP_CWORD == 0branch (_comp_compgen_commands). That matches what Bash does with no bash-completion loaded: in both cases./dofile(an executable) is completed.Callers other than
_comp_command/_comp_root_commandgo through_comp_initialize, which already returns early forcword <= 0, so they do not reach this path.Closes #1383
Closes #768
Testing
New
test_cword0cases intest/t/unit/test_unit_command_offset.pyemulate the Bash call (COMP_CWORD=0,COMP_WORDS=(./com)) for the two cursor positions above and expect./completerfrom the_command_offsetfixture dir.Run on macOS with Bash 5.3.0 built from the GNU release tarball (
BASH_COMPLETION_TEST_BASH):bash_completionchange, both new cases fail:Unexpected output: [bash: COMP_POINT: substring expression < 0andUnexpected output: [bash: COMP_WORDS[0]: unbound variable. With it:t/unit/test_unit_command_offset.py17 passed.--norc, onlybash_completionsourced):A= ./d[TAB]o,A= ./do[TAB] ;,var= ./do[TAB] ;andA= ./do; xwith the cursor after./donow complete./dofilethe same way as Bash without bash-completion;A= ./do[TAB]andnice ./do[TAB]are unchanged.t/unitand 691 of the 730t/test_*.pyfiles (ssh/scp/rsync, network and database client tests excluded) with-n 8: the same pre-existing macOS failures as on main (test_aclocal,test_tar::test_25,test_vipw, intermittentlytest_ps/test_cpio, and environment-diff errors frombash: child setpgid ...: Operation not permitted), nothing new.shellcheck -f gcc bash_completion(0.11.0) andshfmt -d bash_completion(3.14.1) are clean;ruff check/ruff format --check(0.15.20) clean on the test file.Not run: Bash versions other than 5.3 (the CI matrix covers those),
test/runLint(needs GNUgrep -P), the excluded test files, and prek/mypy.Side note, unrelated to this change:
test_cmd_quotedin the same file fails when run on its own on main (pytest t/unit/test_unit_command_offset.py::TestUnitCommandOffset::test_cmd_quoted), because it relies ontest_2[cmd2]having replaced thecmd2compspec first in the shared class-scoped shell. With-nit can fail depending on how tests are distributed across workers.