Compare commits

..

70 Commits

Author SHA1 Message Date
David Adam
28f57aa8ab Bump version for 3.0.2 2019-02-19 21:39:17 +08:00
David Adam
6e24061468 CHANGELOG: updates for 3.0.2 2019-02-19 21:30:49 +08:00
ridiculousfish
5c994b0d47 Only inherit a PWD if it resolves to "."
Fixes #5647
2019-02-18 14:32:15 -08:00
David Adam
e26ab3d81c Bump version for 3.0.1 2019-02-11 20:13:15 +08:00
David Adam
339b195e74 CHANGELOG: updates for 3.0.1 2019-02-11 20:13:15 +08:00
Aaron Gyes
4c6b4188a0 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,<TAB>
* -c now completes commands
* -d requires argument, describes 0..5
* --profile: require argument, allow file completion
2019-02-10 21:27:26 -08:00
David Adam
be47d46e6a CHANGELOG: updates for 3.0.1 2019-02-10 17:07:59 +08:00
Fabian Homborg
0c706e45eb docs/tutorial: Remove mention of caret (^)
While this is still technically included, the tutorial should not
steer people towards it.

[ci skip]
2019-02-09 18:51:23 +01:00
Aaron Gyes
cfd9b52080 string completions: add -e, -f, --no-empty, shorten -d's
I hope this is now complete.

Also, shorten enough descriptions to make `string match --<TAB>`
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.
2019-02-07 04:20:12 -08:00
David Adam
c9e529951b Documentation for while: note updated exit status
From updates in #4982.

(cherry picked from commit 4cc168ae11)
2019-02-04 22:39:01 +08:00
Mahmoud Al-Qudsi
4dfaa33d95 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.
2019-02-02 16:06:29 -06:00
Fabian Homborg
93c0d3f4a5 functions -q: Return false without an argument
This erroneously listed functions and returned true.
2019-02-02 14:12:31 +01:00
Ashe Connor
bfa051e466 ***.fish* -> **.fish`
(cherry picked from commit c7635ed2c0)
2019-01-31 22:05:13 +08:00
Ashe Connor
f0c03ab73e fix "are equivalent" with same example
This was introduced in 87eb073 when ^ redirection was removed from the
docs.

(cherry picked from commit 09ca268d50)
2019-01-31 22:05:13 +08:00
Ashe Connor
9103dc2c23 pcre2 -> regex
(cherry picked from commit d9d2ad1cd6)
2019-01-31 22:05:12 +08:00
Fabian Homborg
a958617425 CHANGELOG: Vi-mode-spinning
The last bit for 3.0.1

[ci skip]
2019-01-28 21:26:10 +01:00
Fabian Homborg
8feabae131 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.
2019-01-28 18:20:57 +01:00
Fabian Homborg
28ee5716fb 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
2019-01-26 21:53:32 +01:00
Fabian Homborg
368787060b CHANGELOG: Add the PRs
I missed the PRs without associated issue.

[ci skip]
2019-01-26 21:36:27 +01:00
Fabian Homborg
0d0a686ea2 CHANGELOG: Update for 3.0.1
This should now contain all closed issues for 3.0.1.

[ci skip]
2019-01-26 21:34:51 +01:00
Fabian Homborg
77b7f5513e 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.
2019-01-26 21:22:55 +01:00
Mahmoud Al-Qudsi
a5ef1e395e Use standard __CYGWIN__ define for Cygwin detection
(cherry picked from commit 462cb6044c)
2019-01-23 17:46:07 -06:00
Mahmoud Al-Qudsi
91ac0f1b18 Work around for Cygwin's broken job control resolving fish 3.0 hang
(cherry picked from commit d1913f0df0)
2019-01-23 17:46:00 -06:00
John McKay
e462c6fe0e print --help to stdout like other builtins (#5495) 2019-01-23 12:00:56 -08:00
Aaron Gyes
b5cbdc9065 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
2019-01-23 11:59:29 -08:00
Aaron Gyes
3bf702067a 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.
2019-01-23 11:59:22 -08:00
Aaron Gyes
5b12d703dd 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.
2019-01-23 11:58:29 -08:00
Aaron Gyes
e8f340a03d string completions: add missing upper, lower, split0, join0, unescape
and --style=regex
2019-01-23 11:58:12 -08:00
Mahmoud Al-Qudsi
aee8e5250a 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`
2019-01-23 14:05:51 +01:00
Mahmoud Al-Qudsi
55526947d2 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.
2019-01-23 14:05:51 +01:00
Mahmoud Al-Qudsi
8737b654bf Fix wcstod_l detection under Linux
This was broken in a8eb02f9f5 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).
2019-01-23 14:05:51 +01:00
Mahmoud Al-Qudsi
0f2470d45a 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.
2019-01-23 14:05:50 +01:00
Mahmoud Al-Qudsi
3875615f45 Define _GNU_SOURCE for wcstod_l check 2019-01-23 14:05:50 +01:00
Mahmoud Al-Qudsi
70f618d598 Fix wcstod_l detection under FreeBSD 2019-01-23 14:05:50 +01:00
Fabian Homborg
c20187e858 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]
2019-01-23 14:04:19 +01:00
Fabian Homborg
da44ee1d08 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.
2019-01-23 12:31:55 +01:00
Johannes Altmanninger
1d80028e24 __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 ".
2019-01-23 11:59:06 +01:00
Mahmoud Al-Qudsi
a1df72dbb6 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.
2019-01-23 00:12:17 -06:00
Fabian Homborg
72423c517a 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]
2019-01-22 14:55:37 -08:00
ridiculousfish
88ee55443c Update docs on tab completions and searching
Fixes #5547
2019-01-22 14:44:09 -08:00
ridiculousfish
6bd3474daf Make control-S begin navigating the pager contents
In addition to showing the search field, actually allow the user to type in
it.
2019-01-22 14:43:44 -08:00
ridiculousfish
dfa61926e8 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
2019-01-22 14:10:50 -08:00
Fabian Homborg
d88be7b5c8 tests/cd: cd back before cleaning up
Otherwise this'd run afoul of OpenIndiana's "no removing $PWD" rule. Spoilsports!

See #5472.
2019-01-22 14:04:27 -08:00
Mahmoud Al-Qudsi
1b551e553b Fix regression for #4178 and others introduced by 364c839
...while still keeping intact the fix for #5519.
2019-01-22 12:39:37 -06:00
Fabian Homborg
963e3217e5 env_get_runtime_path: Check for getpwuid() failure
Otherwise this is a NULL dereference and then crash.

Fixes #5550.
2019-01-22 19:33:22 +01:00
Fabian Homborg
91ecd3b9b5 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]
2019-01-22 19:18:00 +01:00
Fabian Homborg
288cfa8fb2 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]
2019-01-22 19:16:29 +01:00
Fabian Homborg
171ae99295 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.
2019-01-21 18:21:00 -08:00
Fabian Homborg
96f7924661 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]
2019-01-21 18:09:39 -08:00
Mahmoud Al-Qudsi
ec77135cf2 Allow more flexibility with file completions for yarn
Closes #5502
2019-01-21 17:41:16 -08:00
Mahmoud Al-Qudsi
d5d80c0742 Fix extra space in fish_title
Closes #5517. Credit goes to @jadenPete.

[skip-ci]
2019-01-21 17:27:35 -08:00
Fabian Homborg
97f0cc9662 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]
2019-01-21 17:24:49 -08:00
Sam Yu
afb9094b4c Fix completion of directories for configure 2019-01-21 17:21:28 -08:00
Fabian Homborg
f2a1130afd 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.
2019-01-21 17:14:01 -08:00
Fabian Homborg
cb09f9aef2 Switch to readdir from readdir_r
It's deprecated in glibc, and does not work properly on Solaris.

Fixes #5458.
2019-01-21 12:02:05 +01:00
David Adam
749347ff4c debian packaging: recommend python3 or python2
Closes #5492.

(cherry picked from commit 1f897d2c43)
2019-01-21 17:57:38 +11:00
Fabian Homborg
7a163e8e98 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 73bae383e0)
2019-01-21 17:51:50 +11:00
Fabian Homborg
3855608c69 docs: Document $hostname
Fixes #5469.

[ci skip]

(cherry picked from commit 72c0213d42)
2019-01-21 17:50:17 +11:00
Fabian Homborg
8ff8124765 cmake: Add missing HAVE_WCSTOD_L #cmakedefine
Turns out we've been using the fallback everywhere.

See #5453.

(cherry picked from commit 7078aa4642)
2019-01-21 17:49:02 +11:00
David Adam
b6aafda139 CHANGELOG: 3.0.1 verbiage 2019-01-21 17:25:24 +11:00
ridiculousfish
5f7adb3c69 Relnote fix for #5481 2019-01-20 18:05:07 -08:00
Fabian Homborg
40f5dd200b 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]
2019-01-20 18:02:35 -08:00
Fabian Homborg
059804612a 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
2019-01-20 17:46:49 -08:00
ridiculousfish
028bff7b44 Relnote fix for #5519 2019-01-20 17:46:19 -08:00
ridiculousfish
364c839279 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
2019-01-20 17:40:03 -08:00
ridiculousfish
1d21e3f470 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
2019-01-20 16:41:59 -08:00
ridiculousfish
e2f2dbf032 Correctly handle exited jobs in process_mark_finished_children
This is effectively a pick of 2ebdcf82ee
and the subsequent fixup. However we also avoid setting WNOHANG unless
waitpid() indicates a process was reaped.

Fixes #5438
2019-01-20 15:04:27 -08:00
ridiculousfish
f4351eb0f3 Relnote fix for #5449 in 3.0.1 2019-01-20 13:55:18 -08:00
ridiculousfish
1ce9721590 exec to only warn on background jobs in interactive sessions
Extension of fix for #5449 in b007248
2019-01-20 13:53:37 -08:00
Fabian Homborg
60ced5dbc7 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.
2019-01-20 13:53:33 -08:00
49 changed files with 619 additions and 233 deletions

View File

@@ -1,3 +1,48 @@
# fish 3.0.2 (released February 19, 2019)
This release of fish fixes an issue discovered in fish 3.0.1.
### Fixes and improvements
- The PWD environment variable is now ignored if it does not resolve to the true working directory, fixing strange behaviour in terminals started by editors and IDEs (#5647).
If you are upgrading from version 2.7.1 or before, please also review the release notes for 3.0.1, 3.0.0 and 3.0b1 (included below).
---
# fish 3.0.1 (released February 11, 2019)
This release of fish fixes a number of major issues discovered in fish 3.0.0.
### Fixes and improvements
- `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 (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).
- 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).
---
# 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.

View File

@@ -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,20 @@ 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)
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)
# `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)

View File

@@ -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
@@ -150,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

2
debian/control vendored
View File

@@ -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)

View File

@@ -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
@@ -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:
@@ -424,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,
@@ -931,6 +933,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 <a href="commands.html#read">read builtin</a>. Setting this to the empty string will also disable line splitting in <a href="#expand-command-substitution">command substitution</a>. This variable can be changed by the user.
- `PWD`, the current working directory.

View File

@@ -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

View File

@@ -172,10 +172,10 @@ You can pipe between commands with the usual vertical bar:
<outp> 1 2 12</outp>
\endfish
stdin and stdout can be redirected via the familiar &lt; and &gt;. Unlike other shells, stderr is redirected with a caret ^
stdin and stdout can be redirected via the familiar &lt; and &gt;. stderr is redirected with a &gt;2.
\fish{cli-dark}
>_ grep fish < /etc/shells > ~/output.txt ^ ~/errors.txt
>_ grep fish < /etc/shells > ~/output.txt 2> ~/errors.txt
\endfish

View File

@@ -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 <a href="#and">`and`</a> or <a href="#or">`or`</a> for complex conditions. Even more complex control can be achieved with `while true` containing a <a href="#break">break</a>.

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>3.0.0</string>
<string>3.0.2</string>
<key>CFBundleVersion</key>
<string>0.1</string>
<key>LSApplicationCategoryType</key>

View File

@@ -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
@@ -206,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.2"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "fish"
@@ -215,7 +218,7 @@
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "3.0.0"
#define PACKAGE_VERSION "3.0.2"
/* The size of `wchar_t', as computed by sizeof. */
#define SIZEOF_WCHAR_T 4

View File

@@ -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

View File

@@ -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)"

View File

@@ -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
@@ -144,26 +142,20 @@ 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.
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
@@ -251,34 +243,29 @@ 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
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.
@@ -355,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.
@@ -365,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]
@@ -375,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
@@ -446,6 +438,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

View File

@@ -2,33 +2,44 @@
# 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)) -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)) -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 "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 -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 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"

View File

@@ -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'

View File

@@ -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
@@ -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
@@ -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

View File

@@ -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

View File

@@ -6,5 +6,13 @@ 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 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
end

View File

@@ -1,3 +1,3 @@
function fish_title
echo (status current-command) " " (__fish_pwd)
echo (status current-command) (__fish_pwd)
end

View File

@@ -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 {

View File

@@ -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|111][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|111][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

View File

@@ -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('<span style="color: ' + html_color + '">')
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('<span style="color: ' + html_color + '">')
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
@@ -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

View File

@@ -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());

View File

@@ -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'},
@@ -622,9 +623,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);
}
}
}
@@ -1301,7 +1306,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;
}

View File

@@ -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);
}

View File

@@ -960,9 +960,14 @@ 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 may inherit a virtual PWD that doesn't match what getcwd would return; respect that
// if and only if it matches getcwd (#5647). Note we treat PWD as read-only so it was not set in
// vars.
const char *incoming_pwd_cstr = getenv("PWD");
wcstring incoming_pwd = incoming_pwd_cstr ? str2wcstring(incoming_pwd_cstr) : wcstring{};
if (!incoming_pwd.empty() && paths_are_same_file(incoming_pwd, L".")) {
env_set_one(L"PWD", ENV_EXPORT | ENV_GLOBAL, std::move(incoming_pwd));
} else {
env_set_pwd_from_getcwd();
}
env_set_termsize(); // initialize the terminal size variables
@@ -1184,6 +1189,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.
@@ -1654,12 +1660,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;

View File

@@ -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;

View File

@@ -390,16 +390,17 @@ 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) {
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");
#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) {
// 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)

View File

@@ -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

View File

@@ -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);

View File

@@ -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<g::job_conjunction> condition_head = header.child<1>();
tnode_t<g::andor_job_list> 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<while_block_t>();
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;
}
@@ -768,12 +781,15 @@ 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;
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;
}

View File

@@ -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;
}

View File

@@ -354,7 +354,12 @@ typedef unsigned int process_generation_count_t;
static std::vector<pid_t> 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
@@ -442,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
@@ -467,6 +496,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,26 +509,34 @@ 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
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
// 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) {
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)

View File

@@ -2474,9 +2474,15 @@ 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();
if (tcsetattr(0, TCSANOW, &shell_modes) == -1) {
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");
}
}
@@ -2705,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;

View File

@@ -37,27 +37,27 @@ const file_id_t kInvalidFileID = {(dev_t)-1LL, (ino_t)-1LL, (uint64_t)-1LL, -1,
static owning_lock<std::unordered_map<wcstring, wcstring>> 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() {

View File

@@ -10,6 +10,10 @@
#include <locale.h>
#include <string>
#ifdef HAVE_XLOCALE_H
#include <xlocale.h>
#endif
#include "common.h"
#include "maybe.h"

View File

@@ -4,3 +4,6 @@
####################
# cd symlink completion
####################
# Virtual PWD inheritance

View File

@@ -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,31 @@ echo "ls:"
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
set -l real_getcwd (pwd -P)
env HOME=$base/linkhome $fish_path -c 'echo PWD is $PWD'
# Do not inherit a virtual PWD that fails to resolve to getcwd (#5647)
env HOME=$base/linkhome PWD=/tmp $fish_path -c 'echo $PWD' | read output_pwd
test (realpath $output_pwd) = $real_getcwd
and echo "BogusPWD test 1 succeeded"
or echo "BogusPWD test 1 failed: $output_pwd vs $real_getcwd"
env HOME=$base/linkhome PWD=/path/to/nowhere $fish_path -c 'echo $PWD' | read output_pwd
test (realpath $output_pwd) = $real_getcwd
and echo "BogusPWD test 2 succeeded"
or echo "BogusPWD test 2 failed: $output_pwd vs $real_getcwd"
# cd back before removing the test directory again.
cd $oldpwd
rm -Rf $base

View File

@@ -17,3 +17,9 @@ cd:
../a2/
../a3/
../rabbithole/
####################
# Virtual PWD inheritance
PWD is /tmp/cdcomp_test/linkhome
BogusPWD test 1 succeeded
BogusPWD test 2 succeeded

View File

@@ -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

View File

@@ -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

View File

@@ -73,3 +73,7 @@ Function name4 not found as expected
####################
# Checking reserved names
####################
# Checking `functions -q` without arguments
False

View File

@@ -1,4 +1,4 @@
fish: Unknown command 'syntax-error'
fish: Unknown command syntax-error
$XDG_CONFIG_HOME/fish/config.fish (line 2):
syntax-error
^

View File

@@ -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

View File

@@ -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

View File

@@ -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

3
tests/while.err Normal file
View File

@@ -0,0 +1,3 @@
####################
# Loops exit status handling

73
tests/while.in Normal file
View File

@@ -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"

12
tests/while.out Normal file
View File

@@ -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