From 60ced5dbc70a2269ece22ce9d100ddeadc166dbb Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 30 Dec 2018 22:32:07 +0100 Subject: [PATCH 01/67] Only warn on exec for background jobs If it's a foreground job, it is related to the currently running exec. This fixes exec in functions, i.e. function reload exec fish end would previously always ask about the "function reload" job. Fixes #5449. Fixes oh-my-fish/oh-my-fish#664. --- src/parse_execution.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/parse_execution.cpp b/src/parse_execution.cpp index 701d41106..09b7f7d9d 100644 --- a/src/parse_execution.cpp +++ b/src/parse_execution.cpp @@ -773,7 +773,10 @@ parse_execution_result_t parse_execution_context_t::populate_plain_process( bool have_bg = false; const job_t *bg = nullptr; while ((bg = jobs.next())) { - if (!bg->is_completed()) { + // The assumption here is that if it is a foreground job, + // it's related to us. + // This stops us from asking if we're doing `exec` inside a function. + if (!bg->is_completed() && !bg->is_foreground()) { have_bg = true; break; } From 1ce9721590b4d8dddf57be730ba82dccdd3df925 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 20 Jan 2019 13:52:03 -0800 Subject: [PATCH 02/67] exec to only warn on background jobs in interactive sessions Extension of fix for #5449 in b007248 --- src/parse_execution.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parse_execution.cpp b/src/parse_execution.cpp index 09b7f7d9d..68a63c7c1 100644 --- a/src/parse_execution.cpp +++ b/src/parse_execution.cpp @@ -768,7 +768,7 @@ parse_execution_result_t parse_execution_context_t::populate_plain_process( // Protect against exec with background processes running static uint32_t last_exec_run_counter = -1; - if (process_type == INTERNAL_EXEC) { + if (process_type == INTERNAL_EXEC && shell_is_interactive()) { job_iterator_t jobs; bool have_bg = false; const job_t *bg = nullptr; From f4351eb0f30facabf3f94c6804973d4487a035f6 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 20 Jan 2019 13:55:18 -0800 Subject: [PATCH 03/67] Relnote fix for #5449 in 3.0.1 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2efdde7e..d7b6f1aa2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# fish 3.0.1 + +### Fixes and improvements + +- exec now behaves properly inside functions (#5449) + + # fish 3.0.0 (released December 28, 2018) fish 3 is a major release, which introduces some breaking changes alongside improved functionality. Although most existing scripts will continue to work, they should be reviewed against the list contained in the 3.0b1 release notes below. From e2f2dbf032c0a3bcc13b91a5d56cec2f5e294027 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 20 Jan 2019 15:04:27 -0800 Subject: [PATCH 04/67] Correctly handle exited jobs in process_mark_finished_children This is effectively a pick of 2ebdcf82eebec230549b64dc740ea604c7772049 and the subsequent fixup. However we also avoid setting WNOHANG unless waitpid() indicates a process was reaped. Fixes #5438 --- src/proc.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/proc.cpp b/src/proc.cpp index 4790449c5..b7b30dc22 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -467,6 +467,11 @@ static bool process_mark_finished_children(bool block_on_fg) { break; } assert((*process)->pid != INVALID_PID && "Waiting by process on an invalid PID!"); + // Don't wait for completed jobs; see #5438. + if ((*process)->completed) { + process++; + continue; + } pid = waitpid((*process)->pid, &status, options); process++; } else { @@ -475,14 +480,14 @@ static bool process_mark_finished_children(bool block_on_fg) { pid = waitpid(-1 * j->pgid, &status, options); } - // Never make two calls to waitpid(2) without WNOHANG (i.e. with "HANG") in a row, - // because we might wait on a non-stopped job that becomes stopped, but we don't refresh - // our view of the process state before calling waitpid(2) again here. - options |= WNOHANG; - if (pid > 0) { // A child process has been reaped handle_child_status(pid, status); + + // Always set WNOHANG (that is, don't hang). Otherwise we might wait on a non-stopped job + // that becomes stopped, but we don't refresh our view of the process state before + // calling waitpid(2) again here. + options |= WNOHANG; } else if (pid == 0 || errno == ECHILD) { // No killed/dead children in this particular process group if (!wait_by_process) { From 1d21e3f47057f238b4fa3d3b9b8fcd8737d110c8 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 20 Jan 2019 16:37:20 -0800 Subject: [PATCH 05/67] Make while loops evaluate to the last executed command status A while loop now evaluates to the last executed command in the body, or zero if the loop body is empty. This matches POSIX semantics. Add a bunch of tricky tests. See #4982 --- CHANGELOG.md | 1 + src/parse_execution.cpp | 33 +++++++++++++------ tests/while.err | 3 ++ tests/while.in | 73 +++++++++++++++++++++++++++++++++++++++++ tests/while.out | 12 +++++++ 5 files changed, 112 insertions(+), 10 deletions(-) create mode 100644 tests/while.err create mode 100644 tests/while.in create mode 100644 tests/while.out diff --git a/CHANGELOG.md b/CHANGELOG.md index d7b6f1aa2..1b27bd483 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Fixes and improvements - exec now behaves properly inside functions (#5449) +- while loops now evaluate to the last executed command in the loop body (or zero if the body was empty), matching POSIX semantics. # fish 3.0.0 (released December 28, 2018) diff --git a/src/parse_execution.cpp b/src/parse_execution.cpp index 68a63c7c1..5d16f66ad 100644 --- a/src/parse_execution.cpp +++ b/src/parse_execution.cpp @@ -523,13 +523,28 @@ parse_execution_result_t parse_execution_context_t::run_while_statement( const block_t *associated_block) { parse_execution_result_t ret = parse_execution_success; + // "The exit status of the while loop shall be the exit status of the last compound-list-2 + // executed, or zero if none was executed." + // Here are more detailed requirements: + // - If we execute the loop body zero times, or the loop body is empty, the status is success. + // - An empty loop body is treated as true, both in the loop condition and after loop exit. + // - The exit status of the last command is visible in the loop condition. (i.e. do not set the + // exit status to true BEFORE executing the loop condition). + // We achieve this by restoring the status if the loop condition fails, plus a special + // affordance for the first condition. + bool first_cond_check = true; + // The conditions of the while loop. tnode_t condition_head = header.child<1>(); tnode_t condition_boolean_tail = header.child<3>(); // Run while the condition is true. - bool loop_executed = false; for (;;) { + // Save off the exit status if it came from the loop body. We'll restore it if the condition + // is false. + int cond_saved_status = first_cond_check ? EXIT_SUCCESS : proc_get_last_status(); + first_cond_check = false; + // Check the condition. parse_execution_result_t cond_ret = this->run_job_conjunction(condition_head, associated_block); @@ -537,8 +552,13 @@ parse_execution_result_t parse_execution_context_t::run_while_statement( cond_ret = run_job_list(condition_boolean_tail, associated_block); } - // We only continue on successful execution and EXIT_SUCCESS. - if (cond_ret != parse_execution_success || proc_get_last_status() != EXIT_SUCCESS) { + // If the loop condition failed to execute, then exit the loop without modifying the exit + // status. If the loop condition executed with a failure status, restore the status and then + // exit the loop. + if (cond_ret != parse_execution_success) { + break; + } else if (proc_get_last_status() != EXIT_SUCCESS) { + proc_set_last_status(cond_saved_status); break; } @@ -548,8 +568,6 @@ parse_execution_result_t parse_execution_context_t::run_while_statement( break; } - loop_executed = true; - // Push a while block and then check its cancellation reason. while_block_t *wb = parser->push_block(); this->run_job_list(contents, wb); @@ -572,11 +590,6 @@ parse_execution_result_t parse_execution_context_t::run_while_statement( break; } } - - if (loop_executed) { - proc_set_last_status(STATUS_CMD_OK); - } - return ret; } diff --git a/tests/while.err b/tests/while.err new file mode 100644 index 000000000..2549f3894 --- /dev/null +++ b/tests/while.err @@ -0,0 +1,3 @@ + +#################### +# Loops exit status handling diff --git a/tests/while.in b/tests/while.in new file mode 100644 index 000000000..d183a54f6 --- /dev/null +++ b/tests/while.in @@ -0,0 +1,73 @@ +# vim: set ft=fish: + +function never_runs + while false + end +end + +function early_return + while true + return 2 + end +end + +function runs_once + set -l i 1 + while test $i -ne 0 && set i (math $i - 1) + end +end + +# this should return 1 +never_runs; echo "Empty Loop in Function: $status" + +# this should return 0 +runs_once; echo "Runs Once: $status" + +# this should return 2 +early_return; echo "Early Return: $status" + +logmsg Loops exit status handling + +function set_status ; return $argv[1]; end + +# The previous status is visible in the loop condition. +# This includes both the incoming status, and the last command in the +# loop body. +set_status 36 +while begin + set -l saved $status + echo "Condition Status: $status" + set_status $saved + end + true +end + +# The condition status IS visible in the loop body. +set_status 55 +while true + echo "Body Status: $status" + break +end + +# The status of the last command is visible in the loop condition +set_status 13 +while begin + set -l saved $status + echo "Condition 2 Status: $saved" + test $saved -ne 5 + end + set_status 5 +end + +# The status of the last command is visible outside the loop +set rem 5 7 11 +while [ (count $rem) -gt 0 ] + set_status $rem[1] + set rem $rem[2..-1] +end +echo "Loop Exit Status: $status" + +# Empty loops succeed. +false +while false; end +echo "Empty Loop Status: $status" diff --git a/tests/while.out b/tests/while.out new file mode 100644 index 000000000..f23708aa4 --- /dev/null +++ b/tests/while.out @@ -0,0 +1,12 @@ +Empty Loop in Function: 0 +Runs Once: 0 +Early Return: 2 + +#################### +# Loops exit status handling +Condition Status: 36 +Body Status: 0 +Condition 2 Status: 13 +Condition 2 Status: 5 +Loop Exit Status: 11 +Empty Loop Status: 0 From 364c83927968c7fd8936bfb3d9f895d60886c071 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 20 Jan 2019 17:36:31 -0800 Subject: [PATCH 06/67] Unconditionally set the tty mode in reader_readline There was a bogus check for is_interactive_session. But if we are in reader_readline we are necessarily interactive (even if we are not in an interactive session, i.e. a fish script invoked some interactive functionality). Remove this check. Fixes #5519 --- src/reader.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/reader.cpp b/src/reader.cpp index 70b6c4a3d..727f79f9b 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -2474,11 +2474,9 @@ const wchar_t *reader_readline(int nchars) { // Get the current terminal modes. These will be restored when the function returns. if (tcgetattr(STDIN_FILENO, &old_modes) == -1 && errno == EIO) redirect_tty_output(); // Set the new modes. - if (is_interactive_session) { - if (tcsetattr(0, TCSANOW, &shell_modes) == -1) { - if (errno == EIO) redirect_tty_output(); - wperror(L"tcsetattr"); - } + if (tcsetattr(0, TCSANOW, &shell_modes) == -1) { + if (errno == EIO) redirect_tty_output(); + wperror(L"tcsetattr"); } while (!finished && !data->end_loop) { From 028bff7b4444a0eb8ee7c1607b6a87bacdd0e343 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 20 Jan 2019 17:46:19 -0800 Subject: [PATCH 07/67] Relnote fix for #5519 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b27bd483..0baf3ef86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - exec now behaves properly inside functions (#5449) - while loops now evaluate to the last executed command in the loop body (or zero if the body was empty), matching POSIX semantics. +- `read --silent` no longer echoes to the tty when run from a non-interactive script (#5519) # fish 3.0.0 (released December 28, 2018) From 059804612a469e6ea6409be38e36c32f7a173187 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 4 Jan 2019 08:45:53 +0100 Subject: [PATCH 08/67] string: Fix crash with _GLIBCXX_ASSERTIONS This asserted because we accessed wcstring::front() when it was empty. Instead, check explicitly for it being empty before. Fixes #5479 --- src/builtin_string.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/builtin_string.cpp b/src/builtin_string.cpp index 6e810a32e..bbc7e40c0 100644 --- a/src/builtin_string.cpp +++ b/src/builtin_string.cpp @@ -622,9 +622,13 @@ class wildcard_matcher_t : public string_matcher_t { } } if (opts.entire) { - // If the pattern is empty, this becomes one ANY_STRING that matches everything. - if (wcpattern.front() != ANY_STRING) wcpattern.insert(0, 1, ANY_STRING); - if (wcpattern.back() != ANY_STRING) wcpattern.push_back(ANY_STRING); + if (!wcpattern.empty()) { + if (wcpattern.front() != ANY_STRING) wcpattern.insert(0, 1, ANY_STRING); + if (wcpattern.back() != ANY_STRING) wcpattern.push_back(ANY_STRING); + } else { + // If the pattern is empty, this becomes one ANY_STRING that matches everything. + wcpattern.push_back(ANY_STRING); + } } } From 40f5dd200be95f2932e2d0482ae89e48e1eb347a Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 4 Jan 2019 14:48:01 +0100 Subject: [PATCH 09/67] share/config: Don't split /etc/paths entries on spaces This used `read -la`, which _splits_. Instead, don't do that, each line is its own entry. Fixes #5481. [ci skip] --- share/config.fish | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/config.fish b/share/config.fish index 1f393c5f5..160524b93 100644 --- a/share/config.fish +++ b/share/config.fish @@ -208,7 +208,7 @@ if command -sq /usr/libexec/path_helper for path_file in $argv[2] $argv[3]/* if test -f $path_file - while read -la entry + while read -l entry if not contains $entry $result set result $result $entry end From 5f7adb3c69ec5f31f573eb35575a56799d4c6c70 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 20 Jan 2019 18:05:07 -0800 Subject: [PATCH 10/67] Relnote fix for #5481 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0baf3ef86..5c1e9f45a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - exec now behaves properly inside functions (#5449) - while loops now evaluate to the last executed command in the loop body (or zero if the body was empty), matching POSIX semantics. - `read --silent` no longer echoes to the tty when run from a non-interactive script (#5519) +- (macOS only) /etc/paths and /etc/paths.d now correctly set path entries with spaces. Also affects MANPATH. (#5481) # fish 3.0.0 (released December 28, 2018) From b6aafda139608596720304dcedb26768105e749d Mon Sep 17 00:00:00 2001 From: David Adam Date: Mon, 21 Jan 2019 17:25:24 +1100 Subject: [PATCH 11/67] CHANGELOG: 3.0.1 verbiage --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c1e9f45a..0782b2051 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ +<<<<<<< HEAD # fish 3.0.1 +This release of fish fixes a number of major issues discovered in fish 3.0.0. + ### Fixes and improvements - exec now behaves properly inside functions (#5449) @@ -7,6 +10,9 @@ - `read --silent` no longer echoes to the tty when run from a non-interactive script (#5519) - (macOS only) /etc/paths and /etc/paths.d now correctly set path entries with spaces. Also affects MANPATH. (#5481) +If you are upgrading from version 2.7.1 or before, please also review the release notes for 3.0.0 and 3.0b1 (included below). + +--- # fish 3.0.0 (released December 28, 2018) From 8ff81247659cf9b9a0ea5bc6bee183e22d22c4de Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Mon, 31 Dec 2018 10:07:52 +0100 Subject: [PATCH 12/67] cmake: Add missing HAVE_WCSTOD_L #cmakedefine Turns out we've been using the fallback everywhere. See #5453. (cherry picked from commit 7078aa46428aa083053bcefb9e67d41293d6d13a) --- config_cmake.h.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config_cmake.h.in b/config_cmake.h.in index d234acba9..47cfcc5e2 100644 --- a/config_cmake.h.in +++ b/config_cmake.h.in @@ -115,6 +115,9 @@ /* Define to 1 if you have the `wcsndup' function. */ #cmakedefine HAVE_WCSNDUP 1 +/* Define to 1 if you have the `wcstod_l' function. */ +#cmakedefine HAVE_WCSTOD_L 1 + /* Define to 1 if the winsize struct and TIOCGWINSZ macro exist */ #cmakedefine HAVE_WINSIZE 1 From 3855608c690cec92555d5ec8a95703422403137f Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 3 Jan 2019 11:47:32 +0100 Subject: [PATCH 13/67] docs: Document $hostname Fixes #5469. [ci skip] (cherry picked from commit 72c0213d42b77b2f01223b5515669840110ea9b9) --- doc_src/index.hdr.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc_src/index.hdr.in b/doc_src/index.hdr.in index a0e326e89..7f2fe7efc 100644 --- a/doc_src/index.hdr.in +++ b/doc_src/index.hdr.in @@ -931,6 +931,8 @@ The user can change the settings of `fish` by changing the values of certain var - `HOME`, the user's home directory. This variable can be changed by the user. +- `hostname`, the machine's hostname. + - `IFS`, the internal field separator that is used for word splitting with the read builtin. Setting this to the empty string will also disable line splitting in command substitution. This variable can be changed by the user. - `PWD`, the current working directory. From 7a163e8e985aaaf11da9e88b3ce8096895484a01 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 13 Jan 2019 16:36:09 +0100 Subject: [PATCH 14/67] completions/git: Stop limiting to the token This enables fuzzy-matching outside of the current directory again. As it turns out, the performance impact here isn't as large as I thought - it's massively dependent on caching. Fixes #5476. (cherry picked from commit 73bae383e0fee4dc93d247546df3b70504adbb2b) --- share/completions/git.fish | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/share/completions/git.fish b/share/completions/git.fish index 60822fe49..7c4cb1a5c 100644 --- a/share/completions/git.fish +++ b/share/completions/git.fish @@ -144,19 +144,13 @@ function __fish_git_files # (don't use --ignored=no because that was only added in git 2.16, from Jan 2018. set -q ignored; and set -a status_opt --ignored - # Glob just the current token for performance - # and so git shows untracked files (even in untracked dirs) for that. - # If the current token is empty, this matches everything in $PWD. - set -l files (commandline -ct) - # The trailing "**" is necessary to match files inside the given directories. - set files "$files*" "$files*/**" set -q untracked; and set -a status_opt -unormal or set -a status_opt -uno # We need to set status.relativePaths to true because the porcelain v2 format still honors that, # and core.quotePath to false so characters > 0x80 (i.e. non-ASCII) aren't considered special. # We explicitly enable globs so we can use that to match the current token. - set -l git_opt -c status.relativePaths -c core.quotePath= --glob-pathspecs + set -l git_opt -c status.relativePaths -c core.quotePath= # We pick the v2 format if we can, because it shows relative filenames (if used without "-z"). # We fall back on the v1 format by reading git's _version_, because trying v2 first is too slow. @@ -278,7 +272,7 @@ function __fish_git_files set -l previousfile # Note that we can't use space as a delimiter between status and filename, because # the status can contain spaces - " M" is different from "M ". - command git $git_opt status --porcelain -z $status_opt -- $files \ + command git $git_opt status --porcelain -z $status_opt \ | while read -lz line set -l desc # The entire line is the "from" from a rename. From 749347ff4c45fd217054714f53c6df064bb87a1d Mon Sep 17 00:00:00 2001 From: David Adam Date: Tue, 8 Jan 2019 14:50:08 +0800 Subject: [PATCH 15/67] debian packaging: recommend python3 or python2 Closes #5492. (cherry picked from commit 1f897d2c4318a78976bcfb81d668f65ef2d909f0) --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 56c1a692f..5368d3c6a 100644 --- a/debian/control +++ b/debian/control @@ -22,7 +22,7 @@ Description: friendly interactive shell Package: fish-common Architecture: all Depends: ${misc:Depends} -Recommends: fish, python (>=2.6) +Recommends: fish, python3 (>= 3.3) | python (>=2.7) Suggests: xdg-utils Replaces: fish (<= 2.1.1.dfsg-2) Description: friendly interactive shell (architecture-independent files) From cb09f9aef217aadc6cfe81517ca72dc1b0b07e65 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Wed, 2 Jan 2019 14:16:39 +0100 Subject: [PATCH 16/67] Switch to readdir from readdir_r It's deprecated in glibc, and does not work properly on Solaris. Fixes #5458. --- src/wutil.cpp | 43 +++++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/src/wutil.cpp b/src/wutil.cpp index f58eb529a..2dc25019f 100644 --- a/src/wutil.cpp +++ b/src/wutil.cpp @@ -37,27 +37,27 @@ const file_id_t kInvalidFileID = {(dev_t)-1LL, (ino_t)-1LL, (uint64_t)-1LL, -1, static owning_lock> wgettext_map; bool wreaddir_resolving(DIR *dir, const wcstring &dir_path, wcstring &out_name, bool *out_is_dir) { - struct dirent d; - struct dirent *result = NULL; - int retval = readdir_r(dir, &d, &result); - if (retval || !result) { + struct dirent *result = readdir(dir); + if (!result) { out_name = L""; return false; } - out_name = str2wcstring(d.d_name); - if (!out_is_dir) return true; + out_name = str2wcstring(result->d_name); + if (!out_is_dir) { + return true; + } // The caller cares if this is a directory, so check. bool is_dir = false; // We may be able to skip stat, if the readdir can tell us the file type directly. bool check_with_stat = true; #ifdef HAVE_STRUCT_DIRENT_D_TYPE - if (d.d_type == DT_DIR) { + if (result->d_type == DT_DIR) { // Known directory. is_dir = true; check_with_stat = false; - } else if (d.d_type == DT_LNK || d.d_type == DT_UNKNOWN) { + } else if (result->d_type == DT_LNK || result->d_type == DT_UNKNOWN) { // We want to treat symlinks to directories as directories. Use stat to resolve it. check_with_stat = true; } else { @@ -70,7 +70,7 @@ bool wreaddir_resolving(DIR *dir, const wcstring &dir_path, wcstring &out_name, // We couldn't determine the file type from the dirent; check by stat'ing it. cstring fullpath = wcs2string(dir_path); fullpath.push_back('/'); - fullpath.append(d.d_name); + fullpath.append(result->d_name); struct stat buf; if (stat(fullpath.c_str(), &buf) != 0) { is_dir = false; @@ -83,34 +83,24 @@ bool wreaddir_resolving(DIR *dir, const wcstring &dir_path, wcstring &out_name, } bool wreaddir(DIR *dir, wcstring &out_name) { - // We need to use a union to ensure that the dirent struct is large enough to avoid stomping on - // the stack. Some platforms incorrectly defined the `d_name[]` member as being one element - // long when it should be at least NAME_MAX + 1. - union { - struct dirent d; - char c[offsetof(struct dirent, d_name) + NAME_MAX + 1]; - } d_u; - struct dirent *result = NULL; - - int retval = readdir_r(dir, &d_u.d, &result); - if (retval || !result) { + struct dirent *result = readdir(dir); + if (!result) { out_name = L""; return false; } - out_name = str2wcstring(d_u.d.d_name); + out_name = str2wcstring(result->d_name); return true; } bool wreaddir_for_dirs(DIR *dir, wcstring *out_name) { - struct dirent d; struct dirent *result = NULL; while (!result) { - int retval = readdir_r(dir, &d, &result); - if (retval || !result) break; + result = readdir(dir); + if (!result) break; #if HAVE_STRUCT_DIRENT_D_TYPE - switch (d.d_type) { + switch (result->d_type) { case DT_DIR: case DT_LNK: case DT_UNKNOWN: { @@ -129,7 +119,8 @@ bool wreaddir_for_dirs(DIR *dir, wcstring *out_name) { if (result && out_name) { *out_name = str2wcstring(result->d_name); } - return result != NULL; + if (!result) return false; + return true; } const wcstring wgetcwd() { From f2a1130afd9aa9132c9297d850ee6a74404a669e Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 18 Jan 2019 19:24:49 +0100 Subject: [PATCH 17/67] Also set the read-only flag for non-electric vars For some reason, we have two places where a variable can be read-only: - By key in env.cpp:is_read_only(), which is checked via set* - By flag on the actual env_var_t, which is checked e.g. in parse_execution The latter didn't happen for non-electric variables like hostname, because they used the default constructor, because they were constructed via operator[] (or some such C++-iness). This caused for-loops to crash on an assert if they used a non-electric read-only var like $hostname or $SHLVL. Instead, we explicitly set the flag. We might want to remove one of the two read-only checks, or something? Fixes #5548. --- src/env.cpp | 1 + src/env.h | 8 ++++++++ tests/test1.err | 6 ++++++ tests/test1.in | 5 +++++ tests/test1.out | 3 +++ 5 files changed, 23 insertions(+) diff --git a/src/env.cpp b/src/env.cpp index dbb85ed66..2d25cb5de 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -1184,6 +1184,7 @@ static int env_set_internal(const wcstring &key, env_mode_flags_t input_var_mode var.set_vals(std::move(val)); var.set_pathvar(var_mode & ENV_PATHVAR); + var.set_read_only(is_read_only(key)); if (var_mode & ENV_EXPORT) { // The new variable is exported. diff --git a/src/env.h b/src/env.h index 30fb4ab0d..f055eb623 100644 --- a/src/env.h +++ b/src/env.h @@ -122,6 +122,14 @@ class env_var_t { } } + void set_read_only(bool read_only) { + if (read_only) { + flags |= flag_read_only; + } else { + flags &= ~flag_read_only; + } + } + static env_var_flags_t flags_for(const wchar_t *name); env_var_t &operator=(const env_var_t &var) = default; diff --git a/tests/test1.err b/tests/test1.err index 5e9cda705..e5a978376 100644 --- a/tests/test1.err +++ b/tests/test1.err @@ -38,6 +38,12 @@ fish: You cannot use read-only variable 'status' in a for loop for status in a b c ^ +#################### +# That goes for non-electric ones as well (#5548) +fish: You cannot use read-only variable 'hostname' in a for loop +for hostname in a b c + ^ + #################### # For loop control vars available outside the for block diff --git a/tests/test1.in b/tests/test1.in index 104f984ea..7f0f1dcaa 100644 --- a/tests/test1.in +++ b/tests/test1.in @@ -163,6 +163,11 @@ for status in a b c echo $status end +logmsg "That goes for non-electric ones as well (#5548)" +for hostname in a b c + echo $hostname +end + logmsg For loop control vars available outside the for block begin set -l loop_var initial-value diff --git a/tests/test1.out b/tests/test1.out index 56fd4f64d..b3b075fab 100644 --- a/tests/test1.out +++ b/tests/test1.out @@ -96,6 +96,9 @@ Checking for infinite loops in no-execute #################### # For loops with read-only vars is an error (#4342) +#################### +# That goes for non-electric ones as well (#5548) + #################### # For loop control vars available outside the for block $loop_var: set in local scope, unexported, with 1 elements From afb9094b4ce05250f6908cba46882cb2b25bf1a6 Mon Sep 17 00:00:00 2001 From: Sam Yu Date: Sat, 12 Jan 2019 14:05:23 +0800 Subject: [PATCH 18/67] Fix completion of directories for configure --- share/completions/configure.fish | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/share/completions/configure.fish b/share/completions/configure.fish index 67eb5d519..6c7880ef2 100644 --- a/share/completions/configure.fish +++ b/share/completions/configure.fish @@ -4,9 +4,9 @@ complete -c configure -s q -l quiet -d "Quiet mode" complete -c configure -l cache-file -f -d "Cache test results in specified file" complete -c configure -s C -l config-cache -d "Cache test results in file config.cache" complete -c configure -s n -l no-create -d "Do not create output files" -complete -c configure -l srcdir -d "Set source directory" -a "__fish_complete_directories (commandline -ct)" -x -complete -c configure -l prefix -d "Architecture-independent install directory" -a "__fish_complete_directories (commandline -ct)" -x -complete -c configure -l exec-prefix -d "Architecture-dependent install directory" -a "__fish_complete_directories (commandline -ct)" -x +complete -c configure -l srcdir -d "Set source directory" -a "(__fish_complete_directories)" -x +complete -c configure -l prefix -d "Architecture-independent install directory" -a "(__fish_complete_directories)" -x +complete -c configure -l exec-prefix -d "Architecture-dependent install directory" -a "(__fish_complete_directories)" -x complete -c configure -l build -d "Configure for building on BUILD" -x complete -c configure -l host -d "Cross-compile to build programs to run on HOST" -x complete -c configure -l target -d "Configure for building compilers for TARGET" -x From 97f0cc966211aa2daad6e5e2d6a616feb230cb4e Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 17 Jan 2019 09:44:35 +0100 Subject: [PATCH 19/67] Don't wrap functions with themselves Our weird %-expanding function wrappers around kill et all defined "--wraps" for the same name. As it turns out, fish follows that one, and executes the completion multiple times. I didn't notice because these tend to be rather quick on linux, but on macOS that's apparently a real issue. Fixes #5541. [ci skip] --- share/config.fish | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/share/config.fish b/share/config.fish index 160524b93..a3abb82f3 100644 --- a/share/config.fish +++ b/share/config.fish @@ -271,23 +271,23 @@ function __fish_expand_pid_args end end -function bg --wraps bg +function bg builtin bg (__fish_expand_pid_args $argv) end -function fg --wraps fg +function fg builtin fg (__fish_expand_pid_args $argv) end -function kill --wraps kill +function kill command kill (__fish_expand_pid_args $argv) end -function wait --wraps wait +function wait builtin wait (__fish_expand_pid_args $argv) end -function disown --wraps disown +function disown builtin disown (__fish_expand_pid_args $argv) end From d5d80c0742a5022f543cffbd1e01d6cdf3d1507f Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Sun, 13 Jan 2019 16:14:04 -0600 Subject: [PATCH 20/67] Fix extra space in `fish_title` Closes #5517. Credit goes to @jadenPete. [skip-ci] --- share/functions/fish_title.fish | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/functions/fish_title.fish b/share/functions/fish_title.fish index 5eacb73e9..87abe894b 100644 --- a/share/functions/fish_title.fish +++ b/share/functions/fish_title.fish @@ -1,3 +1,3 @@ function fish_title - echo (status current-command) " " (__fish_pwd) + echo (status current-command) (__fish_pwd) end From ec77135cf28f3ab6e62fb98459c5f9232eb4956a Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Thu, 10 Jan 2019 22:20:17 -0600 Subject: [PATCH 21/67] Allow more flexibility with file completions for `yarn` Closes #5502 --- share/completions/yarn.fish | 63 +++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/share/completions/yarn.fish b/share/completions/yarn.fish index ffa11137e..e2650b7d6 100644 --- a/share/completions/yarn.fish +++ b/share/completions/yarn.fish @@ -23,7 +23,8 @@ function __yarn_filtered_list_packages return end - all-the-package-names | string match -er -- "(?:\\b|_)"(commandline -ct | string escape --style=regex) + all-the-package-names | string match -er -- "(?:\\b|_)"(commandline -ct | + string escape --style=regex) | head -n1000 end function __yarn_find_package_json @@ -153,7 +154,7 @@ function __fish_yarn_run end end -complete -f -c yarn -n '__fish_seen_subcommand_from run' -a "(__fish_yarn_run)" +complete -c yarn -n '__fish_seen_subcommand_from run' -a "(__fish_yarn_run)" complete -f -c yarn -n '__fish_use_subcommand' -a tag complete -f -c yarn -n '__fish_seen_subcommand_from tag' -a 'add rm ls' @@ -177,36 +178,36 @@ complete -f -c yarn -n '__fish_use_subcommand' -a why set -g yarn_cmds access add bin cache check clean config generate-lock-entry global info init install licenses link list login logout outdated owner pack publish remove run tag team unlink upgrade upgrade-interactive version versions why # Common short, long options -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l help -s h -d 'output usage information' -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l version -s V -d 'output the version number' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l help -s h -d 'output usage information' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l version -s V -d 'output the version number' # The rest of common options are all of them long -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l verbose -d 'output verbose messages on internal operations' -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l offline -d 'trigger an error if any required dependencies are not available in local cache' -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l prefer-offline -d 'use network only if dependencies are not available in local cache' -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l strict-semver -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l json -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l ignore-scripts -d 'don\'t run lifecycle scripts' -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l har -d 'save HAR output of network traffic' -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l ignore-platform -d 'ignore platform checks' -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l ignore-engines -d 'ignore engines check' -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l ignore-optional -d 'ignore optional dependencies' -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l force -d 'ignore all caches' -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l no-bin-links -d 'don\'t generate bin links when setting up packages' -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l flat -d 'only allow one version of a package' -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l 'prod production' -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l no-lockfile -d 'don\'t read or generate a lockfile' -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l pure-lockfile -d 'don\'t generate a lockfile' -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l frozen-lockfile -d 'don\'t generate a lockfile and fail if an update is needed' -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l global-folder -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l modules-folder -d 'rather than installing modules into the node_modules folder relative to the cwd, output them here' -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l cache-folder -d 'specify a custom folder to store the yarn cache' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l verbose -d 'output verbose messages on internal operations' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l offline -d 'trigger an error if any required dependencies are not available in local cache' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l prefer-offline -d 'use network only if dependencies are not available in local cache' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l strict-semver +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l json +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l ignore-scripts -d 'don\'t run lifecycle scripts' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l har -d 'save HAR output of network traffic' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l ignore-platform -d 'ignore platform checks' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l ignore-engines -d 'ignore engines check' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l ignore-optional -d 'ignore optional dependencies' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l force -d 'ignore all caches' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l no-bin-links -d 'don\'t generate bin links when setting up packages' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l flat -d 'only allow one version of a package' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l 'prod production' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l no-lockfile -d 'don\'t read or generate a lockfile' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l pure-lockfile -d 'don\'t generate a lockfile' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l frozen-lockfile -d 'don\'t generate a lockfile and fail if an update is needed' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l global-folder +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l modules-folder -d 'rather than installing modules into the node_modules folder relative to the cwd, output them here' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l cache-folder -d 'specify a custom folder to store the yarn cache' -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l mutex -d 'use a mutex to ensure only one yarn instance is executing' -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l mutex -a 'file network' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l mutex -d 'use a mutex to ensure only one yarn instance is executing' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l mutex -a 'file network' -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l no-emoji -d 'disable emoji in output' -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l proxy -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l https-proxy -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l no-progress -d 'disable progress bar' -complete -f -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l network-concurrency -d 'maximum number of concurrent network requests' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l no-emoji -d 'disable emoji in output' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l proxy +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l https-proxy +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l no-progress -d 'disable progress bar' +complete -c yarn -n '__fish_seen_subcommand_from $yarn_cmds' -l network-concurrency -d 'maximum number of concurrent network requests' From 96f7924661016a29231c2523f68c794dcb2e5a89 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Mon, 7 Jan 2019 17:24:17 +0100 Subject: [PATCH 22/67] Fix nim prompt (via web_config) This had a helper function defined outside of the fish_prompt function, so `funcsave` missed it (see #736). Fixes #5490. [ci skip] --- .../tools/web_config/sample_prompts/nim.fish | 83 ++++++++++--------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/share/tools/web_config/sample_prompts/nim.fish b/share/tools/web_config/sample_prompts/nim.fish index b935f8413..93c574dd5 100644 --- a/share/tools/web_config/sample_prompts/nim.fish +++ b/share/tools/web_config/sample_prompts/nim.fish @@ -1,49 +1,50 @@ # name: Nim # author: Guilhem "Nim" Saurel − https://github.com/nim65s/dotfiles/ -# This prompt shows: -# - green lines if the last return command is OK, red otherwise -# - your user name, in red if root or yellow otherwise -# - your hostname, in cyan if ssh or blue otherwise -# - the current path (with prompt_pwd) -# - date +%X -# - the current virtual environment, if any -# - the current git status, if any, with __fish_git_prompt -# - the current battery state, if any, and if your power cable is unplugged, and if you have "acpi" -# - current background jobs, if any - -# It goes from: -# ┬─[nim@Hattori:~]─[11:39:00] -# ╰─>$ echo here - -# To: -# ┬─[nim@Hattori:~/w/dashboard]─[11:37:14]─[V:django20]─[G:master↑1|●1✚1…1]─[B:85%, 05:41:42 remaining] -# │ 2 15054 0% arrêtée sleep 100000 -# │ 1 15048 0% arrêtée sleep 100000 -# ╰─>$ echo there - -set __fish_git_prompt_showupstream auto - -function _nim_prompt_wrapper - set retc $argv[1] - set field_name $argv[2] - set field_value $argv[3] - - set_color normal - set_color $retc - echo -n '─' - set_color -o green - echo -n '[' - set_color normal - test -n $field_name - and echo -n $field_name: - set_color $retc - echo -n $field_value - set_color -o green - echo -n ']' -end function fish_prompt + # This prompt shows: + # - green lines if the last return command is OK, red otherwise + # - your user name, in red if root or yellow otherwise + # - your hostname, in cyan if ssh or blue otherwise + # - the current path (with prompt_pwd) + # - date +%X + # - the current virtual environment, if any + # - the current git status, if any, with __fish_git_prompt + # - the current battery state, if any, and if your power cable is unplugged, and if you have "acpi" + # - current background jobs, if any + + # It goes from: + # ┬─[nim@Hattori:~]─[11:39:00] + # ╰─>$ echo here + + # To: + # ┬─[nim@Hattori:~/w/dashboard]─[11:37:14]─[V:django20]─[G:master↑1|●1✚1…1]─[B:85%, 05:41:42 remaining] + # │ 2 15054 0% arrêtée sleep 100000 + # │ 1 15048 0% arrêtée sleep 100000 + # ╰─>$ echo there + + set -q __fish_git_prompt_showupstream + or set -g __fish_git_prompt_showupstream auto + + function _nim_prompt_wrapper + set retc $argv[1] + set field_name $argv[2] + set field_value $argv[3] + + set_color normal + set_color $retc + echo -n '─' + set_color -o green + echo -n '[' + set_color normal + test -n $field_name + and echo -n $field_name: + set_color $retc + echo -n $field_value + set_color -o green + echo -n ']' + end and set retc green or set retc red From 171ae992955761bb1169dc3c36883e8e7d4f84db Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 30 Dec 2018 18:54:09 +0100 Subject: [PATCH 23/67] Don't ASSERT_IS_NOT_FORKED_CHILD so much This is hammered sooo much that it actually hurts performance. for i in (seq 100000); test 1 = 1; end is about 40% (!) slower with it. --- src/parser.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/parser.cpp b/src/parser.cpp index b16c86e47..4196c3dd8 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -108,7 +108,6 @@ parser_t::~parser_t() = default; static parser_t s_principal_parser; parser_t &parser_t::principal_parser() { - ASSERT_IS_NOT_FORKED_CHILD(); ASSERT_IS_MAIN_THREAD(); return s_principal_parser; } From 288cfa8fb249e27aab8abe966f10a96f64b61a2e Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 13 Jan 2019 21:31:49 +0100 Subject: [PATCH 24/67] completions/git: Also don't use files for porcelain=2 This was an oversight from the previous commit. Not that it matters much, because we already removed $files. Still, this would fail if someone defined a global $files, so let's fix it. [ci skip] --- share/completions/git.fish | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/completions/git.fish b/share/completions/git.fish index 7c4cb1a5c..d8dd64ea9 100644 --- a/share/completions/git.fish +++ b/share/completions/git.fish @@ -157,7 +157,7 @@ function __fish_git_files set -l ver (command git --version | string replace -rf 'git version (\d+)\.(\d+)\.?.*' '$1\n$2') # Version >= 2.11.* has the v2 format. if test "$ver[1]" -gt 2 2>/dev/null; or test "$ver[1]" -eq 2 -a "$ver[2]" -ge 11 2>/dev/null - command git $git_opt status --porcelain=2 $status_opt -- $files \ + command git $git_opt status --porcelain=2 $status_opt \ | while read -la -d ' ' line set -l file set -l desc From 91ecd3b9b5503ff066874961ec18913679e19738 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 13 Jan 2019 17:18:39 +0100 Subject: [PATCH 25/67] completions/git: Skip "!" shell-aliases for wrapping We can't complete these, and now the user can do ``` set -g __fish_git_alias_$alias $command ``` e.g. ``` set -g __fish_git_alias_co checkout ``` if the arguments in the alias end up going to `git alias`. Fixes #5412. [ci skip] --- share/completions/git.fish | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/share/completions/git.fish b/share/completions/git.fish index d8dd64ea9..c8683e31e 100644 --- a/share/completions/git.fish +++ b/share/completions/git.fish @@ -440,6 +440,12 @@ end # This is because alias:command is an n:1 mapping (an alias can only have one corresponding command, # but a command can be aliased multiple times) git config -z --get-regexp 'alias\..*' | while read -lz alias command _ + # If the command starts with a "!", it's a shell command, run with /bin/sh, + # or any other shell defined at git's build time. + # + # We can't do anything with them, and we run git-config again for listing aliases, + # so we skip them here. + string match -q '!*' -- $command; and continue # Git aliases can contain chars that variable names can't - escape them. set alias (string replace 'alias.' '' -- $alias | string escape --style=var) set -g __fish_git_alias_$alias $command From 963e3217e5b97f48ec8ad9229cef40c826a8888e Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Tue, 22 Jan 2019 17:14:33 +0100 Subject: [PATCH 26/67] env_get_runtime_path: Check for getpwuid() failure Otherwise this is a NULL dereference and then crash. Fixes #5550. --- src/env.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/env.cpp b/src/env.cpp index 2d25cb5de..c5a83ed43 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -1655,12 +1655,16 @@ wcstring env_get_runtime_path() { } else { // Don't rely on $USER being set, as setup_user() has not yet been called. // See https://github.com/fish-shell/fish-shell/issues/5180 - const char *uname = getpwuid(geteuid())->pw_name; + // getpeuid() can't fail, but getpwuid sure can. + auto pwuid = getpwuid(geteuid()); + const char *uname = pwuid ? pwuid->pw_name : NULL; // /tmp/fish.user std::string tmpdir = "/tmp/fish."; - tmpdir.append(uname); + if (uname) { + tmpdir.append(uname); + } - if (check_runtime_path(tmpdir.c_str()) != 0) { + if (!uname || check_runtime_path(tmpdir.c_str()) != 0) { debug(0, L"Runtime path not available."); debug(0, L"Try deleting the directory %s and restarting fish.", tmpdir.c_str()); return result; From 1b551e553b5b06fca777396d4c44b0e9de56c10b Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Mon, 21 Jan 2019 20:29:31 -0600 Subject: [PATCH 27/67] Fix regression for #4178 and others introduced by 364c839 ...while still keeping intact the fix for #5519. --- src/reader.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/reader.cpp b/src/reader.cpp index 727f79f9b..893ac885f 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -2475,8 +2475,16 @@ const wchar_t *reader_readline(int nchars) { if (tcgetattr(STDIN_FILENO, &old_modes) == -1 && errno == EIO) redirect_tty_output(); // Set the new modes. if (tcsetattr(0, TCSANOW, &shell_modes) == -1) { - if (errno == EIO) redirect_tty_output(); - wperror(L"tcsetattr"); + int err = errno; + if (err == EIO) { + redirect_tty_output(); + } + // This check is required to work around certain issues with fish's approach to + // terminal control when launching interactive processes while in non-interactive + // mode. See #4178 for one such example. + if (err != ENOTTY || is_interactive_session) { + wperror(L"tcsetattr"); + } } while (!finished && !data->end_loop) { From d88be7b5c884b594595197e0ffe6f0eb4fba363e Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 3 Jan 2019 23:17:20 +0100 Subject: [PATCH 28/67] tests/cd: cd back before cleaning up Otherwise this'd run afoul of OpenIndiana's "no removing $PWD" rule. Spoilsports! See #5472. --- tests/cd.in | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/cd.in b/tests/cd.in index 21104a432..fa3964a22 100644 --- a/tests/cd.in +++ b/tests/cd.in @@ -1,3 +1,5 @@ +# Store pwd to later go back before cleaning up +set -l oldpwd (pwd) logmsg cd symlink non-resolution set real (mktemp -d) set link (mktemp -u) @@ -35,4 +37,7 @@ echo "ls:" complete -C'ls ../' echo "cd:" complete -C'cd ../' + +# cd back before removing the test directory again. +cd $oldpwd rm -Rf $base From dfa61926e8f48a012872873e8b889c02401d898e Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Tue, 22 Jan 2019 13:07:55 -0800 Subject: [PATCH 29/67] Correctly inherit a virtual PWD PWD is not set in fish vars because it is read only. Use getenv() to fetch it, allowing fish to inherit a virtual PWD. This cherry pick includes both: 24f251e04 Correctly remove the test directory again in cd test 91a9c9897 Correctly inherit a virtual PWD Fixes #5525 --- src/env.cpp | 6 +++++- tests/cd.err | 3 +++ tests/cd.in | 10 ++++++++++ tests/cd.out | 4 ++++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/env.cpp b/src/env.cpp index c5a83ed43..7c617cb2e 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -962,7 +962,11 @@ void env_init(const struct config_paths_t *paths /* or NULL */) { // initialize the PWD variable if necessary // Note we may inherit a virtual PWD that doesn't match what getcwd would return; respect that. - if (env_get(L"PWD").missing_or_empty()) { + // Note we treat PWD as read-only so it was not set in vars. + const char *incoming_pwd = getenv("PWD"); + if (incoming_pwd && incoming_pwd[0]) { + env_set_one(L"PWD", ENV_EXPORT | ENV_GLOBAL, str2wcstring(incoming_pwd)); + } else { env_set_pwd_from_getcwd(); } env_set_termsize(); // initialize the terminal size variables diff --git a/tests/cd.err b/tests/cd.err index 80bc5c0e6..4653e2ee6 100644 --- a/tests/cd.err +++ b/tests/cd.err @@ -4,3 +4,6 @@ #################### # cd symlink completion + +#################### +# Virtual PWD inheritance diff --git a/tests/cd.in b/tests/cd.in index fa3964a22..fde7cd558 100644 --- a/tests/cd.in +++ b/tests/cd.in @@ -38,6 +38,16 @@ complete -C'ls ../' echo "cd:" complete -C'cd ../' +logmsg Virtual PWD inheritance +# PWD should be imported and respected by fish + +cd $oldpwd +mkdir -p $base/realhome +set fish_path $PWD/../test/root/bin/fish +ln -s $base/realhome $base/linkhome +cd $base/linkhome +env HOME=$base/linkhome $fish_path -c 'echo PWD is $PWD' + # cd back before removing the test directory again. cd $oldpwd rm -Rf $base diff --git a/tests/cd.out b/tests/cd.out index 86ea3299c..73081263d 100644 --- a/tests/cd.out +++ b/tests/cd.out @@ -17,3 +17,7 @@ cd: ../a2/ ../a3/ ../rabbithole/ + +#################### +# Virtual PWD inheritance +PWD is /tmp/cdcomp_test/linkhome From 6bd3474daf9d8b5a9c4bd19fc9b3368a85c49dcc Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Tue, 22 Jan 2019 14:33:47 -0800 Subject: [PATCH 30/67] Make control-S begin navigating the pager contents In addition to showing the search field, actually allow the user to type in it. --- CHANGELOG.md | 3 ++- src/reader.cpp | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0782b2051..e9474eb3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,3 @@ -<<<<<<< HEAD # fish 3.0.1 This release of fish fixes a number of major issues discovered in fish 3.0.0. @@ -9,6 +8,8 @@ This release of fish fixes a number of major issues discovered in fish 3.0.0. - while loops now evaluate to the last executed command in the loop body (or zero if the body was empty), matching POSIX semantics. - `read --silent` no longer echoes to the tty when run from a non-interactive script (#5519) - (macOS only) /etc/paths and /etc/paths.d now correctly set path entries with spaces. Also affects MANPATH. (#5481) +- fish does not hang on launch when running under Cygwin/MSYS2 +- The pager-toggle-search binding (by default Control-S) now positions the cursor in the completions list. If you are upgrading from version 2.7.1 or before, please also review the release notes for 3.0.0 and 3.0b1 (included below). diff --git a/src/reader.cpp b/src/reader.cpp index 893ac885f..2bc74d79d 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -2711,10 +2711,15 @@ const wchar_t *reader_readline(int nchars) { break; } case R_PAGER_TOGGLE_SEARCH: { - if (data->is_navigating_pager_contents()) { + if (!data->pager.empty()) { + // Toggle search, and begin navigating if we are now searching. bool sfs = data->pager.is_search_field_shown(); data->pager.set_search_field_shown(!sfs); data->pager.set_fully_disclosed(true); + if (data->pager.is_search_field_shown() && + !data->is_navigating_pager_contents()) { + select_completion_in_direction(direction_south); + } reader_repaint_needed(); } break; From 88ee55443cd6001a74db799c58e58d268ad01ec4 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Tue, 22 Jan 2019 14:36:25 -0800 Subject: [PATCH 31/67] Update docs on tab completions and searching Fixes #5547 --- doc_src/index.hdr.in | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc_src/index.hdr.in b/doc_src/index.hdr.in index 7f2fe7efc..c75c6b82d 100644 --- a/doc_src/index.hdr.in +++ b/doc_src/index.hdr.in @@ -320,7 +320,9 @@ Autosuggestions are a powerful way to quickly summon frequently entered commands \section completion Tab completion -Tab completion is one of the most time saving features of any modern shell. By tapping the tab key, the user asks `fish` to guess the rest of the command or parameter that the user is currently typing. If `fish` can only find one possible completion, `fish` will write it out. If there is more than one completion, `fish` will write out the longest prefix that all completions have in common. If the completions differ on the first character, a list of all possible completions is printed. The list features descriptions of the completions and if the list doesn't fit the screen, it is scrollable by using the arrow keys, the page up/page down keys, the tab key or the space bar. Once the list has been entered, pressing any other key will start a search. If the list has not been entered, pressing any other key will exit the list and insert the pressed key into the command line. +Tab completion is one of the most time saving features of any modern shell. By tapping the tab key, the user asks `fish` to guess the rest of the command or parameter that the user is currently typing. If `fish` can only find one possible completion, `fish` will write it out. If there is more than one completion, `fish` will write out the longest prefix that all completions have in common. If the completions differ on the first character, a list of all possible completions is printed. The list features descriptions of the completions and if the list doesn't fit the screen, it is scrollable by using the arrow keys, the page up/page down keys, the tab key or the space bar. + +If the list is visible, pressing control-S (or the `pager-toggle-search` binding) will allow filtering the list. Shift-tab (or the `complete-and-search` binding) will trigger completion with the search field immediately visible. These are the general purpose tab completions that `fish` provides: From 72423c517a788843caa0f7cfaf99aa32b4b9a5fa Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Wed, 16 Jan 2019 09:29:17 +0100 Subject: [PATCH 32/67] webconfig: Fix binding tab This broke when --preset was introduced. We allow a "--preset" or "--user" to appear right after the "bind", and save the value, but don't use it yet. Fixes #5534. [ci skip] --- share/tools/web_config/webconfig.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/share/tools/web_config/webconfig.py b/share/tools/web_config/webconfig.py index 58702f2fa..a5c5ef981 100755 --- a/share/tools/web_config/webconfig.py +++ b/share/tools/web_config/webconfig.py @@ -704,6 +704,20 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): for line in out.split('\n'): comps = line.split(' ', 2) + # If we don't have "bind", a sequence and a mapping, + # it's not a valid binding. + if len(comps) < 3: + continue + + # Store the "--preset" value for later + if comps[1] == '--preset': + preset = True + # There's possibly a way to do this faster, but it's not important. + comps = line.split(' ', 3)[1:] + elif comps[1] == '--user': + preset = False + comps = line.split(' ', 3)[1:] + # Check again if we removed the level. if len(comps) < 3: continue From a1df72dbb60f26b1ca6e24b6c3fd39e07a6ebf14 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Wed, 2 Jan 2019 17:25:33 -0600 Subject: [PATCH 33/67] Fix `wcstod_l` infinite recursion under FreeBSD This was the actual issue leading to memory corruption under FreeBSD in issue #5453, worked around by correcting the detection of `wcstod_l` so that our version of the function is not called at all. If we are 100% certain that `wcstod_l` does not exist, then then the existing code is fine. But given that our checks have failed seperately on two different platforms already (FreeBSD and Cygwin/newlib), it's a good precaution to take. --- src/fallback.cpp | 7 ++++--- src/fallback.h | 12 +++++++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/fallback.cpp b/src/fallback.cpp index d7e4e508e..8a7d6a0e2 100644 --- a/src/fallback.cpp +++ b/src/fallback.cpp @@ -390,9 +390,10 @@ int flock(int fd, int op) { #endif // HAVE_FLOCK #ifndef HAVE_WCSTOD_L -// musl doesn't feature wcstod_l, -// so we just wrap wcstod. -double wcstod_l(const wchar_t *enptr, wchar_t **endptr, locale_t loc) { +#undef wcstod_l +// For platforms without wcstod_l C extension, wrap wcstod after changing the +// thread-specific locale. +double fish_compat::wcstod_l(const wchar_t *enptr, wchar_t **endptr, locale_t loc) { char *saved_locale = strdup(setlocale(LC_NUMERIC, NULL)); // Yes, this is hardcoded to use the "C" locale. // That's the only thing we need, and uselocale(loc) broke in my testing. diff --git a/src/fallback.h b/src/fallback.h index f8b7d4977..b935c8460 100644 --- a/src/fallback.h +++ b/src/fallback.h @@ -200,5 +200,15 @@ int flock(int fd, int op); #endif #ifndef HAVE_WCSTOD_L -double wcstod_l(const wchar_t *enptr, wchar_t **endptr, locale_t loc); +// On some platforms if this is incorrectly detected and a system-defined +// defined version of `wcstod_l` exists, calling `wcstod` from our own +// `wcstod_l` can call back into `wcstod_l` causing infinite recursion. +// e.g. FreeBSD defines `wcstod(x, y)` as `wcstod_l(x, y, __get_locale())`. +// Solution: namespace our implementation to make sure there is no symbol +// duplication. +#undef wcstod_l +namespace fish_compat { + double wcstod_l(const wchar_t *enptr, wchar_t **endptr, locale_t loc); +} +#define wcstod_l(x, y, z) fish_compat::wcstod_l(x, y, z) #endif From 1d80028e246b219f981318378a881f4ede03c1c1 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Tue, 22 Jan 2019 01:12:57 +0100 Subject: [PATCH 34/67] __fish_complete_man.fish: escape for regex Previously, using special regex characters or slashes would result in an error message, when pressing tab in a command-line such as "man /usr/bin/time ". --- share/functions/__fish_complete_man.fish | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/share/functions/__fish_complete_man.fish b/share/functions/__fish_complete_man.fish index e65d61c07..a8d3daf97 100644 --- a/share/functions/__fish_complete_man.fish +++ b/share/functions/__fish_complete_man.fish @@ -10,7 +10,8 @@ function __fish_complete_man case '-**' case '*' - set section $prev[1] + set section (string escape --style=regex $prev[1]) + set section (string replace --all / \\/ $section) end set -e prev[1] end From da44ee1d087423cd95298d19ef97c32cac4a8130 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sun, 30 Dec 2018 16:04:57 +0100 Subject: [PATCH 35/67] Don't wait for disowned pgids if they are special If a job is disowned that, for some reason, has a pgid that is special to waitpid, like 0 (process with pgid of the calling process), -1 (any process), or our actual pgid, that would lead to us waiting for too many processes when we later try to reap the disowned processes (to stop zombies from appearing). And that means we'd snag away the processes we actually do want to wait for, which would end with us in a waiting loop. This is tough to reproduce, the easiest I've found was fish -ic 'sleep 5 &; disown; set -g __fish_git_prompt_showupstream auto; __fish_git_prompt' in a git repo. What we do is to not allow special pgids in the disowned_pids list. That means we might leave a zombie around (though we probably wait on 0 somewhere), but that's preferable to infinitely looping. See #5426. --- src/proc.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/proc.cpp b/src/proc.cpp index b7b30dc22..e09747f8a 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -354,7 +354,12 @@ typedef unsigned int process_generation_count_t; static std::vector s_disowned_pids; void add_disowned_pgid(pid_t pgid) { - s_disowned_pids.push_back(pgid * -1); + // NEVER add our own pgid, or one of the special values, + // or waiting for it will + // snag other processes away. + if (pgid != getpgrp() && (pgid > 0 || pgid < -1)) { + s_disowned_pids.push_back(pgid * -1); + } } /// A static value tracking how many SIGCHLDs we have seen, which is used in a heurstic to From c20187e858a257025912b8a17043ed76e774d3b8 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Wed, 23 Jan 2019 14:02:03 +0100 Subject: [PATCH 36/67] completions/git: Stop offering :/ files so much Don't do it when the relative path is simple (purely descending), unless the token starts with ":/". Also stop offering directories - if they need to be disambiguated, the normal completion logic will take care of that. Fixes #5574. [ci skip] --- share/completions/git.fish | 46 ++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/share/completions/git.fish b/share/completions/git.fish index c8683e31e..da7842e6b 100644 --- a/share/completions/git.fish +++ b/share/completions/git.fish @@ -121,8 +121,6 @@ function __fish_git_files contains -- copied $argv; and set -l copied and set -l copied_desc (_ "Copied file") - set -l dir_desc (_ "Directory") - # A literal "?" for use in `case`. set -l q '\\?' if status test-feature qmark-noglob @@ -245,27 +243,22 @@ function __fish_git_files # First the relative filename. printf '%s\t%s\n' "$file" $desc # Now from repo root. - set -l fromroot (builtin realpath -- $file 2>/dev/null) - and set fromroot (string replace -- "$root/" ":/" "$fromroot") - and printf '%s\t%s\n' "$fromroot" $desc - - # And the containing directory. - # TODO: We may want to offer the parent, but only if another child of that also has a change. - # E.g: - # - a/b/c is added - # - a/d/e is modified - # - a/ should be offered, but only a/b/ and a/d/ are. - # - # Always offering all parents is overkill however, which is why we don't currently do it. - set -l dir (string replace -rf '/[^/]+$' '/' -- $file) - and printf '%s\t%s\n' $dir "$dir_desc" + # Only do this if the filename isn't a simple child, + # or the current token starts with ":" + if string match -q '../*' -- $file + or string match -q ':*' -- (commandline -ct) + set -l fromroot (builtin realpath -- $file 2>/dev/null) + and set fromroot (string replace -- "$root/" ":/" "$fromroot") + and printf '%s\t%s\n' "$fromroot" $desc + end end end else # v1 format logic # We need to compute relative paths on our own, which is slow. # Pre-remove the root at least, so we have fewer components to deal with. - set -l _pwd_list (string replace "$root/" "" -- $PWD | string split /) + set -l _pwd_list (string replace "$root/" "" -- $PWD/ | string split /) + test -z "$_pwd_list[-1]"; and set -e _pwd_list[-1] # Cache the previous relative path because these are sorted, so we can reuse it # often for files in the same directory. set -l previous @@ -349,9 +342,7 @@ function __fish_git_files # Again: "XY filename", so the filename starts on character 4. set -l relfile (string sub -s 4 -- $line) - # The filename with ":/" prepended. - set -l file (string replace -- "$root/" ":/" "$root/$relfile") - + set -l file # Computing relative path by hand. set -l abs (string split / -- $relfile) # If it's in the same directory, we just need to change the filename. @@ -359,7 +350,6 @@ function __fish_git_files set previous[-1] $abs[-1] else set -l pwd_list $_pwd_list - set previousfile $abs # Remove common prefix while test "$pwd_list[1]" = "$abs[1]" set -e pwd_list[1] @@ -369,10 +359,18 @@ function __fish_git_files set previous (string replace -r '.*' '..' -- $pwd_list) $abs end set -a file (string join / -- $previous) - printf '%s\n' $file\t$desc - set -l dir (string replace -rf '/[^/]+$' '/' -- $file) - and printf '%s\t%s\n' $dir "$dir_desc" + # The filename with ":/" prepended. + if string match -q '../*' -- $file + or string match -q ':*' -- (commandline -ct) + set file (string replace -- "$root/" ":/" "$root/$relfile") + end + + if test "$root/$relfile" = (pwd -P)/$relfile + set file $relfile + end + + printf '%s\n' $file\t$desc end end end From 70f618d5989b7fb54b6efd5556a63478fbe6d65b Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Mon, 31 Dec 2018 02:31:48 -0600 Subject: [PATCH 37/67] Fix wcstod_l detection under FreeBSD --- cmake/ConfigureChecks.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/ConfigureChecks.cmake b/cmake/ConfigureChecks.cmake index 1444361e9..5182ba808 100644 --- a/cmake/ConfigureChecks.cmake +++ b/cmake/ConfigureChecks.cmake @@ -72,7 +72,7 @@ CHECK_CXX_SYMBOL_EXISTS(wcsdup wchar.h HAVE_WCSDUP) CHECK_CXX_SYMBOL_EXISTS(wcslcpy wchar.h HAVE_WCSLCPY) CHECK_CXX_SYMBOL_EXISTS(wcsncasecmp wchar.h HAVE_WCSNCASECMP) CHECK_CXX_SYMBOL_EXISTS(wcsndup wchar.h HAVE_WCSNDUP) -CHECK_CXX_SYMBOL_EXISTS(wcstod_l wchar.h HAVE_WCSTOD_L) +CHECK_CXX_SYMBOL_EXISTS(wcstod_l "wchar.h;xlocale.h" HAVE_WCSTOD_L) CHECK_CXX_SYMBOL_EXISTS(_sys_errs stdlib.h HAVE__SYS__ERRS) From 3875615f45f861a2cf0b17b9d79a29e3a0b563ac Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Wed, 2 Jan 2019 14:05:06 -0600 Subject: [PATCH 38/67] Define _GNU_SOURCE for wcstod_l check --- cmake/ConfigureChecks.cmake | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmake/ConfigureChecks.cmake b/cmake/ConfigureChecks.cmake index 5182ba808..0b5dfd26a 100644 --- a/cmake/ConfigureChecks.cmake +++ b/cmake/ConfigureChecks.cmake @@ -28,6 +28,7 @@ INCLUDE(CheckIncludeFiles) INCLUDE(CheckStructHasMember) INCLUDE(CheckCXXSourceCompiles) INCLUDE(CheckTypeSize) +INCLUDE(CMakePushCheckState) CHECK_CXX_SYMBOL_EXISTS(backtrace_symbols execinfo.h HAVE_BACKTRACE_SYMBOLS) CHECK_CXX_SYMBOL_EXISTS(clock_gettime time.h HAVE_CLOCK_GETTIME) CHECK_CXX_SYMBOL_EXISTS(ctermid_r stdio.h HAVE_CTERMID_R) @@ -72,7 +73,12 @@ CHECK_CXX_SYMBOL_EXISTS(wcsdup wchar.h HAVE_WCSDUP) CHECK_CXX_SYMBOL_EXISTS(wcslcpy wchar.h HAVE_WCSLCPY) CHECK_CXX_SYMBOL_EXISTS(wcsncasecmp wchar.h HAVE_WCSNCASECMP) CHECK_CXX_SYMBOL_EXISTS(wcsndup wchar.h HAVE_WCSNDUP) + +CMAKE_PUSH_CHECK_STATE(RESET) +# wcstod_l is a GNU-extension, sometimes hidden behind the following define +LIST(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE=1) CHECK_CXX_SYMBOL_EXISTS(wcstod_l "wchar.h;xlocale.h" HAVE_WCSTOD_L) +CMAKE_POP_CHECK_STATE() CHECK_CXX_SYMBOL_EXISTS(_sys_errs stdlib.h HAVE__SYS__ERRS) From 0f2470d45a1b4f0ebe7f46a24ae4bb97b5a418c1 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Wed, 2 Jan 2019 17:29:48 -0600 Subject: [PATCH 39/67] Fix unsafe locale usage in `wcstod_l` fallback Using `setlocale` is both not thread-safe and not correct, as a) The global locale is usually stored in static storage, so simultaneous calls to `setlocale` can result in corruption, and b) `setlocale` changes the locale for the entire application, not just the calling thread. This means that even if we wrapped the `wcstod_l` in a mutex to prevent the previous point, the results would still be incorrect because this would incorrectly influence the results of locale-aware functions executed in other threads while this thread is executing. The previous comment mentioned that `uselocale` hadn't worked. I'm not sure what the failing implementation looked like, but `uselocale` can be tricky. The committed implementation passes the tests for me under Linux and FreeBSD. --- src/fallback.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/fallback.cpp b/src/fallback.cpp index 8a7d6a0e2..41d897296 100644 --- a/src/fallback.cpp +++ b/src/fallback.cpp @@ -394,13 +394,13 @@ int flock(int fd, int op) { // For platforms without wcstod_l C extension, wrap wcstod after changing the // thread-specific locale. double fish_compat::wcstod_l(const wchar_t *enptr, wchar_t **endptr, locale_t loc) { - char *saved_locale = strdup(setlocale(LC_NUMERIC, NULL)); - // Yes, this is hardcoded to use the "C" locale. - // That's the only thing we need, and uselocale(loc) broke in my testing. - setlocale(LC_NUMERIC, "C"); + // Create and use a new, thread-specific locale + locale_t locale = newlocale(LC_NUMERIC, "C", nullptr); + locale_t prev_locale = uselocale(locale); double ret = wcstod(enptr, endptr); - setlocale(LC_NUMERIC, saved_locale); - free(saved_locale); + // Restore the old locale before freeing the locale we created and are still using + uselocale(prev_locale); + freelocale(locale); return ret; } #endif // defined(wcstod_l) From 8737b654bfde81e45cf39976b9ea22f0ddc80c7e Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Wed, 2 Jan 2019 19:07:53 -0600 Subject: [PATCH 40/67] Fix `wcstod_l` detection under Linux This was broken in a8eb02f9f59350f222295e16b8f68dc3b45d9ed5 when the detection was corrected for FreeBSD. This patch makes the detection work for both Linux and FreeBSD instead of one or the other (tested). --- cmake/ConfigureChecks.cmake | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/cmake/ConfigureChecks.cmake b/cmake/ConfigureChecks.cmake index 0b5dfd26a..22b0066a0 100644 --- a/cmake/ConfigureChecks.cmake +++ b/cmake/ConfigureChecks.cmake @@ -75,9 +75,17 @@ CHECK_CXX_SYMBOL_EXISTS(wcsncasecmp wchar.h HAVE_WCSNCASECMP) CHECK_CXX_SYMBOL_EXISTS(wcsndup wchar.h HAVE_WCSNDUP) CMAKE_PUSH_CHECK_STATE(RESET) -# wcstod_l is a GNU-extension, sometimes hidden behind the following define +# `wcstod_l` is a GNU-extension, sometimes hidden behind the following define LIST(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE=1) -CHECK_CXX_SYMBOL_EXISTS(wcstod_l "wchar.h;xlocale.h" HAVE_WCSTOD_L) +# `xlocale.h` is required to find `wcstod_l` in `wchar.h` under FreeBSD, but +# it's not present under Linux. +SET(WCSTOD_L_INCLUDES "") +CHECK_INCLUDE_FILES("xlocale.h" HAVE_XLOCALE_H) +IF(HAVE_XLOCALE_H) + LIST(APPEND WCSTOD_L_INCLUDES "xlocale.h") +ENDIF() +LIST(APPEND WCSTOD_L_INCLUDES "wchar.h") +CHECK_CXX_SYMBOL_EXISTS(wcstod_l "${WCSTOD_L_INCLUDES}" HAVE_WCSTOD_L) CMAKE_POP_CHECK_STATE() CHECK_CXX_SYMBOL_EXISTS(_sys_errs stdlib.h HAVE__SYS__ERRS) From 55526947d256e9933bac886876c044a25fc4820f Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Thu, 10 Jan 2019 19:51:12 -0600 Subject: [PATCH 41/67] Fix `locale_t` under macOS 10.10 `xlocale.h` is not available on Linux, so we can't just universally include it. `HAVE_XLOCALE_H` was already being tested/set in the CMake script as a possible requirement for `wcstod_l` support, this just adds it to `config_cmake_h.in` and uses it in `wutil.h` to gate the include. --- config_cmake.h.in | 3 +++ src/wutil.h | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/config_cmake.h.in b/config_cmake.h.in index 47cfcc5e2..8071546fd 100644 --- a/config_cmake.h.in +++ b/config_cmake.h.in @@ -153,6 +153,9 @@ /* The size of wchar_t in bits. */ #define WCHAR_T_BITS ${WCHAR_T_BITS} +/* Define if xlocale.h is required for locale_t or wide character support */ +#cmakedefine HAVE_XLOCALE_H 1 + /* Enable large inode numbers on Mac OS X 10.5. */ #ifndef _DARWIN_USE_64_BIT_INODE # define _DARWIN_USE_64_BIT_INODE 1 diff --git a/src/wutil.h b/src/wutil.h index 28a8540d1..661e82d05 100644 --- a/src/wutil.h +++ b/src/wutil.h @@ -10,6 +10,10 @@ #include #include +#ifdef HAVE_XLOCALE_H +#include +#endif + #include "common.h" #include "maybe.h" From aee8e5250a1b3d0ae1cbe969c37daadae7a48001 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Wed, 16 Jan 2019 14:42:15 -0600 Subject: [PATCH 42/67] Add missing define for HAVE_WCSTOD_L to osx/config.h I believe this should take care of the reported problem with the corrected definition for `wcstod_l`. For future reference, any changes to `config.h.in` should also be reflected in `osx/config.h` --- osx/config.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osx/config.h b/osx/config.h index d8036fee7..233464b40 100644 --- a/osx/config.h +++ b/osx/config.h @@ -181,6 +181,9 @@ /* Define to 1 if you have the `wcsndup' function. */ /* #undef HAVE_WCSNDUP */ +/* Define to 1 if you have the `wcstod_l' function. */ +#define HAVE_WCSTOD_L 1 + /* Define to 1 if the winsize struct and TIOCGWINSZ macro exist */ #define HAVE_WINSIZE 1 From e8f340a03d8792a97610703d5e41458fea60af44 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Mon, 21 Jan 2019 17:08:49 -0800 Subject: [PATCH 43/67] string completions: add missing upper, lower, split0, join0, unescape and --style=regex --- share/completions/string.fish | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/share/completions/string.fish b/share/completions/string.fish index ea2bae47b..37d72f5b6 100644 --- a/share/completions/string.fish +++ b/share/completions/string.fish @@ -2,23 +2,29 @@ # This follows a strict command-then-options approach, so we can just test the number of tokens complete -f -c string complete -f -c string -n "test (count (commandline -opc)) -ge 2; and not contains -- (commandline -opc)[2] escape" -s q -l quiet -d "Do not print output" +complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a "lower" +complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a "upper" complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a "length" complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a "sub" -complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] sub" -s s -l start -a "(seq 1 10)" -complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] sub" -s l -l length -a "(seq 1 10)" +complete -x -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] sub" -s s -l start -a "(seq 1 10)" +complete -x -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] sub" -s l -l length -a "(seq 1 10)" complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a "split" -complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] split" -s m -l max -a "(seq 1 10)" -d "Specify maximum number of splits" -complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] split" -s r -l right -d "Split right-to-left" +complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a "split0" +complete -x -c string -n 'test (count (commandline -opc)) -ge 2; and string match -qr split0\?\$ -- (commandline -opc)[2]' -s m -l max -a "(seq 1 10)" -d "Specify maximum number of splits" +complete -f -c string -n 'test (count (commandline -opc)) -ge 2; and string match -qr split0\?\$ -- (commandline -opc)[2]' -s r -l right -d "Split right-to-left" complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a "join" +complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a "join0" complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a "trim" complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] trim" -s l -l left -d "Trim only leading characters" complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] trim" -s r -l right -d "Trim only trailing characters" complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] trim" -s c -l chars -d "Specify the chars to trim (default: whitespace)" complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a "escape" -complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] escape" -s n -l no-quoted -d "Escape with \\ instead of quoting" -complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] escape" -l style -d "Pick escaping style" -a " +complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a "unescape" +complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] escape; or contains -- (commandline -opc)[2] unescape" -s n -l no-quoted -d "Escaped with \\ instead of quoted" +complete -x -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] escape; or contains -- (commandline -opc)[2] unescape" -l style -d "Escaping style" -a " (printf '%s\t%s\n' script 'For use in scripts' \ var 'For use as a variable name' \ + regex 'For string match -r, string replace -r' \ url 'For use as a URL')" complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a "match" complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] match" -s n -l index -d "Report index and length of the matches" @@ -29,6 +35,6 @@ complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] match replace" -s i -l ignore-case -d "Case insensitive" complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] match replace" -s r -l regex -d "Use regex instead of globs" complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a "repeat" -complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] repeat" -s n -l count -a "(seq 1 10)" -d "Repetition count" -complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] repeat" -s m -l max -a "(seq 1 10)" -d "Maximum number of printed char" +complete -x -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] repeat" -s n -l count -a "(seq 1 10)" -d "Repetition count" +complete -x -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] repeat" -s m -l max -a "(seq 1 10)" -d "Maximum number of printed char" complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] repeat" -s N -l no-newline -d "Remove newline" From 5b12d703dd6c136a5fd7c7c4c55d5b3d3922238a Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Mon, 21 Jan 2019 13:59:36 -0800 Subject: [PATCH 44/67] Fix fish_config rendering brights as normal on prompt previews I noticed our default brgreen for fish_color_user was rendering as just unstyled white. --- share/tools/web_config/fishconfig.css | 1 + share/tools/web_config/webconfig.py | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/share/tools/web_config/fishconfig.css b/share/tools/web_config/fishconfig.css index ca74fa570..34eafd050 100644 --- a/share/tools/web_config/fishconfig.css +++ b/share/tools/web_config/fishconfig.css @@ -474,6 +474,7 @@ img.delete_icon { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + color: #c0c0c0; /* set_color normal, assume white (not brwhite) */ } .prompt_demo { diff --git a/share/tools/web_config/webconfig.py b/share/tools/web_config/webconfig.py index a5c5ef981..15ae8d2a5 100755 --- a/share/tools/web_config/webconfig.py +++ b/share/tools/web_config/webconfig.py @@ -21,6 +21,7 @@ import socket import string import subprocess import sys +from itertools import chain FISH_BIN_PATH = False # will be set later IS_PY2 = sys.version_info[0] == 2 @@ -254,7 +255,6 @@ def get_special_ansi_escapes(): def append_html_for_ansi_escape(full_val, result, span_open): - # Strip off the initial \x1b[ and terminating m val = full_val[2:-1] @@ -271,10 +271,10 @@ def append_html_for_ansi_escape(full_val, result, span_open): result.append('') return True # span now open - # term8 foreground color - if val in [str(x) for x in range(30, 38)]: + # term16 foreground color + if val in (str(x) for x in chain(range(90, 97), range(30, 38))): close_span() - html_color = html_color_for_ansi_color_index(int(val) - 30) + html_color = html_color_for_ansi_color_index(int(val) - (30 if int(val) < 90 else 82)) result.append('') return True # span now open @@ -284,7 +284,7 @@ def append_html_for_ansi_escape(full_val, result, span_open): close_span() return False - # We don't handle bold or underline yet + # TODO We don't handle bold, underline, italics, dim, or reverse yet # Do nothing on failure return span_open From 3bf702067af06325362ad7e24626aff0f61da7f6 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Mon, 14 Jan 2019 03:08:44 -0800 Subject: [PATCH 45/67] fish_config: tell the user some nice things without Python As discussed in #5492, it would be good if running fish_config without Python actually told the user to install Python. Further, let's give the person some hints on how to configure these things by hand, since they may have to. --- share/functions/fish_config.fish | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/share/functions/fish_config.fish b/share/functions/fish_config.fish index fa6c54e46..b8fb455d6 100644 --- a/share/functions/fish_config.fish +++ b/share/functions/fish_config.fish @@ -6,5 +6,12 @@ function fish_config --description "Launch fish's web based configuration" python2 "$__fish_data_dir/tools/web_config/webconfig.py" $argv else if command -sq python python "$__fish_data_dir/tools/web_config/webconfig.py" $argv + else + echo (set_color $fish_color_error)Cannot launch the web configuration tool.(set_color normal) + echo (set_color -o)fish_config(set_color normal) requires Python. + echo Installing Python will fix this, and also enable completions to be automatically generated from man pages.\n + echo To configure your prompt, create a (set_color -o)fish_prompt(set_color normal) function. + echo There are examples in (set_color $fish_color_valid_path)$__fish_data_dir/tools/web_config/sample_prompts(set_color normal).\n + echo You can tweak your colors by setting the (set_color $fish_color_search_match)\$fish_color_\*(set_color normal) variables. end end From b5cbdc906591c1eafc77a6d555bee6e8f6cbe700 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Mon, 14 Jan 2019 03:23:47 -0800 Subject: [PATCH 46/67] fish_config: make clear python 2 or 3 will both work. A person stuck installing it just for fish on their server doesn't want to waste time installing the wrong one, so assuage that. Also tweak to look nicer with 80 columns --- share/functions/fish_config.fish | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/share/functions/fish_config.fish b/share/functions/fish_config.fish index b8fb455d6..d4ef02c9a 100644 --- a/share/functions/fish_config.fish +++ b/share/functions/fish_config.fish @@ -7,10 +7,11 @@ function fish_config --description "Launch fish's web based configuration" else if command -sq python python "$__fish_data_dir/tools/web_config/webconfig.py" $argv else - echo (set_color $fish_color_error)Cannot launch the web configuration tool.(set_color normal) + echo (set_color $fish_color_error)Cannot launch the web configuration tool:(set_color normal) echo (set_color -o)fish_config(set_color normal) requires Python. - echo Installing Python will fix this, and also enable completions to be automatically generated from man pages.\n - echo To configure your prompt, create a (set_color -o)fish_prompt(set_color normal) function. + echo Installing python2 or python3 will fix this, and also enable completions to be + echo automatically generated from man pages.\n + echo To change your prompt, create a (set_color -o)fish_prompt(set_color normal) function. echo There are examples in (set_color $fish_color_valid_path)$__fish_data_dir/tools/web_config/sample_prompts(set_color normal).\n echo You can tweak your colors by setting the (set_color $fish_color_search_match)\$fish_color_\*(set_color normal) variables. end From e462c6fe0ef6821cd0ff8377fa7b867e0d255d27 Mon Sep 17 00:00:00 2001 From: John McKay <34872500+McKayJT@users.noreply.github.com> Date: Wed, 9 Jan 2019 23:07:09 +0000 Subject: [PATCH 47/67] print --help to stdout like other builtins (#5495) --- src/builtin_string.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/builtin_string.cpp b/src/builtin_string.cpp index bbc7e40c0..8e7777111 100644 --- a/src/builtin_string.cpp +++ b/src/builtin_string.cpp @@ -1305,7 +1305,7 @@ int builtin_string(parser_t &parser, io_streams_t &streams, wchar_t **argv) { } if (wcscmp(argv[1], L"-h") == 0 || wcscmp(argv[1], L"--help") == 0) { - builtin_print_help(parser, streams, L"string", streams.err); + builtin_print_help(parser, streams, L"string", streams.out); return STATUS_CMD_OK; } From 91ac0f1b188d79f8b0d71fd2d50d967ecdd5e3bc Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Wed, 23 Jan 2019 17:42:13 -0600 Subject: [PATCH 48/67] Work around for Cygwin's broken job control resolving fish 3.0 hang (cherry picked from commit d1913f0df0e5d05fa553b6d482f1cb71261f22ba) --- cmake/ConfigureChecks.cmake | 5 +++++ config_cmake.h.in | 3 +++ src/common.h | 9 +++++++++ src/proc.cpp | 32 ++++++++++++++++++++++++++++---- 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/cmake/ConfigureChecks.cmake b/cmake/ConfigureChecks.cmake index 22b0066a0..4313582dc 100644 --- a/cmake/ConfigureChecks.cmake +++ b/cmake/ConfigureChecks.cmake @@ -19,6 +19,11 @@ if (CMAKE_HOST_SYSTEM_VERSION MATCHES ".*-Microsoft") SET(WSL 1) endif() +# Detect Cygwin. +if (CMAKE_SYSTEM_NAME MATCHES "CYGWIN_NT.*") + SET(CYGWIN 1) +endif() + # Set up the config.h file. SET(PACKAGE_NAME "fish") SET(PACKAGE_TARNAME "fish") diff --git a/config_cmake.h.in b/config_cmake.h.in index 8071546fd..2c6fde27d 100644 --- a/config_cmake.h.in +++ b/config_cmake.h.in @@ -4,6 +4,9 @@ /* Define to 1 if compiled on WSL */ #cmakedefine WSL 1 +/* Define to 1 if complied under Cygwin */ +#cmakedefine CYGWIN 1 + /* Define to 1 if you have the `clock_gettime' function. */ #cmakedefine HAVE_CLOCK_GETTIME 1 diff --git a/src/common.h b/src/common.h index 49a381f0f..d0436ff59 100644 --- a/src/common.h +++ b/src/common.h @@ -976,6 +976,15 @@ constexpr bool is_windows_subsystem_for_linux() { #endif } +/// Detect if we are running under Cygwin or Cgywin64 +constexpr bool is_cygwin() { +#ifdef CYGWIN + return true; +#else + return false; +#endif +} + extern "C" { __attribute__((noinline)) void debug_thread_error(void); } diff --git a/src/proc.cpp b/src/proc.cpp index e09747f8a..0228d176b 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -447,10 +447,34 @@ static bool process_mark_finished_children(bool block_on_fg) { options &= ~WNOHANG; } - // If the pgid is 0, we need to wait by process because that's invalid. - // This happens in firejail for reasons not entirely clear to me. - bool wait_by_process = !j->job_chain_is_fully_constructed() || j->pgid == 0; - process_list_t::iterator process = j->processes.begin(); + // Child jobs (produced via execution of functions) share job ids with their not-yet- + // fully-constructed parent jobs, so we have to wait on these by individual process id + // and not by the shared pgroup. End result is the same, but it just makes more calls + // to the kernel. + bool wait_by_process = !j->job_chain_is_fully_constructed(); + + // Firejail can result in jobs with pgroup 0, in which case we cannot wait by + // job id. See discussion in #5295. + if (j->pgid == 0) { + wait_by_process = true; + } + + // Cygwin does some voodoo with regards to process management that I do not understand, but + // long story short, we cannot reap processes by their pgroup. The way child processes are + // launched under Cygwin is... weird, and outwardly they do not appear to retain information + // about their parent process when viewed in Task Manager. Waiting on processes by their + // pgroup results in never reaping any, so we just wait on them by process id instead. + if (is_cygwin()) { + wait_by_process = true; + } + + // When waiting on processes individually in a pipeline, we need to enumerate in reverse + // order so that the first process we actually wait on (i.e. ~WNOHANG) is the last process + // in the IO chain, because that's the one that controls the lifetime of the foreground job + // - as long as it is still running, we are in the background and once it exits or is + // killed, all previous jobs in the IO pipeline must necessarily terminate as well. + auto process = j->processes.begin(); + // waitpid(2) returns 1 process each time, we need to keep calling it until we've reaped all // children of the pgrp in question or else we can't reset the dirty_state flag. In all // cases, calling waitpid(2) is faster than potentially calling select_try() on a process From a5ef1e395e6016a145dbbdd72e175a50a3a2004f Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Mon, 21 Jan 2019 20:06:16 -0600 Subject: [PATCH 49/67] Use standard __CYGWIN__ define for Cygwin detection (cherry picked from commit 462cb6044c5c2f78cf7e23c52af495c6f5e33d91) --- cmake/ConfigureChecks.cmake | 5 ----- config_cmake.h.in | 3 --- src/common.h | 2 +- 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/cmake/ConfigureChecks.cmake b/cmake/ConfigureChecks.cmake index 4313582dc..22b0066a0 100644 --- a/cmake/ConfigureChecks.cmake +++ b/cmake/ConfigureChecks.cmake @@ -19,11 +19,6 @@ if (CMAKE_HOST_SYSTEM_VERSION MATCHES ".*-Microsoft") SET(WSL 1) endif() -# Detect Cygwin. -if (CMAKE_SYSTEM_NAME MATCHES "CYGWIN_NT.*") - SET(CYGWIN 1) -endif() - # Set up the config.h file. SET(PACKAGE_NAME "fish") SET(PACKAGE_TARNAME "fish") diff --git a/config_cmake.h.in b/config_cmake.h.in index 2c6fde27d..8071546fd 100644 --- a/config_cmake.h.in +++ b/config_cmake.h.in @@ -4,9 +4,6 @@ /* Define to 1 if compiled on WSL */ #cmakedefine WSL 1 -/* Define to 1 if complied under Cygwin */ -#cmakedefine CYGWIN 1 - /* Define to 1 if you have the `clock_gettime' function. */ #cmakedefine HAVE_CLOCK_GETTIME 1 diff --git a/src/common.h b/src/common.h index d0436ff59..f0a4be570 100644 --- a/src/common.h +++ b/src/common.h @@ -978,7 +978,7 @@ constexpr bool is_windows_subsystem_for_linux() { /// Detect if we are running under Cygwin or Cgywin64 constexpr bool is_cygwin() { -#ifdef CYGWIN +#ifdef __CYGWIN__ return true; #else return false; From 77b7f5513e240ec8385de3e3157bf2daf99e5628 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sat, 26 Jan 2019 21:16:50 +0100 Subject: [PATCH 50/67] default_command_not_found_handler: Join arguments Without it, this would print the error multiple times, like Unknown command: echs Unknown command: 1 Unknown command: 2 Unknown command: 3 Fixes #5588. --- share/config.fish | 2 +- tests/invocation/broken-config-continues.err | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/share/config.fish b/share/config.fish index a3abb82f3..3d6ba2417 100644 --- a/share/config.fish +++ b/share/config.fish @@ -12,7 +12,7 @@ or set -g __fish_added_user_paths # Create the default command_not_found handler # function __fish_default_command_not_found_handler - printf "fish: Unknown command '%s'\n" (string escape -- $argv) >&2 + printf "fish: Unknown command %s\n" (string escape -- "$argv") >&2 end if status --is-interactive diff --git a/tests/invocation/broken-config-continues.err b/tests/invocation/broken-config-continues.err index d313eb7f7..5ab2906b6 100644 --- a/tests/invocation/broken-config-continues.err +++ b/tests/invocation/broken-config-continues.err @@ -1,4 +1,4 @@ -fish: Unknown command 'syntax-error' +fish: Unknown command syntax-error $XDG_CONFIG_HOME/fish/config.fish (line 2): syntax-error ^ From 0d0a686ea2f28157f0b3e4c0ed8cb92d5f6202b0 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sat, 26 Jan 2019 21:34:30 +0100 Subject: [PATCH 51/67] CHANGELOG: Update for 3.0.1 This should now contain all closed issues for 3.0.1. [ci skip] --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9474eb3f..565420a05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,20 @@ This release of fish fixes a number of major issues discovered in fish 3.0.0. - (macOS only) /etc/paths and /etc/paths.d now correctly set path entries with spaces. Also affects MANPATH. (#5481) - fish does not hang on launch when running under Cygwin/MSYS2 - The pager-toggle-search binding (by default Control-S) now positions the cursor in the completions list. +- The error when a command is not found is now printed a single time instead of once per argument. (#5588) +- The git completions now print correct file paths instead of ../../../ (and so on) with older git versions directly inside a git root. (#5578) +- The git completions won't suggest :/ paths (relative to the git root) so much anymore. (#5574) +- The git completions will now fuzzy-match paths again. (#5476) +- The git completions will ignore shell aliases, so enterprising users can set up the wrapping command (via `set -g __fish_git_alias_$command $whatitwraps`). (#5412) +- A crash when the user's information can't be read was fixed. (#5550) +- fish no longer crashes when $hostname or some other non-electric read-only variable is used as a loop variable. (#5548) +- The "kill" completions won't invoke the same command 25 times anymore, speeding matters up considerably. (#5541) +- Fish now inherits symlinked paths correctly. (#5525) +- fish_title had a few spaces removed, saving space. (#5517) +- The `nim` prompt now works correctly when chosen in fish_config. (#5490) +- A potential crash in `string match` discovered via GLIBCXX_ASSERTIONS was fixed. (#5479) +- A crash on FreeBSD related to the wcstod_l function was fixed. (#5453) +- An assertion that checked getpid() in a tight loop was removed, increasing performance in some cases up to 40%. (#5447) If you are upgrading from version 2.7.1 or before, please also review the release notes for 3.0.0 and 3.0b1 (included below). From 368787060bb0fde0b740cc81d9c3ca27a73f0dc6 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sat, 26 Jan 2019 21:36:27 +0100 Subject: [PATCH 52/67] CHANGELOG: Add the PRs I missed the PRs without associated issue. [ci skip] --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 565420a05..cd377982e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,9 @@ This release of fish fixes a number of major issues discovered in fish 3.0.0. - A potential crash in `string match` discovered via GLIBCXX_ASSERTIONS was fixed. (#5479) - A crash on FreeBSD related to the wcstod_l function was fixed. (#5453) - An assertion that checked getpid() in a tight loop was removed, increasing performance in some cases up to 40%. (#5447) +- `string` now prints help to stdout, like other builtins. (#5495) +- The completions for `configure` now correctly offer directories. (#5518) +- The `man` completions won't interpret the argument as a regex anymore. (#5566) If you are upgrading from version 2.7.1 or before, please also review the release notes for 3.0.0 and 3.0b1 (included below). From 28ee5716fb5e7caed55d0c7047a1f9cbe1f0228e Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sat, 26 Jan 2019 21:50:49 +0100 Subject: [PATCH 53/67] default_command_not_found_handler: Only use $argv[1] That's probably the nicer fix, otherwise this would print things like Unknown command 'aiohsd 1 2 3' when it should just say Unknown command aiohsd --- share/config.fish | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/config.fish b/share/config.fish index 3d6ba2417..53fed8e35 100644 --- a/share/config.fish +++ b/share/config.fish @@ -12,7 +12,7 @@ or set -g __fish_added_user_paths # Create the default command_not_found handler # function __fish_default_command_not_found_handler - printf "fish: Unknown command %s\n" (string escape -- "$argv") >&2 + printf "fish: Unknown command %s\n" (string escape -- $argv[1]) >&2 end if status --is-interactive From 8feabae1316a6d539d8eda3a17d6a4f2e5355f48 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Mon, 28 Jan 2019 18:10:41 +0100 Subject: [PATCH 54/67] Quit immediately with R_EOF If we read an R_EOF, we'd try to match mappings to it. In emacs mode, that's not an issue because the generic binding was always available, but in vi-normal mode there is no generic binding, so we'd endlessly loop, waiting for another character. Fixes #5528. --- src/input.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/input.cpp b/src/input.cpp index 596800167..8b5a94847 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -516,6 +516,10 @@ wint_t input_readch(bool allow_commands) { } default: { return c; } } + } else if (c == R_EOF) { + // If we have R_EOF, we need to immediately quit. + // There's no need to go through the input functions. + return R_EOF; } else { input_common_next_ch(c); input_mapping_execute_matching_or_generic(allow_commands); From a958617425c6be3f1428c1469d0aae960739d1f6 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Mon, 28 Jan 2019 21:25:54 +0100 Subject: [PATCH 55/67] CHANGELOG: Vi-mode-spinning The last bit for 3.0.1 [ci skip] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd377982e..ba6f4ca57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ This release of fish fixes a number of major issues discovered in fish 3.0.0. - `string` now prints help to stdout, like other builtins. (#5495) - The completions for `configure` now correctly offer directories. (#5518) - The `man` completions won't interpret the argument as a regex anymore. (#5566) +- Killing the terminal while fish is in vi-normal mode will no longer send it spinning and eating CPU. (#5528) If you are upgrading from version 2.7.1 or before, please also review the release notes for 3.0.0 and 3.0b1 (included below). From 9103dc2c23b49cbe76851b6ad02a9cc99fc6077c Mon Sep 17 00:00:00 2001 From: Ashe Connor Date: Wed, 30 Jan 2019 15:51:45 +1100 Subject: [PATCH 56/67] pcre2 -> regex (cherry picked from commit d9d2ad1cd6f883492c701be80dcf27530cf68c07) --- doc_src/string.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc_src/string.txt b/doc_src/string.txt index 52bca9445..c4e63b414 100644 --- a/doc_src/string.txt +++ b/doc_src/string.txt @@ -48,7 +48,7 @@ The following subcommands are available. `--style=regex` escapes an input string for literal matching within a regex expression. The string is first converted to UTF-8 before being encoded. -`string unescape` performs the inverse of the `string escape` command. If the string to be unescaped is not properly formatted it is ignored. For example, doing `string unescape --style=var (string escape --style=var $str)` will return the original string. There is no support for unescaping pcre2. +`string unescape` performs the inverse of the `string escape` command. If the string to be unescaped is not properly formatted it is ignored. For example, doing `string unescape --style=var (string escape --style=var $str)` will return the original string. There is no support for unescaping `--style=regex`. \subsection string-join "join" subcommand From f0c03ab73e6a8bda993f1703baf66f13347c796d Mon Sep 17 00:00:00 2001 From: Ashe Connor Date: Wed, 30 Jan 2019 14:07:04 +1100 Subject: [PATCH 57/67] fix "are equivalent" with same example This was introduced in 87eb073 when ^ redirection was removed from the docs. (cherry picked from commit 09ca268d50b2100eec7c0639adeb97920ec8018a) --- doc_src/index.hdr.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc_src/index.hdr.in b/doc_src/index.hdr.in index c75c6b82d..d6f82425a 100644 --- a/doc_src/index.hdr.in +++ b/doc_src/index.hdr.in @@ -166,7 +166,7 @@ Any file descriptor can be redirected in an arbitrary way by prefixing the redir - To redirect output of FD N, write `N>DESTINATION` - To append the output of FD N to a file, write `N>>DESTINATION_FILE` -Example: `echo Hello 2>output.stderr` and `echo Hello 2>output.stderr` are equivalent, and write the standard error (file descriptor 2) of the target program to `output.stderr`. +Example: `echo Hello 2>output.stderr` writes the standard error (file descriptor 2) of the target program to `output.stderr`. \subsection piping Piping From bfa051e466a55f2acb7308cdda1e09b0ef7d4893 Mon Sep 17 00:00:00 2001 From: Ashe Connor Date: Wed, 30 Jan 2019 14:14:19 +1100 Subject: [PATCH 58/67] `***.fish* -> `**.fish` (cherry picked from commit c7635ed2c08ba6e15537b2c285e06637a9637e37) --- doc_src/index.hdr.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc_src/index.hdr.in b/doc_src/index.hdr.in index d6f82425a..0fab0a2c3 100644 --- a/doc_src/index.hdr.in +++ b/doc_src/index.hdr.in @@ -426,7 +426,7 @@ If a star (`*`) or a question mark (`?`) is present in the parameter, `fish` att - `*` can match any string of characters not containing '/'. This includes matching an empty string. -- `**` matches any string of characters. This includes matching an empty string. The matched string may include the `/` character; that is, it recurses into subdirectories. Note that augmenting this wildcard with other strings will not match files in the current working directory (`$PWD`) if you separate the strings with a slash ("/"). This is unlike other shells such as zsh. For example, `**\/*.fish` in zsh will match `.fish` files in the PWD but in fish will only match such files in a subdirectory. In fish you should type `***.fish` to match files in the PWD as well as subdirectories. +- `**` matches any string of characters. This includes matching an empty string. The matched string may include the `/` character; that is, it recurses into subdirectories. Note that augmenting this wildcard with other strings will not match files in the current working directory (`$PWD`) if you separate the strings with a slash ("/"). This is unlike other shells such as zsh. For example, `**\/*.fish` in zsh will match `.fish` files in the PWD but in fish will only match such files in a subdirectory. In fish you should type `**.fish` to match files in the PWD as well as subdirectories. Other shells, such as zsh, provide a rich glob syntax for restricting the files matched by globs. For example, `**(.)`, to only match regular files. Fish prefers to defer such features to programs, such as `find`, rather than reinventing the wheel. Thus, if you want to limit the wildcard expansion to just regular files the fish approach is to define and use a function. For example, From 93c0d3f4a58ee128624309ce91342f00cd87343c Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Fri, 1 Feb 2019 18:29:54 +0100 Subject: [PATCH 59/67] `functions -q`: Return false without an argument This erroneously listed functions and returned true. --- src/builtin_functions.cpp | 5 +++++ tests/function.err | 3 +++ tests/function.in | 3 +++ tests/function.out | 4 ++++ 4 files changed, 15 insertions(+) diff --git a/src/builtin_functions.cpp b/src/builtin_functions.cpp index 8b5b16d97..42575b503 100644 --- a/src/builtin_functions.cpp +++ b/src/builtin_functions.cpp @@ -337,6 +337,11 @@ int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) { return STATUS_CMD_OK; } + // If we query with no argument, just return false. + if (opts.query && argc == optind) { + return STATUS_CMD_ERROR; + } + if (opts.list || argc == optind) { wcstring_list_t names = function_get_names(opts.show_hidden); std::sort(names.begin(), names.end()); diff --git a/tests/function.err b/tests/function.err index 2d69cbb05..7257df763 100644 --- a/tests/function.err +++ b/tests/function.err @@ -29,3 +29,6 @@ fish: function: The name 'test' is reserved, and can not be used as a function name function test; echo banana; end ^ + +#################### +# Checking `functions -q` without arguments diff --git a/tests/function.in b/tests/function.in index 5f64ed777..a774167e4 100644 --- a/tests/function.in +++ b/tests/function.in @@ -48,4 +48,7 @@ diff (functions name3 | psub) (functions name3a | psub) logmsg Checking reserved names function test; echo banana; end + +logmsg Checking `functions -q` without arguments +functions -q; or echo "False" exit 0 diff --git a/tests/function.out b/tests/function.out index 95a79ed2f..6cfd7379e 100644 --- a/tests/function.out +++ b/tests/function.out @@ -73,3 +73,7 @@ Function name4 not found as expected #################### # Checking reserved names + +#################### +# Checking `functions -q` without arguments +False From 4dfaa33d95a2cc16f4a8eb757948bd9053dfbb71 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Mon, 28 Jan 2019 22:25:55 -0600 Subject: [PATCH 60/67] Switch to wait_by_process when `waitpid` without WNOHANG returns nothing By exclusively waiting by pgrp, we can fail to reap processes that change their own pgrp then either crash or close their fds. If we wind up in a situation where `waitpid(2)` returns 0 or ECHLD even though we did not specify `WNOHANG` but we still have unreaped child processes, wait on them by pid. Closes #5596. --- src/proc.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/proc.cpp b/src/proc.cpp index 0228d176b..f61b2d0c2 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -511,6 +511,7 @@ static bool process_mark_finished_children(bool block_on_fg) { if (pid > 0) { // A child process has been reaped + debug(4, "Reaped PID %d", pid); handle_child_status(pid, status); // Always set WNOHANG (that is, don't hang). Otherwise we might wait on a non-stopped job @@ -520,15 +521,22 @@ static bool process_mark_finished_children(bool block_on_fg) { } else if (pid == 0 || errno == ECHILD) { // No killed/dead children in this particular process group if (!wait_by_process) { + if ((options & WNOHANG) == 0) { + // This normally implies that the job has completed, but if we try to wait + // on a job that includes a process that changed its own group before we + // enter `waitpid`, we will be waiting forever. See #5596 for such a case. + wait_by_process = true; + continue; + } break; } } else { // pid < 0 indicates an error. One likely failure is ECHILD (no children), which is - // not an error and is ignored. The other likely failure is EINTR, which means we - // got a signal, which is considered an error. We absolutely do not break or return - // on error, as we need to iterate over all constructed jobs but we only call - // waitpid for one pgrp at a time. We do bypass future waits in case of error, - // however. + // not an error and is ignored in the branch above. The other likely failure is + // EINTR, which means we got a signal, which is considered an error. We absolutely + // do not break or return on error, as we need to iterate over all constructed jobs + // but we only call waitpid for one pgrp at a time. We do bypass future waits in + // case of error, however. has_error = true; // Do not audibly complain on interrupt (see #5293) From c9e529951bd68461f68f643bb9fdc9df729ca810 Mon Sep 17 00:00:00 2001 From: David Adam Date: Mon, 4 Feb 2019 22:26:59 +0800 Subject: [PATCH 61/67] Documentation for while: note updated exit status From updates in #4982. (cherry picked from commit 4cc168ae115cfef19c53b4f00d7fd18361037b8e) --- doc_src/while.txt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/doc_src/while.txt b/doc_src/while.txt index 38338792f..5fb851768 100644 --- a/doc_src/while.txt +++ b/doc_src/while.txt @@ -9,10 +9,8 @@ while CONDITION; COMMANDS...; end `while` repeatedly executes `CONDITION`, and if the exit status is 0, then executes `COMMANDS`. -If the exit status of `CONDITION` is non-zero on the first iteration, `COMMANDS` will not be -executed at all, and the exit status of the loop set to the exit status of `CONDITION`. - -The exit status of the loop is 0 otherwise. +The exit status of the while loop is the exit status of the last iteration of the `COMMANDS` executed, +or 0 if none were executed. (This matches other shells and is POSIX-compatible.) You can use `and` or `or` for complex conditions. Even more complex control can be achieved with `while true` containing a break. From cfd9b520809e6f1141cdb8e642fa39eab09f4d4c Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Thu, 7 Feb 2019 03:45:17 -0800 Subject: [PATCH 62/67] string completions: add -e, -f, --no-empty, shorten -d's I hope this is now complete. Also, shorten enough descriptions to make `string match --` show a two column pager with 80 cols. We really should have shown more retraint in the design of `string`, not all of the flags required both a long and short option created. --- share/completions/string.fish | 21 +++++++++++++-------- src/builtin_string.cpp | 1 + 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/share/completions/string.fish b/share/completions/string.fish index 37d72f5b6..890abf870 100644 --- a/share/completions/string.fish +++ b/share/completions/string.fish @@ -12,29 +12,34 @@ complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a "split" complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a "split0" complete -x -c string -n 'test (count (commandline -opc)) -ge 2; and string match -qr split0\?\$ -- (commandline -opc)[2]' -s m -l max -a "(seq 1 10)" -d "Specify maximum number of splits" complete -f -c string -n 'test (count (commandline -opc)) -ge 2; and string match -qr split0\?\$ -- (commandline -opc)[2]' -s r -l right -d "Split right-to-left" +complete -f -c string -n 'test (count (commandline -opc)) -ge 2; and string match -qr split0\?\$ -- (commandline -opc)[2]' -s n -l no-empty -d "Empty results excluded" + complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a "join" complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a "join0" complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a "trim" -complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] trim" -s l -l left -d "Trim only leading characters" -complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] trim" -s r -l right -d "Trim only trailing characters" +complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] trim" -s l -l left -d "Trim only leading chars" +complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] trim" -s r -l right -d "Trim only trailing chars" complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] trim" -s c -l chars -d "Specify the chars to trim (default: whitespace)" complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a "escape" complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a "unescape" -complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] escape; or contains -- (commandline -opc)[2] unescape" -s n -l no-quoted -d "Escaped with \\ instead of quoted" -complete -x -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] escape; or contains -- (commandline -opc)[2] unescape" -l style -d "Escaping style" -a " +complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] escape; or contains -- (commandline -opc)[2] unescape" -s n -l no-quoted -d "Escape with \\ instead of quotes" +complete -x -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] escape; or contains -- (commandline -opc)[2] unescape" -l style -d "Specify escaping style" -a " (printf '%s\t%s\n' script 'For use in scripts' \ var 'For use as a variable name' \ regex 'For string match -r, string replace -r' \ url 'For use as a URL')" complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a "match" -complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] match" -s n -l index -d "Report index and length of the matches" -complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] match" -s v -l invert -d "Report only non-matching input" +complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] match" -s n -l index -d "Report index, length of match" +complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] match" -s v -l invert -d "Report only non-matches" +complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] match" -s e -l entire -d "Show entire matching lines" complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a "replace" +complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] replace" -s f -l filter -d "Report only actual replacements" # All replace options are also valid for match -complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] match replace" -s a -l all -d "Report all matches per line/string" +complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] match replace" -s a -l all -d "Report every match" complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] match replace" -s i -l ignore-case -d "Case insensitive" complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] match replace" -s r -l regex -d "Use regex instead of globs" + complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a "repeat" complete -x -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] repeat" -s n -l count -a "(seq 1 10)" -d "Repetition count" -complete -x -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] repeat" -s m -l max -a "(seq 1 10)" -d "Maximum number of printed char" +complete -x -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] repeat" -s m -l max -a "(seq 1 10)" -d "Maximum number of printed chars" complete -f -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] repeat" -s N -l no-newline -d "Remove newline" diff --git a/src/builtin_string.cpp b/src/builtin_string.cpp index 8e7777111..ad945fdef 100644 --- a/src/builtin_string.cpp +++ b/src/builtin_string.cpp @@ -413,6 +413,7 @@ static wcstring construct_short_opts(options_t *opts) { //!OCLINT(high npath co // Note that several long flags share the same short flag. That is okay. The caller is expected // to indicate that a max of one of the long flags sharing a short flag is valid. +// Remember: adjust share/functions/string.fish when `string` options change static const struct woption long_options[] = { {L"all", no_argument, NULL, 'a'}, {L"chars", required_argument, NULL, 'c'}, {L"count", required_argument, NULL, 'n'}, {L"entire", no_argument, NULL, 'e'}, From 0c706e45eb6f0ec9cf2a7f8faf603cfb830a1e97 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Sat, 9 Feb 2019 18:48:38 +0100 Subject: [PATCH 63/67] docs/tutorial: Remove mention of caret (^) While this is still technically included, the tutorial should not steer people towards it. [ci skip] --- doc_src/tutorial.hdr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc_src/tutorial.hdr b/doc_src/tutorial.hdr index b4ef8dfce..d11fed687 100644 --- a/doc_src/tutorial.hdr +++ b/doc_src/tutorial.hdr @@ -172,10 +172,10 @@ You can pipe between commands with the usual vertical bar: 1 2 12 \endfish -stdin and stdout can be redirected via the familiar < and >. Unlike other shells, stderr is redirected with a caret ^ +stdin and stdout can be redirected via the familiar < and >. stderr is redirected with a >2. \fish{cli-dark} ->_ grep fish < /etc/shells > ~/output.txt ^ ~/errors.txt +>_ grep fish < /etc/shells > ~/output.txt 2> ~/errors.txt \endfish From be47d46e6a139359a27b43b56474ea82c6b7ced4 Mon Sep 17 00:00:00 2001 From: David Adam Date: Sun, 10 Feb 2019 17:07:59 +0800 Subject: [PATCH 64/67] CHANGELOG: updates for 3.0.1 --- CHANGELOG.md | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba6f4ca57..2d0e1933d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,30 +4,22 @@ This release of fish fixes a number of major issues discovered in fish 3.0.0. ### Fixes and improvements -- exec now behaves properly inside functions (#5449) -- while loops now evaluate to the last executed command in the loop body (or zero if the body was empty), matching POSIX semantics. -- `read --silent` no longer echoes to the tty when run from a non-interactive script (#5519) -- (macOS only) /etc/paths and /etc/paths.d now correctly set path entries with spaces. Also affects MANPATH. (#5481) -- fish does not hang on launch when running under Cygwin/MSYS2 -- The pager-toggle-search binding (by default Control-S) now positions the cursor in the completions list. -- The error when a command is not found is now printed a single time instead of once per argument. (#5588) -- The git completions now print correct file paths instead of ../../../ (and so on) with older git versions directly inside a git root. (#5578) -- The git completions won't suggest :/ paths (relative to the git root) so much anymore. (#5574) -- The git completions will now fuzzy-match paths again. (#5476) -- The git completions will ignore shell aliases, so enterprising users can set up the wrapping command (via `set -g __fish_git_alias_$command $whatitwraps`). (#5412) -- A crash when the user's information can't be read was fixed. (#5550) -- fish no longer crashes when $hostname or some other non-electric read-only variable is used as a loop variable. (#5548) -- The "kill" completions won't invoke the same command 25 times anymore, speeding matters up considerably. (#5541) -- Fish now inherits symlinked paths correctly. (#5525) -- fish_title had a few spaces removed, saving space. (#5517) -- The `nim` prompt now works correctly when chosen in fish_config. (#5490) -- A potential crash in `string match` discovered via GLIBCXX_ASSERTIONS was fixed. (#5479) -- A crash on FreeBSD related to the wcstod_l function was fixed. (#5453) -- An assertion that checked getpid() in a tight loop was removed, increasing performance in some cases up to 40%. (#5447) -- `string` now prints help to stdout, like other builtins. (#5495) -- The completions for `configure` now correctly offer directories. (#5518) -- The `man` completions won't interpret the argument as a regex anymore. (#5566) -- Killing the terminal while fish is in vi-normal mode will no longer send it spinning and eating CPU. (#5528) +- `exec` does not complain about running foreground jobs when called (#5449). +- while loops now evaluate to the last executed command in the loop body (or zero if the body was empty), matching POSIX semantics (#4982). +- `read --silent` no longer echoes to the tty when run from a non-interactive script (#5519). +- On macOS, path entries with spaces in `/etc/paths` and `/etc/paths.d` now correctly set path entries with spaces. Likewise, `MANPATH` is correctly set from `/etc/manpaths` and `/etc/manpaths.d` (#5481). +- fish starts correctly under Cygwin/MSYS2 (#5426). +- The `pager-toggle-search` binding (Control-S by default) now positions the cursor in the completions list. +- The error when a command is not found is now printed a single time, instead of once per argument (#5588). +- Fixes and improvements to the git completions, including printing correct paths with older git versions, fuzzy matching again, reducing unnecessary offers of root paths (starting with `:/`) (#5578, #5574, #5476), and ignoring shell aliases, so enterprising users can set up the wrapping command (via `set -g __fish_git_alias_$command $whatitwraps`) (#5412). +- Significant performance improvements to core shell functions (#5447) and to the `kill` completions (#5541). +- Starting in symbolically-linked working directories works correctly (#5525). +- The default `fish_title` function no longer contains extra spaces (#5517). +- The `nim` prompt now works correctly when chosen in the Web-based configuration (#5490). +- `string` now prints help to stdout, like other builtins (#5495), +- Improvements to the completions for `configure` (#5518) and `man` (#5566). +- Killing the terminal while fish is in vi normal mode will no longer send it spinning and eating CPU. (#5528) +- A number of crashes have been fixed (#5550, #5548, #5479, #5453). If you are upgrading from version 2.7.1 or before, please also review the release notes for 3.0.0 and 3.0b1 (included below). From 4c6b4188a07724eee3a94a73eca182df46f387c2 Mon Sep 17 00:00:00 2001 From: Aaron Gyes Date: Sat, 9 Feb 2019 22:22:58 -0800 Subject: [PATCH 65/67] Drastically improve `fish ` completions * complete .fish files * --debug -> --debug-level * add --init-command/-C * add --debug-stack-frames/-D * add --private/-P * add --features/-f: lists supported features, supports foo, * -c now completes commands * -d requires argument, describes 0..5 * --profile: require argument, allow file completion --- share/completions/fish.fish | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/share/completions/fish.fish b/share/completions/fish.fish index d33d20bc4..d11745b03 100644 --- a/share/completions/fish.fish +++ b/share/completions/fish.fish @@ -1,8 +1,24 @@ -complete -c fish -s c -l "command" -d "Run fish with this command" +complete -c fish -s c -l command -d "Run specified command instead of interactive session" -x -a "(__fish_complete_command)" +complete -c fish -s C -l init-command -d "Run specified command before session" -x -a "(__fish_complete_command)" complete -c fish -s h -l help -d "Display help and exit" complete -c fish -s v -l version -d "Display version and exit" complete -c fish -s n -l no-execute -d "Only parse input, do not execute" complete -c fish -s i -l interactive -d "Run in interactive mode" -complete -c fish -s l -l login -d "Run in login mode" -complete -c fish -s p -l profile -d "Output profiling information to specified file" -f -complete -c fish -s d -l debug -d "Run with the specified verbosity level" +complete -c fish -s l -l login -d "Run as a login shell" +complete -c fish -s p -l profile -d "Output profiling information to specified file" -r +complete -c fish -s d -l debug-level -d "Specify verbosity level" -x -a "0\t'Warnings silenced' +1\t'Default' +2\t'Basic debug output' +3\t'More debug output' +4\t'Much more debug output' +5\t'Too much debug output'" +complete -c fish -s D -l debug-stack-frames -d "Show specified # of frames with debug output" -x -a "(seq 128)\t\n" +complete -c fish -s P -l private -d "Do not persist history" + +function __fish_complete_features + set -l arg_comma (commandline -tc | string replace -rf '(.*,)[^,]*' '$1' | string replace -r -- '--.*=' '') + set -l features (status features | string replace -rf '^([\w-]+).*\t(.*)$' '$1\t$2') + printf "%s\n" "$arg_comma"$features #TODO: remove existing args +end +complete -c fish -s f -l features -d "Run with comma-separated feature flags enabled" -a "(__fish_complete_features)" -x +complete -c fish -x -a "(__fish_complete_suffix .fish)" From 339b195e74f0c42a894c3759b4832e9a270d755d Mon Sep 17 00:00:00 2001 From: David Adam Date: Mon, 11 Feb 2019 19:30:31 +0800 Subject: [PATCH 66/67] CHANGELOG: updates for 3.0.1 --- CHANGELOG.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d0e1933d..1c9062ad8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,17 +9,23 @@ This release of fish fixes a number of major issues discovered in fish 3.0.0. - `read --silent` no longer echoes to the tty when run from a non-interactive script (#5519). - On macOS, path entries with spaces in `/etc/paths` and `/etc/paths.d` now correctly set path entries with spaces. Likewise, `MANPATH` is correctly set from `/etc/manpaths` and `/etc/manpaths.d` (#5481). - fish starts correctly under Cygwin/MSYS2 (#5426). -- The `pager-toggle-search` binding (Control-S by default) now positions the cursor in the completions list. +- The `pager-toggle-search` binding (Ctrl-S by default) will now activate the search field, even when the pager is not focused. - The error when a command is not found is now printed a single time, instead of once per argument (#5588). - Fixes and improvements to the git completions, including printing correct paths with older git versions, fuzzy matching again, reducing unnecessary offers of root paths (starting with `:/`) (#5578, #5574, #5476), and ignoring shell aliases, so enterprising users can set up the wrapping command (via `set -g __fish_git_alias_$command $whatitwraps`) (#5412). - Significant performance improvements to core shell functions (#5447) and to the `kill` completions (#5541). - Starting in symbolically-linked working directories works correctly (#5525). - The default `fish_title` function no longer contains extra spaces (#5517). - The `nim` prompt now works correctly when chosen in the Web-based configuration (#5490). -- `string` now prints help to stdout, like other builtins (#5495), -- Improvements to the completions for `configure` (#5518) and `man` (#5566). +- `string` now prints help to stdout, like other builtins (#5495). - Killing the terminal while fish is in vi normal mode will no longer send it spinning and eating CPU. (#5528) - A number of crashes have been fixed (#5550, #5548, #5479, #5453). +- Improvements to the documentation and certain completions. + +### Known issues + +There is one significant known issue that was not corrected before the release: + +- fish does not run correctly under Windows Services for Linux before Windows 10 version 1809/17763, and the message warning of this may not be displayed (#5619). If you are upgrading from version 2.7.1 or before, please also review the release notes for 3.0.0 and 3.0b1 (included below). From e26ab3d81ce8a31a88d0e19bccb44aca9ec3d3c1 Mon Sep 17 00:00:00 2001 From: David Adam Date: Mon, 11 Feb 2019 19:40:26 +0800 Subject: [PATCH 67/67] Bump version for 3.0.1 --- CHANGELOG.md | 2 +- osx/Info.plist | 2 +- osx/config.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c9062ad8..77a3a4771 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# fish 3.0.1 +# fish 3.0.1 (released February 11, 2019) This release of fish fixes a number of major issues discovered in fish 3.0.0. diff --git a/osx/Info.plist b/osx/Info.plist index 2eb4b5a8e..10b7d27df 100644 --- a/osx/Info.plist +++ b/osx/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 3.0.0 + 3.0.1 CFBundleVersion 0.1 LSApplicationCategoryType diff --git a/osx/config.h b/osx/config.h index 233464b40..77128ac1e 100644 --- a/osx/config.h +++ b/osx/config.h @@ -209,7 +209,7 @@ #define PACKAGE_NAME "fish" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "fish 3.0.0" +#define PACKAGE_STRING "fish 3.0.1" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "fish" @@ -218,7 +218,7 @@ #define PACKAGE_URL "" /* Define to the version of this package. */ -#define PACKAGE_VERSION "3.0.0" +#define PACKAGE_VERSION "3.0.1" /* The size of `wchar_t', as computed by sizeof. */ #define SIZEOF_WCHAR_T 4