mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-28 20:55:11 +00:00
commit
b66e5ea5ea
9 changed files with 59 additions and 8 deletions
|
@ -1040,6 +1040,7 @@ static void escape_string_script(const wchar_t *orig_in, size_t in_len, wcstring
|
||||||
case L'|':
|
case L'|':
|
||||||
case L';':
|
case L';':
|
||||||
case L'"':
|
case L'"':
|
||||||
|
case L'%':
|
||||||
case L'~': {
|
case L'~': {
|
||||||
bool char_is_normal = (c == L'~' && no_tilde) || (c == L'^' && no_caret) ||
|
bool char_is_normal = (c == L'~' && no_tilde) || (c == L'^' && no_caret) ||
|
||||||
(c == L'?' && no_qmark);
|
(c == L'?' && no_qmark);
|
||||||
|
@ -1398,6 +1399,17 @@ static bool unescape_string_internal(const wchar_t *const input, const size_t in
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case L'%': {
|
||||||
|
// Note that this only recognizes %self if the string is literally %self.
|
||||||
|
// %self/foo will NOT match this.
|
||||||
|
if (unescape_special && input_position == 0 &&
|
||||||
|
!wcscmp(input, PROCESS_EXPAND_SELF_STR)) {
|
||||||
|
to_append_or_none = PROCESS_EXPAND_SELF;
|
||||||
|
input_position +=
|
||||||
|
wcslen(PROCESS_EXPAND_SELF_STR) - 1; // skip over 'self' part.
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case L'*': {
|
case L'*': {
|
||||||
if (unescape_special) {
|
if (unescape_special) {
|
||||||
// In general, this is ANY_STRING. But as a hack, if the last appended char
|
// In general, this is ANY_STRING. But as a hack, if the last appended char
|
||||||
|
|
|
@ -924,7 +924,7 @@ void env_init(const struct config_paths_t *paths /* or NULL */) {
|
||||||
wcstring version = str2wcstring(get_fish_version());
|
wcstring version = str2wcstring(get_fish_version());
|
||||||
env_set_one(L"version", ENV_GLOBAL, version);
|
env_set_one(L"version", ENV_GLOBAL, version);
|
||||||
|
|
||||||
// Set the $fish_pid variable (%self replacement)
|
// Set the $fish_pid variable.
|
||||||
env_set_one(L"fish_pid", ENV_GLOBAL, to_string<long>(getpid()));
|
env_set_one(L"fish_pid", ENV_GLOBAL, to_string<long>(getpid()));
|
||||||
|
|
||||||
// Set the $hostname variable
|
// Set the $hostname variable
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
|
|
||||||
/// Characters which make a string unclean if they are the first character of the string. See \c
|
/// Characters which make a string unclean if they are the first character of the string. See \c
|
||||||
/// expand_is_clean().
|
/// expand_is_clean().
|
||||||
#define UNCLEAN_FIRST L"~"
|
#define UNCLEAN_FIRST L"~%"
|
||||||
/// Unclean characters. See \c expand_is_clean().
|
/// Unclean characters. See \c expand_is_clean().
|
||||||
#define UNCLEAN L"$*?\\\"'({})"
|
#define UNCLEAN L"$*?\\\"'({})"
|
||||||
|
|
||||||
|
@ -784,6 +784,13 @@ static void expand_home_directory(wcstring &input) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Expand the %self escape. Note this can only come at the beginning of the string.
|
||||||
|
static void expand_percent_self(wcstring &input) {
|
||||||
|
if (!input.empty() && input.front() == PROCESS_EXPAND_SELF) {
|
||||||
|
input.replace(0, 1, to_string<long>(getpid()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void expand_tilde(wcstring &input) {
|
void expand_tilde(wcstring &input) {
|
||||||
// Avoid needless COW behavior by ensuring we use const at.
|
// Avoid needless COW behavior by ensuring we use const at.
|
||||||
const wcstring &tmp = input;
|
const wcstring &tmp = input;
|
||||||
|
@ -934,12 +941,13 @@ static expand_error_t expand_stage_braces(wcstring input, std::vector<completion
|
||||||
return expand_braces(input, flags, out, errors);
|
return expand_braces(input, flags, out, errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
static expand_error_t expand_stage_home(wcstring input, std::vector<completion_t> *out,
|
static expand_error_t expand_stage_home_and_self(wcstring input, std::vector<completion_t> *out,
|
||||||
expand_flags_t flags, parse_error_list_t *errors) {
|
expand_flags_t flags, parse_error_list_t *errors) {
|
||||||
(void)errors;
|
(void)errors;
|
||||||
if (!(EXPAND_SKIP_HOME_DIRECTORIES & flags)) {
|
if (!(EXPAND_SKIP_HOME_DIRECTORIES & flags)) {
|
||||||
expand_home_directory(input);
|
expand_home_directory(input);
|
||||||
}
|
}
|
||||||
|
expand_percent_self(input);
|
||||||
append_completion(out, std::move(input));
|
append_completion(out, std::move(input));
|
||||||
return EXPAND_OK;
|
return EXPAND_OK;
|
||||||
}
|
}
|
||||||
|
@ -1047,7 +1055,7 @@ expand_error_t expand_string(wcstring input, std::vector<completion_t> *out_comp
|
||||||
|
|
||||||
// Our expansion stages.
|
// Our expansion stages.
|
||||||
const expand_stage_t stages[] = {expand_stage_cmdsubst, expand_stage_variables,
|
const expand_stage_t stages[] = {expand_stage_cmdsubst, expand_stage_variables,
|
||||||
expand_stage_braces, expand_stage_home,
|
expand_stage_braces, expand_stage_home_and_self,
|
||||||
expand_stage_wildcards};
|
expand_stage_wildcards};
|
||||||
|
|
||||||
// Load up our single initial completion.
|
// Load up our single initial completion.
|
||||||
|
|
|
@ -61,6 +61,8 @@ class completion_t;
|
||||||
enum {
|
enum {
|
||||||
/// Character representing a home directory.
|
/// Character representing a home directory.
|
||||||
HOME_DIRECTORY = EXPAND_RESERVED_BASE,
|
HOME_DIRECTORY = EXPAND_RESERVED_BASE,
|
||||||
|
/// Character representing process expansion for %self.
|
||||||
|
PROCESS_EXPAND_SELF,
|
||||||
/// Character representing variable expansion.
|
/// Character representing variable expansion.
|
||||||
VARIABLE_EXPAND,
|
VARIABLE_EXPAND,
|
||||||
/// Character representing variable expansion into a single element.
|
/// Character representing variable expansion into a single element.
|
||||||
|
@ -95,6 +97,9 @@ enum expand_error_t {
|
||||||
EXPAND_WILDCARD_MATCH
|
EXPAND_WILDCARD_MATCH
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// The string represented by PROCESS_EXPAND_SELF
|
||||||
|
#define PROCESS_EXPAND_SELF_STR L"%self"
|
||||||
|
|
||||||
/// Perform various forms of expansion on in, such as tilde expansion (\~USER becomes the users home
|
/// Perform various forms of expansion on in, such as tilde expansion (\~USER becomes the users home
|
||||||
/// directory), variable expansion (\$VAR_NAME becomes the value of the environment variable
|
/// directory), variable expansion (\$VAR_NAME becomes the value of the environment variable
|
||||||
/// VAR_NAME), cmdsubst expansion and wildcard expansion. The results are inserted into the list
|
/// VAR_NAME), cmdsubst expansion and wildcard expansion. The results are inserted into the list
|
||||||
|
|
|
@ -2472,7 +2472,6 @@ static void test_complete() {
|
||||||
do_test(completions.at(1).completion == L"zero");
|
do_test(completions.at(1).completion == L"zero");
|
||||||
do_test((completions.at(1).flags & COMPLETE_NO_SPACE) != 0);
|
do_test((completions.at(1).flags & COMPLETE_NO_SPACE) != 0);
|
||||||
|
|
||||||
|
|
||||||
// Test wraps.
|
// Test wraps.
|
||||||
do_test(comma_join(complete_get_wrap_targets(L"wrapper1")) == L"");
|
do_test(comma_join(complete_get_wrap_targets(L"wrapper1")) == L"");
|
||||||
complete_add_wrapper(L"wrapper1", L"wrapper2");
|
complete_add_wrapper(L"wrapper1", L"wrapper2");
|
||||||
|
@ -4086,6 +4085,13 @@ static void test_highlighting() {
|
||||||
{L"end", highlight_spec_command},
|
{L"end", highlight_spec_command},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
highlight_tests.push_back({
|
||||||
|
{L"echo", highlight_spec_command},
|
||||||
|
{L"%self", highlight_spec_operator},
|
||||||
|
{L"not%self", highlight_spec_param},
|
||||||
|
{L"self%not", highlight_spec_param},
|
||||||
|
});
|
||||||
|
|
||||||
// Verify variables and wildcards in commands using /bin/cat.
|
// Verify variables and wildcards in commands using /bin/cat.
|
||||||
env_set(L"VARIABLE_IN_COMMAND", ENV_LOCAL, {L"a"});
|
env_set(L"VARIABLE_IN_COMMAND", ENV_LOCAL, {L"a"});
|
||||||
env_set(L"VARIABLE_IN_COMMAND2", ENV_LOCAL, {L"at"});
|
env_set(L"VARIABLE_IN_COMMAND2", ENV_LOCAL, {L"at"});
|
||||||
|
|
|
@ -121,6 +121,7 @@ bool is_potential_path(const wcstring &potential_path_fragment, const wcstring_l
|
||||||
for (size_t i = 0; i < path_with_magic.size(); i++) {
|
for (size_t i = 0; i < path_with_magic.size(); i++) {
|
||||||
wchar_t c = path_with_magic.at(i);
|
wchar_t c = path_with_magic.at(i);
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
case PROCESS_EXPAND_SELF:
|
||||||
case VARIABLE_EXPAND:
|
case VARIABLE_EXPAND:
|
||||||
case VARIABLE_EXPAND_SINGLE:
|
case VARIABLE_EXPAND_SINGLE:
|
||||||
case BRACE_BEGIN:
|
case BRACE_BEGIN:
|
||||||
|
@ -443,6 +444,12 @@ static void color_string_internal(const wcstring &buffstr, highlight_spec_t base
|
||||||
const size_t buff_len = buffstr.size();
|
const size_t buff_len = buffstr.size();
|
||||||
std::fill(colors, colors + buff_len, base_color);
|
std::fill(colors, colors + buff_len, base_color);
|
||||||
|
|
||||||
|
// Hacky support for %self which must be an unquoted literal argument.
|
||||||
|
if (buffstr == PROCESS_EXPAND_SELF_STR) {
|
||||||
|
std::fill_n(colors, wcslen(PROCESS_EXPAND_SELF_STR), highlight_spec_operator);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
enum { e_unquoted, e_single_quoted, e_double_quoted } mode = e_unquoted;
|
enum { e_unquoted, e_single_quoted, e_double_quoted } mode = e_unquoted;
|
||||||
int bracket_count = 0;
|
int bracket_count = 0;
|
||||||
for (size_t in_pos = 0; in_pos < buff_len; in_pos++) {
|
for (size_t in_pos = 0; in_pos < buff_len; in_pos++) {
|
||||||
|
@ -691,8 +698,8 @@ class highlighter_t {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructor
|
// Constructor
|
||||||
highlighter_t(const wcstring &str, size_t pos, const env_vars_snapshot_t &ev,
|
highlighter_t(const wcstring &str, size_t pos, const env_vars_snapshot_t &ev, wcstring wd,
|
||||||
wcstring wd, bool can_do_io)
|
bool can_do_io)
|
||||||
: buff(str),
|
: buff(str),
|
||||||
cursor_pos(pos),
|
cursor_pos(pos),
|
||||||
vars(ev),
|
vars(ev),
|
||||||
|
|
|
@ -8,6 +8,9 @@ fish: Invalid index value
|
||||||
echo ()[d]
|
echo ()[d]
|
||||||
^
|
^
|
||||||
|
|
||||||
|
####################
|
||||||
|
# Percent self
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# Catch your breath
|
# Catch your breath
|
||||||
fish: $) is not a valid variable in fish.
|
fish: $) is not a valid variable in fish.
|
||||||
|
|
|
@ -101,6 +101,11 @@ echo $foo[d]
|
||||||
echo ()[1]
|
echo ()[1]
|
||||||
echo ()[d]
|
echo ()[d]
|
||||||
|
|
||||||
|
logmsg Percent self
|
||||||
|
echo %selfNOT NOT%self \%self "%self" '%self'
|
||||||
|
echo %self | string match -qr '^\\d+$'
|
||||||
|
echo "All digits: $status"
|
||||||
|
|
||||||
logmsg Catch your breath
|
logmsg Catch your breath
|
||||||
set paren ')'
|
set paren ')'
|
||||||
echo $$paren
|
echo $$paren
|
||||||
|
|
|
@ -63,6 +63,11 @@
|
||||||
0
|
0
|
||||||
|
|
||||||
|
|
||||||
|
####################
|
||||||
|
# Percent self
|
||||||
|
%selfNOT NOT%self %self %self %self
|
||||||
|
All digits: 0
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# Catch your breath
|
# Catch your breath
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue