mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-05-10 01:21:16 -03:00
Compare commits
70 Commits
Integratio
...
3.0.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
28f57aa8ab | ||
|
|
6e24061468 | ||
|
|
5c994b0d47 | ||
|
|
e26ab3d81c | ||
|
|
339b195e74 | ||
|
|
4c6b4188a0 | ||
|
|
be47d46e6a | ||
|
|
0c706e45eb | ||
|
|
cfd9b52080 | ||
|
|
c9e529951b | ||
|
|
4dfaa33d95 | ||
|
|
93c0d3f4a5 | ||
|
|
bfa051e466 | ||
|
|
f0c03ab73e | ||
|
|
9103dc2c23 | ||
|
|
a958617425 | ||
|
|
8feabae131 | ||
|
|
28ee5716fb | ||
|
|
368787060b | ||
|
|
0d0a686ea2 | ||
|
|
77b7f5513e | ||
|
|
a5ef1e395e | ||
|
|
91ac0f1b18 | ||
|
|
e462c6fe0e | ||
|
|
b5cbdc9065 | ||
|
|
3bf702067a | ||
|
|
5b12d703dd | ||
|
|
e8f340a03d | ||
|
|
aee8e5250a | ||
|
|
55526947d2 | ||
|
|
8737b654bf | ||
|
|
0f2470d45a | ||
|
|
3875615f45 | ||
|
|
70f618d598 | ||
|
|
c20187e858 | ||
|
|
da44ee1d08 | ||
|
|
1d80028e24 | ||
|
|
a1df72dbb6 | ||
|
|
72423c517a | ||
|
|
88ee55443c | ||
|
|
6bd3474daf | ||
|
|
dfa61926e8 | ||
|
|
d88be7b5c8 | ||
|
|
1b551e553b | ||
|
|
963e3217e5 | ||
|
|
91ecd3b9b5 | ||
|
|
288cfa8fb2 | ||
|
|
171ae99295 | ||
|
|
96f7924661 | ||
|
|
ec77135cf2 | ||
|
|
d5d80c0742 | ||
|
|
97f0cc9662 | ||
|
|
afb9094b4c | ||
|
|
f2a1130afd | ||
|
|
cb09f9aef2 | ||
|
|
749347ff4c | ||
|
|
7a163e8e98 | ||
|
|
3855608c69 | ||
|
|
8ff8124765 | ||
|
|
b6aafda139 | ||
|
|
5f7adb3c69 | ||
|
|
40f5dd200b | ||
|
|
059804612a | ||
|
|
028bff7b44 | ||
|
|
364c839279 | ||
|
|
1d21e3f470 | ||
|
|
e2f2dbf032 | ||
|
|
f4351eb0f3 | ||
|
|
1ce9721590 | ||
|
|
60ced5dbc7 |
45
CHANGELOG.md
45
CHANGELOG.md
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
2
debian/control
vendored
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 < 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
|
||||
|
||||
|
||||
|
||||
@@ -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>.
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
function fish_title
|
||||
echo (status current-command) " " (__fish_pwd)
|
||||
echo (status current-command) (__fish_pwd)
|
||||
end
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
22
src/env.cpp
22
src/env.cpp
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
72
src/proc.cpp
72
src/proc.cpp
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
#include <locale.h>
|
||||
#include <string>
|
||||
|
||||
#ifdef HAVE_XLOCALE_H
|
||||
#include <xlocale.h>
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
#include "maybe.h"
|
||||
|
||||
|
||||
@@ -4,3 +4,6 @@
|
||||
|
||||
####################
|
||||
# cd symlink completion
|
||||
|
||||
####################
|
||||
# Virtual PWD inheritance
|
||||
|
||||
29
tests/cd.in
29
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,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -73,3 +73,7 @@ Function name4 not found as expected
|
||||
|
||||
####################
|
||||
# Checking reserved names
|
||||
|
||||
####################
|
||||
# Checking `functions -q` without arguments
|
||||
False
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
fish: Unknown command 'syntax-error'
|
||||
fish: Unknown command syntax-error
|
||||
$XDG_CONFIG_HOME/fish/config.fish (line 2):
|
||||
syntax-error
|
||||
^
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
3
tests/while.err
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
####################
|
||||
# Loops exit status handling
|
||||
73
tests/while.in
Normal file
73
tests/while.in
Normal 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
12
tests/while.out
Normal 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
|
||||
Reference in New Issue
Block a user