[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Completion of ENV variables seems to be broken - leading slash (or e

From: Guillaume Outters
Subject: Re: Completion of ENV variables seems to be broken - leading slash (or even more) is added
Date: Thu, 09 Dec 2021 09:41:32 +0100
User-agent: Roundcube Webmail/0.8.5

Le 2011-03-31 21:47, Chet Ramey a écrit:

On 3/15/11 4:44 PM, Chet Ramey wrote:

The difference is that bash-4.1 expanded $HOME and left the expansion
as part of the replacement text.  Bash-4.2 tries to leave what the
user typed alone, but that leads to an inherently ambiguous situation: when do you quote the `$' in a filename (or, in this case, a directory
name)?  It could be a shell variable, and it could be a character in
the filename.

I've attached a patch that applies a heuristic.  If the directory name
contains a variable, and bash expands it, it removes the appropriate
characters from the set that causes readline to ask bash to quote the
filename.  It's the 90% solution.

It is not perfect: if a character in the filename needs to be quoted,
bash will still quote the `$' in the directory name.  It should handle
most of the cases, however.

I may have a partial solution: not a silver bullet, but making the "90% solution" go to 95%.

=== Idea ===

The idea behind: the part that the user typed is considered well formed (sufficently to return matches),
so try to preserve it, and do quote only the completion's additions.

=== Implementation ===

The implementation (attached) of this idea is still imperfect,
because to identify the user-typed part, I simply compare the first match to the input;
this works in the example's simple case:
as bash completion knows NOT to direxpand, the $HOME from the input is included in the returned matches, and so is considered to be preserved; the quoting happens later, on spaces.
This happens to work on unclosed quotes too (ls "$HOME/sp<TAB>),
because readline starts matching AFTER the quote, so both input and results start with $HOME/sp (without quote).

=== Limitations ===

This DOES NOT work when 1. user-typed part is fully quoted (ls "$HOME/space cowboys"/<TAB>), because readline then passes the quote to the completion function (thus making input and matches diverge), nor (theorically) when 2. a space precedes a var (ls $HOME/space\ cowboys/$SUBDIR/f<TAB>), because the input backslash will be detected as first difference, where to start quoting.

Thus, due to 1., my proposed patch will not resolve Pedro's case in
However, a workaround (without direxpand) can be to not close the quote:
  i='a b'
  ls "$i/<TAB> # Instead of ls "$i"/
(which btw seems to work without my patch).

=== Going further ===

Maybe readline could go further to resolve 1. (and reach a "97% solution"?) by handling specially when, in a closed quote string to complete, the quote character appears at first and last chars (or forelast if the last one is a directory separator): then skip the closing char to handle the string as an unclosed quote.
This would make "$i"/<TAB> work.
To test: "$i/part"/unquoted/"requoted/hey"/<TAB>: how will the middle " be handled?

=== Optionality ===

The patch can easily be deactivated (shopt?):
it works by computing a common prefix length and passing it to make_quoted_replacement,
to tell it where to start replacing.
So by forcing a common prefix length of 0, we're back on the current behavior. (by the way, this is how the patch itself falls back when it is confused by the quote_char having changed)

=== History ===

Yes, you read 2011, not 2021!

Sorry for digging up this 10-years-old subject (archeology fun!), from:
but it seems it has never been resolved,
only circumvented by direxpanding which breaks the beauty of bash knowing how to preserve a $.
(and I happen to get the problem every day)

I'm sending this to bug-readline, because it seems to be solvable by targeting readline only, but bash would be the first "client" for it (reports are found in bug-bash), and in fact I tested it and built the patch on bash's integrated lib/readline.

=== Tests ===

t=/tmp/btest ; i="$t/space cowboys" ; mkdir -p $t/solid "$i/con" "$i/contents" "$i/other" "$i/con/solid" "$i/con/space cowboys"

# Each test block lists:
# Typed sequence
Actual result with current bash + readline
Result with current bash + patched readline

# echo $t/<tab>
echo $t/s
echo $t/s

# echo $t/so<tab>
echo $t/solid/
echo $t/solid/

#echo $t/sp<tab>
echo \$t/space cowboys/ # \$ incorrect
echo $t/space cowboys/

# echo $t/space cowboys/<tab>
echo \$t/space cowboys/ # \$ incorrect
echo $t/space cowboys/

#echo "$t/sp<tab>
echo "\$t/space cowboys/" # \$ incorrect, \  unnecessary.
echo "$t/space cowboys"/

# /!\ Note there's still a problem when quotes are closed:
# echo "$t/space cowboys"/<tab>
echo \$t/space cowboys/ # \$ incorrect
echo \$t/space cowboys/ # Incorrect too
# In forelast case the unclosed " made insert_match pass only the unquoted subpart (starting at $t), which matched with the results. # In the current case insert_match passes the whole string including quotes (starting at "$t), thus match ("$t) and replacement ($t) did not match. # This is the same as https://lists.gnu.org/archive/html/bug-bash/2021-06/msg00131.html # This could perhaps be handled by passing longest_prefix() the quote_char, so that it accepts comparing "$t" with $t when quote_char is "
# (like compare_match does).
# Or forcing callers *NOT* to dequote their matches (by temporarily inhibiting rl_filename_dequoting_function, mapping it to a function that
# removes quotes but not backslashes?).

# /!\ Note that I did *NOT* regress-test against a litteral $ in a filename.


Attachment: readline.non-intrusive-completion-quoting.8.1.patch
Description: Text Data

reply via email to

[Prev in Thread] Current Thread [Next in Thread]