Join variables by their delimiter in quoted expansion

This switches quoted expansion like "$foo" to use foo's delimiter instead of
space. The delimiter is space for normal variables and colonf or path variables.
Expansions like "$PATH" will now expand using ':'.
This commit is contained in:
ridiculousfish 2018-09-30 19:34:01 -04:00
parent 3f3b3a7006
commit 5947aa0171
9 changed files with 41 additions and 13 deletions

View File

@ -1898,7 +1898,18 @@ wcstring_list_t split_string(const wcstring &val, wchar_t sep) {
}
wcstring join_strings(const wcstring_list_t &vals, wchar_t sep) {
if (vals.empty()) return wcstring{};
// Reserve the size we will need.
// count-1 separators, plus the length of all strings.
size_t size = vals.size() - 1;
for (const wcstring &s : vals) {
size += s.size();
}
// Construct the string.
wcstring result;
result.reserve(size);
bool first = true;
for (const wcstring &s : vals) {
if (!first) {

View File

@ -1302,10 +1302,13 @@ int env_remove(const wcstring &key, int var_mode) {
const wcstring_list_t &env_var_t::as_list() const { return vals; }
wchar_t env_var_t::get_delimiter() const {
return is_pathvar() ? PATH_ARRAY_SEP : NONPATH_ARRAY_SEP;
}
/// Return a string representation of the var.
wcstring env_var_t::as_string() const {
wchar_t sep = is_pathvar() ? PATH_ARRAY_SEP : NONPATH_ARRAY_SEP;
return join_strings(vals, sep);
return join_strings(vals, get_delimiter());
}
void env_var_t::to_list(wcstring_list_t &out) const {

View File

@ -101,6 +101,9 @@ class env_var_t {
void to_list(wcstring_list_t &out) const;
const wcstring_list_t &as_list() const;
/// \return the character used when delimiting quoted expansion.
wchar_t get_delimiter() const;
void set_vals(wcstring_list_t v) { vals = std::move(v); }
void set_exports(bool exportv) {

View File

@ -447,6 +447,9 @@ static bool expand_variables(wcstring instr, std::vector<completion_t> *out, siz
}
if (is_single) {
// Quoted expansion. Here we expect the variable's delimiter.
// Note history always has a space delimiter.
wchar_t delimit = history ? L' ' : var->get_delimiter();
wcstring res(instr, 0, varexp_char_idx);
if (!res.empty()) {
if (res.back() != VARIABLE_EXPAND_SINGLE) {
@ -457,15 +460,8 @@ static bool expand_variables(wcstring instr, std::vector<completion_t> *out, siz
}
}
// Append all entries in var_item_list, separated by spaces.
// Remove the last space.
if (!var_item_list.empty()) {
for (const wcstring &item : var_item_list) {
res.append(item);
res.push_back(L' ');
}
res.pop_back();
}
// Append all entries in var_item_list, separated by the delimiter.
res.append(join_strings(var_item_list, delimit));
res.append(instr, var_name_and_slice_stop, wcstring::npos);
return expand_variables(std::move(res), out, varexp_char_idx, errors);
} else {

View File

@ -19,3 +19,6 @@ echo $$paren
####################
# Test tilde expansion
####################
# Test delimiters

View File

@ -126,3 +126,8 @@ end
unlink $tmpdir/linkhome
rmdir $tmpdir/realhome
rmdir $tmpdir
logmsg Test delimiters
set TEST_DELIMITER one two three
set TEST_DELIMITER_PATH one two three
echo "$TEST_DELIMITER" "$TEST_DELIMITER_PATH"

View File

@ -73,3 +73,7 @@ All digits: 0
####################
# Test tilde expansion
####################
# Test delimiters
one two three one:two:three

View File

@ -306,8 +306,9 @@ set -gx FOOPATH one two three four
../test/root/bin/fish -c 'echo Elements in FOO and FOOPATH: (count $FOO) (count $FOOPATH)'
# some must use colon separators!
set -lx MANPATH man1 man2 man3 ; env | grep '^MANPATH='
# ensure we don't escape colon values
# ensure we don't escape space and colon values
set -x DONT_ESCAPE_COLONS 1: 2: :3: ; env | grep '^DONT_ESCAPE_COLONS='
set -x DONT_ESCAPE_SPACES '1 ' '2 ' ' 3 ' 4 ; env | grep '^DONT_ESCAPE_SPACES='
set -x DONT_ESCAPE_COLONS_PATH 1: 2: :3: ; env | grep '^DONT_ESCAPE_COLONS_PATH='
true

View File

@ -44,3 +44,5 @@ Elements in DISPLAY: 1
Elements in FOO and FOOPATH: 1 4
MANPATH=man1:man2:man3
DONT_ESCAPE_COLONS=1: 2: :3:
DONT_ESCAPE_SPACES=1 2 3 4
DONT_ESCAPE_COLONS_PATH=1::2:::3: