Compare commits

..

167 Commits

Author SHA1 Message Date
Kurtis Rader
a928517e95 improve converting strings to ints/longs
The existing code is inconsistent, and in a couple of cases wrong, about
dealing with strings that are not valid ints. For example, there are
locations that call wcstol() and check errno without first setting errno
to zero. Normalize the code to a consistent pattern.  This is mostly to
deal with inconsistencies between BSD, GNU, and other UNIXes.

This does make some syntax more liberal. For example `echo $PATH[1 .. 3]`
is now valid due to uniformly allowing leading and trailing whitespace
around numbers. Whereas prior to this change you would get a "Invalid
index value" error. Contrast this with `echo $PATH[ 1.. 3 ]` which was
valid and still is.
2016-11-25 18:52:15 -08:00
David B. Lamkins
5ec9fcd8d4 Allow browser for help to be chosen indenpendent of $BROWSER. 2016-11-25 18:35:22 -08:00
Valentin Hăloiu
ed5f90d22e Update key binding docs to reflect actual behavior
Some key bindings were updated in fish 2.4.0 but in some cases the
documentation does not correctly reflect the actual behavior. This
commit attempts to fix that.
2016-11-24 18:58:08 -08:00
Harm Aarts
5cfd3eb63a Update LXD completions. 2016-11-23 23:48:01 +01:00
Kurtis Rader
aad2848e80 use consistent mechanism to validate var names
Builtin commands that validate var names should use a consistent
mechanism. I noticed that builtin_read() had it's own custom code that
differed slightly from wcsvarname().

Fixes #3569
2016-11-22 16:18:20 -08:00
Kurtis Rader
320cb6857f an invalid flag to function is handled wrong
Specifically, an invalid flag keeps the function from being defined but
does not emit an error message.

Fixes #2827
2016-11-22 16:17:51 -08:00
Kurtis Rader
9ac78e06b4 fix builtin ulimit arg handling
Fixes #3570
2016-11-21 21:15:59 -08:00
Aaron Gyes
93e6f57dfc Run make depend
Some object file dependencies have changed.
2016-11-20 20:38:52 -08:00
Kurtis Rader
45c7836bec remove is_wchar_ucs2()
My previous change removed one place where is_wchar_ucs2() was used and
replaced it with compile time tests. This change does the same for the
other uses.
2016-11-20 18:25:49 -08:00
Kurtis Rader
b8778ba4a2 make fish_tests work on MS Windows with C++11
On Cygwin there are two narrowing conversions at line 931 in
src/fish_tests.cpp due to the code assuming a wchar_t is four bytes.
Obviously that's wrong but only became an issue with the pending change to
switch to C++11. The problematic values aren't actually used on Windows
because the tests that would use them are bypassed if is_wchar_ucs2()
returns true. This change predicates that code on a compile time rather
than a run time test.
2016-11-20 18:05:34 -08:00
Kurtis Rader
b16511344e fix incorrect pointer to int comparison
This came to my attention while testing the PR that switches us to the
C++11 standard and one of the compilers reported this error.
2016-11-20 15:04:51 -08:00
Aaron Gyes
1054a2fd36 Makefile.in: fix output alignment spacing 2016-11-20 14:38:02 -08:00
ridiculousfish
b86b84e2a9 L'\0' is not a pointer, don't compare it to one
Compare to NULL instead. Comparison with original code
shows this is what is intended.
2016-11-20 00:30:55 -08:00
ridiculousfish
52d1b6b97d Remove some dead functions
icompare_pred and icompare in history.cpp are unused
2016-11-19 23:12:49 -08:00
ridiculousfish
9b4310b10f Ensure we clear first_unwritten_new_item_index after history::merge
Prevents an issue where we think we've written out history items,
but we haven't, and so they get lost. Fixes #3496
2016-11-19 22:40:50 -08:00
Aaron Gyes
13a4ef80b3 Nuke spurious newline of shell exit.
Nobody has any idea why it's here, and it is mildy annoying to some
users, so let's remove it. Fixes #3502
2016-11-19 16:00:54 -08:00
ridiculousfish
0de2a1072f Fix a pair of implicit conversion warnings 2016-11-19 15:45:08 -08:00
maxried
2e5693a6bc Fix erroneous \t in sysctl completion (#3562)
The last commit to this auto completion changed it to use `string replace` instead of `tr`. Unfortunately they do not behave the same. `tr " = " "\t"` replaces " = " with a tabulator character, while `string replace -a " = " "\t"` replaces it with \t. Either `string` is misbehaving or this auto completion was broken.
2016-11-18 11:10:09 -08:00
Fabian Homborg
acc2353328 vi_cursor: For TERM = xterm require another condition
We cannot just use TERM = xterm and defined Ss sequence, as some old
vte-based terminals are still in the wild that don't support the
sequence and don't have $VTE_VERSION set.

I have tested this on

- konsole - supported and works ($KONSOLE_PROFILE_NAME)
- new xterm - supported and works ($XTERM_VERSION)
- lxterminal-gtk3 - supported and works ($VTE_VERSION)
- new gnome-terminal - supported and works ($VTE_VERSION)
- lxterminal-gtk2 - not supported and deactivated (no $VTE_VERSION)
- tmux in konsole - works
- tmux in lxterminal-gtk2 - deactivated

and for all supported ones with the respective variable erased, to see
that it is deactivated.

Fixes #3499.
2016-11-18 19:24:29 +01:00
Olivier Perret
8423345e09 Add completions for mkvextract (#3492)
* add completions for mkvextract

* fix edge cases with option placement in mkvextract.fish

* improve resiliency to errors in mkvextract.fish

* minor fixes in mkvextract.fish
2016-11-18 14:39:20 +01:00
Harm Aarts
36d4283d17 Add LXC/LXD completions.
At the moment this covers only the most basic use cases.
Texts are taken from `lxc help` command.
2016-11-18 12:27:29 +01:00
Kurtis Rader
acd8363c38 allow complete -d ''
There isn't a good reason to disallow an explicitly empty completion
description. Since I'm touching the code also modify the argument
parsing the match the style of most of the builtins.

Fixes #3557.
2016-11-17 14:53:50 -08:00
Kurtis Rader
e8a31a13a1 make it easy to get the legacy hybrid key bindings
The changes related to issue #3068 removed most of the emacs bindings
from vi mode. However, since fish 2.4.0 was released several people have
pointed out that the directions for reinstating the legacy hybrid key
bindings don't work. This change fixes that and makes it easier to use
the legacy hybrid bindings.

Fixes #3556
2016-11-16 22:45:00 -08:00
Fabian Homborg
3e82be4ac2 vi_cursor: Set required VTE version to 4000
It seems the changelog entry for 1910 was misleading.

Fixes #3499.
2016-11-16 22:43:33 +01:00
Kurtis Rader
521546a986 fix some lint warnings
This fixes some of the IWYU and cppcheck lint warnings. And only on
macOS (formerly OS X). Fixing these types of warnings on a broader set
of platforms should be done but this is a baby step to making `make
lint-all` have few, if any, warnings. This reduces the number of lines
in the `make lint-all` output on macOS by over 500 lines.
2016-11-15 21:15:22 -08:00
Kurtis Rader
708f80d855 handle unexpected args to binding mode functions
Fixes #3472
2016-11-15 18:44:20 -08:00
Kurtis Rader
8645aa94c8 improve linting tool
I found that after fixing the args to `cppcheck` it started reporting
lots of varFuncNullUB warnings. Suppress them as they should be safe to
ignore. Also, improve the readability of the script.
2016-11-14 19:20:12 -08:00
Kurtis Rader
043725cdd5 fix the style of fish_default_key_bindings.fish 2016-11-13 13:39:55 -08:00
Kurtis Rader
209a2576cd fix using external realpath command
Fixes #3489
2016-11-13 13:34:19 -08:00
Kurtis Rader
5284a133b0 silence "parameter 'notifier' is unused." 2016-11-11 21:07:30 -08:00
Kurtis Rader
2d26a262e7 make cppcheck useful again 2016-11-11 20:48:34 -08:00
Kurtis Rader
2e81ade66a don't use set_color reset
There was a discussion recently on Gitter about `set_color reset`. The
result was @floam creating commit bd03c3fbc to change it to `set_color
normal` in share/functions/vared.fish. This does the same for
tests/test_util.fish.
2016-11-11 19:07:52 -08:00
Kurtis Rader
5eb1ef4b4a use enum_map for parser enums
This simplifies the parsing code slightly and makes it more consistent
with how we deal with enums in the *builtin.cpp* module.
2016-11-11 18:56:56 -08:00
Kurtis Rader
5d6415b6bf use binary search for enum map lookups
Switch from a linear to a binary search when looking for a matching
string in an enum map. Testing shows this is a little more than twice as
fast when searching for keywords in the sixteen entry keyword_map array.
This speedup doesn't matter much when searching for subbcommands but any
slow down in the parser is unacceptable.
2016-11-11 18:02:43 -08:00
Aaron Gyes
bd03c3fbc5 vared.fish don't use undocumented 'reset' color
... there is no practical difference in behavior using this here
and it is not documented.
2016-11-11 14:08:28 -08:00
Kurtis Rader
20bcbcc252 fix webconfig.py lint issues 2016-11-10 16:23:08 -08:00
Kurtis Rader
47a9f99523 more robust fish_config IPv6 detection
Fixes #3530
2016-11-10 15:43:59 -08:00
David Adam
7356987e6e debian packaging: soften xdg-utils recommendation to suggestion
Closes #3534
2016-11-09 23:07:11 +08:00
Kurtis Rader
6518b6c6b7 make subcommand lookups table driven
I'm going to use the same mechanism elsewhere such as token_type_map
in src/parse_tree.cpp. But this change only affects the recently
introduce subcommand handling for the history and status commands.
2016-11-08 15:30:52 -08:00
Aaron Gyes
d5462fb3d7 Update issue template for 2.4.0 2016-11-08 14:04:34 -08:00
David Adam
d7283cdaa1 Merge branch 'Integration_2.4.0' 2016-11-08 12:06:15 +08:00
David Adam
54360d8cfe Bump version for 2.4.0 2016-11-08 11:20:54 +08:00
David Adam
0b0d0e7799 CHANGELOG: updates for 2.4.0 2016-11-08 11:20:50 +08:00
Kurtis Rader
609100c196 detect if the magic fish wide chars can be encoded
Verified on Cygwin on MS Windows 7 when invoked as
`env LANG=zh_CN.GBK@cjknarrow fish`. No regression seen
when run on other systems with UTF-8 locales.

Fixes #3503
2016-11-07 13:19:09 -08:00
Kurtis Rader
9e922a6e02 make status saner vis-a-vis arg parsing
The `status` command currently silently allows incompatible flags (i.e.,
subcommands). Too, using flags to specify subcommands misleads the user
into thinking they can specify multiple subcommands.

We recently modified the `history` command to deprecate using flags for
subcommands. This change does the same for the `status` command.

Fixes #3509
2016-11-07 12:11:08 -08:00
Colin Marquardt
a275618589 Typofix: shoe -> show 2016-11-07 09:46:07 -08:00
Kurtis Rader
83c7931afb treat TERM "tmux" the same as "screen"
To the extent that fish special-cases TERM values relevant to the
`screen` program it should do the same for the `tmux` program.

Fixes #3512
2016-11-06 20:27:48 -08:00
Kurtis Rader
1155c4b413 silence false positive errors from some compilers
Fixes #3529
2016-11-06 17:48:26 -08:00
Fabian Weisshaar
7a1146ebb5 add caffeinate completion, see #3525 2016-11-06 05:43:45 -08:00
Fabian Weisshaar
180c211dd2 add mdimport completion 2016-11-06 05:43:45 -08:00
Fabian Weisshaar
848495d4cf add mddiagnose completion 2016-11-06 05:43:45 -08:00
Fabian Weisshaar
87c51f2c10 add tmutil completion 2016-11-06 05:43:45 -08:00
Fabian Weisshaar
b41fced062 add mdfind completion 2016-11-06 05:43:45 -08:00
Fabian Weisshaar
71e835feec add mdls completion 2016-11-06 05:43:45 -08:00
Fabian Weisshaar
313cb0d248 add mdutil completion 2016-11-06 05:43:45 -08:00
Fabian Weisshaar
0c4ede5627 add nvram completion 2016-11-06 05:43:45 -08:00
Aaron Gyes
034aaaa62b cppcheck: incorrect printf specifiers 2016-11-06 04:29:47 -08:00
Aaron Gyes
839cd2a1c7 lint.fish: fix line number display 2016-11-05 15:38:49 -07:00
Aaron Gyes
adba0550d5 lint.fish: colorize cppcheck output 2016-11-05 15:37:19 -07:00
Aaron Gyes
6d1c127687 Enable LTO for fish.app release builds.
Shaves 2MB off app bundle size
2016-11-05 12:21:22 -07:00
Kurtis Rader
7cca963b8f lint all programs on macOS 2016-11-04 20:12:51 -07:00
Kurtis Rader
1fb8f4e277 lint: misc cleanups
Earlier lint cleanups overlooked a couple of modules because on macOS at
the moment oclint ignores them. I noticed this when I ran `make lint-all`
on Ubuntu.
2016-11-04 20:12:51 -07:00
Kurtis Rader
98863541c3 lint: prefer early exits and continue
Fix a location I missed in my earlier cleanup regarding early exits.
2016-11-04 20:12:51 -07:00
Aaron Gyes
87bfd1a01e Revert "Add a fish_key_reader wrapper"
This reverts commit c02f5ceb0f.
2016-11-04 19:08:48 -07:00
Aaron Gyes
95385eda80 Create a fish_key_reader wrapper ala fish_indent
Needed for fish_key_reader to work in a .app bundle without
fish previously installed.

I just copied fish_indent.fish and s/indent/key_reader
2016-11-04 19:07:37 -07:00
Aaron Gyes
c02f5ceb0f Add a fish_key_reader wrapper
This will be necessary for fkk to work when one is using the .app
bundle and has not installed fish otherwise.

I just copied fish_indent.fish.
2016-11-04 19:05:10 -07:00
Aaron Gyes
4ba1f9e398 Include fkk with fish.app 2016-11-04 18:56:57 -07:00
Aaron Gyes
294e78205c Allow xcode to build fish_key_reader 2016-11-04 18:50:37 -07:00
Aaron Gyes
d437a84828 Fix two xcode warnings
An unused macro and a documentation error.
2016-11-04 18:11:37 -07:00
Aaron Gyes
2f28e96956 Fix fish_tests xcode target 2016-11-04 17:55:51 -07:00
Manzur Mukhitdinov
00a8766635 auto-complete for sysbench (0.4.12)
SysBench is a modular, cross-platform and multi-threaded benchmark tool for
evaluating OS parameters that are important for a system running a database
under intensive load
2016-11-04 22:22:12 +01:00
Fabian Weisshaar
097d2246c2 add dig completion 2016-11-04 22:19:55 +01:00
Kurtis Rader
23c3101440 lint: goto and dead code 2016-11-03 16:53:58 -07:00
Kurtis Rader
003ea83410 lint: too few branches in switch statement 2016-11-03 16:41:51 -07:00
Kurtis Rader
de87419df9 lint: multiple unary operator 2016-11-03 16:37:26 -07:00
Kurtis Rader
4e505efc50 lint: redundant if statement 2016-11-03 16:32:27 -07:00
Kurtis Rader
b7d910a941 lint: long variable name 2016-11-03 16:19:41 -07:00
Kurtis Rader
f05fe4e292 lint: problems with default in switch statements 2016-11-03 16:19:41 -07:00
Patrick Häcker
72e687296b Create autocompletion for dpkg-reconfigure
The dpkg-reconfigure command is used on Debian and Ubuntu based systems to reconfigure packages.

According to the relevant manpage's the commited completion file should be complete.
2016-11-03 13:14:28 +01:00
Fabian Homborg
c9c311fbdb fish_vi_cursor: Ignore errors from tput
Fixes #3519.

(cherry picked from commit b9b66791c1)
2016-11-03 15:41:16 +08:00
Fabian Homborg
b9b66791c1 fish_vi_cursor: Ignore errors from tput
Fixes #3519.
2016-11-03 08:34:55 +01:00
Kurtis Rader
9b0d45d4fa lint: unnecessary else statement 2016-11-02 14:44:27 -07:00
Kurtis Rader
5709c81fe0 lint: empty while statement 2016-11-02 14:22:34 -07:00
Kurtis Rader
e35b91d38c lint: empty else block 2016-11-02 14:17:26 -07:00
Kurtis Rader
4f4d34e664 lint: missing break in switch statement 2016-11-02 14:07:12 -07:00
Kurtis Rader
f6047f02d6 lint: constant conditional operator 2016-11-01 21:19:34 -07:00
Kurtis Rader
71e69b6d75 lint: empty if statement 2016-11-01 20:42:02 -07:00
Kurtis Rader
60c47deca9 lint: avoid branching statement as last in loop 2016-11-01 20:00:09 -07:00
Kurtis Rader
c10952c354 lint: fish_indent all sample prompts 2016-11-01 19:19:45 -07:00
Kurtis Rader
e73226d7e8 lint: unused parameter 2016-11-01 19:12:39 -07:00
Aaron Gyes
19e12e3747 Revert mistaken file inclusion.
I was testing command descriptions and mistakenly left in a bogus file.
2016-10-31 23:46:40 -07:00
Aaron Gyes
e4ce5ca24f Revert "sorin right prompt: reset color at end"
This reverts commit 9701d5cc7b.
2016-10-31 23:43:46 -07:00
Aaron Gyes
01fb830bf5 Revert "Sorin prompt: updates"
This reverts commit c18614552d.
2016-10-31 23:43:20 -07:00
Aaron Gyes
edcf15e3d7 Sorin prompt: updates
Use $USER, prompt_hostname, string
Update to use correct color names such as magenta over purple.
Use bright color variants instead of bold in some cases.
2016-10-31 23:41:04 -07:00
Aaron Gyes
9f05697dcc sorin right prompt: reset color at end
bold mode being left enabled was causing issues in the pager.
2016-10-31 23:40:29 -07:00
Aaron Gyes
c18614552d Sorin prompt: updates
Use $USER, prompt_hostname, string
Update to use correct color names such as magenta over purple.
Use bright color variants instead of bold in some cases.
2016-10-31 23:29:50 -07:00
Aaron Gyes
9701d5cc7b sorin right prompt: reset color at end
bold mode being left enabled was causing issues in the pager.
2016-10-31 21:28:05 -07:00
Kurtis Rader
50fc3d72df lint: Use early exit/continue 2016-10-31 18:17:38 -07:00
Kurtis Rader
feaeca4999 lint: Use early exit/continue 2016-10-31 18:17:38 -07:00
Kurtis Rader
d4fb9a0e65 lint: Use early exit/continue 2016-10-31 18:17:38 -07:00
Kurtis Rader
2c38978115 lint: Use early exit/continue 2016-10-31 18:17:37 -07:00
Kurtis Rader
520f810bf9 lint: Use early exit/continue 2016-10-31 18:17:37 -07:00
Kurtis Rader
d441de33e5 lint: Use early exit/continue 2016-10-31 18:17:37 -07:00
Kurtis Rader
46b791240a lint: Use early exit/continue 2016-10-31 18:17:33 -07:00
Kurtis Rader
3bd24ddb17 lint: Use early exit/continue 2016-10-31 18:14:57 -07:00
Kurtis Rader
26c1430e82 lint: Use early exit/continue 2016-10-31 18:05:10 -07:00
Kurtis Rader
6c3900ff64 lint: Use early exit/continue 2016-10-31 18:05:10 -07:00
Kurtis Rader
6192e2453e lint: Use early exit/continue 2016-10-31 18:05:09 -07:00
Kurtis Rader
eab836864e lint: Use early exit/continue 2016-10-31 18:05:01 -07:00
Kurtis Rader
225caa2fe8 lint: Use early exit/continue 2016-10-31 18:03:03 -07:00
Kurtis Rader
4fe2a2921f lint: Use early exit/continue 2016-10-31 18:00:59 -07:00
Kurtis Rader
7779132595 lint: Use early exit/continue 2016-10-31 17:58:41 -07:00
Kurtis Rader
ca5a4ec1d5 lint: Use early exit/continue 2016-10-31 13:29:10 -07:00
Kurtis Rader
49ed20c8cb lint: Use early exit/continue 2016-10-31 13:29:10 -07:00
Aaron Gyes
a5f6382d77 Update changelog 2016-10-31 12:03:09 -07:00
Aaron Gyes
b2f047421d Supress fish_title only for Terminal.app
VTE terminals apparently do not use the OSC sequence to compose
title components.
2016-10-31 12:00:44 -07:00
Aaron Gyes
dfe7813c02 Fix Terminal.app title
Defining fish_title here is too late because there will already be a
title set. Work around issue by clearing it at same time.
2016-10-31 12:00:44 -07:00
David Adam
ddbf63c46f CHANGELOG: updates for 2.4.0 2016-10-31 22:35:36 +08:00
Fabian Homborg
c8fe0e53dd Rework cursor detection
Fixes #3499.

(cherry picked from commit 2a5ad198bf)
2016-10-31 21:52:50 +08:00
Fabian Homborg
7bcae09674 Disable vi-cursor on xterm < 282
Fixes #3499.

@zanchey: This is for integration-2.4.0.

(cherry picked from commit 7ea2dc4488)
2016-10-31 21:52:50 +08:00
Fabian Homborg
2a5ad198bf Rework cursor detection
Fixes #3499.
2016-10-31 21:51:06 +08:00
Aaron Gyes
960cc628b2 Don't choke defining aliases with quotes
Fixes #3510
2016-10-31 01:37:23 -07:00
Aaron Gyes
6b41240cd2 Revert "Move PCRE2 to pcre2"
This reverts commit f4f9ed56ee.
2016-10-30 21:29:48 -07:00
Aaron Gyes
6e873719fd Fix alias doc typo
Fix spelling typo, and a couple small tweaks.
2016-10-30 21:25:21 -07:00
Aaron Gyes
f4f9ed56ee Move PCRE2 to pcre2 2016-10-30 12:38:45 -07:00
David Adam
9f23f619c9 Makefile: pass correct version macro
Fixes display of version in documentation header. A shell-style variable
instead of a Makefile-style variable left it displayed as
ISH_BUILD_VERSION.

(cherry picked from commit 1e234f492c)
2016-10-30 14:27:11 +08:00
David Adam
1e234f492c Makefile: pass correct version macro
Fixes display of version in documentation header. A shell-style variable
instead of a Makefile-style variable left it displayed as
ISH_BUILD_VERSION.
2016-10-30 14:26:11 +08:00
Kurtis Rader
f0ab1331a5 lint: Use early exit/continue 2016-10-29 21:46:11 -07:00
Kurtis Rader
99b729eb4d lint: Use early exit/continue 2016-10-29 21:20:29 -07:00
Kurtis Rader
9af0797334 lint: Use early exit/continue 2016-10-29 20:51:03 -07:00
Kurtis Rader
6bef7b7be9 lint: constant if expression 2016-10-29 19:01:19 -07:00
Kurtis Rader
b0b2182535 lint: missing default in switch statements 2016-10-29 18:27:51 -07:00
Aaron Gyes
fb979922b3 Update alias docs 2016-10-29 13:57:05 -07:00
Aaron Gyes
c4bd110fca List alias-created functions on alias sans args
The previous change I made here makes this not hard to do, but
kind of lame in implementation.
2016-10-28 22:31:58 -07:00
Kurtis Rader
b663b0e818 lint: redundant if statement 2016-10-28 19:15:05 -07:00
Kurtis Rader
41f1232cf9 disable oclint BitwiseOperatorInConditional warning 2016-10-28 17:52:56 -07:00
Kurtis Rader
4a2aed1f8e lint: unnecessary else statement 2016-10-28 17:43:20 -07:00
Aaron Gyes
2d46969d3e alias: identify as alias in description.
Like so:

~ $ alias foo=bar
~ $ functions foo
function foo --description 'alias foo=bar'
	bar  $argv;
end
2016-10-28 14:44:55 -07:00
Kurtis Rader
f382fa8e8a lint: multiple unary operator 2016-10-27 21:21:54 -07:00
Fabian Homborg
7ea2dc4488 Disable vi-cursor on xterm < 282
Fixes #3499.

@zanchey: This is for integration-2.4.0.
2016-10-27 10:16:57 +02:00
Fabian Homborg
56679d4776 Don't use open function if a command exists
Turns out this is also the case on Haiku.

It also eliminates a fork.

Closes #3487.
2016-10-26 15:48:42 +02:00
Kurtis Rader
070ef6fd5b fix regression introduced by commit 851e449
My earlier attempt with commit 851e449 to eliminate all the compiler
warnings about mixing signed and unsigned ints in an expression
introduced a subtle bug. This fixes that mistake.

Fixes #3488

(cherry picked from commit 075be74cc4)
2016-10-26 18:28:49 +08:00
Kurtis Rader
075be74cc4 fix regression introduced by commit 851e449
My earlier attempt with commit 851e449 to eliminate all the compiler
warnings about mixing signed and unsigned ints in an expression
introduced a subtle bug. This fixes that mistake.

Fixes #3488
2016-10-25 20:56:15 -07:00
Aaron Gyes
5a8be61954 defaults completions: shorten and improve brevity
At 80 columns the description obscured 'find' in 'default find'.

Improve others.

(cherry picked from commit cbe2d4b5f1)
2016-10-25 08:55:03 +08:00
Fabian Weisshaar
7fdbbe0711 add defaults (macOS) completion
(cherry picked from commit 7878dbc4f0)
2016-10-25 08:55:02 +08:00
Fabian Weisshaar
8af6bb4436 add listFilesystems to diskutil completion
(cherry picked from commit e16f6ca2aa)
2016-10-25 08:55:02 +08:00
Kurtis Rader
2bb52c65c2 fix bug introduced by 42458ff7
There was one block of code modified by commit 42458ff7 that had
convoluted, inverted, logic. In the process of collapsing nested
"if" blocks the logic was modified to avoid using "!" everywhere the
bool was tested. Unfortunately I neglected to modify two of the
conditions used to set that var to reflect the changed polarity.
2016-10-24 17:13:39 -07:00
Kurtis Rader
37d91d0c29 change name of the function 2016-10-23 15:02:14 -07:00
Kurtis Rader
8dfee7ff76 add new file to change 2016-10-23 14:56:18 -07:00
Kurtis Rader
07de13f61f implement a fish_prompt_hostname function
Standardize how the host name is included in the prompts that do so.

Fixes #3480
2016-10-23 14:20:54 -07:00
Aaron Gyes
668de88e69 Supress fish_title only for Terminal.app
VTE terminals apparently do not use the OSC sequence to compose
title components.
2016-10-23 12:02:01 -07:00
Kurtis Rader
31432c3535 Revert "Fix lexicon_filter verbosity"
This reverts commit dcb39af8c0.

It breaks building the documentation because splitting the sed invocation
in the `lexicon_filter` target from the preceding `if` block means the
`WORDBL` and `WORDBR` shell vars aren't available.

(cherry picked from commit 100a0ea549)
2016-10-23 20:54:29 +08:00
Kurtis Rader
cdb82e45ac lint: remove another "too few branches in switch statement" 2016-10-22 22:12:22 -07:00
Kurtis Rader
a90b521eb4 lint: remove unused function 2016-10-22 21:28:46 -07:00
Kurtis Rader
25e0a39165 fix bug introduced by lint cleanup commit 42458ff 2016-10-22 21:14:21 -07:00
Kurtis Rader
d982427216 remove unused function
The fish_key_reader program was the only user of the
`set_wait_on_escape_ms()` function and that use was removed with commit
0461743. So remove it from the main fish code. This was found by `make
lint`.
2016-10-22 21:08:53 -07:00
Kurtis Rader
21521b2953 lint: too few branches in switch statement
Someone was way too enamored of the `switch` statement. Using it in
places where a simple `if...else if...else` was clearer and shorter.
2016-10-22 21:01:27 -07:00
Kurtis Rader
42458ff7ab lint: "collapsible if statements" warnings 2016-10-22 19:09:40 -07:00
Aaron Gyes
a8c9019a39 Re-fix 'fix lexicon_filter verbosity' 2016-10-22 18:37:11 -07:00
Kurtis Rader
100a0ea549 Revert "Fix lexicon_filter verbosity"
This reverts commit dcb39af8c0.

It breaks building the documentation because splitting the sed invocation
in the `lexicon_filter` target from the preceding `if` block means the
`WORDBL` and `WORDBR` shell vars aren't available.
2016-10-22 18:23:03 -07:00
Aaron Gyes
cbe2d4b5f1 defaults completions: shorten and improve brevity
At 80 columns the description obscured 'find' in 'default find'.

Improve others.
2016-10-22 12:37:00 -07:00
Fabian Weisshaar
7878dbc4f0 add defaults (macOS) completion 2016-10-22 20:13:18 +02:00
Fabian Weisshaar
e16f6ca2aa add listFilesystems to diskutil completion 2016-10-22 20:13:18 +02:00
Aaron Gyes
c7e26e494e Fix Terminal.app title
Defining fish_title here is too late because there will already be a
title set. Work around issue by clearing it at same time.
2016-10-22 10:47:46 -07:00
Kurtis Rader
6e6b294a3f lint: deal with "double negative" warnings 2016-10-20 21:14:40 -07:00
Kurtis Rader
00303ed07f lint cleanup: parameter reassignment 2016-10-20 18:53:31 -07:00
Kurtis Rader
345950ac1b workaround broken groff man page config
Fixes #2673
2016-10-19 13:43:04 -07:00
142 changed files with 6145 additions and 4962 deletions

View File

@@ -1,4 +1,9 @@
<?xml version="1.0"?>
<!-- Sadly we can't enable the following two rules since doing so causes false
positives in standard header files rather than just project specific
source files. If we can find a way to enable these rules by also
excluding system include files we should do so.
<rule version="1">
<pattern> wcwidth \(</pattern>
<message>
@@ -16,3 +21,4 @@
<summary>Always use fish_wcswidth rather than wcswidth.</summary>
</message>
</rule>
<--!>

10
.cppcheck.suppressions Normal file
View File

@@ -0,0 +1,10 @@
// suppress all instances of varFuncNullUB: "Passing NULL after the last typed
// argument to a variadic function leads to undefined behaviour." That's
// because all the places we do this are valid and won't cause problems even
// on a ILP64 platform because we're careful about using NULL rather than 0.
varFuncNullUB
// Suppress the warning about unmatched suppressions. At the moment these
// warnings are emitted even when removing the suppression comment results in
// the warning being suppressed. In other words this unmatchedSuppression
// warnings are false positives.
unmatchedSuppression

View File

@@ -1,5 +1,5 @@
<!-- check if this problem is already solved! github.com/issues?q=is:issue+user:fish-shell -->
- [ ] Have you checked if problem occurs with [fish 2.3.1](/fish-shell/fish-shell/releases/tag/2.3.1)?
- [ ] Have you checked if problem occurs with [fish 2.4.0](/fish-shell/fish-shell/releases/tag/2.4.0)?
- [ ] Tried fish without third-party customizations *(check `sh -c 'env HOME=$(mktemp -d) fish'`)*?
**fish version installed** *(`fish --version`)*:

14
.oclint
View File

@@ -51,3 +51,17 @@ disable-rules:
# and is therefore just noise. Disable this rule.
#
- InvertedLogic
#
# The idea behind the "double negative" rule is sound since constructs
# like "!!(var & flag)" should be written as "static_cast<bool>(var &
# flag)". Unfortunately this rule has way too many false positives;
# especially in the context of assert statements. So disable this rule.
#
- DoubleNegative
#
# Avoiding bitwise operators in a conditional is a good idea with one
# exception: testing whether a bit flag is set. Which happens to be the
# only time you'll see something like `if (j->flags & JOB_CONSTRUCTED)`
# in fish source.
#
- BitwiseOperatorInConditional

View File

@@ -1,3 +1,19 @@
# fish next-2.x (released ???)
---
# fish 2.4.0 (released November 8, 2016)
There are no major changes between 2.4b1 and 2.4.0.
## Notable fixes and improvements
- The documentation is now generated properly and with the correct version identifier.
- Automatic cursor changes are now only enabled on the subset of XTerm versions known to support them, resolving a problem where older versions printed garbage to the terminal before and after every prompt (#3499).
- Improved the title set in Apple Terminal.app.
- Added completions for `defaults` and improved completions for `diskutil` (#3478).
---
# fish 2.4b1 (released October 18, 2016)
## Significant changes

View File

@@ -286,7 +286,7 @@ prof: all
# directory once Doxygen is done.
#
doc: $(HDR_FILES_SRC) Doxyfile.user $(HTML_SRC) $(HELP_SRC) doc.h $(HDR_FILES) lexicon_filter
@echo " SED doxygen $(em)user_doc$(sgr0)"
@echo " doxygen $(em)user_doc$(sgr0)"
$v (cat Doxyfile.user; echo INPUT_FILTER=./lexicon_filter; echo PROJECT_NUMBER=$(FISH_BUILD_VERSION) | $(SED) "s/-.*//") | doxygen - && touch user_doc
$v rm -f $(wildcard $(addprefix ./user_doc/html/,arrow*.png bc_s.png bdwn.png closed.png doc.png folder*.png ftv2*.png nav*.png open.png splitbar.png sync_*.png tab*.* doxygen.* dynsections.js jquery.js pages.html))
@@ -367,7 +367,7 @@ test_interactive: $(call filter_up_to,test_interactive,$(active_test_goals))
# builtins
#
doc_src/commands.hdr:$(HELP_SRC) doc_src/commands.hdr.in |
@echo " CAT AWK $(em)$@$(sgr0)"
@echo " CAT AWK $(em)$@$(sgr0)"
$v rm -f command_list.tmp command_list_toc.tmp $@
$v for i in $(sort $(HELP_SRC)); do \
echo "<hr>" >>command_list.tmp; \
@@ -383,10 +383,10 @@ doc_src/commands.hdr:$(HELP_SRC) doc_src/commands.hdr.in |
$v cat $@.in | $(AWK) '{if ($$0 ~ /@command_list_toc@/) { system("cat command_list_toc.txt"); } else if ($$0 ~ /@command_list@/){ system("cat command_list.txt");} else{ print $$0;}}' >$@
toc.txt: $(HDR_FILES:index.hdr=index.hdr.in) | show-SED
@echo " SED $(em)$@$(sgr0)"
@echo " SED $(em)$@$(sgr0)"
$v rm -f toc.tmp $@
# Ugly hack to set the toc initial title for the main page
$v echo '- <a href="index.html" id="toc-index">fish shell documentation - $FISH_BUILD_VERSION</a>' > toc.tmp
$v echo '- <a href="index.html" id="toc-index">fish shell documentation - $(FISH_BUILD_VERSION)</a>' > toc.tmp
# The first sed command captures the page name, followed by the description
# The second sed command captures the command name \1 and the description \2, but only up to a dash
# This is to reduce the size of the TOC in the command listing on the main page
@@ -400,7 +400,7 @@ toc.txt: $(HDR_FILES:index.hdr=index.hdr.in) | show-SED
$v mv toc.tmp $@
doc_src/index.hdr: toc.txt doc_src/index.hdr.in | show-AWK
@echo " AWK CAT $(em)$@$(sgr0)"
@echo " AWK CAT $(em)$@$(sgr0)"
$v cat $@.in | $(AWK) '{if ($$0 ~ /@toc@/){ system("cat toc.txt");} else{ print $$0;}}' >$@
#
@@ -415,7 +415,7 @@ doc_src/index.hdr: toc.txt doc_src/index.hdr.in | show-AWK
lexicon.txt: doc_src/commands.hdr $(FUNCTIONS_DIR_FILES) $(COMPLETIONS_DIR_FILES) share/functions/__fish_config_interactive.fish | show-SED show-FGREP
$v rm -f lexicon.tmp lexicon_catalog.tmp lexicon_catalog.txt $@
# Scan sources for commands/functions/binaries/colours. If GNU sed was portable, this could be much smarter.
@echo " SEDFGREP $(em)$@$(sgr0)"
@echo " SEDFGREP $(em)$@$(sgr0)"
$v $(SED) <command_list_toc.txt >>lexicon.tmp -n \
-e "s|^.*>\([a-z][a-z_]*\)</a>|'\1'|w lexicon_catalog.tmp" \
-e "s|'\(.*\)'|bltn \1|p"; mv lexicon_catalog.tmp lexicon_catalog.txt
@@ -453,8 +453,7 @@ lexicon_filter: lexicon.txt lexicon_filter.in | show-SED
WORDBL='[[:<:]]'; WORDBR='[[:>:]]'; \
else \
WORDBL='\\<'; WORDBR='\\>'; \
fi
$v $(SED) <lexicon.txt >>$@.tmp -n -e "s|^\([a-z][a-z][a-z][a-z]\) \([a-z_-]*\)$$|s,$$WORDBL\2$$WORDBR,@\1{\2},g|p" -e '$$G;s/.*\n/b tidy/p'
fi; $(SED) <lexicon.txt >>$@.tmp -n -e "s|^\([a-z][a-z][a-z][a-z]\) \([a-z_-]*\)$$|s,$$WORDBL\2$$WORDBR,@\1{\2},g|p" -e '$$G;s/.*\n/b tidy/p';
$v mv $@.tmp $@; test -x $@ || chmod a+x $@;
@@ -475,7 +474,7 @@ doc.h: $(HDR_FILES)
# the internal help function text.
#
%.doxygen:%.txt
@echo " cat * $(em)$@$(sgr0)"
@echo " cat * $(em)$@$(sgr0)"
$v echo "/** \page " `basename $*` >$@;
$v cat $*.txt >>$@;
$v echo "*/" >>$@
@@ -521,7 +520,7 @@ doc.h: $(HDR_FILES)
# Create a template translation object
#
messages.pot: $(wildcard src/*.cpp src/*.h share/completions/*.fish share/functions/*.fish)
@echo " xgettext $(em)$@$(sgr0)"
@echo " xgettext $(em)$@$(sgr0)"
xgettext -k_ -kN_ $(wildcard src/*.cpp src/*.h) -o messages.pot
$v xgettext -j -k_ -kN_ -k--description -LShell --from-code=UTF-8 $(wildcard share/completions/*.fish share/functions/*.fish) share/fish.config -o messages.pot
@@ -650,6 +649,7 @@ install-force: all install-translations | show-datadir show-sysconfdir show-extr
$v $(INSTALL) -m 755 -d $(DESTDIR)$(datadir)/fish
$v $(INSTALL) -m 755 -d $(DESTDIR)$(datadir)/fish/completions
$v $(INSTALL) -m 755 -d $(DESTDIR)$(datadir)/fish/functions
$v $(INSTALL) -m 755 -d $(DESTDIR)$(datadir)/fish/groff
$v $(INSTALL) -m 755 -d $(DESTDIR)$(datadir)/fish/man/man1
$v $(INSTALL) -m 755 -d $(DESTDIR)$(datadir)/fish/tools
$v $(INSTALL) -m 755 -d $(DESTDIR)$(datadir)/fish/tools/web_config
@@ -674,6 +674,7 @@ install-force: all install-translations | show-datadir show-sysconfdir show-extr
$(INSTALL) -m 644 $$i $(DESTDIR)$(datadir)/fish/functions/; \
done;
@echo "Installing $(bo)man pages$(sgr0)";
$v $(INSTALL) -m 644 share/groff/* $(DESTDIR)$(datadir)/fish/groff/
$v for i in $(wildcard share/man/man1/*.1); do \
$(INSTALL) -m 644 $$i $(DESTDIR)$(datadir)/fish/man/man1/; \
done;
@@ -817,7 +818,7 @@ $(PCRE2_LIB): $(PCRE2_H)
$v $(MAKE) V=$(V) -C $(PCRE2_DIR) libpcre2-$(PCRE2_WIDTH).la
$(PCRE2_H):
@echo " autoconf $(em)$@$(sgr0)"
@echo " autoconf $(em)$@$(sgr0)"
$v (cd $(PCRE2_DIR) && ./config.status)
#
@@ -1019,14 +1020,13 @@ obj/expand.o: src/complete.h src/env.h src/exec.h src/expand.h
obj/expand.o: src/parse_constants.h src/iothread.h src/parse_util.h
obj/expand.o: src/tokenizer.h src/path.h src/proc.h src/io.h src/parse_tree.h
obj/expand.o: src/util.h src/wildcard.h src/wutil.h
obj/fallback.o: config.h src/signal.h src/fallback.h src/util.h
obj/fallback.o: config.h src/signal.h src/common.h src/fallback.h src/util.h
obj/fish.o: config.h src/builtin.h src/common.h src/fallback.h src/signal.h
obj/fish.o: src/env.h src/event.h src/expand.h src/parse_constants.h
obj/fish.o: src/fish_version.h src/function.h src/history.h src/wutil.h
obj/fish.o: src/input.h src/input_common.h src/io.h src/parser.h
obj/fish.o: src/parse_tree.h src/tokenizer.h src/proc.h src/path.h
obj/fish.o: src/reader.h src/complete.h src/highlight.h src/color.h
obj/fish.o: src/wildcard.h
obj/fish.o: src/input.h src/io.h src/parser.h src/parse_tree.h
obj/fish.o: src/tokenizer.h src/proc.h src/path.h src/reader.h src/complete.h
obj/fish.o: src/highlight.h src/color.h
obj/fish_indent.o: config.h src/color.h src/common.h src/fallback.h
obj/fish_indent.o: src/signal.h src/env.h src/fish_version.h src/highlight.h
obj/fish_indent.o: src/input.h src/output.h src/parse_constants.h
@@ -1135,8 +1135,8 @@ obj/sanity.o: src/wutil.h src/kill.h src/proc.h src/io.h src/parse_tree.h
obj/sanity.o: src/parse_constants.h src/tokenizer.h src/reader.h
obj/sanity.o: src/complete.h src/highlight.h src/color.h src/env.h
obj/sanity.o: src/sanity.h
obj/screen.o: config.h src/common.h src/fallback.h src/signal.h src/env.h
obj/screen.o: src/highlight.h src/color.h src/output.h src/pager.h
obj/screen.o: config.h src/common.h src/fallback.h src/signal.h
obj/screen.o: src/highlight.h src/color.h src/env.h src/output.h src/pager.h
obj/screen.o: src/complete.h src/reader.h src/parse_constants.h src/screen.h
obj/screen.o: src/util.h
obj/signal.o: config.h src/signal.h src/common.h src/fallback.h src/event.h
@@ -1145,7 +1145,7 @@ obj/signal.o: src/tokenizer.h src/reader.h src/complete.h src/highlight.h
obj/signal.o: src/color.h src/env.h src/wutil.h
obj/tokenizer.o: config.h src/common.h src/fallback.h src/signal.h
obj/tokenizer.o: src/tokenizer.h src/wutil.h
obj/utf8.o: config.h src/utf8.h
obj/utf8.o: config.h src/common.h src/fallback.h src/signal.h src/utf8.h
obj/util.o: config.h src/common.h src/fallback.h src/signal.h src/util.h
obj/util.o: src/wutil.h
obj/wcstringutil.o: config.h src/common.h src/fallback.h src/signal.h

View File

@@ -35,10 +35,14 @@ for arg in $argv
set cppcheck_args $cppcheck_args $arg
else if string match -q -- '-I*' $arg
set cppcheck_args $cppcheck_args $arg
else if string match -q -- '-iquote*' $arg
set cppcheck_args $cppcheck_args $arg
end
end
# Not sure when this became necessary but without these flags cppcheck no longer works on macOS.
# It complains that "Cppcheck cannot find all the include files." It appears that cppcheck used
# to, but no longer, recognizes the -iquote flag. So switch to hardcoding the appropriate -I flags.
set cppcheck_args $cppcheck_args -I . -I ./src
if test "$machine_type" = "x86_64"
set cppcheck_args -D__x86_64__ -D__LP64__ $cppcheck_args
end
@@ -49,7 +53,8 @@ else
# We haven't been asked to lint all the source. If there are uncommitted
# changes lint those, else lint the files in the most recent commit.
# Select (cached files) (modified but not cached, and untracked files)
set files (git diff-index --cached HEAD --name-only) (git ls-files --exclude-standard --others --modified)
set files (git diff-index --cached HEAD --name-only)
set files $files (git ls-files --exclude-standard --others --modified)
if not set -q files[1]
# No pending changes so lint the files in the most recent commit.
set files (git diff-tree --no-commit-id --name-only -r HEAD)
@@ -75,9 +80,12 @@ if set -q c_files[1]
for c_file in $c_files
switch $kernel_name
case Darwin
include-what-you-use -Xiwyu --no_default_mappings -Xiwyu --mapping_file=build_tools/iwyu.osx.imp $cppcheck_args --std=c++11 $c_file 2>&1
include-what-you-use -Xiwyu --no_default_mappings -Xiwyu \
--mapping_file=build_tools/iwyu.osx.imp --std=c++11 \
$cppcheck_args $c_file 2>&1
case Linux
include-what-you-use -Xiwyu --mapping_file=build_tools/iwyu.linux.imp $cppcheck_args $c_file 2>&1
include-what-you-use -Xiwyu --mapping_file=build_tools/iwyu.linux.imp \
$cppcheck_args $c_file 2>&1
case '*' # hope for the best
include-what-you-use $cppcheck_args $c_file 2>&1
end
@@ -92,7 +100,25 @@ if set -q c_files[1]
# The stderr to stdout redirection is because cppcheck, incorrectly IMHO, writes its
# diagnostic messages to stderr. Anyone running this who wants to capture its output will
# expect those messages to be written to stdout.
cppcheck -q --verbose --std=posix --language=c++ --template "[{file}:{line}]: {severity} ({id}): {message}" --suppress=missingIncludeSystem --inline-suppr --enable=$cppchecks --rule-file=.cppcheck.rule $cppcheck_args $c_files 2>&1
set -l cn (set_color normal)
set -l cb (set_color --bold)
set -l cu (set_color --underline)
set -l cm (set_color magenta)
set -l cbrm (set_color brmagenta)
set -l template "[$cb$cu{file}$cn$cb:{line}$cn] $cbrm{severity}$cm ({id}):$cn\n {message}"
set cppcheck_args -q --verbose --std=posix --language=c++ --template $template \
--suppress=missingIncludeSystem --inline-suppr --enable=$cppchecks \
--rule-file=.cppcheck.rules --suppressions-list=.cppcheck.suppressions $cppcheck_args
cppcheck $cppcheck_args $c_files 2>&1
echo
echo ========================================
echo 'Running `cppcheck --check-config` to identify missing includes similar problems.'
echo 'Ignore unmatchedSuppression warnings as they are probably false positives we'
echo 'cannot suppress.'
echo ========================================
cppcheck $cppcheck_args --check-config $c_files 2>&1
end
if type -q oclint
@@ -105,7 +131,7 @@ if set -q c_files[1]
# output will expect those messages to be written to stdout.
if test "$kernel_name" = "Darwin"
if not test -f compile_commands.json
xcodebuild >xcodebuild.log
xcodebuild -alltargets >xcodebuild.log
oclint-xcodebuild xcodebuild.log >/dev/null
end
if test $all = yes

5
debian/control vendored
View File

@@ -13,7 +13,7 @@ Vcs-Browser: https://github.com/fish-shell/fish-shell
Package: fish
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, fish-common (= ${source:Version}), passwd (>= 4.0.3-10), bc, gettext-base, man-db
Recommends: xsel (>=1.2.0), xdg-utils
Recommends: xsel (>=1.2.0)
Description: friendly interactive shell
Fish is a command-line shell for modern systems, focusing on user-friendliness,
sensibility and discoverability in interactive use. The syntax is simple, but
@@ -22,7 +22,8 @@ Description: friendly interactive shell
Package: fish-common
Architecture: all
Depends: ${misc:Depends}
Recommends: fish, python (>=2.6), xdg-utils
Recommends: fish, python (>=2.6)
Suggests: xdg-utils
Replaces: fish (<= 2.1.1.dfsg-2)
Description: friendly interactive shell (architecture-independent files)
Fish is a command-line shell for modern systems, focusing on user-friendliness,

View File

@@ -2,39 +2,34 @@
\subsection alias-synopsis Synopsis
\fish{synopsis}
alias
alias NAME DEFINITION
alias NAME=DEFINITION
\endfish
\subsection alias-description Description
`alias` is a simple wrapper for the `function` builtin. It exists for backwards compatibility with Posix shells. For other uses, it is recommended to define a <a href='#function'>function</a>.
`alias` is a simple wrapper for the `function` builtin, which creates a function wrapping a command. It has similar syntax to POSIX shell `alias`. For other uses, it is recommended to define a <a href='#function'>function</a>.
`fish` does not keep track of which functions have been defined using `alias`. They must be erased using `functions -e`.
`fish` marks functions that have been created by `alias` by including the command used to create them in the function description. You can list `alias`-created functions by running `alias` without arguments. They must be erased using `functions -e`.
- `NAME` is the name of the alias
- `DEFINITION` is the actual command to execute. The string `$argv` will be appended.
You cannot create an alias to a function with the same name.
Note that spaces need to be escaped in the call to alias just like in the commandline _even inside the quotes_.
You cannot create an alias to a function with the same name. Note that spaces need to be escaped in the call to `alias` just like at the command line, _even inside quoted parts_.
\subsection alias-example Example
The following code will create `rmi`, which runs `rm` with additional arguments on every invocation.
\fish
alias rmi "rm -i"
alias rmi="rm -i"
# This is equivalent to entering the following function:
function rmi
function rmi --wraps rm --description 'alias rmi=rm -i'
rm -i $argv
end
# This needs to have the spaces escaped or "Chrome.app..." will be seen as an argument to "/Applications/Google":
alias chrome='/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome banana'
\endfish

View File

@@ -13,6 +13,8 @@ If a `SECTION` is specified, the help for that command is shown.
If the BROWSER environment variable is set, it will be used to display the documentation. Otherwise, fish will search for a suitable browser.
If you prefer to use a different browser (other than as described above) for fish help, you can set the fish_help_browser variable. This variable may be set as an array, where the first element is the browser command and the rest are browser options.
Note that most builtin commands display their help in the terminal when given the `--help` option.

View File

@@ -14,8 +14,6 @@ history ( -h | --help )
`history` is used to search, delete, and otherwise manipulate the history of interactive commands.
Note that for backwards compatibility each subcommand can also be specified as a long option. For example, rather than `history search` you can type `history --search`. Those long options are deprecated and will be removed in a future release.
The following operations (sub-commands) are available:
- `search` returns history items matching the search string. If no search string is provided it returns all history items. This is the default operation if no other operation is specified. You only have to explicitly say `history search` if you wish to search for one of the subcommands. The `--contains` search option will be used if you don't specify a different search option. Entries are ordered newest to oldest. If stdout is attached to a tty the output will be piped through your pager by the history function. The history builtin simply writes the results to stdout.
@@ -60,9 +58,10 @@ history --search --contains "foo"
history --delete --prefix "foo"
# Interactively deletes commands which start with "foo" from the history.
# You can select more than one entry by entering their IDs seperated by a space.
\endfish
\subsection history-notes Notes
If you specify both `--prefix` and `--contains` the last flag seen is used.
\endfish
Note that for backwards compatibility each subcommand can also be specified as a long option. For example, rather than `history search` you can type `history --search`. Those long options are deprecated and will be removed in a future release.

View File

@@ -977,7 +977,7 @@ Some bindings are shared between emacs- and vi-mode because they aren't text edi
- @key{Alt,&uarr;,Up} and @key{Alt,&darr;,Down} search the command history for the previous/next token containing the token under the cursor before the search was started. If the commandline was not on a token when the search started, all tokens match. See the <a href='#history'>history</a> section for more information on history searching.
- @key{Control,C} deletes the entire line.
- @key{Control,C} cancels the entire line.
- @key{Control,D} delete one character to the right of the cursor. If the command line is empty, @key{Control,D} will exit fish.
@@ -987,6 +987,8 @@ Some bindings are shared between emacs- and vi-mode because they aren't text edi
- @key{Control,W} moves the previous path component (everything up to the previous "/") to the <a href="#killring">killring</a>.
- @key{Control,X} copies the current buffer to the system's clipboard, @key{Control,V} inserts the clipboard contents.
- @key{Alt,D} moves the next word to the <a href="#killring">killring</a>.
- @key{Alt,H} (or @key{F1}) shows the manual page for the current command, if one exists.
@@ -1068,16 +1070,11 @@ Command mode is also known as normal mode.
- @key{[} and @key{]} search the command history for the previous/next token containing the token under the cursor before the search was started. See the <a href='#history'>history</a> section for more information on history searching.
- @key{Control, X} copies the current buffer to the system's clipboard, @key{Control, V} inserts the clipboard contents.
- @key{Control,C} deletes the entire line.
- @key{Backspace} moves the cursor left.
\subsubsection vi-mode-insert Insert mode
- @key{Escape} or @key{Control,C} enters <a href="#vi-mode-command">command mode</a>.
- @key{Control,x} moves the cursor to the end of the line. If an autosuggestion is available, it will be accepted completely.
- @key{Escape} enters <a href="#vi-mode-command">command mode</a>.
- @key{Backspace} removes one character to the left.

View File

@@ -9,6 +9,8 @@ open FILES...
`open` opens a file in its default application, using the appropriate tool for the operating system. On GNU/Linux, this requires the common but optional `xdg-open` utility, from the `xdg-utils` package.
Note that this function will not be used if a command by this name exists (which is the case on macOS or Haiku).
\subsection open-example Example

View File

@@ -2,33 +2,50 @@
\subsection status-synopsis Synopsis
\fish{synopsis}
status [OPTION]
status
status is-login
status is-interactive
status is-block
status is-command-substitution
status is-no-job-control
status is-full-job-control
status is-interactive-job-control
status current-filename
status current-line-number
status print-stack-trace
status job-control CONTROL-TYPE
\endfish
\subsection status-description Description
With no arguments, `status` displays a summary of the current login and job control status of the shell.
The following options are available:
The following operations (sub-commands) are available:
- `-c` or `--is-command-substitution` returns 0 if fish is currently executing a command substitution.
- `is-command-sub` returns 0 if fish is currently executing a command substitution. Also `-c` or `--is-command-substitution`.
- `-b` or `--is-block` returns 0 if fish is currently executing a block of code.
- `is-block` returns 0 if fish is currently executing a block of code. Also `-b` or `--is-block`.
- `-i` or `--is-interactive` returns 0 if fish is interactive - that is, connected to a keyboard.
- `is-interactive` returns 0 if fish is interactive - that is, connected to a keyboard. Also `-i` or `--is-interactive`.
- `-l` or `--is-login` returns 0 if fish is a login shell - that is, if fish should perform login tasks such as setting up the PATH.
- `is-login` returns 0 if fish is a login shell - that is, if fish should perform login tasks such as setting up the PATH. Also `-l` or `--is-login`.
- `--is-full-job-control` returns 0 if full job control is enabled.
- `is-full-job-control` returns 0 if full job control is enabled. Also `--is-full-job-control` (no short flag).
- `--is-interactive-job-control` returns 0 if interactive job control is enabled.
- `is-interactive-job-control` returns 0 if interactive job control is enabled. Also, `--is-interactive-job-control` (no short flag).
- `--is-no-job-control` returns 0 if no job control is enabled.
- `is-no-job-control` returns 0 if no job control is enabled. Also `--is-no-job-control` (no short flag).
- `-f` or `--current-filename` prints the filename of the currently running script.
- `current-filename` prints the filename of the currently running script. Also `-f` or `--current-filename`.
- `-n` or `--current-line-number` prints the line number of the currently running script.
- `current-line-number` prints the line number of the currently running script. Also `-n` or `--current-line-number`.
- `-j CONTROLTYPE` or `--job-control=CONTROLTYPE` sets the job control type, which can be `none`, `full`, or `interactive`.
- `job-control CONTROL-TYPE` sets the job control type, which can be `none`, `full`, or `interactive`. Also `-j CONTROL-TYPE` or `--job-control=CONTROL-TYPE`.
- `-t` or `--print-stack-trace` prints a stack trace of all function calls on the call stack.
- `print-stack-trace` prints a stack trace of all function calls on the call stack. Also `-t` or `--print-stack-trace`.
\subsection status-notes Notes
For backwards compatibility each subcommand can also be specified as a long or short option. For example, rather than `status is-login` you can type `status --is-login`. The flag forms are deprecated and may be removed in a future release (but not before fish 3.0).
You can only specify one subcommand per invocation even if you use the flag form of the subcommand.

View File

@@ -56,6 +56,7 @@
D01A2C9B16964C8200767098 /* Copy Files */,
);
dependencies = (
9C7A55801DCD73930049C25D /* PBXTargetDependency */,
D0F01A1315AA36280034B3B1 /* PBXTargetDependency */,
D0F01A1715AA36300034B3B1 /* PBXTargetDependency */,
D0A564EF168D09C000AF6161 /* PBXTargetDependency */,
@@ -67,6 +68,72 @@
/* Begin PBXBuildFile section */
63A2C0E91CC60F3B00973404 /* pcre2_find_bracket.c in Sources */ = {isa = PBXBuildFile; fileRef = 63A2C0E81CC5F9FB00973404 /* pcre2_find_bracket.c */; };
9C7A55271DCD651F0049C25D /* fallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853E13B3ACEE0099B651 /* fallback.cpp */; };
9C7A55281DCD65540049C25D /* builtin_commandline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853013B3ACEE0099B651 /* builtin_commandline.cpp */; };
9C7A55291DCD65540049C25D /* builtin_complete.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853113B3ACEE0099B651 /* builtin_complete.cpp */; };
9C7A552A1DCD65540049C25D /* builtin_jobs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853213B3ACEE0099B651 /* builtin_jobs.cpp */; };
9C7A552B1DCD65540049C25D /* builtin_set.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853313B3ACEE0099B651 /* builtin_set.cpp */; };
9C7A552C1DCD65540049C25D /* builtin_set_color.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0C861EA16CC7054003B5A04 /* builtin_set_color.cpp */; };
9C7A552D1DCD65540049C25D /* builtin_ulimit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853413B3ACEE0099B651 /* builtin_ulimit.cpp */; };
9C7A552E1DCD65540049C25D /* builtin_printf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0CA63F316FC275F00093BD4 /* builtin_printf.cpp */; };
9C7A552F1DCD65820049C25D /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855E13B3ACEE0099B651 /* util.cpp */; };
9C7A55361DCD71330049C25D /* autoload.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0C6FCC914CFA4B0004CE8AD /* autoload.cpp */; };
9C7A55371DCD71330049C25D /* builtin_commandline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853013B3ACEE0099B651 /* builtin_commandline.cpp */; };
9C7A55381DCD71330049C25D /* builtin_complete.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853113B3ACEE0099B651 /* builtin_complete.cpp */; };
9C7A55391DCD71330049C25D /* builtin_jobs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853213B3ACEE0099B651 /* builtin_jobs.cpp */; };
9C7A553A1DCD71330049C25D /* builtin_set.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853313B3ACEE0099B651 /* builtin_set.cpp */; };
9C7A553B1DCD71330049C25D /* builtin_set_color.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0C861EA16CC7054003B5A04 /* builtin_set_color.cpp */; };
9C7A553C1DCD71330049C25D /* builtin_ulimit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853413B3ACEE0099B651 /* builtin_ulimit.cpp */; };
9C7A553D1DCD71330049C25D /* builtin_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0F3373A1506DE3C00ECEFC0 /* builtin_test.cpp */; };
9C7A553E1DCD71330049C25D /* builtin_printf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0CA63F316FC275F00093BD4 /* builtin_printf.cpp */; };
9C7A553F1DCD71330049C25D /* builtin_string.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D04F7F7B1BA4BF4000B0F227 /* builtin_string.cpp */; };
9C7A55401DCD71330049C25D /* color.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0B6B0FE14E88BA400AD6C10 /* color.cpp */; };
9C7A55411DCD71330049C25D /* common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853613B3ACEE0099B651 /* common.cpp */; };
9C7A55421DCD71330049C25D /* event.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853B13B3ACEE0099B651 /* event.cpp */; };
9C7A55431DCD71330049C25D /* input_common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854913B3ACEE0099B651 /* input_common.cpp */; };
9C7A55441DCD71330049C25D /* io.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854C13B3ACEE0099B651 /* io.cpp */; };
9C7A55451DCD71330049C25D /* iothread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854D13B3ACEE0099B651 /* iothread.cpp */; };
9C7A55461DCD71330049C25D /* parse_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855213B3ACEE0099B651 /* parse_util.cpp */; };
9C7A55471DCD71330049C25D /* path.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855513B3ACEE0099B651 /* path.cpp */; };
9C7A55481DCD71330049C25D /* parse_execution.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D052D8091868F7FC003ABCBD /* parse_execution.cpp */; };
9C7A55491DCD71330049C25D /* postfork.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D09B1C1914FC7B5B00F91077 /* postfork.cpp */; };
9C7A554A1DCD71330049C25D /* screen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855A13B3ACEE0099B651 /* screen.cpp */; };
9C7A554B1DCD71330049C25D /* signal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855C13B3ACEE0099B651 /* signal.cpp */; };
9C7A554C1DCD71330049C25D /* utf8.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0C9733718DE5449002D7C81 /* utf8.cpp */; };
9C7A554D1DCD71330049C25D /* builtin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853513B3ACEE0099B651 /* builtin.cpp */; };
9C7A554E1DCD71330049C25D /* function.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854413B3ACEE0099B651 /* function.cpp */; };
9C7A554F1DCD71330049C25D /* complete.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853713B3ACEE0099B651 /* complete.cpp */; };
9C7A55501DCD71330049C25D /* env.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853A13B3ACEE0099B651 /* env.cpp */; };
9C7A55511DCD71330049C25D /* exec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853C13B3ACEE0099B651 /* exec.cpp */; };
9C7A55521DCD71330049C25D /* wcstringutil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0F5B46319CFCDE80090665E /* wcstringutil.cpp */; };
9C7A55531DCD71330049C25D /* expand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853D13B3ACEE0099B651 /* expand.cpp */; };
9C7A55541DCD71330049C25D /* fallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853E13B3ACEE0099B651 /* fallback.cpp */; };
9C7A55551DCD71330049C25D /* fish_version.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D00F63F019137E9D00FCCDEC /* fish_version.cpp */; settings = {COMPILER_FLAGS = "-I$(DERIVED_FILE_DIR)"; }; };
9C7A55561DCD71330049C25D /* highlight.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854713B3ACEE0099B651 /* highlight.cpp */; };
9C7A55571DCD71330049C25D /* history.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854813B3ACEE0099B651 /* history.cpp */; };
9C7A55581DCD71330049C25D /* kill.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854F13B3ACEE0099B651 /* kill.cpp */; };
9C7A55591DCD71330049C25D /* parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855413B3ACEE0099B651 /* parser.cpp */; };
9C7A555A1DCD71330049C25D /* parser_keywords.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855313B3ACEE0099B651 /* parser_keywords.cpp */; };
9C7A555B1DCD71330049C25D /* proc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855713B3ACEE0099B651 /* proc.cpp */; };
9C7A555C1DCD71330049C25D /* reader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855813B3ACEE0099B651 /* reader.cpp */; };
9C7A555D1DCD71330049C25D /* sanity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855913B3ACEE0099B651 /* sanity.cpp */; };
9C7A555E1DCD71330049C25D /* tokenizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855D13B3ACEE0099B651 /* tokenizer.cpp */; };
9C7A555F1DCD71330049C25D /* wildcard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0856013B3ACEE0099B651 /* wildcard.cpp */; };
9C7A55601DCD71330049C25D /* wgetopt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855F13B3ACEE0099B651 /* wgetopt.cpp */; };
9C7A55611DCD71330049C25D /* wutil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0856113B3ACEE0099B651 /* wutil.cpp */; };
9C7A55621DCD71330049C25D /* input.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854A13B3ACEE0099B651 /* input.cpp */; };
9C7A55631DCD71330049C25D /* output.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855113B3ACEE0099B651 /* output.cpp */; };
9C7A55641DCD71330049C25D /* intern.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854B13B3ACEE0099B651 /* intern.cpp */; };
9C7A55651DCD71330049C25D /* env_universal_common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853813B3ACEE0099B651 /* env_universal_common.cpp */; };
9C7A55661DCD71330049C25D /* pager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D03238891849D1980032CF2C /* pager.cpp */; };
9C7A55681DCD71330049C25D /* parse_tree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0C52F351765284C00BFAB82 /* parse_tree.cpp */; };
9C7A55691DCD71330049C25D /* parse_productions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0FE8EE7179FB75F008C9F21 /* parse_productions.cpp */; };
9C7A556A1DCD71330049C25D /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855E13B3ACEE0099B651 /* util.cpp */; };
9C7A556C1DCD71330049C25D /* libncurses.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D02A8C15983CFA008E62BD /* libncurses.dylib */; };
9C7A556D1DCD71330049C25D /* libpcre2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D04F7FD01BA4E29300B0F227 /* libpcre2.a */; };
9C7A557D1DCD71890049C25D /* fish_key_reader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9C7A557C1DCD717C0049C25D /* fish_key_reader.cpp */; };
9C7A557E1DCD71CD0049C25D /* print_help.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855613B3ACEE0099B651 /* print_help.cpp */; };
9C7A55811DCD739C0049C25D /* fish_key_reader in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9C7A55721DCD71330049C25D /* fish_key_reader */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
D00769121990137800CA4627 /* autoload.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0C6FCC914CFA4B0004CE8AD /* autoload.cpp */; };
D00769131990137800CA4627 /* builtin_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0F3373A1506DE3C00ECEFC0 /* builtin_test.cpp */; };
D00769141990137800CA4627 /* color.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0B6B0FE14E88BA400AD6C10 /* color.cpp */; };
@@ -286,6 +353,27 @@
/* End PBXBuildRule section */
/* Begin PBXContainerItemProxy section */
9C7A55321DCD71330049C25D /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D0A084F213B3AC130099B651 /* Project object */;
proxyType = 1;
remoteGlobalIDString = D008D0C41BC58F8800841177;
remoteInfo = "generate-version-header";
};
9C7A55341DCD71330049C25D /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D0A084F213B3AC130099B651 /* Project object */;
proxyType = 1;
remoteGlobalIDString = D04F7FCF1BA4E29300B0F227;
remoteInfo = libpcre2.a;
};
9C7A557F1DCD73930049C25D /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D0A084F213B3AC130099B651 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 9C7A55301DCD71330049C25D;
remoteInfo = fish_key_reader;
};
D008D0CA1BC58FDD00841177 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D0A084F213B3AC130099B651 /* Project object */;
@@ -438,6 +526,7 @@
dstPath = base/bin;
dstSubfolderSpec = 1;
files = (
9C7A55811DCD739C0049C25D /* fish_key_reader in CopyFiles */,
D0F019F115A977140034B3B1 /* fish in CopyFiles */,
D0F019F315A977290034B3B1 /* fish_indent in CopyFiles */,
);
@@ -468,6 +557,17 @@
/* Begin PBXFileReference section */
4E142D731B56B5D7008783C8 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = config.h; path = ../osx/config.h; sourceTree = "<group>"; };
63A2C0E81CC5F9FB00973404 /* pcre2_find_bracket.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pcre2_find_bracket.c; sourceTree = "<group>"; };
9C7A55721DCD71330049C25D /* fish_key_reader */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fish_key_reader; sourceTree = BUILT_PRODUCTS_DIR; };
9C7A55731DCD716F0049C25D /* builtin_commandline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = builtin_commandline.h; sourceTree = "<group>"; };
9C7A55741DCD716F0049C25D /* builtin_complete.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = builtin_complete.h; sourceTree = "<group>"; };
9C7A55751DCD716F0049C25D /* builtin_jobs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = builtin_jobs.h; sourceTree = "<group>"; };
9C7A55761DCD716F0049C25D /* builtin_printf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = builtin_printf.h; sourceTree = "<group>"; };
9C7A55771DCD716F0049C25D /* builtin_set_color.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = builtin_set_color.h; sourceTree = "<group>"; };
9C7A55781DCD716F0049C25D /* builtin_set.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = builtin_set.h; sourceTree = "<group>"; };
9C7A55791DCD716F0049C25D /* builtin_string.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = builtin_string.h; sourceTree = "<group>"; };
9C7A557A1DCD716F0049C25D /* builtin_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = builtin_test.h; sourceTree = "<group>"; };
9C7A557B1DCD716F0049C25D /* builtin_ulimit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = builtin_ulimit.h; sourceTree = "<group>"; };
9C7A557C1DCD717C0049C25D /* fish_key_reader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fish_key_reader.cpp; sourceTree = "<group>"; };
D00769421990137800CA4627 /* fish_tests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fish_tests; sourceTree = BUILT_PRODUCTS_DIR; };
D00F63F019137E9D00FCCDEC /* fish_version.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fish_version.cpp; sourceTree = "<group>"; };
D01A2D23169B730A00767098 /* man1 */ = {isa = PBXFileReference; lastKnownFileType = text; name = man1; path = pages_for_manpath/man1; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -618,6 +718,15 @@
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
9C7A556B1DCD71330049C25D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9C7A556C1DCD71330049C25D /* libncurses.dylib in Frameworks */,
9C7A556D1DCD71330049C25D /* libpcre2.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D007693C1990137800CA4627 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -743,6 +852,16 @@
D0D02A91159845EF008E62BD /* Sources */ = {
isa = PBXGroup;
children = (
9C7A557C1DCD717C0049C25D /* fish_key_reader.cpp */,
9C7A55731DCD716F0049C25D /* builtin_commandline.h */,
9C7A55741DCD716F0049C25D /* builtin_complete.h */,
9C7A55751DCD716F0049C25D /* builtin_jobs.h */,
9C7A55761DCD716F0049C25D /* builtin_printf.h */,
9C7A55771DCD716F0049C25D /* builtin_set_color.h */,
9C7A55781DCD716F0049C25D /* builtin_set.h */,
9C7A55791DCD716F0049C25D /* builtin_string.h */,
9C7A557A1DCD716F0049C25D /* builtin_test.h */,
9C7A557B1DCD716F0049C25D /* builtin_ulimit.h */,
4E142D731B56B5D7008783C8 /* config.h */,
D0C6FCCB14CFA4B7004CE8AD /* autoload.h */,
D0C6FCC914CFA4B0004CE8AD /* autoload.cpp */,
@@ -888,6 +1007,7 @@
D0D02AD01598642A008E62BD /* fish_indent */,
D00769421990137800CA4627 /* fish_tests */,
D04F7FD01BA4E29300B0F227 /* libpcre2.a */,
9C7A55721DCD71330049C25D /* fish_key_reader */,
);
name = Products;
sourceTree = "<group>";
@@ -905,6 +1025,24 @@
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
9C7A55301DCD71330049C25D /* fish_key_reader */ = {
isa = PBXNativeTarget;
buildConfigurationList = 9C7A556E1DCD71330049C25D /* Build configuration list for PBXNativeTarget "fish_key_reader" */;
buildPhases = (
9C7A55351DCD71330049C25D /* Sources */,
9C7A556B1DCD71330049C25D /* Frameworks */,
);
buildRules = (
);
dependencies = (
9C7A55311DCD71330049C25D /* PBXTargetDependency */,
9C7A55331DCD71330049C25D /* PBXTargetDependency */,
);
name = fish_key_reader;
productName = fish_Xcode;
productReference = 9C7A55721DCD71330049C25D /* fish_key_reader */;
productType = "com.apple.product-type.tool";
};
D00769101990137800CA4627 /* fish_tests */ = {
isa = PBXNativeTarget;
buildConfigurationList = D007693E1990137800CA4627 /* Build configuration list for PBXNativeTarget "fish_tests" */;
@@ -1031,6 +1169,7 @@
D00769101990137800CA4627 /* fish_tests */,
D04F7FCF1BA4E29300B0F227 /* pcre2 */,
D008D0C41BC58F8800841177 /* generate-version-header */,
9C7A55301DCD71330049C25D /* fish_key_reader */,
);
};
/* End PBXProject section */
@@ -1226,10 +1365,80 @@
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
9C7A55351DCD71330049C25D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
9C7A557E1DCD71CD0049C25D /* print_help.cpp in Sources */,
9C7A557D1DCD71890049C25D /* fish_key_reader.cpp in Sources */,
9C7A55361DCD71330049C25D /* autoload.cpp in Sources */,
9C7A55371DCD71330049C25D /* builtin_commandline.cpp in Sources */,
9C7A55381DCD71330049C25D /* builtin_complete.cpp in Sources */,
9C7A55391DCD71330049C25D /* builtin_jobs.cpp in Sources */,
9C7A553A1DCD71330049C25D /* builtin_set.cpp in Sources */,
9C7A553B1DCD71330049C25D /* builtin_set_color.cpp in Sources */,
9C7A553C1DCD71330049C25D /* builtin_ulimit.cpp in Sources */,
9C7A553D1DCD71330049C25D /* builtin_test.cpp in Sources */,
9C7A553E1DCD71330049C25D /* builtin_printf.cpp in Sources */,
9C7A553F1DCD71330049C25D /* builtin_string.cpp in Sources */,
9C7A55401DCD71330049C25D /* color.cpp in Sources */,
9C7A55411DCD71330049C25D /* common.cpp in Sources */,
9C7A55421DCD71330049C25D /* event.cpp in Sources */,
9C7A55431DCD71330049C25D /* input_common.cpp in Sources */,
9C7A55441DCD71330049C25D /* io.cpp in Sources */,
9C7A55451DCD71330049C25D /* iothread.cpp in Sources */,
9C7A55461DCD71330049C25D /* parse_util.cpp in Sources */,
9C7A55471DCD71330049C25D /* path.cpp in Sources */,
9C7A55481DCD71330049C25D /* parse_execution.cpp in Sources */,
9C7A55491DCD71330049C25D /* postfork.cpp in Sources */,
9C7A554A1DCD71330049C25D /* screen.cpp in Sources */,
9C7A554B1DCD71330049C25D /* signal.cpp in Sources */,
9C7A554C1DCD71330049C25D /* utf8.cpp in Sources */,
9C7A554D1DCD71330049C25D /* builtin.cpp in Sources */,
9C7A554E1DCD71330049C25D /* function.cpp in Sources */,
9C7A554F1DCD71330049C25D /* complete.cpp in Sources */,
9C7A55501DCD71330049C25D /* env.cpp in Sources */,
9C7A55511DCD71330049C25D /* exec.cpp in Sources */,
9C7A55521DCD71330049C25D /* wcstringutil.cpp in Sources */,
9C7A55531DCD71330049C25D /* expand.cpp in Sources */,
9C7A55541DCD71330049C25D /* fallback.cpp in Sources */,
9C7A55551DCD71330049C25D /* fish_version.cpp in Sources */,
9C7A55561DCD71330049C25D /* highlight.cpp in Sources */,
9C7A55571DCD71330049C25D /* history.cpp in Sources */,
9C7A55581DCD71330049C25D /* kill.cpp in Sources */,
9C7A55591DCD71330049C25D /* parser.cpp in Sources */,
9C7A555A1DCD71330049C25D /* parser_keywords.cpp in Sources */,
9C7A555B1DCD71330049C25D /* proc.cpp in Sources */,
9C7A555C1DCD71330049C25D /* reader.cpp in Sources */,
9C7A555D1DCD71330049C25D /* sanity.cpp in Sources */,
9C7A555E1DCD71330049C25D /* tokenizer.cpp in Sources */,
9C7A555F1DCD71330049C25D /* wildcard.cpp in Sources */,
9C7A55601DCD71330049C25D /* wgetopt.cpp in Sources */,
9C7A55611DCD71330049C25D /* wutil.cpp in Sources */,
9C7A55621DCD71330049C25D /* input.cpp in Sources */,
9C7A55631DCD71330049C25D /* output.cpp in Sources */,
9C7A55641DCD71330049C25D /* intern.cpp in Sources */,
9C7A55651DCD71330049C25D /* env_universal_common.cpp in Sources */,
9C7A55661DCD71330049C25D /* pager.cpp in Sources */,
9C7A55681DCD71330049C25D /* parse_tree.cpp in Sources */,
9C7A55691DCD71330049C25D /* parse_productions.cpp in Sources */,
9C7A556A1DCD71330049C25D /* util.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D00769111990137800CA4627 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
9C7A552F1DCD65820049C25D /* util.cpp in Sources */,
9C7A55281DCD65540049C25D /* builtin_commandline.cpp in Sources */,
9C7A55291DCD65540049C25D /* builtin_complete.cpp in Sources */,
9C7A552A1DCD65540049C25D /* builtin_jobs.cpp in Sources */,
9C7A552B1DCD65540049C25D /* builtin_set.cpp in Sources */,
9C7A552C1DCD65540049C25D /* builtin_set_color.cpp in Sources */,
9C7A552D1DCD65540049C25D /* builtin_ulimit.cpp in Sources */,
9C7A552E1DCD65540049C25D /* builtin_printf.cpp in Sources */,
9C7A55271DCD651F0049C25D /* fallback.cpp in Sources */,
D00769121990137800CA4627 /* autoload.cpp in Sources */,
D00769131990137800CA4627 /* builtin_test.cpp in Sources */,
D00769141990137800CA4627 /* color.cpp in Sources */,
@@ -1440,6 +1649,21 @@
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
9C7A55311DCD71330049C25D /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D008D0C41BC58F8800841177 /* generate-version-header */;
targetProxy = 9C7A55321DCD71330049C25D /* PBXContainerItemProxy */;
};
9C7A55331DCD71330049C25D /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D04F7FCF1BA4E29300B0F227 /* pcre2 */;
targetProxy = 9C7A55341DCD71330049C25D /* PBXContainerItemProxy */;
};
9C7A55801DCD73930049C25D /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 9C7A55301DCD71330049C25D /* fish_key_reader */;
targetProxy = 9C7A557F1DCD73930049C25D /* PBXContainerItemProxy */;
};
D008D0CB1BC58FDD00841177 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D008D0C41BC58F8800841177 /* generate-version-header */;
@@ -1503,6 +1727,42 @@
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
9C7A556F1DCD71330049C25D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
LLVM_LTO = NO;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
9C7A55701DCD71330049C25D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
LLVM_LTO = YES_THIN;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
9C7A55711DCD71330049C25D /* Release_C++11 */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
LLVM_LTO = YES_THIN;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = "Release_C++11";
};
D007693F1990137800CA4627 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -1511,6 +1771,7 @@
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
LLVM_LTO = NO;
PRODUCT_NAME = fish_tests;
};
name = Debug;
@@ -1523,6 +1784,7 @@
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
LLVM_LTO = YES_THIN;
PRODUCT_NAME = fish_tests;
};
name = Release;
@@ -1535,6 +1797,7 @@
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
LLVM_LTO = YES_THIN;
PRODUCT_NAME = fish_tests;
};
name = "Release_C++11";
@@ -1619,6 +1882,7 @@
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
INFOPLIST_FILE = osx/Info.plist;
LLVM_LTO = YES_THIN;
PRODUCT_BUNDLE_IDENTIFIER = "com.ridiculousfish.fish-shell";
PRODUCT_NAME = fish;
WRAPPER_EXTENSION = app;
@@ -1632,6 +1896,7 @@
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
LLVM_LTO = YES_THIN;
PRODUCT_NAME = fish;
};
name = "Release_C++11";
@@ -1644,6 +1909,7 @@
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
LLVM_LTO = YES_THIN;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = "Release_C++11";
@@ -1694,6 +1960,7 @@
);
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
GCC_WARN_UNUSED_VARIABLE = NO;
LLVM_LTO = NO;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/osx/pcre2 $(SRCROOT)/osx/shared_headers/";
@@ -1719,6 +1986,7 @@
);
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
GCC_WARN_UNUSED_VARIABLE = NO;
LLVM_LTO = YES_THIN;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/osx/pcre2 $(SRCROOT)/osx/shared_headers/";
@@ -1744,6 +2012,7 @@
);
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
GCC_WARN_UNUSED_VARIABLE = NO;
LLVM_LTO = YES_THIN;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/osx/pcre2 $(SRCROOT)/osx/shared_headers/";
@@ -1900,6 +2169,7 @@
);
GCC_WARN_UNINITIALIZED_AUTOS = YES;
INFOPLIST_FILE = osx/Info.plist;
LLVM_LTO = NO;
PRODUCT_BUNDLE_IDENTIFIER = "com.ridiculousfish.fish-shell";
PRODUCT_NAME = fish;
WRAPPER_EXTENSION = app;
@@ -1917,6 +2187,7 @@
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
INFOPLIST_FILE = osx/Info.plist;
LLVM_LTO = YES_THIN;
PRODUCT_BUNDLE_IDENTIFIER = "com.ridiculousfish.fish-shell";
PRODUCT_NAME = fish;
WRAPPER_EXTENSION = app;
@@ -1935,6 +2206,7 @@
"$(inherited)",
);
GCC_WARN_UNINITIALIZED_AUTOS = YES;
LLVM_LTO = NO;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
@@ -1947,6 +2219,7 @@
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
LLVM_LTO = YES_THIN;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
@@ -1958,6 +2231,7 @@
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
LLVM_LTO = NO;
PRODUCT_NAME = fish;
};
name = Debug;
@@ -1969,6 +2243,7 @@
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
LLVM_LTO = YES_THIN;
PRODUCT_NAME = fish;
};
name = Release;
@@ -1996,6 +2271,16 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
9C7A556E1DCD71330049C25D /* Build configuration list for PBXNativeTarget "fish_key_reader" */ = {
isa = XCConfigurationList;
buildConfigurations = (
9C7A556F1DCD71330049C25D /* Debug */,
9C7A55701DCD71330049C25D /* Release */,
9C7A55711DCD71330049C25D /* Release_C++11 */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D007693E1990137800CA4627 /* Build configuration list for PBXNativeTarget "fish_tests" */ = {
isa = XCConfigurationList;
buildConfigurations = (

View File

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

View File

@@ -5,7 +5,7 @@
#define HAVE_BACKTRACE_SYMBOLS 1
/* Define to 1 if you have the `clock_gettime' function. */
/* #undef HAVE_CLOCK_GETTIME */
#define HAVE_CLOCK_GETTIME 1
/* Define to 1 if you have the <curses.h> header file. */
#define HAVE_CURSES_H 1
@@ -51,7 +51,7 @@
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `mkostemp' function. */
/* #undef HAVE_MKOSTEMP */
#define HAVE_MKOSTEMP 1
/* Define to 1 if you have the <ncurses/curses.h> header file. */
/* #undef HAVE_NCURSES_CURSES_H */
@@ -167,7 +167,7 @@
#define PACKAGE_NAME "fish"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "fish 2.4b1"
#define PACKAGE_STRING "fish 2.4.0-git"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "fish"
@@ -176,7 +176,7 @@
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "2.4b1"
#define PACKAGE_VERSION "2.4.0-git"
/* The size of `wchar_t', as computed by sizeof. */
#define SIZEOF_WCHAR_T 4

View File

@@ -18,11 +18,11 @@ static void die(const char *format, ...) {
vfprintf(stderr, format, ap);
va_end(ap);
fputc('\n', stderr);
if (s_command_path[0] != '\0') {
unlink(s_command_path);
}
exit(EXIT_FAILURE);
}
@@ -31,14 +31,14 @@ static void launch_fish_with_applescript(NSString *fish_binary_path)
// load the script from a resource by fetching its URL from within our bundle
NSString *path = [[NSBundle mainBundle] pathForResource:@"launch_fish" ofType:@"scpt"];
if (! path) die("Couldn't get path to launch_fish.scpt");
NSURL *url = [NSURL fileURLWithPath:path isDirectory:NO];
if (! url) die("Couldn't get URL to launch_fish.scpt");
NSDictionary *errors = nil;
NSAppleScript *appleScript = [[NSAppleScript alloc] initWithContentsOfURL:url error:&errors];
if (! appleScript) die("Couldn't load AppleScript");
// create the first parameter
NSAppleEventDescriptor *firstParameter =
[NSAppleEventDescriptor descriptorWithString:fish_binary_path];
@@ -84,16 +84,17 @@ static void launch_fish_with_applescript(NSString *fish_binary_path)
/* This approach asks Terminal to open a script that we control */
int main(void) {
@autoreleasepool {
/* Get the fish executable. Make sure it's absolute. */
NSURL *fish_executable = [[NSBundle mainBundle] URLForResource:@"fish" withExtension:@"" subdirectory:@"base/bin"];
NSURL *fish_executable = [[NSBundle mainBundle] URLForResource:@"fish" withExtension:@""
subdirectory:@"base/bin"];
if (! fish_executable)
die("Could not find fish executable in bundle");
launch_fish_with_applescript([fish_executable path]);
}
/* If we succeeded, it will clean itself up */
return 0;
}

View File

@@ -0,0 +1,11 @@
# completion for caffeinate (macOS)
complete -c caffeinate -s d -f -d 'Create an assertion to prevent the display from sleeping'
complete -c caffeinate -s i -f -d 'Create an assertion to prevent the system from idle sleeping'
complete -c caffeinate -s m -f -d 'Create an assertion to prevent the disk from idle sleeping'
complete -c caffeinate -s s -f -d 'Create an assertion to prevent the system from sleeping (AC power)'
complete -c caffeinate -s u -f -d 'Create an assertion to declare that user is active'
complete -c caffeinate -s t -x -a '10 60 300 600 1800 3600' -d 'Specifies the timeout value in seconds'
complete -c caffeinate -s w -x -a '(__fish_complete_pids)' -d 'Waits for the process with the specified PID to exit'
complete -c caffeinate -x -a '(__fish_complete_subcommand)'

View File

@@ -0,0 +1,33 @@
# completion for defaults (macOS)
function __fish_defaults_domains
defaults domains | string split ", "
end
complete -f -c defaults -o 'currentHost' -d 'Restricts preferences operations to the current logged-in host'
complete -f -c defaults -o 'host' -d 'Restricts preferences operations to hostname'
# read
complete -f -c defaults -n '__fish_use_subcommand' -a read -d 'Shows defaults entire given domain'
complete -f -c defaults -n '__fish_seen_subcommand_from read read-type write rename delete' -a '(__fish_defaults_domains)'
complete -f -c defaults -n '__fish_seen_subcommand_from read read-type write rename delete' -o 'app'
# write
complete -f -c defaults -n '__fish_use_subcommand' -a write -d 'Writes domain or or a key in the domain'
complete -f -c defaults -n '__fish_seen_subcommand_from write' -o 'string' -d 'String as the value for the given key'
complete -f -c defaults -n '__fish_seen_subcommand_from write' -o 'data' -d 'Raw data bytes for given key'
complete -f -c defaults -n '__fish_seen_subcommand_from write' -o 'int' -d 'Integer as the value for the given key'
complete -f -c defaults -n '__fish_seen_subcommand_from write' -o 'float' -d 'Floating point number as the value for the given key'
complete -f -c defaults -n '__fish_seen_subcommand_from write' -o 'bool' -d 'Boolean as the value for the given key'
complete -f -c defaults -n '__fish_seen_subcommand_from write' -o 'date' -d 'Date as the value for the given key'
complete -f -c defaults -n '__fish_seen_subcommand_from write' -o 'array' -d 'Array as the value for the given key'
complete -f -c defaults -n '__fish_seen_subcommand_from write' -o 'array-add' -d 'Add new elements to the end of an array'
complete -f -c defaults -n '__fish_seen_subcommand_from write' -o 'dict' -d 'Add a dictionary to domain'
complete -f -c defaults -n '__fish_seen_subcommand_from write' -o 'dict-add' -d 'Add new key/value pairs to a dictionary'
complete -f -c defaults -n '__fish_use_subcommand' -a read-type -d 'Shows the type for the given domain, key'
complete -f -c defaults -n '__fish_use_subcommand' -a rename -d 'Renames old_key to new_key'
complete -f -c defaults -n '__fish_use_subcommand' -a delete -d 'Deletes domain or a key in the domain'
complete -f -c defaults -n '__fish_use_subcommand' -a domains -d 'Prints the names of all domains in the users defaults system'
complete -f -c defaults -n '__fish_use_subcommand' -a find -d 'Searches for word in domain names, keys, and values'
complete -f -c defaults -n '__fish_use_subcommand' -a help -d 'Prints a list of possible command formats'

View File

@@ -0,0 +1,64 @@
# completion for dig
function __fish_complete_dig
set -l token (commandline -ct)
switch $token
case '+tries=*' '+retry=*' '+time=*' '+bufsize=*' '+ndots=*' '+edns=*'
printf '%s\n' $token(seq 0 50)
end
end
complete -f -c dig -s 4 -d 'Use IPv4 query transport only'
complete -f -c dig -s 6 -d 'Use IPv6 query transport only'
complete -f -c dig -s m -d 'Enable memory usage debugging'
complete -c dig -s b -x -d 'Bind to source address/port'
complete -c dig -s f -r -d 'Specify batch mode file'
complete -c dig -s c -x -a 'IN CH HS QCLASS' -d 'Specify query class'
complete -c dig -s k -r -d 'Specify TSIG key file'
complete -c dig -s y -x -d 'specify named base64 TSIG key'
complete -c dig -s p -x -d 'Specify port number'
complete -c dig -s q -x -d 'Specify query name'
complete -c dig -s t -x -a 'A AAAA AFSDB APL CAA CDNSKEY CDS CERT CNAME DHCID DLV DNAME DNSKEY DS HIP IPSECKEY KEY KX LOC MX NAPTR NS NSEC NSEC3 NSEC3PARAM PTR RRSIG RP SIG SOA SRV SSHFP TA TKEY TLSA TSIG TXT URI' -d 'Specify query type'
complete -c dig -s x -x -d 'Reverse lookup'
complete -f -c dig -s h -d 'Print help and exit'
complete -f -c dig -s v -d 'Print version and exit'
complete -f -c dig -a '+vc +novc' -d 'TCP mode'
complete -f -c dig -a '+tcp +notcp' -d 'TCP mode, alternate syntax'
complete -f -c dig -a '+search +nosearch' -d 'Set whether to use searchlist'
complete -f -c dig -a '+showsearch +noshowsearch' -d 'Search with intermediate results'
complete -f -c dig -a '+defname +nodefname' -d 'Deprecated, treated as a synonym for +[no]search'
complete -f -c dig -a '+recurse +norecurse' -d 'Recursive mode'
complete -f -c dig -a '+ignore +noignore' -d 'Dont revert to TCP for TC responses.'
complete -f -c dig -a '+fail +nofail' -d 'Dont try next server on SERVFAIL'
complete -f -c dig -a '+besteffort +nobesteffort' -d 'Try to parse even illegal messages'
complete -f -c dig -a '+aaonly +noaaonly' -d 'Set AA flag in query (+[no]aaflag)'
complete -f -c dig -a '+adflag +noadflag' -d 'Set AD flag in query'
complete -f -c dig -a '+cdflag +nocdflag' -d 'Set CD flag in query'
complete -f -c dig -a '+cl +nocl' -d 'Control display of class in records'
complete -f -c dig -a '+cmd +nocmd' -d 'Control display of command line'
complete -f -c dig -a '+comments +nocomments' -d 'Control display of comment lines'
complete -f -c dig -a '+question +noquestion' -d 'Control display of question'
complete -f -c dig -a '+answer +noanswer' -d 'Control display of answer'
complete -f -c dig -a '+authority +noauthority' -d 'Control display of authority'
complete -f -c dig -a '+additional +noadditional' -d 'Control display of additional'
complete -f -c dig -a '+stats +nostats' -d 'Control display of statistics'
complete -f -c dig -a '+short +noshort' -d 'Disable everything except short form of answer'
complete -f -c dig -a '+ttlid +nottlid' -d 'Control display of ttls in records'
complete -f -c dig -a '+all +noall' -d 'Set or clear all display flags'
complete -f -c dig -a '+qr +noqr' -d 'Print question before sending'
complete -f -c dig -a '+nssearch +nonssearch' -d 'Search all authoritative nameservers'
complete -f -c dig -a '+identify +noidentify' -d 'ID responders in short answers'
complete -f -c dig -a '+trace +notrace' -d 'Trace delegation down from root'
complete -f -c dig -a '+dnssec +nodnssec' -d 'Request DNSSEC records'
complete -f -c dig -a '+nsid +nonsid' -d 'Request Name Server ID'
complete -f -c dig -a '+multiline +nomultiline' -d 'Print records in an expanded format'
complete -f -c dig -a '+onesoa +noonesoa' -d 'AXFR prints only one soa record'
complete -f -c dig -a '+tries=' -d 'Set number of UDP attempts'
complete -f -c dig -a '+retry=' -d 'Set number of UDP retries'
complete -f -c dig -a '+time=' -d 'Set query timeout'
complete -f -c dig -a '+bufsize=' -d 'Set EDNS0 Max UDP packet size'
complete -f -c dig -a '+ndots=' -d 'Set NDOTS value'
complete -f -c dig -a '+edns=' -d 'Set EDNS version'
complete -c dig -a '(__fish_complete_dig)'

View File

@@ -1,4 +1,4 @@
#completion for diskutil
# completion for diskutil (macOS)
function __fish_diskutil_devices
set -l mountpoints /dev/disk*; printf '%s\n' $mountpoints
@@ -22,6 +22,10 @@ complete -f -c diskutil -n '__fish_seen_subcommand_from info' -o 'all' -d 'Proce
# activity
complete -f -c diskutil -n '__fish_use_subcommand' -a activity -d 'Continuously display system-wide disk manipulation activity'
# listFilesystems
complete -f -c diskutil -n '__fish_use_subcommand' -a listFilesystems -d 'Show the file system personalities available'
complete -f -c diskutil -n '__fish_seen_subcommand_from listFilesystems' -o 'plist' -d 'Return a property list'
# umount
complete -f -c diskutil -n '__fish_use_subcommand' -a umount -d 'Unmount a single volume'
complete -f -c diskutil -n '__fish_seen_subcommand_from umount' -a '(__fish_diskutil_mounted_volumes)'

View File

@@ -0,0 +1,14 @@
# Completions for the `dpkg-reconfigure` command
complete -f -c dpkg-reconfigure -a '(__fish_print_packages)' --description 'Package'
# Support flags
complete -x -f -c dpkg-reconfigure -s h -l help --description 'Display help'
# General options
complete -f -c dpkg-reconfigure -s f -l frontend -r -a "dialog readline noninteractive gnome kde editor web" --description 'Set configuration frontend'
complete -f -c dpkg-reconfigure -s p -l priority -r -a "low medium high critical" --description 'Set priority threshold'
complete -f -c dpkg-reconfigure -l default-priority --description 'Use default priority threshold'
complete -f -c dpkg-reconfigure -s u -l unseen-only --description 'Show only unseen question'
complete -f -c dpkg-reconfigure -l force --description 'Reconfigure also inconsistent packages'
complete -f -c dpkg-reconfigure -l no-reload --description 'Prevent reloading templates'

View File

@@ -0,0 +1,51 @@
function __fish_lxc_no_subcommand -d 'Test if lxc has yet to be given the command'
for i in (commandline --tokenize --cut-at-cursor --current-process)
if contains -- $i config copy delete exec file help image launch list move network profile publish remote restore restart snapshot start stop
return 1
end
end
return 0
end
function __fish_lxc_list_containers
lxc list -c n | string match -r '\| [a-zA-Z_-]+' | string replace -r '\| ' ''
end
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments config --description 'Manage configuration.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments copy --description 'Copy containers within or in between lxd instances.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments delete --description 'Delete containers or snapshots.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments exec --description 'Execute the specified command in a container.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments file --description 'Manage files on a container.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments finger --description 'Check if the LXD instance is up.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments help --description 'Print help.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments image --description 'Manipulate container images.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments info --description 'List information on LXD servers and containers.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments init --description 'Initialize a container from a particular image.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments launch --description 'Launch a container from a particular image.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments list --description 'Lists the available resources.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments manpage --description 'Prints all the subcommands help.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments monitor --description 'Monitor activity on the LXD server.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments move --description 'Move containers within or in between lxd instances.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments network --description 'Manage networks.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments pause --description 'Changes state of one or more containers to pause.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments profile --description 'Manage configuration profiles.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments publish --description 'Publish containers as images.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments remote --description 'Manage remote LXD servers.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments restart --description 'Changes state of one or more containers to restart.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments restore --description 'Set the current state of a container back to a snapshot.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments snapshot --description 'Create a read-only snapshot of a container.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments start --description 'Changes state of one or more containers to start.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments stop --description 'Changes state of one or more containers to stop.'
complete --condition '__fish_lxc_no_subcommand' --command lxc --no-files --arguments version --description 'Prints the version number of this client tool.'
# config
complete --condition '__fish_seen_subcommand_from config' --command lxc --no-files --arguments "device get set unset show edit trust"
# exec
complete --condition '__fish_seen_subcommand_from exec' --command lxc --no-files --arguments "(__fish_lxc_list_containers)"
# start
complete --condition '__fish_seen_subcommand_from start' --command lxc --no-files --arguments "(__fish_lxc_list_containers)"
# stop
complete --condition '__fish_seen_subcommand_from stop' --command lxc --no-files --arguments "(__fish_lxc_list_containers)"

View File

@@ -0,0 +1,12 @@
# completion for mddiagnose (macOS)
complete -c mddiagnose -s h -f -d 'Display help'
complete -c mddiagnose -s d -f -d 'Ignore unknown options'
complete -c mddiagnose -s n -f -d 'Do not reveal the resulting package in the Finder'
complete -c mddiagnose -s r -f -d 'Avoid restricted operations such as heap'
complete -c mddiagnose -s s -f -d 'Skip gathering system.log'
complete -c mddiagnose -s v -f -d 'Prints version of mddiagnose'
complete -c mddiagnose -s m -f -d 'Minimal report'
complete -c mddiagnose -s e -r -d 'Evalute indexing information for path'
complete -c mddiagnose -s p -r -d 'Evalute permissions information for path'
complete -c mddiagnose -s f -r -d 'Write the diagnostic to the specified path'

View File

@@ -0,0 +1,12 @@
# completion for mdfind (macOS)
complete -c mdfind -o attr -x -d 'Fetches the value of the specified attribute'
complete -c mdfind -o count -f -d 'Query only reports matching items count'
complete -c mdfind -o onlyin -x -a '(__fish_complete_directories (commandline -ct))' -d 'Search only within given directory'
complete -c mdfind -o live -f -d 'Query should stay active'
complete -c mdfind -o name -x -d 'Search on file name only'
complete -c mdfind -o reprint -f -d 'Reprint results on live update'
complete -c mdfind -s s -x -d 'Show contents of smart folder'
complete -c mdfind -s 0 -f -d 'Use NUL (\0) as a path separator, for use with xargs -0'
complete -c mdfind -o literal -f -d 'Force the provided query string to be taken as a literal'
complete -c mdfind -o interpret -f -d 'Interprete query string as Spotlight query'

View File

@@ -0,0 +1,13 @@
# completion for mdimport (macOS)
complete -c mdimport -s g -r -d 'Import files using the listed plugin'
complete -c mdimport -s V -f -d 'Print timing information for this run'
complete -c mdimport -s A -f -d 'Print out the list of all of the attributes and exit'
complete -c mdimport -s X -f -d 'Print out the schema file and exit'
complete -c mdimport -s r -f -d 'Ask the server to reimport files for UTIs claimed by the listed plugin'
complete -c mdimport -s p -f -d 'Print out performance information gathered during the run'
complete -c mdimport -s L -f -d 'Print the list of installed importers and exit'
complete -c mdimport -s d -x -a '1 2 3 4' -d 'Print debugging information'
complete -c mdimport -s n -f -d 'Dont send the imported attributes to the data store'
complete -c mdimport -s w -x -d 'Wait for the specified interval between scanning files'
complete -c mdimport -s o -r -d 'Write the imported attributes to a file'

View File

@@ -0,0 +1,6 @@
# completion for mdls (macOS)
complete -c mdls -s n -o name -x -d 'Print only the matching metadata attribute value'
complete -c mdls -s r -o raw -f -d 'Print raw attribute data'
complete -c mdls -n '__fish_seen_subcommand_from -raw -r' -o nullMarker -x -d 'Sets a marker string to be used when a requested attribute is null'
complete -c mdls -s p -o plist -r -d 'Output attributes in XML format to file'

View File

@@ -0,0 +1,24 @@
# completion for mdutil (macOS)
function __fish_mdutil_volumes
command mdutil -a -s | while read -l line
if string match -q \t"*" -- $line
printf "%s\n" $line
else
# Use printf to not output a newline so indented lines are joined
# to non-indented ones
printf "%s" (string replace -r ':$' '' -- $line)
end
end
end
complete -c mdutil -s p -f -d 'Publish metadata'
complete -c mdutil -s i -f -a 'on off' -d 'Turn indexing on or off'
complete -c mdutil -s d -f -d 'Disable Spotlight activity for volume'
complete -c mdutil -s E -f -d 'Erase and rebuild index'
complete -c mdutil -s s -f -d 'Print indexing status'
complete -c mdutil -s t -x -a '(__fish_mdutil_volumes)' -d 'Resolve files from file id with an optional volume path or device id'
complete -c mdutil -s a -f -d 'Apply command to all volumes'
complete -c mdutil -s V -x -a '(__fish_mdutil_volumes)' -d 'Apply command to all stores on the specified volume'
complete -c mdutil -s v -f -d 'Display verbose information'
complete -c mdutil -x -a '(__fish_mdutil_volumes)'

View File

@@ -0,0 +1,82 @@
# Sample output of 'mkvmerge -i file.mkv'
#
# File 'file.mkv': container: Matroska
# Track ID 0: video (MPEG-4p10/AVC/h.264)
# Track ID 1: audio (AAC)
# Track ID 2: subtitles (SubStationAlpha)
# Attachment ID 1: type 'application/x-truetype-font', size 53532 bytes, file name 'some_font.ttf'
# Chapters: 7 entires
function __fish_mkvextract_find_matroska_in_args
set -l cmd (commandline -opc)
if not set -q cmd[3]
return 1
end
for c in $cmd[3..-1]
set -l skip_next 1
test $skip_next -eq 0; and set skip_next 1; and continue
switch $c
# General options with an argument we need to skip
case "--ui-language" "--command-line-charset" "--output-charset" "-r" "--redirect-output" "-c" "--blockadd" "--simple-language"
set skip_next 0
continue
# these behave like commands and everything after them is ignored
case "-h" "--help" "-V" "--version"
return 1
case "*"
if test -f "$c"
echo $c
return 0
end
continue
end
end
return 1
end
function __fish_mkvextract_print_attachments
if set -l matroska (__fish_mkvextract_find_matroska_in_args)
if set -l info (mkvmerge -i $matroska)
string match 'Attachment ID*' -- $info | string replace -r '.*?(\d+).*? type \'(.*?)\'.*?file name \'(.*?)\'' '$1:\t$3 ($2)'
end
end
end
function __fish_mkvextract_print_tracks
if set -l matroska (__fish_mkvextract_find_matroska_in_args)
if set -l info (mkvmerge -i $matroska)
string match 'Track ID*' -- $info | string replace -r '.*?(\d+): (.*)' '$1:\t$2'
end
end
end
# simple options
complete -f -c mkvextract -s V -l "version" -d "Show version information"
complete -f -c mkvextract -s h -l "help" -d "Show help"
# commands
complete -f -c mkvextract -n "test (count (commandline -opc)) -lt 2" -a "tracks" -d "Extract tracks to external files"
complete -f -c mkvextract -n "test (count (commandline -opc)) -lt 2" -a "tags" -d "Extract tags as XML"
complete -f -c mkvextract -n "test (count (commandline -opc)) -lt 2" -a "attachments" -d "Extract attachments"
complete -f -c mkvextract -n "test (count (commandline -opc)) -lt 2" -a "chapters" -d "Extract chapters as XML"
complete -f -c mkvextract -n "test (count (commandline -opc)) -lt 2" -a "cuesheet" -d "Extract chapters and tags as CUE sheet"
complete -f -c mkvextract -n "test (count (commandline -opc)) -lt 2" -a "timecodes_v2" -d "Extract timecodes of a track as timecode v2 file"
complete -f -c mkvextract -n "test (count (commandline -opc)) -lt 2" -a "cues" -d "Extract cue information as text file"
# dynamic tracks and attachments completions
complete -f -c mkvextract -n "__fish_seen_subcommand_from tracks timecodes_v2 cues" -a "(__fish_mkvextract_print_tracks)"
complete -f -c mkvextract -n "__fish_seen_subcommand_from attachments" -a "(__fish_mkvextract_print_attachments)"
# options common to all commands
complete -f -c mkvextract -n "test (count (commandline -opc)) -ge 2" -s f -l "parse-fully" -d "Parse the whole file instead of relying on the index"
complete -f -c mkvextract -n "test (count (commandline -opc)) -ge 2" -s v -l "verbose" -d "Increase verbosity"
complete -f -c mkvextract -n "test (count (commandline -opc)) -ge 2" -s q -l "quiet" -d "Suppress status output"
complete -f -c mkvextract -n "test (count (commandline -opc)) -ge 2" -r -l "ui-language" -d "Force the translations for 'code' to be used"
complete -f -c mkvextract -n "test (count (commandline -opc)) -ge 2" -r -l "command-line-charset" -d "Charset for strings on the command line"
complete -f -c mkvextract -n "test (count (commandline -opc)) -ge 2" -r -l "output-charset" -d "Outputs messages in specified charset"
complete -f -c mkvextract -n "test (count (commandline -opc)) -ge 2" -r -s r -l "redirect-output" -d "Redirect all messages into a file"
# command-specific options
complete -f -c mkvextract -n "__fish_seen_subcommand_from tracks" -r -s c -d "Convert text subtitles to a charset"
complete -f -c mkvextract -n "__fish_seen_subcommand_from tracks" -l "cuesheet" -d "Also try to extract the CUE sheet"
complete -f -c mkvextract -n "__fish_seen_subcommand_from tracks" -r -l "blockadd" -d "Keep only the BlockAdditions up to the specified level"
complete -f -c mkvextract -n "__fish_seen_subcommand_from tracks" -l "raw" -d "Extract the data to a raw file"
complete -f -c mkvextract -n "__fish_seen_subcommand_from tracks" -l "fullraw" -d "Extract the data to a raw file including the CodecPrivate as header"
complete -f -c mkvextract -n "__fish_seen_subcommand_from chapters" -s s -l "simple" -d "Exports the chapter information in a simple format"
complete -f -c mkvextract -n "__fish_seen_subcommand_from chapters" -r -l "simple-language" -d "Uses the chapter names of the specified language"

View File

@@ -0,0 +1,12 @@
# completion for nvram (macOS)
function __fish_nvram_variables
command nvram -p
end
complete -c nvram -s x -f -d 'Use XML format for reading and writing variables'
complete -c nvram -s p -f -d 'Print all of the firmware variables'
complete -c nvram -s f -r -d 'Set firmware variables from a text file'
complete -c nvram -s d -x -a '(__fish_nvram_variables)' -d 'Deletes the named firmware variable'
complete -c nvram -s c -f -d 'Delete all of the firmware variable'
complete -c nvram -x -a '(__fish_nvram_variables)'

View File

@@ -1,14 +1,25 @@
# Note that when a completion file is sourced a new block scope is created so `set -l` works.
set -l __fish_status_all_commands is-login is-interactive is-block is-command-substitution is-no-job-control is-interactive-job-control is-full-job-control current-filename current-line-number print-stack-trace job-control
# These are the recognized flags.
complete -c status -s h -l help --description "Display help and exit"
complete -c status -l is-command-substitution --description "Test if a command substitution is currently evaluated"
complete -c status -l is-block --description "Test if a code block is currently evaluated"
complete -c status -l is-interactive --description "Test if this is an interactive shell"
complete -c status -l is-login --description "Test if this is a login shell"
complete -c status -l is-full-job-control --description "Test if all new jobs are put under job control"
complete -c status -l is-interactive-job-control --description "Test if only interactive new jobs are put under job control"
complete -c status -l is-no-job-control --description "Test if new jobs are never put under job control"
complete -c status -s j -l job-control -xa "full interactive none" --description "Set which jobs are out under job control"
complete -c status -s t -l print-stack-trace --description "Print a list of all function calls leading up to running the current command"
complete -c status -s f -l current-filename --description "Print the filename of the currently running script"
complete -c status -s n -l current-line-number --description "Print the line number of the currently running script"
complete -c status -s t -l print-stack-trace --description "Prints a trace of all function calls on the stack"
# The "is-something" subcommands.
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a is-login -d "Test if this is a login shell"
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a is-interactive -d "Test if this is an interactive shell"
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a is-command-substitution -d "Test if a command substitution is currently evaluated"
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a is-block -d "Test if a code block is currently evaluated"
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a is-no-job-control -d "Test if new jobs are never put under job control"
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a is-interactive-job-control -d "Test if only interactive new jobs are put under job control"
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a is-full-job-control -d "Test if all new jobs are put under job control"
# The subcommands that are not "is-something" which don't change the fish state.
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a current-filename -d "Print the filename of the currently running script"
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a current-line-number -d "Print the line number of the currently running script"
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a print-stack-trace -d "Print a list of all function calls leading up to running the current command"
# The job-control command changes fish state.
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a job-control -d "Set which jobs are under job control"
complete -f -c status -n "__fish_seen_subcommand_from job-control" -a full -d "Set all jobs under job control"
complete -f -c status -n "__fish_seen_subcommand_from job-control" -a interactive -d "Set only interactive jobs under job control"
complete -f -c status -n "__fish_seen_subcommand_from job-control" -a none -d "Set no jobs under job control"

View File

@@ -165,7 +165,7 @@ for cmd in $blame $diff $log $merge
_svn_cmpl_ $cmd -l extensions -s x -d 'Ignore changes in amount of whitespace' -xa '-b --ignore-space-change'
_svn_cmpl_ $cmd -l extensions -s x -d 'Ignore all whitespace' -xa '-w --ignore-all-space'
_svn_cmpl_ $cmd -l extensions -s x -d 'Ignore eol style' -xa '-w --ignore-eol-style'
_svn_cmpl_ $cmd -l extensions -s x -d 'Show C function name' -xa '-p --shoe-c-function'
_svn_cmpl_ $cmd -l extensions -s x -d 'Show C function name' -xa '-p --show-c-function'
# Next completion doesn't work, since fish doesn't respect -x key
#_svn_cmpl_ $cmd -l extensions -n '__fish_seen_subcommand_from --diff-cmd' -xa '(__fish_complete_svn_diff)'

View File

@@ -0,0 +1,111 @@
### Auto-complete for sysbench (cross-platform and multi-threaded benchmark tool) ###
### sub commands specification ###
complete -c sysbench -f -a "run\t'Run the test'"
complete -c sysbench -n "__fish_contains_opt test=fileio" -a "
prepare\t'Prepare and create test file'
cleanup\t'Cleanup test files'
"
complete -c sysbench -n "__fish_contains_opt test=oltp" -a "
prepare\t'Prepare test table'
cleanup\t'Cleanup test table'
"
### generic long options specification ###
complete -c sysbench -x -l num-threads -d 'The total number of worker threads to create (default: 1)'
complete -c sysbench -x -l max-requests -d 'Limit for total number of requests. 0 means unlimited (default: 10000)'
complete -c sysbench -x -l max-time -d 'Limit for total execution time in seconds. 0 means unlimited (default: 0)'
complete -c sysbench -x -l thread-stack-size -d 'Size of stack for each thread (defaut: 32K)'
complete -c sysbench -f -l init-rng -d 'Specifies if random numbers generator should be initialized from timer (defaut: off)' -a 'on off'
complete -c sysbench -x -l test -d 'Name of the test mode to run(required)' -a "
cpu\t'Benchmark cpu by calculating prime numbers'
threads\t'Benchmark scheduler performance'
mutex\t'Benchmark mutex implementation'
fileio\t'Benchmark various file I/O workloads'
oltp\t'Benchmark a real database performance'
"
complete -c sysbench -f -l debug -d 'Print more debug info (default: off)' -a 'on off'
complete -c sysbench -f -l validate -d 'Perform validation of test results where possible (default: off)' -a 'on off'
complete -c sysbench -l help -d 'Print help on general syntax'
complete -c sysbench -l version -d 'Show version of program'
complete -c sysbench -x -l percentile -d 'A percentile rank of query execution times to count (default: 95)'
complete -c sysbench -f -l batch -d 'Dump current results periodically (default: off)' -a 'on off'
complete -c sysbench -x -l batch-delay -d 'Delay between batch dumps in secods (default: 300)'
### options for test=`cpu` mode ###
complete -c sysbench -n "__fish_contains_opt test=cpu" -x -l cpu-max-prime -d 'Calculation of prime numbers up to the specified value'
### options for test=`threads` mode ###
complete -c sysbench -n "__fish_contains_opt test=threads" -x -l thread-yields -d 'Number of lock/yield/unlock loops to execute per each request (default: 1000)'
complete -c sysbench -n "__fish_contains_opt test=threads" -x -l thread-locks -d 'Number of mutexes to create (default: 8)'
### options for test=`mutex` mode ###
complete -c sysbench -n "__fish_contains_opt test=mutex" -x -l mutex-num -d 'Number of mutexes to create (default: 4096)'
complete -c sysbench -n "__fish_contains_opt test=mutex" -x -l memory-scope -d 'Specifies whether each thread uses a global or local allocation (default:global)' -a "
local\t'Allocate memory locally'
global\t'Allocate memory globally'
"
complete -c sysbench -n "__fish_contains_opt test=mutex" -x -l memory-total-size -d 'Total size of data to transfer (default: 100G)'
complete -c sysbench -n "__fish_contains_opt test=mutex" -x -l memory-oper -d 'Type of memory operations' -a 'read write'
### options for test=`fileio` mode ###
complete -c sysbench -n "__fish_contains_opt test=fileio" -x -l file-num -d 'Number of files to create (default: 128)'
complete -c sysbench -n "__fish_contains_opt test=fileio" -x -l file-block-size -d 'Block size to use in all I/O operations (default: 16K)'
complete -c sysbench -n "__fish_contains_opt test=fileio" -x -l file-total-size -d 'Total size of files (default: 2G)'
complete -c sysbench -n "__fish_contains_opt test=fileio" -x -l file-test-mode -d 'Type of workload to produce' -a "
seqwr\t'Sequential write'
seqrewr\t'Sequential rewrite'
seqrd\t'Sequential read'
rndrd\t'Random read'
rndwr\t'Random write'
rndrw\t'Random read/write'
"
complete -c sysbench -n "__fish_contains_opt test=fileio" -x -l file-io-mode -d 'I/O mode (default: sync)' -a 'sync async fastmmap slowmmap'
complete -c sysbench -n "__fish_contains_opt test=fileio" -x -l file-async-backlog -d 'Number of asynchronous operations to queue per thread (default: 128)'
complete -c sysbench -n "__fish_contains_opt test=fileio" -x -l file-extra-flags -d 'Additional flags to use with open(2)'
complete -c sysbench -n "__fish_contains_opt test=fileio" -x -l file-fsync-freq -d 'Do fsync() after this number of requests (default: 0)'
complete -c sysbench -n "__fish_contains_opt test=fileio" -f -l file-fsync-all -d 'Do fsync() after each write operation (default: no)' -a 'yes no'
complete -c sysbench -n "__fish_contains_opt test=fileio" -f -l file-fsync-end -d 'Do fsync() at the end of the test (default: yes)' -a 'yes no'
complete -c sysbench -n "__fish_contains_opt test=fileio" -x -l file-fsync-mode -d 'Method used for synchronization: fsync, fdatasync (default: fsync)' -a 'fsync fdatasync'
complete -c sysbench -n "__fish_contains_opt test=fileio" -x -l file-merged-requests -d 'Upper limit of I/O requests merge (default: 0)'
complete -c sysbench -n "__fish_contains_opt test=fileio" -x -l file-rw-ratio -d 'reads/writes ratio for combined random read/write test (default: 1.5)'
### options for test=`oltp` mode ###
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-test-mode -d 'Execution mode: simple, complex and nontrx(non-transactional)(default: complex)' -a "
simple\t'Simple'
complex\t'Advanced transactional'
nontrx\t'Non-transactional'
"
complete -c sysbench -n "__fish_contains_opt test=oltp" -f -l oltp-read-only -d 'Read-only mode. No UPDATE, DELETE or INSERT queries will be performed. (default: off)' -a 'on off'
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-range-size -d 'Range size for range queries (default: 100)'
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-point-selects -d 'Number of point select queries in a single transaction (default: 10)'
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-simple-ranges -d 'Number of simple range queries in a single transaction (default: 1)'
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-sum-ranges -d 'Number of SUM range queries in a single transaction (default: 1)'
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-order-ranges -d 'Number of ORDER range queries in a single transaction (default: 1)'
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-distinct-ranges -d 'Number of DISTINCT range queries in a single transaction (default: 1)'
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-index-updates -d 'Number of index UPDATE queries in a single transaction (default: 1)'
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-non-index-updates -d 'Number of non-index UPDATE queries in a single transaction (default: 1)'
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-nontrx-mode -d 'Type of queries for non-transactional execution mode (default: select)' -a 'select update_key update_nokey insert delete'
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-connect-delay -d 'Time to sleep(in microseconds) after each connection to database (default: 10000)'
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-user-delay-min -d 'Minimum time to sleep(in microseconds) after each request (default: 0)'
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-user-delay-max -d 'Maximum time to sleep(in microseconds) after each request (default: 0)'
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-table-name -d 'Name of the test table (default: sbtest)'
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-table-size -d 'Number of rows in the test table (default: 10000)'
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l oltp-dist-type -d 'Distribution type of random numbers (default: special)' -a "
uniform\t'Uniform distribution'
gauss\t'Gaussian distribution'
special\t'Specified percent of numbers is generated in a specified percent of cases'
"
complete -c sysbench -n "__fish_contains_opt oltp-dist-type=special" -x -l oltp-dist-pct -d 'Percentage of values to be treated as \'special\'(default: 1)'
complete -c sysbench -n "__fish_contains_opt oltp-dist-type=special" -x -l oltp-dist-res -d 'Percentage of cases when \'special\' values are generated (default: 75)'
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l db-ps-mode -d 'Use "Prepared Statements" API if supported, otherwise - use clientside statements: disable, auto (default: auto)' -a 'disable auto'
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l mysql-host -d 'MySQL server host (default: localhost)' -a "(__fish_print_hostnames)"
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l mysql-port -d 'MySQL server port (default: 3306)'
complete -c sysbench -n "__fish_contains_opt test=oltp" -l mysql-socket -d 'Unix socket file to communicate with the MySQL server'
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l mysql-user -d 'MySQL user (default: sbtest)'
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l mysql-password -d 'MySQL password'
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l mysql-db -d 'MySQL database name (default: sbtest)'
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l mysql-table-engine -d 'Type of the test table to use' -a 'myisam innodb heap ndbcluster bdb maria falcon pbxt'
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l mysql-ssl -d 'Use SSL connections. (default: no)' -a 'yes no'
complete -c sysbench -n "__fish_contains_opt test=oltp" -x -l myisam-max-rows -d 'MAX_ROWS option for MyISAM tables (required for big tables) (default: 1000000)'
complete -c sysbench -n "__fish_contains_opt test=oltp" -l mysql-create-options -d 'Additional options passed to CREATE TABLE.'

View File

@@ -3,7 +3,7 @@ if type -q -f sysctl
if sysctl -h >/dev/null ^/dev/null
# Print sysctl keys and values, separated by a tab
function __fish_sysctl_values
sysctl -a ^/dev/null | string replace -a " = " "\t"
sysctl -a ^/dev/null | string replace -a " = " \t
end
complete -c sysctl -a '(__fish_sysctl_values)' -f
@@ -32,7 +32,7 @@ if type -q -f sysctl
else
# OSX sysctl
function __fish_sysctl_values
sysctl -a ^/dev/null | string replace -a ":" "\t"
sysctl -a ^/dev/null | string replace -a ":" \t
end
complete -c sysctl -a '(__fish_sysctl_values)' -f

View File

@@ -0,0 +1,56 @@
# completion for tmutil (macOS)
complete -f -c tmutil -n '__fish_use_subcommand' -a addexclusion -d 'Add an exclusion not to back up a file'
complete -f -c tmutil -n '__fish_seen_subcommand_from addexclusion' -s v -d 'Volume exclusion'
complete -f -c tmutil -n '__fish_seen_subcommand_from addexclusion' -s p -d 'Path exclusion'
complete -r -c tmutil -n '__fish_use_subcommand' -a associatedisk -d 'Bind a snapshot volume directory to the specified local disk'
complete -r -c tmutil -n '__fish_use_subcommand' -a calculatedrift -d 'Determine the amount of change between snapshots'
complete -r -c tmutil -n '__fish_use_subcommand' -a compare -d 'Perform a backup diff'
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s a -d 'Compare all supported metadata'
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s n -d 'No metadata comparison'
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s @ -d 'Compare extended attributes'
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s c -d 'Compare creation times'
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s d -d 'Compare file data forks'
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s e -d 'Compare ACLs'
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s f -d 'Compare file flags'
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s g -d 'Compare GIDs'
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s m -d 'Compare file modes'
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s s -d 'Compare sizes'
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s t -d 'Compare modification times'
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s u -d 'Compare UIDs'
complete -r -c tmutil -n '__fish_seen_subcommand_from compare' -s D -d 'Limit traversal depth to depth levels from the beginning of iteration'
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s E -d 'Dont take exclusions into account'
complete -r -c tmutil -n '__fish_seen_subcommand_from compare' -s I -d 'Ignore path'
complete -f -c tmutil -n '__fish_seen_subcommand_from compare' -s U -d 'Ignore logical volume identity'
complete -r -c tmutil -n '__fish_use_subcommand' -a delete -d 'Delete one or more snapshots'
complete -f -c tmutil -n '__fish_use_subcommand' -a destinationinfo -d 'Print information about destinations'
complete -f -c tmutil -n '__fish_use_subcommand' -a disable -d 'Turn off automatic backups'
complete -f -c tmutil -n '__fish_use_subcommand' -a disablelocal -d 'Turn off local Time Machine snapshots'
complete -f -c tmutil -n '__fish_use_subcommand' -a enable -d 'Turn on automatic backups'
complete -f -c tmutil -n '__fish_use_subcommand' -a enablelocal -d 'Turn on local Time Machine snapshots'
complete -r -c tmutil -n '__fish_use_subcommand' -a inheritbackup -d 'Claim a machine directory or sparsebundle for use by the current machine'
complete -f -c tmutil -n '__fish_use_subcommand' -a isexcluded -d 'Determine if a file, directory, or volume are excluded from backups'
complete -f -c tmutil -n '__fish_use_subcommand' -a latestbackup -d 'Print the path to the latest snapshot'
complete -f -c tmutil -n '__fish_use_subcommand' -a listbackups -d 'Print paths for all snapshots'
complete -f -c tmutil -n '__fish_use_subcommand' -a machinedirectory -d 'Print the path to the current machine directory'
complete -f -c tmutil -n '__fish_use_subcommand' -a removedestination -d 'Removes a backup destination'
complete -f -c tmutil -n '__fish_use_subcommand' -a removeexclusion -d 'Remove an exclusion'
complete -f -c tmutil -n '__fish_seen_subcommand_from removeexclusion' -s v -d 'Volume exclusion'
complete -f -c tmutil -n '__fish_seen_subcommand_from removeexclusion' -s p -d 'Path exclusion'
complete -f -c tmutil -n '__fish_use_subcommand' -a restore -d 'Restore an item'
complete -r -c tmutil -n '__fish_seen_subcommand_from restore' -s v
complete -r -c tmutil -n '__fish_use_subcommand' -a setdestination -d 'Set a backup destination'
complete -f -c tmutil -n '__fish_seen_subcommand_from setdestination' -s a -d 'Add to the list of destinations'
complete -f -c tmutil -n '__fish_seen_subcommand_from setdestination' -s p -d 'Enter the password at a non-echoing interactive prompt'
complete -f -c tmutil -n '__fish_use_subcommand' -a snapshot -d 'Create new local Time Machine snapshot'
complete -f -c tmutil -n '__fish_use_subcommand' -a startbackup -d 'Begin a backup if one is not already running'
complete -f -c tmutil -n '__fish_seen_subcommand_from startbackup' -s a -l auto -d 'Automatic mode'
complete -f -c tmutil -n '__fish_seen_subcommand_from startbackup' -s b -l block -d 'Block until finished'
complete -f -c tmutil -n '__fish_seen_subcommand_from startbackup' -s r -l rotation -d 'Autmatic rotation'
complete -r -c tmutil -n '__fish_seen_subcommand_from startbackup' -s d -l destination -d 'Backup destination'
complete -f -c tmutil -n '__fish_use_subcommand' -a stopbackup -d 'Cancel a backup currently in progress'
complete -r -c tmutil -n '__fish_use_subcommand' -a uniquesize -d 'Analyze the specified path and determine its unique size'
complete -r -c tmutil -n '__fish_use_subcommand' -a verifychecksums -d 'Verify snapshot'
complete -f -c tmutil -n '__fish_use_subcommand' -a version -d 'Print version'
complete -f -c tmutil -n '__fish_seen_subcommand_from destinationinfo isexcluded compare' -s X -d 'Print as XML'

View File

@@ -220,13 +220,18 @@ function __fish_config_interactive -d "Initializations that should be performed
# Notify terminals when $PWD changes (issue #906)
# VTE and Terminal.app support this in practice.
if test "0$VTE_VERSION" -ge 3405 -o "$TERM_PROGRAM" = "Apple_Terminal"
function fish_title; end
function __update_cwd_osc --on-variable PWD --description 'Notify capable terminals when $PWD changes'
status --is-command-substitution
or test -n "$INSIDE_EMACS"
and return
printf \e\]7\;file://\%s\%s\a (hostname) (echo -n $PWD | __fish_urlencode)
end
if test "$TERM_PROGRAM" = "Apple_Terminal"
# Suppress duplicative title display on Terminal.app
echo -n \e\]0\;\a # clear existing title
function fish_title
end
end
__update_cwd_osc # Run once because we might have already inherited a PWD from an old tab
end

View File

@@ -39,10 +39,11 @@ function __fish_print_help --description "Print help message for the specified f
set cols (math $cols - 4) # leave a bit of space on the right
set rLL -rLL=$cols[1]n
end
set -lx GROFF_TMAC_PATH $__fish_datadir/groff
if test -e "$__fish_datadir/man/man1/$item.1"
set help (nroff -man -c -t $rLL "$__fish_datadir/man/man1/$item.1" ^/dev/null)
set help (nroff -c -man -mfish -t $rLL "$__fish_datadir/man/man1/$item.1" ^/dev/null)
else if test -e "$__fish_datadir/man/man1/$item.1.gz"
set help (gunzip -c "$__fish_datadir/man/man1/$item.1.gz" ^/dev/null | nroff -man -c -t $rLL ^/dev/null)
set help (gunzip -c "$__fish_datadir/man/man1/$item.1.gz" ^/dev/null | nroff -c -man -mfish -t $rLL ^/dev/null)
end
# The original implementation trimmed off the top 5 lines and bottom 3 lines

View File

@@ -3,7 +3,14 @@ function __fish_shared_key_bindings -d "Bindings shared between emacs and vi mod
# They are supposed to be unrelated to text-editing (or movement).
# This takes $argv so the vi-bindings can pass the mode they are valid in.
if contains -- -h $argv
or contains -- --help $argv
echo "Sorry but this function doesn't support -h or --help"
return 1
end
bind $argv \cy yank
or return # protect against invalid $argv
bind $argv \ey yank-pop
# Left/Right arrow
@@ -81,10 +88,11 @@ function __fish_shared_key_bindings -d "Bindings shared between emacs and vi mod
bind $argv -k f1 __fish_man_page
bind $argv \eh __fish_man_page
# This will make sure the output of the current command is paged using the default pager when you press Meta-p.
# This will make sure the output of the current command is paged using the default pager when
# you press Meta-p.
# If none is set, less will be used.
bind $argv \ep '__fish_paginate'
# Make it easy to turn an unexecuted command into a comment in the shell history. Also,
# remove the commenting chars so the command can be further edited then executed.
bind $argv \e\# __fish_toggle_comment_commandline

View File

@@ -1,4 +1,4 @@
function alias --description 'Legacy function for creating shellscript functions using an alias-like syntax'
function alias --description 'Creates a function wrapping a command'
if count $argv > /dev/null
switch $argv[1]
case -h --h --he --hel --help
@@ -14,8 +14,12 @@ function alias --description 'Legacy function for creating shellscript functions
switch (count $argv)
case 0
echo "Fish implements aliases using functions. Use 'functions' builtin to see list of functions and 'functions function_name' to see function definition, type 'help alias' for more information."
return 1
for func in (functions -n)
set -l output (functions $func | string match -r -- "function .* --description '(alias .*)'" | string split \n)
set -q output[2]
and echo $output[2]
end
return 0
case 1
set -l tmp (string replace -r "=" '\n' -- $argv) ""
set name $tmp[1]
@@ -60,5 +64,6 @@ function alias --description 'Legacy function for creating shellscript functions
set prefix command
end
end
echo "function $name --wraps $first_word; $prefix $first_word $body \$argv; end" | source
set -l cmd_string (string escape "alias $argv")
echo "function $name --wraps $first_word --description $cmd_string; $prefix $first_word $body \$argv; end" | source
end

View File

@@ -1,86 +1,95 @@
function fish_default_key_bindings -d "Default (Emacs-like) key bindings for fish"
if not set -q argv[1]
# Clear earlier bindings, if any
bind --erase --all
if test "$fish_key_bindings" != "fish_default_key_bindings"
# Allow the user to set the variable universally
set -q fish_key_bindings; or set -g fish_key_bindings
set fish_key_bindings fish_default_key_bindings # This triggers the handler, which calls us again and ensures the user_key_bindings are executed
return
end
end
if contains -- -h $argv
or contains -- --help $argv
echo "Sorry but this function doesn't support -h or --help"
return 1
end
if not set -q argv[1]
bind --erase --all # clear earlier bindings, if any
if test "$fish_key_bindings" != "fish_default_key_bindings"
# Allow the user to set the variable universally
set -q fish_key_bindings
or set -g fish_key_bindings
# This triggers the handler, which calls us again and ensures the user_key_bindings
# are executed.
set fish_key_bindings fish_default_key_bindings
return
end
end
# These are shell-specific bindings that we share with vi mode.
__fish_shared_key_bindings $argv
or return # protect against invalid $argv
# This is the default binding, i.e. the one used if no other binding matches
bind $argv "" self-insert
# This is the default binding, i.e. the one used if no other binding matches
bind $argv "" self-insert
or exit # protect against invalid $argv
bind $argv \n execute
bind $argv \r execute
bind $argv \n execute
bind $argv \r execute
bind $argv \ck kill-line
bind $argv \ck kill-line
bind $argv \eOC forward-char
bind $argv \eOD backward-char
bind $argv \e\[C forward-char
bind $argv \e\[D backward-char
bind $argv -k right forward-char
bind $argv -k left backward-char
bind $argv \eOC forward-char
bind $argv \eOD backward-char
bind $argv \e\[C forward-char
bind $argv \e\[D backward-char
bind $argv -k right forward-char
bind $argv -k left backward-char
bind $argv -k dc delete-char
bind $argv -k backspace backward-delete-char
bind $argv \x7f backward-delete-char
bind $argv -k dc delete-char
bind $argv -k backspace backward-delete-char
bind $argv \x7f backward-delete-char
# for PuTTY
# https://github.com/fish-shell/fish-shell/issues/180
bind $argv \e\[1~ beginning-of-line
bind $argv \e\[3~ delete-char
bind $argv \e\[4~ end-of-line
# for PuTTY
# https://github.com/fish-shell/fish-shell/issues/180
bind $argv \e\[1~ beginning-of-line
bind $argv \e\[3~ delete-char
bind $argv \e\[4~ end-of-line
# OS X SnowLeopard doesn't have these keys. Don't show an annoying error message.
bind $argv -k home beginning-of-line 2> /dev/null
bind $argv -k end end-of-line 2> /dev/null
bind $argv \e\[3\;2~ backward-delete-char # Mavericks Terminal.app shift-delete
# OS X SnowLeopard doesn't have these keys. Don't show an annoying error message.
bind $argv -k home beginning-of-line 2>/dev/null
bind $argv -k end end-of-line 2>/dev/null
bind $argv \e\[3\;2~ backward-delete-char # Mavericks Terminal.app shift-delete
bind $argv \ca beginning-of-line
bind $argv \ce end-of-line
bind $argv \ch backward-delete-char
bind $argv \cp up-or-search
bind $argv \cn down-or-search
bind $argv \cf forward-char
bind $argv \cb backward-char
bind $argv \ct transpose-chars
bind $argv \et transpose-words
bind $argv \eu upcase-word
bind $argv \ca beginning-of-line
bind $argv \ce end-of-line
bind $argv \ch backward-delete-char
bind $argv \cp up-or-search
bind $argv \cn down-or-search
bind $argv \cf forward-char
bind $argv \cb backward-char
bind $argv \ct transpose-chars
bind $argv \et transpose-words
bind $argv \eu upcase-word
# This clashes with __fish_list_current_token
# bind $argv \el downcase-word
bind $argv \ec capitalize-word
bind $argv \e\x7f backward-kill-word
bind $argv \eb backward-word
bind $argv \ef forward-word
bind $argv \e\[1\;5C forward-word
bind $argv \e\[1\;5D backward-word
bind $argv -k ppage beginning-of-history
bind $argv -k npage end-of-history
bind $argv \e\< beginning-of-buffer
bind $argv \e\> end-of-buffer
# This clashes with __fish_list_current_token
# bind $argv \el downcase-word
bind $argv \ec capitalize-word
bind $argv \e\x7f backward-kill-word
bind $argv \eb backward-word
bind $argv \ef forward-word
bind $argv \e\[1\;5C forward-word
bind $argv \e\[1\;5D backward-word
bind $argv -k ppage beginning-of-history
bind $argv -k npage end-of-history
bind $argv \e\< beginning-of-buffer
bind $argv \e\> end-of-buffer
bind \ed forward-kill-word
bind \ed kill-word
bind \ed forward-kill-word
bind \ed kill-word
# Ignore some known-bad control sequences
# https://github.com/fish-shell/fish-shell/issues/1917
bind \e\[I 'begin;end'
bind \e\[O 'begin;end'
# Ignore some known-bad control sequences
# https://github.com/fish-shell/fish-shell/issues/1917
bind \e\[I 'begin;end'
bind \e\[O 'begin;end'
# term-specific special bindings
switch "$TERM"
case 'rxvt*'
bind $argv \e\[8~ end-of-line
bind $argv \eOc forward-word
bind $argv \eOd backward-word
end
# term-specific special bindings
switch "$TERM"
case 'rxvt*'
bind $argv \e\[8~ end-of-line
bind $argv \eOc forward-word
bind $argv \eOd backward-word
end
end

View File

@@ -3,11 +3,6 @@
# Set the default prompt command.
function fish_fallback_prompt --description "A simple fallback prompt without too much color or special characters for linux VTs"
# Just calculate this once, to save a few cycles when displaying the prompt
if not set -q __fish_prompt_hostname
set -g __fish_prompt_hostname (hostname|cut -d . -f 1)
end
set -l color_cwd
set -l suffix
switch $USER
@@ -23,5 +18,5 @@ function fish_fallback_prompt --description "A simple fallback prompt without to
set suffix '>'
end
echo -n -s "$USER" @ "$__fish_prompt_hostname" ' ' (set_color $color_cwd) (prompt_pwd) (set_color normal) "$suffix "
echo -n -s "$USER" @ (prompt_hostname) ' ' (set_color $color_cwd) (prompt_pwd) (set_color normal) "$suffix "
end

View File

@@ -0,0 +1,18 @@
function fish_hybrid_key_bindings --description "Vi-style bindings that inherit emacs-style bindings in all modes"
bind --erase --all # clear earlier bindings, if any
if test "$fish_key_bindings" != "fish_hybrid_key_bindings"
# Allow the user to set the variable universally
set -q fish_key_bindings
or set -g fish_key_bindings
# This triggers the handler, which calls us again and ensures the user_key_bindings
# are executed.
set fish_key_bindings fish_hybrid_key_bindings
return
end
for mode in default insert visual
fish_default_key_bindings -M $mode
end
fish_vi_key_bindings --no-erase
end

View File

@@ -0,0 +1,7 @@
# check if command fish_key_reader works and is the same version that
# came with this fish. This will happen one time.
command -s fish_key_reader > /dev/null
and command fish_key_reader --version 2>&1 | string match -rq $FISH_VERSION
# if alias doesn't define the function here, this is an autoloaded "nothing".
# the command (if there is one) will be used by default.
or alias fish_key_reader=(string escape $__fish_bin_dir/fish_key_reader)

View File

@@ -2,6 +2,7 @@
function fish_mode_prompt --description "Displays the current mode"
# Do nothing if not in vi mode
if test "$fish_key_bindings" = "fish_vi_key_bindings"
or test "$fish_key_bindings" = "fish_hybrid_key_bindings"
switch $fish_bind_mode
case default
set_color --bold --background red white

View File

@@ -3,11 +3,6 @@
# Set the default prompt command.
function fish_prompt --description "Write out the prompt"
# Just calculate this once, to save a few cycles when displaying the prompt
if not set -q __fish_prompt_hostname
set -g __fish_prompt_hostname (hostname|cut -d . -f 1)
end
set -l color_cwd
set -l suffix
switch $USER
@@ -23,5 +18,5 @@ function fish_prompt --description "Write out the prompt"
set suffix '>'
end
echo -n -s "$USER" @ "$__fish_prompt_hostname" ' ' (set_color $color_cwd) (prompt_pwd) (set_color normal) "$suffix "
echo -n -s "$USER" @ (prompt_hostname) ' ' (set_color $color_cwd) (prompt_pwd) (set_color normal) "$suffix "
end

View File

@@ -1,11 +1,63 @@
function fish_vi_cursor -d 'Set cursor shape for different vi modes'
# Since we read exported variables (KONSOLE_PROFILE_NAME and ITERM_PROFILE)
# we need to check harder if we're actually in a supported terminal,
# because we might be in a term-in-a-term (emacs ansi-term).
if not contains -- $TERM xterm konsole xterm-256color konsole-256color
and not set -q TMUX
# Check hard if we are in a supporting terminal.
#
# Challenges here are term-in-a-terms (emacs ansi-term does not support this, tmux does),
# that we can only figure out if we are in konsole/iterm/vte via exported variables,
# and ancient xterm versions.
#
# tmux defaults to $TERM = screen, but can do this if it is in a supporting terminal.
# Unfortunately, we can only detect this via the exported variables, so we miss some cases.
#
# We will also miss some cases of terminal-stacking,
# e.g. tmux started in suckless' st (no support) started in konsole.
# But since tmux in konsole seems rather common and that case so uncommon,
# we will just fail there (though it seems that tmux or st swallow it anyway).
#
# We use the `tput` here just to see if terminfo thinks we can change the cursor.
# We cannot use that sequence directly as it's not the correct one for konsole and iTerm,
# and because we may want to change the cursor even though terminfo says we can't (tmux).
if not tput Ss > /dev/null ^/dev/null
# Whitelist tmux...
and not begin
set -q TMUX
# ...in a supporting term...
and begin set -q KONSOLE_PROFILE_NAME
or set -q ITERM_PROFILE
or test "$VTE_VERSION" -ge 4000
or test (string replace -r "XTerm\((\d+)\)" '$1' -- $XTERM_VERSION) -ge 280
end
# .. unless an unsupporting terminal has been started in tmux inside a supporting one
and begin string match -q "screen*" -- $TERM
or string match -q "tmux*" -- $TERM
end
end
and not string match -q "konsole*" -- $TERM
# Blacklist
or begin
# vte-based terms set $TERM = xterm*, but only gained support relatively recently.
# From https://bugzilla.gnome.org/show_bug.cgi?id=720821, it appears it was version 0.40.0
set -q VTE_VERSION
and test "$VTE_VERSION" -lt 4000
end
or set -q INSIDE_EMACS
or begin
# TERM = xterm is special because plenty of things claim to be it, but aren't fully compatible
# This includes old vte-terms (without $VTE_VERSION), old xterms (without $XTERM_VERSION or < 280)
# and maybe other stuff.
# This needs to be kept _at least_ as long as Ubuntu 14.04 is still a thing
# because that ships a gnome-terminal without support and without $VTE_VERSION.
string match -q 'xterm*' -- $TERM
and not begin set -q KONSOLE_PROFILE_NAME
or set -q ITERM_PROFILE
or test "$VTE_VERSION" -ge 4000
# If $XTERM_VERSION is undefined, this will return 1 and print an error. Silence it.
or test (string replace -r "XTerm\((\d+)\)" '$1' -- $XTERM_VERSION) -ge 280 ^/dev/null
end
end
return
end
set -l terminal $argv[1]
set -q terminal[1]
or set terminal auto
@@ -18,11 +70,9 @@ function fish_vi_cursor -d 'Set cursor shape for different vi modes'
or set -q ITERM_PROFILE
set function __fish_cursor_konsole
set uses_echo 1
else if string match -q "xterm*" -- $TERM; or test "$VTE_VERSION" -gt 1910
else
set function __fish_cursor_xterm
set uses_echo 1
else
return 1
end
case konsole
set function __fish_cursor_konsole

View File

@@ -1,29 +1,41 @@
function fish_vi_key_bindings --description 'vi-like key bindings for fish'
if contains -- -h $argv
or contains -- --help $argv
echo "Sorry but this function doesn't support -h or --help"
return 1
end
# Erase all bindings if not explicitly requested otherwise to
# allow for hybrid bindings.
# This needs to be checked here because if we are called again
# via the variable handler the argument will be gone.
if not contains -- $argv[1] --no-erase
bind --erase --all
else if set -q argv[1]
set -l rebind true
if test "$argv[1]" = "--no-erase"
set rebind false
set -e argv[1]
else
bind --erase --all # clear earlier bindings, if any
end
# Allow just calling this function to correctly set the bindings.
# Because it's a rather discoverable name, users will execute it
# and without this would then have subtly broken bindings.
if test "$fish_key_bindings" != "fish_vi_key_bindings"
# Allow the user to set the variable universally
and test "$rebind" = "true"
# Allow the user to set the variable universally.
set -q fish_key_bindings
or set -g fish_key_bindings
set fish_key_bindings fish_vi_key_bindings # This triggers the handler, which calls us again and ensures the user_key_bindings are executed
# This triggers the handler, which calls us again and ensures the user_key_bindings
# are executed.
set fish_key_bindings fish_vi_key_bindings
return
end
# The default escape timeout is 300ms. But for users of Vi bindings that can be slightly
# annoying when trying to switch to Vi "normal" mode. So set a shorter timeout in this case
# unless the user has explicitly set the delay.
set -q fish_escape_delay_ms; or set -g fish_escape_delay_ms 100
set -q fish_escape_delay_ms
or set -g fish_escape_delay_ms 100
set -l init_mode insert
# These are only the special vi-style keys

View File

@@ -2,7 +2,6 @@ function help --description 'Show help for the fish shell'
# Declare variables to set correct scope
set -l fish_browser
set -l fish_browser_bg
set -l h syntax completion editor job-control todo bugs history killring help
set h $h color prompt title variables builtin-overview changes expand
@@ -23,58 +22,58 @@ function help --description 'Show help for the fish shell'
# by the help function defined below.
#
set -l graphical_browsers htmlview x-www-browser firefox galeon mozilla konqueror epiphany opera netscape rekonq google-chrome chromium-browser
set -l text_browsers htmlview www-browser links elinks lynx w3m
if type -q "$BROWSER"
# User has manually set a preferred browser, so we respect that
set fish_browser $BROWSER
# If browser is known to be graphical, put into background
if contains -- $BROWSER $graphical_browsers
set fish_browser_bg 1
end
if set -q fish_help_browser[1]
# User has set a fish-specific help browser. This overrides the
# browser that may be defined by $BROWSER. The fish_help_browser
# variable may be an array containing a browser name plus options.
set fish_browser $fish_help_browser
else
# Check for a text-based browser.
for i in $text_browsers
if type -q -f $i
set fish_browser $i
break
end
end
set -l text_browsers htmlview www-browser links elinks lynx w3m
# If we are in a graphical environment, check if there is a graphical
# browser to use instead.
if test "$DISPLAY" -a \( "$XAUTHORITY" = "$HOME/.Xauthority" -o "$XAUTHORITY" = "" \)
for i in $graphical_browsers
if set -q BROWSER
# User has manually set a preferred browser, so we respect that
set fish_browser $BROWSER
else
# Check for a text-based browser.
for i in $text_browsers
if type -q -f $i
set fish_browser $i
set fish_browser_bg 1
break
end
end
end
# If we are in a graphical environment, check if there is a graphical
# browser to use instead.
if test "$DISPLAY" -a \( "$XAUTHORITY" = "$HOME/.Xauthority" -o "$XAUTHORITY" = "" \)
for i in $graphical_browsers
if type -q -f $i
set fish_browser $i
break
end
end
end
# If the OS appears to be Windows (graphical), try to use cygstart
if type -q cygstart
set fish_browser cygstart
# If xdg-open is available, just use that
else if type -q xdg-open
set fish_browser xdg-open
end
# If the OS appears to be Windows (graphical), try to use cygstart
if type -q cygstart
set fish_browser cygstart
# If xdg-open is available, just use that
else if type -q xdg-open
set fish_browser xdg-open
end
# On OS X, we go through osascript by default
if test (uname) = Darwin
if type -q osascript
set fish_browser osascript
# On OS X, we go through osascript by default
if test (uname) = Darwin
if type -q osascript
set fish_browser osascript
end
end
end
end
if test -z $fish_browser
if not set -q fish_browser
printf (_ '%s: Could not find a web browser.\n') help
printf (_ 'Please set the variable $BROWSER to a suitable browser and try again.\n\n')
printf (_ 'Please set the variable $BROWSER or fish_help_browser and try again.\n\n')
return 1
end
@@ -136,17 +135,15 @@ function help --description 'Show help for the fish shell'
return
end
if test $fish_browser_bg
switch $fish_browser
# If browser is known to be graphical, put into background
if contains -- $fish_browser[1] $graphical_browsers
switch $fish_browser[1]
case 'htmlview' 'x-www-browser'
printf (_ 'help: Help is being displayed in your default browser.\n')
case '*'
printf (_ 'help: Help is being displayed in %s.\n') $fish_browser
printf (_ 'help: Help is being displayed in %s.\n') $fish_browser[1]
end
eval "$fish_browser $page_url &"
else
eval $fish_browser $page_url

View File

@@ -3,7 +3,7 @@
# application for the file.
#
if not test (uname) = Darwin
if not command -s open >/dev/null
function open --description "Open file in default application"
if count $argv >/dev/null
switch $argv[1]

View File

@@ -0,0 +1,10 @@
# Fetching the host name can be expensive if there is a problem with DNS or whatever subsystem the
# hostname command uses. So cache the answer so including it in the prompt doesn't make fish seem
# slow.
if not set -q __fish_prompt_hostname
set -g __fish_prompt_hostname (hostname | string split '.')[1]
end
function prompt_hostname
echo $__fish_prompt_hostname
end

View File

@@ -1,50 +1,53 @@
# Provide a minimalist realpath implementation to help deal with platforms that may not provide it
# as a command. If a realpath command is available simply pass all arguments thru to it. If not
# fallback to alternative solutions.
# as a command. If an external realpath or grealpath command is available simply pass all arguments
# thru to it. If not fallback to our builtin.
# The following is slightly subtle. The first time `realpath` is invoked by autoloading this script
# will be read. If we see that there is an external realpath command we just return. That will cause
# fish to run the external command. Or, if there is a grealpath, we alias it.
# On the other hand, if an external command isn't found we provide a function that will facilitate
# fallback behavion through our builtin.
# The following is slightly subtle. We have to define a realpath function even if there is an
# external command by that name. That's because if we don't the parser will select our builtin.
# However, we only want our builtin if there is no external realpath command.
if not command -s realpath >/dev/null
# If there is a HomeBrew installed version of GNU realpath named grealpath use that.
if command -s grealpath >/dev/null
function realpath -w grealpath -d "print the resolved path [grealpath]"
grealpath $argv
end
exit 0
if command -s realpath >/dev/null
function realpath -w realpath -d "print the resolved path [command realpath]"
command realpath $argv
end
exit 0
end
# If there is a HomeBrew installed version of GNU realpath named grealpath use that.
if command -s grealpath >/dev/null
function realpath -w grealpath -d "print the resolved path [command grealpath]"
command grealpath $argv
end
exit 0
end
function realpath -d "return an absolute path without symlinks"
if test -z "$argv"
printf "usage: %s%s%s %sfile%s …\n" (set_color -o) $_ (set_color normal) (set_color -u) (set_color normal)
echo " resolves files as absolute paths without symlinks"
return 1
end
function realpath -d "return an absolute path without symlinks"
if test -z "$argv"
printf "usage: %s%s%s %sfile%s …\n" (set_color -o) $_ (set_color normal) (set_color -u) (set_color normal)
echo " resolves files as absolute paths without symlinks"
return 1
end
# Loop over arguments - allow our realpath to work on more than one path per invocation
# like gnu/bsd realpath.
for arg in $argv
switch $arg
# These - no can do our realpath
case -s --strip --no-symlinks -z --zero --relative-base\* --relative-to\*
__fish_print_help realpath
return 2
# Loop over arguments - allow our realpath to work on more than one path per invocation
# like gnu/bsd realpath.
for arg in $argv
switch $arg
# These - no can do our realpath
case -s --strip --no-symlinks -z --zero --relative-base\* --relative-to\*
__fish_print_help realpath
return 2
case -h --help --version
__fish_print_help realpath
return 0
case -h --help --version
__fish_print_help realpath
return 0
# Handle commands called with these arguments by dropping the arguments to protect
# realpath from them. There are no sure things here.
case -e --canonicalize-existing --physical -P -q --quiet -m --canonicalize-missing
continue
case -e --canonicalize-existing --physical -P -q --quiet -m --canonicalize-missing
continue
case "*"
builtin realpath $arg
end
case "*"
builtin realpath $arg
end
end
end

View File

@@ -37,7 +37,7 @@ function vared --description "Edit variable value"
end
end
else
printf (_ '%s: %s is an array variable. Use %svared%s %s[n]%s to edit the n:th element of %s\n') vared $argv (set_color $fish_color_command; echo) (set_color $fish_color_normal; echo) $argv (set_color reset; echo) $argv
printf (_ '%s: %s is an array variable. Use %svared%s %s[n]%s to edit the n:th element of %s\n') vared $argv (set_color $fish_color_command; echo) (set_color $fish_color_normal; echo) $argv (set_color normal; echo) $argv
end
end
else

14
share/groff/fish.tmac Normal file
View File

@@ -0,0 +1,14 @@
.\" This is needed on systems that ship with groff versions older than 1.20;
.\" such as macOS up thru Sierra (10.12). See fish issue #2673.
.\"
.\" For UTF-8, map some characters conservatively for the sake
.\" of easy cut and paste.
.
.if '\*[.T]'utf8' \{\
. rchar \- - ' `
.
. char \- \N'45'
. char - \N'45'
. char ' \N'39'
. char ` \N'96'
.\}

View File

@@ -12,8 +12,8 @@ function fish_prompt -d "Write out the prompt"
if [ (_git_branch_name) ]
set -l git_branch (set_color -o blue)(_git_branch_name)
if [ (_is_git_dirty) ]
for i in (git branch -qv --no-color| string match -r \*|cut -d' ' -f4-|cut -d] -f1|tr , \n)\
(git status --porcelain | cut -c 1-2 | uniq)
for i in (git branch -qv --no-color | string match -r \* | cut -d' ' -f4- | cut -d] -f1 | tr , \n)\
(git status --porcelain | cut -c 1-2 | uniq)
switch $i
case "*[ahead *"
set git_status "$git_status"(set_color red)
@@ -39,29 +39,10 @@ function fish_prompt -d "Write out the prompt"
set git_info "(git$git_status$git_branch"(set_color white)")"
end
set_color -b black
printf '%s%s%s%s%s%s%s%s%s%s%s%s%s'\
(set_color -o white) \
'❰' \
(set_color green) \
$USER \
(set_color white) \
'❙' \
(set_color yellow) \
(echo $PWD | sed -e "s|^$HOME|~|") \
(set_color white) \
$git_info \
(set_color white) \
'❱' \
(set_color white)
printf '%s%s%s%s%s%s%s%s%s%s%s%s%s' (set_color -o white) '❰' (set_color green) $USER (set_color white) '❙' (set_color yellow) (echo $PWD | sed -e "s|^$HOME|~|") (set_color white) $git_info (set_color white) '❱' (set_color white)
if test $laststatus -eq 0
printf "%s✔%s≻%s " \
(set_color -o green)\
(set_color white) \
(set_color normal)
printf "%s✔%s≻%s " (set_color -o green) (set_color white) (set_color normal)
else
printf "%s✘%s≻%s " \
(set_color -o red) \
(set_color white) \
(set_color normal)
printf "%s✘%s≻%s " (set_color -o red) (set_color white) (set_color normal)
end
end

View File

@@ -1,24 +1,19 @@
# name: Classic
function fish_prompt --description "Write out the prompt"
# Just calculate this once, to save a few cycles when displaying the prompt
if not set -q __fish_prompt_hostname
set -g __fish_prompt_hostname (hostname|cut -d . -f 1)
end
set -l color_cwd
set -l suffix
switch $USER
case root toor
if set -q fish_color_cwd_root
set color_cwd $fish_color_cwd_root
else
set color_cwd $fish_color_cwd
end
set suffix '#'
case '*'
set color_cwd $fish_color_cwd
set suffix '>'
end
set -l color_cwd
set -l suffix
switch $USER
case root toor
if set -q fish_color_cwd_root
set color_cwd $fish_color_cwd_root
else
set color_cwd $fish_color_cwd
end
set suffix '#'
case '*'
set color_cwd $fish_color_cwd
set suffix '>'
end
echo -n -s "$USER" @ "$__fish_prompt_hostname" ' ' (set_color $color_cwd) (prompt_pwd) (set_color normal) "$suffix "
echo -n -s "$USER" @ (prompt_hostname) ' ' (set_color $color_cwd) (prompt_pwd) (set_color normal) "$suffix "
end

View File

@@ -10,25 +10,20 @@ function fish_prompt --description "Write out the prompt"
printf "%s(%d)%s " (set_color red --bold) $last_status (set_color normal)
end
# Just calculate this once, to save a few cycles when displaying the prompt
if not set -q __fish_prompt_hostname
set -g __fish_prompt_hostname (hostname|cut -d . -f 1)
end
set -l color_cwd
set -l suffix
switch $USER
case root toor
if set -q fish_color_cwd_root
set color_cwd $fish_color_cwd_root
else
case root toor
if set -q fish_color_cwd_root
set color_cwd $fish_color_cwd_root
else
set color_cwd $fish_color_cwd
end
set suffix '#'
case '*'
set color_cwd $fish_color_cwd
end
set suffix '#'
case '*'
set color_cwd $fish_color_cwd
set suffix '>'
set suffix '>'
end
echo -n -s "$USER" @ "$__fish_prompt_hostname" ' ' (set_color $color_cwd) (prompt_pwd) (set_color normal) "$suffix "
echo -n -s "$USER" @ (prompt_hostname) ' ' (set_color $color_cwd) (prompt_pwd) (set_color normal) "$suffix "
end

View File

@@ -3,71 +3,68 @@
# vim: set noet:
function fish_prompt --description 'Write out the prompt'
set -l last_status $status
set -l last_status $status
set -l normal (set_color normal)
# Just calculate this once, to save a few cycles when displaying the prompt
if not set -q __fish_prompt_hostname
set -g __fish_prompt_hostname (hostname|cut -d . -f 1)
end
# Hack; fish_config only copies the fish_prompt function (see #736)
if not set -q -g __fish_classic_git_functions_defined
set -g __fish_classic_git_functions_defined
set -l normal (set_color normal)
function __fish_repaint_user --on-variable fish_color_user --description "Event handler, repaint when fish_color_user changes"
if status --is-interactive
commandline -f repaint ^/dev/null
end
end
# Hack; fish_config only copies the fish_prompt function (see #736)
if not set -q -g __fish_classic_git_functions_defined
set -g __fish_classic_git_functions_defined
function __fish_repaint_host --on-variable fish_color_host --description "Event handler, repaint when fish_color_host changes"
if status --is-interactive
commandline -f repaint ^/dev/null
end
end
function __fish_repaint_user --on-variable fish_color_user --description "Event handler, repaint when fish_color_user changes"
if status --is-interactive
commandline -f repaint ^/dev/null
end
end
function __fish_repaint_host --on-variable fish_color_host --description "Event handler, repaint when fish_color_host changes"
if status --is-interactive
commandline -f repaint ^/dev/null
end
end
function __fish_repaint_status --on-variable fish_color_status --description "Event handler; repaint when fish_color_status changes"
if status --is-interactive
commandline -f repaint ^/dev/null
end
end
function __fish_repaint_status --on-variable fish_color_status --description "Event handler; repaint when fish_color_status changes"
if status --is-interactive
commandline -f repaint ^/dev/null
end
end
function __fish_repaint_bind_mode --on-variable fish_key_bindings --description "Event handler; repaint when fish_key_bindings changes"
if status --is-interactive
commandline -f repaint ^/dev/null
end
end
function __fish_repaint_bind_mode --on-variable fish_key_bindings --description "Event handler; repaint when fish_key_bindings changes"
if status --is-interactive
commandline -f repaint ^/dev/null
end
end
# initialize our new variables
if not set -q __fish_classic_git_prompt_initialized
set -qU fish_color_user; or set -U fish_color_user -o green
set -qU fish_color_host; or set -U fish_color_host -o cyan
set -qU fish_color_status; or set -U fish_color_status red
set -U __fish_classic_git_prompt_initialized
end
end
# initialize our new variables
if not set -q __fish_classic_git_prompt_initialized
set -qU fish_color_user
or set -U fish_color_user -o green
set -qU fish_color_host
or set -U fish_color_host -o cyan
set -qU fish_color_status
or set -U fish_color_status red
set -U __fish_classic_git_prompt_initialized
end
end
set -l color_cwd
set -l prefix
switch $USER
case root toor
if set -q fish_color_cwd_root
set color_cwd $fish_color_cwd_root
else
set color_cwd $fish_color_cwd
end
set suffix '#'
case '*'
set color_cwd $fish_color_cwd
set suffix '>'
end
set -l color_cwd
set -l prefix
switch $USER
case root toor
if set -q fish_color_cwd_root
set color_cwd $fish_color_cwd_root
else
set color_cwd $fish_color_cwd
end
set suffix '#'
case '*'
set color_cwd $fish_color_cwd
set suffix '>'
end
set -l prompt_status
if test $last_status -ne 0
set prompt_status ' ' (set_color $fish_color_status) "[$last_status]" "$normal"
end
set -l prompt_status
if test $last_status -ne 0
set prompt_status ' ' (set_color $fish_color_status) "[$last_status]" "$normal"
end
echo -n -s (set_color $fish_color_user) "$USER" $normal @ (set_color $fish_color_host) "$__fish_prompt_hostname" $normal ' ' (set_color $color_cwd) (prompt_pwd) $normal (__fish_vcs_prompt) $normal $prompt_status "> "
echo -n -s (set_color $fish_color_user) "$USER" $normal @ (set_color $fish_color_host) (prompt_hostname) $normal ' ' (set_color $color_cwd) (prompt_pwd) $normal (__fish_vcs_prompt) $normal $prompt_status "> "
end

View File

@@ -2,54 +2,55 @@
# author: Maurizio De Santis
function fish_prompt --description 'Write out the prompt, prepending the Debian chroot environment if present'
if not set -q __fish_prompt_normal
set -g __fish_prompt_normal (set_color normal)
end
# Just calculate these once, to save a few cycles when displaying the prompt
if not set -q __fish_prompt_hostname
set -g __fish_prompt_hostname (hostname|cut -d . -f 1)
if not set -q __fish_prompt_chroot_env
set -g __fish_prompt_chroot_env (set_color yellow)
end
# Set variable identifying the chroot you work in (used in the prompt below)
if begin
not set -q debian_chroot
and test -r /etc/debian_chroot
end
if not set -q __fish_prompt_normal
set -g __fish_prompt_normal (set_color normal)
set debian_chroot (cat /etc/debian_chroot)
end
if begin
not set -q __fish_debian_chroot_prompt
and set -q debian_chroot
and test -n $debian_chroot
end
set -g __fish_debian_chroot_prompt "($debian_chroot)"
end
if not set -q __fish_prompt_chroot_env
set -g __fish_prompt_chroot_env (set_color yellow)
end
# Prepend the chroot environment if present
if set -q __fish_debian_chroot_prompt
echo -n -s "$__fish_prompt_chroot_env" "$__fish_debian_chroot_prompt" "$__fish_prompt_normal" ' '
end
# Set variable identifying the chroot you work in (used in the prompt below)
if begin; not set -q debian_chroot; and test -r /etc/debian_chroot; end
set debian_chroot (cat /etc/debian_chroot)
end
if begin; not set -q __fish_debian_chroot_prompt; and set -q debian_chroot; and test -n $debian_chroot; end
set -g __fish_debian_chroot_prompt "($debian_chroot)"
end
switch $USER
# Prepend the chroot environment if present
if set -q __fish_debian_chroot_prompt
echo -n -s "$__fish_prompt_chroot_env" "$__fish_debian_chroot_prompt" "$__fish_prompt_normal" ' '
end
case root toor
switch $USER
case root toor
if not set -q __fish_prompt_cwd
if set -q fish_color_cwd_root
set -g __fish_prompt_cwd (set_color $fish_color_cwd_root)
else
set -g __fish_prompt_cwd (set_color $fish_color_cwd)
end
if not set -q __fish_prompt_cwd
if set -q fish_color_cwd_root
set -g __fish_prompt_cwd (set_color $fish_color_cwd_root)
else
set -g __fish_prompt_cwd (set_color $fish_color_cwd)
end
end
echo -n -s "$USER" @ "$__fish_prompt_hostname" ' ' "$__fish_prompt_cwd" (prompt_pwd) "$__fish_prompt_normal" '# '
echo -n -s "$USER" @ (prompt_hostname) ' ' "$__fish_prompt_cwd" (prompt_pwd) "$__fish_prompt_normal" '# '
case '*'
case '*'
if not set -q __fish_prompt_cwd
set -g __fish_prompt_cwd (set_color $fish_color_cwd)
end
if not set -q __fish_prompt_cwd
set -g __fish_prompt_cwd (set_color $fish_color_cwd)
end
echo -n -s "$USER" @ "$__fish_prompt_hostname" ' ' "$__fish_prompt_cwd" (prompt_pwd) "$__fish_prompt_normal" '> '
echo -n -s "$USER" @ (prompt_hostname) ' ' "$__fish_prompt_cwd" (prompt_pwd) "$__fish_prompt_normal" '> '
end
end
end

View File

@@ -6,46 +6,41 @@ function fish_prompt --description 'Write out the prompt'
#Save the return status of the previous command
set stat $status
# Just calculate these once, to save a few cycles when displaying the prompt
if not set -q __fish_prompt_hostname
set -g __fish_prompt_hostname (hostname|cut -d . -f 1)
end
if not set -q __fish_prompt_normal
if not set -q __fish_prompt_normal
set -g __fish_prompt_normal (set_color normal)
end
if not set -q __fish_color_blue
if not set -q __fish_color_blue
set -g __fish_color_blue (set_color -o blue)
end
#Set the color for the status depending on the value
#Set the color for the status depending on the value
set __fish_color_status (set_color -o green)
if test $stat -gt 0
set __fish_color_status (set_color -o red)
end
switch $USER
switch $USER
case root toor
case root toor
if not set -q __fish_prompt_cwd
if set -q fish_color_cwd_root
set -g __fish_prompt_cwd (set_color $fish_color_cwd_root)
else
if not set -q __fish_prompt_cwd
if set -q fish_color_cwd_root
set -g __fish_prompt_cwd (set_color $fish_color_cwd_root)
else
set -g __fish_prompt_cwd (set_color $fish_color_cwd)
end
end
printf '%s@%s %s%s%s# ' $USER (prompt_hostname) "$__fish_prompt_cwd" (prompt_pwd) "$__fish_prompt_normal"
case '*'
if not set -q __fish_prompt_cwd
set -g __fish_prompt_cwd (set_color $fish_color_cwd)
end
end
printf '%s@%s %s%s%s# ' $USER $__fish_prompt_hostname "$__fish_prompt_cwd" (prompt_pwd) "$__fish_prompt_normal"
case '*'
if not set -q __fish_prompt_cwd
set -g __fish_prompt_cwd (set_color $fish_color_cwd)
end
printf '[%s] %s%s@%s %s%s %s(%s)%s \f\r> ' (date "+%H:%M:%S") "$__fish_color_blue" $USER $__fish_prompt_hostname "$__fish_prompt_cwd" "$PWD" "$__fish_color_status" "$stat" "$__fish_prompt_normal"
printf '[%s] %s%s@%s %s%s %s(%s)%s \f\r> ' (date "+%H:%M:%S") "$__fish_color_blue" $USER (prompt_hostname) "$__fish_prompt_cwd" "$PWD" "$__fish_color_status" "$stat" "$__fish_prompt_normal"
end
end
end

View File

@@ -4,94 +4,94 @@
function fish_prompt --description 'Write out the prompt'
if not set -q __fish_git_prompt_show_informative_status
set -g __fish_git_prompt_show_informative_status 1
end
if not set -q __fish_git_prompt_hide_untrackedfiles
set -g __fish_git_prompt_hide_untrackedfiles 1
end
if not set -q __fish_git_prompt_show_informative_status
set -g __fish_git_prompt_show_informative_status 1
end
if not set -q __fish_git_prompt_hide_untrackedfiles
set -g __fish_git_prompt_hide_untrackedfiles 1
end
if not set -q __fish_git_prompt_color_branch
set -g __fish_git_prompt_color_branch magenta --bold
end
if not set -q __fish_git_prompt_showupstream
set -g __fish_git_prompt_showupstream "informative"
end
if not set -q __fish_git_prompt_char_upstream_ahead
set -g __fish_git_prompt_char_upstream_ahead "↑"
end
if not set -q __fish_git_prompt_char_upstream_behind
set -g __fish_git_prompt_char_upstream_behind "↓"
end
if not set -q __fish_git_prompt_char_upstream_prefix
set -g __fish_git_prompt_char_upstream_prefix ""
end
if not set -q __fish_git_prompt_color_branch
set -g __fish_git_prompt_color_branch magenta --bold
end
if not set -q __fish_git_prompt_showupstream
set -g __fish_git_prompt_showupstream "informative"
end
if not set -q __fish_git_prompt_char_upstream_ahead
set -g __fish_git_prompt_char_upstream_ahead "↑"
end
if not set -q __fish_git_prompt_char_upstream_behind
set -g __fish_git_prompt_char_upstream_behind "↓"
end
if not set -q __fish_git_prompt_char_upstream_prefix
set -g __fish_git_prompt_char_upstream_prefix ""
end
if not set -q __fish_git_prompt_char_stagedstate
set -g __fish_git_prompt_char_stagedstate "●"
end
if not set -q __fish_git_prompt_char_dirtystate
set -g __fish_git_prompt_char_dirtystate "✚"
end
if not set -q __fish_git_prompt_char_untrackedfiles
set -g __fish_git_prompt_char_untrackedfiles "…"
end
if not set -q __fish_git_prompt_char_conflictedstate
set -g __fish_git_prompt_char_conflictedstate "✖"
end
if not set -q __fish_git_prompt_char_cleanstate
set -g __fish_git_prompt_char_cleanstate "✔"
end
if not set -q __fish_git_prompt_char_stagedstate
set -g __fish_git_prompt_char_stagedstate "●"
end
if not set -q __fish_git_prompt_char_dirtystate
set -g __fish_git_prompt_char_dirtystate "✚"
end
if not set -q __fish_git_prompt_char_untrackedfiles
set -g __fish_git_prompt_char_untrackedfiles "…"
end
if not set -q __fish_git_prompt_char_conflictedstate
set -g __fish_git_prompt_char_conflictedstate "✖"
end
if not set -q __fish_git_prompt_char_cleanstate
set -g __fish_git_prompt_char_cleanstate "✔"
end
if not set -q __fish_git_prompt_color_dirtystate
set -g __fish_git_prompt_color_dirtystate blue
end
if not set -q __fish_git_prompt_color_stagedstate
set -g __fish_git_prompt_color_stagedstate yellow
end
if not set -q __fish_git_prompt_color_invalidstate
set -g __fish_git_prompt_color_invalidstate red
end
if not set -q __fish_git_prompt_color_untrackedfiles
set -g __fish_git_prompt_color_untrackedfiles $fish_color_normal
end
if not set -q __fish_git_prompt_color_cleanstate
set -g __fish_git_prompt_color_cleanstate green --bold
end
if not set -q __fish_git_prompt_color_dirtystate
set -g __fish_git_prompt_color_dirtystate blue
end
if not set -q __fish_git_prompt_color_stagedstate
set -g __fish_git_prompt_color_stagedstate yellow
end
if not set -q __fish_git_prompt_color_invalidstate
set -g __fish_git_prompt_color_invalidstate red
end
if not set -q __fish_git_prompt_color_untrackedfiles
set -g __fish_git_prompt_color_untrackedfiles $fish_color_normal
end
if not set -q __fish_git_prompt_color_cleanstate
set -g __fish_git_prompt_color_cleanstate green --bold
end
set -l last_status $status
set -l last_status $status
if not set -q __fish_prompt_normal
set -g __fish_prompt_normal (set_color normal)
end
if not set -q __fish_prompt_normal
set -g __fish_prompt_normal (set_color normal)
end
set -l color_cwd
set -l prefix
switch $USER
case root toor
if set -q fish_color_cwd_root
set color_cwd $fish_color_cwd_root
else
set color_cwd $fish_color_cwd
end
set suffix '#'
case '*'
set color_cwd $fish_color_cwd
set suffix '$'
end
set -l color_cwd
set -l prefix
switch $USER
case root toor
if set -q fish_color_cwd_root
set color_cwd $fish_color_cwd_root
else
set color_cwd $fish_color_cwd
end
set suffix '#'
case '*'
set color_cwd $fish_color_cwd
set suffix '$'
end
# PWD
set_color $color_cwd
echo -n (prompt_pwd)
set_color normal
# PWD
set_color $color_cwd
echo -n (prompt_pwd)
set_color normal
printf '%s ' (__fish_vcs_prompt)
printf '%s ' (__fish_vcs_prompt)
if not test $last_status -eq 0
set_color $fish_color_error
end
if not test $last_status -eq 0
set_color $fish_color_error
end
echo -n "$suffix "
echo -n "$suffix "
set_color normal
set_color normal
end

View File

@@ -1,4 +1,4 @@
# name: Just a Dollar
function fish_prompt
echo -n '$ '
echo -n '$ '
end

View File

@@ -2,19 +2,13 @@
# author: Steve
function fish_prompt --description 'Write out the prompt'
# Just calculate these once, to save a few cycles when displaying the prompt
if not set -q __fish_prompt_hostname
set -g __fish_prompt_hostname (hostname -s)
end
if not set -q __fish_prompt_normal
set -g __fish_prompt_normal (set_color normal)
end
if not set -q __fish_prompt_normal
set -g __fish_prompt_normal (set_color normal)
end
if not set -q __fish_prompt_cwd
set -g __fish_prompt_cwd (set_color $fish_color_cwd)
end
echo -n -s "$USER" @ "$__fish_prompt_hostname" ' ' "$__fish_prompt_cwd" (prompt_pwd) (__fish_vcs_prompt) "$__fish_prompt_normal" '> '
if not set -q __fish_prompt_cwd
set -g __fish_prompt_cwd (set_color $fish_color_cwd)
end
echo -n -s "$USER" @ (prompt_hostname) ' ' "$__fish_prompt_cwd" (prompt_pwd) (__fish_vcs_prompt) "$__fish_prompt_normal" '> '
end

View File

@@ -2,8 +2,8 @@
# author: ridiculous_fish
function fish_prompt
set_color $fish_color_cwd
echo -n (basename $PWD)
set_color normal
echo -n ' ) '
set_color $fish_color_cwd
echo -n (basename $PWD)
set_color normal
echo -n ' ) '
end

View File

@@ -2,8 +2,11 @@
# author: Guilhem "Nim" Saurel https://github.com/nim65s/dotfiles/
function fish_prompt
and set retc green; or set retc red
tty|string match -q -r tty; and set tty tty; or set tty pts
and set retc green
or set retc red
tty | string match -q -r tty
and set tty tty
or set tty pts
set_color $retc
if [ $tty = tty ]
@@ -26,7 +29,7 @@ function fish_prompt
else
set_color -o cyan
end
echo -n (hostname)
echo -n (prompt_hostname)
set_color -o white
#echo -n :(prompt_pwd)
echo -n :(pwd|sed "s=$HOME=~=")
@@ -46,16 +49,16 @@ function fish_prompt
echo -n (date +%X)
set_color -o green
echo -n ]
if type -q acpi
if [ (acpi -a 2> /dev/null | string match -r off) ]
echo -n '─['
set_color -o red
echo -n (acpi -b|cut -d' ' -f 4-)
set_color -o green
echo -n ']'
end
end
if [ (acpi -a 2> /dev/null | string match -r off) ]
echo -n '─['
set_color -o red
echo -n (acpi -b|cut -d' ' -f 4-)
set_color -o green
echo -n ']'
end
end
echo
set_color normal
for job in (jobs)

View File

@@ -3,28 +3,28 @@
function fish_prompt
if not set -q VIRTUAL_ENV_DISABLE_PROMPT
set -g VIRTUAL_ENV_DISABLE_PROMPT true
end
set_color yellow
printf '%s' (whoami)
set_color normal
printf ' at '
if not set -q VIRTUAL_ENV_DISABLE_PROMPT
set -g VIRTUAL_ENV_DISABLE_PROMPT true
end
set_color yellow
printf '%s' (whoami)
set_color normal
printf ' at '
set_color magenta
printf '%s' (hostname|cut -d . -f 1)
set_color normal
printf ' in '
set_color magenta
echo -n (prompt_hostname)
set_color normal
printf ' in '
set_color $fish_color_cwd
printf '%s' (prompt_pwd)
set_color normal
set_color $fish_color_cwd
printf '%s' (prompt_pwd)
set_color normal
# Line 2
echo
if test $VIRTUAL_ENV
printf "(%s) " (set_color blue)(basename $VIRTUAL_ENV)(set_color normal)
end
printf '↪ '
set_color normal
# Line 2
echo
if test $VIRTUAL_ENV
printf "(%s) " (set_color blue)(basename $VIRTUAL_ENV)(set_color normal)
end
printf '↪ '
set_color normal
end

View File

@@ -3,74 +3,76 @@
function fish_prompt
if not set -q -g __fish_robbyrussell_functions_defined
set -g __fish_robbyrussell_functions_defined
function _git_branch_name
echo (git symbolic-ref HEAD ^/dev/null | sed -e 's|^refs/heads/||')
if not set -q -g __fish_robbyrussell_functions_defined
set -g __fish_robbyrussell_functions_defined
function _git_branch_name
echo (git symbolic-ref HEAD ^/dev/null | sed -e 's|^refs/heads/||')
end
function _is_git_dirty
echo (git status -s --ignore-submodules=dirty ^/dev/null)
end
function _is_git_repo
type -q git
or return 1
git status -s >/dev/null ^/dev/null
end
function _hg_branch_name
echo (hg branch ^/dev/null)
end
function _is_hg_dirty
echo (hg status -mard ^/dev/null)
end
function _is_hg_repo
type -q hg
or return 1
hg summary >/dev/null ^/dev/null
end
function _repo_branch_name
eval "_$argv[1]_branch_name"
end
function _is_repo_dirty
eval "_is_$argv[1]_dirty"
end
function _repo_type
if _is_hg_repo
echo 'hg'
else if _is_git_repo
echo 'git'
end
end
end
function _is_git_dirty
echo (git status -s --ignore-submodules=dirty ^/dev/null)
set -l cyan (set_color -o cyan)
set -l yellow (set_color -o yellow)
set -l red (set_color -o red)
set -l blue (set_color -o blue)
set -l normal (set_color normal)
set -l arrow "$red"
if [ $USER = 'root' ]
set arrow "$red# "
end
function _is_git_repo
type -q git; or return 1
git status -s >/dev/null ^/dev/null
set -l cwd $cyan(basename (prompt_pwd))
set -l repo_type (_repo_type)
if [ $repo_type ]
set -l repo_branch $red(_repo_branch_name $repo_type)
set repo_info "$blue $repo_type:($repo_branch$blue)"
if [ (_is_repo_dirty $repo_type) ]
set -l dirty "$yellow"
set repo_info "$repo_info$dirty"
end
end
function _hg_branch_name
echo (hg branch ^/dev/null)
end
function _is_hg_dirty
echo (hg status -mard ^/dev/null)
end
function _is_hg_repo
type -q hg; or return 1
hg summary >/dev/null ^/dev/null
end
function _repo_branch_name
eval "_$argv[1]_branch_name"
end
function _is_repo_dirty
eval "_is_$argv[1]_dirty"
end
function _repo_type
if _is_hg_repo
echo 'hg'
else if _is_git_repo
echo 'git'
end
end
end
set -l cyan (set_color -o cyan)
set -l yellow (set_color -o yellow)
set -l red (set_color -o red)
set -l blue (set_color -o blue)
set -l normal (set_color normal)
set -l arrow "$red"
if [ $USER = 'root' ]
set arrow "$red# "
end
set -l cwd $cyan(basename (prompt_pwd))
set -l repo_type (_repo_type)
if [ $repo_type ]
set -l repo_branch $red(_repo_branch_name $repo_type)
set repo_info "$blue $repo_type:($repo_branch$blue)"
if [ (_is_repo_dirty $repo_type) ]
set -l dirty "$yellow"
set repo_info "$repo_info$dirty"
end
end
echo -n -s $arrow ' '$cwd $repo_info $normal ' '
echo -n -s $arrow ' '$cwd $repo_info $normal ' '
end

View File

@@ -1,9 +1,9 @@
# name: Screen Savvy
# author: Matthias
function fish_prompt -d "Write out the prompt"
if test -z $WINDOW
printf '%s%s@%s%s%s%s%s> ' (set_color yellow) (whoami) (set_color purple) (hostname|cut -d . -f 1) (set_color $fish_color_cwd) (prompt_pwd) (set_color normal)
else
printf '%s%s@%s%s%s(%s)%s%s%s> ' (set_color yellow) (whoami) (set_color purple) (hostname|cut -d . -f 1) (set_color white) (echo $WINDOW) (set_color $fish_color_cwd) (prompt_pwd) (set_color normal)
end
if test -z $WINDOW
printf '%s%s@%s%s%s%s%s> ' (set_color yellow) (whoami) (set_color purple) (prompt_hostname) (set_color $fish_color_cwd) (prompt_pwd) (set_color normal)
else
printf '%s%s@%s%s%s(%s)%s%s%s> ' (set_color yellow) (whoami) (set_color purple) (prompt_hostname) (set_color white) (echo $WINDOW) (set_color $fish_color_cwd) (prompt_pwd) (set_color normal)
end
end

View File

@@ -2,52 +2,55 @@
# author: Ivan Tham <ivanthamjunhoe@gmail.com>
function fish_prompt
test $SSH_TTY; and printf (set_color red)(whoami)(set_color white)'@'(set_color yellow)(hostname)' '
test $USER = 'root'; and echo (set_color red)"#"
test $SSH_TTY
and printf (set_color red)$USER(set_color brwhite)'@'(set_color yellow)(prompt_hostname)' '
test $USER = 'root'
and echo (set_color red)"#"
# Main
echo -n (set_color cyan)(prompt_pwd) (set_color red)''(set_color yellow)''(set_color green)' '
echo -n (set_color cyan)(prompt_pwd) (set_color red)''(set_color yellow)''(set_color green)' '
end
function fish_right_prompt
# last status
test $status != 0; and printf (set_color red)"⏎ "
test $status != 0
and printf (set_color red)"⏎ "
if git rev-parse ^ /dev/null
# Purple if branch detached else green
git branch -qv | grep "\*" | grep -q detached
and set_color purple --bold
or set_color green --bold
if git rev-parse ^/dev/null
# Magenta if branch detached else green
git branch -qv | grep "\*" | string match -rq detached
and set_color brmagenta
or set_color brgreen
# Need optimization on this block (eliminate space)
git name-rev --name-only HEAD
# Merging state
git merge -q ^ /dev/null; or printf ':'(set_color red)'merge'
git merge -q ^/dev/null
or printf ':'(set_color red)'merge'
printf ' '
# Symbols
for i in (git branch -qv --no-color|grep \*|cut -d' ' -f4-|cut -d] -f1|tr , \n)\
(git status --porcelain | cut -c 1-2 | uniq)
switch $i
for i in (git branch -qv --no-color|grep \*|cut -d' ' -f4-|cut -d] -f1|tr , \n)\
(git status --porcelain | cut -c 1-2 | uniq)
switch $i
case "*[ahead *"
printf (set_color purple)' '
printf (set_color magenta)' '
case "*behind *"
printf (set_color purple)' '
case "."
printf (set_color green)' '
case " D"
printf (set_color red)' '
case "*M*"
printf (set_color blue)' '
printf (set_color magenta)' '
case "."
printf (set_color green)' '
case " D"
printf (set_color red)' '
case "*M*"
printf (set_color blue)' '
case "*R*"
printf (set_color purple)' '
printf (set_color brmagenta)' '
case "*U*"
printf (set_color brown)' '
case "??"
printf (set_color white)' '
end
end
end
printf (set_color bryellow)' '
case "??"
printf (set_color brwhite)' '
end
end
end
end

View File

@@ -2,35 +2,35 @@
# author: terlar - https://github.com/terlar
function fish_prompt --description 'Write out the prompt'
set -l last_status $status
set -l last_status $status
# User
set_color $fish_color_user
echo -n (whoami)
set_color normal
# User
set_color $fish_color_user
echo -n (whoami)
set_color normal
echo -n '@'
echo -n '@'
# Host
set_color $fish_color_host
echo -n (hostname -s)
set_color normal
# Host
set_color $fish_color_host
echo -n (prompt_hostname)
set_color normal
echo -n ':'
echo -n ':'
# PWD
set_color $fish_color_cwd
echo -n (prompt_pwd)
set_color normal
# PWD
set_color $fish_color_cwd
echo -n (prompt_pwd)
set_color normal
__terlar_git_prompt
__fish_hg_prompt
echo
__terlar_git_prompt
__fish_hg_prompt
echo
if not test $last_status -eq 0
set_color $fish_color_error
end
if not test $last_status -eq 0
set_color $fish_color_error
end
echo -n '➤ '
set_color normal
echo -n '➤ '
set_color normal
end

View File

@@ -2,12 +2,14 @@
# author: Jon Clayden
function fish_prompt -d "Write out the prompt"
set -l home_escaped (echo -n $HOME | sed 's/\//\\\\\//g')
set -l pwd (echo -n $PWD | sed "s/^$home_escaped/~/" | sed 's/ /%20/g')
set -l prompt_symbol ''
switch $USER
case root toor; set prompt_symbol '#'
case '*'; set prompt_symbol '$'
end
printf "[%s@%s %s%s%s]%s " $USER (hostname -s) (set_color $fish_color_cwd) $pwd (set_color normal) $prompt_symbol
set -l home_escaped (echo -n $HOME | sed 's/\//\\\\\//g')
set -l pwd (echo -n $PWD | sed "s/^$home_escaped/~/" | sed 's/ /%20/g')
set -l prompt_symbol ''
switch $USER
case root toor
set prompt_symbol '#'
case '*'
set prompt_symbol '$'
end
printf "[%s@%s %s%s%s]%s " $USER (prompt_hostname) (set_color $fish_color_cwd) $pwd (set_color normal) $prompt_symbol
end

View File

@@ -1,50 +1,49 @@
#!/usr/bin/env python
from __future__ import unicode_literals
# Whether we're Python 2
import sys
import binascii
import cgi
import glob
import multiprocessing.pool
import os
import operator
import os
import random
import re
import select
import socket
import string
import subprocess
import sys
import webbrowser
FISH_BIN_PATH = False # will be set later
IS_PY2 = sys.version_info[0] == 2
if IS_PY2:
import SimpleHTTPServer
import SocketServer
from urlparse import parse_qs
else:
import http.server as SimpleHTTPServer
import socketserver as SocketServer
from urllib.parse import parse_qs
# Check to see if IPv6 is enabled in the kernel
HAS_IPV6 = True
try:
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
s.close()
except:
HAS_IPV6 = False
# Disable CLI web browsers
term = os.environ.pop('TERM', None)
import webbrowser
if term:
os.environ['TERM'] = term
import subprocess
import re, socket, cgi, select, time, glob, random, string, binascii
try:
import json
except ImportError:
import simplejson as json
FISH_BIN_PATH = False # will be set later
def run_fish_cmd(text):
from subprocess import PIPE
# ensure that fish is using UTF-8
ctype = os.environ.get("LC_ALL", os.environ.get("LC_CTYPE", os.environ.get("LANG")))
# Ensure that fish is using UTF-8.
ctype = os.environ.get("LC_ALL", os.environ.get("LC_CTYPE",
os.environ.get("LANG")))
env = None
if ctype is None or re.search(r"\.utf-?8$", ctype, flags=re.I) is None:
# override LC_CTYPE with en_US.UTF-8
@@ -52,68 +51,66 @@ def run_fish_cmd(text):
# Fish makes the same assumption in config.fish
env = os.environ.copy()
env.update(LC_CTYPE="en_US.UTF-8", LANG="en_US.UTF-8")
p = subprocess.Popen([FISH_BIN_PATH], stdin=PIPE, stdout=PIPE, stderr=PIPE, env=env)
p = subprocess.Popen([FISH_BIN_PATH], stdin=PIPE, stdout=PIPE, stderr=PIPE,
env=env)
out, err = p.communicate(text.encode('utf-8'))
out = out.decode('utf-8', 'replace')
err = err.decode('utf-8', 'replace')
return(out, err)
def escape_fish_cmd(text):
# Replace one backslash with two, and single quotes with backslash-quote
escaped = text.replace('\\', '\\\\').replace("'", "\\'")
return "'" + escaped + "'"
named_colors = {
'black' : '000000',
'red' : '800000',
'green' : '008000',
'brown' : '725000',
'yellow' : '808000',
'blue' : '000080',
'magenta' : '800080',
'purple' : '800080',
'cyan' : '008080',
'grey' : 'e5e5e5',
'brgrey' : '555555',
'white' : 'c0c0c0',
'brblack' : '808080',
'brred' : 'ff0000',
'brgreen' : '00ff00',
'brbrown' : 'ffff00',
'bryellow' : 'ffff00',
'brblue' : '0000ff',
'brmagenta' : 'ff00ff',
'brpurple' : 'ff00ff',
'brcyan' : '00ffff',
'brwhite' : 'ffffff'
'black': '000000', 'red': '800000', 'green': '008000', 'brown': '725000',
'yellow': '808000', 'blue': '000080', 'magenta': '800080',
'purple': '800080', 'cyan': '008080', 'grey': 'e5e5e5', 'brgrey': '555555',
'white': 'c0c0c0', 'brblack': '808080', 'brred': 'ff0000',
'brgreen': '00ff00', 'brbrown': 'ffff00', 'bryellow': 'ffff00',
'brblue': '0000ff', 'brmagenta': 'ff00ff', 'brpurple': 'ff00ff',
'brcyan': '00ffff', 'brwhite': 'ffffff'
}
bindings_blacklist = set(["self-insert", "'begin;end'"])
def parse_one_color(comp):
""" A basic function to parse a single color value like 'FFA000' """
if comp in named_colors:
# Named color
return named_colors[comp]
elif re.match(r"[0-9a-fA-F]{3}", comp) is not None or re.match(r"[0-9a-fA-F]{6}", comp) is not None:
elif (re.match(r"[0-9a-fA-F]{3}", comp) is not None or
re.match(r"[0-9a-fA-F]{6}", comp) is not None):
# Hex color
return comp
else:
# Unknown
return ''
def better_color(c1, c2):
""" Indicate which color is "better", i.e. prefer term256 colors """
if not c2: return c1
if not c1: return c2
if c1 == 'normal': return c2
if c2 == 'normal': return c1
if c2 in named_colors: return c1
if c1 in named_colors: return c2
if not c2:
return c1
if not c1:
return c2
if c1 == 'normal':
return c2
if c2 == 'normal':
return c1
if c2 in named_colors:
return c1
if c1 in named_colors:
return c2
return c1
def parse_color(color_str):
""" A basic function to parse a color string, for example, 'red' '--bold' """
""" A basic function to parse a color string, for example, 'red' '--bold'.
"""
comps = color_str.split(' ')
color = 'normal'
background_color = ''
@@ -127,21 +124,69 @@ def parse_color(color_str):
underline = True
elif comp.startswith('--background='):
# Background color
background_color = better_color(background_color, parse_one_color(comp[len('--background='):]))
background_color = better_color(
background_color, parse_one_color(comp[len('--background='):]))
else:
# Regular color
color = better_color(color, parse_one_color(comp))
return {"color": color, "background": background_color, "bold": bold, "underline": underline}
return {"color": color, "background": background_color, "bold": bold,
"underline": underline}
def parse_bool(val):
val = val.lower()
if val.startswith('f') or val.startswith('0'): return False
if val.startswith('t') or val.startswith('1'): return True
if val.startswith('f') or val.startswith('0'):
return False
if val.startswith('t') or val.startswith('1'):
return True
return bool(val)
def html_color_for_ansi_color_index(val):
arr = ['black', '#AA0000', '#00AA00', '#AA5500', '#0000AA', '#AA00AA', '#00AAAA', '#AAAAAA', '#555555', '#FF5555', '#55FF55', '#FFFF55', '#5555FF', '#FF55FF', '#55FFFF', 'white', '#000000', '#00005f', '#000087', '#0000af', '#0000d7', '#0000ff', '#005f00', '#005f5f', '#005f87', '#005faf', '#005fd7', '#005fff', '#008700', '#00875f', '#008787', '#0087af', '#0087d7', '#0087ff', '#00af00', '#00af5f', '#00af87', '#00afaf', '#00afd7', '#00afff', '#00d700', '#00d75f', '#00d787', '#00d7af', '#00d7d7', '#00d7ff', '#00ff00', '#00ff5f', '#00ff87', '#00ffaf', '#00ffd7', '#00ffff', '#5f0000', '#5f005f', '#5f0087', '#5f00af', '#5f00d7', '#5f00ff', '#5f5f00', '#5f5f5f', '#5f5f87', '#5f5faf', '#5f5fd7', '#5f5fff', '#5f8700', '#5f875f', '#5f8787', '#5f87af', '#5f87d7', '#5f87ff', '#5faf00', '#5faf5f', '#5faf87', '#5fafaf', '#5fafd7', '#5fafff', '#5fd700', '#5fd75f', '#5fd787', '#5fd7af', '#5fd7d7', '#5fd7ff', '#5fff00', '#5fff5f', '#5fff87', '#5fffaf', '#5fffd7', '#5fffff', '#870000', '#87005f', '#870087', '#8700af', '#8700d7', '#8700ff', '#875f00', '#875f5f', '#875f87', '#875faf', '#875fd7', '#875fff', '#878700', '#87875f', '#878787', '#8787af', '#8787d7', '#8787ff', '#87af00', '#87af5f', '#87af87', '#87afaf', '#87afd7', '#87afff', '#87d700', '#87d75f', '#87d787', '#87d7af', '#87d7d7', '#87d7ff', '#87ff00', '#87ff5f', '#87ff87', '#87ffaf', '#87ffd7', '#87ffff', '#af0000', '#af005f', '#af0087', '#af00af', '#af00d7', '#af00ff', '#af5f00', '#af5f5f', '#af5f87', '#af5faf', '#af5fd7', '#af5fff', '#af8700', '#af875f', '#af8787', '#af87af', '#af87d7', '#af87ff', '#afaf00', '#afaf5f', '#afaf87', '#afafaf', '#afafd7', '#afafff', '#afd700', '#afd75f', '#afd787', '#afd7af', '#afd7d7', '#afd7ff', '#afff00', '#afff5f', '#afff87', '#afffaf', '#afffd7', '#afffff', '#d70000', '#d7005f', '#d70087', '#d700af', '#d700d7', '#d700ff', '#d75f00', '#d75f5f', '#d75f87', '#d75faf', '#d75fd7', '#d75fff', '#d78700', '#d7875f', '#d78787', '#d787af', '#d787d7', '#d787ff', '#d7af00', '#d7af5f', '#d7af87', '#d7afaf', '#d7afd7', '#d7afff', '#d7d700', '#d7d75f', '#d7d787', '#d7d7af', '#d7d7d7', '#d7d7ff', '#d7ff00', '#d7ff5f', '#d7ff87', '#d7ffaf', '#d7ffd7', '#d7ffff', '#ff0000', '#ff005f', '#ff0087', '#ff00af', '#ff00d7', '#ff00ff', '#ff5f00', '#ff5f5f', '#ff5f87', '#ff5faf', '#ff5fd7', '#ff5fff', '#ff8700', '#ff875f', '#ff8787', '#ff87af', '#ff87d7', '#ff87ff', '#ffaf00', '#ffaf5f', '#ffaf87', '#ffafaf', '#ffafd7', '#ffafff', '#ffd700', '#ffd75f', '#ffd787', '#ffd7af', '#ffd7d7', '#ffd7ff', '#ffff00', '#ffff5f', '#ffff87', '#ffffaf', '#ffffd7', '#ffffff', '#080808', '#121212', '#1c1c1c', '#262626', '#303030', '#3a3a3a', '#444444', '#4e4e4e', '#585858', '#626262', '#6c6c6c', '#767676', '#808080', '#8a8a8a', '#949494', '#9e9e9e', '#a8a8a8', '#b2b2b2', '#bcbcbc', '#c6c6c6', '#d0d0d0', '#dadada', '#e4e4e4', '#eeeeee']
arr = ['black', '#AA0000', '#00AA00', '#AA5500', '#0000AA', '#AA00AA',
'#00AAAA', '#AAAAAA', '#555555', '#FF5555', '#55FF55', '#FFFF55',
'#5555FF', '#FF55FF', '#55FFFF', 'white', '#000000', '#00005f',
'#000087', '#0000af', '#0000d7', '#0000ff', '#005f00', '#005f5f',
'#005f87', '#005faf', '#005fd7', '#005fff', '#008700', '#00875f',
'#008787', '#0087af', '#0087d7', '#0087ff', '#00af00', '#00af5f',
'#00af87', '#00afaf', '#00afd7', '#00afff', '#00d700', '#00d75f',
'#00d787', '#00d7af', '#00d7d7', '#00d7ff', '#00ff00', '#00ff5f',
'#00ff87', '#00ffaf', '#00ffd7', '#00ffff', '#5f0000', '#5f005f',
'#5f0087', '#5f00af', '#5f00d7', '#5f00ff', '#5f5f00', '#5f5f5f',
'#5f5f87', '#5f5faf', '#5f5fd7', '#5f5fff', '#5f8700', '#5f875f',
'#5f8787', '#5f87af', '#5f87d7', '#5f87ff', '#5faf00', '#5faf5f',
'#5faf87', '#5fafaf', '#5fafd7', '#5fafff', '#5fd700', '#5fd75f',
'#5fd787', '#5fd7af', '#5fd7d7', '#5fd7ff', '#5fff00', '#5fff5f',
'#5fff87', '#5fffaf', '#5fffd7', '#5fffff', '#870000', '#87005f',
'#870087', '#8700af', '#8700d7', '#8700ff', '#875f00', '#875f5f',
'#875f87', '#875faf', '#875fd7', '#875fff', '#878700', '#87875f',
'#878787', '#8787af', '#8787d7', '#8787ff', '#87af00', '#87af5f',
'#87af87', '#87afaf', '#87afd7', '#87afff', '#87d700', '#87d75f',
'#87d787', '#87d7af', '#87d7d7', '#87d7ff', '#87ff00', '#87ff5f',
'#87ff87', '#87ffaf', '#87ffd7', '#87ffff', '#af0000', '#af005f',
'#af0087', '#af00af', '#af00d7', '#af00ff', '#af5f00', '#af5f5f',
'#af5f87', '#af5faf', '#af5fd7', '#af5fff', '#af8700', '#af875f',
'#af8787', '#af87af', '#af87d7', '#af87ff', '#afaf00', '#afaf5f',
'#afaf87', '#afafaf', '#afafd7', '#afafff', '#afd700', '#afd75f',
'#afd787', '#afd7af', '#afd7d7', '#afd7ff', '#afff00', '#afff5f',
'#afff87', '#afffaf', '#afffd7', '#afffff', '#d70000', '#d7005f',
'#d70087', '#d700af', '#d700d7', '#d700ff', '#d75f00', '#d75f5f',
'#d75f87', '#d75faf', '#d75fd7', '#d75fff', '#d78700', '#d7875f',
'#d78787', '#d787af', '#d787d7', '#d787ff', '#d7af00', '#d7af5f',
'#d7af87', '#d7afaf', '#d7afd7', '#d7afff', '#d7d700', '#d7d75f',
'#d7d787', '#d7d7af', '#d7d7d7', '#d7d7ff', '#d7ff00', '#d7ff5f',
'#d7ff87', '#d7ffaf', '#d7ffd7', '#d7ffff', '#ff0000', '#ff005f',
'#ff0087', '#ff00af', '#ff00d7', '#ff00ff', '#ff5f00', '#ff5f5f',
'#ff5f87', '#ff5faf', '#ff5fd7', '#ff5fff', '#ff8700', '#ff875f',
'#ff8787', '#ff87af', '#ff87d7', '#ff87ff', '#ffaf00', '#ffaf5f',
'#ffaf87', '#ffafaf', '#ffafd7', '#ffafff', '#ffd700', '#ffd75f',
'#ffd787', '#ffd7af', '#ffd7d7', '#ffd7ff', '#ffff00', '#ffff5f',
'#ffff87', '#ffffaf', '#ffffd7', '#ffffff', '#080808', '#121212',
'#1c1c1c', '#262626', '#303030', '#3a3a3a', '#444444', '#4e4e4e',
'#585858', '#626262', '#6c6c6c', '#767676', '#808080', '#8a8a8a',
'#949494', '#9e9e9e', '#a8a8a8', '#b2b2b2', '#bcbcbc', '#c6c6c6',
'#d0d0d0', '#dadada', '#e4e4e4', '#eeeeee']
if val < 0 or val >= len(arr):
return ''
else:
@@ -149,6 +194,8 @@ def html_color_for_ansi_color_index(val):
# Function to return special ANSI escapes like exit_attribute_mode
g_special_escapes_dict = None
def get_special_ansi_escapes():
global g_special_escapes_dict
if g_special_escapes_dict is None:
@@ -160,8 +207,10 @@ def get_special_ansi_escapes():
def get_tparm(key):
val = None
key = curses.tigetstr("sgr0")
if key: val = curses.tparm(key)
if val: val = val.decode('utf-8')
if key:
val = curses.tparm(key)
if val:
val = val.decode('utf-8')
return val
# Just a few for now
@@ -173,6 +222,8 @@ def get_special_ansi_escapes():
# Given a known ANSI escape sequence, convert it to HTML and append to the list
# Returns whether we have an open <span>
def append_html_for_ansi_escape(full_val, result, span_open):
# Strip off the initial \x1b[ and terminating m
@@ -187,16 +238,16 @@ def append_html_for_ansi_escape(full_val, result, span_open):
match = re.match('38;5;(\d+)', val)
if match is not None:
close_span()
html_color = html_color_for_ansi_color_index(int(match.group(1)))
html_color = html_color_for_ansi_color_index(int(match.group(1)))
result.append('<span style="color: ' + html_color + '">')
return True # span now open
return True # span now open
# term8 foreground color
if val in [str(x) for x in 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)
result.append('<span style="color: ' + html_color + '">')
return True # span now open
return True # span now open
# Try special escapes
special_escapes = get_special_ansi_escapes()
@@ -209,15 +260,17 @@ def append_html_for_ansi_escape(full_val, result, span_open):
# Do nothing on failure
return span_open
def strip_ansi(val):
# Make a half-assed effort to strip ANSI control sequences
# We assume that all such sequences start with 0x1b and end with m,
# which catches most cases
return re.sub("\x1b[^m]*m", '', val)
def ansi_prompt_line_width(val):
# Given an ANSI prompt, return the length of its longest line, as in the number of characters it takes up
# Start by stripping off ANSI
# Given an ANSI prompt, return the length of its longest line, as in the
# number of characters it takes up. Start by stripping off ANSI.
stripped_val = strip_ansi(val)
# Now count the longest line
@@ -225,10 +278,10 @@ def ansi_prompt_line_width(val):
def ansi_to_html(val):
# Split us up by ANSI escape sequences
# We want to catch not only the standard color codes, but also things like sgr0
# Hence this lame check
# Note that Python 2.6 doesn't have a flag param to re.split, so we have to compile it first
# Split us up by ANSI escape sequences. We want to catch not only the
# standard color codes, but also things like sgr0. Hence this lame check.
# Note that Python 2.6 doesn't have a flag param to re.split, so we have to
# compile it first.
reg = re.compile("""
( # Capture
\x1b # Escape
@@ -253,10 +306,12 @@ def ansi_to_html(val):
result.append(cgi.escape(strip_ansi(component)))
else:
# It's an escape sequence. Close the previous escape.
span_open = append_html_for_ansi_escape(component, result, span_open)
span_open = append_html_for_ansi_escape(component, result,
span_open)
# Close final escape
if span_open: result.append('</span>')
if span_open:
result.append('</span>')
# Remove empty elements
result = [x for x in result if x]
@@ -272,6 +327,7 @@ def ansi_to_html(val):
return ''.join(result)
class FishVar:
""" A class that represents a variable """
def __init__(self, name, value):
@@ -283,15 +339,20 @@ class FishVar:
def get_json_obj(self):
# Return an array(3): name, value, flags
flags = []
if self.universal: flags.append('universal')
if self.exported: flags.append('exported')
return {"name": self.name, "value": self.value, "Flags": ', '.join(flags)}
if self.universal:
flags.append('universal')
if self.exported:
flags.append('exported')
return {"name": self.name, "value": self.value,
"Flags": ', '.join(flags)}
class FishBinding:
"""A class that represents keyboard binding """
def __init__(self, command, raw_binding, readable_binding, description=None):
self.command = command
def __init__(self, command, raw_binding, readable_binding,
description=None):
self.command = command
self.bindings = []
self.description = description
self.add_binding(raw_binding, readable_binding)
@@ -302,23 +363,24 @@ class FishBinding:
i['raw_bindings'].append(raw_binding)
break
else:
self.bindings.append({'readable_binding':readable_binding, 'raw_bindings':[raw_binding]})
self.bindings.append({'readable_binding': readable_binding,
'raw_bindings': [raw_binding]})
def get_json_obj(self):
return {"command" : self.command, "bindings": self.bindings, "description": self.description}
return {"command": self.command, "bindings": self.bindings,
"description": self.description}
class BindingParser:
""" Class to parse codes for bind command """
#TODO: What does snext and sprevious mean ?
readable_keys= { "dc":"Delete", "npage": "Page Up", "ppage":"Page Down",
"sdc": "Shift Delete", "shome": "Shift Home",
"left": "Left Arrow", "right": "Right Arrow",
"up": "Up Arrow", "down": "Down Arrow",
"sleft": "Shift Left", "sright": "Shift Right",
"btab": "Shift Tab"
}
# TODO: What does snext and sprevious mean ?
readable_keys = {"dc": "Delete", "npage": "Page Up", "ppage": "Page Down",
"sdc": "Shift Delete", "shome": "Shift Home",
"left": "Left Arrow", "right": "Right Arrow",
"up": "Up Arrow", "down": "Down Arrow",
"sleft": "Shift Left", "sright": "Shift Right",
"btab": "Shift Tab"}
def set_buffer(self, buffer):
""" Sets code to parse """
@@ -356,7 +418,8 @@ class BindingParser:
# \[1\; is start of control sequence
if c == '1':
b = self.get_char(); c = self.get_char()
b = self.get_char()
c = self.get_char()
if b == '\\' and c == '~':
result += "Home"
elif c == ";":
@@ -369,7 +432,8 @@ class BindingParser:
# \[4\~ is End
if c == '4':
b = self.get_char(); c = self.get_char()
b = self.get_char()
c = self.get_char()
if b == '\\' and c == '~':
result += "End"
@@ -466,7 +530,7 @@ class FishConfigTCPServer(SocketServer.TCPServer):
"""TCPServer that only accepts connections from localhost (IPv4/IPv6)."""
WHITELIST = set(['::1', '::ffff:127.0.0.1', '127.0.0.1'])
address_family = socket.AF_INET6 if HAS_IPV6 else socket.AF_INET
address_family = socket.AF_INET6 if socket.has_ipv6 else socket.AF_INET
def verify_request(self, request, client_address):
return client_address[0] in FishConfigTCPServer.WHITELIST
@@ -526,7 +590,7 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
for match in re.finditer(r"^fish_color_(\S+) ?(.*)", line):
color_name, color_value = [x.strip() for x in match.group(1, 2)]
color_desc = descriptions.get(color_name, '')
data = { "name": color_name, "description" : color_desc }
data = {"name": color_name, "description": color_desc}
data.update(parse_color(color_value))
result.append(data)
remaining.discard(color_name)
@@ -564,18 +628,22 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
vars = {}
for line in out.split('\n'):
comps = line.split(' ', 1)
if len(comps) < 2: continue
if len(comps) < 2:
continue
fish_var = FishVar(comps[0], comps[1])
vars[fish_var.name] = fish_var
# Mark universal variables. L means don't abbreviate.
for name in self.do_get_variable_names('set -nUL'):
if name in vars: vars[name].universal = True
if name in vars:
vars[name].universal = True
# Mark exported variables. L means don't abbreviate.
for name in self.do_get_variable_names('set -nxL'):
if name in vars: vars[name].exported = True
if name in vars:
vars[name].exported = True
return [vars[key].get_json_obj() for key in sorted(vars.keys(), key=lambda x: x.lower())]
return [vars[key].get_json_obj() for key
in sorted(vars.keys(), key=lambda x: x.lower())]
def do_get_bindings(self):
""" Get key bindings """
@@ -621,29 +689,37 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
bindings.append(fish_binding)
command_to_binding[command] = fish_binding
return [ binding.get_json_obj() for binding in bindings ]
return [binding.get_json_obj() for binding in bindings]
def do_get_history(self):
# Use \x1e ("record separator") to distinguish between history items. The first
# backslash is so Python passes one backslash to fish
# Use \x1e ("record separator") to distinguish between history items.
# The first backslash is so Python passes one backslash to fish.
out, err = run_fish_cmd('for val in $history; echo -n $val \\x1e; end')
result = out.split(' \x1e')
if result: result.pop() # Trim off the trailing element
if result:
result.pop() # trim off the trailing element
return result
def do_get_color_for_variable(self, name):
"Return the color with the given name, or the empty string if there is none"
# Return the color with the given name, or the empty string if there is
# none.
out, err = run_fish_cmd("echo -n $" + name)
return out
def do_set_color_for_variable(self, name, color, background_color, bold, underline):
if not color: color = 'normal'
def do_set_color_for_variable(self, name, color, background_color, bold,
underline):
if not color:
color = 'normal'
"Sets a color for a fish color name, like 'autosuggestion'"
command = 'set -U fish_color_' + name
if color: command += ' ' + color
if background_color: command += ' --background=' + background_color
if bold: command += ' --bold'
if underline: command += ' --underline'
if color:
command += ' ' + color
if background_color:
command += ' --background=' + background_color
if bold:
command += ' --bold'
if underline:
command += ' --underline'
out, err = run_fish_cmd(command)
return out
@@ -655,7 +731,7 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def do_delete_history_item(self, history_item_text):
# It's really lame that we always return success here
cmd = ('builtin history delete --exact -- %s; builtin history save' %
escape_fish_cmd(history_item_text))
escape_fish_cmd(history_item_text))
out, err = run_fish_cmd(cmd)
return True
@@ -669,29 +745,35 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
prompt_demo_ansi, err = run_fish_cmd(command_to_run)
prompt_demo_html = ansi_to_html(prompt_demo_ansi)
prompt_demo_font_size = self.font_size_for_ansi_prompt(prompt_demo_ansi)
result = {'function': prompt_function_text, 'demo': prompt_demo_html, 'font_size': prompt_demo_font_size }
result = {'function': prompt_function_text, 'demo': prompt_demo_html,
'font_size': prompt_demo_font_size}
if extras_dict:
result.update(extras_dict)
return result
def do_get_current_prompt(self):
# Return the current prompt
# We run 'false' to demonstrate how the prompt shows the command status (#1624)
# Return the current prompt. We run 'false' to demonstrate how the
# prompt shows the command status (#1624).
prompt_func, err = run_fish_cmd('functions fish_prompt')
result = self.do_get_prompt('builtin cd "' + initial_wd + '" ; false ; fish_prompt', prompt_func.strip(), {'name': 'Current'})
result = self.do_get_prompt(
'builtin cd "' + initial_wd + '" ; false ; fish_prompt',
prompt_func.strip(), {'name': 'Current'})
return result
def do_get_sample_prompt(self, text, extras_dict):
# Return the prompt you get from the given text
# extras_dict is a dictionary whose values get merged in
# We run 'false' to demonstrate how the prompt shows the command status (#1624)
cmd = text + "\n builtin cd \"" + initial_wd + "\" \n false \n fish_prompt\n"
# Return the prompt you get from the given text. Extras_dict is a
# dictionary whose values get merged in. We run 'false' to demonstrate
# how the prompt shows the command status (#1624)
cmd = (text + "\n builtin cd \"" + initial_wd +
"\" \n false \n fish_prompt\n")
return self.do_get_prompt(cmd, text.strip(), extras_dict)
def parse_one_sample_prompt_hash(self, line, result_dict):
# Allow us to skip whitespace, etc.
if not line: return True
if line.isspace(): return True
if not line:
return True
if line.isspace():
return True
# Parse a comment hash like '# name: Classic'
match = re.match(r"#\s*(\w+?): (.+)", line, re.IGNORECASE)
@@ -703,7 +785,6 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
# Skip other hash comments
return line.startswith('#')
def read_one_sample_prompt(self, path):
try:
with open(path, 'rb') as fd:
@@ -713,10 +794,13 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
parsing_hashes = True
unicode_lines = (line.decode('utf-8') for line in fd)
for line in unicode_lines:
# Parse hashes until parse_one_sample_prompt_hash return False
# Parse hashes until parse_one_sample_prompt_hash return
# False.
if parsing_hashes:
parsing_hashes = self.parse_one_sample_prompt_hash(line, extras_dict)
# Maybe not we're not parsing hashes, or maybe we already were not
parsing_hashes = self.parse_one_sample_prompt_hash(
line, extras_dict)
# Maybe not we're not parsing hashes, or maybe we already
# were not.
if not parsing_hashes:
function_lines.append(line)
func = ''.join(function_lines).strip()
@@ -758,7 +842,8 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
return True
def do_save_abbreviation(self, abbreviation):
out, err = run_fish_cmd('abbr --add \'%s %s\'' % (abbreviation['word'], abbreviation['phrase']))
out, err = run_fish_cmd('abbr --add \'%s %s\'' % (
abbreviation['word'], abbreviation['phrase']))
if err:
return err
else:
@@ -768,21 +853,29 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
if len(haystack) < len(needle):
return False
bits = 0
for x,y in zip(haystack, needle):
for x, y in zip(haystack, needle):
bits |= ord(x) ^ ord(y)
return bits == 0
def font_size_for_ansi_prompt(self, prompt_demo_ansi):
width = ansi_prompt_line_width(prompt_demo_ansi)
# Pick a font size
if width >= 70: font_size = '8pt'
if width >= 60: font_size = '10pt'
elif width >= 50: font_size = '11pt'
elif width >= 40: font_size = '13pt'
elif width >= 30: font_size = '15pt'
elif width >= 25: font_size = '16pt'
elif width >= 20: font_size = '17pt'
else: font_size = '18pt'
if width >= 70:
font_size = '8pt'
if width >= 60:
font_size = '10pt'
elif width >= 50:
font_size = '11pt'
elif width >= 40:
font_size = '13pt'
elif width >= 30:
font_size = '15pt'
elif width >= 25:
font_size = '16pt'
elif width >= 20:
font_size = '17pt'
else:
font_size = '18pt'
return font_size
def do_GET(self):
@@ -820,7 +913,7 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
# Return valid output
self.send_response(200)
self.send_header('Content-type','application/json')
self.send_header('Content-type', 'application/json')
self.end_headers()
self.write_to_wfile('\n')
@@ -861,7 +954,9 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
if what:
# Not sure why we get lists here?
output = self.do_set_color_for_variable(what[0], color[0], background_color[0], parse_bool(bold[0]), parse_bool(underline[0]))
output = self.do_set_color_for_variable(
what[0], color[0], background_color[0],
parse_bool(bold[0]), parse_bool(underline[0]))
else:
output = 'Bad request'
elif p == '/get_function/':
@@ -881,13 +976,13 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
output = ["Unable to set prompt"]
elif p == '/save_abbreviation/':
r = self.do_save_abbreviation(postvars)
if r == True:
if r:
output = ["OK"]
else:
output = [r]
elif p == '/remove_abbreviation/':
r = self.do_remove_abbreviation(postvars)
if r == True:
if r:
output = ["OK"]
else:
output = [r]
@@ -896,7 +991,7 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
# Return valid output
self.send_response(200)
self.send_header('Content-type','application/json')
self.send_header('Content-type', 'application/json')
self.end_headers()
self.write_to_wfile('\n')
@@ -932,7 +1027,8 @@ redirect_template_html = """
fish_bin_dir = os.environ.get('__fish_bin_dir')
fish_bin_path = None
if not fish_bin_dir:
print('The __fish_bin_dir environment variable is not set. Looking in $PATH...')
print('The __fish_bin_dir environment variable is not set. '
'Looking in $PATH...')
# distutils.spawn is terribly broken, because it looks in wd before PATH,
# and doesn't actually validate that the file is even executable
for p in os.environ['PATH'].split(os.pathsep):
@@ -950,7 +1046,8 @@ else:
fish_bin_path = os.path.join(fish_bin_dir, 'fish')
if not os.access(fish_bin_path, os.X_OK):
print("fish could not be executed at path '%s'. Is fish installed correctly?" % fish_bin_path)
print("fish could not be executed at path '%s'. "
"Is fish installed correctly?" % fish_bin_path)
sys.exit(-1)
FISH_BIN_PATH = fish_bin_path
@@ -958,8 +1055,8 @@ FISH_BIN_PATH = fish_bin_path
# so get the current working directory
initial_wd = os.getcwd()
# Make sure that the working directory is the one that contains the script server file,
# because the document root is the working directory
# Make sure that the working directory is the one that contains the script
# server file, because the document root is the working directory.
where = os.path.dirname(sys.argv[0])
os.chdir(where)
@@ -968,7 +1065,7 @@ authkey = binascii.b2a_hex(os.urandom(16)).decode('ascii')
# Try to find a suitable port
PORT = 8000
HOST = "::" if HAS_IPV6 else "localhost"
HOST = "::" if socket.has_ipv6 else "localhost"
while PORT <= 9000:
try:
Handler = FishConfigHTTPRequestHandler
@@ -992,16 +1089,17 @@ if PORT > 9000:
# Just look at the first letter
initial_tab = ''
if len(sys.argv) > 1:
for tab in ['functions', 'prompt', 'colors', 'variables', 'history', 'bindings', 'abbreviations']:
for tab in ['functions', 'prompt', 'colors', 'variables', 'history',
'bindings', 'abbreviations']:
if tab.startswith(sys.argv[1]):
initial_tab = '#' + tab
break
url = 'http://localhost:%d/%s/%s' % (PORT, authkey, initial_tab)
# Create temporary file to hold redirect to real server
# This prevents exposing the URL containing the authentication key on the command line
# (see CVE-2014-2914 or https://github.com/fish-shell/fish-shell/issues/1438)
# Create temporary file to hold redirect to real server. This prevents exposing
# the URL containing the authentication key on the command line (see
# CVE-2014-2914 or https://github.com/fish-shell/fish-shell/issues/1438).
if 'XDG_CACHE_HOME' in os.environ:
dirname = os.path.expanduser(os.path.expandvars('$XDG_CACHE_HOME/fish/'))
else:
@@ -1012,11 +1110,12 @@ try:
os.makedirs(dirname, 0o0700)
except OSError as e:
if e.errno == 17:
pass
pass
else:
raise e
raise e
randtoken = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6))
randtoken = ''.join(random.choice(string.ascii_uppercase + string.digits)
for _ in range(6))
filename = dirname + 'web_config-%s.html' % randtoken
f = open(filename, 'w')

View File

@@ -1,7 +1,6 @@
// The classes responsible for autoloading functions and completions.
#include "config.h" // IWYU pragma: keep
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <stddef.h>
@@ -157,6 +156,19 @@ autoload_function_t *autoload_t::get_autoloaded_function_with_creation(const wcs
return func;
}
static bool use_cached(autoload_function_t *func, bool really_load, bool allow_stale_functions) {
if (!func) {
return false; // can't use a function that doesn't exist
}
if (really_load && !func->is_placeholder && !func->is_loaded) {
return false; // can't use an unloaded function
}
if (!allow_stale_functions && is_stale(func)) {
return false; // can't use a stale function
}
return true; // I guess we can use it
}
/// This internal helper function does all the real work. By using two functions, the internal
/// function can return on various places in the code, and the caller can take care of various
/// cleanup work.
@@ -169,35 +181,21 @@ autoload_function_t *autoload_t::get_autoloaded_function_with_creation(const wcs
bool autoload_t::locate_file_and_maybe_load_it(const wcstring &cmd, bool really_load, bool reload,
const wcstring_list_t &path_list) {
// Note that we are NOT locked in this function!
bool reloaded = 0;
bool reloaded = false;
// Try using a cached function. If we really want the function to be loaded, require that it be
// really loaded. If we're not reloading, allow stale functions.
{
bool allow_stale_functions = !reload;
scoped_lock locker(lock);
autoload_function_t *func = this->get_node(cmd); // get the function
// Determine if we can use this cached function.
bool use_cached;
if (!func) {
// Can't use a function that doesn't exist.
use_cached = false;
} else if (really_load && !func->is_placeholder && !func->is_loaded) {
use_cached = false; // can't use an unloaded function
} else if (!allow_stale_functions && is_stale(func)) {
use_cached = false; // can't use a stale function
} else {
use_cached = true; // I guess we can use it
}
// If we can use this function, return whether we were able to access it.
if (use_cached) {
assert(func != NULL);
if (use_cached(func, really_load, allow_stale_functions)) {
return func->is_internalized || func->access.accessible;
}
}
// The source of the script will end up here.
wcstring script_source;
bool has_script_source = false;
@@ -234,55 +232,52 @@ bool autoload_t::locate_file_and_maybe_load_it(const wcstring &cmd, bool really_
if (!has_script_source) {
// Iterate over path searching for suitable completion files.
for (size_t i = 0; i < path_list.size(); i++) {
for (size_t i = 0; i < path_list.size() && !found_file; i++) {
wcstring next = path_list.at(i);
wcstring path = next + L"/" + cmd + L".fish";
const file_access_attempt_t access = access_file(path, R_OK);
if (access.accessible) {
found_file = true;
// Now we're actually going to take the lock.
scoped_lock locker(lock);
autoload_function_t *func = this->get_node(cmd);
// Generate the source if we need to load it.
bool need_to_load_function =
really_load &&
(func == NULL || func->access.mod_time != access.mod_time || !func->is_loaded);
if (need_to_load_function) {
// Generate the script source.
wcstring esc = escape_string(path, 1);
script_source = L"source " + esc;
has_script_source = true;
// Remove any loaded command because we are going to reload it. Note that this
// will deadlock if command_removed calls back into us.
if (func && func->is_loaded) {
command_removed(cmd);
func->is_placeholder = false;
}
// Mark that we're reloading it.
reloaded = true;
}
// Create the function if we haven't yet. This does not load it. Do not trigger
// eviction unless we are actually loading, because we don't want to evict off of
// the main thread.
if (!func) {
func = get_autoloaded_function_with_creation(cmd, really_load);
}
// It's a fiction to say the script is loaded at this point, but we're definitely
// going to load it down below.
if (need_to_load_function) func->is_loaded = true;
// Unconditionally record our access time.
func->access = access;
break;
if (!access.accessible) {
continue;
}
// Now we're actually going to take the lock.
scoped_lock locker(lock);
autoload_function_t *func = this->get_node(cmd);
// Generate the source if we need to load it.
bool need_to_load_function =
really_load &&
(func == NULL || func->access.mod_time != access.mod_time || !func->is_loaded);
if (need_to_load_function) {
// Generate the script source.
wcstring esc = escape_string(path, 1);
script_source = L"source " + esc;
has_script_source = true;
// Remove any loaded command because we are going to reload it. Note that this
// will deadlock if command_removed calls back into us.
if (func && func->is_loaded) {
command_removed(cmd);
func->is_placeholder = false;
}
// Mark that we're reloading it.
reloaded = true;
}
// Create the function if we haven't yet. This does not load it. Do not trigger
// eviction unless we are actually loading, because we don't want to evict off of
// the main thread.
if (!func) func = get_autoloaded_function_with_creation(cmd, really_load);
// It's a fiction to say the script is loaded at this point, but we're definitely
// going to load it down below.
if (need_to_load_function) func->is_loaded = true;
// Unconditionally record our access time.
func->access = access;
found_file = true;
}
// If no file or builtin script was found we insert a placeholder function. Later we only
@@ -313,7 +308,7 @@ bool autoload_t::locate_file_and_maybe_load_it(const wcstring &cmd, bool really_
if (really_load) {
return reloaded;
} else {
return found_file || has_script_source;
}
return found_file || has_script_source;
}

File diff suppressed because it is too large Load Diff

View File

@@ -109,6 +109,7 @@ int builtin_function(parser_t &parser, io_streams_t &streams, const wcstring_lis
void builtin_print_help(parser_t &parser, io_streams_t &streams, const wchar_t *cmd,
output_stream_t &b);
int builtin_count_args(const wchar_t *const *argv);
bool builtin_is_valid_varname(const wchar_t *varname, wcstring &errstr, const wchar_t *cmd);
void builtin_unknown_option(parser_t &parser, io_streams_t &streams, const wchar_t *cmd,
const wchar_t *opt);

View File

@@ -127,6 +127,10 @@ static void replace_part(const wchar_t *begin, const wchar_t *end, const wchar_t
out_pos += wcslen(insert);
break;
}
default: {
DIE("unexpected append_mode");
break;
}
}
out.append(end);
reader_set_buffer(out, out_pos);
@@ -152,29 +156,23 @@ static void write_part(const wchar_t *begin, const wchar_t *end, int cut_at_curs
while (tok.next(&token)) {
if ((cut_at_cursor) && (token.offset + token.text.size() >= pos)) break;
switch (token.type) {
case TOK_STRING: {
wcstring tmp = token.text;
unescape_string_in_place(&tmp, UNESCAPE_INCOMPLETE);
out.append(tmp);
out.push_back(L'\n');
break;
}
default: { break; }
if (token.type == TOK_STRING) {
wcstring tmp = token.text;
unescape_string_in_place(&tmp, UNESCAPE_INCOMPLETE);
out.append(tmp);
out.push_back(L'\n');
}
}
streams.out.append(out);
free(buff);
} else {
if (cut_at_cursor) {
end = begin + pos;
streams.out.append(begin, pos);
} else {
streams.out.append(begin, end - begin);
}
// debug( 0, L"woot2 %ls -> %ls", buff, esc );
streams.out.append(begin, end - begin);
streams.out.append(L"\n");
streams.out.push_back(L'\n');
}
}
@@ -332,6 +330,10 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv)
builtin_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
return 1;
}
default: {
DIE("unexpected opt");
break;
}
}
}
@@ -424,12 +426,8 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv)
if (cursor_mode) {
if (argc - w.woptind) {
wchar_t *endptr;
long new_pos;
errno = 0;
new_pos = wcstol(argv[w.woptind], &endptr, 10);
if (*endptr || errno) {
long new_pos = fish_wcstol(argv[w.woptind]);
if (errno) {
streams.err.append_format(BUILTIN_ERR_NOT_NUMBER, argv[0], argv[w.woptind]);
builtin_print_help(parser, streams, argv[0], streams.err);
}
@@ -476,26 +474,24 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv)
parse_util_token_extent(get_buffer(), get_cursor_pos(), &begin, &end, 0, 0);
break;
}
default: {
DIE("unexpected buffer_part");
break;
}
}
switch (argc - w.woptind) {
case 0: {
write_part(begin, end, cut_at_cursor, tokenize, streams);
break;
}
case 1: {
replace_part(begin, end, argv[w.woptind], append_mode);
break;
}
default: {
wcstring sb = argv[w.woptind];
for (int i = w.woptind + 1; i < argc; i++) {
sb.push_back(L'\n');
sb.append(argv[i]);
}
replace_part(begin, end, sb.c_str(), append_mode);
break;
int arg_count = argc - w.woptind;
if (arg_count == 0) {
write_part(begin, end, cut_at_cursor, tokenize, streams);
} else if (arg_count == 1) {
replace_part(begin, end, argv[w.woptind], append_mode);
} else {
wcstring sb = argv[w.woptind];
for (int i = w.woptind + 1; i < argc; i++) {
sb.push_back(L'\n');
sb.append(argv[i]);
}
replace_part(begin, end, sb.c_str(), append_mode);
}
return 0;

View File

@@ -122,64 +122,46 @@ static void builtin_complete_remove(const wcstring_list_t &cmd, const wcstring_l
// complete.cpp for any heavy lifting.
int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
ASSERT_IS_MAIN_THREAD();
wgetopter_t w;
bool res = false;
int argc = 0;
static int recursion_level = 0;
wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
int result_mode = SHARED;
int remove = 0;
int authoritative = -1;
wcstring short_opt;
wcstring_list_t gnu_opt, old_opt;
const wchar_t *comp = L"", *desc = L"", *condition = L"";
bool do_complete = false;
wcstring do_complete_param;
wcstring_list_t cmd;
wcstring_list_t cmd_to_complete;
wcstring_list_t path;
wcstring_list_t wrap_targets;
static int recursion_level = 0;
argc = builtin_count_args(argv);
w.woptind = 0;
while (!res) {
static const struct woption long_options[] = {{L"exclusive", no_argument, 0, 'x'},
{L"no-files", no_argument, 0, 'f'},
{L"require-parameter", no_argument, 0, 'r'},
{L"path", required_argument, 0, 'p'},
{L"command", required_argument, 0, 'c'},
{L"short-option", required_argument, 0, 's'},
{L"long-option", required_argument, 0, 'l'},
{L"old-option", required_argument, 0, 'o'},
{L"description", required_argument, 0, 'd'},
{L"arguments", required_argument, 0, 'a'},
{L"erase", no_argument, 0, 'e'},
{L"unauthoritative", no_argument, 0, 'u'},
{L"authoritative", no_argument, 0, 'A'},
{L"condition", required_argument, 0, 'n'},
{L"wraps", required_argument, 0, 'w'},
{L"do-complete", optional_argument, 0, 'C'},
{L"help", no_argument, 0, 'h'},
{0, 0, 0, 0}};
int opt_index = 0;
int opt =
w.wgetopt_long(argc, argv, L"a:c:p:s:l:o:d:frxeuAn:C::w:h", long_options, &opt_index);
if (opt == -1) break;
const wchar_t *short_options = L":a:c:p:s:l:o:d:frxeuAn:C::w:h";
const struct woption long_options[] = {{L"exclusive", no_argument, NULL, 'x'},
{L"no-files", no_argument, NULL, 'f'},
{L"require-parameter", no_argument, NULL, 'r'},
{L"path", required_argument, NULL, 'p'},
{L"command", required_argument, NULL, 'c'},
{L"short-option", required_argument, NULL, 's'},
{L"long-option", required_argument, NULL, 'l'},
{L"old-option", required_argument, NULL, 'o'},
{L"description", required_argument, NULL, 'd'},
{L"arguments", required_argument, NULL, 'a'},
{L"erase", no_argument, NULL, 'e'},
{L"unauthoritative", no_argument, NULL, 'u'},
{L"authoritative", no_argument, NULL, 'A'},
{L"condition", required_argument, NULL, 'n'},
{L"wraps", required_argument, NULL, 'w'},
{L"do-complete", optional_argument, NULL, 'C'},
{L"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}};
int opt;
wgetopter_t w;
while ((opt = w.wgetopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
switch (opt) {
case 0: {
if (long_options[opt_index].flag != 0) break;
streams.err.append_format(BUILTIN_ERR_UNKNOWN, argv[0],
long_options[opt_index].name);
builtin_print_help(parser, streams, argv[0], streams.err);
res = true;
break;
}
case 'x': {
result_mode |= EXCLUSIVE;
break;
@@ -199,19 +181,15 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
if (opt == 'p')
path.push_back(tmp);
else
cmd.push_back(tmp);
cmd_to_complete.push_back(tmp);
} else {
streams.err.append_format(L"%ls: Invalid token '%ls'\n", argv[0], w.woptarg);
res = true;
streams.err.append_format(L"%ls: Invalid token '%ls'\n", cmd, w.woptarg);
return STATUS_BUILTIN_ERROR;
}
break;
}
case 'd': {
desc = w.woptarg;
if (w.woptarg[0] == '\0') {
streams.err.append_format(L"%ls: -d requires a non-empty string\n", argv[0]);
res = true;
}
break;
}
case 'u': {
@@ -225,24 +203,24 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
case 's': {
short_opt.append(w.woptarg);
if (w.woptarg[0] == '\0') {
streams.err.append_format(L"%ls: -s requires a non-empty string\n", argv[0]);
res = true;
streams.err.append_format(L"%ls: -s requires a non-empty string\n", cmd);
return STATUS_BUILTIN_ERROR;
}
break;
}
case 'l': {
gnu_opt.push_back(w.woptarg);
if (w.woptarg[0] == '\0') {
streams.err.append_format(L"%ls: -l requires a non-empty string\n", argv[0]);
res = true;
streams.err.append_format(L"%ls: -l requires a non-empty string\n", cmd);
return STATUS_BUILTIN_ERROR;
}
break;
}
case 'o': {
old_opt.push_back(w.woptarg);
if (w.woptarg[0] == '\0') {
streams.err.append_format(L"%ls: -o requires a non-empty string\n", argv[0]);
res = true;
streams.err.append_format(L"%ls: -o requires a non-empty string\n", cmd);
return STATUS_BUILTIN_ERROR;
}
break;
}
@@ -268,143 +246,142 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
if (arg == NULL) {
// This corresponds to using 'complete -C' in non-interactive mode.
// See #2361.
builtin_missing_argument(parser, streams, argv[0], argv[w.woptind - 1]);
builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1]);
return STATUS_BUILTIN_ERROR;
}
do_complete_param = arg;
break;
}
case 'h': {
builtin_print_help(parser, streams, argv[0], streams.out);
return 0;
builtin_print_help(parser, streams, cmd, streams.out);
return STATUS_BUILTIN_OK;
}
case ':': {
builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1]);
return STATUS_BUILTIN_ERROR;
}
case '?': {
builtin_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
res = true;
builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1]);
return STATUS_BUILTIN_ERROR;
}
default: {
DIE("unexpected retval from wgetopt_long");
break;
}
}
}
if (!res) {
if (condition && wcslen(condition)) {
const wcstring condition_string = condition;
parse_error_list_t errors;
if (parse_util_detect_errors(condition_string, &errors,
false /* do not accept incomplete */)) {
streams.err.append_format(L"%ls: Condition '%ls' contained a syntax error", argv[0],
condition);
for (size_t i = 0; i < errors.size(); i++) {
streams.err.append_format(L"\n%s: ", argv[0]);
streams.err.append(errors.at(i).describe(condition_string));
}
res = true;
if (w.woptind != argc) {
streams.err.append_format(BUILTIN_ERR_TOO_MANY_ARGUMENTS, cmd);
builtin_print_help(parser, streams, cmd, streams.err);
return STATUS_BUILTIN_ERROR;
}
if (condition && wcslen(condition)) {
const wcstring condition_string = condition;
parse_error_list_t errors;
if (parse_util_detect_errors(condition_string, &errors,
false /* do not accept incomplete */)) {
streams.err.append_format(L"%ls: Condition '%ls' contained a syntax error", cmd,
condition);
for (size_t i = 0; i < errors.size(); i++) {
streams.err.append_format(L"\n%s: ", cmd);
streams.err.append(errors.at(i).describe(condition_string));
}
return STATUS_BUILTIN_ERROR;
}
}
if (!res) {
if (comp && wcslen(comp)) {
wcstring prefix;
if (argv[0]) {
prefix.append(argv[0]);
prefix.append(L": ");
}
if (comp && wcslen(comp)) {
wcstring prefix;
prefix.append(cmd);
prefix.append(L": ");
wcstring err_text;
if (parser.detect_errors_in_argument_list(comp, &err_text, prefix.c_str())) {
streams.err.append_format(L"%ls: Completion '%ls' contained a syntax error\n",
argv[0], comp);
streams.err.append(err_text);
streams.err.push_back(L'\n');
res = true;
}
wcstring err_text;
if (parser.detect_errors_in_argument_list(comp, &err_text, prefix.c_str())) {
streams.err.append_format(L"%ls: Completion '%ls' contained a syntax error\n", cmd,
comp);
streams.err.append(err_text);
streams.err.push_back(L'\n');
return STATUS_BUILTIN_ERROR;
}
}
if (!res) {
if (do_complete) {
const wchar_t *token;
if (do_complete) {
const wchar_t *token;
parse_util_token_extent(do_complete_param.c_str(), do_complete_param.size(), &token, 0,
0, 0);
parse_util_token_extent(do_complete_param.c_str(), do_complete_param.size(), &token, 0,
0, 0);
// Create a scoped transient command line, so that bulitin_commandline will see our
// argument, not the reader buffer.
builtin_commandline_scoped_transient_t temp_buffer(do_complete_param);
// Create a scoped transient command line, so that bulitin_commandline will see our
// argument, not the reader buffer.
builtin_commandline_scoped_transient_t temp_buffer(do_complete_param);
if (recursion_level < 1) {
recursion_level++;
if (recursion_level < 1) {
recursion_level++;
std::vector<completion_t> comp;
complete(do_complete_param, &comp, COMPLETION_REQUEST_DEFAULT,
env_vars_snapshot_t::current());
std::vector<completion_t> comp;
complete(do_complete_param, &comp, COMPLETION_REQUEST_DEFAULT,
env_vars_snapshot_t::current());
for (size_t i = 0; i < comp.size(); i++) {
const completion_t &next = comp.at(i);
for (size_t i = 0; i < comp.size(); i++) {
const completion_t &next = comp.at(i);
// Make a fake commandline, and then apply the completion to it.
const wcstring faux_cmdline = token;
size_t tmp_cursor = faux_cmdline.size();
wcstring faux_cmdline_with_completion = completion_apply_to_command_line(
next.completion, next.flags, faux_cmdline, &tmp_cursor, false);
// Make a fake commandline, and then apply the completion to it.
const wcstring faux_cmdline = token;
size_t tmp_cursor = faux_cmdline.size();
wcstring faux_cmdline_with_completion = completion_apply_to_command_line(
next.completion, next.flags, faux_cmdline, &tmp_cursor, false);
// completion_apply_to_command_line will append a space unless COMPLETE_NO_SPACE
// is set. We don't want to set COMPLETE_NO_SPACE because that won't close
// quotes. What we want is to close the quote, but not append the space. So we
// just look for the space and clear it.
if (!(next.flags & COMPLETE_NO_SPACE) &&
string_suffixes_string(L" ", faux_cmdline_with_completion)) {
faux_cmdline_with_completion.resize(faux_cmdline_with_completion.size() -
1);
}
// The input data is meant to be something like you would have on the command
// line, e.g. includes backslashes. The output should be raw, i.e. unescaped. So
// we need to unescape the command line. See #1127.
unescape_string_in_place(&faux_cmdline_with_completion, UNESCAPE_DEFAULT);
streams.out.append(faux_cmdline_with_completion);
// Append any description.
if (!next.description.empty()) {
streams.out.push_back(L'\t');
streams.out.append(next.description);
}
streams.out.push_back(L'\n');
// completion_apply_to_command_line will append a space unless COMPLETE_NO_SPACE
// is set. We don't want to set COMPLETE_NO_SPACE because that won't close
// quotes. What we want is to close the quote, but not append the space. So we
// just look for the space and clear it.
if (!(next.flags & COMPLETE_NO_SPACE) &&
string_suffixes_string(L" ", faux_cmdline_with_completion)) {
faux_cmdline_with_completion.resize(faux_cmdline_with_completion.size() -
1);
}
recursion_level--;
}
} else if (w.woptind != argc) {
streams.err.append_format(_(L"%ls: Too many arguments\n"), argv[0]);
builtin_print_help(parser, streams, argv[0], streams.err);
// The input data is meant to be something like you would have on the command
// line, e.g. includes backslashes. The output should be raw, i.e. unescaped. So
// we need to unescape the command line. See #1127.
unescape_string_in_place(&faux_cmdline_with_completion, UNESCAPE_DEFAULT);
streams.out.append(faux_cmdline_with_completion);
res = true;
} else if (cmd.empty() && path.empty()) {
// No arguments specified, meaning we print the definitions of all specified completions
// to stdout.
streams.out.append(complete_print());
// Append any description.
if (!next.description.empty()) {
streams.out.push_back(L'\t');
streams.out.append(next.description);
}
streams.out.push_back(L'\n');
}
recursion_level--;
}
} else if (cmd_to_complete.empty() && path.empty()) {
// No arguments specified, meaning we print the definitions of all specified completions
// to stdout.
streams.out.append(complete_print());
} else {
int flags = COMPLETE_AUTO_SPACE;
if (remove) {
builtin_complete_remove(cmd_to_complete, path, short_opt.c_str(), gnu_opt, old_opt);
} else {
int flags = COMPLETE_AUTO_SPACE;
builtin_complete_add(cmd_to_complete, path, short_opt.c_str(), gnu_opt, old_opt,
result_mode, authoritative, condition, comp, desc, flags);
}
if (remove) {
builtin_complete_remove(cmd, path, short_opt.c_str(), gnu_opt, old_opt);
} else {
builtin_complete_add(cmd, path, short_opt.c_str(), gnu_opt, old_opt, result_mode,
authoritative, condition, comp, desc, flags);
}
// Handle wrap targets (probably empty). We only wrap commands, not paths.
for (size_t w = 0; w < wrap_targets.size(); w++) {
const wcstring &wrap_target = wrap_targets.at(w);
for (size_t i = 0; i < cmd.size(); i++) {
(remove ? complete_remove_wrapper : complete_add_wrapper)(cmd.at(i),
wrap_target);
}
// Handle wrap targets (probably empty). We only wrap commands, not paths.
for (size_t w = 0; w < wrap_targets.size(); w++) {
const wcstring &wrap_target = wrap_targets.at(w);
for (size_t i = 0; i < cmd_to_complete.size(); i++) {
(remove ? complete_remove_wrapper : complete_add_wrapper)(cmd_to_complete.at(i),
wrap_target);
}
}
}
return res ? 1 : 0;
return STATUS_BUILTIN_OK;
}

View File

@@ -101,6 +101,10 @@ static void builtin_jobs_print(const job_t *j, int mode, int header, io_streams_
}
break;
}
default: {
DIE("unexpected mode");
break;
}
}
}
@@ -159,6 +163,10 @@ int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
builtin_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
return 1;
}
default: {
DIE("unexpected opt");
break;
}
}
}
@@ -178,11 +186,8 @@ int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
int i;
for (i = w.woptind; i < argc; i++) {
int pid;
wchar_t *end;
errno = 0;
pid = fish_wcstoi(argv[i], &end, 10);
if (errno || *end) {
int pid = fish_wcstoi(argv[i]);
if (errno || pid < 0) {
streams.err.append_format(_(L"%ls: '%ls' is not a job\n"), argv[0], argv[i]);
return 1;
}

View File

@@ -54,7 +54,7 @@
#include <limits.h>
#include <locale.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <wchar.h>
@@ -508,39 +508,48 @@ void builtin_printf_state_t::print_direc(const wchar_t *start, size_t length, wc
case L'G': {
long double arg = string_to_scalar_type<long double>(argument, this);
if (!have_field_width) {
if (!have_precision)
if (!have_precision) {
this->append_format_output(fmt.c_str(), arg);
else
} else {
this->append_format_output(fmt.c_str(), precision, arg);
}
} else {
if (!have_precision)
if (!have_precision) {
this->append_format_output(fmt.c_str(), field_width, arg);
else
} else {
this->append_format_output(fmt.c_str(), field_width, precision, arg);
}
}
break;
}
case L'c': {
if (!have_field_width)
if (!have_field_width) {
this->append_format_output(fmt.c_str(), *argument);
else
} else {
this->append_format_output(fmt.c_str(), field_width, *argument);
}
break;
}
case L's': {
if (!have_field_width) {
if (!have_precision) {
this->append_format_output(fmt.c_str(), argument);
} else
} else {
this->append_format_output(fmt.c_str(), precision, argument);
}
} else {
if (!have_precision)
if (!have_precision) {
this->append_format_output(fmt.c_str(), field_width, argument);
else
} else {
this->append_format_output(fmt.c_str(), field_width, precision, argument);
}
}
break;
}
default: {
DIE("unexpected opt");
break;
}
}
}
@@ -588,8 +597,7 @@ int builtin_printf_state_t::print_formatted(const wchar_t *format, int argc, wch
}
modify_allowed_format_specifiers(ok, "aAcdeEfFgGiosuxX", true);
for (;; f++, direc_length++) {
for (bool continue_looking_for_flags = true; continue_looking_for_flags;) {
switch (*f) {
case L'I':
case L'\'': {
@@ -609,10 +617,16 @@ int builtin_printf_state_t::print_formatted(const wchar_t *format, int argc, wch
modify_allowed_format_specifiers(ok, "cs", false);
break;
}
default: { goto no_more_flag_characters; }
default: {
continue_looking_for_flags = false;
break;
}
}
if (continue_looking_for_flags) {
f++;
direc_length++;
}
}
no_more_flag_characters:;
if (*f == L'*') {
++f;
@@ -687,7 +701,10 @@ int builtin_printf_state_t::print_formatted(const wchar_t *format, int argc, wch
f += print_esc(f, false);
break;
}
default: { this->append_output(*f); }
default: {
this->append_output(*f);
break;
}
}
}
return save_argc - argc;

View File

@@ -3,7 +3,9 @@
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <wchar.h>
#include <wctype.h>
#include <algorithm>
@@ -77,12 +79,10 @@ static int my_env_set(const wchar_t *key, const wcstring_list_t &val, int scope,
struct stat buff;
if (wstat(dir, &buff) == -1) {
error = true;
}
else if (!S_ISDIR(buff.st_mode)) {
} else if (!S_ISDIR(buff.st_mode)) {
error = true;
errno = ENOTDIR;
}
else if (waccess(dir, X_OK) == -1) {
} else if (waccess(dir, X_OK) == -1) {
error = true;
}
@@ -90,7 +90,7 @@ static int my_env_set(const wchar_t *key, const wcstring_list_t &val, int scope,
any_success = true;
} else {
streams.err.append_format(_(BUILTIN_SET_PATH_ERROR), L"set", key, dir.c_str(),
strerror(errno));
strerror(errno));
const wchar_t *colon = wcschr(dir.c_str(), L':');
if (colon && *(colon + 1)) {
@@ -123,6 +123,9 @@ static int my_env_set(const wchar_t *key, const wcstring_list_t &val, int scope,
}
switch (env_set(key, val_str, scope | ENV_USER)) {
case ENV_OK: {
break;
}
case ENV_PERM: {
streams.err.append_format(_(L"%ls: Tried to change the read-only variable '%ls'\n"),
L"set", key);
@@ -143,6 +146,10 @@ static int my_env_set(const wchar_t *key, const wcstring_list_t &val, int scope,
retcode = 1;
break;
}
default: {
DIE("unexpected env_set() ret val");
break;
}
}
return retcode;
@@ -159,7 +166,6 @@ static int my_env_set(const wchar_t *key, const wcstring_list_t &val, int scope,
static int parse_index(std::vector<long> &indexes, const wchar_t *src, const wchar_t *name,
size_t var_count, io_streams_t &streams) {
size_t len;
int count = 0;
const wchar_t *src_orig = src;
@@ -167,9 +173,7 @@ static int parse_index(std::vector<long> &indexes, const wchar_t *src, const wch
return 0;
}
while (*src != L'\0' && (iswalnum(*src) || *src == L'_')) {
src++;
}
while (*src != L'\0' && (iswalnum(*src) || *src == L'_')) src++;
if (*src != L'[') {
streams.err.append_format(_(BUILTIN_SET_ARG_COUNT), L"set");
@@ -177,7 +181,6 @@ static int parse_index(std::vector<long> &indexes, const wchar_t *src, const wch
}
len = src - src_orig;
if ((wcsncmp(src_orig, name, len) != 0) || (wcslen(name) != (len))) {
streams.err.append_format(
_(L"%ls: Multiple variable names specified in single call (%ls and %.*ls)\n"), L"set",
@@ -186,37 +189,26 @@ static int parse_index(std::vector<long> &indexes, const wchar_t *src, const wch
}
src++;
while (iswspace(*src)) {
src++;
}
while (iswspace(*src)) src++;
while (*src != L']') {
wchar_t *end;
long l_ind;
errno = 0;
l_ind = wcstol(src, &end, 10);
if (end == src || errno) {
const wchar_t *end;
long l_ind = fish_wcstol(src, &end);
if (errno > 0) { // ignore errno == -1 meaning the int did not end with a '\0'
streams.err.append_format(_(L"%ls: Invalid index starting at '%ls'\n"), L"set", src);
return 0;
}
if (l_ind < 0) {
l_ind = var_count + l_ind + 1;
}
if (l_ind < 0) l_ind = var_count + l_ind + 1;
src = end;
src = end; //!OCLINT(parameter reassignment)
if (*src == L'.' && *(src + 1) == L'.') {
src += 2;
long l_ind2 = wcstol(src, &end, 10);
if (end == src || errno) {
long l_ind2 = fish_wcstol(src, &end);
if (errno > 0) { // ignore errno == -1 meaning the int did not end with a '\0'
return 1;
}
src = end;
src = end; //!OCLINT(parameter reassignment)
if (l_ind2 < 0) {
l_ind2 = var_count + l_ind2 + 1;
@@ -231,6 +223,7 @@ static int parse_index(std::vector<long> &indexes, const wchar_t *src, const wch
indexes.push_back(l_ind);
count++;
}
while (iswspace(*src)) src++;
}
@@ -342,7 +335,7 @@ int builtin_set(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
int erase = 0, list = 0, unexport = 0;
int universal = 0, query = 0;
bool shorten_ok = true;
bool preserve_incoming_failure_exit_status = true;
bool preserve_failure_exit_status = true;
const int incoming_exit_status = proc_get_last_status();
// Variables used for performing the actual work.
@@ -351,8 +344,6 @@ int builtin_set(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
int scope;
int slice = 0;
const wchar_t *bad_char = NULL;
// Parse options to obtain the requested operation and the modifiers.
w.woptind = 0;
while (1) {
@@ -368,12 +359,12 @@ int builtin_set(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
}
case 'e': {
erase = 1;
preserve_incoming_failure_exit_status = false;
preserve_failure_exit_status = false;
break;
}
case 'n': {
list = 1;
preserve_incoming_failure_exit_status = false;
preserve_failure_exit_status = false;
break;
}
case 'x': {
@@ -402,7 +393,7 @@ int builtin_set(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
}
case 'q': {
query = 1;
preserve_incoming_failure_exit_status = false;
preserve_failure_exit_status = false;
break;
}
case 'h': {
@@ -528,18 +519,11 @@ int builtin_set(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
*wcschr(dest, L'[') = 0;
}
if (!wcslen(dest)) {
free(dest);
streams.err.append_format(BUILTIN_ERR_VARNAME_ZERO, argv[0]);
wcstring errstr;
if (!builtin_is_valid_varname(dest, errstr, argv[0])) {
streams.err.append(errstr);
builtin_print_help(parser, streams, argv[0], streams.err);
return 1;
}
if ((bad_char = wcsvarname(dest))) {
streams.err.append_format(BUILTIN_ERR_VARCHAR, argv[0], *bad_char);
builtin_print_help(parser, streams, argv[0], streams.err);
free(dest);
return 1;
return STATUS_BUILTIN_ERROR;
}
// Set assignment can work in two modes, either using slices or using the whole array. We detect
@@ -633,7 +617,7 @@ int builtin_set(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
free(dest);
if (retcode == STATUS_BUILTIN_OK && preserve_incoming_failure_exit_status)
if (retcode == STATUS_BUILTIN_OK && preserve_failure_exit_status)
retcode = incoming_exit_status;
return retcode;
}

View File

@@ -77,13 +77,13 @@ int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
// Parse options to obtain the requested operation and the modifiers.
w.woptind = 0;
while (1) {
int c = w.wgetopt_long(argc, argv, short_options, long_options, 0);
int opt = w.wgetopt_long(argc, argv, short_options, long_options, 0);
if (c == -1) {
if (opt == -1) {
break;
}
switch (c) {
switch (opt) {
case 0: {
break;
}
@@ -110,6 +110,10 @@ int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
case '?': {
return STATUS_BUILTIN_ERROR;
}
default: {
DIE("unexpected opt");
break;
}
}
}
@@ -159,19 +163,17 @@ int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
builtin_set_color_output.clear();
output_set_writer(set_color_builtin_outputter);
if (bold) {
if (enter_bold_mode) writembs(tparm(enter_bold_mode));
if (bold && enter_bold_mode) {
writembs(tparm(enter_bold_mode));
}
if (underline) {
if (enter_underline_mode) writembs(enter_underline_mode);
if (underline && enter_underline_mode) {
writembs(enter_underline_mode);
}
if (bgcolor != NULL) {
if (bg.is_normal()) {
write_color(rgb_color_t::black(), false /* not is_fg */);
writembs(tparm(exit_attribute_mode));
}
if (bgcolor != NULL && bg.is_normal()) {
write_color(rgb_color_t::black(), false /* not is_fg */);
writembs(tparm(exit_attribute_mode));
}
if (!fg.is_none()) {
@@ -188,10 +190,8 @@ int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
}
}
if (bgcolor != NULL) {
if (!bg.is_normal() && !bg.is_reset()) {
write_color(bg, false /* not is_fg */);
}
if (bgcolor != NULL && !bg.is_normal() && !bg.is_reset()) {
write_color(bg, false /* not is_fg */);
}
// Restore saved writer function.

View File

@@ -100,12 +100,13 @@ static int string_escape(parser_t &parser, io_streams_t &streams, int argc, wcha
escape_flags_t flags = ESCAPE_ALL;
wgetopter_t w;
for (;;) {
int c = w.wgetopt_long(argc, argv, short_options, long_options, 0);
int opt = w.wgetopt_long(argc, argv, short_options, long_options, 0);
if (c == -1) {
if (opt == -1) {
break;
}
switch (c) {
switch (opt) {
case 0: {
break;
}
@@ -117,6 +118,10 @@ static int string_escape(parser_t &parser, io_streams_t &streams, int argc, wcha
string_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
return BUILTIN_STRING_ERROR;
}
default: {
DIE("unexpected opt");
break;
}
}
}
@@ -145,11 +150,13 @@ static int string_join(parser_t &parser, io_streams_t &streams, int argc, wchar_
bool quiet = false;
wgetopter_t w;
for (;;) {
int c = w.wgetopt_long(argc, argv, short_options, long_options, 0);
if (c == -1) {
int opt = w.wgetopt_long(argc, argv, short_options, long_options, 0);
if (opt == -1) {
break;
}
switch (c) {
switch (opt) {
case 0: {
break;
}
@@ -161,6 +168,10 @@ static int string_join(parser_t &parser, io_streams_t &streams, int argc, wchar_
string_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
return BUILTIN_STRING_ERROR;
}
default: {
DIE("unexpected opt");
break;
}
}
}
@@ -202,12 +213,12 @@ static int string_length(parser_t &parser, io_streams_t &streams, int argc, wcha
bool quiet = false;
wgetopter_t w;
for (;;) {
int c = w.wgetopt_long(argc, argv, short_options, long_options, 0);
int opt = w.wgetopt_long(argc, argv, short_options, long_options, 0);
if (c == -1) {
if (opt == -1) {
break;
}
switch (c) {
switch (opt) {
case 0: {
break;
}
@@ -219,6 +230,10 @@ static int string_length(parser_t &parser, io_streams_t &streams, int argc, wcha
string_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
return BUILTIN_STRING_ERROR;
}
default: {
DIE("unexpected opt");
break;
}
}
}
@@ -499,12 +514,12 @@ static int string_match(parser_t &parser, io_streams_t &streams, int argc, wchar
bool regex = false;
wgetopter_t w;
for (;;) {
int c = w.wgetopt_long(argc, argv, short_options, long_options, 0);
int opt = w.wgetopt_long(argc, argv, short_options, long_options, 0);
if (c == -1) {
if (opt == -1) {
break;
}
switch (c) {
switch (opt) {
case 0: {
break;
}
@@ -536,6 +551,10 @@ static int string_match(parser_t &parser, io_streams_t &streams, int argc, wchar
string_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
return BUILTIN_STRING_ERROR;
}
default: {
DIE("unexpected opt");
break;
}
}
}
@@ -666,59 +685,63 @@ class regex_replacer_t : public string_replacer_t {
regex(argv0, pattern, opts.ignore_case, streams),
replacement(interpret_escapes(replacement_)) {}
bool replace_matches(const wchar_t *arg) {
// A return value of true means all is well (even if no replacements were performed), false
// indicates an unrecoverable error.
if (regex.code == 0) {
// pcre2_compile() failed
return false;
}
uint32_t options = PCRE2_SUBSTITUTE_OVERFLOW_LENGTH | PCRE2_SUBSTITUTE_EXTENDED |
(opts.all ? PCRE2_SUBSTITUTE_GLOBAL : 0);
size_t arglen = wcslen(arg);
PCRE2_SIZE bufsize = (arglen == 0) ? 16 : 2 * arglen;
wchar_t *output = (wchar_t *)malloc(sizeof(wchar_t) * bufsize);
int pcre2_rc = 0;
for (;;) {
if (output == NULL) {
DIE_MEM();
}
PCRE2_SIZE outlen = bufsize;
pcre2_rc = pcre2_substitute(regex.code, PCRE2_SPTR(arg), arglen,
0, // start offset
options, regex.match,
0, // match context
PCRE2_SPTR(replacement.c_str()), PCRE2_ZERO_TERMINATED,
(PCRE2_UCHAR *)output, &outlen);
if (pcre2_rc == PCRE2_ERROR_NOMEMORY && bufsize < outlen) {
bufsize = outlen;
// cppcheck-suppress memleakOnRealloc
output = (wchar_t *)realloc(output, sizeof(wchar_t) * bufsize);
continue;
}
break;
}
bool rc = true;
if (pcre2_rc < 0) {
string_error(streams, _(L"%ls: Regular expression substitute error: %ls\n"), argv0,
pcre2_strerror(pcre2_rc).c_str());
rc = false;
} else {
if (!opts.quiet) {
streams.out.append(output);
streams.out.append(L'\n');
}
total_replaced += pcre2_rc;
}
free(output);
return rc;
}
bool replace_matches(const wchar_t *arg);
};
/// A return value of true means all is well (even if no replacements were performed), false
/// indicates an unrecoverable error.
bool regex_replacer_t::replace_matches(const wchar_t *arg) {
if (regex.code == 0) {
// pcre2_compile() failed
return false;
}
uint32_t options = PCRE2_SUBSTITUTE_OVERFLOW_LENGTH | PCRE2_SUBSTITUTE_EXTENDED |
(opts.all ? PCRE2_SUBSTITUTE_GLOBAL : 0);
size_t arglen = wcslen(arg);
PCRE2_SIZE bufsize = (arglen == 0) ? 16 : 2 * arglen;
wchar_t *output = (wchar_t *)malloc(sizeof(wchar_t) * bufsize);
int pcre2_rc;
bool done = false;
while (!done) {
if (output == NULL) {
DIE_MEM();
}
PCRE2_SIZE outlen = bufsize;
pcre2_rc = pcre2_substitute(regex.code, PCRE2_SPTR(arg), arglen,
0, // start offset
options, regex.match,
0, // match context
PCRE2_SPTR(replacement.c_str()), PCRE2_ZERO_TERMINATED,
(PCRE2_UCHAR *)output, &outlen);
if (pcre2_rc != PCRE2_ERROR_NOMEMORY || bufsize >= outlen) {
done = true;
} else {
bufsize = outlen;
wchar_t *new_output = (wchar_t *)realloc(output, sizeof(wchar_t) * bufsize);
if (new_output) output = new_output;
}
}
bool rc = true;
if (pcre2_rc < 0) {
string_error(streams, _(L"%ls: Regular expression substitute error: %ls\n"), argv0,
pcre2_strerror(pcre2_rc).c_str());
rc = false;
} else {
if (!opts.quiet) {
streams.out.append(output);
streams.out.append(L'\n');
}
total_replaced += pcre2_rc;
}
free(output);
return rc;
}
static int string_replace(parser_t &parser, io_streams_t &streams, int argc, wchar_t **argv) {
const wchar_t *short_options = L"aiqr";
const struct woption long_options[] = {{L"all", no_argument, 0, 'a'},
@@ -731,12 +754,12 @@ static int string_replace(parser_t &parser, io_streams_t &streams, int argc, wch
bool regex = false;
wgetopter_t w;
for (;;) {
int c = w.wgetopt_long(argc, argv, short_options, long_options, 0);
int opt = w.wgetopt_long(argc, argv, short_options, long_options, 0);
if (c == -1) {
if (opt == -1) {
break;
}
switch (c) {
switch (opt) {
case 0: {
break;
}
@@ -760,6 +783,10 @@ static int string_replace(parser_t &parser, io_streams_t &streams, int argc, wch
string_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
return BUILTIN_STRING_ERROR;
}
default: {
DIE("unexpected opt");
break;
}
}
}
@@ -851,10 +878,8 @@ static int string_split(parser_t &parser, io_streams_t &streams, int argc, wchar
break;
}
case 'm': {
errno = 0;
wchar_t *endptr = 0;
max = wcstol(w.woptarg, &endptr, 10);
if (*endptr != L'\0' || errno != 0) {
max = fish_wcstol(w.woptarg);
if (errno) {
string_error(streams, BUILTIN_ERR_NOT_NUMBER, argv[0], w.woptarg);
return BUILTIN_STRING_ERROR;
}
@@ -876,6 +901,10 @@ static int string_split(parser_t &parser, io_streams_t &streams, int argc, wchar
string_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
return BUILTIN_STRING_ERROR;
}
default: {
DIE("unexpected opt");
break;
}
}
}
@@ -938,7 +967,7 @@ static int string_sub(parser_t &parser, io_streams_t &streams, int argc, wchar_t
long length = -1;
bool quiet = false;
wgetopter_t w;
wchar_t *endptr = NULL;
for (;;) {
int c = w.wgetopt_long(argc, argv, short_options, long_options, 0);
@@ -950,16 +979,14 @@ static int string_sub(parser_t &parser, io_streams_t &streams, int argc, wchar_t
break;
}
case 'l': {
errno = 0;
length = wcstol(w.woptarg, &endptr, 10);
if (*endptr != L'\0' || (errno != 0 && errno != ERANGE)) {
string_error(streams, BUILTIN_ERR_NOT_NUMBER, argv[0], w.woptarg);
return BUILTIN_STRING_ERROR;
}
length = fish_wcstol(w.woptarg);
if (length < 0 || errno == ERANGE) {
string_error(streams, _(L"%ls: Invalid length value '%ls'\n"), argv[0],
w.woptarg);
return BUILTIN_STRING_ERROR;
} else if (errno) {
string_error(streams, BUILTIN_ERR_NOT_NUMBER, argv[0], w.woptarg);
return BUILTIN_STRING_ERROR;
}
break;
}
@@ -968,16 +995,14 @@ static int string_sub(parser_t &parser, io_streams_t &streams, int argc, wchar_t
break;
}
case 's': {
errno = 0;
start = wcstol(w.woptarg, &endptr, 10);
if (*endptr != L'\0' || (errno != 0 && errno != ERANGE)) {
string_error(streams, BUILTIN_ERR_NOT_NUMBER, argv[0], w.woptarg);
return BUILTIN_STRING_ERROR;
}
start = fish_wcstol(w.woptarg);
if (start == 0 || start == LONG_MIN || errno == ERANGE) {
string_error(streams, _(L"%ls: Invalid start value '%ls'\n"), argv[0],
w.woptarg);
return BUILTIN_STRING_ERROR;
} else if (errno) {
string_error(streams, BUILTIN_ERR_NOT_NUMBER, argv[0], w.woptarg);
return BUILTIN_STRING_ERROR;
}
break;
}
@@ -989,6 +1014,10 @@ static int string_sub(parser_t &parser, io_streams_t &streams, int argc, wchar_t
string_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
return BUILTIN_STRING_ERROR;
}
default: {
DIE("unexpected opt");
break;
}
}
}
@@ -1078,6 +1107,10 @@ static int string_trim(parser_t &parser, io_streams_t &streams, int argc, wchar_
string_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
return BUILTIN_STRING_ERROR;
}
default: {
DIE("unexpected opt");
break;
}
}
}
@@ -1124,7 +1157,8 @@ static int string_trim(parser_t &parser, io_streams_t &streams, int argc, wchar_
static const struct string_subcommand {
const wchar_t *name;
int (*handler)(parser_t &, io_streams_t &, int argc, wchar_t **argv);
int (*handler)(parser_t &, io_streams_t &, int argc, //!OCLINT(unused param)
wchar_t **argv); //!OCLINT(unused param)
}
string_subcommands[] = {

View File

@@ -518,8 +518,8 @@ expression *test_parser::parse_expression(unsigned int start, unsigned int end)
unsigned int argc = end - start;
switch (argc) {
case 0: {
assert(0); // should have been caught by the above test
return NULL;
DIE("argc should not be zero"); // should have been caught by the above test
break;
}
case 1: {
return error(L"Missing argument at index %u", start + 1);
@@ -579,62 +579,55 @@ bool binary_primary::evaluate(wcstring_list_t &errors) {
}
bool unary_operator::evaluate(wcstring_list_t &errors) {
switch (token) {
case test_bang: {
assert(subject.get());
return !subject->evaluate(errors);
}
default: {
errors.push_back(format_string(L"Unknown token type in %s", __func__));
return false;
}
if (token == test_bang) {
assert(subject.get());
return !subject->evaluate(errors);
}
errors.push_back(format_string(L"Unknown token type in %s", __func__));
return false;
}
bool combining_expression::evaluate(wcstring_list_t &errors) {
switch (token) {
case test_combine_and:
case test_combine_or: {
// One-element case.
if (subjects.size() == 1) return subjects.at(0)->evaluate(errors);
if (token == test_combine_and || token == test_combine_or) {
assert(!subjects.empty()); //!OCLINT(multiple unary operator)
assert(combiners.size() + 1 == subjects.size());
// Evaluate our lists, remembering that AND has higher precedence than OR. We can
// visualize this as a sequence of OR expressions of AND expressions.
assert(combiners.size() + 1 == subjects.size());
assert(!subjects.empty());
// One-element case.
if (subjects.size() == 1) return subjects.at(0)->evaluate(errors);
size_t idx = 0, max = subjects.size();
bool or_result = false;
while (idx < max) {
if (or_result) { // short circuit
// Evaluate our lists, remembering that AND has higher precedence than OR. We can
// visualize this as a sequence of OR expressions of AND expressions.
size_t idx = 0, max = subjects.size();
bool or_result = false;
while (idx < max) {
if (or_result) { // short circuit
break;
}
// Evaluate a stream of AND starting at given subject index. It may only have one
// element.
bool and_result = true;
for (; idx < max; idx++) {
// Evaluate it, short-circuiting.
and_result = and_result && subjects.at(idx)->evaluate(errors);
// If the combiner at this index (which corresponding to how we combine with the
// next subject) is not AND, then exit the loop.
if (idx + 1 < max && combiners.at(idx) != test_combine_and) {
idx++;
break;
}
// Evaluate a stream of AND starting at given subject index. It may only have one
// element.
bool and_result = true;
for (; idx < max; idx++) {
// Evaluate it, short-circuiting.
and_result = and_result && subjects.at(idx)->evaluate(errors);
// If the combiner at this index (which corresponding to how we combine with the
// next subject) is not AND, then exit the loop.
if (idx + 1 < max && combiners.at(idx) != test_combine_and) {
idx++;
break;
}
}
// OR it in.
or_result = or_result || and_result;
}
return or_result;
}
default: {
errors.push_back(format_string(L"Unknown token type in %s", __func__));
return BUILTIN_TEST_FAIL;
// OR it in.
or_result = or_result || and_result;
}
return or_result;
}
errors.push_back(format_string(L"Unknown token type in %s", __func__));
return BUILTIN_TEST_FAIL;
}
bool parenthetical_expression::evaluate(wcstring_list_t &errors) {
@@ -798,42 +791,36 @@ int builtin_test(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
// Collect the arguments into a list.
const wcstring_list_t args(argv + 1, argv + 1 + argc);
switch (argc) {
case 0: {
// Per 1003.1, exit false.
return BUILTIN_TEST_FAIL;
}
case 1: {
// Per 1003.1, exit true if the arg is non-empty.
return args.at(0).empty() ? BUILTIN_TEST_FAIL : BUILTIN_TEST_SUCCESS;
}
default: {
// Try parsing. If expr is not nil, we are responsible for deleting it.
wcstring err;
expression *expr = test_parser::parse_args(args, err);
if (!expr) {
#if 0
printf("Oops! test was given args:\n");
for (size_t i=0; i < argc; i++) {
printf("\t%ls\n", args.at(i).c_str());
}
printf("and returned parse error: %ls\n", err.c_str());
#endif
streams.err.append(err);
return BUILTIN_TEST_FAIL;
}
if (argc == 0) {
return BUILTIN_TEST_FAIL; // Per 1003.1, exit false.
} else if (argc == 1) {
// Per 1003.1, exit true if the arg is non-empty.
return args.at(0).empty() ? BUILTIN_TEST_FAIL : BUILTIN_TEST_SUCCESS;
}
wcstring_list_t eval_errors;
bool result = expr->evaluate(eval_errors);
if (!eval_errors.empty()) {
printf("test returned eval errors:\n");
for (size_t i = 0; i < eval_errors.size(); i++) {
printf("\t%ls\n", eval_errors.at(i).c_str());
}
}
delete expr;
return result ? BUILTIN_TEST_SUCCESS : BUILTIN_TEST_FAIL;
// Try parsing. If expr is not nil, we are responsible for deleting it.
wcstring err;
expression *expr = test_parser::parse_args(args, err);
if (!expr) {
#if 0
printf("Oops! test was given args:\n");
for (size_t i=0; i < argc; i++) {
printf("\t%ls\n", args.at(i).c_str());
}
printf("and returned parse error: %ls\n", err.c_str());
#endif
streams.err.append(err);
return BUILTIN_TEST_FAIL;
}
wcstring_list_t eval_errors;
bool result = expr->evaluate(eval_errors);
if (!eval_errors.empty()) {
printf("test returned eval errors:\n");
for (size_t i = 0; i < eval_errors.size(); i++) {
printf("\t%ls\n", eval_errors.at(i).c_str());
}
}
return 1;
delete expr;
return result ? BUILTIN_TEST_SUCCESS : BUILTIN_TEST_FAIL;
}

View File

@@ -2,13 +2,14 @@
#include "config.h" // IWYU pragma: keep
#include <errno.h>
#include <stddef.h>
#include <sys/resource.h>
#include <wchar.h>
#include "builtin.h"
#include "common.h"
#include "fallback.h" // IWYU pragma: keep
#include "io.h"
#include "proc.h"
#include "util.h"
#include "wgetopt.h"
#include "wutil.h" // IWYU pragma: keep
@@ -120,14 +121,11 @@ static const wchar_t *get_desc(int what) {
/// Set the new value of the specified resource limit. This function does _not_ multiply the limit
// value by the multiplier constant used by the commandline ulimit.
static int set(int resource, int hard, int soft, rlim_t value, io_streams_t &streams) {
static int set_limit(int resource, int hard, int soft, rlim_t value, io_streams_t &streams) {
struct rlimit ls;
getrlimit(resource, &ls);
if (hard) {
ls.rlim_max = value;
}
if (hard) ls.rlim_max = value;
if (soft) {
ls.rlim_cur = value;
@@ -139,185 +137,169 @@ static int set(int resource, int hard, int soft, rlim_t value, io_streams_t &str
}
if (setrlimit(resource, &ls)) {
if (errno == EPERM)
if (errno == EPERM) {
streams.err.append_format(
L"ulimit: Permission denied when changing resource of type '%ls'\n",
get_desc(resource));
else
} else {
builtin_wperror(L"ulimit", streams);
return 1;
}
return STATUS_BUILTIN_ERROR;
}
return 0;
return STATUS_BUILTIN_OK;
}
/// The ulimit builtin, used for setting resource limits.
int builtin_ulimit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wgetopter_t w;
int hard = 0;
int soft = 0;
int what = RLIMIT_FSIZE;
int report_all = 0;
wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
bool report_all = false;
bool hard = false;
bool soft = false;
int what = RLIMIT_FSIZE;
w.woptind = 0;
while (1) {
static const struct woption long_options[] = {
{L"all", no_argument, 0, 'a'},
{L"hard", no_argument, 0, 'H'},
{L"soft", no_argument, 0, 'S'},
{L"core-size", no_argument, 0, 'c'},
{L"data-size", no_argument, 0, 'd'},
{L"file-size", no_argument, 0, 'f'},
{L"lock-size", no_argument, 0, 'l'},
{L"resident-set-size", no_argument, 0, 'm'},
{L"file-descriptor-count", no_argument, 0, 'n'},
{L"stack-size", no_argument, 0, 's'},
{L"cpu-time", no_argument, 0, 't'},
{L"process-count", no_argument, 0, 'u'},
{L"virtual-memory-size", no_argument, 0, 'v'},
{L"help", no_argument, 0, 'h'},
{0, 0, 0, 0}};
int opt_index = 0;
int opt = w.wgetopt_long(argc, argv, L"aHScdflmnstuvh", long_options, &opt_index);
if (opt == -1) break;
const wchar_t *short_options = L":HSacdflmnstuvh";
const struct woption long_options[] = {{L"all", no_argument, NULL, 'a'},
{L"hard", no_argument, NULL, 'H'},
{L"soft", no_argument, NULL, 'S'},
{L"core-size", no_argument, NULL, 'c'},
{L"data-size", no_argument, NULL, 'd'},
{L"file-size", no_argument, NULL, 'f'},
{L"lock-size", no_argument, NULL, 'l'},
{L"resident-set-size", no_argument, NULL, 'm'},
{L"file-descriptor-count", no_argument, NULL, 'n'},
{L"stack-size", no_argument, NULL, 's'},
{L"cpu-time", no_argument, NULL, 't'},
{L"process-count", no_argument, NULL, 'u'},
{L"virtual-memory-size", no_argument, NULL, 'v'},
{L"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}};
int opt;
wgetopter_t w;
while ((opt = w.wgetopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
switch (opt) {
case 0: {
if (long_options[opt_index].flag != 0) break;
streams.err.append_format(BUILTIN_ERR_UNKNOWN, argv[0],
long_options[opt_index].name);
builtin_print_help(parser, streams, argv[0], streams.err);
return 1;
}
case L'a': {
report_all = 1;
case 'a': {
report_all = true;
break;
}
case L'H': {
hard = 1;
case 'H': {
hard = true;
break;
}
case L'S': {
soft = 1;
case 'S': {
soft = true;
break;
}
case L'c': {
case 'c': {
what = RLIMIT_CORE;
break;
}
case L'd': {
case 'd': {
what = RLIMIT_DATA;
break;
}
case L'f': {
case 'f': {
what = RLIMIT_FSIZE;
break;
}
#ifdef RLIMIT_MEMLOCK
case L'l': {
case 'l': {
what = RLIMIT_MEMLOCK;
break;
}
#endif
#ifdef RLIMIT_RSS
case L'm': {
case 'm': {
what = RLIMIT_RSS;
break;
}
#endif
case L'n': {
case 'n': {
what = RLIMIT_NOFILE;
break;
}
case L's': {
case 's': {
what = RLIMIT_STACK;
break;
}
case L't': {
case 't': {
what = RLIMIT_CPU;
break;
}
#ifdef RLIMIT_NPROC
case L'u': {
case 'u': {
what = RLIMIT_NPROC;
break;
}
#endif
#ifdef RLIMIT_AS
case L'v': {
case 'v': {
what = RLIMIT_AS;
break;
}
#endif
case L'h': {
builtin_print_help(parser, streams, argv[0], streams.out);
case 'h': {
builtin_print_help(parser, streams, cmd, streams.out);
return 0;
}
case L'?': {
builtin_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
return 1;
case ':': {
streams.err.append_format(BUILTIN_ERR_MISSING, cmd, argv[w.woptind - 1]);
return STATUS_BUILTIN_ERROR;
}
case '?': {
builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1]);
return STATUS_BUILTIN_ERROR;
}
default: {
DIE("unexpected retval from wgetopt_long");
break;
}
}
}
if (report_all) {
if (argc - w.woptind == 0) {
print_all(hard, streams);
} else {
streams.err.append(argv[0]);
streams.err.append(L": Too many arguments\n");
builtin_print_help(parser, streams, argv[0], streams.err);
return 1;
}
return 0;
print_all(hard, streams);
return STATUS_BUILTIN_OK;
}
switch (argc - w.woptind) {
case 0: { // show current limit value
print(what, hard, streams);
break;
}
case 1: { // change current limit value
rlim_t new_limit;
wchar_t *end;
// Set both hard and soft limits if nothing else was specified.
if (!(hard + soft)) {
hard = soft = 1;
}
if (wcscasecmp(argv[w.woptind], L"unlimited") == 0) {
new_limit = RLIM_INFINITY;
} else if (wcscasecmp(argv[w.woptind], L"hard") == 0) {
new_limit = get(what, 1);
} else if (wcscasecmp(argv[w.woptind], L"soft") == 0) {
new_limit = get(what, soft);
} else {
errno = 0;
new_limit = wcstol(argv[w.woptind], &end, 10);
if (errno || *end) {
streams.err.append_format(L"%ls: Invalid limit '%ls'\n", argv[0],
argv[w.woptind]);
builtin_print_help(parser, streams, argv[0], streams.err);
return 1;
}
new_limit *= get_multiplier(what);
}
return set(what, hard, soft, new_limit, streams);
}
default: {
streams.err.append(argv[0]);
streams.err.append(L": Too many arguments\n");
builtin_print_help(parser, streams, argv[0], streams.err);
return 1;
}
int arg_count = argc - w.woptind;
if (arg_count == 0) {
// Show current limit value.
print(what, hard, streams);
return STATUS_BUILTIN_OK;
} else if (arg_count != 1) {
streams.err.append_format(BUILTIN_ERR_TOO_MANY_ARGUMENTS, cmd);
builtin_print_help(parser, streams, cmd, streams.err);
return STATUS_BUILTIN_ERROR;
}
return 0;
// Change current limit value.
if (!hard && !soft) {
// Set both hard and soft limits if neither was specified.
hard = soft = true;
}
rlim_t new_limit;
if (*argv[w.woptind] == L'\0') {
streams.err.append_format(_(L"%ls: New limit cannot be an empty string\n"), cmd);
builtin_print_help(parser, streams, cmd, streams.err);
return STATUS_BUILTIN_ERROR;
} else if (wcscasecmp(argv[w.woptind], L"unlimited") == 0) {
new_limit = RLIM_INFINITY;
} else if (wcscasecmp(argv[w.woptind], L"hard") == 0) {
new_limit = get(what, 1);
} else if (wcscasecmp(argv[w.woptind], L"soft") == 0) {
new_limit = get(what, soft);
} else {
new_limit = fish_wcstol(argv[w.woptind]);
if (errno) {
streams.err.append_format(_(L"%ls: Invalid limit '%ls'\n"), cmd, argv[w.woptind]);
builtin_print_help(parser, streams, cmd, streams.err);
return STATUS_BUILTIN_ERROR;
}
new_limit *= get_multiplier(what);
}
return set_limit(what, hard, soft, new_limit, streams);
}

View File

@@ -96,7 +96,7 @@ class rgb_color_t {
color24_t to_color24() const;
/// Returns whether the color is bold.
bool is_bold() const { return !!(flags & flag_bold); }
bool is_bold() const { return static_cast<bool>(flags & flag_bold); }
/// Set whether the color is bold.
void set_bold(bool x) {
@@ -107,7 +107,7 @@ class rgb_color_t {
}
/// Returns whether the color is underlined.
bool is_underline() const { return !!(flags & flag_underline); }
bool is_underline() const { return static_cast<bool>(flags & flag_underline); }
/// Set whether the color is underlined.
void set_underline(bool x) {

View File

@@ -43,7 +43,7 @@ struct termios shell_modes;
// Note we foolishly assume that pthread_t is just a primitive. But it might be a struct.
static pthread_t main_thread_id = 0;
static bool thread_assertions_configured_for_testing = false;
static bool thread_asserts_cfg_for_testing = false;
wchar_t ellipsis_char;
wchar_t omitted_newline_char;
@@ -56,7 +56,7 @@ int debug_stack_frames = 0; // default number of stack frames to show on debug(
static pid_t initial_pid = 0;
/// Be able to restore the term's foreground process group.
static pid_t initial_foreground_process_group = -1;
static pid_t initial_fg_process_group = -1;
/// This struct maintains the current state of the terminal size. It is updated on demand after
/// receiving a SIGWINCH. Do not touch this struct directly, it's managed with a rwlock. Use
@@ -107,6 +107,7 @@ demangled_backtrace(int max_frames, int skip_levels) {
void __attribute__((noinline))
show_stackframe(const wchar_t msg_level, int frame_count, int skip_levels) {
ASSERT_IS_NOT_FORKED_CHILD();
if (frame_count < 1) return;
// TODO: Decide if this is still needed. I'm commenting it out because it caused me some grief
// while trying to debug a test failure. And the tests run just fine without spurious failures
@@ -115,7 +116,6 @@ show_stackframe(const wchar_t msg_level, int frame_count, int skip_levels) {
// Hack to avoid showing backtraces in the tester.
// if (program_name && !wcscmp(program_name, L"(ignore)")) return;
if (frame_count < 1) frame_count = 999;
debug_shared(msg_level, L"Backtrace:");
std::vector<wcstring> bt = demangled_backtrace(frame_count, skip_levels + 2);
for (int i = 0; (size_t)i < bt.size(); i++) {
@@ -196,15 +196,14 @@ static wcstring str2wcs_internal(const char *in, const size_t in_len) {
// Protect against broken mbrtowc() implementations which attempt to encode UTF-8
// sequences longer than four bytes (e.g., OS X Snow Leopard).
use_encode_direct = true;
} else if (sizeof(wchar_t) == 2 && (in[in_pos] & 0xF8) == 0xF0) {
} else if (sizeof(wchar_t) == 2 && //!OCLINT(constant if expression)
(in[in_pos] & 0xF8) == 0xF0) {
// Assume we are in a UTF-16 environment (e.g., Cygwin) using a UTF-8 encoding.
// The bits set check will be true for a four byte UTF-8 sequence that requires
// two UTF-16 chars. Something that doesn't work with our simple use of mbrtowc().
use_encode_direct = true;
} else {
ret = mbrtowc(&wc, &in[in_pos], in_len - in_pos, &state);
// fprintf(stderr, "WTF in_pos %d ret %d\n", in_pos, ret);
// Determine whether to encode this character with our crazy scheme.
if (wc >= ENCODE_DIRECT_BASE && wc < ENCODE_DIRECT_BASE + 256) {
use_encode_direct = true;
@@ -219,7 +218,8 @@ static wcstring str2wcs_internal(const char *in, const size_t in_len) {
} else if (ret > in_len - in_pos) {
// Other error codes? Terrifying, should never happen.
use_encode_direct = true;
} else if (sizeof(wchar_t) == 2 && wc >= 0xD800 && wc <= 0xDFFF) {
} else if (sizeof(wchar_t) == 2 && wc >= 0xD800 && //!OCLINT(constant if expression)
wc <= 0xDFFF) {
// If we get a surrogate pair char on a UTF-16 system (e.g., Cygwin) then
// it's guaranteed the UTF-8 decoding is wrong so use direct encoding.
use_encode_direct = true;
@@ -227,24 +227,20 @@ static wcstring str2wcs_internal(const char *in, const size_t in_len) {
}
if (use_encode_direct) {
// fprintf(stderr, "WTF use_encode_direct\n");
wc = ENCODE_DIRECT_BASE + (unsigned char)in[in_pos];
result.push_back(wc);
in_pos++;
memset(&state, 0, sizeof state);
} else if (ret == 0) {
// fprintf(stderr, "WTF null byte\n");
// Embedded null byte!
} else if (ret == 0) { // embedded null byte!
result.push_back(L'\0');
in_pos++;
memset(&state, 0, sizeof state);
} else {
// fprintf(stderr, "WTF null byte\n");
// Normal case.
} else { // normal case
result.push_back(wc);
in_pos += ret;
}
}
return result;
}
@@ -286,16 +282,15 @@ std::string wcs2string(const wcstring &input) {
result.reserve(input.size());
mbstate_t state = {};
char converted[MB_LEN_MAX + 1];
char converted[MB_LEN_MAX];
for (size_t i = 0; i < input.size(); i++) {
wchar_t wc = input[i];
if (wc == INTERNAL_SEPARATOR) {
// Do nothing.
; // do nothing
} else if (wc >= ENCODE_DIRECT_BASE && wc < ENCODE_DIRECT_BASE + 256) {
result.push_back(wc - ENCODE_DIRECT_BASE);
} else if (MB_CUR_MAX == 1) // single-byte locale (C/POSIX/ISO-8859)
{
} else if (MB_CUR_MAX == 1) { // single-byte locale (C/POSIX/ISO-8859)
// If `wc` contains a wide character we emit a question-mark.
if (wc & ~0xFF) {
wc = '?';
@@ -305,8 +300,8 @@ std::string wcs2string(const wcstring &input) {
} else {
memset(converted, 0, sizeof converted);
size_t len = wcrtomb(converted, wc, &state);
if (len == (size_t)(-1)) {
debug(1, L"Wide character %d has no narrow representation", wc);
if (len == (size_t)-1) {
debug(1, L"Wide character U+%4X has no narrow representation", wc);
memset(&state, 0, sizeof(state));
} else {
result.append(converted, len);
@@ -332,7 +327,7 @@ static char *wcs2str_internal(const wchar_t *in, char *out) {
while (in[in_pos]) {
if (in[in_pos] == INTERNAL_SEPARATOR) {
// Do nothing.
; // do nothing
} else if (in[in_pos] >= ENCODE_DIRECT_BASE && in[in_pos] < ENCODE_DIRECT_BASE + 256) {
out[out_pos++] = in[in_pos] - ENCODE_DIRECT_BASE;
} else if (MB_CUR_MAX == 1) // single-byte locale (C/POSIX/ISO-8859)
@@ -346,7 +341,7 @@ static char *wcs2str_internal(const wchar_t *in, char *out) {
} else {
size_t len = wcrtomb(&out[out_pos], in[in_pos], &state);
if (len == (size_t)-1) {
debug(1, L"Wide character %d has no narrow representation", in[in_pos]);
debug(1, L"Wide character U+%4X has no narrow representation", in[in_pos]);
memset(&state, 0, sizeof(state));
} else {
out_pos += len;
@@ -359,6 +354,14 @@ static char *wcs2str_internal(const wchar_t *in, char *out) {
return out;
}
/// Test if the character can be encoded using the current locale.
static bool can_be_encoded(wchar_t wc) {
char converted[MB_LEN_MAX];
mbstate_t state = {};
return wcrtomb(converted, wc, &state) != (size_t)-1;
}
wcstring format_string(const wchar_t *format, ...) {
va_list va;
va_start(va, format);
@@ -449,11 +452,11 @@ wchar_t *quote_end(const wchar_t *pos) {
}
void fish_setlocale() {
// Use ellipsis if on known unicode system, otherwise use $.
ellipsis_char = (fish_wcwidth(L'\x2026') > 0) ? L'\x2026' : L'$';
// Use the Unicode "ellipsis" symbol if it can be encoded using the current locale.
ellipsis_char = can_be_encoded(L'\x2026') ? L'\x2026' : L'$';
// U+23CE is the "return" character
omitted_newline_char = (fish_wcwidth(L'\x23CE') > 0) ? L'\x23CE' : L'~';
// Use the Unicode "return" symbol if it can be encoded using the current locale.
omitted_newline_char = can_be_encoded(L'\x23CE') ? L'\x23CE' : L'~';
}
bool contains_internal(const wchar_t *a, int vararg_handle, ...) {
@@ -768,9 +771,9 @@ static void escape_string_internal(const wchar_t *orig_in, size_t in_len, wcstri
assert(orig_in != NULL);
const wchar_t *in = orig_in;
bool escape_all = !!(flags & ESCAPE_ALL);
bool no_quoted = !!(flags & ESCAPE_NO_QUOTED);
bool no_tilde = !!(flags & ESCAPE_NO_TILDE);
bool escape_all = static_cast<bool>(flags & ESCAPE_ALL);
bool no_quoted = static_cast<bool>(flags & ESCAPE_NO_QUOTED);
bool no_tilde = static_cast<bool>(flags & ESCAPE_NO_TILDE);
int need_escape = 0;
int need_complex_escape = 0;
@@ -1117,8 +1120,8 @@ static bool unescape_string_internal(const wchar_t *const input, const size_t in
wcstring result;
result.reserve(input_len);
const bool unescape_special = !!(flags & UNESCAPE_SPECIAL);
const bool allow_incomplete = !!(flags & UNESCAPE_INCOMPLETE);
const bool unescape_special = static_cast<bool>(flags & UNESCAPE_SPECIAL);
const bool allow_incomplete = static_cast<bool>(flags & UNESCAPE_INCOMPLETE);
int bracket_count = 0;
@@ -1220,6 +1223,7 @@ static bool unescape_string_internal(const wchar_t *const input, const size_t in
to_append_or_none = unescape_special ? INTERNAL_SEPARATOR : NOT_A_WCHAR;
break;
}
default: { break; }
}
} else if (mode == mode_single_quotes) {
if (c == L'\\') {
@@ -1297,6 +1301,7 @@ static bool unescape_string_internal(const wchar_t *const input, const size_t in
}
break;
}
default: { break; }
}
}
@@ -1505,7 +1510,7 @@ bool list_contains_string(const wcstring_list_t &list, const wcstring &str) {
}
int create_directory(const wcstring &d) {
int ok = 0;
bool ok = false;
struct stat buf;
int stat_res = 0;
@@ -1514,18 +1519,10 @@ int create_directory(const wcstring &d) {
}
if (stat_res == 0) {
if (S_ISDIR(buf.st_mode)) {
ok = 1;
}
} else {
if (errno == ENOENT) {
wcstring dir = wdirname(d);
if (!create_directory(dir)) {
if (!wmkdir(d, 0700)) {
ok = 1;
}
}
}
if (S_ISDIR(buf.st_mode)) ok = true;
} else if (errno == ENOENT) {
wcstring dir = wdirname(d);
if (!create_directory(dir) && !wmkdir(d, 0700)) ok = true;
}
return ok ? 0 : -1;
@@ -1682,9 +1679,7 @@ __attribute__((noinline)) void debug_thread_error(void) {
void set_main_thread() { main_thread_id = pthread_self(); }
void configure_thread_assertions_for_testing(void) {
thread_assertions_configured_for_testing = true;
}
void configure_thread_assertions_for_testing(void) { thread_asserts_cfg_for_testing = true; }
bool is_forked_child(void) {
// Just bail if nobody's called setup_fork_guards, e.g. some of our tools.
@@ -1704,14 +1699,14 @@ void setup_fork_guards(void) {
}
void save_term_foreground_process_group(void) {
initial_foreground_process_group = tcgetpgrp(STDIN_FILENO);
initial_fg_process_group = tcgetpgrp(STDIN_FILENO);
}
void restore_term_foreground_process_group(void) {
if (initial_foreground_process_group != -1) {
if (initial_fg_process_group != -1) {
// This is called during shutdown and from a signal handler. We don't bother to complain on
// failure.
tcsetpgrp(STDIN_FILENO, initial_foreground_process_group);
tcsetpgrp(STDIN_FILENO, initial_fg_process_group);
}
}
@@ -1721,7 +1716,7 @@ bool is_main_thread() {
}
void assert_is_main_thread(const char *who) {
if (!is_main_thread() && !thread_assertions_configured_for_testing) {
if (!is_main_thread() && !thread_asserts_cfg_for_testing) {
fprintf(stderr,
"Warning: %s called off of main thread. Break on debug_thread_error to debug.\n",
who);
@@ -1739,7 +1734,7 @@ void assert_is_not_forked_child(const char *who) {
}
void assert_is_background_thread(const char *who) {
if (is_main_thread() && !thread_assertions_configured_for_testing) {
if (is_main_thread() && !thread_asserts_cfg_for_testing) {
fprintf(stderr,
"Warning: %s called on the main thread (may block!). Break on debug_thread_error "
"to debug.\n",
@@ -1761,7 +1756,7 @@ void assert_is_locked(void *vmutex, const char *who, const char *caller) {
}
void scoped_lock::lock(void) {
assert(!locked);
assert(!locked); //!OCLINT(multiple unary operator)
ASSERT_IS_NOT_FORKED_CHILD();
VOMIT_ON_FAILURE_NO_ERRNO(pthread_mutex_lock(lock_obj));
locked = true;
@@ -1785,7 +1780,7 @@ scoped_lock::~scoped_lock() {
}
void scoped_rwlock::lock(void) {
assert(!(locked || locked_shared));
assert(!(locked || locked_shared)); //!OCLINT(multiple unary operator)
ASSERT_IS_NOT_FORKED_CHILD();
VOMIT_ON_FAILURE_NO_ERRNO(pthread_rwlock_rdlock(rwlock_obj));
locked = true;
@@ -1799,7 +1794,7 @@ void scoped_rwlock::unlock(void) {
}
void scoped_rwlock::lock_shared(void) {
assert(!(locked || locked_shared));
assert(!(locked || locked_shared)); //!OCLINT(multiple unary operator)
ASSERT_IS_NOT_FORKED_CHILD();
VOMIT_ON_FAILURE_NO_ERRNO(pthread_rwlock_wrlock(rwlock_obj));
locked_shared = true;

View File

@@ -211,6 +211,9 @@ extern bool has_working_tty_timestamps;
}
/// Pause for input, then exit the program. If supported, print a backtrace first.
// The `return` will never be run but silences oclint warnings. Especially when this is called
// from within a `switch` block. As of the time I'm writing this oclint doesn't recognize the
// `__attribute__((noreturn))` on the exit_without_destructors() function.
#define FATAL_EXIT() \
{ \
char exit_read_buff; \
@@ -258,7 +261,7 @@ extern bool has_working_tty_timestamps;
#define contains(str, ...) contains_internal(str, 0, __VA_ARGS__, NULL)
/// Print a stack trace to stderr.
void show_stackframe(const wchar_t msg_level, int frame_count = -1, int skip_levels = 0);
void show_stackframe(const wchar_t msg_level, int frame_count = 100, int skip_levels = 0);
/// Read a line from the stream f into the string. Returns the number of bytes read or -1 on
/// failure.
@@ -775,7 +778,50 @@ long convert_digit(wchar_t d, int base);
(void)(expr); \
} while (0)
#endif
// Return true if the character is in a range reserved for fish's private use.
bool fish_reserved_codepoint(wchar_t c);
/// Used for constructing mappings between enums and strings. The resulting array must be sorted
/// according to the `str` member since str_to_enum() does a binary search. Also the last entry must
/// have NULL for the `str` member and the default value for `val` to be returned if the string
/// isn't found.
template <typename T>
struct enum_map {
T val;
const wchar_t *const str;
};
/// Given a string return the matching enum. Return the sentinal enum if no match is made. The map
/// must be sorted by the `str` member. A binary search is twice as fast as a linear search with 16
/// elements in the map.
template <typename T>
static T str_to_enum(const wchar_t *name, const enum_map<T> map[], int len) {
// Ignore the sentinel value when searching as it is the "not found" value.
size_t left = 0, right = len - 1;
while (left < right) {
size_t mid = left + (right - left) / 2;
int cmp = wcscmp(name, map[mid].str);
if (cmp < 0) {
right = mid; // name was smaller than mid
} else if (cmp > 0) {
left = mid + 1; // name was larger than mid
} else {
return map[mid].val; // found it
}
}
return map[len - 1].val; // return the sentinel value
}
/// Given an enum return the matching string.
template <typename T>
static const wchar_t *enum_to_str(T enum_val, const enum_map<T> map[]) {
for (const enum_map<T> *entry = map; entry->str; entry++) {
if (enum_val == entry->val) {
return entry->str;
}
}
return NULL;
};
#endif

View File

@@ -119,7 +119,7 @@ typedef struct complete_entry_opt {
case option_type_double_long:
return 2;
}
assert(0 && "Unreachable");
DIE("unreachable");
}
} complete_entry_opt_t;
@@ -289,9 +289,11 @@ class completer_t {
return flags & COMPLETION_REQUEST_AUTOSUGGESTION ? COMPLETE_AUTOSUGGEST : COMPLETE_DEFAULT;
}
bool wants_descriptions() const { return !!(flags & COMPLETION_REQUEST_DESCRIPTIONS); }
bool wants_descriptions() const {
return static_cast<bool>(flags & COMPLETION_REQUEST_DESCRIPTIONS);
}
bool fuzzy() const { return !!(flags & COMPLETION_REQUEST_FUZZY_MATCH); }
bool fuzzy() const { return static_cast<bool>(flags & COMPLETION_REQUEST_FUZZY_MATCH); }
fuzzy_match_type_t max_fuzzy_match_type() const {
// If we are doing fuzzy matching, request all types; if not request only prefix matching.
@@ -668,22 +670,22 @@ void completer_t::complete_cmd(const wcstring &str_cmd, bool use_function, bool
std::vector<completion_t> possible_comp;
if (use_command) {
if (expand_string(str_cmd, &this->completions,
EXPAND_SPECIAL_FOR_COMMAND | EXPAND_FOR_COMPLETIONS | EXECUTABLES_ONLY |
this->expand_flags(),
NULL) != EXPAND_ERROR) {
if (this->wants_descriptions()) {
this->complete_cmd_desc(str_cmd);
expand_error_t result = expand_string(str_cmd, &this->completions,
EXPAND_SPECIAL_FOR_COMMAND | EXPAND_FOR_COMPLETIONS |
EXECUTABLES_ONLY | this->expand_flags(),
NULL);
if (result != EXPAND_ERROR && this->wants_descriptions()) {
this->complete_cmd_desc(str_cmd);
}
}
}
if (use_implicit_cd) {
if (!expand_string(str_cmd, &this->completions,
EXPAND_FOR_COMPLETIONS | DIRECTORIES_ONLY | this->expand_flags(),
NULL)) {
// Not valid as implicit cd.
}
// We don't really care if this succeeds or fails. If it succeeds this->completions will be
// updated with choices for the user.
(void)expand_string(str_cmd, &this->completions,
EXPAND_FOR_COMPLETIONS | DIRECTORIES_ONLY | this->expand_flags(), NULL);
}
if (str_cmd.find(L'/') == wcstring::npos && str_cmd.at(0) != L'~') {
if (use_function) {
wcstring_list_t names = function_get_names(str_cmd.at(0) == L'_');
@@ -875,11 +877,10 @@ bool completer_t::complete_param(const wcstring &scmd_orig, const wcstring &spop
if (this->type() == COMPLETE_DEFAULT) {
ASSERT_IS_MAIN_THREAD();
complete_load(cmd, true);
} else if (this->type() == COMPLETE_AUTOSUGGEST) {
// Maybe load this command (on the main thread).
if (!completion_autoloader.has_tried_loading(cmd)) {
iothread_perform_on_main(complete_load_no_reload, &cmd);
}
} else if (this->type() == COMPLETE_AUTOSUGGEST &&
!completion_autoloader.has_tried_loading(cmd)) {
// Load this command (on the main thread).
iothread_perform_on_main(complete_load_no_reload, &cmd);
}
// Make a list of lists of all options that we care about.
@@ -925,13 +926,12 @@ bool completer_t::complete_param(const wcstring &scmd_orig, const wcstring &spop
for (option_list_t::const_iterator oiter = options.begin(); oiter != options.end();
++oiter) {
const complete_entry_opt_t *o = &*oiter;
if (o->type == option_type_single_long) {
if (param_match(o, popt) && this->condition_test(o->condition)) {
old_style_match = true;
if (o->result_mode & NO_COMMON) use_common = false;
if (o->result_mode & NO_FILES) use_files = false;
complete_from_args(str, o->comp, o->localized_desc(), o->flags);
}
if (o->type == option_type_single_long && param_match(o, popt) &&
this->condition_test(o->condition)) {
old_style_match = true;
if (o->result_mode & NO_COMMON) use_common = false;
if (o->result_mode & NO_FILES) use_files = false;
complete_from_args(str, o->comp, o->localized_desc(), o->flags);
}
}
@@ -956,71 +956,73 @@ bool completer_t::complete_param(const wcstring &scmd_orig, const wcstring &spop
}
}
if (use_common) {
for (option_list_t::const_iterator oiter = options.begin(); oiter != options.end();
++oiter) {
const complete_entry_opt_t *o = &*oiter;
// If this entry is for the base command, check if any of the arguments match.
if (!this->condition_test(o->condition)) continue;
if (o->option.empty()) {
use_files = use_files && ((o->result_mode & NO_FILES) == 0);
complete_from_args(str, o->comp, o->localized_desc(), o->flags);
}
if (!use_common) {
continue;
}
if (wcslen(str) > 0 && use_switches) {
// Check if the short style option matches.
if (short_ok(str, o, options)) {
// It's a match.
const wcstring desc = o->localized_desc();
append_completion(&this->completions, o->option, desc, 0);
}
// Check if the long style option matches.
if (o->type == option_type_single_long || o->type == option_type_double_long) {
int match = 0, match_no_case = 0;
wcstring whole_opt(o->expected_dash_count(), L'-');
whole_opt.append(o->option);
match = string_prefixes_string(str, whole_opt);
if (!match) {
match_no_case = wcsncasecmp(str, whole_opt.c_str(), wcslen(str)) == 0;
}
if (match || match_no_case) {
int has_arg = 0; // does this switch have any known arguments
int req_arg = 0; // does this switch _require_ an argument
size_t offset = 0;
complete_flags_t flags = 0;
if (match) {
offset = wcslen(str);
} else {
flags = COMPLETE_REPLACES_TOKEN;
}
has_arg = !o->comp.empty();
req_arg = (o->result_mode & NO_COMMON);
if (o->type == option_type_double_long && (has_arg && !req_arg)) {
// Optional arguments to a switch can only be handled using the '=',
// so we add it as a completion. By default we avoid using '=' and
// instead rely on '--switch switch-arg', since it is more commonly
// supported by homebrew getopt-like functions.
wcstring completion =
format_string(L"%ls=", whole_opt.c_str() + offset);
append_completion(&this->completions, completion, C_(o->desc),
flags);
}
append_completion(&this->completions, whole_opt.c_str() + offset,
C_(o->desc), flags);
}
}
}
for (option_list_t::const_iterator oiter = options.begin(); oiter != options.end();
++oiter) {
const complete_entry_opt_t *o = &*oiter;
// If this entry is for the base command, check if any of the arguments match.
if (!this->condition_test(o->condition)) continue;
if (o->option.empty()) {
use_files = use_files && ((o->result_mode & NO_FILES) == 0);
complete_from_args(str, o->comp, o->localized_desc(), o->flags);
}
if (wcslen(str) == 0 || !use_switches) {
continue;
}
// Check if the short style option matches.
if (short_ok(str, o, options)) {
// It's a match.
const wcstring desc = o->localized_desc();
append_completion(&this->completions, o->option, desc, 0);
}
// Check if the long style option matches.
if (o->type != option_type_single_long && o->type != option_type_double_long) {
continue;
}
int match = 0, match_no_case = 0;
wcstring whole_opt(o->expected_dash_count(), L'-');
whole_opt.append(o->option);
match = string_prefixes_string(str, whole_opt);
if (!match) {
match_no_case = wcsncasecmp(str, whole_opt.c_str(), wcslen(str)) == 0;
}
if (!match && !match_no_case) {
continue;
}
int has_arg = 0; // does this switch have any known arguments
int req_arg = 0; // does this switch _require_ an argument
size_t offset = 0;
complete_flags_t flags = 0;
if (match) {
offset = wcslen(str);
} else {
flags = COMPLETE_REPLACES_TOKEN;
}
has_arg = !o->comp.empty();
req_arg = (o->result_mode & NO_COMMON);
if (o->type == option_type_double_long && (has_arg && !req_arg)) {
// Optional arguments to a switch can only be handled using the '=', so we add it as
// a completion. By default we avoid using '=' and instead rely on '--switch
// switch-arg', since it is more commonly supported by homebrew getopt-like
// functions.
wcstring completion = format_string(L"%ls=", whole_opt.c_str() + offset);
append_completion(&this->completions, completion, C_(o->desc), flags);
}
append_completion(&this->completions, whole_opt.c_str() + offset, C_(o->desc), flags);
}
}
@@ -1144,31 +1146,35 @@ bool completer_t::try_complete_variable(const wcstring &str) {
}
switch (c) {
case L'\\':
case L'\\': {
in_pos++;
break;
case L'$':
}
case L'$': {
if (mode == e_unquoted || mode == e_double_quoted) {
variable_start = in_pos;
}
break;
case L'\'':
}
case L'\'': {
if (mode == e_single_quoted) {
mode = e_unquoted;
} else if (mode == e_unquoted) {
mode = e_single_quoted;
}
break;
case L'"':
}
case L'"': {
if (mode == e_double_quoted) {
mode = e_unquoted;
} else if (mode == e_unquoted) {
mode = e_double_quoted;
}
break;
}
default: {
break; // all other chars ignored here
}
}
}
@@ -1196,50 +1202,52 @@ bool completer_t::try_complete_user(const wcstring &str) {
#else
const wchar_t *cmd = str.c_str();
const wchar_t *first_char = cmd;
int res = 0;
double start_time = timef();
if (*first_char == L'~' && !wcschr(first_char, L'/')) {
const wchar_t *user_name = first_char + 1;
const wchar_t *name_end = wcschr(user_name, L'~');
if (name_end == 0) {
struct passwd *pw;
size_t name_len = wcslen(user_name);
setpwent();
while ((pw = getpwent()) != 0) {
double current_time = timef();
if (current_time - start_time > 0.2) {
return 1;
}
if (pw->pw_name) {
const wcstring pw_name_str = str2wcstring(pw->pw_name);
const wchar_t *pw_name = pw_name_str.c_str();
if (wcsncmp(user_name, pw_name, name_len) == 0) {
wcstring desc = format_string(COMPLETE_USER_DESC, pw_name);
append_completion(&this->completions, &pw_name[name_len], desc,
COMPLETE_NO_SPACE);
res = 1;
} else if (wcsncasecmp(user_name, pw_name, name_len) == 0) {
wcstring name = format_string(L"~%ls", pw_name);
wcstring desc = format_string(COMPLETE_USER_DESC, pw_name);
append_completion(&this->completions, name, desc, COMPLETE_REPLACES_TOKEN |
COMPLETE_DONT_ESCAPE |
COMPLETE_NO_SPACE);
res = 1;
}
}
}
endpwent();
}
if (*first_char != L'~' || wcschr(first_char, L'/')) {
return false;
}
return res;
const wchar_t *user_name = first_char + 1;
const wchar_t *name_end = wcschr(user_name, L'~');
if (name_end) {
return false;
}
double start_time = timef();
bool result = false;
struct passwd *pw;
size_t name_len = wcslen(user_name);
setpwent();
while ((pw = getpwent()) != 0) {
double current_time = timef();
if (current_time - start_time > 0.2) {
return 1;
}
if (!pw->pw_name) {
continue;
}
const wcstring pw_name_str = str2wcstring(pw->pw_name);
const wchar_t *pw_name = pw_name_str.c_str();
if (wcsncmp(user_name, pw_name, name_len) == 0) {
wcstring desc = format_string(COMPLETE_USER_DESC, pw_name);
append_completion(&this->completions, &pw_name[name_len], desc, COMPLETE_NO_SPACE);
result = true;
} else if (wcsncasecmp(user_name, pw_name, name_len) == 0) {
wcstring name = format_string(L"~%ls", pw_name);
wcstring desc = format_string(COMPLETE_USER_DESC, pw_name);
append_completion(&this->completions, name, desc, COMPLETE_REPLACES_TOKEN |
COMPLETE_DONT_ESCAPE |
COMPLETE_NO_SPACE);
result = true;
}
}
endpwent();
return result;
#endif
}
@@ -1534,7 +1542,7 @@ wcstring complete_print() {
break;
}
case option_type_short: {
assert(!o->option.empty());
assert(!o->option.empty()); //!OCLINT(multiple unary operator)
append_format(out, L" --short-option '%lc'", o->option.at(0));
break;
}

View File

@@ -8,15 +8,12 @@
#include <pwd.h>
#include <stddef.h>
#include <stdlib.h>
#ifdef HAVE__NL_MSG_CAT_CNTR
#include <string.h>
#endif
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <wchar.h>
#include <wctype.h>
#include <algorithm>
#include <map>
#include <set>
@@ -283,10 +280,6 @@ static void universal_callback(fish_message_type_t type, const wchar_t *name) {
str = L"ERASE";
break;
}
default: {
assert(0 && "Unhandled fish_message_type_t constant!");
abort();
}
}
if (str) {
@@ -418,10 +411,10 @@ void env_init(const struct config_paths_t *paths /* or NULL */) {
const env_var_t shlvl_str = env_get_string(L"SHLVL");
wcstring nshlvl_str = L"1";
if (!shlvl_str.missing()) {
wchar_t *end;
long shlvl_i = wcstol(shlvl_str.c_str(), &end, 10);
while (iswspace(*end)) ++end; // skip trailing whitespace
if (shlvl_i >= 0 && *end == '\0') {
const wchar_t *end;
// TODO: Figure out how to handle invalid numbers better. Shouldn't we issue a diagnostic?
long shlvl_i = fish_wcstol(shlvl_str.c_str(), &end);
if (!errno && shlvl_i >= 0) {
nshlvl_str = to_string<long>(shlvl_i + 1);
}
}
@@ -476,6 +469,25 @@ static env_node_t *env_get_node(const wcstring &key) {
return env;
}
/// Set the value of the environment variable whose name matches key to val.
///
/// Memory policy: All keys and values are copied, the parameters can and should be freed by the
/// caller afterwards
///
/// \param key The key
/// \param val The value
/// \param var_mode The type of the variable. Can be any combination of ENV_GLOBAL, ENV_LOCAL,
/// ENV_EXPORT and ENV_USER. If mode is zero, the current variable space is searched and the current
/// mode is used. If no current variable with the same name is found, ENV_LOCAL is assumed.
///
/// Returns:
///
/// * ENV_OK on success.
/// * ENV_PERM, can only be returned when setting as a user, e.g. ENV_USER is set. This means that
/// the user tried to change a read-only variable.
/// * ENV_SCOPE, the variable cannot be set in the given scope. This applies to readonly/electric
/// variables set from the local or universal scopes, or set as exported.
/// * ENV_INVALID, the variable value was invalid. This applies only to special variables.
int env_set(const wcstring &key, const wchar_t *val, env_mode_flags_t var_mode) {
ASSERT_IS_MAIN_THREAD();
bool has_changed_old = has_changed_exported;
@@ -501,18 +513,14 @@ int env_set(const wcstring &key, const wchar_t *val, env_mode_flags_t var_mode)
}
if (key == L"umask") {
wchar_t *end;
// Set the new umask.
if (val && wcslen(val)) {
errno = 0;
long mask = wcstol(val, &end, 8);
if (!errno && (!*end) && (mask <= 0777) && (mask >= 0)) {
long mask = fish_wcstol(val, NULL, 8);
if (!errno && mask <= 0777 && mask >= 0) {
umask(mask);
// Do not actually create a umask variable, on env_get, it will be calculated
// dynamically.
return 0;
return ENV_OK;
}
}
@@ -521,7 +529,7 @@ int env_set(const wcstring &key, const wchar_t *val, env_mode_flags_t var_mode)
// Zero element arrays are internaly not coded as null but as this placeholder string.
if (!val) {
val = ENV_NULL;
val = ENV_NULL; //!OCLINT(parameter reassignment)
}
if (var_mode & ENV_UNIVERSAL) {
@@ -566,10 +574,10 @@ int env_set(const wcstring &key, const wchar_t *val, env_mode_flags_t var_mode)
node = top;
} else if (preexisting_node != NULL) {
node = preexisting_node;
if ((var_mode & (ENV_EXPORT | ENV_UNEXPORT)) == 0) {
// use existing entry's exportv
var_mode = preexisting_entry_exportv ? ENV_EXPORT : 0;
var_mode = //!OCLINT(parameter reassignment)
preexisting_entry_exportv ? ENV_EXPORT : 0;
}
} else {
if (!get_proc_had_barrier()) {
@@ -635,7 +643,7 @@ int env_set(const wcstring &key, const wchar_t *val, env_mode_flags_t var_mode)
// debug( 1, L"env_set: return from event firing" );
react_to_variable_change(key);
return 0;
return ENV_OK;
}
/// Attempt to remove/free the specified key/value pair from the specified map.
@@ -713,7 +721,7 @@ int env_remove(const wcstring &key, int var_mode) {
}
const wchar_t *env_var_t::c_str(void) const {
assert(!is_missing);
assert(!is_missing); //!OCLINT(multiple unary operator)
return wcstring::c_str();
}
@@ -864,9 +872,7 @@ void env_push(bool new_scope) {
node->next = top;
node->new_scope = new_scope;
if (new_scope) {
if (local_scope_exports(top)) mark_changed_exported();
}
if (new_scope && local_scope_exports(top)) mark_changed_exported();
top = node;
}
@@ -884,7 +890,7 @@ void env_pop() {
}
}
if (killme->new_scope) {
if (killme->new_scope) { //!OCLINT(collapsible if statements)
if (killme->exportv || local_scope_exports(killme->next)) mark_changed_exported();
}

View File

@@ -36,8 +36,8 @@ enum {
};
typedef uint32_t env_mode_flags_t;
/// Error code for trying to alter read-only variable.
enum { ENV_PERM = 1, ENV_SCOPE, ENV_INVALID };
/// Return values for `env_set()`.
enum { ENV_OK, ENV_PERM, ENV_SCOPE, ENV_INVALID };
/// A struct of configuration directories, determined in main() that fish will optionally pass to
/// env_init.
@@ -51,26 +51,6 @@ struct config_paths_t {
/// Initialize environment variable data.
void env_init(const struct config_paths_t *paths = NULL);
/// Set the value of the environment variable whose name matches key to val.
///
/// Memory policy: All keys and values are copied, the parameters can and should be freed by the
/// caller afterwards
///
/// \param key The key
/// \param val The value
/// \param mode The type of the variable. Can be any combination of ENV_GLOBAL, ENV_LOCAL,
/// ENV_EXPORT and ENV_USER. If mode is zero, the current variable space is searched and the current
/// mode is used. If no current variable with the same name is found, ENV_LOCAL is assumed.
///
/// \returns 0 on success or an error code on failiure.
///
/// The current error codes are:
///
/// * ENV_PERM, can only be returned when setting as a user, e.g. ENV_USER is set. This means that
/// the user tried to change a read-only variable.
/// * ENV_SCOPE, the variable cannot be set in the given scope. This applies to readonly/electric
/// variables set from the local or universal scopes, or set as exported.
/// * ENV_INVALID, the variable value was invalid. This applies only to special variables.
int env_set(const wcstring &key, const wchar_t *val, env_mode_flags_t mode);
class env_var_t : public wcstring {

View File

@@ -17,7 +17,6 @@
#include <sys/types.h>
#include <unistd.h>
#include <wchar.h>
#include <wctype.h>
#include <string>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
@@ -231,7 +230,7 @@ static bool append_file_entry(fish_message_type_t type, const wcstring &key_in,
result->push_back(' ');
// Append variable name like "fish_color_cwd".
if (wcsvarname(key_in.c_str())) {
if (wcsvarname(key_in)) {
debug(0, L"Illegal variable name: '%ls'", key_in.c_str());
success = false;
}
@@ -930,23 +929,24 @@ static bool get_mac_address(unsigned char macaddr[MAC_ADDRESS_MAX_LEN],
struct ifaddrs *ifap;
bool ok = false;
if (getifaddrs(&ifap) == 0) {
for (const ifaddrs *p = ifap; p; p = p->ifa_next) {
if (p->ifa_addr && p->ifa_addr->sa_family == AF_LINK) {
if (p->ifa_name && p->ifa_name[0] &&
!strcmp((const char *)p->ifa_name, interface)) {
const sockaddr_dl &sdl = *reinterpret_cast<sockaddr_dl *>(p->ifa_addr);
size_t alen = sdl.sdl_alen;
if (alen > MAC_ADDRESS_MAX_LEN) alen = MAC_ADDRESS_MAX_LEN;
memcpy(macaddr, sdl.sdl_data + sdl.sdl_nlen, alen);
ok = true;
break;
}
}
}
freeifaddrs(ifap);
if (getifaddrs(&ifap) != 0) {
return ok;
}
for (const ifaddrs *p = ifap; p; p = p->ifa_next) {
bool is_af_link = p->ifa_addr && p->ifa_addr->sa_family == AF_LINK;
if (is_af_link && p->ifa_name && p->ifa_name[0] &&
!strcmp((const char *)p->ifa_name, interface)) {
const sockaddr_dl &sdl = *reinterpret_cast<sockaddr_dl *>(p->ifa_addr);
size_t alen = sdl.sdl_alen;
if (alen > MAC_ADDRESS_MAX_LEN) alen = MAC_ADDRESS_MAX_LEN;
memcpy(macaddr, sdl.sdl_data + sdl.sdl_nlen, alen);
ok = true;
break;
}
}
freeifaddrs(ifap);
return ok;
}
@@ -978,11 +978,8 @@ wcstring get_machine_identifier() {
for (size_t i = 0; i < MAC_ADDRESS_MAX_LEN; i++) {
append_format(result, L"%02x", mac_addr[i]);
}
} else if (get_hostname_identifier(&result)) {
// Hooray
} else {
// Fallback
result.assign(L"nohost");
} else if (!get_hostname_identifier(&result)) {
result.assign(L"nohost"); // fallback to a dummy value
}
return result;
}
@@ -1033,12 +1030,11 @@ class universal_notifier_shmem_poller_t : public universal_notifier_t {
}
// Set the size, if it's too small.
if (!errored && size < (off_t)sizeof(universal_notifier_shmem_t)) {
if (ftruncate(fd, sizeof(universal_notifier_shmem_t)) < 0) {
int err = errno;
report_error(err, L"Unable to truncate shared memory object with path '%s'", path);
errored = true;
}
bool set_size = !errored && size < (off_t)sizeof(universal_notifier_shmem_t);
if (set_size && ftruncate(fd, sizeof(universal_notifier_shmem_t)) < 0) {
int err = errno;
report_error(err, L"Unable to truncate shared memory object with path '%s'", path);
errored = true;
}
// Memory map the region.
@@ -1074,7 +1070,7 @@ class universal_notifier_shmem_poller_t : public universal_notifier_t {
void post_notification() {
if (region != NULL) {
/* Read off the seed */
uint32_t seed = ntohl(region->universal_variable_seed);
uint32_t seed = ntohl(region->universal_variable_seed); //!OCLINT(constant cond op)
// Increment it. Don't let it wrap to zero.
do {
@@ -1083,9 +1079,9 @@ class universal_notifier_shmem_poller_t : public universal_notifier_t {
last_seed = seed;
// Write out our data.
region->magic = htonl(SHMEM_MAGIC_NUMBER);
region->version = htonl(SHMEM_VERSION_CURRENT);
region->universal_variable_seed = htonl(seed);
region->magic = htonl(SHMEM_MAGIC_NUMBER); //!OCLINT(constant cond op)
region->version = htonl(SHMEM_VERSION_CURRENT); //!OCLINT(constant cond op)
region->universal_variable_seed = htonl(seed); //!OCLINT(constant cond op)
}
}
@@ -1106,7 +1102,7 @@ class universal_notifier_shmem_poller_t : public universal_notifier_t {
bool poll() {
bool result = false;
if (region != NULL) {
uint32_t seed = ntohl(region->universal_variable_seed);
uint32_t seed = ntohl(region->universal_variable_seed); //!OCLINT(constant cond op)
if (seed != last_seed) {
result = true;
last_seed = seed;
@@ -1237,10 +1233,12 @@ class universal_notifier_named_pipe_t : public universal_notifier_t {
int fd = wopen_cloexec(vars_path, O_RDWR | O_NONBLOCK, 0600);
if (fd < 0 && errno == ENOENT) {
// File doesn't exist, try creating it.
if (mkfifo(narrow_path.c_str(), 0600) >= 0) {
int mkfifo_status = mkfifo(narrow_path.c_str(), 0600);
if (mkfifo_status != -1) {
fd = wopen_cloexec(vars_path, O_RDWR | O_NONBLOCK, 0600);
}
}
if (fd < 0) {
// Maybe open failed, maybe mkfifo failed.
int err = errno;
@@ -1314,13 +1312,11 @@ class universal_notifier_named_pipe_t : public universal_notifier_t {
if (pipe_fd >= 0) {
// We need to write some data (any data) to the pipe, then wait for a while, then read
// it back. Nobody is expected to read it except us.
int pid_nbo = htonl(getpid());
int pid_nbo = htonl(getpid()); //!OCLINT(constant cond op)
ssize_t amt_written = write(this->pipe_fd, &pid_nbo, sizeof pid_nbo);
if (amt_written < 0) {
if (errno == EWOULDBLOCK || errno == EAGAIN) {
// Very unsual: the pipe is full!
drain_excessive_data();
}
if (amt_written < 0 && (errno == EWOULDBLOCK || errno == EAGAIN)) {
// Very unsual: the pipe is full!
drain_excessive_data();
}
// Now schedule a read for some time in the future.
@@ -1358,8 +1354,6 @@ class universal_notifier_named_pipe_t : public universal_notifier_t {
}
bool poll() {
bool result = false;
// Check if we are past the readback time.
if (this->readback_time_usec > 0 && get_time() >= this->readback_time_usec) {
// Read back what we wrote. We do nothing with the value.
@@ -1374,30 +1368,29 @@ class universal_notifier_named_pipe_t : public universal_notifier_t {
}
// Check to see if we are doing readability polling.
if (polling_due_to_readable_fd && pipe_fd >= 0) {
// We are polling, so we are definitely going to sync.
result = true;
// See if this is still readable.
fd_set fds;
FD_ZERO(&fds);
FD_SET(this->pipe_fd, &fds);
struct timeval timeout = {};
select(this->pipe_fd + 1, &fds, NULL, NULL, &timeout);
if (!FD_ISSET(this->pipe_fd, &fds)) {
// No longer readable, no longer polling.
polling_due_to_readable_fd = false;
drain_if_still_readable_time_usec = 0;
} else {
// Still readable. If it's been readable for a long time, there is probably
// lingering data on the pipe.
if (get_time() >= drain_if_still_readable_time_usec) {
drain_excessive_data();
}
}
if (!polling_due_to_readable_fd || pipe_fd < 0) {
return false;
}
return result;
// We are polling, so we are definitely going to sync.
// See if this is still readable.
fd_set fds;
FD_ZERO(&fds);
FD_SET(this->pipe_fd, &fds);
struct timeval timeout = {};
select(this->pipe_fd + 1, &fds, NULL, NULL, &timeout);
if (!FD_ISSET(this->pipe_fd, &fds)) {
// No longer readable, no longer polling.
polling_due_to_readable_fd = false;
drain_if_still_readable_time_usec = 0;
} else {
// Still readable. If it's been readable for a long time, there is probably
// lingering data on the pipe.
if (get_time() >= drain_if_still_readable_time_usec) {
drain_excessive_data();
}
}
return true;
}
};
@@ -1416,23 +1409,25 @@ static universal_notifier_t::notifier_strategy_t fetch_default_strategy_from_env
const size_t opt_count = sizeof options / sizeof *options;
const char *var = getenv(UNIVERSAL_NOTIFIER_ENV_NAME);
if (var != NULL && var[0] != '\0') {
size_t i;
for (i = 0; i < opt_count; i++) {
if (!strcmp(var, options[i].name)) {
result = options[i].strat;
break;
}
if (var == NULL || var[0] == '\0') {
return result;
}
size_t i;
for (i = 0; i < opt_count; i++) {
if (!strcmp(var, options[i].name)) {
result = options[i].strat;
break;
}
if (i >= opt_count) {
fprintf(stderr, "Warning: unrecognized value for %s: '%s'\n",
UNIVERSAL_NOTIFIER_ENV_NAME, var);
fprintf(stderr, "Warning: valid values are ");
for (size_t j = 0; j < opt_count; j++) {
fprintf(stderr, "%s%s", j > 0 ? ", " : "", options[j].name);
}
fputc('\n', stderr);
}
if (i >= opt_count) {
fprintf(stderr, "Warning: unrecognized value for %s: '%s'\n",
UNIVERSAL_NOTIFIER_ENV_NAME, var);
fprintf(stderr, "Warning: valid values are ");
for (size_t j = 0; j < opt_count; j++) {
fprintf(stderr, "%s%s", j > 0 ? ", " : "", options[j].name);
}
fputc('\n', stderr);
}
return result;
}
@@ -1460,7 +1455,7 @@ universal_notifier_t &universal_notifier_t::default_notifier() {
universal_notifier_t *universal_notifier_t::new_notifier_for_strategy(
universal_notifier_t::notifier_strategy_t strat, const wchar_t *test_path) {
if (strat == strategy_default) {
strat = resolve_default_strategy();
strat = resolve_default_strategy(); //!OCLINT(parameter reassignment)
}
switch (strat) {
case strategy_shmem_polling: {

View File

@@ -88,6 +88,10 @@ static int event_match(const event_t &classv, const event_t &instance) {
case EVENT_GENERIC: {
return instance.str_param1 == classv.str_param1;
}
default: {
DIE("unexpected classv.type");
break;
}
}
// This should never be reached.
@@ -226,7 +230,10 @@ static wcstring event_desc_compact(const event_t &event) {
res = format_string(L"EVENT_GENERIC(%ls)", event.str_param1.c_str());
break;
}
default: { res = format_string(L"unknown/illegal event(%x)", event.type); }
default: {
res = format_string(L"unknown/illegal event(%x)", event.type);
break;
}
}
if (event.function_name.size()) {
return format_string(L"%ls: \"%ls\"", res.c_str(), event.function_name.c_str());

View File

@@ -9,16 +9,13 @@
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wchar.h>
#include <algorithm>
#include <vector>
#ifdef HAVE_SPAWN_H
#include <spawn.h>
#endif
#include <wctype.h>
#include <map>
#include <memory>
#include <string>
@@ -282,11 +279,6 @@ static bool io_transmogrify(const io_chain_t &in_chain, io_chain_t *out_chain,
out.reset(new io_fd_t(in->fd, fd, false));
break;
}
default: {
// Unknown type, should never happen.
assert(0 && "Unhandled io_mode constant");
abort();
}
}
if (out.get() != NULL) result_chain.push_back(out);
@@ -353,7 +345,7 @@ static void internal_exec_helper(parser_t &parser, const wcstring &def, node_off
// foreground process group, we don't use posix_spawn if we're going to foreground the process. (If
// we use fork(), we can call tcsetpgrp after the fork, before the exec, and avoid the race).
static bool can_use_posix_spawn_for_job(const job_t *job, const process_t *process) {
if (job_get_flag(job, JOB_CONTROL)) {
if (job_get_flag(job, JOB_CONTROL)) { //!OCLINT(collapsible if statements)
// We are going to use job control; therefore when we launch this job it will get its own
// process group ID. But will it be foregrounded?
if (job_get_flag(job, JOB_TERMINAL) && job_get_flag(job, JOB_FOREGROUND)) {
@@ -406,7 +398,7 @@ void exec_job(parser_t &parser, job_t *j) {
if ((io->io_mode == IO_BUFFER)) {
io_buffer_t *io_buffer = static_cast<io_buffer_t *>(io.get());
assert(!io_buffer->is_input);
assert(!io_buffer->is_input); //!OCLINT(multiple unary operator)
}
}
@@ -426,10 +418,8 @@ void exec_job(parser_t &parser, job_t *j) {
const env_var_t shlvl_str = env_get_string(L"SHLVL", ENV_GLOBAL | ENV_EXPORT);
wcstring nshlvl_str = L"0";
if (!shlvl_str.missing()) {
wchar_t *end;
long shlvl_i = wcstol(shlvl_str.c_str(), &end, 10);
while (iswspace(*end)) ++end; // skip trailing whitespace
if (shlvl_i > 0 && *end == '\0') {
long shlvl_i = fish_wcstol(shlvl_str.c_str());
if (!errno && shlvl_i > 0) {
nshlvl_str = to_string<long>(shlvl_i - 1);
}
}
@@ -442,7 +432,7 @@ void exec_job(parser_t &parser, job_t *j) {
j->first_process->completed = 1;
return;
}
assert(0 && "This should be unreachable");
DIE("this should be unreachable");
}
// We may have block IOs that conflict with fd redirections. For example, we may have a command
@@ -827,9 +817,7 @@ void exec_job(parser_t &parser, job_t *j) {
case INTERNAL_EXEC:
// We should have handled exec up above.
assert(
0 &&
"INTERNAL_EXEC process found in pipeline, where it should never be. Aborting.");
DIE("INTERNAL_EXEC process found in pipeline, where it should never be. Aborting.");
break;
}
@@ -913,45 +901,42 @@ void exec_job(parser_t &parser, job_t *j) {
// output, so that we can truncate the file. Does not apply to /dev/null.
bool must_fork = redirection_is_to_real_file(stdout_io.get()) ||
redirection_is_to_real_file(stderr_io.get());
if (!must_fork) {
if (p->next == NULL) {
const bool stdout_is_to_buffer =
stdout_io && stdout_io->io_mode == IO_BUFFER;
const bool no_stdout_output = stdout_buffer.empty();
const bool no_stderr_output = stderr_buffer.empty();
if (!must_fork && p->next == NULL) {
const bool stdout_is_to_buffer = stdout_io && stdout_io->io_mode == IO_BUFFER;
const bool no_stdout_output = stdout_buffer.empty();
const bool no_stderr_output = stderr_buffer.empty();
if (no_stdout_output && no_stderr_output) {
// The builtin produced no output and is not inside of a pipeline. No
// need to fork or even output anything.
debug(3, L"Skipping fork: no output for internal builtin '%ls'",
p->argv0());
fork_was_skipped = true;
} else if (no_stderr_output && stdout_is_to_buffer) {
// The builtin produced no stderr, and its stdout is going to an
// internal buffer. There is no need to fork. This helps out the
// performance quite a bit in complex completion code.
debug(3, L"Skipping fork: buffered output for internal builtin '%ls'",
p->argv0());
if (no_stdout_output && no_stderr_output) {
// The builtin produced no output and is not inside of a pipeline. No
// need to fork or even output anything.
debug(3, L"Skipping fork: no output for internal builtin '%ls'",
p->argv0());
fork_was_skipped = true;
} else if (no_stderr_output && stdout_is_to_buffer) {
// The builtin produced no stderr, and its stdout is going to an
// internal buffer. There is no need to fork. This helps out the
// performance quite a bit in complex completion code.
debug(3, L"Skipping fork: buffered output for internal builtin '%ls'",
p->argv0());
io_buffer_t *io_buffer = static_cast<io_buffer_t *>(stdout_io.get());
const std::string res = wcs2string(builtin_io_streams->out.buffer());
io_buffer_t *io_buffer = static_cast<io_buffer_t *>(stdout_io.get());
const std::string res = wcs2string(builtin_io_streams->out.buffer());
io_buffer->out_buffer_append(res.data(), res.size());
fork_was_skipped = true;
} else if (stdout_io.get() == NULL && stderr_io.get() == NULL) {
// We are writing to normal stdout and stderr. Just do it - no need to
// fork.
debug(3, L"Skipping fork: ordinary output for internal builtin '%ls'",
p->argv0());
const std::string outbuff = wcs2string(stdout_buffer);
const std::string errbuff = wcs2string(stderr_buffer);
bool builtin_io_done = do_builtin_io(outbuff.data(), outbuff.size(),
errbuff.data(), errbuff.size());
if (!builtin_io_done && errno != EPIPE) {
show_stackframe(L'E');
}
fork_was_skipped = true;
io_buffer->out_buffer_append(res.data(), res.size());
fork_was_skipped = true;
} else if (stdout_io.get() == NULL && stderr_io.get() == NULL) {
// We are writing to normal stdout and stderr. Just do it - no need to
// fork.
debug(3, L"Skipping fork: ordinary output for internal builtin '%ls'",
p->argv0());
const std::string outbuff = wcs2string(stdout_buffer);
const std::string errbuff = wcs2string(stderr_buffer);
bool builtin_io_done = do_builtin_io(outbuff.data(), outbuff.size(),
errbuff.data(), errbuff.size());
if (!builtin_io_done && errno != EPIPE) {
show_stackframe(L'E');
}
fork_was_skipped = true;
}
}
@@ -1074,7 +1059,7 @@ void exec_job(parser_t &parser, job_t *j) {
setup_child_process(j, p, process_net_io_chain);
safe_launch_process(p, actual_cmd, argv, envv);
// safe_launch_process _never_ returns...
assert(0 && "safe_launch_process should not have returned");
DIE("safe_launch_process should not have returned");
} else {
debug(2, L"Fork #%d, pid %d: external command '%s' from '%ls'\n",
g_fork_count, pid, p->argv0(), file ? file : L"<no file>");
@@ -1088,17 +1073,13 @@ void exec_job(parser_t &parser, job_t *j) {
// This is the parent process. Store away information on the child, and possibly
// fice it control over the terminal.
p->pid = pid;
set_child_group(j, p, 0);
break;
}
case INTERNAL_EXEC: {
// We should have handled exec up above.
assert(
0 &&
"INTERNAL_EXEC process found in pipeline, where it should never be. Aborting.");
DIE("INTERNAL_EXEC process found in pipeline, where it should never be. Aborting.");
break;
}
}
@@ -1177,37 +1158,38 @@ static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst,
// If the caller asked us to preserve the exit status, restore the old status. Otherwise set the
// status of the subcommand.
proc_set_last_status(apply_exit_status ? subcommand_status : prev_status);
is_subshell = prev_subshell;
if (lst != NULL && io_buffer.get() != NULL) {
const char *begin = io_buffer->out_buffer_ptr();
const char *end = begin + io_buffer->out_buffer_size();
if (split_output) {
const char *cursor = begin;
while (cursor < end) {
// Look for the next separator.
const char *stop = (const char *)memchr(cursor, '\n', end - cursor);
const bool hit_separator = (stop != NULL);
if (!hit_separator) {
// If it's not found, just use the end.
stop = end;
}
// Stop now points at the first character we do not want to copy.
const wcstring wc = str2wcstring(cursor, stop - cursor);
lst->push_back(wc);
if (lst == NULL || io_buffer.get() == NULL) {
return subcommand_status;
}
// If we hit a separator, skip over it; otherwise we're at the end.
cursor = stop + (hit_separator ? 1 : 0);
const char *begin = io_buffer->out_buffer_ptr();
const char *end = begin + io_buffer->out_buffer_size();
if (split_output) {
const char *cursor = begin;
while (cursor < end) {
// Look for the next separator.
const char *stop = (const char *)memchr(cursor, '\n', end - cursor);
const bool hit_separator = (stop != NULL);
if (!hit_separator) {
// If it's not found, just use the end.
stop = end;
}
} else {
// we're not splitting output, but we still want to trim off a trailing newline.
if (end != begin && end[-1] == '\n') {
--end;
}
const wcstring wc = str2wcstring(begin, end - begin);
// Stop now points at the first character we do not want to copy.
const wcstring wc = str2wcstring(cursor, stop - cursor);
lst->push_back(wc);
// If we hit a separator, skip over it; otherwise we're at the end.
cursor = stop + (hit_separator ? 1 : 0);
}
} else {
// We're not splitting output, but we still want to trim off a trailing newline.
if (end != begin && end[-1] == '\n') {
--end;
}
const wcstring wc = str2wcstring(begin, end - begin);
lst->push_back(wc);
}
return subcommand_status;

View File

@@ -166,36 +166,31 @@ wcstring expand_escape_variable(const wcstring &in) {
tokenize_variable_array(in, lst);
switch (lst.size()) {
case 0: {
buff.append(L"''");
break;
}
case 1: {
const wcstring &el = lst.at(0);
size_t size = lst.size();
if (size == 0) {
buff.append(L"''");
} else if (size == 1) {
const wcstring &el = lst.at(0);
if (el.find(L' ') != wcstring::npos && is_quotable(el)) {
if (el.find(L' ') != wcstring::npos && is_quotable(el)) {
buff.append(L"'");
buff.append(el);
buff.append(L"'");
} else {
buff.append(escape_string(el, 1));
}
} else {
for (size_t j = 0; j < lst.size(); j++) {
const wcstring &el = lst.at(j);
if (j) buff.append(L" ");
if (is_quotable(el)) {
buff.append(L"'");
buff.append(el);
buff.append(L"'");
} else {
buff.append(escape_string(el, 1));
}
break;
}
default: {
for (size_t j = 0; j < lst.size(); j++) {
const wcstring &el = lst.at(j);
if (j) buff.append(L" ");
if (is_quotable(el)) {
buff.append(L"'");
buff.append(el);
buff.append(L"'");
} else {
buff.append(escape_string(el, 1));
}
}
}
}
return buff;
@@ -225,10 +220,8 @@ static bool match_pid(const wcstring &cmd, const wchar_t *proc, size_t *offset)
const wcstring base_cmd = wbasename(cmd);
bool result = string_prefixes_string(proc, base_cmd);
if (result) {
// It's a match. Return the offset within the full command.
if (offset) *offset = cmd.size() - base_cmd.size();
}
// It's a match. Return the offset within the full command.
if (result && offset) *offset = cmd.size() - base_cmd.size();
return result;
}
@@ -400,7 +393,10 @@ bool process_iterator_t::next_process(wcstring *out_str, pid_t *out_pid) {
if (buf.st_uid != getuid()) continue;
// Remember the pid.
pid = fish_wcstoi(name.c_str(), NULL, 10);
pid = fish_wcstoi(name.c_str());
if (errno || pid < 0) {
debug(1, _(L"Unexpected failure to convert pid '%ls' to integer\n"), name.c_str());
}
// The 'cmdline' file exists, it should contain the commandline.
FILE *cmdfile;
@@ -442,7 +438,7 @@ struct find_job_data_t {
/// The following function is invoked on the main thread, because the job list is not thread safe.
/// It should search the job list for something matching the given proc, and then return 1 to stop
/// the search, 0 to continue it .
/// the search, 0 to continue it.
static int find_job(const struct find_job_data_t *info) {
ASSERT_IS_MAIN_THREAD();
@@ -484,12 +480,8 @@ static int find_job(const struct find_job_data_t *info) {
}
}
} else {
int jid;
wchar_t *end;
errno = 0;
jid = fish_wcstoi(proc, &end, 10);
if (jid > 0 && !errno && !*end) {
int jid = fish_wcstoi(proc);
if (!errno && jid > 0) {
j = job_get(jid);
if ((j != 0) && (j->command_wcstr() != 0) && (!j->command_is_empty())) {
append_completion(&completions, to_string<long>(j->pgid));
@@ -501,42 +493,45 @@ static int find_job(const struct find_job_data_t *info) {
found = 1;
}
if (!found) {
job_iterator_t jobs;
while ((j = jobs.next())) {
if (j->command_is_empty()) continue;
if (found) {
return found;
}
size_t offset;
if (match_pid(j->command(), proc, &offset)) {
if (flags & EXPAND_FOR_COMPLETIONS) {
append_completion(&completions, j->command_wcstr() + offset + wcslen(proc),
COMPLETE_JOB_DESC, 0);
} else {
append_completion(&completions, to_string<long>(j->pgid));
found = 1;
}
job_iterator_t jobs;
while ((j = jobs.next())) {
if (j->command_is_empty()) continue;
size_t offset;
if (match_pid(j->command(), proc, &offset)) {
if (flags & EXPAND_FOR_COMPLETIONS) {
append_completion(&completions, j->command_wcstr() + offset + wcslen(proc),
COMPLETE_JOB_DESC, 0);
} else {
append_completion(&completions, to_string<long>(j->pgid));
found = 1;
}
}
}
if (!found) {
jobs.reset();
while ((j = jobs.next())) {
process_t *p;
if (j->command_is_empty()) continue;
for (p = j->first_process; p; p = p->next) {
if (p->actual_cmd.empty()) continue;
if (found) {
return found;
}
size_t offset;
if (match_pid(p->actual_cmd, proc, &offset)) {
if (flags & EXPAND_FOR_COMPLETIONS) {
append_completion(&completions,
wcstring(p->actual_cmd, offset + wcslen(proc)),
COMPLETE_CHILD_PROCESS_DESC, 0);
} else {
append_completion(&completions, to_string<long>(p->pid), L"", 0);
found = 1;
}
}
jobs.reset();
while ((j = jobs.next())) {
process_t *p;
if (j->command_is_empty()) continue;
for (p = j->first_process; p; p = p->next) {
if (p->actual_cmd.empty()) continue;
size_t offset;
if (match_pid(p->actual_cmd, proc, &offset)) {
if (flags & EXPAND_FOR_COMPLETIONS) {
append_completion(&completions, wcstring(p->actual_cmd, offset + wcslen(proc)),
COMPLETE_CHILD_PROCESS_DESC, 0);
} else {
append_completion(&completions, to_string<long>(p->pid), L"", 0);
found = 1;
}
}
}
@@ -632,13 +627,11 @@ static bool expand_pid(const wcstring &instr_with_sep, expand_flags_t flags,
const size_t prev_count = out->size();
find_process(in + 1, flags, out);
if (prev_count == out->size()) {
if (!(flags & EXPAND_FOR_COMPLETIONS)) {
// We failed to find anything.
append_syntax_error(errors, 1, FAILED_EXPANSION_PROCESS_ERR_MSG,
escape(in + 1, ESCAPE_NO_QUOTED).c_str());
return false;
}
if (prev_count == out->size() && !(flags & EXPAND_FOR_COMPLETIONS)) {
// We failed to find anything.
append_syntax_error(errors, 1, FAILED_EXPANSION_PROCESS_ERR_MSG,
escape(in + 1, ESCAPE_NO_QUOTED).c_str());
return false;
}
return true;
@@ -649,25 +642,22 @@ static bool expand_pid(const wcstring &instr_with_sep, expand_flags_t flags,
/// with [.
static size_t parse_slice(const wchar_t *in, wchar_t **end_ptr, std::vector<long> &idx,
std::vector<size_t> &source_positions, size_t array_size) {
wchar_t *end;
const long size = (long)array_size;
size_t pos = 1; // skip past the opening square bracket
// debug( 0, L"parse_slice on '%ls'", in );
while (1) {
long tmp;
while (iswspace(in[pos]) || (in[pos] == INTERNAL_SEPARATOR)) pos++;
if (in[pos] == L']') {
pos++;
break;
}
errno = 0;
const size_t i1_src_pos = pos;
tmp = wcstol(&in[pos], &end, 10);
if ((errno) || (end == &in[pos])) {
const wchar_t *end;
long tmp = fish_wcstol(&in[pos], &end);
// We don't test `*end` as is typically done because we expect it to not be the null char.
// Ignore the case of errno==-1 because it means the end char wasn't the null char.
if (errno > 0) {
return pos;
}
// debug( 0, L"Push idx %d", tmp );
@@ -680,8 +670,9 @@ static size_t parse_slice(const wchar_t *in, wchar_t **end_ptr, std::vector<long
while (in[pos] == INTERNAL_SEPARATOR) pos++;
const size_t number_start = pos;
long tmp1 = wcstol(&in[pos], &end, 10);
if ((errno) || (end == &in[pos])) {
long tmp1 = fish_wcstol(&in[pos], &end);
// Ignore the case of errno==-1 because it means the end char wasn't the null char.
if (errno > 0) {
return pos;
}
pos = end - in;
@@ -704,11 +695,8 @@ static size_t parse_slice(const wchar_t *in, wchar_t **end_ptr, std::vector<long
}
if (end_ptr) {
// debug( 0, L"Remainder is '%ls', slice def was %d characters long", in+pos, pos );
*end_ptr = (wchar_t *)(in + pos);
}
// debug( 0, L"ok, done" );
return 0;
}
@@ -755,193 +743,196 @@ static int expand_variables(const wcstring &instr, std::vector<completion_t> *ou
for (long i = last_idx - 1; (i >= 0) && is_ok && !empty; i--) {
const wchar_t c = instr.at(i);
if ((c == VARIABLE_EXPAND) || (c == VARIABLE_EXPAND_SINGLE)) {
size_t start_pos = i + 1;
size_t stop_pos;
long var_len;
int is_single = (c == VARIABLE_EXPAND_SINGLE);
if (c != VARIABLE_EXPAND && c != VARIABLE_EXPAND_SINGLE) {
continue;
}
stop_pos = start_pos;
while (stop_pos < insize) {
const wchar_t nc = instr.at(stop_pos);
if (nc == VARIABLE_EXPAND_EMPTY) {
stop_pos++;
break;
}
if (!wcsvarchr(nc)) break;
long var_len;
int is_single = (c == VARIABLE_EXPAND_SINGLE);
size_t start_pos = i + 1;
size_t stop_pos = start_pos;
while (stop_pos < insize) {
const wchar_t nc = instr.at(stop_pos);
if (nc == VARIABLE_EXPAND_EMPTY) {
stop_pos++;
}
// printf( "Stop for '%c'\n", in[stop_pos]);
var_len = stop_pos - start_pos;
if (var_len == 0) {
if (errors) {
parse_util_expand_variable_error(instr, 0 /* global_token_pos */, i, errors);
}
is_ok = false;
break;
}
if (!wcsvarchr(nc)) break;
var_tmp.append(instr, start_pos, var_len);
env_var_t var_val;
if (var_len == 1 && var_tmp[0] == VARIABLE_EXPAND_EMPTY) {
var_val = env_var_t::missing_var();
} else {
var_val = expand_var(var_tmp.c_str());
stop_pos++;
}
// printf( "Stop for '%c'\n", in[stop_pos]);
var_len = stop_pos - start_pos;
if (var_len == 0) {
if (errors) {
parse_util_expand_variable_error(instr, 0 /* global_token_pos */, i, errors);
}
if (!var_val.missing()) {
int all_vars = 1;
wcstring_list_t var_item_list;
is_ok = false;
break;
}
if (is_ok) {
tokenize_variable_array(var_val, var_item_list);
var_tmp.append(instr, start_pos, var_len);
env_var_t var_val;
if (var_len == 1 && var_tmp[0] == VARIABLE_EXPAND_EMPTY) {
var_val = env_var_t::missing_var();
} else {
var_val = expand_var(var_tmp.c_str());
}
const size_t slice_start = stop_pos;
if (slice_start < insize && instr.at(slice_start) == L'[') {
wchar_t *slice_end;
size_t bad_pos;
all_vars = 0;
const wchar_t *in = instr.c_str();
bad_pos = parse_slice(in + slice_start, &slice_end, var_idx_list,
var_pos_list, var_item_list.size());
if (bad_pos != 0) {
append_syntax_error(errors, stop_pos + bad_pos, L"Invalid index value");
if (!var_val.missing()) {
int all_vars = 1;
wcstring_list_t var_item_list;
if (is_ok) {
tokenize_variable_array(var_val, var_item_list);
const size_t slice_start = stop_pos;
if (slice_start < insize && instr.at(slice_start) == L'[') {
wchar_t *slice_end;
size_t bad_pos;
all_vars = 0;
const wchar_t *in = instr.c_str();
bad_pos = parse_slice(in + slice_start, &slice_end, var_idx_list, var_pos_list,
var_item_list.size());
if (bad_pos != 0) {
append_syntax_error(errors, stop_pos + bad_pos, L"Invalid index value");
is_ok = false;
break;
}
stop_pos = (slice_end - in);
}
if (!all_vars) {
wcstring_list_t string_values(var_idx_list.size());
for (size_t j = 0; j < var_idx_list.size(); j++) {
long tmp = var_idx_list.at(j);
// Check that we are within array bounds. If not, truncate the list to
// exit.
if (tmp < 1 || (size_t)tmp > var_item_list.size()) {
size_t var_src_pos = var_pos_list.at(j);
// The slice was parsed starting at stop_pos, so we have to add that
// to the error position.
append_syntax_error(errors, slice_start + var_src_pos,
ARRAY_BOUNDS_ERR);
is_ok = false;
var_idx_list.resize(j);
break;
} else {
// Replace each index in var_idx_list inplace with the string value
// at the specified index.
// al_set( var_idx_list, j, wcsdup((const wchar_t *)al_get(
// &var_item_list, tmp-1 ) ) );
string_values.at(j) = var_item_list.at(tmp - 1);
}
stop_pos = (slice_end - in);
}
if (!all_vars) {
wcstring_list_t string_values(var_idx_list.size());
for (size_t j = 0; j < var_idx_list.size(); j++) {
long tmp = var_idx_list.at(j);
// Check that we are within array bounds. If not, truncate the list to
// exit.
if (tmp < 1 || (size_t)tmp > var_item_list.size()) {
size_t var_src_pos = var_pos_list.at(j);
// The slice was parsed starting at stop_pos, so we have to add that
// to the error position.
append_syntax_error(errors, slice_start + var_src_pos,
ARRAY_BOUNDS_ERR);
is_ok = false;
var_idx_list.resize(j);
break;
} else {
// Replace each index in var_idx_list inplace with the string value
// at the specified index.
// al_set( var_idx_list, j, wcsdup((const wchar_t *)al_get(
// &var_item_list, tmp-1 ) ) );
string_values.at(j) = var_item_list.at(tmp - 1);
}
}
// string_values is the new var_item_list.
var_item_list.swap(string_values);
}
}
if (is_ok) {
if (is_single) {
wcstring res(instr, 0, i);
if (i > 0) {
if (instr.at(i - 1) != VARIABLE_EXPAND_SINGLE) {
res.push_back(INTERNAL_SEPARATOR);
} else if (var_item_list.empty() || var_item_list.front().empty()) {
// First expansion is empty, but we need to recursively expand.
res.push_back(VARIABLE_EXPAND_EMPTY);
}
}
for (size_t j = 0; j < var_item_list.size(); j++) {
const wcstring &next = var_item_list.at(j);
if (is_ok) {
if (j != 0) res.append(L" ");
res.append(next);
}
}
assert(stop_pos <= insize);
res.append(instr, stop_pos, insize - stop_pos);
is_ok &= expand_variables(res, out, i, errors);
} else {
for (size_t j = 0; j < var_item_list.size(); j++) {
const wcstring &next = var_item_list.at(j);
if (is_ok && (i == 0) && stop_pos == insize) {
append_completion(out, next);
} else {
if (is_ok) {
wcstring new_in;
new_in.append(instr, 0, i);
if (i > 0) {
if (instr.at(i - 1) != VARIABLE_EXPAND) {
new_in.push_back(INTERNAL_SEPARATOR);
} else if (next.empty()) {
new_in.push_back(VARIABLE_EXPAND_EMPTY);
}
}
assert(stop_pos <= insize);
new_in.append(next);
new_in.append(instr, stop_pos, insize - stop_pos);
is_ok &= expand_variables(new_in, out, i, errors);
}
}
}
}
// string_values is the new var_item_list.
var_item_list.swap(string_values);
}
}
if (!is_ok) {
return is_ok;
}
// Even with no value, we still need to parse out slice syntax. Behave as though we
// had 1 value, so $foo[1] always works.
const size_t slice_start = stop_pos;
if (slice_start < insize && instr.at(slice_start) == L'[') {
const wchar_t *in = instr.c_str();
wchar_t *slice_end;
size_t bad_pos;
bad_pos = parse_slice(in + slice_start, &slice_end, var_idx_list, var_pos_list, 1);
if (bad_pos != 0) {
append_syntax_error(errors, stop_pos + bad_pos, L"Invalid index value");
is_ok = 0;
return is_ok;
}
stop_pos = (slice_end - in);
// Validate that the parsed indexes are valid.
for (size_t j = 0; j < var_idx_list.size(); j++) {
long tmp = var_idx_list.at(j);
if (tmp != 1) {
size_t var_src_pos = var_pos_list.at(j);
append_syntax_error(errors, slice_start + var_src_pos, ARRAY_BOUNDS_ERR);
is_ok = 0;
return is_ok;
if (is_single) {
wcstring res(instr, 0, i);
if (i > 0) {
if (instr.at(i - 1) != VARIABLE_EXPAND_SINGLE) {
res.push_back(INTERNAL_SEPARATOR);
} else if (var_item_list.empty() || var_item_list.front().empty()) {
// First expansion is empty, but we need to recursively expand.
res.push_back(VARIABLE_EXPAND_EMPTY);
}
}
}
// Expand a non-existing variable.
if (c == VARIABLE_EXPAND) {
// Regular expansion, i.e. expand this argument to nothing.
empty = true;
} else {
// Expansion to single argument.
wcstring res;
res.append(instr, 0, i);
if (i > 0 && instr.at(i - 1) == VARIABLE_EXPAND_SINGLE) {
res.push_back(VARIABLE_EXPAND_EMPTY);
for (size_t j = 0; j < var_item_list.size(); j++) {
const wcstring &next = var_item_list.at(j);
if (is_ok) {
if (j != 0) res.append(L" ");
res.append(next);
}
}
assert(stop_pos <= insize);
res.append(instr, stop_pos, insize - stop_pos);
is_ok &= expand_variables(res, out, i, errors);
} else {
for (size_t j = 0; j < var_item_list.size(); j++) {
const wcstring &next = var_item_list.at(j);
if (is_ok && i == 0 && stop_pos == insize) {
append_completion(out, next);
} else {
if (is_ok) {
wcstring new_in;
new_in.append(instr, 0, i);
if (i > 0) {
if (instr.at(i - 1) != VARIABLE_EXPAND) {
new_in.push_back(INTERNAL_SEPARATOR);
} else if (next.empty()) {
new_in.push_back(VARIABLE_EXPAND_EMPTY);
}
}
assert(stop_pos <= insize);
new_in.append(next);
new_in.append(instr, stop_pos, insize - stop_pos);
is_ok &= expand_variables(new_in, out, i, errors);
}
}
}
}
return is_ok;
}
// Even with no value, we still need to parse out slice syntax. Behave as though we
// had 1 value, so $foo[1] always works.
const size_t slice_start = stop_pos;
if (slice_start < insize && instr.at(slice_start) == L'[') {
const wchar_t *in = instr.c_str();
wchar_t *slice_end;
size_t bad_pos;
bad_pos = parse_slice(in + slice_start, &slice_end, var_idx_list, var_pos_list, 1);
if (bad_pos != 0) {
append_syntax_error(errors, stop_pos + bad_pos, L"Invalid index value");
is_ok = 0;
return is_ok;
}
stop_pos = (slice_end - in);
// Validate that the parsed indexes are valid.
for (size_t j = 0; j < var_idx_list.size(); j++) {
long tmp = var_idx_list.at(j);
if (tmp != 1) {
size_t var_src_pos = var_pos_list.at(j);
append_syntax_error(errors, slice_start + var_src_pos, ARRAY_BOUNDS_ERR);
is_ok = 0;
return is_ok;
}
}
}
// Expand a non-existing variable.
if (c == VARIABLE_EXPAND) {
// Regular expansion, i.e. expand this argument to nothing.
empty = true;
} else {
// Expansion to single argument.
wcstring res;
res.append(instr, 0, i);
if (i > 0 && instr.at(i - 1) == VARIABLE_EXPAND_SINGLE) {
res.push_back(VARIABLE_EXPAND_EMPTY);
}
assert(stop_pos <= insize);
res.append(instr, stop_pos, insize - stop_pos);
is_ok &= expand_variables(res, out, i, errors);
return is_ok;
}
}
@@ -985,6 +976,10 @@ static expand_error_t expand_brackets(const wcstring &instr, expand_flags_t flag
}
case BRACKET_SEP: {
if (bracket_count == 1) last_sep = pos;
break;
}
default: {
break; // we ignore all other characters here
}
}
}
@@ -1025,21 +1020,19 @@ static expand_error_t expand_brackets(const wcstring &instr, expand_flags_t flag
tot_len = length_preceding_brackets + length_following_brackets;
item_begin = bracket_begin + 1;
for (const wchar_t *pos = (bracket_begin + 1); true; pos++) {
if (bracket_count == 0) {
if ((*pos == BRACKET_SEP) || (pos == bracket_end)) {
assert(pos >= item_begin);
size_t item_len = pos - item_begin;
if (bracket_count == 0 && ((*pos == BRACKET_SEP) || (pos == bracket_end))) {
assert(pos >= item_begin);
size_t item_len = pos - item_begin;
wcstring whole_item;
whole_item.reserve(tot_len + item_len + 2);
whole_item.append(in, length_preceding_brackets);
whole_item.append(item_begin, item_len);
whole_item.append(bracket_end + 1);
expand_brackets(whole_item, flags, out, errors);
wcstring whole_item;
whole_item.reserve(tot_len + item_len + 2);
whole_item.append(in, length_preceding_brackets);
whole_item.append(item_begin, item_len);
whole_item.append(bracket_end + 1);
expand_brackets(whole_item, flags, out, errors);
item_begin = pos + 1;
if (pos == bracket_end) break;
}
item_begin = pos + 1;
if (pos == bracket_end) break;
}
if (*pos == BRACKET_BEGIN) {
@@ -1076,6 +1069,10 @@ static int expand_cmdsubst(const wcstring &input, std::vector<completion_t> *out
case 1: {
break;
}
default: {
DIE("unhandled parse_ret value");
break;
}
}
const wcstring subcmd(paran_begin + 1, paran_end - paran_begin - 1);
@@ -1299,6 +1296,9 @@ static void remove_internal_separator(wcstring *str, bool conv) {
str->at(idx) = L'*';
break;
}
default: {
break; // we ignore all other characters
}
}
}
}
@@ -1307,8 +1307,10 @@ static void remove_internal_separator(wcstring *str, bool conv) {
/// A stage in string expansion is represented as a function that takes an input and returns a list
/// of output (by reference). We get flags and errors. It may return an error; if so expansion
/// halts.
typedef expand_error_t (*expand_stage_t)(const wcstring &input, std::vector<completion_t> *out,
expand_flags_t flags, parse_error_list_t *errors);
typedef expand_error_t (*expand_stage_t)(const wcstring &input, //!OCLINT(unused param)
std::vector<completion_t> *out, //!OCLINT(unused param)
expand_flags_t flags, //!OCLINT(unused param)
parse_error_list_t *errors); //!OCLINT(unused param)
static expand_error_t expand_stage_cmdsubst(const wcstring &input, std::vector<completion_t> *out,
expand_flags_t flags, parse_error_list_t *errors) {
@@ -1389,7 +1391,7 @@ static expand_error_t expand_stage_wildcards(const wcstring &input, std::vector<
const bool has_wildcard = wildcard_has(path_to_expand, true /* internal, i.e. ANY_CHAR */);
if (has_wildcard && (flags & EXECUTABLES_ONLY)) {
// Don't do wildcard expansion for executables. See #785. Make them expand to nothing here.
; // don't do wildcard expansion for executables, see issue #785
} else if (((flags & EXPAND_FOR_COMPLETIONS) && (!(flags & EXPAND_SKIP_WILDCARDS))) ||
has_wildcard) {
// We either have a wildcard, or we don't have a wildcard but we're doing completion
@@ -1401,8 +1403,8 @@ static expand_error_t expand_stage_wildcards(const wcstring &input, std::vector<
// which may be CDPATH if the special flag is set.
const wcstring working_dir = env_get_pwd_slash();
wcstring_list_t effective_working_dirs;
bool for_cd = !!(flags & EXPAND_SPECIAL_FOR_CD);
bool for_command = !!(flags & EXPAND_SPECIAL_FOR_COMMAND);
bool for_cd = static_cast<bool>(flags & EXPAND_SPECIAL_FOR_CD);
bool for_command = static_cast<bool>(flags & EXPAND_SPECIAL_FOR_COMMAND);
if (!for_cd && !for_command) {
// Common case.
effective_working_dirs.push_back(working_dir);
@@ -1517,19 +1519,17 @@ expand_error_t expand_string(const wcstring &input, std::vector<completion_t> *o
bool expand_one(wcstring &string, expand_flags_t flags, parse_error_list_t *errors) {
std::vector<completion_t> completions;
bool result = false;
if ((!(flags & EXPAND_FOR_COMPLETIONS)) && expand_is_clean(string)) {
if (!(flags & EXPAND_FOR_COMPLETIONS) && expand_is_clean(string)) {
return true;
}
if (expand_string(string, &completions, flags | EXPAND_NO_DESCRIPTIONS, errors)) {
if (completions.size() == 1) {
string = completions.at(0).completion;
result = true;
}
if (expand_string(string, &completions, flags | EXPAND_NO_DESCRIPTIONS, errors) &&
completions.size() == 1) {
string = completions.at(0).completion;
return true;
}
return result;
return false;
}
// https://github.com/fish-shell/fish-shell/issues/367
@@ -1556,24 +1556,26 @@ static std::string escape_single_quoted_hack_hack_hack_hack(const char *str) {
bool fish_xdm_login_hack_hack_hack_hack(std::vector<std::string> *cmds, int argc,
const char *const *argv) {
bool result = false;
if (cmds && cmds->size() == 1) {
const std::string &cmd = cmds->at(0);
if (cmd == "exec \"${@}\"" || cmd == "exec \"$@\"") {
// We're going to construct a new command that starts with exec, and then has the
// remaining arguments escaped.
std::string new_cmd = "exec";
for (int i = 1; i < argc; i++) {
const char *arg = argv[i];
if (arg) {
new_cmd.push_back(' ');
new_cmd.append(escape_single_quoted_hack_hack_hack_hack(arg));
}
}
if (!cmds || cmds->size() != 1) {
return false;
}
cmds->at(0) = new_cmd;
result = true;
bool result = false;
const std::string &cmd = cmds->at(0);
if (cmd == "exec \"${@}\"" || cmd == "exec \"$@\"") {
// We're going to construct a new command that starts with exec, and then has the
// remaining arguments escaped.
std::string new_cmd = "exec";
for (int i = 1; i < argc; i++) {
const char *arg = argv[i];
if (arg) {
new_cmd.push_back(' ');
new_cmd.append(escape_single_quoted_hack_hack_hack_hack(arg));
}
}
cmds->at(0) = new_cmd;
result = true;
}
return result;
}

View File

@@ -203,13 +203,10 @@ size_t wcslcpy(wchar_t *dst, const wchar_t *src, size_t siz) {
// Not enough room in dst, add NUL and traverse rest of src.
if (n == 0) {
if (siz != 0) *d = '\0';
// NUL-terminate dst.
while (*s++)
;
if (siz != 0) *d = '\0'; // NUL-terminate dst
while (*s++) ; // ignore rest of src
}
return s - src - 1;
// Count does not include NUL.
return s - src - 1; // count does not include NUL
}
#endif
@@ -353,7 +350,7 @@ static int bisearch(wchar_t ucs, const struct interval *table, int max) {
if (ucs > table[mid].last)
min = mid + 1;
else if (ucs < table[mid].first)
max = mid - 1;
max = mid - 1; //!OCLINT(parameter reassignment)
else
return 1;
}

View File

@@ -17,7 +17,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
@@ -47,13 +46,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#include "function.h"
#include "history.h"
#include "input.h"
#include "input_common.h"
#include "io.h"
#include "parser.h"
#include "path.h"
#include "proc.h"
#include "reader.h"
#include "wildcard.h"
#include "wutil.h" // IWYU pragma: keep
// PATH_MAX may not exist.
@@ -314,6 +311,7 @@ static int fish_parse_opt(int argc, char **argv, std::vector<std::string> *cmds)
case 0: {
fwprintf(stderr, _(L"getopt_long() unexpectedly returned zero\n"));
exit(127);
break;
}
case 'c': {
cmds->push_back(optarg);
@@ -358,6 +356,7 @@ static int fish_parse_opt(int argc, char **argv, std::vector<std::string> *cmds)
case 'v': {
fwprintf(stdout, _(L"%s, version %s\n"), PACKAGE_NAME, get_fish_version());
exit(0);
break;
}
case 'D': {
char *end;
@@ -377,6 +376,7 @@ static int fish_parse_opt(int argc, char **argv, std::vector<std::string> *cmds)
default: {
// We assume getopt_long() has already emitted a diagnostic msg.
exit(1);
break;
}
}
}
@@ -424,11 +424,6 @@ int main(int argc, char **argv) {
int res = 1;
int my_optind = 0;
// We can't do this at compile time due to the use of enum symbols.
assert(EXPAND_SENTINAL >= EXPAND_RESERVED_BASE && EXPAND_SENTINAL <= EXPAND_RESERVED_END);
assert(ANY_SENTINAL >= WILDCARD_RESERVED_BASE && ANY_SENTINAL <= WILDCARD_RESERVED_END);
assert(R_SENTINAL >= INPUT_COMMON_BASE && R_SENTINAL <= INPUT_COMMON_END);
program_name = L"fish";
set_main_thread();
setup_fork_guards();

View File

@@ -102,7 +102,7 @@ static void dump_node(indent_t node_indent, const parse_node_t &node, const wcst
nextc_str[1] = L'c';
nextc_str[2] = nextc + '@';
}
fwprintf(stderr, L"{off %4d, len %4d, indent %2u, kw %ls, %ls} [%ls|%ls|%ls]\n",
fwprintf(stderr, L"{off %4u, len %4u, indent %2u, kw %ls, %ls} [%ls|%ls|%ls]\n",
node.source_start, node.source_length, node_indent, keyword_description(node.keyword),
token_type_description(node.type), prevc_str, source_txt.c_str(), nextc_str);
}

View File

@@ -206,9 +206,8 @@ static void process_input(bool continuous_mode) {
output_bind_command(bind_chars);
if (first_char_seen && !continuous_mode) {
return;
} else {
continue;
}
continue;
}
prev_tstamp = output_elapsed_time(prev_tstamp, first_char_seen);
@@ -307,11 +306,13 @@ int main(int argc, char **argv) {
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}};
int opt;
while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
bool error = false;
while (!error && (opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
switch (opt) {
case 0: {
fprintf(stderr, "getopt_long() unexpectedly returned zero\n");
exit(1);
error = true;
break;
}
case 'c': {
continuous_mode = true;
@@ -320,6 +321,7 @@ int main(int argc, char **argv) {
case 'h': {
print_help("fish_key_reader", 0);
exit(0);
break;
}
case 'd': {
char *end;
@@ -332,7 +334,7 @@ int main(int argc, char **argv) {
debug_level = (int)tmp;
} else {
fwprintf(stderr, _(L"Invalid value '%s' for debug-level flag"), optarg);
exit(1);
error = true;
}
break;
}
@@ -347,16 +349,19 @@ int main(int argc, char **argv) {
debug_stack_frames = (int)tmp;
} else {
fwprintf(stderr, _(L"Invalid value '%s' for debug-stack-frames flag"), optarg);
exit(1);
error = true;
break;
}
break;
}
default: {
// We assume getopt_long() has already emitted a diagnostic msg.
exit(1);
error = true;
break;
}
}
}
if (error) return 1;
argc -= optind;
if (argc != 0) {

View File

@@ -4,12 +4,14 @@
// IWYU pragma: no_include <cstring>
// IWYU pragma: no_include <cstddef>
#include <assert.h>
#include <errno.h>
#include <libgen.h>
#include <limits.h>
#include <pthread.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -67,8 +69,6 @@
static const char *const *s_arguments;
static int s_test_run_count = 0;
bool is_wchar_ucs2() { return sizeof(wchar_t) == 2; }
// Indicate if we should test the given function. Either we test everything (all arguments) or we
// run only tests that have a prefix in s_arguments.
static bool should_test_function(const char *func_name) {
@@ -95,17 +95,15 @@ static bool should_test_function(const char *func_name) {
#define ESCAPE_TEST_LENGTH 100
/// The higest character number of character to try and escape.
#define ESCAPE_TEST_CHAR 4000
/// Number of laps to run performance testing loop.
#define LAPS 50
/// Number of encountered errors.
static int err_count = 0;
/// Print formatted output.
static void say(const wchar_t *blah, ...) {
static void say(const wchar_t *fmt, ...) {
va_list va;
va_start(va, blah);
vwprintf(blah, va);
va_start(va, fmt);
vwprintf(fmt, va);
va_end(va);
wprintf(L"\n");
}
@@ -156,21 +154,103 @@ static int chdir_set_pwd(const char *path) {
return ret;
}
#define do_test(e) \
do { \
if (!(e)) err(L"Test failed on line %lu: %s", __LINE__, #e); \
// The odd formulation of these macros is to avoid "multiple unary operator" warnings from oclint
// were we to use the more natural "if (!(e)) err(..." form. We have to do this because the rules
// for the C preprocessor make it practically impossible to embed a comment in the body of a macro.
#define do_test(e) \
do { \
if (e) { \
; \
} else { \
err(L"Test failed on line %lu: %s", __LINE__, #e); \
} \
} while (0)
#define do_test_from(e, from_line) \
do { \
if (!(e)) err(L"Test failed on line %lu (from %lu): %s", __LINE__, from_line, #e); \
#define do_test_from(e, from) \
do { \
if (e) { \
; \
} else { \
err(L"Test failed on line %lu (from %lu): %s", __LINE__, from, #e); \
} \
} while (0)
#define do_test1(e, msg) \
do { \
if (!(e)) err(L"Test failed on line %lu: %ls", __LINE__, (msg)); \
#define do_test1(e, msg) \
do { \
if (e) { \
; \
} else { \
err(L"Test failed on line %lu: %ls", __LINE__, (msg)); \
} \
} while (0)
/// Test that the fish functions for converting strings to numbers work.
static void test_str_to_num() {
const wchar_t *end;
int i;
long l;
i = fish_wcstoi(L"");
do_test1(errno == EINVAL && i == 0, L"converting empty string to int did not fail");
i = fish_wcstoi(L" \n ");
do_test1(errno == EINVAL && i == 0, L"converting whitespace string to int did not fail");
i = fish_wcstoi(L"123");
do_test1(errno == 0 && i == 123, L"converting valid num to int did not succeed");
i = fish_wcstoi(L"-123");
do_test1(errno == 0 && i == -123, L"converting valid num to int did not succeed");
i = fish_wcstoi(L" 345 ");
do_test1(errno == 0 && i == 345, L"converting valid num to int did not succeed");
i = fish_wcstoi(L" -345 ");
do_test1(errno == 0 && i == -345, L"converting valid num to int did not succeed");
i = fish_wcstoi(L"x345");
do_test1(errno == EINVAL && i == 0, L"converting invalid num to int did not fail");
i = fish_wcstoi(L" x345");
do_test1(errno == EINVAL && i == 0, L"converting invalid num to int did not fail");
i = fish_wcstoi(L"456 x");
do_test1(errno == -1 && i == 456, L"converting invalid num to int did not fail");
i = fish_wcstoi(L"99999999999999999999999");
do_test1(errno == ERANGE && i == INT_MAX, L"converting invalid num to int did not fail");
i = fish_wcstoi(L"-99999999999999999999999");
do_test1(errno == ERANGE && i == INT_MIN, L"converting invalid num to int did not fail");
i = fish_wcstoi(L"567]", &end);
do_test1(errno == -1 && i == 567 && *end == L']',
L"converting valid num to int did not succeed");
// This is subtle. "567" in base 8 is "375" in base 10. The final "8" is not converted.
i = fish_wcstoi(L"5678", &end, 8);
do_test1(errno == -1 && i == 375 && *end == L'8',
L"converting invalid num to int did not fail");
l = fish_wcstol(L"");
do_test1(errno == EINVAL && l == 0, L"converting empty string to long did not fail");
l = fish_wcstol(L" \t ");
do_test1(errno == EINVAL && l == 0, L"converting whitespace string to long did not fail");
l = fish_wcstol(L"123");
do_test1(errno == 0 && l == 123, L"converting valid num to long did not succeed");
l = fish_wcstol(L"-123");
do_test1(errno == 0 && l == -123, L"converting valid num to long did not succeed");
l = fish_wcstol(L" 345 ");
do_test1(errno == 0 && l == 345, L"converting valid num to long did not succeed");
l = fish_wcstol(L" -345 ");
do_test1(errno == 0 && l == -345, L"converting valid num to long did not succeed");
l = fish_wcstol(L"x345");
do_test1(errno == EINVAL && l == 0, L"converting invalid num to long did not fail");
l = fish_wcstol(L" x345");
do_test1(errno == EINVAL && l == 0, L"converting invalid num to long did not fail");
l = fish_wcstol(L"456 x");
do_test1(errno == -1 && l == 456, L"converting invalid num to long did not fail");
l = fish_wcstol(L"99999999999999999999999");
do_test1(errno == ERANGE && l == LONG_MAX, L"converting invalid num to long did not fail");
l = fish_wcstol(L"-99999999999999999999999");
do_test1(errno == ERANGE && l == LONG_MIN, L"converting invalid num to long did not fail");
l = fish_wcstol(L"567]", &end);
do_test1(errno == -1 && l == 567 && *end == L']',
L"converting valid num to long did not succeed");
// This is subtle. "567" in base 8 is "375" in base 10. The final "8" is not converted.
l = fish_wcstol(L"5678", &end, 8);
do_test1(errno == -1 && l == 375 && *end == L'8',
L"converting invalid num to long did not fail");
}
/// Test sane escapes.
static void test_unescape_sane() {
const struct test_t {
@@ -200,13 +280,12 @@ static void test_unescape_sane() {
if (unescape_string(L"echo \\U110000", &output, UNESCAPE_DEFAULT)) {
err(L"Should not have been able to unescape \\U110000\n");
}
if (is_wchar_ucs2()) {
// TODO: Make this work on MS Windows.
} else {
if (!unescape_string(L"echo \\U10FFFF", &output, UNESCAPE_DEFAULT)) {
err(L"Should have been able to unescape \\U10FFFF\n");
}
#if WCHAR_MAX != 0xffff
// TODO: Make this work on MS Windows.
if (!unescape_string(L"echo \\U10FFFF", &output, UNESCAPE_DEFAULT)) {
err(L"Should have been able to unescape \\U10FFFF\n");
}
#endif
}
/// Test the escaping/unescaping code by escaping/unescaping random strings and verifying that the
@@ -486,7 +565,7 @@ static parser_test_error_bits_t detect_argument_errors(const wcstring &src) {
return PARSER_TEST_ERROR;
}
assert(!tree.empty());
assert(!tree.empty()); //!OCLINT(multiple unary operator)
const parse_node_t *first_arg = tree.next_node_in_node_list(tree.at(0), symbol_argument, NULL);
assert(first_arg != NULL);
return parse_util_detect_errors_in_argument(*first_arg, first_arg->get_source(src));
@@ -495,7 +574,6 @@ static parser_test_error_bits_t detect_argument_errors(const wcstring &src) {
/// Test the parser.
static void test_parser() {
say(L"Testing parser");
parser_t parser;
say(L"Testing block nesting");
if (!parse_util_detect_errors(L"if; end")) {
@@ -629,7 +707,8 @@ static void test_parser() {
#if 0
// This is disabled since it produces a long backtrace. We should find a way to either visually
// compress the backtrace, or disable error spewing.
parser_t::principal_parser().eval(L"function recursive1 ; recursive2 ; end ; function recursive2 ; recursive1 ; end ; recursive1; ", io_chain_t(), TOP);
parser_t::principal_parser().eval(L"function recursive1 ; recursive2 ; end ; "
L"function recursive2 ; recursive1 ; end ; recursive1; ", io_chain_t(), TOP);
#endif
say(L"Testing empty function name");
@@ -835,19 +914,21 @@ static void test_utf82wchar(const char *src, size_t slen, const wchar_t *dst, si
size_t size;
wchar_t *mem = NULL;
#if WCHAR_MAX == 0xffff
// Hack: if wchar is only UCS-2, and the UTF-8 input string contains astral characters, then
// tweak the expected size to 0.
if (src != NULL && is_wchar_ucs2()) {
if (src) {
// A UTF-8 code unit may represent an astral code point if it has 4 or more leading 1s.
const unsigned char astral_mask = 0xF0;
for (size_t i = 0; i < slen; i++) {
if ((src[i] & astral_mask) == astral_mask) {
// Astral char. We expect this conversion to just fail.
res = 0;
// Astral char. We want this conversion to fail.
res = 0; //!OCLINT(parameter reassignment)
break;
}
}
}
#endif
if (!dst) {
size = utf8_to_wchar(src, slen, NULL, flags);
@@ -884,18 +965,20 @@ static void test_wchar2utf8(const wchar_t *src, size_t slen, const char *dst, si
size_t size;
char *mem = NULL;
#if WCHAR_MAX == 0xffff
// Hack: if wchar is simulating UCS-2, and the wchar_t input string contains astral characters,
// then tweak the expected size to 0.
if (src != NULL && is_wchar_ucs2()) {
if (src) {
const uint32_t astral_mask = 0xFFFF0000U;
for (size_t i = 0; i < slen; i++) {
if ((src[i] & astral_mask) != 0) {
/* astral char */
res = 0;
// Astral char. We want this conversion to fail.
res = 0; //!OCLINT(parameter reassignment)
break;
}
}
}
#endif
if (dst) {
mem = (char *)malloc(dlen);
@@ -927,10 +1010,7 @@ static void test_utf8() {
wchar_t w1[] = {0x54, 0x65, 0x73, 0x74};
wchar_t w2[] = {0x0422, 0x0435, 0x0441, 0x0442};
wchar_t w3[] = {0x800, 0x1e80, 0x98c4, 0x9910, 0xff00};
wchar_t w4[] = {0x15555, 0xf7777, 0x0a};
wchar_t wb[] = {(wchar_t)-2, 0xa, (wchar_t)0xffffffff, 0x0441};
wchar_t wm[] = {0x41, 0x0441, 0x3042, 0xff67, 0x9b0d};
wchar_t wb1[] = {0x0a, 0x0422};
wchar_t wb2[] = {0xd800, 0xda00, 0x41, 0xdfff, 0x0a};
wchar_t wbom[] = {0xfeff, 0x41, 0x0a};
wchar_t wbom2[] = {0x41, 0xa};
@@ -939,14 +1019,19 @@ static void test_utf8() {
unsigned char u2[] = {0xd0, 0xa2, 0xd0, 0xb5, 0xd1, 0x81, 0xd1, 0x82};
unsigned char u3[] = {0xe0, 0xa0, 0x80, 0xe1, 0xba, 0x80, 0xe9, 0xa3,
0x84, 0xe9, 0xa4, 0x90, 0xef, 0xbc, 0x80};
unsigned char u4[] = {0xf0, 0x95, 0x95, 0x95, 0xf3, 0xb7, 0x9d, 0xb7, 0x0a};
unsigned char ub[] = {0xa, 0xd1, 0x81};
unsigned char um[] = {0x41, 0xd1, 0x81, 0xe3, 0x81, 0x82, 0xef, 0xbd, 0xa7, 0xe9, 0xac, 0x8d};
unsigned char ub1[] = {0xa, 0xff, 0xd0, 0xa2, 0xfe, 0x8f, 0xe0, 0x80};
unsigned char uc080[] = {0xc0, 0x80};
unsigned char ub2[] = {0xed, 0xa1, 0x8c, 0xed, 0xbe, 0xb4, 0x0a};
unsigned char ubom[] = {0x41, 0xa};
unsigned char ubom2[] = {0xef, 0xbb, 0xbf, 0x41, 0x0a};
#if WCHAR_MAX != 0xffff
wchar_t w4[] = {0x15555, 0xf7777, 0x0a};
wchar_t wb[] = {(wchar_t)-2, 0xa, (wchar_t)0xffffffff, 0x0441};
wchar_t wb1[] = {0x0a, 0x0422};
unsigned char u4[] = {0xf0, 0x95, 0x95, 0x95, 0xf3, 0xb7, 0x9d, 0xb7, 0x0a};
unsigned char ub[] = {0xa, 0xd1, 0x81};
unsigned char ub1[] = {0xa, 0xff, 0xd0, 0xa2, 0xfe, 0x8f, 0xe0, 0x80};
#endif
// UTF-8 -> UCS-4 string.
test_utf82wchar(ubom2, sizeof(ubom2), wbom2, sizeof(wbom2) / sizeof(*wbom2), UTF8_SKIP_BOM,
@@ -990,18 +1075,6 @@ static void test_utf8() {
test_wchar2utf8(w1, sizeof(w1) / sizeof(*w1), u1, 0, 0, 0, "invalid params, dst is not NULL");
test_wchar2utf8(NULL, 10, nullc, 0, 0, 0, "invalid params, src length is not 0");
// The following tests won't pass on systems (e.g., Cygwin) where sizeof wchar_t is 2. That's
// due to several reasons but the primary one is that narrowing conversions of literals assigned
// to the wchar_t arrays above don't result in values that will be treated as errors by the
// conversion functions.
if (is_wchar_ucs2()) return;
test_utf82wchar(u4, sizeof(u4), w4, sizeof(w4) / sizeof(*w4), 0, sizeof(w4) / sizeof(*w4),
"u4/w4 4 octets chars");
test_wchar2utf8(w4, sizeof(w4) / sizeof(*w4), u4, sizeof(u4), 0, sizeof(u4),
"w4/u4 4 octets chars");
test_wchar2utf8(wb, sizeof(wb) / sizeof(*wb), ub, sizeof(ub), 0, 0, "wb/ub bad chars");
test_wchar2utf8(wb, sizeof(wb) / sizeof(*wb), ub, sizeof(ub), UTF8_IGNORE_ERROR, sizeof(ub),
"wb/ub ignore bad chars");
test_wchar2utf8(wm, sizeof(wm) / sizeof(*wm), um, sizeof(um), 0, sizeof(um),
"wm/um mixed languages");
test_wchar2utf8(wm, sizeof(wm) / sizeof(*wm), um, sizeof(um) - 1, 0, 0, "wm/um boundaries -1");
@@ -1009,20 +1082,34 @@ static void test_utf8() {
"wm/um boundaries +1");
test_wchar2utf8(wm, sizeof(wm) / sizeof(*wm), nullc, 0, 0, sizeof(um),
"wm/um calculate length");
test_utf82wchar(um, sizeof(um), wm, sizeof(wm) / sizeof(*wm), 0, sizeof(wm) / sizeof(*wm),
"um/wm mixed languages");
test_utf82wchar(um, sizeof(um), wm, sizeof(wm) / sizeof(*wm) + 1, 0, sizeof(wm) / sizeof(*wm),
"um/wm boundaries +1");
test_utf82wchar(um, sizeof(um), NULL, 0, 0, sizeof(wm) / sizeof(*wm), "um/wm calculate length");
// The following tests won't pass on systems (e.g., Cygwin) where sizeof wchar_t is 2. That's
// due to several reasons but the primary one is that narrowing conversions of literals assigned
// to the wchar_t arrays above don't result in values that will be treated as errors by the
// conversion functions.
#if WCHAR_MAX != 0xffff
test_utf82wchar(u4, sizeof(u4), w4, sizeof(w4) / sizeof(*w4), 0, sizeof(w4) / sizeof(*w4),
"u4/w4 4 octets chars");
test_wchar2utf8(w4, sizeof(w4) / sizeof(*w4), u4, sizeof(u4), 0, sizeof(u4),
"w4/u4 4 octets chars");
test_wchar2utf8(wb, sizeof(wb) / sizeof(*wb), ub, sizeof(ub), 0, 0, "wb/ub bad chars");
test_wchar2utf8(wb, sizeof(wb) / sizeof(*wb), ub, sizeof(ub), UTF8_IGNORE_ERROR, sizeof(ub),
"wb/ub ignore bad chars");
test_wchar2utf8(wb, sizeof(wb) / sizeof(*wb), nullc, 0, 0, 0,
"wb calculate length of bad chars");
test_wchar2utf8(wb, sizeof(wb) / sizeof(*wb), nullc, 0, UTF8_IGNORE_ERROR, sizeof(ub),
"calculate length, ignore bad chars");
test_utf82wchar(ub1, sizeof(ub1), wb1, sizeof(wb1) / sizeof(*wb1), UTF8_IGNORE_ERROR,
sizeof(wb1) / sizeof(*wb1), "ub1/wb1 ignore bad chars");
test_utf82wchar(um, sizeof(um), wm, sizeof(wm) / sizeof(*wm), 0, sizeof(wm) / sizeof(*wm),
"um/wm mixed languages");
test_utf82wchar(um, sizeof(um), wm, sizeof(wm) / sizeof(*wm) + 1, 0, sizeof(wm) / sizeof(*wm),
"um/wm boundaries +1");
test_utf82wchar(um, sizeof(um), NULL, 0, 0, sizeof(wm) / sizeof(*wm), "um/wm calculate length");
test_utf82wchar(ub1, sizeof(ub1), NULL, 0, 0, 0, "ub1 calculate length of bad chars");
test_utf82wchar(ub1, sizeof(ub1), NULL, 0, UTF8_IGNORE_ERROR, sizeof(wb1) / sizeof(*wb1),
"ub1 calculate length, ignore bad chars");
#endif
}
static void test_escape_sequences(void) {
@@ -1139,7 +1226,8 @@ static bool expand_test(const wchar_t *in, expand_flags_t flags, ...) {
}
if (!res) {
if ((arg = va_arg(va, wchar_t *)) != 0) {
arg = va_arg(va, wchar_t *);
if (arg) {
wcstring msg = L"Expected [";
bool first = true;
for (wcstring_list_t::const_iterator it = expected.begin(), end = expected.end();
@@ -2209,7 +2297,6 @@ static void test_history_matches(history_search_t &search, size_t matches, unsig
size_t i;
for (i = 0; i < matches; i++) {
do_test(search.go_backwards());
wcstring item = search.current_string();
}
// do_test_from(!search.go_backwards(), from_line);
bool result = search.go_backwards();
@@ -2403,9 +2490,13 @@ bool poll_notifier(universal_notifier_t *note) {
static void trigger_or_wait_for_notification(universal_notifier_t *notifier,
universal_notifier_t::notifier_strategy_t strategy) {
// This argument should be removed if it isn't actually needed by these unit tests. I'm going to
// silence the warning. See https://github.com/fish-shell/fish-shell/issues/3439.
UNUSED(notifier);
switch (strategy) {
case universal_notifier_t::strategy_default: {
assert(0 && "strategy_default should be passed");
DIE("strategy_default should be passed");
break;
}
case universal_notifier_t::strategy_shmem_polling: {
@@ -2815,6 +2906,22 @@ void history_tests_t::test_history_merge(void) {
}
}
// Make sure incorporate_external_changes doesn't drop items! (#3496)
history_t *const writer = hists[0];
history_t *const reader = hists[1];
const wcstring more_texts[] = {L"Item_#3496_1", L"Item_#3496_2", L"Item_#3496_3",
L"Item_#3496_4", L"Item_#3496_5", L"Item_#3496_6"};
for (size_t i = 0; i < sizeof more_texts / sizeof *more_texts; i++) {
// time_barrier because merging will ignore items that may be newer
if (i > 0) time_barrier();
writer->add(more_texts[i]);
writer->incorporate_external_changes();
reader->incorporate_external_changes();
for (size_t j = 0; j < i; j++) {
do_test(history_contains(reader, more_texts[j]));
}
}
// Clean up.
for (size_t i = 0; i < 3; i++) {
delete hists[i];
@@ -3063,35 +3170,35 @@ static bool test_1_parse_ll2(const wcstring &src, wcstring *out_cmd, wcstring *o
out_joined_args->clear();
*out_deco = parse_statement_decoration_none;
bool result = false;
parse_node_tree_t tree;
if (parse_tree_from_string(src, parse_flag_none, &tree, NULL)) {
// Get the statement. Should only have one.
const parse_node_tree_t::parse_node_list_t stmt_nodes =
tree.find_nodes(tree.at(0), symbol_plain_statement);
if (stmt_nodes.size() != 1) {
say(L"Unexpected number of statements (%lu) found in '%ls'", stmt_nodes.size(),
src.c_str());
return false;
}
const parse_node_t &stmt = *stmt_nodes.at(0);
// Return its decoration.
*out_deco = tree.decoration_for_plain_statement(stmt);
// Return its command.
tree.command_for_plain_statement(stmt, src, out_cmd);
// Return arguments separated by spaces.
const parse_node_tree_t::parse_node_list_t arg_nodes =
tree.find_nodes(stmt, symbol_argument);
for (size_t i = 0; i < arg_nodes.size(); i++) {
if (i > 0) out_joined_args->push_back(L' ');
out_joined_args->append(arg_nodes.at(i)->get_source(src));
}
result = true;
if (!parse_tree_from_string(src, parse_flag_none, &tree, NULL)) {
return false;
}
return result;
// Get the statement. Should only have one.
const parse_node_tree_t::parse_node_list_t stmt_nodes =
tree.find_nodes(tree.at(0), symbol_plain_statement);
if (stmt_nodes.size() != 1) {
say(L"Unexpected number of statements (%lu) found in '%ls'", stmt_nodes.size(),
src.c_str());
return false;
}
const parse_node_t &stmt = *stmt_nodes.at(0);
// Return its decoration.
*out_deco = tree.decoration_for_plain_statement(stmt);
// Return its command.
tree.command_for_plain_statement(stmt, src, out_cmd);
// Return arguments separated by spaces.
const parse_node_tree_t::parse_node_list_t arg_nodes = tree.find_nodes(stmt, symbol_argument);
for (size_t i = 0; i < arg_nodes.size(); i++) {
if (i > 0) out_joined_args->push_back(L' ');
out_joined_args->append(arg_nodes.at(i)->get_source(src));
}
return true;
}
// Test the LL2 (two token lookahead) nature of the parser by exercising the special builtin and
@@ -3255,29 +3362,31 @@ static wcstring_list_t separate_by_format_specifiers(const wchar_t *format) {
// Walk over the format specifier (if any).
cursor = next_specifier;
if (*cursor == '%') {
cursor++;
// Flag
if (wcschr(L"#0- +'", *cursor)) cursor++;
// Minimum field width
while (iswdigit(*cursor)) cursor++;
// Precision
if (*cursor == L'.') {
cursor++;
while (iswdigit(*cursor)) cursor++;
}
// Length modifier
if (!wcsncmp(cursor, L"ll", 2) || !wcsncmp(cursor, L"hh", 2)) {
cursor += 2;
} else if (wcschr(L"hljtzqL", *cursor)) {
cursor++;
}
// The format specifier itself. We allow any character except NUL.
if (*cursor != L'\0') {
cursor += 1;
}
assert(cursor <= end);
if (*cursor != '%') {
continue;
}
cursor++;
// Flag
if (wcschr(L"#0- +'", *cursor)) cursor++;
// Minimum field width
while (iswdigit(*cursor)) cursor++;
// Precision
if (*cursor == L'.') {
cursor++;
while (iswdigit(*cursor)) cursor++;
}
// Length modifier
if (!wcsncmp(cursor, L"ll", 2) || !wcsncmp(cursor, L"hh", 2)) {
cursor += 2;
} else if (wcschr(L"hljtzqL", *cursor)) {
cursor++;
}
// The format specifier itself. We allow any character except NUL.
if (*cursor != L'\0') {
cursor += 1;
}
assert(cursor <= end);
}
return result;
}
@@ -3852,7 +3961,7 @@ long return_timezone_hour(time_t tstamp, const wchar_t *timezone) {
struct tm ltime;
char ltime_str[3];
char *str_ptr;
int n;
size_t n;
env_set(L"TZ", timezone, ENV_EXPORT);
localtime_r(&tstamp, &ltime);
@@ -3904,7 +4013,7 @@ int main(int argc, char **argv) {
}
}
srand(time(0));
srand((unsigned int)time(NULL));
configure_thread_assertions_for_testing();
program_name = L"(ignore)";
@@ -3927,6 +4036,7 @@ int main(int argc, char **argv) {
// Set default signal handlers, so we can ctrl-C out of this.
signal_reset_handlers();
if (should_test_function("str_to_num")) test_str_to_num();
if (should_test_function("highlighting")) test_highlighting();
if (should_test_function("new_parser_ll2")) test_new_parser_ll2();
if (should_test_function("new_parser_fuzzing"))

View File

@@ -161,7 +161,7 @@ void function_add(const function_data_t &data, const parser_t &parser, int defin
UNUSED(parser);
ASSERT_IS_MAIN_THREAD();
CHECK(!data.name.empty(), );
CHECK(!data.name.empty(), ); //!OCLINT(multiple unary operator)
CHECK(data.definition, );
scoped_lock locker(functions_lock);
@@ -272,9 +272,9 @@ bool function_get_desc(const wcstring &name, wcstring *out_desc) {
if (out_desc && func && !func->description.empty()) {
out_desc->assign(_(func->description.c_str()));
return true;
} else {
return false;
}
return false;
}
void function_set_desc(const wcstring &name, const wcstring &desc) {
@@ -311,8 +311,8 @@ wcstring_list_t function_get_names(int get_hidden) {
const wcstring &name = iter->first;
// Maybe skip hidden.
if (!get_hidden) {
if (name.empty() || name.at(0) == L'_') continue;
if (!get_hidden && (name.empty() || name.at(0) == L'_')) {
continue;
}
names.insert(name);
}

Some files were not shown because too many files have changed in this diff Show More