mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-06 18:18:51 +00:00
cc32b4f2a7
This is opt-in through a new feature flag "ampersand-nobg-in-token". When this flag and "qmark-noglob" are enabled, this command no longer needs quoting: curl https://example.com/thing?foo=bar&duran=duran Compared to the previous approach e1570a4 ("Let '&' only separate as the first char of a word"), this has some advantages: 1. "&&" and "&>" are no longer affected. They are still special, even if used between tokens without spaces, like "echo bar&>foo". Maybe this is not really *better*, but it avoids risking to annoy users by breaking the old variant. 2. "&" is still special if at the end of a token, like in "sleep 1&". Word movement is not affected by the semantics change, so Alt-F and friends still stop at every "&".
67 lines
2.4 KiB
C++
67 lines
2.4 KiB
C++
#include "config.h" // IWYU pragma: keep
|
|
|
|
#include "future_feature_flags.h"
|
|
|
|
#include <cwchar>
|
|
|
|
#include "wcstringutil.h"
|
|
|
|
features_t::features_t() {
|
|
for (const metadata_t &md : metadata) {
|
|
this->set(md.flag, md.default_value);
|
|
}
|
|
}
|
|
|
|
/// The set of features applying to this instance.
|
|
features_t features_t::global_features;
|
|
|
|
const features_t::metadata_t features_t::metadata[features_t::flag_count] = {
|
|
{stderr_nocaret, L"stderr-nocaret", L"3.0", L"^ no longer redirects stderr", true},
|
|
{qmark_noglob, L"qmark-noglob", L"3.0", L"? no longer globs", false},
|
|
{string_replace_backslash, L"regex-easyesc", L"3.1", L"string replace -r needs fewer \\'s",
|
|
false},
|
|
{ampersand_nobg_in_token, L"ampersand-nobg-in-token", L"3.4",
|
|
L"& only backgrounds if followed by a separating character", false},
|
|
};
|
|
|
|
const struct features_t::metadata_t *features_t::metadata_for(const wchar_t *name) {
|
|
assert(name && "null flag name");
|
|
for (const auto &md : metadata) {
|
|
if (!std::wcscmp(name, md.name)) return &md;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void features_t::set_from_string(const wcstring &str) {
|
|
wcstring_list_t entries = split_string(str, L',');
|
|
const wchar_t *whitespace = L"\t\n\v\f\r ";
|
|
for (wcstring entry : entries) {
|
|
if (entry.empty()) continue;
|
|
|
|
// Trim leading and trailing whitespace
|
|
entry.erase(0, entry.find_first_not_of(whitespace));
|
|
entry.erase(entry.find_last_not_of(whitespace) + 1);
|
|
|
|
const wchar_t *name = entry.c_str();
|
|
bool value = true;
|
|
// A "no-" prefix inverts the sense.
|
|
if (string_prefixes_string(L"no-", name)) {
|
|
value = false;
|
|
name += const_strlen("no-");
|
|
}
|
|
// Look for a feature with this name. If we don't find it, assume it's a group name and set
|
|
// all features whose group contain it. Do nothing even if the string is unrecognized; this
|
|
// is to allow uniform invocations of fish (e.g. disable a feature that is only present in
|
|
// future versions).
|
|
// The special name 'all' may be used for those who like to live on the edge.
|
|
if (const metadata_t *md = metadata_for(name)) {
|
|
this->set(md->flag, value);
|
|
} else {
|
|
for (const metadata_t &md : metadata) {
|
|
if (std::wcsstr(md.groups, name) || !std::wcscmp(name, L"all")) {
|
|
this->set(md.flag, value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|