Compare commits

..

104 Commits

Author SHA1 Message Date
Johannes Altmanninger
56bbdb3f39 Release 4.0.9
Created by ./build_tools/release.sh 4.0.9
2025-09-27 20:24:24 +02:00
Johannes Altmanninger
ce4aa7669d Release workflow fixups 2025-09-27 20:20:44 +02:00
Johannes Altmanninger
af8d8d3d1b release-notes.sh: add stats, round off committer list
Instead of adding these to the Markdown directly, add it to the
fake CHANGELOG.rst source, which makes escaping easier, and allows
generating other formats than Markdown in future.

(cherry picked from commit 06bbac8ed6)
2025-09-27 14:23:25 +02:00
Johannes Altmanninger
fecd0b4bf1 Revert "Only load sphinx_markdown_builder extension if it's used"
sphinx-build fails with

	sphinx.errors.SphinxError: Builder name markdown not registered or available through entry point

Apparently this issue was hidden locally by caching, and not checked
in CI because of this error causing
tests/checks/sphinx-markdown-changelog.fish to be skipped.

	sphinx-build 7.2.6
	runner@runnervm3ublj:~/work/fish-shell/fish-shell$ python -c 'import sphinx_markdown_builder'
	Traceback (most recent call last):
	  File "<string>", line 1, in <module>
	  File "/home/runner/.local/lib/python3.12/site-packages/sphinx_markdown_builder/__init__.py", line 6, in <module>
	    from sphinx.util.typing import ExtensionMetadata
	ImportError: cannot import name 'ExtensionMetadata' from 'sphinx.util.typing' (/usr/lib/python3/dist-packages/sphinx/util/typing.py)

This reverts commit 7b495497d7.

While at it, fail the test earlier if something went wrong, because the
remaining check will likely also fail and confuse.

(cherry picked from commit aab22a453b)
2025-09-27 14:23:25 +02:00
Johannes Altmanninger
2d4a43302a release-notes.sh: remove line breaks from generated Markdown, for GitHub
GitHub-flavored Markdown translates line breaks to <br/>, which does
not match our intent. Work around that by joining lines when producing
Markdown output.

(cherry picked from commit 4cc2d2ec30)
2025-09-27 14:23:25 +02:00
Johannes Altmanninger
5a4a913220 Enable sphinx parallelism also when building markdown release notes
We get a warning about sphinx_markdown_builder not being
parallelizable. Fix that.

Ref: https://github.com/liran-funaro/sphinx-markdown-builder/pull/38
(cherry picked from commit e6541c5c93)
2025-09-27 06:03:16 +02:00
Johannes Altmanninger
904ceba858 Only load sphinx_markdown_builder extension if it's used
As is, building man pages or HTML docs while sphinx_markdown_builder
is installed, will result in unrelated warnings.  Remove those by
removing it from the extensions config.  Markdown building (only used
for changelog) seems to work without this just fine.

(cherry picked from commit 7b495497d7)
2025-09-27 06:03:16 +02:00
Johannes Altmanninger
3c2adfbd4b Fix markdown changelog generation test
System tests typically run outside the workspace directory, but they
still have read-only access to the workspace; fix it accordingly.
This test only works on git checkouts, not in tarballs, so skip it
if .git doesn't exist.

(cherry picked from commit 6e90d9bd6f)
2025-09-27 06:03:16 +02:00
Johannes Altmanninger
9e4850b40a Disable sphinx-markdown-builder in tests again for now
Somehow I didn't realize this breaks the tests/checks/sphinx-* tests.

(cherry picked from commit b37b57781b)
2025-09-27 06:03:16 +02:00
Johannes Altmanninger
211b3f6670 release workflow: credit contributors in release notes
While at it, do a 's/^--$/^---/' to fix Markdown syntax for horizontal
line for CommonMark-based parsers.

(cherry picked from commit 22ffc31b71)
2025-09-24 15:58:42 +02:00
Johannes Altmanninger
d530e127f5 Test markdown changelog creation in CI
Extract a github action to install the same version used in the release
workflow.  In future we should probably migrate to requirements.txt
or similar.

(cherry picked from commit 127c02992d)
2025-09-24 15:58:42 +02:00
Johannes Altmanninger
a6698098db release workflow: resolve relative references in changelog properly
Instead of having sphinx-build only build CHANGELOG.rst, build the
entire thing, so relative references (":doc:", ":ref:") can be resolved
properly.  Replace our sed-based hacks with 'markdown_http_base'.

(cherry picked from commit 765ca54d59)
2025-09-24 15:58:42 +02:00
Johannes Altmanninger
f73b260a3a release workflow: extract script for generating markdown release notes
(cherry picked from commit 1519ea74be)
2025-09-24 15:58:42 +02:00
Daniel Rainer
ffa7abd6ff Fix release workflow syntax
The previous version results in an immediate workflow failure due to a
syntax error in the YAML. `workflow_dispatch` should be a dictionary
key, with its value being another dictionary (whose only key is `inputs`
at the moment).

(cherry picked from commit c8f31ceedb)
2025-09-24 15:58:42 +02:00
Johannes Altmanninger
b87ef689fa github release workflow: fix structure
(cherry picked from commit b1d1ef1b6e)
2025-09-24 15:58:42 +02:00
Johannes Altmanninger
4fe70f6965 github release workflow: only run on explicit dispatch
Release automation can be tested on any GitHub fork, using

	build_tools/release.sh $version $repository_owner $git_remote

which should work perfectly except for macOS packages (which fail
unless provided GitHub secrets).

People might push tags to their forks, both non-release tags (which
would trigger an early failure in "is-release-tag") or replicas of
our actual release tags (which would create a draft release etc. and
only fail when building macOS packages).

Run on explicit workflow dispatch to make sure it's not triggered by
accident like that.

This means that we'll use the .github/workflows/release.yml from
the default branch (i.e. master), so try to make sure it matches the
version in the release, to prevent accidents.

Closes #11816

(cherry picked from commit 01361b9217)
2025-09-24 15:58:42 +02:00
Johannes Altmanninger
7001abca9f github release workflow: use github context only if needed
(cherry picked from commit dab8df1a18)
2025-09-24 15:58:42 +02:00
Johannes Altmanninger
199316f1a3 build_tools/make_macos_pkg.sh: fix inconsistent version computation
make_tarball.sh and others do it differently.

(cherry picked from commit c771ff06d4)
2025-09-24 15:58:42 +02:00
David Adam
78c9ab29cd debian packaging: don't remove Cargo.toml.orig files
Newer versions of cargo include the Cargo.toml.orig file when vendoring,
but dh_clean removes those by default. Try to disable this to fix the
package builds again.

(cherry picked from commit 67e8657109)
2025-09-21 10:41:44 +08:00
David Adam
91c9dbdd89 debian packaging: use the correct test target
(cherry picked from commit 5e2ddaace9)
2025-09-21 10:41:44 +08:00
David Adam
e737ad1f0f debian packaging: fix typo 2025-09-20 22:11:10 +08:00
Johannes Altmanninger
6f536c6304 Fix new job control test; changelog 2025-09-20 14:57:49 +02:00
Piotr Kubaj
a1b4b391b2 path.rs: fix build on ARM / POWER
error[E0308]: mismatched types
   --> src/path.rs:749:13
    |
748 |         let remoteness = remoteness_via_statfs(
    |                          --------------------- arguments to this function are incorrect
749 |             libc::statfs,
    |             ^^^^^^^^^^^^ expected fn pointer, found fn item
    |
    = note: expected fn pointer `unsafe extern "C" fn(*const i8, _) -> _`
                  found fn item `unsafe extern "C" fn(*const u8, _) -> _ {libc::statfs}`
note: function defined here
   --> src/path.rs:712:12
    |
712 |         fn remoteness_via_statfs<StatFS, Flags>(
    |            ^^^^^^^^^^^^^^^^^^^^^
713 |             statfn: unsafe extern "C" fn(*const i8, *mut StatFS) -> libc::c_int,
    |             -------------------------------------------------------------------

error[E0308]: mismatched types
   --> src/path.rs:725:34
    |
725 |             if unsafe { (statfn)(path.as_ptr(), buf.as_mut_ptr()) } < 0 {
    |                         -------- ^^^^^^^^^^^^^ expected `*const i8`, found `*const u8`
    |                         |
    |                         arguments to this function are incorrect
    |
    = note: expected raw pointer `*const i8`
               found raw pointer `*const u8`

For more information about this error, try `rustc --explain E0308`.
error: could not compile `fish` (lib) due to 2 previous errors

(cherry picked from commit 91ee45b0e1)
2025-09-20 14:32:55 +02:00
Johannes Altmanninger
a27f615350 Fix crash on "bg" of non-job-controlled job
fish -c 'sleep 1 & bg %1' is supposed to fail because the job is not
under job control.

When we try to print the failure, we accidentally still
hold a borrow of the job list.  This blows up because we use
"builtin_print_help_error()" to print the failure message; that
function runs "job_reap()" which wants an exclusive borrow of the
job list. Let's drop our job list earlier.

(cherry picked from commit 26116b477e)
2025-09-20 14:03:49 +02:00
Johannes Altmanninger
46ce8a1d2f Fix regression breaking self-insert of kitty shifted codepoint
Commit 50a6e486a5 (Allow explicit shift modifier for non-ASCII
letters, fix capslock behavior, 2025-03-30) delayed handling of kitty
keyboard protocol's shifted codepoints.  It does handle shifted
codepoints when matching keys to mappings; but it fails to handle
them in the self-insert code paths where we want to insert the text
represented by CharEvent::Key.
Fix it by resolving the shifted key.

Fixes #11813

(cherry picked from commit bb916f8d73)
2025-09-20 14:03:38 +02:00
Johannes Altmanninger
03ccc88868 Move key codepoint computation to key event
For the next commit.

(cherry picked from commit 8d12dfe065)
2025-09-20 14:02:30 +02:00
Johannes Altmanninger
79cf4c3e0b build_tools/release.sh: approve macos-codesign 2025-09-19 09:53:02 +02:00
Johannes Altmanninger
701e1a3b02 github release workflow: make sure that last changelog entry isn't given spurious markup
(cherry picked from commit ff633bd744)
2025-09-18 10:46:40 +02:00
Johannes Altmanninger
b1ec703ceb Release 4.0.8
Created by ./build_tools/release.sh 4.0.8
2025-09-18 10:00:03 +02:00
Johannes Altmanninger
553612f74a github release workflow: work around trailing "---"-line in changelog
The extracted release notes trigger a sphinx warning

	/tmp/tmp.V6RGP92nc2/src/index.rst:6:Document may not end with a transition.

which we don't seem to get on the full CHANGELOG.rst.
Let's work around that for now.

(cherry picked from commit 0d46c26988)
2025-09-18 09:58:55 +02:00
Johannes Altmanninger
861decb003 build_tools/release.sh: relax assertion about changelog title
I'd like to move to a process where everything goes into master first,
and then flows downstream to any release branches (i.e. no merging
of Integration_* branches back into master).

The only thing we need to change for that is to add release notes for
patch releases eagerly on master.  That implies that we want to use
the actual version instead of ???.  (Only if something goes wrong
in the release process, we need to change this on both branches,
but that should happen too often.)

(cherry picked from commit 1840df96a2)
2025-09-18 09:38:30 +02:00
Johannes Altmanninger
3b8780aa6c build_tools/release.sh: push to the integration branch when all goes well
Also, ignore any "sendemail.to" Git config, and remove a temporary
statement in release notes.

(cherry picked from commit 3456b33050)
2025-09-18 09:32:37 +02:00
Johannes Altmanninger
7783505bee Fix new-style bindings shadowing raw escape sequence bindings
Given

	bind up "echo user up, new notation"
	bind \e\[A "echo user up, legacy notation"

prior to b9d9e7edc6 (Match bindings with explicit shift
first, 2025-05-24), we prioritized the legacy notation because
input_mapping_insert_sorted() makes us try longer sequences first --
and "up" is only one key compared to the three-key legacy sequence.

This prioritization was broken in b9d9e7edc6, causing plugins that
update to the "bind up" notation to break users who haven't (#11803).

Even worse, it caused preset bindings to shadow user ones:

	bind --preset up "echo preset up, new notation"
	bind \e\[A "echo user up, legacy notation"

Restore backwards compatibility by treating matches against legacy
notation like exact matches again.

(cherry picked from commit 9a04c15894)
2025-09-18 09:29:45 +02:00
Johannes Altmanninger
23c25ffe43 build_tools/release.sh: fixes for updating fish-site
Also check that "cd fish-site && make && make new-release" doesn't
leave behind untracked files we're not aware of.  This implies that
this script ought to refuse to run if there are untracked files,
at least in fish-site.

(cherry picked from commit 529f722d2f)
2025-09-13 11:13:17 +02:00
Johannes Altmanninger
7619fa316c Release 4.0.6
Created by ./build_tools/release.sh 4.0.6
2025-09-12 11:47:41 +02:00
Johannes Altmanninger
e2005c64b3 Backport release-script related changes from master
Will commit these to master momentarily (#10449).
2025-09-12 11:47:01 +02:00
Johannes Altmanninger
9ada3e6c16 Group changelog entries 2025-09-12 11:14:52 +02:00
Johannes Altmanninger
bdba2c227d CHANGELOG: update 2025-09-11 13:55:30 +02:00
Johannes Altmanninger
201882e72a CHANGELOG: fix inline literal RST syntax 2025-09-09 07:46:31 +02:00
Johannes Altmanninger
1db0ff9f77 Allow overriding __fish_update_cwd_osc to work around terminal bugs
See #11777

While at it, pull in the TERM=dumb check from master.

(cherry picked from commit 898cc3242b)
2025-09-05 09:39:57 +02:00
Johannes Altmanninger
9258275fe6 config_paths: fix compiled-in locale dir for installed, non-embed builds
Commit bf65b9e3a7 (Change `gettext` paths to be relocatable (#11195),
2025-03-30) broke the locale path.

Commit c3740b85be (config_paths: fix compiled-in locale dir,
2025-06-12) fixed what it calls "case 4", but "case 2" is also
affected; fix that. Before/after:

	$ ~/.local/opt/fish/bin/fish -d config
	paths.locale: /home/johannes/.local/opt/fish/share/fish/locale
	$ ~/.local/opt/fish/bin/fish -d config
	paths.locale: /home/johannes/.local/opt/fish/share/locale

See https://github.com/fish-shell/fish-shell/issues/11683#issuecomment-3218190662

(cherry picked from commit 21a07f08a3)
2025-08-29 19:29:03 +02:00
Johannes Altmanninger
6900b89c82 Add mark-prompt feature flag
So far, terminals that fail to parse OSC sequences are the only reason
for wanting to turn off OSC 133.  Let's allow to work around it by
adding a feature flag (which is implied to be temporary).

To use it, run this once, and restart fish:

    set -Ua fish_features no-mark-prompt

Tested with

    fish -i | string escape | grep 133 &&
    ! fish_features=no-mark-prompt fish -i | string escape | grep 133

See #11749
Also #11609
2025-08-27 09:17:35 +02:00
Johannes Altmanninger
9c0086b7af Backport default alt-delete binding
This is standard on macOS and in chrome/firefox.

On master, this was sneakily added in
2bb5cbc959 (Default bindings for token movements v2, 2025-03-04)
and before that in
6af96a81a8 (Default bindings for token movement commands, 2024-10-05)

Ref: https://lobste.rs/s/ndlwoh/wizard_his_shell#c_qvhnvd
2025-08-02 09:53:22 +02:00
Johannes Altmanninger
e200abe39c __fish_seen_subcommand_from: fix regression causing false negatives given multiple arguments
Fixes 2bfa7db7bc (Restructure __fish_seen_subcommand_from, 2024-07-07)
Fixes #11685

(cherry picked from commit 4412164fd4)
2025-07-26 20:36:53 +02:00
Johannes Altmanninger
0c8f1f4220 Fix async-signal safety in SIGTERM handler
Cherry-picked from
- 941701da3d (Restore some async-signal discipline to SIGTERM, 2025-06-15)
- 81d45caa76e (Restore terminal state on SIGTERM again, 2025-06-21)

Also, be more careful in terminal_protocols_disable_ifn about accessing
reader_current_data(), as pointed out in 65a4cb5245 (Revert "Restore terminal
state on SIGTERM again", 2025-07-19).

See #11597
2025-07-26 13:09:18 +02:00
Johannes Altmanninger
e593da1c2e Increase timeout when reading escape sequences inside paste/kitty kbd
Historically, fish has treated input bytes [0x1b, 'b'] as alt-b (rather than
"escape,b") if the second byte arrives within 30ms of the first.

Since we made builtin bind match key events instead of raw byte sequences,
we have another place where we do similar disambiguation: when we read keys
such as alt-left ("\e[1;3D"), we only consider bytes to be part of this
sequence if stdin is immediately readable (actually "readable after a 1ms
timeout" since e1be842 (Work around torn byte sequences in qemu kbd input
with 1ms timeout, 2025-03-04)).

This is technically wrong but has worked in practice (for Kakoune etc.).

Issue #11668 reports two issues on some Windows terminals feeding a remote
fish shell:
- the "bracketed paste finished" sequence may be split into multiple packets,
  which causes a delay of > 1ms between individual bytes being readable.
- AutoHotKey scripts simulating seven "left" keys result in sequence tearing
  as well.

Try to fix the paste case by increasing the timeout when parsing escape
sequences.

Also increase the timeout for terminals that support the kitty keyboard
protocol.  The user should only notice this new delay after pressing one of
escape,O, escape,P, escape,[, or escape,] **while the kitty keyboard protocol
is disabled** (e.g. while an external command is running).  In this case,
the fish_escape_delay_ms is also virtually increased; hopefully this edge
case is not ever relevant.

Part of #11668

(cherry picked from commit 30ff3710a0)
2025-07-25 18:29:19 +02:00
Johannes Altmanninger
6666c8f1cd Block interrupts and uvar events while decoding key
readb() has only one caller that passes blocking=false: try_readb().
This function is used while decoding keys; anything but a successful read
is treated as "end of input sequence".

This means that key input sequences such as \e[1;3D
can be torn apart by
- signals (EINTR) which is more likely since e1be842 (Work around torn byte
  sequences in qemu kbd input with 1ms timeout, 2025-03-04).
- universal variable notifications (from other fish processes)

Fix this by blocking signals and not listening on the uvar fd.  We do something
similar when matching key sequences against bindings, so extract a function
and use it for key decoding too.

Ref: https://github.com/fish-shell/fish-shell/issues/11668#issuecomment-3101341081
(cherry picked from commit da96172739)
2025-07-25 18:21:27 +02:00
Johannes Altmanninger
3e61036911 Revert "Change readch() into try_readch()"
try_readch() was added to help a fuzzing harness, specifically to avoid a
call to `unreachable!()` in the NothingToRead case.  I don't know much about
that but it seems like we should find a better way to tell the fuzzer that
this can't happen.

Fortunately the next commit will get rid of readb()'s "blocking" argument,
along the NothingToRead enum variant. So we'll no longer need this.

This reverts commit b92830cb17.

(cherry picked from commit fb7ee0db74)
2025-07-25 18:21:27 +02:00
Johannes Altmanninger
f23a479b81 Reduce MaybeUninit lifetime
(cherry picked from commit 137f220225)
2025-07-25 18:21:27 +02:00
王宇逸
e274ff41d0 Use uninit instead of zeroed (src/input_common.rs)
(cherry picked from commit 7c2c7f5874)
2025-07-25 18:21:27 +02:00
Johannes Altmanninger
d2af306f3d Fix some unused-ControlFlow warnings 2025-07-25 18:11:04 +02:00
Johannes Altmanninger
0e7c7f1745 Remove unused import
(cherry picked from commit 07ff4e7df0)
2025-07-25 11:57:21 +02:00
Johannes Altmanninger
3fada80553 Fix regression causing \e[ to be interpreted as ctrl-[
Fixes 3201cb9f01 (Stop parsing invalid CSI/SS3 sequences as alt-[/alt-o,
2024-12-30).

(cherry picked from commit 43d583d991)
2025-07-25 11:49:07 +02:00
Johannes Altmanninger
c7d4acbef8 Update changelog 2025-06-29 16:01:44 +02:00
Johannes Altmanninger
e204a4c126 Add ctrl-alt-h compatibility binding
Historically, ctrl-i sends the same code as tab, ctrl-h sends backspace and
ctrl-j and ctrl-m behave like enter.

Even for terminals that send unambiguous encodings (via the kitty keyboard
protocol), we have kept bindings like ctrl-h, to support existing habits.

We forgot that pressing alt-ctrl-h would behave like alt-backspace (and can
be easier to reach) so maybe we should add that as well.

Don't add ctrl-shift-i because at least on Linux, that's usually intercepted
by the terminal emulator.

Technically there are some more such as "ctrl-2" (which used to do the same as
"ctrl-space") but I don't think anyone uses that over "ctrl-space".

Closes #https://github.com/fish-shell/fish-shell/discussions/11548

(cherry picked from commit 4d67ca7c58)
2025-06-28 14:20:03 +02:00
Johannes Altmanninger
9af33802ec Use statvfs on NetBSD again to fix build
From commit ba00d721f4 (Correct statvfs call to statfs, 2025-06-19):

> This was missed in the Rust port

To elaborate:

- ec176dc07e (Port path.h, 2023-04-09) didn't change this (as before,
 `statvfs` used `ST_LOCAL` and `statfs` used `MNT_LOCAL`)
- 6877773fdd (Fix build on NetBSD (#10270), 2024-01-28) changed the `statvfs`
  call to `statfs`, presumably due to the libc-wrapper for
  `statvfs` being missing on NetBSD.  This change happens
  to work fine on NetBSD because they do [`#define ST_LOCAL
  MNT_LOCAL`](https://github.com/fish-shell/fish-shell/pull/11486#discussion_r2092408952)
  But it was wrong on others like macOS and FreeBSD, which was fixed by
  ba00d721f4 (but that broke the build on NetBSD).
- 7228cb15bf (Include sys/statvfs.h for the definition of ST_LOCAL (Rust
  port regression), 2025-05-16)
  fixed a code clone left behind by the above commit (incorrectly assuming
  that the clone had always existed.)

Fix the NetBSD build specifically by using statfs on that platform.

Note that this still doesn't make the behavior equivalent to commit LastC++11.
That one used ST_LOCAL if defined, and otherwise MNT_LOCAL if defined.

If we want perfect equivalence, we could detect both flags in `src/build.rs`.
Then we would also build on operating systems that define neither. Not sure.

Closes #11596

(cherry picked from commit 6644cc9b0e)
2025-06-28 11:46:25 +02:00
王宇逸
eecf0814a1 Use uninit instead of zeroed (cherry-pikcked only the change to src/path.rs)
(cherry picked from commit 7c2c7f5874)
2025-06-28 11:46:25 +02:00
Johannes Altmanninger
1ceebdf580 Fix some CSI commands being sent to old midnight commander
Commit 97581ed20f (Do send bracketed paste inside midnight commander,
2024-10-12) accidentally started sending CSI commands such as "CSI >5;0m",
which we intentionally didn't do for some old versions of Midnight Commander,
which fail to parse them. Fix that.

Fixes #11617
2025-06-25 13:36:03 +02:00
Johannes Altmanninger
335f91babd completions/git: fix spurious error when no subcommand is in $PATH
Systems like NixOS might not have "git-receive-pack" or any other "git-*"
executable in in $PATH -- instead they patch git to use absolute paths.
This is weird. But no reason for us to fail. Silence the error.

Fixes #11590

(cherry picked from commit 4f46d369c4)
2025-06-24 11:59:57 +08:00
Johannes Altmanninger
ec66749369 __fish_complete_list: only unescape "$(commandline -t)"
Commit cd3da62d24 (fix(completion): unescape strings for __fish_complete_list,
2024-09-17) bravely addressed an issue that exists in a lot of completions.
It did so only for __fish_complete_list. Fair enough.

Unfortunately it unescaped more than just "$(commandline -t)".

This causes the problem described at
https://github.com/fish-shell/fish-shell/issues/11508#issuecomment-2889088934
where completion descriptions containing a backslash followed by "n" are
interpreted as newlines, breaking the completion parser.  Fix that.

(cherry picked from commit 60881f1195)
2025-06-21 18:58:33 +02:00
Johannes Altmanninger
6e9e33d81d __fish_complete_list: strip "--foo=" prefix from replacing completions
Given a command line like

	foo --foo=bar=baz=qux\=argument

(the behavior is the same if '=' is substituted with ':').

fish completes arguments starting from the last unescaped separator, i.e.

	foo --foo=bar=baz=qux\=argument
			 ^
__fish_complete_list provides completions like

	printf %s\n (commandline -t)(printf %s\n choice1 choice2 ...)

This means that completions include the "--foo=bar=baz=" prefix.

This is wrong. This wasn't a problem until commit f9febba (Fix replacing
completions with a -foo prefix, 2024-12-14), because prior to that, replacing
completions would replace the entire token.
This made it too hard to writ ecompletions like

	complete -c foo -s s -l long -xa "hello-world goodbye-friend"

that would work with "foo --long fri" as well as "foo --long=frie".
Replacing the entire token would only work if the completion included that
prefix, but the above command is supposed to just work.
So f9febba made us replace only the part after the separator.

Unfortunately that caused the earlier problem.  Work around this.  The change
is not pretty, but it's a compromise until we have a better way of telling
which character fish considers to be the separator.

Fixes #11508

(cherry picked from commit 320ebb6859)
2025-06-21 18:58:17 +02:00
Peter Ammon
f3ebc68d5d Correct statvfs call to statfs
This was missed in the Rust port - C++ had statfs for MNT_LOCAL and not statvfs.
The effect of this is that fish never thought its filesystem was local on macOS
or BSDs (Linux was OK). This caused history race tests to fail, and also could
in rare cases result in history items being dropped with multiple concurrent
sessions.

This fixes the history race tests under macOS and FreeBSD - we weren't locking
because we thought the history was a remote file.

Cherry-picked from ba00d721f4
2025-06-19 15:36:19 -07:00
Johannes Altmanninger
4be17bfefb fixup! Extract config path module. NFC
Fix cargo (non-cmake) build.
2025-06-13 12:17:10 +02:00
Johannes Altmanninger
6fd0025f38 Make LOCALEDIR relocatable as well
As explained in c3740b85be (config_paths: fix compiled-in locale dir,
2025-06-12), fish is "relocatable", i.e. "mv /usr/ /usr2/" will leave
"/usr2/bin/fish" fully functional.

There is one exception: for LOCALEDIR we always use the path determined at
compile time.
This seems wrong; let's use the same relocatable-logic as for other paths.

Inspired by bf65b9e3a7 (Change `gettext` paths to be relocatable (#11195),
2025-03-30).
2025-06-13 11:52:46 +02:00
Johannes Altmanninger
052fc18db9 Extract config path module. NFC
This is the "code movement" part of bf65b9e3 ("Change `gettext` paths to be
relocatable (#11195)").

While at it, fix some warnings.
2025-06-13 11:52:46 +02:00
Integral
63a08e53e5 Replace some PathBuf with Path avoid unnecessary heap allocation (#10929)
(cherry picked from commit b19a467ea6)
2025-06-11 11:38:53 +02:00
Erick Howard
62ac23453e Code cleanup in src/bin/fish.rs to make it more idiomatic (#10975)
Code cleanup in `src/bin/fish.rs` to make it more idiomatic

(cherry picked from commit 967c4b2272)
2025-06-11 11:31:05 +02:00
Johannes Altmanninger
c052beb4dd Fix build on Rust 1.70 2025-06-10 17:56:21 +02:00
Johannes Altmanninger
e0cabacdaa kitty keyboard protocol: fall back to base layout key
On terminals that do not implement the kitty keyboard protocol "ctrl-ц" on
a Russian keyboard layout generally sends the same byte as "ctrl-w". This
is because historically there was no standard way to encode "ctrl-ц",
and the "ц" letter happens to be in the same position as "w" on the PC-101
keyboard layout.

Users have gotten used to this, probably because many of them are switching
between a Russian (or Greek etc.) and an English layout.

Vim/Emacs allow opting in to this behavior by setting the "input method"
(which probably means "keyboard layout").

Match key events that have the base layout key set against bindings for
that key.

Closes #11520

---

Alternatively, we could add the relevant preset bindings (for "ctrl-ц" etc.)
but
1. this will be wrong if there is a disagreement on the placement of "ц" between two layouts
2. there are a lot of them
3. it won't work for user bindings (for better or worse)

(cherry picked from commit 7a79728df3)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
59b9f57802 fish_key_reader: unopinionated description for bind notation variants
As explained in the parent commit, "alt-+" is usually preferred over
"alt-shift-=" but both have their moments. We communicate this via a comment
saying "# recommended notation". This is not always true and not super helpful,
especially as we add a third variant for #11520 (physical key), which is
the recommended one for users who switch between English and Cyrillic layouts.

Only explain what each variant does. Based on this the user may figure out
which one to use.

(cherry picked from commit 4cbd1b83f1)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
65fc2b539c Fix some invalid assertions parsing keys
For example the terminal sending « CSI 55296 ; 5 u » would crash fish.

(cherry picked from commit c7391d1026)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
3f1add9e21 Sanitize some inputs in CSI parser
This was copied from C++ code but we have overflow checks, which
forces us to actually handle errors.

While at it, add some basic error logging.

Fixes #11092

(cherry picked from commit 4c28a7771e)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
68d2cafa6e input: remove unnecessary check in bracketed paste code path
When "self.paste_is_buffering()" is true, "parse_escape_sequence()" explicitly
returns "None" instead of "Some(Escape)".  This is irrelevant because this
return value is never read, as long as "self.paste_is_buffering()" remains
true until "parse_escape_sequence()" returns, because the caller will return
early in that case. Paste buffering only ends if we actually read a complete
escape sequence (for ending bracketed paste).

Remove this extra branch.

(cherry picked from commit e5fdd77b09)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
b9d9e7edc6 Match bindings with explicit shift first
The new key notation canonicalizes aggressively, e.g.  these two bindings
clash:

	bind ctrl-shift-a something
	bind shift-ctrl-a something else

This means that key events generally match at most one active binding that
uses the new syntax.

The exception -- two coexisting new-syntax binds that match the same key
event -- was added by commit 50a6e486a5 (Allow explicit shift modifier for
non-ASCII letters, fix capslock behavior, 2025-03-30):

	bind ctrl-A 'echo A'
	bind ctrl-shift-a 'echo shift-a'

The precedence was determined by definition order.
This doesn't seem very useful.

A following patch wants to resolve #11520 by matching "ctrl-ц" events against
"ctrl-w" bindings. It would be surprising if a "ctrl-w" binding shadowed a
"ctrl-ц" one based on something as subtle as definition order.  Additionally,
definition order semantics (which is an unintended cause of the implementation)
is not really obvious.  Reverse definition order would make more sense.

Remove the ambiguity by always giving precedence to bindings that use
explicit shift.

Unrelated to this, as established in 50a6e486a5, explicit shift is still
recommended for bicameral letters but not typically for others -- e.g. alt-+
is typically preferred over alt-shift-= because the former also works on a
German keyboard.

See #11520

(cherry picked from commit 08c8afcb12)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
6b17ec7dae Allow explicit shift modifier for non-ASCII letters, fix capslock behavior
We canonicalize "ctrl-shift-i" to "ctrl-I".
Both when deciphering this notation (as given to builtin bind),
and when receiving it as a key event ("\e[105;73;6u")

This has problems:

A. Our bind notation canonicalization only works for 26 English letters.
   For example, "ctrl-shift-ä" is not supported -- only "ctrl-Ä" is.
   We could try to fix that but this depends on the keyboard layout.
   For example "bind alt-shift-=" and "bind alt-+" are equivalent on a "us"
   layout but not on a "de" layout.
B. While capslock is on, the key event won't include a shifted key ("73" here).
   This is due a quirk in the kitty keyboard protocol[^1].  This means that
   fish_key_reader's canonicalization doesn't work (unless we call toupper()
   ourselves).

I think we want to support both notations.

It's recommended to match all of these (in this order) when pressing
"ctrl-shift-i".

	1. bind ctrl-shift-i do-something
	2. bind ctrl-shift-I do-something
	3. bind ctrl-I do-something
	4. bind ctrl-i do-something

Support 1 and 3 for now, allowing both bindings to coexist. No priorities
for now. This solves problem A, and -- if we take care to use the explicit
shift notation -- problem B.

For keys that are not affected by capslock, problem B does not apply.  In this
case, recommend the shifted notation ("alt-+" instead of "alt-shift-=")
since that seems more intuitive.
Though if we prioritized "alt-shift-=" over "alt-+" as per the recommendation,
that's an argument against the shifted key.

Example output for some key events:

	$ fish_key_reader -cV
	# decoded from: \e\[61:43\;4u
	bind alt-+ 'do something' # recommended notation
	bind alt-shift-= 'do something'
	# decoded from: \e\[61:43\;68u
	bind alt-+ 'do something' # recommended notation
	bind alt-shift-= 'do something'

	# decoded from: \e\[105:73\;6u
	bind ctrl-I 'do something'
	bind ctrl-shift-i 'do something' # recommended notation
	# decoded from: \e\[105\;70u
	bind ctrl-shift-i 'do something'

Due to the capslock quirk, the last one has only one matching representation
since there is no shifted key.  We could decide to match ctrl-shift-i events
(that don't have a shifted key) to ctrl-I bindings (for ASCII letters), as
before this patch. But that case is very rare, it should only happen when
capslock is on, so it's probably not even a breaking change.

The other way round is supported -- we do match ctrl-I events (typically
with shifted key) to ctrl-shift-i bindings (but only for ASCII letters).
This is mainly for backwards compatibility.

Also note that, bindings without other modifiers currently need to use the
shifted key (like "Ä", not "shift-ä"), since we still get a legacy encoding,
until we request "Report all keys as escape codes".

[^1]: <https://github.com/kovidgoyal/kitty/issues/8493>

(cherry picked from commit 50a6e486a5)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
08d796890a Stop accepting "bind shift-A"
This notation doesn't make sense, use either A or shift-a.  We accept it
for ASCII letters only -- things like "bind shift-!" or "bind shift-Ä"
do not work as of today, we don't tolerate extra shift modifiers yet.
So let's remove it for consistency.

Note that the next commit will allow the shift-A notation again, but it will
not match shift-a events.

(cherry picked from commit 7f25d865a9)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
4f98ef36f6 Extract KeyEvent type
The be used in the grandchild commit.

(cherry picked from commit 855a1f702e)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
a09c78491f Extract function for creating key event with modifiers
(cherry picked from commit fabbbba037)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
02932d6b8c Extract constant for the number of function keys
Switch to fish_wcstoul because we want the constant to be unsigned.
It's u32 because most callers of function_key() want that.

(cherry picked from commit e9d1cdfe87)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
7cca98bda2 Fix regression decoding function keys
Commit 109ef88831 (Add menu and printscreen keys, 2025-01-01)
accidentally broke an assumption by inverting f1..f12.  Fix that.

Fixes #11098

(cherry picked from commit d2b2c5286a)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
b77fc28692 Add menu and printscreen keys
These aren't typically used in the terminal but they are present on
many keyboards.

Also reorganize the named key constants a bit.  Between F500 and
ENCODE_DIRECT_BASE (F600) we have space for 256 named keys.

(cherry picked from commit 109ef88831)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
3475531ef7 Also ignore invalid recursive escape sequences
We parse "\e\e[x" as alt-modified "Invalid" key.  Due to this extra
modifier, we accidentally add it to the input queue, instead of
dropping this invalid key.

We don't really want to try to extract some valid keys from this
invalid sequence, see also the parent commit.

This allows us to remove misplaced validation that was added by
e8e91c97a6 (fish_key_reader: ignore sentinel key, 2024-04-02) but
later obsoleted by 66c6e89f98 (Don't add collateral sentinel key to
input queue, 2024-04-03).

(cherry picked from commit 84f19a931d)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
8222ed891b Stop parsing invalid CSI/SS3 sequences as alt-[/alt-o
This situation can be triggered in practice inside a terminal like tmux
3.5 by running

	tmux new-session fish -C 'sleep 2' -d reader -o log-file

and typing "alt-escape x"

The log shows that we drop treat this as alt-[ and drop  the x on the floor.

	reader: Read char alt-\[ -- Key { modifiers: Modifiers { ctrl: false,
	alt: true, shift: false }, codepoint: '[' } -- [27, 91, 120]

This input ("\e[x") is ambiguous.

It looks like it could mean "alt-[,x".  However that conflicts with a
potential future CSI code, so it makes no sense to try to support this.

Returning "None" from parse_csi() causes this weird behavior of
returning "alt-[" and dropping the rest of the parsed sequence.
This is too easy; it has even crept into a bunch of places
where the input sequence is actually valid like "VT200 button released"
but where we definitely don't want to report any key.

Fix the default: report no key for all unknown sequences and
intentionally-suppressed sequences.  Treat it at "alt-[" only when
there is no input byte available, which is more or less unambiguous,
hence a strong enough signal that this is a actually "alt-[".

(cherry picked from commit 3201cb9f01)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
f787e6858c Fix tests/checks/autoload.fish
Apparently this test runs with "build/tests" as CWD when run with cmake.
2025-06-10 16:50:00 +02:00
Fabian Boehm
a014166795 completions/nmcli: Complete at runtime
This used to get all the interfaces and ssids when the completions
were loaded. That's obviously wrong, given that ssids especially can, you know, change

(cherry picked from commit 9116c61736)

cherry-picking since this easy to trigger
(seen again in https://github.com/fish-shell/fish-shell/pull/11549)
2025-06-06 11:52:17 +02:00
Johannes Altmanninger
f7e639504a completions/git: improve idempotency in case of double load
As mentioned in the previous few commits and in #11535, running
"set fish_complete_path ..."  and "complete -C 'git ...'"  may result in
"share/completions/git.fish" being loaded multiple times.

This is usually fine because fish internally erases all cached completions
whenever fish_complete_path changes.

Unfortunately there is at least global variable that grows each time git.fish
is sourced. This doesn't make a functional difference but it does slow
down completions.  Fix that by resetting the variable at load time.

(cherry picked from commit 4b5650ee4f)
2025-05-29 18:01:22 +02:00
Johannes Altmanninger
028b60cad6 Fix "set fish_complete_path" accidentally disabling autoloading
Commit 5918bca1eb (Make "complete -e" prevent completion autoloading,
2024-08-24) makes "complete -e foo" add a tombstone for "foo", meaning we
will never again load completions for "foo".

Due to an oversight, the same tombstone is added when we clear cached
completions after changing "fish_complete_path", preventing completions from
being loaded in that case.  Fix this by restoring the old behavior unless
the user actually used "complete -e".

(cherry picked from commit a7c04890c9)
2025-05-29 18:01:04 +02:00
Johannes Altmanninger
b11e22d905 Fix uvar file mtime force-update (Rust port regression)
When two fish processes rewrite the uvar file concurrent, they rely on the
uvar file's mtime (queried after taking a lock, if locking is supported) to
tell us whether their view of the uvar file is still up-to-date.  If it is,
they proceed to move it into place atomically via rename().

Since the observable mtime only updates on every OS clock tick, we call
futimens() manually to force-update that, to make sure that -- unless both
fish conincide on the same *nanosecond* -- other fish will notice that the
file changed.

Unfortunately, commit 77aeb6a2a8 (Port execution, 2023-10-08) accidentally
made us call futimens() only if clock_gettime() failed, instead of when
it succeeded. This means that we need to wait for the next clock tick to
observe a change in mtime.
Any resulting false negatives might have caused us to drop universal variable updates.

Reported in https://github.com/fish-shell/fish-shell/pull/11492#discussion_r2098948362

See #10300

(cherry picked from commit 8617964d4d)
2025-05-23 08:50:17 +02:00
Johannes Altmanninger
33f8415785 Fixup history file EINTR loop to actually loop
Fixes d84e68dd4f (Retry history file flock() on EINTR, 2025-05-20).

(cherry picked from commit 3867163193)
2025-05-20 17:19:12 +02:00
Johannes Altmanninger
5ccd155177 Retry history file flock() on EINTR
When locking the uvar file, we retry whenever flock() fails with EINTR
(e.g. due to ctrl-c).

But not when locking the history file.  This seems wrong; all other libc
functions in the "history_file" code path do retry.

Fix that. In future we should extract a function.

Note that there are other inconsistencies; flock_uvar_file() does not
shy away from remote file systems and does not respect ABANDONED_LOCKING.
This means that empirically probably neither are necessary; let's make things
consistent in future.

See https://github.com/fish-shell/fish-shell/pull/11492#discussion_r2095096200
Might help #10300

(cherry picked from commit 4d84e68dd4)
2025-05-20 15:32:56 +02:00
Johannes Altmanninger
0f8d3a5174 Revert "Temporarily enable history_file debug category by default"
Commit f906a949cf (Temporarily enable history_file debug category by default,
2024-10-09) enabled the "history_file" debug category by default to gather
more data.

Judging from
https://github.com/fish-shell/fish-shell/issues/10300#issuecomment-2876718382
the logs didn't help, or were at least not visible when logging to stderr
(due to reboot).

Let's disable "history_file" logs again to remove potential
noise if the file system is read-only, disk is full etc., see
https://github.com/fish-shell/fish-shell/pull/11492#discussion_r2094781120

See #10300

(cherry picked from commit 285a810814)
2025-05-20 15:31:57 +02:00
Johannes Altmanninger
c4a26cb2b1 builtin status: remove spurious newline from current-command (Rust port regression)
WHen "status current-command" is called outside a function it always returns
"fish". An extra newline crept in, fix that.

Fixes 77aeb6a2a8 (Port execution, 2023-10-08).
Fixes #11503

(cherry picked from commit e26b585ce5)
2025-05-20 12:33:01 +02:00
Johannes Altmanninger
7228cb15bf Include sys/statvfs.h for the definition of ST_LOCAL (Rust port regression)
See https://man.netbsd.org/statvfs.5.
According to https://github.com/NetBSD/src/blob/trunk/sys/sys/statvfs.h#L135,
NetBSD has "#define ST_LOCAL MNT_LOCAL".  So this commit likely makes no
difference on existing systems.

While at it
- comment include statements
- remove a code clone

See #11486

(cherry picked from commit d68f8bdd3b)
2025-05-16 08:21:56 +02:00
Alan Somers
d5b46d6535 Fix remote filesystem detection on FreeBSD
Need an extra include to get the definition of MNT_LOCAL

Fixes #11483

(cherry picked from commit 7f4998ad9b)
2025-05-16 08:21:25 +02:00
Johannes Altmanninger
d4b4d44f14 Fix Vi mode glitch when replacing at last character
Another regression from d51f669647 (Vi mode: avoid placing cursor beyond last
character, 2024-02-14) "Unfortunately Vi mode sometimes needs to temporarily
select past end". So do the replace_one mode bindings which were forgotten.

Fix this.

This surfaces a tricky problem: when we use something like

	bind '' self-insert some-command

When key event "x" matches this generic binding, we insert both "self-insert"
and "some-command" at the front of the queue, and do *not* consume "x",
since the binding is empty.

Since there is a command (that might call "exit"), we insert a check-exit
event too, after "self-insert some-command" but _before_ "x".

The check-exit event makes "self-insert" do nothing. I don't think there's a
good reason for this; self-insert can only be triggered by a key event that
maps to self-insert; so there must always be a real key available for it to
consume. A "commandline -f self-insert" is a nop. Skip check-exit here.

Fixes #11484

(cherry picked from commit 107e4d11de)
2025-05-13 00:31:22 +02:00
Johannes Altmanninger
b8cfd6d12b Fix typo causing wrong cursor position after Vi mode paste
Regressed in d51f669647 (Vi mode: avoid placing cursor beyond last character,
2024-02-14).

(cherry picked from commit 50500ec5b9)
2025-05-13 00:31:09 +02:00
Johannes Altmanninger
6fb22a4fd1 Fix regression causing crash indenting commandline with "$()"
Commit b00899179f (Don't indent multi-line quoted strings; do indent inside
(), 2024-04-28) changed how we compute indents for string tokens with command
substitutions:

	echo "begin
	not indented
	end $(
	begin
	    indented
	end)"(
	begin
	    indented
	end
	)

For the leading quoted part of the string, we compute indentation only for
the first character (the opening quote), see 4c43819d32 (Fix crash indenting
quoted suffix after command substitution, 2024-09-28).

The command substitutions, we do indent as usual.

To implement the above, we need to separate quoted from non-quoted
parts. This logic crashes when indent_string_part() is wrongly passed
is_double_quoted=true.

This is because, given the string "$()"$(), parse_util_locate_cmdsub calls
quote_end() at index 4 (the second quote). This is wrong because that function
should only be called at opening quotes; this is a closing quote. The opening
quote is virtual here. Hack around this.

Fixes #11444

(cherry picked from commit 48704dc612)
2025-05-12 21:41:10 +02:00
Johannes Altmanninger
35849c57dc Explicit type for "$()" hack in parse_util_locate_cmdsub
(cherry picked from commit 8abab0e2cc)
2025-05-12 21:41:10 +02:00
Johannes Altmanninger
27504658ce Remove code clone in parse_util_locate_cmdsub
(cherry picked from commit bd178c8ba8)
2025-05-12 21:41:10 +02:00
Johannes Altmanninger
db323348c7 Set transient command line in custom completions (Rust port regression)
Commit df3b0bd89f (Fix commandline state for custom completions with variable
overrides, 2022-01-26) made us push a transient command line for custom
completions based on a tautological null-pointer check ("var_assignments").

Commit 77aeb6a2a8 (Port execution, 2023-10-08) turned the null pointer into
a reference and replaced the check with "!ad.var_assignments.is_empty()".
This broke scenarios that relied on the transient commandline.  In particular
the attached test cases rely on the transient commandline implicitly placing
the cursor at the end, irrespective of the cursor in the actual commandline.

I'm not sure if there is an easy way to identify these scenarios.

Let's restore historical behavior by always pushing the transient command line.

Fixes #11423

(cherry picked from commit 97641c7bf6)
2025-05-12 21:39:42 +02:00
Johannes Altmanninger
edb1b5f333 Share alt-{b,f} with Vi mode, to work around Terminal.app/Ghostty more
Commit f4503af037 (Make alt-{b,f} move in directory history if commandline is
empty, 2025-01-06) had the intentional side effect of making alt-{left,right}
(move in directory history) work in Terminal.app and Ghostty without other,
less reliable workarounds.
That commit says "that [workaround] alone should not be the reason for
this change."; maybe this was wrong.

Extend the workaround to Vi mode.  The intention here is to provide
alt-{left,right} in Vi mode.  This also adds alt-{b,f} which is odd but
mostly harmless (?) because those don't do anything else in Vi mode.
It might be confusing when studying "bind" output but that one already has
almost 400 lines for Vi mode.

Closes #11479

(cherry picked from commit 3081d0157b)
2025-05-12 21:35:47 +02:00
Daniel Rainer
2d8d377ddc Make printf unicode-aware
Specifically, the width and precision format specifiers are interpreted as
referring to the width of the grapheme clusters rather than the byte count of
the string. Note that grapheme clusters can differ in width.

If a precision is specified for a string, meaning its "maximum number of
characters", we consider this to limit the width displayed.
If there is a grapheme cluster whose width is greater than 1,
it might not be possible to get precisely the desired width.
In such cases, this last grapheme cluster is excluded from the output.

Note that the definitions used here are not consistent with the `string length`
builtin at the moment, but this has already been the case.

(cherry picked from commit 09eae92888)
2025-05-12 21:33:40 +02:00
Peter Ammon
057dd930b4 Changelog fix for #11354 2025-05-08 18:42:57 -07:00
Cuichen Li
25b944e3e6 Revert "Work around $PATH issues under WSL (#10506)"
This reverts commit 3374692b91.
2025-05-08 18:41:02 -07:00
641 changed files with 756749 additions and 569517 deletions

View File

@@ -24,4 +24,4 @@ tasks:
ninja
- test: |
cd fish-shell/build
ninja test
env ninja test

View File

@@ -20,4 +20,4 @@ tasks:
ninja
- test: |
cd fish/build
ninja test
env ninja test

View File

@@ -1,8 +0,0 @@
# This file is _not_ included in the tarballs for now
# Binary builds on Linux packaging infrastructure need to overwrite it to make `cargo vendor` work
# Releases and development builds made using OBS/Launchpad will _not_ reflect the contents of this
# file
[resolver]
# Make cargo 1.84+ respect MSRV (rust-version in Cargo.toml)
incompatible-rust-versions = "fallback"

View File

@@ -20,15 +20,17 @@ linux_task:
# container:
# <<: *step
# image: ghcr.io/krobelus/fish-ci/focal-32bit:latest
tests_script:
# cirrus at times gives us 32 procs and 2 GB of RAM
# Unrestriced parallelism results in OOM
- lscpu || true
- (cat /proc/meminfo | grep MemTotal) || true
- mkdir build && cd build
- FISH_TEST_MAX_CONCURRENCY=6 cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug ..
- cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCTEST_PARALLEL_LEVEL=6 ..
- ninja -j 6 fish
- ninja fish_run_tests
only_if: $CIRRUS_REPO_OWNER == 'fish-shell'
linux_arm_task:
@@ -39,26 +41,34 @@ linux_arm_task:
- name: jammy-armv7-32bit
arm_container:
image: ghcr.io/fish-shell/fish-ci/jammy-armv7-32bit
tests_script:
# cirrus at times gives us 32 procs and 2 GB of RAM
# Unrestriced parallelism results in OOM
- lscpu || true
- (cat /proc/meminfo | grep MemTotal) || true
- mkdir build && cd build
- FISH_TEST_MAX_CONCURRENCY=6 cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug ..
- cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCTEST_PARALLEL_LEVEL=6 ..
- ninja -j 6 fish
- file ./fish
- ninja fish_run_tests
# CI task disabled during RIIR transition
only_if: false && $CIRRUS_REPO_OWNER == 'fish-shell'
freebsd_task:
matrix:
- name: FreeBSD 14
# - name: FreeBSD 14
# freebsd_instance:
# image_family: freebsd-14-0-snap
- name: FreeBSD 13
freebsd_instance:
image: freebsd-14-3-release-amd64-ufs
image: freebsd-13-2-release-amd64
# - name: FreeBSD 12.3
# freebsd_instance:
# image: freebsd-12-3-release-amd64
tests_script:
- pkg install -y cmake-core devel/pcre2 devel/ninja lang/rust misc/py-pexpect git-lite
- pkg install -y cmake-core devel/pcre2 devel/ninja misc/py-pexpect git-lite terminfo-db
# libclang.so is a required build dependency for rust-c++ ffi bridge
- pkg install -y llvm
# BSDs have the following behavior: root may open or access files even if
@@ -71,7 +81,16 @@ freebsd_task:
- mkdir build && cd build
- chown -R fish-user ..
- sudo -u fish-user -s whoami
- sudo -u fish-user -s FISH_TEST_MAX_CONCURRENCY=1 cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug ..
- sudo -u fish-user -s ninja -j 6 fish
- sudo -u fish-user -s ninja fish_run_tests
# FreeBSD's pkg currently has rust 1.66.0 while we need rust 1.70.0+. Use rustup to install
# the latest, but note that it only installs rust per-user.
- sudo -u fish-user -s fetch -qo - https://sh.rustup.rs > rustup.sh
- sudo -u fish-user -s sh ./rustup.sh -y --profile=minimal
# `sudo -s ...` does not invoke a login shell so we need a workaround to make sure the
# rustup environment is configured for subsequent `sudo -s ...` commands.
# For some reason, this doesn't do the job:
# - sudo -u fish-user sh -c 'echo source \$HOME/.cargo/env >> $HOME/.cshrc'
- sudo -u fish-user -s cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCTEST_PARALLEL_LEVEL=1 ..
- sudo -u fish-user sh -c '. $HOME/.cargo/env; ninja -j 6 fish'
- sudo -u fish-user sh -c '. $HOME/.cargo/env; ninja fish_run_tests'
only_if: $CIRRUS_REPO_OWNER == 'fish-shell'

View File

@@ -13,16 +13,20 @@ max_line_length = 100
indent_style = tab
[*.{md,rst}]
max_line_length = unset
trim_trailing_whitespace = false
[*.sh]
indent_size = 4
[build_tools/release.sh]
max_line_length = 72
[Dockerfile]
indent_size = 2
[share/{completions,functions}/**.fish]
max_line_length = unset
[{COMMIT_EDITMSG,git-revise-todo}]
max_line_length = 80
[{COMMIT_EDITMSG,git-revise-todo,*.jjdescription}]
max_line_length = 72

12
.gitattributes vendored
View File

@@ -5,10 +5,9 @@
# let git show off diff hunk headers, help git diff -L:
# https://git-scm.com/docs/gitattributes
*.c diff=cpp
*.cpp diff=cpp
*.h diff=cpp
*.py diff=py
*.rs diff=rust
# add a [diff "fish"] to git config with pattern
*.fish diff=fish
@@ -22,13 +21,12 @@
/.github/* export-ignore
/.builds export-ignore
/.builds/* export-ignore
# to make cargo vendor work correctly
/.cargo/ export-ignore
/.cargo/config.toml export-ignore
# for linguist, which drives GitHub's language statistics
# for linguist; let github identify our project as C++ instead of C due to pcre2
pcre2/** linguist-vendored
alpine.js linguist-vendored
doc_src/** linguist-documentation
*.fish linguist-language=fish
# see 70f2899fcd which attempts to "rig the count"
src/*.h linguist-language=c++
src/builtins/*.h linguist-language=c++
share/completions/*.fish linguist-documentation

View File

@@ -1,18 +1,10 @@
---
name: "Bug Report"
about: "Simple template for bug reports"
title: ""
labels: []
assignees: []
---
<!--
Please tell us which fish version you are using by executing the following:
fish --version
echo $version
Please tell us which operating system (output of `uname`) and terminal you are using.
Please tell us which operating system and terminal you are using. The output of `uname -a` and `echo $TERM` may be helpful in this regard although other commands might be relevant in your specific situation.
Please tell us if you tried fish without third-party customizations by executing this command and whether it affected the behavior you are reporting:

View File

@@ -0,0 +1,14 @@
name: Install sphinx-markdown-builder
permissions:
contents: read
runs:
using: "composite"
steps:
- shell: bash
run: |
set -x
commit=b259de1dc97573a71470a1d71c3d83535934136b
pip install git+https://github.com/krobelus/sphinx-markdown-builder@"$commit"
python -c 'import sphinx_markdown_builder'

View File

@@ -1,14 +1,12 @@
name: Oldest Supported Rust Toolchain
on:
workflow_call:
inputs:
targets:
description: Comma-separated list of target triples to install for this toolchain
required: false
components:
description: Comma-separated list of components to be additionally installed
required: false
inputs:
targets:
description: Comma-separated list of target triples to install for this toolchain
required: false
components:
description: Comma-separated list of components to be additionally installed
required: false
permissions:
contents: read

View File

@@ -1,14 +1,12 @@
name: Stable Rust Toolchain
on:
workflow_call:
inputs:
targets:
description: Comma-separated list of target triples to install for this toolchain
required: false
components:
description: Comma-separated list of components to be additionally installed
required: false
inputs:
targets:
description: Comma-separated list of target triples to install for this toolchain
required: false
components:
description: Comma-separated list of components to be additionally installed
required: false
permissions:
contents: read
@@ -16,7 +14,7 @@ permissions:
runs:
using: "composite"
steps:
- uses: dtolnay/rust-toolchain@1.88
- uses: dtolnay/rust-toolchain@1.89
with:
targets: ${{ inputs.targets }}
components: ${{ inputs.components }}

View File

@@ -1,42 +0,0 @@
name: macOS build and codesign
on:
workflow_dispatch: # Enables manual trigger from GitHub UI
jobs:
build-and-code-sign:
runs-on: macos-latest
environment: macos-codesign
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: ./.github/actions/rust-toolchain@oldest-supported
with:
targets: x86_64-apple-darwin
- name: Install Rust Stable
uses: ./.github/actions/rust-toolchain@stable
with:
targets: aarch64-apple-darwin
- name: build-and-codesign
run: |
cargo install apple-codesign
mkdir -p "$FISH_ARTEFACT_PATH"
echo "$MAC_CODESIGN_APP_P12_BASE64" | base64 --decode > /tmp/app.p12
echo "$MAC_CODESIGN_INSTALLER_P12_BASE64" | base64 --decode > /tmp/installer.p12
echo "$MACOS_NOTARIZE_JSON" > /tmp/notarize.json
./build_tools/make_pkg.sh -s -f /tmp/app.p12 -i /tmp/installer.p12 -p "$MAC_CODESIGN_PASSWORD" -n -j /tmp/notarize.json
rm /tmp/installer.p12 /tmp/app.p12 /tmp/notarize.json
env:
MAC_CODESIGN_APP_P12_BASE64: ${{ secrets.MAC_CODESIGN_APP_P12_BASE64 }}
MAC_CODESIGN_INSTALLER_P12_BASE64: ${{ secrets.MAC_CODESIGN_INSTALLER_P12_BASE64 }}
MAC_CODESIGN_PASSWORD: ${{ secrets.MAC_CODESIGN_PASSWORD }}
MACOS_NOTARIZE_JSON: ${{ secrets.MACOS_NOTARIZE_JSON }}
# macOS runners keep having issues loading Cargo.toml dependencies from git (GitHub) instead
# of crates.io, so give this a try. It's also sometimes significantly faster on all platforms.
CARGO_NET_GIT_FETCH_WITH_CLI: true
FISH_ARTEFACT_PATH: /tmp/fish-built
- uses: actions/upload-artifact@v4
with:
name: macOS Artefacts
path: /tmp/fish-built/*
if-no-files-found: error

View File

@@ -3,7 +3,7 @@ name: make fish_run_tests
on: [push, pull_request]
env:
FISH_TEST_MAX_CONCURRENCY: "4"
CTEST_PARALLEL_LEVEL: "1"
CMAKE_BUILD_PARALLEL_LEVEL: "4"
permissions:
@@ -16,12 +16,13 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/rust-toolchain@oldest-supported
- uses: dtolnay/rust-toolchain@1.70
- name: Install deps
run: |
sudo apt install gettext libpcre2-dev python3-pexpect python3-sphinx tmux
sudo apt install gettext libpcre2-dev python3-pexpect tmux
# Generate a locale that uses a comma as decimal separator.
sudo locale-gen fr_FR.UTF-8
- uses: ./.github/actions/install-sphinx-markdown-builder
- name: cmake
run: |
mkdir build && cd build
@@ -32,14 +33,6 @@ jobs:
- name: make fish_run_tests
run: |
make -C build VERBOSE=1 fish_run_tests
- name: translation updates
run: |
# Generate PO files. This should not result it a change in the repo if all translations are
# up to date.
# Ensure that fish is available as an executable.
PATH="$PWD/build:$PATH" build_tools/update_translations.fish --no-mo
# Show diff output. Fail if there is any.
git --no-pager diff --exit-code || { echo 'There are uncommitted changes after regenerating the gettext PO files. Make sure to update them via `build_tools/update_translations.fish --no-mo` after changing source files.'; exit 1; }
ubuntu-32bit-static-pcre2:
@@ -47,7 +40,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/rust-toolchain@oldest-supported
- uses: dtolnay/rust-toolchain@1.70
with:
targets: "i586-unknown-linux-gnu" # rust-toolchain wants this comma-separated
- name: Install deps
@@ -90,14 +83,13 @@ jobs:
- name: Install deps
run: |
sudo apt install gettext libpcre2-dev python3-pexpect tmux
sudo apt install llvm # for llvm-symbolizer
- name: cmake
env:
CC: clang
run: |
mkdir build && cd build
# Rust's ASAN requires the build system to explicitly pass a --target triple. We read that
# value from CMake variable Rust_CARGO_TARGET.
# value from CMake variable Rust_CARGO_TARGET (shared with corrosion).
cmake .. -DASAN=1 -DRust_CARGO_TARGET=x86_64-unknown-linux-gnu -DCMAKE_BUILD_TYPE=Debug
- name: make
run: |
@@ -113,8 +105,8 @@ jobs:
# UPDATE: this can cause spurious leak reports for __cxa_thread_atexit_impl() under glibc.
LSAN_OPTIONS: verbosity=0:log_threads=0:use_tls=1:print_suppressions=0
run: |
set -x
export ASAN_SYMBOLIZER_PATH=$(command -v /usr/bin/llvm-symbolizer* | sort -n | head -1)
llvm_version=$(clang --version | awk 'NR==1 { split($NF, version, "."); print version[1] }')
export ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer-$llvm_version
export LSAN_OPTIONS="$LSAN_OPTIONS:suppressions=$PWD/build_tools/lsan_suppressions.txt"
make -C build VERBOSE=1 fish_run_tests
@@ -128,7 +120,7 @@ jobs:
#
# steps:
# - uses: actions/checkout@v4
# - uses: ./.github/actions/rust-toolchain@oldest-supported
# - uses: dtolnay/rust-toolchain@1.70
# - name: Install deps
# run: |
# sudo apt install gettext libpcre2-dev python3-pexpect tmux
@@ -156,7 +148,7 @@ jobs:
CARGO_NET_GIT_FETCH_WITH_CLI: true
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/rust-toolchain@oldest-supported
- uses: dtolnay/rust-toolchain@1.70
- name: Install deps
run: |
# --break-system-packages because homebrew has now declared itself "externally managed".

190
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,190 @@
name: Create a new release
on:
workflow_dispatch:
inputs:
version:
description: 'Version to release (tag name)'
required: true
type: string
permissions:
contents: write
jobs:
is-release-tag:
name: Pre-release checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
# Workaround for https://github.com/actions/checkout/issues/882
ref: ${{ inputs.version }}
- name: Check if the pushed tag looks like a release
run: |
set -x
commit_subject=$(git log -1 --format=%s)
tag=$(git describe)
[ "$commit_subject" = "Release $tag" ]
source-tarball:
needs: [is-release-tag]
name: Create the source tarball
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
tarball-name: ${{ steps.version.outputs.tarball-name }}
steps:
- uses: actions/checkout@v4
with:
# Workaround for https://github.com/actions/checkout/issues/882
ref: ${{ inputs.version }}
- name: Install dependencies
run: sudo apt install cmake gettext ninja-build python3-pip python3-sphinx
- uses: ./.github/actions/install-sphinx-markdown-builder
- name: Create tarball
run: |
set -x
mkdir /tmp/fish-built
FISH_ARTEFACT_PATH=/tmp/fish-built ./build_tools/make_tarball.sh
relnotes=/tmp/fish-built/release-notes.md
# Need history since the last release (i.e. tag) for stats.
git fetch --tags
git fetch --unshallow
sh -x ./build_tools/release-notes.sh >"$relnotes"
# Delete title
sed -n 1p "$relnotes" | grep -q "^## fish .*"
sed -n 2p "$relnotes" | grep -q '^$'
sed -i 1,2d "$relnotes"
- name: Upload tarball artifact
uses: actions/upload-artifact@v4
with:
name: source-tarball
path: |
/tmp/fish-built/fish-${{ inputs.version }}.tar.xz
/tmp/fish-built/release-notes.md
if-no-files-found: error
packages-for-linux:
needs: [is-release-tag]
name: Build single-file fish for Linux (experimental)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
# Workaround for https://github.com/actions/checkout/issues/882
ref: ${{ inputs.version }}
- name: Install Rust Stable
uses: ./.github/actions/rust-toolchain@stable
with:
targets: x86_64-unknown-linux-musl,aarch64-unknown-linux-musl
- name: Install dependencies
run: sudo apt install crossbuild-essential-arm64 musl-tools python3-sphinx
- name: Build statically-linked executables
run: |
set -x
CFLAGS="-D_FORTIFY_SOURCE=2" \
CMAKE_WITH_GETTEXT=0 \
CC=aarch64-linux-gnu-gcc \
RUSTFLAGS="-C linker=aarch64-linux-gnu-gcc -C link-arg=-lgcc -C link-arg=-D_FORTIFY_SOURCE=0" \
cargo build --release --target aarch64-unknown-linux-musl --bin fish
cargo build --release --target x86_64-unknown-linux-musl --bin fish
- name: Compress
run: |
set -x
for arch in x86_64 aarch64; do
tar -cazf fish-$(git describe)-linux-$arch.tar.xz \
-C target/$arch-unknown-linux-musl/release fish
done
- uses: actions/upload-artifact@v4
with:
name: Static builds for Linux
path: fish-${{ inputs.version }}-linux-*.tar.xz
if-no-files-found: error
create-draft-release:
needs:
- is-release-tag
- source-tarball
- packages-for-linux
name: Create release draft
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
# Workaround for https://github.com/actions/checkout/issues/882
ref: ${{ inputs.version }}
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
merge-multiple: true
path: /tmp/artifacts
- name: List artifacts
run: find /tmp/artifacts -type f
- name: Create draft release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ inputs.version }}
name: fish ${{ inputs.version }}
body_path: /tmp/artifacts/release-notes.md
draft: true
files: |
/tmp/artifacts/fish-${{ inputs.version }}.tar.xz
/tmp/artifacts/fish-${{ inputs.version }}-linux-*.tar.xz
packages-for-macos:
needs: [is-release-tag, create-draft-release]
name: Build packages for macOS
runs-on: macos-latest
environment: macos-codesign
steps:
- uses: actions/checkout@v4
with:
# Workaround for https://github.com/actions/checkout/issues/882
ref: ${{ inputs.version }}
- name: Install Rust
uses: ./.github/actions/rust-toolchain@oldest-supported
with:
targets: x86_64-apple-darwin
- name: Install Rust Stable
uses: ./.github/actions/rust-toolchain@stable
with:
targets: aarch64-apple-darwin
- name: Build and codesign
run: |
die() { echo >&2 "$*"; exit 1; }
[ -n "$MAC_CODESIGN_APP_P12_BASE64" ] || die "Missing MAC_CODESIGN_APP_P12_BASE64"
[ -n "$MAC_CODESIGN_INSTALLER_P12_BASE64" ] || die "Missing MAC_CODESIGN_INSTALLER_P12_BASE64"
[ -n "$MAC_CODESIGN_PASSWORD" ] || die "Missing MAC_CODESIGN_PASSWORD"
[ -n "$MACOS_NOTARIZE_JSON" ] || die "Missing MACOS_NOTARIZE_JSON"
set -x
export FISH_ARTEFACT_PATH=/tmp/fish-built
# macOS runners keep having issues loading Cargo.toml dependencies from git (GitHub) instead
# of crates.io, so give this a try. It's also sometimes significantly faster on all platforms.
export CARGO_NET_GIT_FETCH_WITH_CLI=true
cargo install apple-codesign
mkdir -p "$FISH_ARTEFACT_PATH"
echo "$MAC_CODESIGN_APP_P12_BASE64" | base64 --decode >/tmp/app.p12
echo "$MAC_CODESIGN_INSTALLER_P12_BASE64" | base64 --decode >/tmp/installer.p12
echo "$MACOS_NOTARIZE_JSON" >/tmp/notarize.json
./build_tools/make_macos_pkg.sh -s -f /tmp/app.p12 \
-i /tmp/installer.p12 -p "$MAC_CODESIGN_PASSWORD" \
-n -j /tmp/notarize.json
version=$(git describe)
[ -f "${FISH_ARTEFACT_PATH}/fish-$version.app.zip" ]
[ -f "${FISH_ARTEFACT_PATH}/fish-$version.pkg" ]
rm /tmp/installer.p12 /tmp/app.p12 /tmp/notarize.json
env:
MAC_CODESIGN_APP_P12_BASE64: ${{ secrets.MAC_CODESIGN_APP_P12_BASE64 }}
MAC_CODESIGN_INSTALLER_P12_BASE64: ${{ secrets.MAC_CODESIGN_INSTALLER_P12_BASE64 }}
MAC_CODESIGN_PASSWORD: ${{ secrets.MAC_CODESIGN_PASSWORD }}
MACOS_NOTARIZE_JSON: ${{ secrets.MACOS_NOTARIZE_JSON }}
- name: Add macOS packages to the release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
version=$(git describe)
gh release upload $version \
/tmp/fish-built/fish-$version.app.zip \
/tmp/fish-built/fish-$version.pkg

View File

@@ -8,48 +8,34 @@ permissions:
jobs:
rustfmt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/rust-toolchain@stable
with:
components: rustfmt
- uses: dtolnay/rust-toolchain@stable
- name: cargo fmt
run: cargo fmt --check
run: cargo fmt --check --all
clippy-stable:
clippy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/rust-toolchain@stable
with:
components: clippy
- uses: dtolnay/rust-toolchain@stable
- name: Install deps
run: |
sudo apt install gettext
sudo apt install gettext libpcre2-dev
- name: cmake
run: |
cmake -B build
- name: cargo clippy
run: cargo clippy --workspace --all-targets -- --deny=warnings
# This used to have --deny=warnings, but that turns rust release day
# into automatic CI failure day, so we don't do that.
run: cargo clippy --workspace --all-targets
clippy-msrv:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/rust-toolchain@oldest-supported
with:
components: clippy
- name: Install deps
run: |
sudo apt install gettext
- name: cargo clippy
run: cargo clippy --workspace --all-targets -- --deny=warnings
rustdoc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/rust-toolchain@stable
- name: cargo doc
run: |
RUSTDOCFLAGS='-D warnings' cargo doc --workspace
- name: cargo doctest
run: |
cargo test --doc --workspace
# Disabling for now because it also checks "advisories",
# making CI fail for reasons unrelated to the patch
# cargo-deny:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v3
# - uses: EmbarkStudios/cargo-deny-action@v1

View File

@@ -1,76 +0,0 @@
name: staticbuilds
on:
# release:
# types: [published]
# schedule:
# - cron: "14 13 * * *"
workflow_dispatch:
jobs:
staticbuilds-linux:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: ./.github/actions/rust-toolchain@oldest-supported
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Prepare
run: |
sudo apt install python3-sphinx
rustup target add x86_64-unknown-linux-musl
rustup target add aarch64-unknown-linux-musl
sudo apt install musl-tools crossbuild-essential-arm64 python3-pexpect tmux -y
- name: Build
run: |
CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2" CMAKE_WITH_GETTEXT=0 CC=aarch64-linux-gnu-gcc RUSTFLAGS="-C linker=aarch64-linux-gnu-gcc -C link-arg=-lgcc -C link-arg=-D_FORTIFY_SOURCE=0" cargo build --release --target aarch64-unknown-linux-musl --bin fish
cargo build --release --target x86_64-unknown-linux-musl
- name: Test
run: |
tests/test_driver.py target/x86_64-unknown-linux-musl/release/
- name: Compress
run: |
tar -cazf fish-static-x86_64-$(git describe).tar.xz -C target/x86_64-unknown-linux-musl/release/ fish
tar -cazf fish-static-aarch64-$(git describe).tar.xz -C target/aarch64-unknown-linux-musl/release/ fish
- uses: actions/upload-artifact@v4
with:
name: fish-static-linux
path: |
fish-*.tar.xz
retention-days: 14
staticbuilds-macos:
runs-on: macos-latest
permissions:
contents: read
steps:
- uses: ./.github/actions/rust-toolchain@oldest-supported
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Prepare
run: |
sudo pip3 install --break-system-packages sphinx
rustup target add x86_64-apple-darwin
rustup target add aarch64-apple-darwin
- name: Build
run: |
PCRE2_SYS_STATIC=1 cargo build --release --target aarch64-apple-darwin --bin fish
PCRE2_SYS_STATIC=1 cargo build --release --target x86_64-apple-darwin --bin fish
- name: Compress
run: |
tar -cazf fish-macos-aarch64.tar.xz -C target/aarch64-apple-darwin/release/ fish
tar -cazf fish-macos-x86_64.tar.xz -C target/x86_64-apple-darwin/release/ fish
- uses: actions/upload-artifact@v4
with:
name: fish-static-macos
path: |
fish-macos-*.tar.xz
retention-days: 14

6
.gitignore vendored
View File

@@ -38,7 +38,7 @@ Desktop.ini
Thumbs.db
ehthumbs.db
*.mo
messages.pot
.directory
.fuse_hidden*
@@ -77,7 +77,6 @@ __pycache__
/share/__fish_build_paths.fish
/share/pkgconfig
/tests/*.tmp.*
/tests/.last-check-all-files
# xcode
## Build generated
@@ -103,6 +102,3 @@ target/
# Generated by clangd
/.cache
# JetBrains editors.
.idea/

View File

@@ -1,97 +1,57 @@
fish 4.1.0 (released ???)
=========================
fish 4.0.9 (released September 27, 2025)
========================================
.. ignore for 4.1: 10929 10940 10948 10955 10965 10975 10989 10990 10998 11028 11052 11055 11069 11071 11079 11092 11098 11104 11106 11110 11140 11146 11148 11150 11214 11218 11259 11288 11299 11328 11350 11373 11395 11417 11419
This release fixes:
Notable improvements and fixes
------------------------------
- Compound commands (``begin; echo 1; echo 2; end``) can now be now be abbreviated using braces (``{ echo1; echo 2 }``), like in other shells.
- Fish now supports transient prompts: if :envvar:`fish_transient_prompt` is set to 1, fish will reexecute prompt functions with the ``--final-rendering`` argument before running a commandline (:issue:`11153`).
- When tab completion results are truncated, any common directory name is omitted. E.g. if you complete "share/functions", and it includes the files "foo.fish" and "bar.fish",
the completion pager will now show "…/foo.fish" and "…/bar.fish". This will make the candidates shorter and allow for more to be shown at once (:issue:`11250`).
- The self-installing configuration introduced in fish 4.0 has been changed.
Now fish built with embedded data will just read the data straight from its own binary or write it out when necessary, instead of requiring an installation step on start.
That means it is now possible to build fish as a single file and copy it to a compatible system, including as a different user, without extracting any files.
As before this is the default when building via `cargo`, and disabled when building via `cmake`, and for packagers we continue to recommend cmake.
Note: When fish is built like this, the `$__fish_data_dir` variable will be empty because that directory no longer has meaning. If you need to load files from there,
use `status get-file` or find alternatives (like loading completions for "foo" via `complete -C"foo "`).
We're considering making data embedding mandatory in future releases because it has a few advantages even for installation from a package (like making file conflicts with other packages impossible). (:issue:`11143`)
Deprecations and removed features
---------------------------------
- Tokens like ``{echo,echo}`` or ``{ echo, echo }`` in command position are no longer interpreted as brace expansion but as compound command.
- Terminfo-style key names (``bind -k``) are no longer supported. They had been superseded by the native notation since 4.0,
and currently they would map back to information from terminfo, which does not match what terminals would send with the kitty keyboard protocol (:issue:`11342`).
- fish no longer reads the terminfo database, so its behavior is no longer affected by the :envvar:`TERM` environment variable (:issue:`11344`).
For the time being, this can be turned off via the "ignore-terminfo" feature flag::
set -Ua fish_features no-ignore-terminfo
- The ``--install`` option when fish is built as self-installable was removed. If you need to write out fish's data you can use the new ``status list-files`` and ``status get-file`` subcommands, but it should no longer be necessary. (:issue:`11143`)
- RGB colors (``set_color ff0000``) now default to using 24-bit RGB true-color commands, even if $COLORTERM is unset, because that is often lost e.g. over ssh (:issue:`11372`)
- To go back to using the nearest match from the 256-color palette, use ``set fish_term24bit 0`` or set $COLORTERM to a value that is not "24bit" or "truecolor".
To make the nearest-match logic use the 16 color palette instead, use ``set fish_term256 0``.
- Inside macOS Terminal.app, fish makes an attempt to still use the palette colors.
If that doesn't work, use ``set fish_term24bit 0``.
- ``set_color --background=COLOR`` no longer implicitly activates bold mode.
To mitigate this change on existing installations that use a default theme, update your theme with ``fish_config theme choose`` or ``fish_config theme save``.
Scripting improvements
----------------------
Interactive improvements
------------------------
- Autosuggestions are now also provided in multi-line command lines. Like `ctrl-r`, autosuggestions operate only on the current line.
- Autosuggestions used to not suggest multi-line commandlines from history; now autosuggestions include individual lines from multi-line command lines.
- The history search now preserves ordering between :kbd:`ctrl-s` forward and :kbd:`ctrl-r` backward searches.
- Left mouse click (as requested by `click_events <terminal-compatibility.html#click-events>`__) can now select pager items (:issue:`10932`).
- Instead of flashing all the text to the left of the cursor, fish now flashes the matched token during history token search, the completed token during completion (:issue:`11050`), the autosuggestion when deleting it, and the full command line in all other cases.
- Pasted commands are now stripped of any ``$`` prefix.
- The :kbd:`alt-s` binding will now also use ``run0`` if available.
New or improved bindings
^^^^^^^^^^^^^^^^^^^^^^^^
- On non-macOS systems, :kbd:`alt-left`, :kbd:`alt-right`, :kbd:`alt-backspace`, :kbd:`alt-delete` no longer operate on punctuation-delimited words but on whole arguments, possibly including special characters like ``/`` and quoted spaces.
On macOS, the corresponding :kbd:`ctrl-` prefixed keys operate on whole arguments.
Word operations are still available via the other respective modifier, same as in the browser.
- :kbd:`ctrl-z` (undo) after executing a command will restore the previous cursor position instead of placing the cursor at the end of the command line.
- The OSC 133 prompt marking feature has learned about kitty's ``click_events=1`` flag, which allows moving fish's cursor by clicking.
- :kbd:`ctrl-l` now pushes all text located above the prompt to the terminal's scrollback, before clearing and redrawing the screen (via a new special input function ``scrollback-push``).
For compatibility with terminals that do not provide the scroll-forward command,
this is only enabled by default if the terminal advertises support for the ``indn`` capability via XTGETTCAP.
- Bindings using shift with non-ASCII letters (such as :kbd:`ctrl-shift-ä`) are now supported.
If there is any modifier other than shift, this is the recommended notation (as opposed to :kbd:`ctrl-Ä`).
- Vi mode has learned :kbd:`ctrl-a` (increment) and :kbd:`ctrl-x` (decrement) (:issue:`11570`).
Completions
^^^^^^^^^^^
- ``git`` completions now show the remote url as a description when completing remotes.
- ``systemctl`` completions no longer print escape codes if ``SYSTEMD_COLORS`` is set (:issue:`11465`).
Improved terminal support
^^^^^^^^^^^^^^^^^^^^^^^^^
- Support for double, curly, dotted and dashed underlines in `fish_color_*` variables and :doc:`set_color <cmds/set_color>` (:issue:`10957`).
- Underlines can now be colored independent of text (:issue:`7619`).
- New documentation page `Terminal Compatibility <terminal-compatibility.html>`_ (also accessible via ``man fish-terminal-compatibility``) lists required and optional terminal control sequences used by fish.
Other improvements
------------------
- ``fish_indent`` and ``fish_key_reader`` are now available as builtins, and if fish is called with that name it will act like the given tool (as a multi-call binary).
This allows truly distributing fish as a single file. (:issue:`10876`)
- ``fish_indent --dump-parse-tree`` now emits simple metrics about the tree including its memory consumption.
For distributors
----------------
- ``fish_indent`` and ``fish_key_reader`` are still built as separate binaries for now, but can also be replaced with a symlink if you want to save disk space (:issue:`10876`).
- The CMake system was simplified and no longer second-guesses rustup. It will run rustc and cargo via $PATH or in ~/.cargo/bin/.
If that doesn't match your setup, set the Rust_COMPILER and Rust_CARGO cmake variables (:issue:`11328`).
- Cygwin support has been reintroduced, since rust gained a Cygwin target (https://github.com/rust-lang/rust/pull/134999, :issue:`11238`).
- a regression in 4.0.6 causing shifted keys to not be inserted on some terminals (:issue:`11813`).
- a regression in 4.0.6 causing the build to fail on systems where ``char`` is unsigned (:issue:`11804`).
- a regression in 4.0.0 causing a crash on an invalid :doc:`bg <cmds/bg>` invocation.
--------------
fish 4.0.8 (released September 18, 2025)
========================================
This release fixes a regression in 4.0.6 that caused user bindings to be shadowed by either fish's or a plugin's bindings (:issue:`11803`).
--------------
fish 4.0.6 (released September 12, 2025)
========================================
This release of fish fixes a number of issues identified in fish 4.0.2:
- fish now properly inherits $PATH under Windows WSL2 (:issue:`11354`).
- Remote filesystems are detected properly again on non-Linux systems.
- the :doc:`printf <cmds/printf>` builtin no longer miscalculates width of multi-byte characters (:issue:`11412`).
- For many years, fish has been "relocatable" -- it was possible to move the entire ``CMAKE_INSTALL_PREFIX`` and fish would use paths relative to its binary.
Only gettext locale paths were still determined purely at compile time, which has been fixed.
- the :doc:`commandline <cmds/commandline>` builtin failed to print the commandline set by a ``commandline -C`` invocation, which broke some completion scripts.
This has been corrected (:issue:`11423`).
- To work around terminals that fail to parse Operating System Command (OSC) sequences, a temporary feature flag has been added.
It allows you to disable prompt marking (OSC 133) by running (once) ``set -Ua fish_features no-mark-prompt`` and restarting fish (:issue:`11749`).
- The routines to save history and universal variables have seen some robustness improvements.
- builtin :doc:`status current-command <cmds/status>` no longer prints a trailing blank line.
- A crash displaying multi-line quoted command substitutions has been fixed (:issue:`11444`).
- Commands like ``set fish_complete_path ...`` accidentally disabled completion autoloading, which has been corrected.
- ``nmcli`` completions have been fixed to query network information dynamically instead of only when completing the first time.
- Git completions no longer print an error when no `git-foo` executable is in :envvar:`PATH`.
- Custom completions like ``complete foo -l long -xa ...`` that use the output of ``commandline -t``.
on a command-line like ``foo --long=`` have been invalidated by a change in 4.0; the completion scripts have been adjusted accordingly (:issue:`11508`).
- Some completions were misinterpreted, which caused garbage to be displayed in the completion list. This has been fixed.
- fish no longer interprets invalid control sequences from the terminal as if they were :kbd:`alt-[` or :kbd:`alt-o` key strokes.
- :doc:`bind <cmds/bind>` has been taught about the :kbd:`printscreen` and :kbd:`menu` keys.
- :kbd:`alt-delete` now deletes the word right of the cursor.
- :kbd:`ctrl-alt-h` erases the last word again (:issue:`11548`).
- :kbd:`alt-left` :kbd:`alt-right` were misinterpreted because they send unexpected sequences on some terminals; a workaround has been added. (:issue:`11479`).
- Key bindings like ``bind shift-A`` are no longer accepted; use ``bind shift-a`` or ``bind A``.
- Key bindings like ``bind shift-a`` take precedence over ``bind A`` when the key event included the shift modifier.
- Bindings using shift with non-ASCII letters (such as :kbd:`ctrl-shift-ä`) are now supported.
- Bindings with modifiers such as ``bind ctrl-w`` work again on non-Latin keyboard layouts such as a Russian one.
This is implemented by allowing key events such as :kbd:`ctrl-ц` to match bindings of the corresponding Latin key, using the kitty keyboard protocol's base layout key (:issue:`11520`).
- Vi mode: The cursor position after pasting via :kbd:`p` has been corrected.
- Vi mode: Trying to replace the last character via :kbd:`r` no longer replaces the last-but-one character (:issue:`11484`),
fish 4.0.2 (released April 20, 2025)
====================================
@@ -131,7 +91,7 @@ This release of fish includes the following improvements compared to fish 4.0.0:
- Completions for ``wine`` correctly include files again (:issue:`11202`).
- On macOS, paths from ``/etc/paths`` and ``/etc/manpaths`` containing colons are handled correctly (:issue:`10684`). This functionality was included in the 4.0.0 release notes but was missing from the source code.
- The XTerm ``modifyOtherKeys`` keyboard encoding is no longer used under WezTerm, as it does not work correctly in all layouts (:issue:`11204`).
- :kbd:`option-left` and other similar keys should now work in iTerm versions before 3.5.12; the kitty keyboard protocol is now disabled on these versions (:issue:`11192`).
- kbd:`option-left` and other similar keys should now work in iTerm versions before 3.5.12; the kitty keyboard protocol is now disabled on these versions (:issue:`11192`).
- The kitty keyboard protocol is no longer used under Midnight Commander, as it does not work correctly (:issue:`10640`).
- fish now sends the commandline along with the OSC 133 semantic prompt command start sequence. This fixes a test in the kitty terminal (:issue:`11203`).
- Git completions for third-party commands like "git-absorb" are completed correctly again (:issue:`11205`).
@@ -292,6 +252,7 @@ Interactive improvements
The color scheme will not be upgraded for existing installs. If you want, you should select it again via ``fish_config``.
- Command lines which are larger than the terminal are now displayed correctly, instead of multiple blank lines being displayed (:issue:`7296`).
- Prompts that use external commands will no longer produce an infinite loop if the command crashes (:issue:`9796`).
- Undo (:kbd:`ctrl-z`) restores the cursor position too (:issue:`10838`).
- The output of ``jobs`` shows "-" for jobs that have the same process group ID as the fish process, rather than "-2" (:issue:`10833`).
- Job expansion (``%1`` syntax) works properly for jobs that are a mixture of external commands and functions (:issue:`10832`).
- Command lines which have more lines than the terminal can be displayed and edited correctly (:issue:`10827`).
@@ -308,7 +269,6 @@ New or improved bindings
- :kbd:`shift-delete` will also remove the currently-displayed autosuggestion from history, and remove it as a suggestion.
- :kbd:`ctrl-Z` (also known as :kbd:`ctrl-shift-z`) is now bound to redo.
- Some improvements to the :kbd:`alt-e` binding which edits the command line in an external editor:
- The editor's cursor position is copied back to fish. This is currently supported for Vim and Kakoune.
- Cursor position synchronization is only supported for a set of known editors, which are now also detected in aliases which use ``complete --wraps``. For example, use ``complete --wraps my-vim vim`` to synchronize cursors when ``EDITOR=my-vim``.
- Multiline commands are indented before being sent to the editor, which matches how they are displayed in fish.
@@ -317,18 +277,15 @@ New or improved bindings
- :kbd:`alt-d` on an empty command line lists the directory history again. This restores the behavior of version 2.1.
- ``history-prefix-search-backward`` and ``-forward`` now maintain the cursor position, instead of moving the cursor to the end of the command line (:issue:`10430`).
- The following keys have refined behavior if the terminal supports :ref:`the new keyboard encodings <changelog-new-bindings>`:
- :kbd:`shift-enter` now inserts a newline instead of executing the command line.
- :kbd:`ctrl-backspace` now deletes the last word instead of only one character (:issue:`10741`).
- :kbd:`ctrl-delete` deletes the next word (same as :kbd:`alt-d`).
- New special input functions:
- ``forward-char-passive`` and ``backward-char-passive`` are like their non-passive variants but do not accept autosuggestions or move focus in the completion pager (:issue:`10398`).
- ``forward-token``, ``backward-token``, ``kill-token``, and ``backward-kill-token`` are similar to the ``*-bigword`` variants but for the whole argument token (which includes escaped spaces) (:issue:`2014`).
- ``clear-commandline``, which merely clears the command line, as an alternative to ``cancel-commandline`` which prints ``^C`` and a new prompt (:issue:`10213`).
- The ``accept-autosuggestion`` special input function now returns false when there was nothing to accept (:issue:`10608`).
- Vi mode has seen some improvements but continues to suffer from the lack of people working on it.
- New default cursor shapes for insert and replace mode.
- :kbd:`ctrl-n` in insert mode accepts autosuggestions (:issue:`10339`).
- Outside insert mode, the cursor will no longer be placed beyond the last character on the commandline.
@@ -666,7 +623,7 @@ fish 3.6.0 (released January 7, 2023)
Notable improvements and fixes
------------------------------
- By default, :kbd:`ctrl-r` now opens the command history in the pager (:issue:`602`). This is fully searchable and syntax-highlighted, as an alternative to the incremental search seen in other shells. The new special input function ``history-pager`` has been added for custom bindings.
- Abbreviations are more flexible (:issue:`9313`, :issue:`5003`, :issue:`2287`):
- Abbrevations are more flexible (:issue:`9313`, :issue:`5003`, :issue:`2287`):
- They may optionally replace tokens anywhere on the command line, instead of only commands
- Matching tokens may be described using a regular expression instead of a literal word
@@ -762,7 +719,7 @@ Interactive improvements
- A new variable, :envvar:`fish_cursor_selection_mode`, can be used to configure whether the command line selection includes the character under the cursor (``inclusive``) or not (``exclusive``). The new default is ``exclusive``; use ``set fish_cursor_selection_mode inclusive`` to get the previous behavior back (:issue:`7762`).
- fish's completion pager now fills half the terminal on first tab press instead of only 4 rows, which should make results visible more often and save key presses, without constantly snapping fish to the top of the terminal (:issue:`9105`, :issue:`2698`).
- The ``complete-and-search`` binding, used with :kbd:`shift-tab` by default, selects the first item in the results immediately (:issue:`9080`).
- ``bind`` output is now syntax-highlighted when used interactively.
- ``bind`` output is now syntax-highlighted when used interacively.
- :kbd:`alt-h` (the default ``__fish_man_page`` binding) does a better job of showing the manual page of the command under cursor (:issue:`9020`).
- If :envvar:`fish_color_valid_path` contains an actual color instead of just modifiers, those will be used for valid paths even if the underlying color isn't "normal" (:issue:`9159`).
- The key combination for the QUIT terminal sequence, often :kbd:`ctrl-\\` (``\x1c``), can now be used as a binding (:issue:`9234`).
@@ -991,7 +948,7 @@ Interactive improvements
New or improved bindings
^^^^^^^^^^^^^^^^^^^^^^^^
- The :kbd:`alt-s` binding will now insert ``doas`` instead of ``sudo`` if necessary (:issue:`8942`).
- The ``kill-whole-line`` special input function now kills the newline preceding the last line. This makes ``dd`` in vi-mode clear the last line properly.
- The ``kill-whole-line`` special input function now kills the newline preceeding the last line. This makes ``dd`` in vi-mode clear the last line properly.
- The new ``kill-inner-line`` special input function kills the line without any newlines, allowing ``cc`` in vi-mode to clear the line while preserving newlines (:issue:`8983`).
- On terminals that emit special sequences for these combinations, :kbd:`shift-space` is bound like :kbd:`space`, and :kbd:`ctrl-enter` is bound like :kbd:`return` (:issue:`8874`).
@@ -1100,7 +1057,7 @@ Deprecations and removed features
> set -Ua fish_features ampersand-nobg-in-token
- ``$status`` is now forbidden as a command, to prevent a surprisingly common error among new users: Running ``if $status`` (:issue:`8171`). This applies *only* to ``$status``, other variables are still allowed.
- ``set --query`` now returns an exit status of 255 if given no variable names. This means ``if set -q $foo`` will not enter the if-block if ``$foo`` is empty or unset. To restore the previous behavior, use ``if not set -q foo; or set -q $foo`` - but this is unlikely to be desirable (:issue:`8214`).
- ``set --query`` now returns an exit status of 255 if given no variable names. This means ``if set -q $foo`` will not enter the if-block if ``$foo`` is empty or unset. To restore the previous behavior, use ``if not set -q foo; or set -q $foo`` - but this is unlikely to be desireable (:issue:`8214`).
- ``_`` is now a reserved keyword (:issue:`8342`).
- The special input functions ``delete-or-exit``, ``nextd-or-forward-word`` and ``prevd-or-backward-word`` replace fish functions of the same names (:issue:`8538`).
- Mac OS X 10.9 is no longer supported. The minimum Mac version is now 10.10 "Yosemite."
@@ -1123,7 +1080,7 @@ Scripting improvements
- ``commandline`` gained a ``--paging-full-mode`` option to check if the pager is showing all the possible lines (no "7 more rows" message) (:issue:`8485`).
- List expansion correctly reports an error when used with all zero indexes (:issue:`8213`).
- Running ``fish`` with a directory instead of a script as argument (eg ``fish .``) no longer leads to an infinite loop. Instead it errors out immediately (:issue:`8258`)
- Some error messages occurring after fork, like "text file busy" have been replaced by bespoke error messages for fish (like "File is currently open for writing"). This also restores error messages with current glibc versions that removed sys_errlist (:issue:`8234`, :issue:`4183`).
- Some error messages occuring after fork, like "text file busy" have been replaced by bespoke error messages for fish (like "File is currently open for writing"). This also restores error messages with current glibc versions that removed sys_errlist (:issue:`8234`, :issue:`4183`).
- The ``realpath`` builtin now also squashes leading slashes with the ``--no-symlinks`` option (:issue:`8281`).
- When trying to ``cd`` to a dangling (broken) symbolic link, fish will print an error noting that the target is a broken link (:issue:`8264`).
- On MacOS terminals that are not granted permissions to access a folder, ``cd`` would print a spurious "rotten symlink" error, which has been corrected to "permission denied" (:issue:`8264`).
@@ -1629,7 +1586,7 @@ Interactive improvements
- :kbd:`ctrl-c` handling has been reimplemented in C++ and is therefore quicker (:issue:`5259`), no longer occasionally prints an "unknown command" error (:issue:`7145`) or overwrites multiline prompts (:issue:`3537`).
- :kbd:`ctrl-c` no longer kills background jobs for which job control is
disabled, matching POSIX semantics (:issue:`6828`, :issue:`6861`).
- Autosuggestions work properly after :kbd:`ctrl-c` cancels the current command line (:issue:`6937`).
- Autosuggestions work properly after :kbd:`ctrl-c` cancels the current commmand line (:issue:`6937`).
- History search is now case-insensitive unless the search string contains an uppercase character (:issue:`7273`).
- ``fish_update_completions`` gained a new ``--keep`` option, which improves speed by skipping completions that already exist (:issue:`6775`, :issue:`6796`).
- Aliases containing an embedded backslash appear properly in the output of ``alias`` (:issue:`6910`).
@@ -2183,7 +2140,7 @@ Interactive improvements
argument.
- Syntax highlighting works correctly with variables as commands
(:issue:`5658`) and redirections to close file descriptors (:issue:`6092`).
- ``help`` works properly on Windows Subsystem for Linux (:issue:`5759`, :issue:`6338`).
- ``help`` works properly on Windows Subsytem for Linux (:issue:`5759`, :issue:`6338`).
- A bug where ``disown`` could crash the shell has been fixed (:issue:`5720`).
- fish will not autosuggest files ending with ``~`` unless there are no
other candidates, as these are generally backup files (:issue:`985`).
@@ -3125,7 +3082,7 @@ Other significant changes
- Some systems ``su`` implementations do not set the ``USER``
environment variable; it is now reset for root users (:issue:`3916`).
- Under terminals which support it, bracketed paste is enabled,
escaping problematic characters for security and convenience (:issue:`3871`).
escaping problematic characters for security and convience (:issue:`3871`).
Inside single quotes (``'``), single quotes and backslashes in pasted
text are escaped (:issue:`967`). The ``fish_clipboard_paste`` function (bound
to ``C-v`` by default) is still the recommended pasting method where
@@ -3254,9 +3211,9 @@ Other significant changes
- fish no longer prints a warning when it identifies a running instance
of an old version (2.1.0 and earlier). Changes to universal variables
may not propagate between these old versions and 2.5b1.
- Improved compatibility with Android (:issue:`3585`), MSYS/mingw (:issue:`2360`), and
- Improved compatiblity with Android (:issue:`3585`), MSYS/mingw (:issue:`2360`), and
Solaris (:issue:`3456`, :issue:`3340`).
- Like other shells, the ``test`` built-in now returns an error for
- Like other shells, the ``test`` builting now returns an error for
numeric operations on invalid integers (:issue:`3346`, :issue:`3581`).
- ``complete`` no longer recognises ``--authoritative`` and
``--unauthoritative`` options, and they are marked as obsolete.

View File

@@ -7,6 +7,9 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(DEFAULT_BUILD_TYPE "RelWithDebInfo")
# Generate Xcode schemas (but not for tests).
set(CMAKE_XCODE_GENERATE_SCHEME 1)
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to default '${DEFAULT_BUILD_TYPE}'")
set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}")
@@ -14,6 +17,7 @@ endif()
# Set up standard directories.
include(GNUInstallDirs)
add_definitions(-D_UNICODE=1)
include(cmake/gettext.cmake)
@@ -26,6 +30,12 @@ include(cmake/Rust.cmake)
# Work around issue where archive-built libs go in the wrong place.
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
set(FISH_IN_TREE_BUILD TRUE)
else()
set(FISH_IN_TREE_BUILD FALSE)
endif()
# Set up the machinery around FISH-BUILD-VERSION-FILE
# This defines the FBVF variable.
include(Version)
@@ -36,11 +46,6 @@ get_filename_component(REAL_CMAKE_SOURCE_DIR "${CMAKE_SOURCE_DIR}" REALPATH)
add_definitions(-DCMAKE_BINARY_DIR="${REAL_CMAKE_BINARY_DIR}")
add_definitions(-DCMAKE_SOURCE_DIR="${REAL_CMAKE_SOURCE_DIR}")
set(build_types Release RelWithDebInfo Debug "")
if(NOT "${CMAKE_BUILD_TYPE}" IN_LIST build_types)
message(WARNING "Unsupported build type ${CMAKE_BUILD_TYPE}. If this doesn't build, try one of Release, RelWithDebInfo or Debug")
endif()
# Define a function to build and link dependencies.
function(CREATE_TARGET target)
add_custom_target(
@@ -76,6 +81,8 @@ create_target(fish_key_reader)
# Set up the docs.
include(cmake/Docs.cmake)
# A helper for running tests.
add_executable(fish_test_helper src/fish_test_helper.c)
# Set up tests.
include(cmake/Tests.cmake)

View File

@@ -126,3 +126,4 @@ enforcement ladder](https://github.com/mozilla/diversity).
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

View File

@@ -50,7 +50,7 @@ Contributing completions
Completion scripts are the most common contribution to fish, and they are very welcome.
In general, we'll take all well-written completion scripts for a command that is publicly available.
In general, we'll take all well-written completion scripts for a command that is publically available.
This means no private tools or personal scripts, and we do reserve the right to reject for other reasons.
Before you try to contribute them to fish, consider if the authors of the tool you are completing want to maintain the script instead.
@@ -196,14 +196,8 @@ The tests can be found in three places:
- tests/pexpects for interactive tests using `pexpect <https://pexpect.readthedocs.io/en/stable/>`__
When in doubt, the bulk of the tests should be added as a littlecheck test in tests/checks, as they are the easiest to modify and run, and much faster and more dependable than pexpect tests. The syntax is fairly self-explanatory. It's a fish script with the expected output in ``# CHECK:`` or ``# CHECKERR:`` (for stderr) comments.
If your littlecheck test has a specific dependency, use ``# REQUIRE: ...`` with a posix sh script.
The pexpects are written in python and can simulate input and output to/from a terminal, so they are needed for anything that needs actual interactivity. The runner is in tests/pexpect_helper.py, in case you need to modify something there.
These tests can be run via the tests/test_driver.py python script, which will set up the environment.
It sets up a temporary $HOME and also uses it as the current directory, so you do not need to create a temporary directory in them.
If you need a command to do something weird to test something, maybe add it to the ``fish_test_helper`` binary (in tests/fish_test_helper.c), or see if it can already do it.
The pexpects are written in python and can simulate input and output to/from a terminal, so they are needed for anything that needs actual interactivity. The runner is in build_tools/pexpect_helper.py, in case you need to modify something there.
Local testing
-------------
@@ -215,15 +209,6 @@ The tests can be run on your local computer on all operating systems.
cmake path/to/fish-shell
make fish_run_tests
Or you can run them on a fish, without involving cmake::
cargo build
cargo test # for the unit tests
tests/test_driver.py target/debug # for the script and interactive tests
Here, the first argument to test_driver.py refers to a directory with ``fish``, ``fish_indent`` and ``fish_key_reader`` in it.
In this example we're in the root of the git repo and have run ``cargo build`` without ``--release``, so it's a debug build.
Git hooks
---------
@@ -284,62 +269,37 @@ Contributing Translations
Fish uses the GNU gettext library to translate messages from English to
other languages.
Translation sources are
Creating and updating translations requires the Gettext tools, including
``xgettext``, ``msgfmt`` and ``msgmerge``. Translation sources are
stored in the ``po`` directory, named ``LANG.po``, where ``LANG`` is the
two letter ISO 639-1 language code of the target language (e.g. ``de`` for
German). A region specifier can also be used (e.g. ``pt_BR`` for Brazilian Portuguese).
two letter ISO 639-1 language code of the target language (eg ``de`` for
German).
Adding translations for a new language
--------------------------------------
To create a new translation:
Creating new translations requires the Gettext tools.
More specifically, you will need ``msguniq`` and ``msgmerge`` for creating translations for a new
language.
To create a new translation, run::
* generate a ``messages.pot`` file by running ``build_tools/fish_xgettext.fish`` from
the source tree
* copy ``messages.pot`` to ``po/LANG.po``
build_tools/update_translations.fish po/LANG.po
To update a translation:
By default, this also creates ``mo`` files, which contain the information from the ``po`` files in a
binary format.
Fish uses these files for translating at runtime.
They are not tracked in version control, but they can help translators check if their translations
show up correctly.
If you build fish locally (``cargo build``), and then run the resulting binary,
it will make use of the ``mo`` files generated by the script.
Use the ``LANG`` environment variable to tell fish which language to use, e.g.::
* generate a ``messages.pot`` file by running
``build_tools/fish_xgettext.fish`` from the source tree
LANG=pt_BR.utf8 target/debug/fish
* update the existing translation by running
``msgmerge --update --no-fuzzy-matching po/LANG.po messages.pot``
If you do not care about the ``mo`` files you can pass the ``--no-mo`` flag to the
``update_translations.fish`` script.
Modifying existing translations
-------------------------------
If you want to work on translations for a language which already has a corresponding ``po`` file, it
is sufficient to edit this file. No other changes are necessary.
To see your translations in action you can run::
build_tools/update_translations.fish --only-mo po/LANG.po
to update the binary ``mo`` used by fish. Check the information for adding new languages for a
description on how you can get fish to use these files.
Running this script requires a fish executable and the gettext ``msgfmt`` tool.
Editing PO files
----------------
The ``--no-fuzzy-matching`` is important as we have had terrible experiences with gettext's "fuzzy" translations in the past.
Many tools are available for editing translation files, including
command-line and graphical user interface programs. For simple use, you can use your text editor.
command-line and graphical user interface programs. For simple use, you can just use your text editor.
Open up the po file, for example ``po/sv.po``, and you'll see something like::
msgid "%ls: No suitable job\n"
msgstr ""
msgstr ""
The ``msgid`` here is the "name" of the string to translate, typically the English string to translate.
The second line (``msgstr``) is where your translation goes.
The ``msgid`` here is the "name" of the string to translate, typically the english string to translate. The second line (``msgstr``) is where your translation goes.
For example::
@@ -352,17 +312,11 @@ Also any escaped characters, like that ``\n`` newline at the end, should be kept
Our tests run ``msgfmt --check-format /path/to/file``, so they would catch mismatched placeholders - otherwise fish would crash at runtime when the string is about to be used.
Be cautious about blindly updating an existing translation file.
``msgid`` strings should never be updated manually, only by running the appropriate script.
Modifications to strings in source files
----------------------------------------
If a string changes in the sources, the old translations will no longer work.
They will be preserved in the ``po`` files, but commented-out (starting with ``#~``).
If you add/remove/change a translatable strings in a source file,
run ``build_tools/update_translations.fish`` to propagate this to all translation files (``po/*.po``).
This is only relevant for developers modifying the source files of fish or fish scripts.
Be cautious about blindly updating an existing translation file. Trivial
changes to an existing message (eg changing the punctuation) will cause
existing translations to be removed, since the tools do literal string
matching. Therefore, in general, you need to carefully review any
recommended deletions.
Setting Code Up For Translations
--------------------------------

View File

@@ -1,7 +1,7 @@
Fish is a smart and user-friendly command line shell.
Copyright (C) 2005-2009 Axel Liljencrantz
Copyright (C) 2009- fish-shell contributors
Copyright (C) 2009-2024 fish-shell contributors
fish is free software.

195
Cargo.lock generated
View File

@@ -4,9 +4,9 @@ version = 3
[[package]]
name = "allocator-api2"
version = "0.2.21"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
[[package]]
name = "autocfg"
@@ -31,9 +31,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.2.7"
version = "1.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7"
checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945"
dependencies = [
"jobserver",
"libc",
@@ -54,9 +54,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "cpufeatures"
version = "0.2.16"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3"
checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
dependencies = [
"libc",
]
@@ -71,6 +71,19 @@ dependencies = [
"typenum",
]
[[package]]
name = "dashmap"
version = "5.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
dependencies = [
"cfg-if",
"hashbrown 0.14.5",
"lock_api",
"once_cell",
"parking_lot_core",
]
[[package]]
name = "digest"
version = "0.10.7"
@@ -89,23 +102,23 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "errno"
version = "0.3.11"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
dependencies = [
"libc",
"windows-sys",
"windows-sys 0.52.0",
]
[[package]]
name = "fish"
version = "4.1.0-alpha0"
version = "4.0.9"
dependencies = [
"bitflags",
"cc",
"errno",
"fish-gettext-extraction",
"fish-printf",
"lazy_static",
"libc",
"lru",
"nix",
@@ -118,17 +131,9 @@ dependencies = [
"rust-embed",
"serial_test",
"terminfo",
"unix_path",
"widestring",
]
[[package]]
name = "fish-gettext-extraction"
version = "0.0.1"
dependencies = [
"proc-macro2",
]
[[package]]
name = "fish-printf"
version = "0.2.1"
@@ -147,9 +152,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foldhash"
version = "0.1.4"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
[[package]]
name = "generic-array"
@@ -163,9 +168,15 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.15.2"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "hashbrown"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
dependencies = [
"allocator-api2",
"equivalent",
@@ -182,10 +193,16 @@ dependencies = [
]
[[package]]
name = "libc"
version = "0.2.172"
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.159"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
[[package]]
name = "lock_api"
@@ -205,11 +222,11 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "lru"
version = "0.13.0"
version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465"
checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
dependencies = [
"hashbrown",
"hashbrown 0.15.0",
]
[[package]]
@@ -226,9 +243,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "nix"
version = "0.30.1"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
dependencies = [
"bitflags",
"cfg-if",
@@ -306,18 +323,18 @@ dependencies = [
[[package]]
name = "phf"
version = "0.11.3"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
dependencies = [
"phf_shared",
]
[[package]]
name = "phf_codegen"
version = "0.11.3"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a"
checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a"
dependencies = [
"phf_generator",
"phf_shared",
@@ -325,9 +342,9 @@ dependencies = [
[[package]]
name = "phf_generator"
version = "0.11.3"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
dependencies = [
"phf_shared",
"rand",
@@ -335,9 +352,9 @@ dependencies = [
[[package]]
name = "phf_shared"
version = "0.11.3"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
dependencies = [
"siphasher",
]
@@ -350,24 +367,24 @@ checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "portable-atomic"
version = "1.10.0"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6"
checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
[[package]]
name = "proc-macro2"
version = "1.0.95"
version = "1.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
@@ -389,9 +406,9 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
[[package]]
name = "redox_syscall"
version = "0.5.8"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
dependencies = [
"bitflags",
]
@@ -425,7 +442,7 @@ dependencies = [
"proc-macro2",
"quote",
"rust-embed-utils",
"syn",
"syn 2.0.79",
"walkdir",
]
@@ -448,48 +465,33 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "scc"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28e1c91382686d21b5ac7959341fcb9780fa7c03773646995a87c950fa7be640"
dependencies = [
"sdd",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "sdd"
version = "3.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "478f121bb72bbf63c52c93011ea1791dca40140dfe13f8336c4c5ac952c33aa9"
[[package]]
name = "serial_test"
version = "3.2.0"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9"
checksum = "538c30747ae860d6fb88330addbbd3e0ddbe46d662d032855596d8a8ca260611"
dependencies = [
"once_cell",
"dashmap",
"lazy_static",
"parking_lot",
"scc",
"serial_test_derive",
]
[[package]]
name = "serial_test_derive"
version = "3.2.0"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef"
checksum = "079a83df15f85d89a68d64ae1238f142f172b1fa915d0d76b26a7cba1b659a69"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 1.0.109",
]
[[package]]
@@ -511,9 +513,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "siphasher"
version = "1.0.1"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
[[package]]
name = "smallvec"
@@ -523,9 +525,20 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "syn"
version = "2.0.95"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
dependencies = [
"proc-macro2",
"quote",
@@ -552,9 +565,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicode-ident"
version = "1.0.14"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
name = "unicode-segmentation"
@@ -568,21 +581,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
[[package]]
name = "unix_path"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af8e291873ae77c4c8d9c9b34d0bee68a35b048fb39c263a5155e0e353783eaf"
dependencies = [
"unix_str",
]
[[package]]
name = "unix_str"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ace0b4755d0a2959962769239d56267f8a024fef2d9b32666b3dcd0946b0906"
[[package]]
name = "version_check"
version = "0.9.5"
@@ -601,9 +599,9 @@ dependencies = [
[[package]]
name = "widestring"
version = "1.2.0"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d"
checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311"
[[package]]
name = "winapi-util"
@@ -611,7 +609,16 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys",
"windows-sys 0.59.0",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]

View File

@@ -1,12 +1,10 @@
[workspace]
resolver = "2"
members = ["printf", "gettext-extraction"]
members = ["printf"]
[workspace.package]
# To build revisions that use Corrosion (those before 2024-01), use CMake 3.19, Rustc 1.78 and Rustup 1.27.
rust-version = "1.70"
edition = "2021"
repository = "https://github.com/fish-shell/fish-shell"
[profile.release]
overflow-checks = true
@@ -18,13 +16,14 @@ debug = true
[package]
name = "fish"
version = "4.1.0-alpha0"
version = "4.0.9"
edition.workspace = true
rust-version.workspace = true
default-run = "fish"
# see doc_src/license.rst for details
# don't forget to update COPYING and debian/copyright too
license = "GPL-2.0-only AND LGPL-2.0-or-later AND MIT AND PSF-2.0"
repository = "https://github.com/fish-shell/fish-shell"
homepage = "https://fishshell.com"
readme = "README.rst"
@@ -35,12 +34,13 @@ pcre2 = { git = "https://github.com/fish-shell/rust-pcre2", tag = "0.2.9-utf32",
bitflags = "2.5.0"
errno = "0.3.0"
libc = "0.2"
lazy_static = "1.4.0"
libc = "0.2.155"
# lru pulls in hashbrown by default, which uses a faster (though less DoS resistant) hashing algo.
# disabling default features uses the stdlib instead, but it doubles the time to rewrite the history
# files as of 22 April 2024.
lru = "0.13.0"
nix = { version = "0.30.1", default-features = false, features = [
lru = "0.12.3"
nix = { version = "0.29.0", default-features = false, features = [
"event",
"inotify",
"resource",
@@ -49,13 +49,12 @@ nix = { version = "0.30.1", default-features = false, features = [
num-traits = "0.2.19"
once_cell = "1.19.0"
fish-printf = { path = "./printf", features = ["widestring"] }
fish-gettext-extraction = { path = "./gettext-extraction" }
# Don't use the "getrandom" feature as it requires "getentropy" which was not
# available on macOS < 10.12. We can enable "getrandom" when we raise the
# minimum supported version to 10.12.
rand = { version = "0.8.5", default-features = false, features = ["small_rng"] }
widestring = "1.2.0"
widestring = "1.1.0"
# We need 0.9.0 specifically for some crash fixes.
terminfo = "0.9.0"
rust-embed = { version = "8.2.0", optional = true }
@@ -66,15 +65,12 @@ portable-atomic = { version = "1", default-features = false, features = [
] }
[dev-dependencies]
serial_test = { version = "3", default-features = false }
serial_test = { version = "1.0.0", default-features = false }
[build-dependencies]
cc = "1.0.94"
rsconf = "0.2.2"
[target.'cfg(windows)'.build-dependencies]
unix_path = "1.0.1"
[lib]
crate-type = ["rlib"]
path = "src/lib.rs"
@@ -92,15 +88,15 @@ name = "fish_key_reader"
path = "src/bin/fish_key_reader.rs"
[features]
default = ["embed-data"]
default = ["installable"]
benchmark = []
embed-data = ["dep:rust-embed"]
installable = ["dep:rust-embed"]
# The following features are auto-detected by the build-script and should not be enabled manually.
asan = []
tsan = []
[workspace.lints]
[lints]
rust.non_camel_case_types = "allow"
rust.non_upper_case_globals = "allow"
rust.unknown_lints = "allow"
@@ -108,12 +104,3 @@ rust.unstable_name_collisions = "allow"
clippy.manual_range_contains = "allow"
clippy.needless_return = "allow"
clippy.needless_lifetimes = "allow"
# We do not want to use the e?print(ln)?! macros.
# These lints flag their use.
# In the future, they might change to flag other methods of printing.
clippy.print_stdout = "deny"
clippy.print_stderr = "deny"
[lints]
workspace = true

View File

@@ -16,3 +16,4 @@ WORKDIR /src
RUN cmake3 . &&\
make &&\
make install

View File

@@ -47,12 +47,12 @@ Linux/CentOS are available from the `openSUSE Build
Service <https://software.opensuse.org/download.html?project=shells%3Afish&package=fish>`__.
Packages for Ubuntu are available from the `fish
PPA <https://launchpad.net/~fish-shell/+archive/ubuntu/release-4>`__,
PPA <https://launchpad.net/~fish-shell/+archive/ubuntu/release-3>`__,
and can be installed using the following commands:
::
sudo apt-add-repository ppa:fish-shell/release-4
sudo apt-add-repository ppa:fish-shell/release-3
sudo apt update
sudo apt install fish
@@ -75,7 +75,7 @@ If packages are not available for your platform, GPG-signed tarballs are
available from `fishshell.com <https://fishshell.com/>`__ and
`fish-shell on
GitHub <https://github.com/fish-shell/fish-shell/releases>`__. See the
`Building <#building>`_ section for instructions.
`Building <#building>`__ section for instructions.
Running fish
------------
@@ -87,6 +87,8 @@ Dependencies
Running fish requires:
- A terminfo database, typically from curses or ncurses (preinstalled on most \*nix systems) - this needs to be the directory tree format, not the "hashed" database.
If this is unavailable, fish uses an included xterm-256color definition.
- some common \*nix system utilities (currently ``mktemp``), in
addition to the basic POSIX utilities (``cat``, ``cut``, ``dirname``,
``file``, ``ls``, ``mkdir``, ``mkfifo``, ``rm``, ``sort``, ``tee``, ``tr``,
@@ -157,9 +159,6 @@ CMake Build options
In addition to the normal CMake build options (like ``CMAKE_INSTALL_PREFIX``), fish's CMake build has some other options available to customize it.
- Rust_COMPILER=path - the path to rustc. If not set, cmake will check $PATH and ~/.cargo/bin
- Rust_CARGO=path - the path to cargo. If not set, cmake will check $PATH and ~/.cargo/bin
- Rust_CARGO_TARGET=target - the target to pass to cargo. Set this for cross-compilation.
- BUILD_DOCS=ON|OFF - whether to build the documentation. This is automatically set to OFF when Sphinx isn't installed.
- INSTALL_DOCS=ON|OFF - whether to install the docs. This is automatically set to on when BUILD_DOCS is or prebuilt documentation is available (like when building in-tree from a tarball).
- FISH_USE_SYSTEM_PCRE2=ON|OFF - whether to use an installed pcre2. This is normally autodetected.
@@ -167,19 +166,19 @@ In addition to the normal CMake build options (like ``CMAKE_INSTALL_PREFIX``), f
- WITH_GETTEXT=ON|OFF - whether to build with gettext support for translations.
- extra_functionsdir, extra_completionsdir and extra_confdir - to compile in an additional directory to be searched for functions, completions and configuration snippets
Building fish with embedded data (experimental)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Building fish as self-installable (experimental)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can also build fish with the data files embedded.
You can also build fish as a self-installing binary.
This will include all the datafiles like the included functions or web configuration tool in the main ``fish`` binary.
Fish will then read these right from its own binary, and print them out when needed. Some files, like the webconfig tool and the manpage completion generator, will be extracted to a temporary directory on-demand. You can list the files with ``status list-files`` and print one with ``status get-file path/to/file`` (e.g. ``status get-file functions/fish_prompt.fish`` to get the default prompt).
On the first interactive run, and whenever it notices they are out of date, it will extract the datafiles to ~/.local/share/fish/install/ (currently, subject to change). You can do this manually by running ``fish --install``.
To install fish with embedded files, just use ``cargo``, like::
To install fish as self-installable, just use ``cargo``, like::
cargo install --path /path/to/fish # if you have a git clone
cargo install --git https://github.com/fish-shell/fish-shell --tag 4.0.0 # to build from git with a specific version
cargo install --git https://github.com/fish-shell/fish-shell --tag 4.0 # to build from git once 4.0 is released
cargo install --git https://github.com/fish-shell/fish-shell # to build the current development snapshot without cloning
This will place the binaries in ``~/.cargo/bin/``, but you can place them wherever you want.

View File

@@ -1,35 +0,0 @@
# Security Reporting
If you wish to report a security vulnerability privately, we appreciate your diligence. Please follow the guidelines below to submit your report.
## Reporting
To report a security vulnerability, please provide the following information:
1. **PROJECT**
- Include the URL of the project repository - Example: <https://github.com/fish-shell/fish-shell>
2. **PUBLIC**
- Indicate whether this vulnerability has already been publicly discussed or disclosed.
- If so, provide relevant links.
3. **DESCRIPTION**
- Provide a detailed description of the security vulnerability.
- Include as much information as possible to help us understand and address the issue.
Send this information, along with any additional relevant details, to <rf@fishshell.com>.
## Confidentiality
We kindly ask you to keep the report confidential until a public announcement is made.
## Notes
- Vulnerabilities will be handled on a best-effort basis.
- You may request an advance copy of the patched release, but we cannot guarantee early access before the public release.
- You will be notified via email simultaneously with the public announcement.
- We will respond within a few weeks to confirm whether your report has been accepted or rejected.
Thank you for helping to improve the security of our project!

View File

@@ -8,4 +8,5 @@ for file in *.fish
echo FAILING FILE $file
end
end
end

View File

@@ -1,6 +1,6 @@
#!/bin/sh
if [ "$#" -gt 2 ] || [ "$#" -eq 0 ]; then
if [ "$#" -gt 2 -o "$#" -eq 0 ]; then
echo "Usage: driver.sh /path/to/fish [/path/to/other/fish]"
exit 1
fi

132
build.rs
View File

@@ -5,34 +5,29 @@
use std::error::Error;
use std::path::{Path, PathBuf};
fn canonicalize<P: AsRef<Path>>(path: P) -> PathBuf {
std::fs::canonicalize(path).unwrap()
}
fn canonicalize_str<P: AsRef<Path>>(path: P) -> String {
canonicalize(path).to_str().unwrap().to_owned()
}
const MANIFEST_DIR: &str = env!("CARGO_MANIFEST_DIR");
fn main() {
setup_paths();
// Add our default to enable tools that don't go through CMake, like "cargo test" and the
// language server.
let cargo_target_dir: PathBuf = option_env!("CARGO_TARGET_DIR")
.map(canonicalize)
.unwrap_or(canonicalize(MANIFEST_DIR).join("target"));
// FISH_BUILD_DIR is set by CMake, if we are using it.
rsconf::set_env_value(
"FISH_BUILD_DIR",
option_env!("FISH_BUILD_DIR").unwrap_or(cargo_target_dir.to_str().unwrap()),
);
// OUT_DIR is set by Cargo when the build script is running (not compiling)
let default_build_dir = env::var("OUT_DIR").unwrap();
let build_dir = option_env!("FISH_BUILD_DIR").unwrap_or(&default_build_dir);
let build_dir = std::fs::canonicalize(build_dir).unwrap();
let build_dir = build_dir.to_str().unwrap();
rsconf::set_env_value("FISH_BUILD_DIR", build_dir);
// We need to canonicalize (i.e. realpath) the manifest dir because we want to be able to
// compare it directly as a string at runtime.
rsconf::set_env_value("CARGO_MANIFEST_DIR", &canonicalize_str(MANIFEST_DIR));
rsconf::set_env_value(
"CARGO_MANIFEST_DIR",
std::fs::canonicalize(env!("CARGO_MANIFEST_DIR"))
.unwrap()
.as_path()
.to_str()
.unwrap(),
);
// Some build info
rsconf::set_env_value("BUILD_TARGET_TRIPLE", &env::var("TARGET").unwrap());
@@ -46,30 +41,18 @@ fn main() {
std::env::set_var("FISH_BUILD_VERSION", version);
let targetman = cargo_target_dir.join("fish-man");
#[cfg(feature = "embed-data")]
#[cfg(feature = "installable")]
#[cfg(not(clippy))]
{
let cman = std::fs::canonicalize(env!("CARGO_MANIFEST_DIR")).unwrap();
let targetman = cman.as_path().join("target").join("man");
build_man(&targetman);
}
#[cfg(any(not(feature = "embed-data"), clippy))]
{
let sec1dir = targetman.join("man1");
let _ = std::fs::create_dir_all(sec1dir.to_str().unwrap());
}
rsconf::rebuild_if_paths_changed(&["src", "printf", "Cargo.toml", "Cargo.lock", "build.rs"]);
// These are necessary if built with embedded functions,
// but only in release builds (because rust-embed in debug builds reads from the filesystem).
#[cfg(feature = "embed-data")]
#[cfg(not(debug_assertions))]
rsconf::rebuild_if_paths_changed(&["doc_src", "share"]);
rsconf::rebuild_if_env_changed("FISH_GETTEXT_EXTRACTION_FILE");
cc::Build::new().file("src/libc.c").compile("flibc.a");
rsconf::rebuild_if_path_changed("src/libc.c");
cc::Build::new()
.file("src/libc.c")
.include(build_dir)
.compile("flibc.a");
let mut build = cc::Build::new();
// Add to the default library search path
@@ -105,9 +88,7 @@ fn detect_cfgs(target: &mut Target) {
"",
&(|_: &Target| Ok(false)) as &dyn Fn(&Target) -> Result<bool, Box<dyn Error>>,
),
("apple", &detect_apple),
("bsd", &detect_bsd),
("cygwin", &detect_cygwin),
("gettext", &have_gettext),
("small_main_stack", &has_small_stack),
// See if libc supports the thread-safe localeconv_l(3) alternative to localeconv(3).
@@ -142,15 +123,6 @@ fn detect_cfgs(target: &mut Target) {
}
}
fn detect_apple(_: &Target) -> Result<bool, Box<dyn Error>> {
Ok(cfg!(any(target_os = "ios", target_os = "macos")))
}
fn detect_cygwin(_: &Target) -> Result<bool, Box<dyn Error>> {
// Cygwin target is usually cross-compiled.
Ok(std::env::var("CARGO_CFG_TARGET_OS").unwrap() == "cygwin")
}
/// Detect if we're being compiled for a BSD-derived OS, allowing targeting code conditionally with
/// `#[cfg(bsd)]`.
///
@@ -227,14 +199,14 @@ fn have_gettext(target: &Target) -> Result<bool, Box<dyn Error>> {
/// 0.5 MiB is small enough that we'd have to drastically reduce MAX_STACK_DEPTH to less than 10, so
/// we instead use a workaround to increase the main thread size.
fn has_small_stack(_: &Target) -> Result<bool, Box<dyn Error>> {
#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "netbsd")))]
#[cfg(not(any(target_os = "macos", target_os = "netbsd")))]
return Ok(false);
// NetBSD 10 also needs this but can't find pthread_get_stacksize_np.
#[cfg(target_os = "netbsd")]
return Ok(true);
#[cfg(any(target_os = "ios", target_os = "macos"))]
#[cfg(target_os = "macos")]
{
use core::ffi;
@@ -255,9 +227,6 @@ fn has_small_stack(_: &Target) -> Result<bool, Box<dyn Error>> {
}
fn setup_paths() {
#[cfg(windows)]
use unix_path::{Path, PathBuf};
fn get_path(name: &str, default: &str, onvar: &Path) -> PathBuf {
let mut var = PathBuf::from(env::var(name).unwrap_or(default.to_string()));
if var.is_relative() {
@@ -325,7 +294,7 @@ fn get_version(src_dir: &Path) -> String {
let path = src_dir.join("version");
if let Ok(strver) = read_to_string(path) {
return strver;
return strver.to_string();
}
let args = &["describe", "--always", "--dirty=-dirty"];
@@ -352,36 +321,17 @@ fn get_version(src_dir: &Path) -> String {
// or because it refused (safe.directory applies to `git describe`!)
// So we read the SHA ourselves.
fn get_git_hash() -> Result<String, Box<dyn std::error::Error>> {
let gitdir = Path::new(MANIFEST_DIR).join(".git");
let jjdir = Path::new(MANIFEST_DIR).join(".jj");
let commit_id = if gitdir.exists() {
// .git/HEAD contains ref: refs/heads/branch
let headpath = gitdir.join("HEAD");
let headstr = read_to_string(headpath)?;
let headref = headstr.split(' ').nth(1).unwrap().trim();
let gitdir = Path::new(env!("CARGO_MANIFEST_DIR")).join(".git");
// .git/refs/heads/branch contains the SHA
let refpath = gitdir.join(headref);
// Shorten to 9 characters (what git describe does currently)
read_to_string(refpath)?
} else if jjdir.exists() {
let output = Command::new("jj")
.args([
"log",
"--revisions",
"@",
"--no-graph",
"--ignore-working-copy",
"--template",
"commit_id",
])
.output()
.unwrap();
String::from_utf8_lossy(&output.stdout).to_string()
} else {
return Err("did not find either of .git or .jj".into());
};
let refstr = &commit_id[0..9];
// .git/HEAD contains ref: refs/heads/branch
let headpath = gitdir.join("HEAD");
let headstr = read_to_string(headpath)?;
let headref = headstr.split(' ').collect::<Vec<_>>()[1].trim();
// .git/refs/heads/branch contains the SHA
let refpath = gitdir.join(headref);
// Shorten to 9 characters (what git describe does currently)
let refstr = &read_to_string(refpath)?[0..9];
let refstr = refstr.trim();
let version = env!("CARGO_PKG_VERSION").to_owned();
@@ -391,14 +341,17 @@ fn get_git_hash() -> Result<String, Box<dyn std::error::Error>> {
get_git_hash().expect("Could not get a version. Either set $FISH_BUILD_VERSION or install git.")
}
#[cfg(feature = "embed-data")]
#[cfg(feature = "installable")]
// disable clippy because otherwise it would panic without sphinx
#[cfg(not(clippy))]
fn build_man(build_dir: &Path) {
use std::process::Command;
let mandir = build_dir;
let sec1dir = mandir.join("man1");
let docsrc_path = canonicalize(MANIFEST_DIR).join("doc_src");
let docsrc_path = std::fs::canonicalize(env!("CARGO_MANIFEST_DIR"))
.unwrap()
.as_path()
.join("doc_src");
let docsrc = docsrc_path.to_str().unwrap();
let args = &[
"-j",
@@ -448,7 +401,10 @@ fn build_man(build_dir: &Path) {
);
}
Ok(out) => {
if !out.success() {
if out.success() {
// Success!
return;
} else {
panic!("sphinx-build failed to build the man pages.");
}
}

View File

@@ -1,54 +0,0 @@
#!/bin/sh
{
set -ex
lint=true
if [ "$FISH_CHECK_LINT" = false ]; then
lint=false
fi
cargo_args=$FISH_CHECK_CARGO_ARGS
target_triple=$FISH_CHECK_TARGET_TRIPLE
if [ -n "$target_triple" ]; then
cargo_args="$cargo_args --target=$FISH_CHECK_TARGET_TRIPLE"
fi
cargo() {
subcmd=$1
shift
# shellcheck disable=2086
command cargo "$subcmd" $cargo_args "$@"
}
cleanup () {
if [ -n "$template_file" ] && [ -e "$template_file" ]; then
rm "$template_file"
fi
}
trap cleanup EXIT INT TERM HUP
if $lint; then
export RUSTFLAGS="--deny=warnings ${RUSTFLAGS}"
export RUSTDOCFLAGS="--deny=warnings ${RUSTDOCFLAGS}"
fi
repo_root="$(dirname "$0")/.."
build_dir="${CARGO_TARGET_DIR:-$repo_root/target}/${target_triple}/debug"
template_file=$(mktemp)
FISH_GETTEXT_EXTRACTION_FILE=$template_file cargo build --workspace --all-targets
if $lint; then
PATH="$build_dir:$PATH" "$repo_root/build_tools/style.fish" --all --check
cargo clippy --workspace --all-targets
fi
cargo test --no-default-features --workspace --all-targets
cargo test --doc --workspace
if $lint; then
cargo doc --workspace
fi
FISH_GETTEXT_EXTRACTION_FILE=$template_file "$repo_root/tests/test_driver.py" "$build_dir"
exit
}

15
build_tools/diff_profiles.fish Executable file → Normal file
View File

@@ -5,13 +5,6 @@
#
# Usage: ./diff_profiles.fish profile1.log profile2.log > profile_diff.log
if test (count $argv) -ne 2
echo "Incorrect number of arguments."
echo "Usage: "(status filename)" profile1.log profile2.log"
exit 1
end
set -l profile1 (cat $argv[1])
set -l profile2 (cat $argv[2])
@@ -22,13 +15,13 @@ while set -l next_line_no (math $line_no + 1) && set -q profile1[$next_line_no]
set -l line1 $profile1[$line_no]
set -l line2 $profile2[$line_no]
if not string match -qr '^\s*\d+\s+\d+' $line1
if not string match -qr '^\d+\t\d+' $line1
echo $line1
continue
end
set -l results1 (string match -r '^\s*(\d+)\s+(\d+)\s+(.*)' $line1)
set -l results2 (string match -r '^\s*(\d+)\s+(\d+)\s+(.*)' $line2)
set -l results1 (string match -r '^(\d+)\t(\d+)\s+(.*)' $line1)
set -l results2 (string match -r '^(\d+)\t(\d+)\s+(.*)' $line2)
# times from both files
set -l time1 $results1[2..3]
@@ -49,5 +42,5 @@ while set -l next_line_no (math $line_no + 1) && set -q profile1[$next_line_no]
set diff[1] (math $time1[1] - $time2[1])
set diff[2] (math $time1[2] - $time2[2])
printf '%10d %10d %s\n' $diff[1] $diff[2] $remainder1
echo $diff[1] $diff[2] $remainder1
end

View File

@@ -1,87 +1,68 @@
#!/usr/bin/env fish
#
# Tool to generate gettext messages template file.
# Writes to stdout.
# Intended to be called from `update_translations.fish`.
# Tool to generate messages.pot
argparse use-existing-template= -- $argv
or exit $status
# Create temporary directory for these operations. OS X `mktemp` is somewhat restricted, so this block
# works around that - based on share/functions/funced.fish.
set -q TMPDIR
or set -l TMPDIR /tmp
set -l tmpdir (mktemp -d $TMPDIR/fish.XXXXXX)
or exit 1
begin
# Write header. This is required by msguniq.
# Note that this results in the file being overwritten.
# This is desired behavior, to get rid of the results of prior invocations
# of this script.
begin
echo 'msgid ""'
echo 'msgstr ""'
echo '"Content-Type: text/plain; charset=UTF-8\n"'
echo ""
end
# This is a gigantic crime.
# xgettext still does not support rust *at all*, so we use cargo-expand to get all our wgettext invocations.
set -l expanded (cargo expand --lib; for f in fish{,_indent,_key_reader}; cargo expand --bin $f; end)
set -g repo_root (status dirname)/..
# Extract any gettext call
set -l strs (printf '%s\n' $expanded | grep -A1 wgettext_static_str |
grep 'widestring::internals::core::primitive::str =' |
string match -rg '"(.*)"' | string match -rv '^%ls$|^$' |
# escaping difference between gettext and cargo-expand: single-quotes
string replace -a "\'" "'" | sort -u)
set -l rust_extraction_file
if set -l --query _flag_use_existing_template
set rust_extraction_file $_flag_use_existing_template
else
set rust_extraction_file (mktemp)
# We need to build to ensure that the proc macro for extracting strings runs.
FISH_GETTEXT_EXTRACTION_FILE=$rust_extraction_file cargo check
or exit 1
end
# Extract any constants
set -a strs (string match -rv 'BUILD_VERSION:|PACKAGE_NAME' -- $expanded |
string match -rg 'const [A-Z_]*: &str = "(.*)"' | string replace -a "\'" "'")
# Get rid of duplicates and sort.
msguniq --no-wrap --strict --sort-output $rust_extraction_file
or exit 1
# We construct messages.pot ourselves instead of forcing this into msgmerge or whatever.
# The escaping so far works out okay.
for str in $strs
# grep -P needed for string escape to be compatible (PCRE-style),
# -H gives the filename, -n the line number.
# If you want to run this on non-GNU grep: Don't.
echo "#:" (grep -PHn -r -- (string escape --style=regex -- $str) src/ |
head -n1 | string replace -r ':\s.*' '')
echo "msgid \"$str\""
echo 'msgstr ""'
end >messages.pot
if not set -l --query _flag_use_existing_template
rm $rust_extraction_file
end
# This regex handles descriptions for `complete` and `function` statements. These messages are not
# particularly important to translate. Hence the "implicit" label.
set -l implicit_regex '(?:^| +)(?:complete|function).*? (?:-d|--description) (([\'"]).+?(?<!\\\\)\\2).*'
function extract_fish_script_messages --argument-names regex
# This regex handles explicit requests to translate a message. These are more important to translate
# than messages which should be implicitly translated.
set -l explicit_regex '.*\( *_ (([\'"]).+?(?<!\\\\)\\2) *\).*'
# Using xgettext causes more trouble than it helps.
# This is due to handling of escaping in fish differing from formats xgettext understands
# (e.g. POSIX shell strings).
# We work around this issue by manually writing the file content.
mkdir -p $tmpdir/implicit/share/completions $tmpdir/implicit/share/functions
mkdir -p $tmpdir/explicit/share/completions $tmpdir/explicit/share/functions
# Steps:
# 1. We extract strings to be translated from the relevant files and drop the rest. This step
# depends on the regex matching the entire line, and the first capture group matching the
# string.
# 2. We unescape. This gets rid of some escaping necessary in fish strings.
# 3. The resulting strings are sorted alphabetically. This step is optional. Not sorting would
# result in strings from the same file appearing together. Removing duplicates is also
# optional, since msguniq takes care of that later on as well.
# 4. Single backslashes are replaced by double backslashes. This results in the backslashes
# being interpreted as literal backslashes by gettext tooling.
# 5. Double quotes are escaped, such that they are not interpreted as the start or end of
# a msgid.
# 6. We transform the string into the format expected in a PO file.
cat $share_dir/config.fish $share_dir/completions/*.fish $share_dir/functions/*.fish |
string replace --filter --regex $regex '$1' |
string unescape |
sort -u |
sed -E -e 's_\\\\_\\\\\\\\_g' -e 's_"_\\\\"_g' -e 's_^(.*)$_msgid "\1"\nmsgstr ""\n_'
end
for f in share/config.fish share/completions/*.fish share/functions/*.fish
# Extract explicit attempts to translate a message. That is, those that are of the form
# `(_ "message")`.
string replace --filter --regex $explicit_regex '$1' <$f | string unescape \
| string replace --all '"' '\\"' | string replace -r '(.*)' 'N_ "$1"' >$tmpdir/explicit/$f
set -g share_dir $repo_root/share
# Handle `complete` / `function` description messages. The `| fish` is subtle. It basically
# avoids the need to use `source` with a command substitution that could affect the current
# shell.
string replace --filter --regex $implicit_regex '$1' <$f | string unescape \
| string replace --all '"' '\\"' | string replace -r '(.*)' 'N_ "$1"' >$tmpdir/implicit/$f
end
# This regex handles explicit requests to translate a message. These are more important to translate
# than messages which should be implicitly translated.
set -l explicit_regex '.*\( *_ (([\'"]).+?(?<!\\\\)\\2) *\).*'
extract_fish_script_messages $explicit_regex
xgettext -j -k -kN_ -LShell --from-code=UTF-8 -cDescription --no-wrap -o messages.pot $tmpdir/{ex,im}plicit/share/*/*.fish
# This regex handles descriptions for `complete` and `function` statements. These messages are not
# particularly important to translate. Hence the "implicit" label.
set -l implicit_regex '^(?:\s|and |or )*(?:complete|function).*? (?:-d|--description) (([\'"]).+?(?<!\\\\)\\2).*'
extract_fish_script_messages $implicit_regex
end |
# At this point, all extracted strings have been written to stdout,
# starting with the ones taken from the Rust sources,
# followed by strings explicitly marked for translation in fish scripts,
# and finally the strings from fish scripts which get translated implicitly.
# Because we do not eliminate duplicates across these categories,
# we do it here, since other gettext tools expect no duplicates.
msguniq --no-wrap
# Remove the tmpdir from the location to avoid churn
sed -i 's_^#: /.*/share/_#: share/_' messages.pot
rm -r $tmpdir

View File

@@ -47,7 +47,7 @@ then
# HACK: Git failed, so we keep the current version file.
# This helps in case you built fish as a normal user
# and then try to `sudo make install` it.
date +%s > "${OUTPUT_DIR}"fish-build-version-witness.txt
date +%s > ${OUTPUT_DIR}fish-build-version-witness.txt
exit 0
fi
@@ -67,4 +67,4 @@ test "$VN" = "$VC" || {
# Output the fish-build-version-witness.txt
# See https://cmake.org/cmake/help/v3.4/policy/CMP0058.html
date +%s > "${OUTPUT_DIR}"fish-build-version-witness.txt
date +%s > ${OUTPUT_DIR}fish-build-version-witness.txt

View File

@@ -1,392 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>platform-application</key>
<true/>
<key>com.apple.private.security.no-container</key>
<true/>
<key>com.apple.private.security.container-manager</key>
<true/>
<key>com.apple.private.skip-library-validation</key>
<true/>
<key>com.apple.private.MobileContainerManager.allowed</key>
<true/>
<key>com.apple.private.security.storage.adprivacyd</key>
<true/>
<key>com.apple.private.security.storage.amfid</key>
<true/>
<key>com.apple.private.security.storage.AppBundles</key>
<true/>
<key>com.apple.private.security.storage.AppDataContainers</key>
<true/>
<key>com.apple.private.security.storage.automation-mode</key>
<true/>
<key>com.apple.private.security.storage.Biome</key>
<true/>
<key>com.apple.private.security.storage.Calendar</key>
<true/>
<key>com.apple.private.security.storage.CallHistory</key>
<true/>
<key>com.apple.private.security.storage.CarrierBundles</key>
<true/>
<key>com.apple.private.security.storage.chronod</key>
<true/>
<key>com.apple.private.security.storage.CloudDocsDB</key>
<true/>
<key>com.apple.private.security.storage.CloudKit</key>
<true/>
<key>com.apple.private.security.storage.containers</key>
<true/>
<key>com.apple.private.security.storage.CoreFollowUp</key>
<true/>
<key>com.apple.private.security.storage.CoreKnowledge</key>
<true/>
<key>com.apple.private.security.storage.Cryptex</key>
<true/>
<key>com.apple.private.security.storage.demo_backup</key>
<true/>
<key>com.apple.private.security.storage.DocumentRevisions</key>
<true/>
<key>com.apple.private.security.storage.DumpPanic</key>
<true/>
<key>com.apple.private.security.storage.ExposureNotification</key>
<true/>
<key>com.apple.private.security.storage.FaceTime</key>
<true/>
<key>com.apple.private.security.storage.familycircled</key>
<true/>
<key>com.apple.private.security.storage.FindMy</key>
<true/>
<key>com.apple.private.security.storage.fpsd</key>
<true/>
<key>com.apple.private.security.storage.Health</key>
<true/>
<key>com.apple.private.security.storage.HomeAI</key>
<true/>
<key>com.apple.private.security.storage.HomeKit</key>
<true/>
<key>com.apple.private.security.storage.iCloudDrive</key>
<true/>
<key>com.apple.private.security.storage.idcredd</key>
<true/>
<key>com.apple.private.security.storage.IdentityServices</key>
<true/>
<key>com.apple.private.security.storage.kbd</key>
<true/>
<key>com.apple.private.security.storage.Keychains</key>
<true/>
<key>com.apple.private.security.storage.Lockdown</key>
<true/>
<key>com.apple.private.security.storage.Mail</key>
<true/>
<key>com.apple.private.security.storage.Messages</key>
<true/>
<key>com.apple.private.security.storage.MessagesMetaData</key>
<true/>
<key>com.apple.private.security.storage.MobileContainerManager</key>
<true/>
<key>com.apple.private.security.storage.MobileDocuments</key>
<true/>
<key>com.apple.private.security.storage.MobileIdentityService</key>
<true/>
<key>com.apple.private.security.storage.mobilesync</key>
<true/>
<key>com.apple.private.security.storage.multimodalsearchd</key>
<true/>
<key>com.apple.private.security.storage.NanoTimeKit.FaceSupport</key>
<true/>
<key>com.apple.private.security.storage.News</key>
<true/>
<key>com.apple.private.security.storage.Notes</key>
<true/>
<key>com.apple.private.security.storage.Photos</key>
<true/>
<key>com.apple.private.security.storage.PhotosLibraries</key>
<true/>
<key>com.apple.private.security.storage.pipelined</key>
<true/>
<key>com.apple.private.security.storage.preferences</key>
<true/>
<key>com.apple.private.security.storage.PrivacyAccounting</key>
<true/>
<key>com.apple.private.security.storage.Safari</key>
<true/>
<key>com.apple.private.security.storage.SearchParty</key>
<true/>
<key>com.apple.private.security.storage.SecureElementService</key>
<true/>
<key>com.apple.private.security.storage.SensorKit</key>
<true/>
<key>com.apple.private.security.storage.SFAnalytics</key>
<true/>
<key>com.apple.private.security.storage.SiriInference</key>
<true/>
<key>com.apple.private.security.storage.SiriReferenceResolution</key>
<true/>
<key>com.apple.private.security.storage.SiriVocabulary</key>
<true/>
<key>com.apple.private.security.storage.SoC</key>
<true/>
<key>com.apple.private.security.storage.SpeechPersonalizedLM</key>
<true/>
<key>com.apple.private.security.storage.Spotlight</key>
<true/>
<key>com.apple.private.security.storage.StatusKit</key>
<true/>
<key>com.apple.private.security.storage.Stocks</key>
<true/>
<key>com.apple.private.security.storage.Suggestions</key>
<true/>
<key>com.apple.private.security.storage.SymptomFramework</key>
<true/>
<key>com.apple.private.security.storage.sysdagnose.ScreenshotServicesService</key>
<true/>
<key>com.apple.private.security.storage.TCC</key>
<true/>
<key>com.apple.private.security.storage.TimeMachine</key>
<true/>
<key>com.apple.private.security.storage.triald</key>
<true/>
<key>com.apple.private.security.storage.trustd</key>
<true/>
<key>com.apple.private.security.storage.trustd-private</key>
<true/>
<key>com.apple.private.security.storage.universalaccess</key>
<true/>
<key>com.apple.private.security.storage.Voicemail</key>
<true/>
<key>com.apple.private.security.storage.Wireless</key>
<true/>
<key>com.apple.private.security.disk-device-access</key>
<true/>
<key>com.apple.rootless.storage.ane_model_cache</key>
<true/>
<key>com.apple.rootless.storage.apfs_boot_mount</key>
<true/>
<key>com.apple.rootless.storage.clientScripter</key>
<true/>
<key>com.apple.rootless.storage.com.apple.mediaanalysisd</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.CarPlayAppBlacklist</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.DeviceCheck</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.DictionaryServices.dictionary2</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.DuetExpertCenterAsset</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.EmbeddedNL</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Font5</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Font6</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.HealthKt.FeatureAvailability</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.HomeKit</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.MacinTalkVoiceAssets</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.MailDynamicData</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.MXLongFormVideoApps</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.network.networknomicon</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.PKITrustSupplementals</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.SharingDeviceAssets</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.SiriShortcutsMobileAsset</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.TimeZoneUpdate</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.VoiceServices.CombinedVocalizerVoices</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.VoiceServices.CustomVoice</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.VoiceServices.GryphonVoice</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.VoiceServicesVocalizerVoice</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.VoiceServices.VoiceResources</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.VoiceTriggerAssets</key>
<true/>
<key>com.apple.rootless.storage.CoreAnalytics</key>
<true/>
<key>com.apple.rootless.storage.coreduet_knowledge_store</key>
<true/>
<key>com.apple.rootless.storage.coreidvd</key>
<true/>
<key>com.apple.rootless.storage.coreknowledge</key>
<true/>
<key>com.apple.rootless.storage.CoreRoutine</key>
<true/>
<key>com.apple.rootless.storage.CoreSpeech</key>
<true/>
<key>com.apple.rootless.storage.dmd</key>
<true/>
<key>com.apple.rootless.storage.dprivacyd_storage</key>
<true/>
<key>com.apple.rootless.storage.ExtensibleSSO</key>
<true/>
<key>com.apple.rootless.storage.facekit</key>
<true/>
<key>com.apple.rootless.storage.fpsd</key>
<true/>
<key>com.apple.rootless.storage.MobileStorageMounter</key>
<true/>
<key>com.apple.rootless.storage.MusicApp</key>
<true/>
<key>com.apple.rootless.storage.nsurlsessiond</key>
<true/>
<key>com.apple.rootless.storage.pearl-field-diagnostics</key>
<true/>
<key>com.apple.rootless.storage.proactivepredictions</key>
<true/>
<key>com.apple.rootless.storage.QLThumbnailCache</key>
<true/>
<key>com.apple.rootless.storage.remotemanagementd</key>
<true/>
<key>com.apple.rootless.storage.RoleAccountStaging</key>
<true/>
<key>com.apple.rootless.storage.sensorkit</key>
<true/>
<key>com.apple.rootless.storage.shortcuts</key>
<true/>
<key>com.apple.rootless.storage.siriremembers</key>
<true/>
<key>com.apple.rootless.storage.timezone</key>
<true/>
<key>com.apple.rootless.storage.triald</key>
<true/>
<key>com.apple.rootless.storage.voiceshortcuts</key>
<true/>
<key>com.apple.private.security.storage-exempt.heritable</key>
<true/>
<key>com.apple.private.security.storage.AppleMediaServices</key>
<true/>
<key>com.apple.private.security.storage.ContactlessReader</key>
<true/>
<key>com.apple.private.security.storage.CoreRoutine</key>
<true/>
<key>com.apple.private.security.storage.DiagnosticReports</key>
<true/>
<key>com.apple.private.security.storage.DiagnosticReports.read-write</key>
<true/>
<key>com.apple.private.security.storage.DoNotDisturb</key>
<true/>
<key>com.apple.private.security.storage.Home</key>
<true/>
<key>com.apple.private.security.storage.IntelligencePlatform</key>
<true/>
<key>com.apple.private.security.storage.Location</key>
<true/>
<key>com.apple.private.security.storage.ManagedConfiguration</key>
<true/>
<key>com.apple.private.security.storage.MapsSync</key>
<true/>
<key>com.apple.private.security.storage.MobileBackup</key>
<true/>
<key>com.apple.private.security.storage.MobileStorageMounter</key>
<true/>
<key>com.apple.private.security.storage.PassKit</key>
<true/>
<key>com.apple.private.security.storage.SiriFeatureStore</key>
<true/>
<key>com.apple.private.security.storage.SiriSELF</key>
<true/>
<key>com.apple.private.security.storage.SoundProfileAsset</key>
<true/>
<key>com.apple.private.security.storage.TextUnderstanding</key>
<true/>
<key>com.apple.private.security.storage.Weather</key>
<true/>
<key>com.apple.private.security.storage.appleaccountd</key>
<true/>
<key>com.apple.private.security.storage.ciconia</key>
<true/>
<key>com.apple.private.security.storage.clipserviced</key>
<true/>
<key>com.apple.private.security.storage.coreduet_knowledge_store</key>
<true/>
<key>com.apple.private.security.storage.driverkitd</key>
<true/>
<key>com.apple.private.security.storage.geoanalyticsd</key>
<true/>
<key>com.apple.private.security.storage.geod</key>
<true/>
<key>com.apple.private.security.storage.launchd</key>
<true/>
<key>com.apple.private.security.storage.sessionkitd</key>
<true/>
<key>com.apple.private.security.storage.sysdiagnose.ScreenshotServicesService</key>
<true/>
<key>com.apple.private.security.storage.sysdiagnose.sysdiagnose</key>
<true/>
<key>com.apple.private.security.storage.tmp</key>
<true/>
<key>com.apple.rootless.critical</key>
<true/>
<key>com.apple.rootless.datavault.metadata</key>
<true/>
<key>com.apple.rootless.install</key>
<true/>
<key>com.apple.rootless.install.heritable</key>
<true/>
<key>com.apple.rootless.restricted-block-devices</key>
<true/>
<key>com.apple.rootless.storage.MobileAssetDownload</key>
<true/>
<key>com.apple.rootless.storage.amsengagementd</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.HealthKit.FeatureAvailability</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriDialogAssets</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriExperienceCam</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriFindMyConfigurationFiles</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriInferredHelpfulness</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriTextToSpeech</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriUnderstandingAsrAssistant</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriUnderstandingAsrHammer</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriUnderstandingAsrUaap</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriUnderstandingAttentionAssets</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriUnderstandingMorphun</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriUnderstandingNL</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriUnderstandingNLOverrides</key>
<true/>
<key>com.apple.rootless.storage.coreparsec_feedbacks</key>
<true/>
<key>com.apple.rootless.storage.coreparsec_uploadables</key>
<true/>
<key>com.apple.rootless.storage.early_boot_mount</key>
<true/>
<key>com.apple.rootless.storage.screentime</key>
<true/>
<key>com.apple.rootless.volume.ISCRecovery</key>
<true/>
<key>com.apple.rootless.volume.Preboot</key>
<true/>
<key>com.apple.rootless.volume.Recovery</key>
<true/>
<key>com.apple.rootless.volume.Update</key>
<true/>
<key>com.apple.rootless.volume.VM</key>
<true/>
<key>com.apple.rootless.volume.iSCPreboot</key>
<true/>
</dict>
</plist>

View File

@@ -1,24 +1,23 @@
#!/usr/bin/env python
"""Command line test driver."""
""" Command line test driver. """
from __future__ import unicode_literals
from __future__ import print_function
import argparse
import asyncio
import datetime
from difflib import SequenceMatcher
import io
import re
import shlex
import subprocess
import sys
import unicodedata
try:
from itertools import zip_longest
except ImportError:
from itertools import izip_longest as zip_longest
from difflib import SequenceMatcher
# Directives can occur at the beginning of a line, or anywhere in a line that does not start with #.
COMMENT_RE = r"^(?:[^#].*)?#\s*"
@@ -33,11 +32,8 @@ CHECK_STDOUT_RE = re.compile(COMMENT_RE + r"CHECK:\s+(.*)\n")
# A regex capturing lines that should be checked against stderr.
CHECK_STDERR_RE = re.compile(COMMENT_RE + r"CHECKERR:\s+(.*)\n")
VARIABLE_OVERRIDE_RE = re.compile(r"\w+=.*")
SKIP = object()
def find_command(program):
import os
@@ -51,7 +47,6 @@ def find_command(program):
return None
class Config(object):
def __init__(self):
# Whether to have verbose output.
@@ -62,7 +57,7 @@ class Config(object):
self.progress = False
def colors(self):
"""Return a dictionary mapping color names to ANSI escapes"""
""" Return a dictionary mapping color names to ANSI escapes """
def ansic(n):
return "\033[%dm" % n if self.colorize else ""
@@ -94,6 +89,9 @@ def output(*args):
print("".join(args) + "\n")
import unicodedata
def esc(m):
map = {
"\n": "\\n",
@@ -130,7 +128,7 @@ class CheckerError(Exception):
class Line(object):
"""A line that remembers where it came from."""
""" A line that remembers where it came from. """
def __init__(self, text, number, file):
self.text = text
@@ -158,7 +156,7 @@ class Line(object):
raise NotImplementedError
def subline(self, text):
"""Return a substring of our line with the given text, preserving number and file."""
""" Return a substring of our line with the given text, preserving number and file. """
return Line(text, self.number, self.file)
@staticmethod
@@ -230,7 +228,7 @@ class TestFailure(object):
if self.signal:
fmtstrs += [
" Process was killed by signal {BOLD}" + self.signal + "{RESET}",
"",
""
]
if self.line and self.check:
fmtstrs += [
@@ -351,7 +349,7 @@ class TestFailure(object):
return "\n".join(fmtstrs).format(**fields)
def print_message(self):
"""Print our message to stdout."""
""" Print our message to stdout. """
print(self.message())
@@ -369,10 +367,7 @@ def perform_substitution(input_str, subs):
text = m.group(1)
for key, replacement in subs_ordered:
if text.startswith(key):
# shell-quote the replacement, so it's usable in #RUN lines.
# We could loosen this and only do it for #RUN/#REQUIRES,
# but so far we don't need it anywhere.
return shlex.quote(replacement + text[len(key) :])
return replacement + text[len(key) :]
# No substitution found, so we default to running it as-is,
# which will end up running it via $PATH.
return text
@@ -380,33 +375,28 @@ def perform_substitution(input_str, subs):
return re.sub(r"%(%|[a-zA-Z0-9_-]+)", subber, input_str)
def runproc(cmd, env=None):
"""Wrapper around subprocess.Popen to save typing"""
return asyncio.run(runproc_async(cmd, env=env))
async def runproc_async(cmd, env=None):
"""Wrapper around subprocess.Popen to save typing"""
PIPE = asyncio.subprocess.PIPE
DEVNULL = asyncio.subprocess.DEVNULL
return await asyncio.create_subprocess_shell(
def runproc(cmd):
""" Wrapper around subprocess.Popen to save typing """
PIPE = subprocess.PIPE
proc = subprocess.Popen(
cmd,
stdin=DEVNULL,
stdin=PIPE,
stdout=PIPE,
stderr=PIPE,
env=env,
shell=True,
close_fds=True, # For Python 2.6 as shipped on RHEL 6
)
return proc
class TestRun(object):
def __init__(self, name, runcmd, checker, subs, config, env=None):
def __init__(self, name, runcmd, checker, subs, config):
self.name = name
self.runcmd = runcmd
self.subbed_command = perform_substitution(runcmd.args, subs)
self.checker = checker
self.subs = subs
self.config = config
self.env = env
def check(self, lines, checks):
# Reverse our lines and checks so we can pop off the end.
@@ -451,7 +441,7 @@ class TestRun(object):
# SCREENFULS of text.
# So we truncate the check list.
if len(usedchecks) > len(usedlines):
usedchecks = usedchecks[: len(usedlines) + 5]
usedchecks = usedchecks[:len(usedlines) + 5]
# Do a SequenceMatch! This gives us a diff-like thing.
diff = SequenceMatcher(a=usedlines, b=usedchecks, autojunk=False)
@@ -479,37 +469,24 @@ class TestRun(object):
return None
def run(self):
"""Run the command. Return a TestFailure, or None."""
return asyncio.run(self.run_async())
async def run_async(self):
"""Run the command. Return a TestFailure, or None."""
""" Run the command. Return a TestFailure, or None. """
def split_by_newlines(s):
"""Decode a string and split it by newlines only,
retaining the newlines.
"""
return [
s + "\n"
for s in s.decode("utf-8", errors="backslashreplace").split("\n")
]
return [s + "\n" for s in s.decode("utf-8").split("\n")]
if self.config.verbose:
print(self.subbed_command)
proc = await runproc_async(self.subbed_command, env=self.env)
stdout, stderr = await proc.communicate()
proc = runproc(self.subbed_command)
stdout, stderr = proc.communicate()
# HACK: This is quite cheesy: POSIX specifies that sh should return 127 for a missing command.
# It's also possible that it'll be returned in other situations,
# most likely when the last command in a shell script doesn't exist.
# So we check if the command *we execute* exists, and complain then.
status = proc.returncode
cmd = next(
(
word
for word in shlex.split(self.subbed_command)
if not VARIABLE_OVERRIDE_RE.match(word)
)
)
cmd = shlex.split(self.subbed_command)[0]
if status == 127 and not find_command(cmd):
raise CheckerError("Command could not be found: " + cmd)
if status == 126 and not find_command(cmd):
@@ -540,7 +517,6 @@ class TestRun(object):
# Process was killed by a signal and failed,
# add a message.
import signal
# Unfortunately strsignal only exists in python 3.8+,
# and signal.signals is 3.5+.
if hasattr(signal, "Signals"):
@@ -643,7 +619,6 @@ class CheckCmd(object):
class Checker(object):
def __init__(self, name, lines):
self.name = name
# Helper to yield subline containing group1 from all matching lines.
def group1s(regex):
for line in lines:
@@ -675,15 +650,8 @@ class Checker(object):
]
def check_file(input_file, name, subs, config, failure_handler, env=None):
"""Check a single file. Return a True on success, False on error."""
return asyncio.run(
check_file_async(input_file, name, subs, config, failure_handler, env=env)
)
async def check_file_async(input_file, name, subs, config, failure_handler, env=None):
"""Check a single file. Return a True on success, False on error."""
def check_file(input_file, name, subs, config, failure_handler):
""" Check a single file. Return a True on success, False on error. """
success = True
lines = Line.readfile(input_file, name)
checker = Checker(name, lines)
@@ -691,8 +659,10 @@ async def check_file_async(input_file, name, subs, config, failure_handler, env=
# Run all the REQUIRES lines first,
# if any of them fail it's a SKIP
for reqcmd in checker.requirecmds:
proc = await runproc_async(perform_substitution(reqcmd.args, subs), env=env)
await proc.communicate()
proc = runproc(
perform_substitution(reqcmd.args, subs)
)
proc.communicate()
if proc.returncode > 0:
return SKIP
@@ -701,22 +671,16 @@ async def check_file_async(input_file, name, subs, config, failure_handler, env=
# Only then run the RUN lines.
for runcmd in checker.runcmds:
failure = await TestRun(
name, runcmd, checker, subs, config, env=env
).run_async()
failure = TestRun(name, runcmd, checker, subs, config).run()
if failure:
failure_handler(failure)
success = False
return success
def check_path(path, subs, config, failure_handler, env=None):
return asyncio.run(check_path_async(path, subs, config, failure_handler, env=env))
async def check_path_async(path, subs, config, failure_handler, env=None):
def check_path(path, subs, config, failure_handler):
with io.open(path, encoding="utf-8") as fd:
return await check_file_async(fd, path, subs, config, failure_handler, env=env)
return check_file(fd, path, subs, config, failure_handler)
def parse_subs(subs):
@@ -741,7 +705,7 @@ def parse_subs(subs):
def get_argparse():
"""Return a littlecheck argument parser."""
""" Return a littlecheck argument parser. """
parser = argparse.ArgumentParser(
description="littlecheck: command line tool tester."
)

View File

@@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
# Helper to notarize an .app.zip or .pkg file.
@@ -13,7 +13,7 @@ for INPUT in "$@"; do
echo "Processing $INPUT"
test -f "$INPUT" || die "Not a file: $INPUT"
ext="${INPUT##*.}"
{ test "$ext" = "zip" || test "$ext" = "pkg"; } || die "Unrecognized extension: $ext"
(test "$ext" = "zip" || test "$ext" = "pkg") || die "Unrecognized extension: $ext"
xcrun notarytool submit "$INPUT" --keychain-profile AC_PASSWORD --wait
@@ -21,7 +21,9 @@ for INPUT in "$@"; do
TMPDIR=$(mktemp -d)
echo "Extracting to $TMPDIR"
unzip -q "$INPUT" -d "$TMPDIR"
STAPLE_TARGET=$(echo "$TMPDIR"/*)
# Force glob expansion.
STAPLE_TARGET="$TMPDIR"/*
STAPLE_TARGET=$(echo $STAPLE_TARGET)
else
STAPLE_TARGET="$INPUT"
fi
@@ -33,7 +35,7 @@ for INPUT in "$@"; do
INPUT_FULL=$(realpath "$INPUT")
rm -f "$INPUT"
cd "$(dirname "$STAPLE_TARGET")"
zip -r -q "$INPUT_FULL" "$(basename "$STAPLE_TARGET")"
zip -r -q "$INPUT_FULL" $(basename "$STAPLE_TARGET")
fi
echo "Processed $INPUT"

177
build_tools/make_macos_pkg.sh Executable file
View File

@@ -0,0 +1,177 @@
#!/usr/bin/env bash
# Script to produce an OS X installer .pkg and .app(.zip)
usage() {
echo "Build macOS packages, optionally signing and notarizing them."
echo "Usage: $0 options"
echo "Options:"
echo " -s Enables code signing"
echo " -f <APP_KEY.p12> Path to .p12 file for application signing"
echo " -i <INSTALLER_KEY.p12> Path to .p12 file for installer signing"
echo " -p <PASSWORD> Password for the .p12 files (necessary to access the certificates)"
echo " -e <entitlements file> (Optional) Path to an entitlements XML file"
echo " -n Enables notarization. This will fail if code signing is not also enabled."
echo " -j <API_KEY.JSON> Path to JSON file generated with \`rcodesign encode-app-store-connect-api-key\` (required for notarization)"
echo
exit 1
}
set -x
set -e
SIGN=
NOTARIZE=
ARM64_DEPLOY_TARGET='MACOSX_DEPLOYMENT_TARGET=11.0'
X86_64_DEPLOY_TARGET='MACOSX_DEPLOYMENT_TARGET=10.9'
# As of this writing, the most recent Rust release supports macOS back to 10.12.
# The first supported version of macOS on arm64 is 10.15, so any Rust is fine for arm64.
# We wish to support back to 10.9 on x86-64; the last version of Rust to support that is
# version 1.73.0.
RUST_VERSION_X86_64=1.70.0
while getopts "sf:i:p:e:nj:" opt; do
case $opt in
s) SIGN=1;;
f) P12_APP_FILE=$(realpath "$OPTARG");;
i) P12_INSTALL_FILE=$(realpath "$OPTARG");;
p) P12_PASSWORD="$OPTARG";;
e) ENTITLEMENTS_FILE=$(realpath "$OPTARG");;
n) NOTARIZE=1;;
j) API_KEY_FILE=$(realpath "$OPTARG");;
\?) usage;;
esac
done
if [ -n "$SIGN" ] && { [ -z "$P12_APP_FILE" ] || [ -z "$P12_INSTALL_FILE" ] || [ -z "$P12_PASSWORD" ]; }; then
usage
fi
if [ -n "$NOTARIZE" ] && [ -z "$API_KEY_FILE" ]; then
usage
fi
VERSION=$(build_tools/git_version_gen.sh --stdout 2>/dev/null)
echo "Version is $VERSION"
PKGDIR=$(mktemp -d)
echo "$PKGDIR"
SRC_DIR=$PWD
OUTPUT_PATH=${FISH_ARTEFACT_PATH:-~/fish_built}
mkdir -p "$PKGDIR/build_x86_64" "$PKGDIR/build_arm64" "$PKGDIR/root" "$PKGDIR/intermediates" "$PKGDIR/dst"
# Build and install for arm64.
# Pass FISH_USE_SYSTEM_PCRE2=OFF because a system PCRE2 on macOS will not be signed by fish,
# and will probably not be built universal, so the package will fail to validate/run on other systems.
# Note CMAKE_OSX_ARCHITECTURES is still relevant for the Mac app.
{ cd "$PKGDIR/build_arm64" \
&& cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_EXE_LINKER_FLAGS="-Wl,-ld_classic" \
-DWITH_GETTEXT=OFF \
-DRust_CARGO_TARGET=aarch64-apple-darwin \
-DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' \
-DFISH_USE_SYSTEM_PCRE2=OFF \
"$SRC_DIR" \
&& env $ARM64_DEPLOY_TARGET make VERBOSE=1 -j 12 \
&& env DESTDIR="$PKGDIR/root/" $ARM64_DEPLOY_TARGET make install;
}
# Build for x86-64 but do not install; instead we will make some fat binaries inside the root.
# Set RUST_VERSION_X86_64 to the last version of Rust that supports macOS 10.9.
{ cd "$PKGDIR/build_x86_64" \
&& cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_EXE_LINKER_FLAGS="-Wl,-ld_classic" \
-DWITH_GETTEXT=OFF \
-DRust_TOOLCHAIN="$RUST_VERSION_X86_64" \
-DRust_CARGO_TARGET=x86_64-apple-darwin \
-DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' \
-DFISH_USE_SYSTEM_PCRE2=OFF "$SRC_DIR" \
&& env $X86_64_DEPLOY_TARGET make VERBOSE=1 -j 12; }
# Fatten them up.
for FILE in "$PKGDIR"/root/usr/local/bin/*; do
X86_FILE="$PKGDIR/build_x86_64/$(basename "$FILE")"
rcodesign macho-universal-create --output "$FILE" "$FILE" "$X86_FILE"
chmod 755 "$FILE"
done
if test -n "$SIGN"; then
echo "Signing executables"
ARGS=(
--p12-file "$P12_APP_FILE"
--p12-password "$P12_PASSWORD"
--code-signature-flags runtime
--for-notarization
)
if [ -n "$ENTITLEMENTS_FILE" ]; then
ARGS+=(--entitlements-xml-file "$ENTITLEMENTS_FILE")
fi
for FILE in "$PKGDIR"/root/usr/local/bin/*; do
(set +x; rcodesign sign "${ARGS[@]}" "$FILE")
done
fi
pkgbuild --scripts "$SRC_DIR/build_tools/osx_package_scripts" --root "$PKGDIR/root/" --identifier 'com.ridiculousfish.fish-shell-pkg' --version "$VERSION" "$PKGDIR/intermediates/fish.pkg"
productbuild --package-path "$PKGDIR/intermediates" --distribution "$SRC_DIR/build_tools/osx_distribution.xml" --resources "$SRC_DIR/build_tools/osx_package_resources/" "$OUTPUT_PATH/fish-$VERSION.pkg"
if test -n "$SIGN"; then
echo "Signing installer"
ARGS=(
--p12-file "$P12_INSTALL_FILE"
--p12-password "$P12_PASSWORD"
--code-signature-flags runtime
--for-notarization
)
(set +x; rcodesign sign "${ARGS[@]}" "$OUTPUT_PATH/fish-$VERSION.pkg")
fi
# Make the app
(cd "$PKGDIR/build_arm64" && env $ARM64_DEPLOY_TARGET make -j 12 fish_macapp)
(cd "$PKGDIR/build_x86_64" && env $X86_64_DEPLOY_TARGET make -j 12 fish_macapp)
# Make the app's /usr/local/bin binaries universal. Note fish.app/Contents/MacOS/fish already is, courtesy of CMake.
cd "$PKGDIR/build_arm64"
for FILE in fish.app/Contents/Resources/base/usr/local/bin/*; do
X86_FILE="$PKGDIR/build_x86_64/fish.app/Contents/Resources/base/usr/local/bin/$(basename "$FILE")"
rcodesign macho-universal-create --output "$FILE" "$FILE" "$X86_FILE"
# macho-universal-create screws up the permissions.
chmod 755 "$FILE"
done
if test -n "$SIGN"; then
echo "Signing app"
ARGS=(
--p12-file "$P12_APP_FILE"
--p12-password "$P12_PASSWORD"
--code-signature-flags runtime
--for-notarization
)
if [ -n "$ENTITLEMENTS_FILE" ]; then
ARGS+=(--entitlements-xml-file "$ENTITLEMENTS_FILE")
fi
(set +x; rcodesign sign "${ARGS[@]}" "fish.app")
fi
cp -R "fish.app" "$OUTPUT_PATH/fish-$VERSION.app"
cd "$OUTPUT_PATH"
# Maybe notarize.
if test -n "$NOTARIZE"; then
echo "Notarizing"
rcodesign notarize --staple --wait --max-wait-seconds 1800 --api-key-file "$API_KEY_FILE" "$OUTPUT_PATH/fish-$VERSION.pkg"
rcodesign notarize --staple --wait --max-wait-seconds 1800 --api-key-file "$API_KEY_FILE" "$OUTPUT_PATH/fish-$VERSION.app"
fi
# Zip it up.
zip -r "fish-$VERSION.app.zip" "fish-$VERSION.app" && rm -Rf "fish-$VERSION.app"
rm -rf "$PKGDIR"

View File

@@ -18,22 +18,22 @@ set -e
BUILD_TOOL="make"
BUILD_GENERATOR="Unix Makefiles"
if command -v ninja >/dev/null; then
BUILD_TOOL="ninja"
BUILD_GENERATOR="Ninja"
BUILD_TOOL="ninja"
BUILD_GENERATOR="Ninja"
fi
# We need GNU tar as that supports the --mtime and --transform options
TAR=notfound
for try in tar gtar gnutar; do
if $try -Pcf /dev/null --mtime now /dev/null >/dev/null 2>&1; then
TAR=$try
break
fi
if $try -Pcf /dev/null --mtime now /dev/null >/dev/null 2>&1; then
TAR=$try
break
fi
done
if [ "$TAR" = "notfound" ]; then
echo 'No suitable tar (supporting --mtime) found as tar/gtar/gnutar in PATH'
exit 1
echo 'No suitable tar (supporting --mtime) found as tar/gtar/gnutar in PATH'
exit 1
fi
# Get the current directory, which we'll use for symlinks
@@ -59,11 +59,11 @@ git archive --format=tar --prefix="$prefix"/ HEAD > "$path"
PREFIX_TMPDIR=$(mktemp -d)
cd "$PREFIX_TMPDIR"
echo "$VERSION" > version
cmake -G "$BUILD_GENERATOR" -DCMAKE_BUILD_TYPE=Debug "$wd"
cmake -G "$BUILD_GENERATOR" "$wd"
$BUILD_TOOL doc
TAR_APPEND="$TAR --append --file=$path --mtime=now --owner=0 --group=0 \
--mode=g+w,a+rX --transform s/^/$prefix\//"
--mode=g+w,a+rX --transform s/^/$prefix\//"
$TAR_APPEND --no-recursion user_doc
$TAR_APPEND user_doc/html user_doc/man
$TAR_APPEND version

View File

@@ -11,15 +11,15 @@ set -e
# We need GNU tar as that supports the --mtime and --transform options
TAR=notfound
for try in tar gtar gnutar; do
if $try -Pcf /dev/null --mtime now /dev/null >/dev/null 2>&1; then
TAR=$try
break
fi
if $try -Pcf /dev/null --mtime now /dev/null >/dev/null 2>&1; then
TAR=$try
break
fi
done
if [ "$TAR" = "notfound" ]; then
echo 'No suitable tar (supporting --mtime) found as tar/gtar/gnutar in PATH'
exit 1
echo 'No suitable tar (supporting --mtime) found as tar/gtar/gnutar in PATH'
exit 1
fi
# Get the current directory, which we'll use for telling Cargo where to find the sources
@@ -45,7 +45,7 @@ cd "$PREFIX_TMPDIR"
mkdir .cargo
cargo vendor --manifest-path "$wd/Cargo.toml" > .cargo/config.toml
tar cfvJ "$path".xz vendor .cargo
tar cfvJ $path.xz vendor .cargo
cd -
rm -r "$PREFIX_TMPDIR"

View File

@@ -8,6 +8,7 @@
code, tt {
font-family: ui-monospace, Menlo, monospace;
}
</style>
</head>
<body>

View File

@@ -4,12 +4,12 @@
if test $# -eq 0
then
echo "usage: $0 shellname [shellname ...]"
echo usage: $0 shellname [shellname ...]
exit 1
fi
scriptname=$(basename "$0")
if [ "$(id -u)" -ne 0 ]; then
scriptname=`basename "$0"`
if [[ $UID -ne 0 ]]; then
echo "${scriptname} must be run as root"
exit 1
fi
@@ -20,7 +20,6 @@ tmpfile=${file}.tmp
set -o noclobber
# shellcheck disable=SC2064
trap "rm -f $tmpfile" EXIT
if ! cat $file > $tmpfile
@@ -33,13 +32,15 @@ EOF
fi
# Append a newline if it doesn't exist
[ -z "$(tail -c1 "$tmpfile")" ] || echo "" >> "$tmpfile"
if [ "$(tail -c1 "$tmpfile"; echo x)" != $'\nx' ]; then
echo "" >> "$tmpfile"
fi
for i
do
if ! grep -q "^${i}$" "$tmpfile"
then
echo "$i" >> "$tmpfile"
echo $i >> "$tmpfile"
fi
done

View File

@@ -1,3 +1,3 @@
#!/bin/sh -x
./add-shell "${DSTVOLUME}"usr/local/bin/fish
./add-shell ${DSTVOLUME}usr/local/bin/fish

View File

@@ -1,7 +1,7 @@
#!/bin/sh -x
echo "Removing any previous installation"
pkgutil --pkg-info "${INSTALL_PKG_SESSION_ID}" && pkgutil --only-files --files "${INSTALL_PKG_SESSION_ID}" | while read -r installed
do rm -v "${DSTVOLUME}${installed}"
pkgutil --pkg-info ${INSTALL_PKG_SESSION_ID} && pkgutil --only-files --files ${INSTALL_PKG_SESSION_ID} | while read installed
do rm -v ${DSTVOLUME}${installed}
done
echo "... removed"

View File

@@ -30,27 +30,20 @@ TIMEOUT_SECS = 5
UNEXPECTED_SUCCESS = object()
# When rendering fish's output, remove the control sequences that modify terminal state,
# to avoid confusing the calling terminal.
# to avoid confusing the calling terminal. No need to replace things like colors and cursor
# movement that are harmless and/or will not leak anyway.
SANITIZE_FOR_PRINTING_RE = re.compile(
r"""
# Filter CSI commands except for colors and cursor movement.
(?!\x1b\[\d*m)
(?!\x1b\[K)
(?!\x1b\[\d*[ABCD])
\x1b\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]
# OSC
| \x1b\].*?\x07
# DCS
| \x1bP.*?\x1b\\
# application keypad mode
\x1b\[\?1004[hl]
| \x1b\[\?2004[hl]
| \x1b\[>4;[10]m
| \x1b\[>5u
| \x1b\[<1u
| \x1b=
| \x1b>
| \x1b\].*?\x07
""",
re.VERBOSE,
)
assert SANITIZE_FOR_PRINTING_RE.sub("", "\x1b[>4;1m") == ""
assert SANITIZE_FOR_PRINTING_RE.sub("", "\x1b[31m") == "\x1b[31m"
re.VERBOSE)
def get_prompt_re(counter):
@@ -162,15 +155,9 @@ class SpawnedProc(object):
before giving up on some expected output.
env: a string->string dictionary, describing the environment variables.
"""
import shlex
if name not in env:
raise ValueError("'%s' variable not found in environment" % name)
exe_path = env.get(name)
# HACK: If there are no args, pexpect will fail if exe_path contains any shell metachars.
# But not if there are args, in which case it probably switches spawning method?
if "args" not in kwargs:
exe_path = shlex.quote(exe_path)
self.colorize = sys.stdout.isatty() or env.get("FISH_FORCE_COLOR", "0") == "1"
self.messages = []
self.start_time = None
@@ -179,8 +166,6 @@ class SpawnedProc(object):
)
self.spawn.delaybeforesend = None
self.prompt_counter = 0
if env.get("TERM") != "dumb":
self.spawn.send("\x1b[?123c") # Primary Device Attribute
def time_since_first_message(self):
"""Return a delta in seconds since the first message, or 0 if this is the first."""
@@ -274,11 +259,7 @@ class SpawnedProc(object):
failtype = pexpect_error_type(err)
# If we get an EOF, we check if the process exited with a signal.
# This shows us e.g. if it crashed
if (
failtype == "EOF"
and self.spawn.signalstatus is not None
and self.spawn.signalstatus != 0
):
if failtype == 'EOF' and self.spawn.signalstatus is not None and self.spawn.signalstatus != 0:
failtype = "SIGNAL " + Signals(self.spawn.signalstatus).name
fmtkeys = {"failtype": failtype, "pat": escape(pat)}
@@ -308,14 +289,12 @@ class SpawnedProc(object):
print("")
print("{CYAN}When written to the tty, this looks like:{RESET}".format(**colors))
print("{CYAN}<-------{RESET}".format(**colors))
sys.stdout.write(SANITIZE_FOR_PRINTING_RE.sub("", self.spawn.before))
sys.stdout.write(SANITIZE_FOR_PRINTING_RE.sub('', self.spawn.before))
sys.stdout.flush()
maybe_nl = ""
maybe_nl=""
if not self.spawn.before.endswith("\n"):
maybe_nl = "\n{CYAN}(no trailing newline)".format(**colors)
print(
"{RESET}{maybe_nl}{CYAN}------->{RESET}".format(maybe_nl=maybe_nl, **colors)
)
maybe_nl="\n{CYAN}(no trailing newline)".format(**colors)
print("{RESET}{maybe_nl}{CYAN}------->{RESET}".format(maybe_nl=maybe_nl, **colors))
print("")
@@ -382,24 +361,22 @@ class SpawnedProc(object):
def control(char: str) -> str:
"""Returns the char sent when control is pressed along the given key."""
""" Returns the char sent when control is pressed along the given key. """
assert len(char) == 1
char = char.lower()
if ord("a") <= ord(char) <= ord("z"):
return chr(ord(char) - ord("a") + 1)
return chr(
{
"@": 0,
"`": 0,
"[": 27,
"{": 27,
"\\": 28,
"|": 28,
"]": 29,
"}": 29,
"^": 30,
"~": 30,
"_": 31,
"?": 127,
}[char]
)
return chr({
"@": 0,
"`": 0,
"[": 27,
"{": 27,
"\\": 28,
"|": 28,
"]": 29,
"}": 29,
"^": 30,
"~": 30,
"_": 31,
"?": 127,
}[char])

104
build_tools/release-notes.sh Executable file
View File

@@ -0,0 +1,104 @@
#!/bin/sh
set -e
workspace_root=$(dirname "$0")/..
relnotes_tmp=$(mktemp -d)
mkdir -p "$relnotes_tmp/fake-workspace" "$relnotes_tmp/out"
(
cd "$workspace_root"
cp -r doc_src CONTRIBUTING.rst README.rst "$relnotes_tmp/fake-workspace"
)
version=$(sed 's,^fish \(\S*\) .*,\1,; 1q' "$workspace_root/CHANGELOG.rst")
previous_version=$(
cd "$workspace_root"
awk <CHANGELOG.rst '
( /^fish \S*\.\S*\.\S* \(released .*\)$/ &&
NR > 1 &&
# Skip tags that have not been created yet..
system("git rev-parse --verify >/dev/null --quiet refs/tags/"$2) == 0 \
) {
print $2; ok = 1; exit
}
END { exit !ok }
'
)
minor_version=${version%.*}
previous_minor_version=${previous_version%.*}
{
sed -n 1,2p <"$workspace_root/CHANGELOG.rst"
ListCommitters() {
comm "$@" "$relnotes_tmp/committers-then" "$relnotes_tmp/committers-now"
}
(
cd "$workspace_root"
git log "$previous_version" --format="%aN" | sort -u >"$relnotes_tmp/committers-then"
git log "$previous_version".. --format="%aN" | sort -u >"$relnotes_tmp/committers-now"
ListCommitters -13 >"$relnotes_tmp/committers-new"
ListCommitters -12 >"$relnotes_tmp/committers-returning"
)
if [ "$minor_version" != "$previous_minor_version" ]; then
(
cd "$workspace_root"
num_commits=$(git log --no-merges --format=%H "$previous_version".. | wc -l)
num_authors=$(wc -l <"$relnotes_tmp/committers-now")
num_new_authors=$(wc -l <"$relnotes_tmp/committers-new")
printf %s \
"This release comprises $num_commits commits since $previous_version," \
" contributed by $num_authors authors, $num_new_authors of which are new committers."
echo
echo
)
fi
printf %s "$(awk <"$workspace_root/CHANGELOG.rst" '
NR <= 2 || /^\.\. ignore / { next }
/^===/ { exit }
{ print }
' | sed '$d')" |
sed -e '$s/^----*$//' # Remove spurious transitions at the end of the document.
if [ "$minor_version" != "$previous_minor_version" ]; then
JoinEscaped() {
sed 's/\S/\\&/g' |
awk '
NR != 1 { printf ",\n" }
{ printf "%s", $0 }
END { printf "\n" }
'
}
echo ""
echo "---"
echo ""
echo "Thanks to everyone who contributed through issue discussions, code reviews, or code changes."
echo
printf "Welcome our new committers: "
JoinEscaped <"$relnotes_tmp/committers-new"
echo
printf "Welcome back our returning committers: "
JoinEscaped <"$relnotes_tmp/committers-returning"
fi
echo
echo "---"
echo
echo "*Download links: To download the source code for fish, we suggest the file named \"fish-$version.tar.xz\". The file downloaded from \"Source code (tar.gz)\" will not build correctly.*"
echo
echo "*The files called fish-$version-linux-\*.tar.xz are experimental packages containing a single standalone ``fish`` binary for any Linux with the given CPU architecture.*"
} >"$relnotes_tmp/fake-workspace"/CHANGELOG.rst
sphinx-build >&2 -j auto \
-W -E -b markdown -c "$workspace_root/doc_src" \
-d "$relnotes_tmp/doctree" "$relnotes_tmp/fake-workspace/doc_src" "$relnotes_tmp/out" \
-D markdown_http_base="https://fishshell.com/docs/$minor_version" \
-D markdown_uri_doc_suffix=".html" \
-D markdown_github_flavored=1 \
"$@"
# Skip changelog header
sed -n 1p "$relnotes_tmp/out/relnotes.md" | grep -Fxq "# Release notes"
sed -n 2p "$relnotes_tmp/out/relnotes.md" | grep -Fxq ''
sed 1,2d "$relnotes_tmp/out/relnotes.md"
rm -r "$relnotes_tmp"

229
build_tools/release.sh Executable file
View File

@@ -0,0 +1,229 @@
#!/bin/sh
{
set -ex
version=$1
repository_owner=fish-shell
remote=origin
if [ -n "$2" ]; then
set -u
repository_owner=$2
remote=$3
set +u
[ $# -eq 3 ]
fi
[ -n "$version" ]
for tool in \
bundle \
gh \
jq \
ruby \
timeout \
; do
if ! command -v "$tool" >/dev/null; then
echo >&2 "$0: missing command: $1"
exit 1
fi
done
repo_root="$(dirname "$0")/.."
fish_site=$repo_root/../fish-site
for path in . "$fish_site"
do
if ! git -C "$path" diff HEAD --quiet ||
git ls-files --others --exclude-standard | grep .; then
echo >&2 "$0: index and worktree must be clean"
exit 1
fi
done
if git tag | grep -qxF "$version"; then
echo >&2 "$0: tag $version already exists"
exit 1
fi
integration_branch=$(
git for-each-ref --points-at=HEAD 'refs/heads/Integration_*' \
--format='%(refname:strip=2)'
)
[ -n "$integration_branch" ] ||
git merge-base --is-ancestor $remote/master HEAD
sed -n 1p CHANGELOG.rst | grep -q '^fish .*(released .*)$'
sed -n 2p CHANGELOG.rst | grep -q '^===*$'
changelog_title="fish $version (released $(date +'%B %d, %Y'))"
sed -i \
-e "1c$changelog_title" \
-e "2c$(printf %s "$changelog_title" | sed s/./=/g)" \
CHANGELOG.rst
CommitVersion() {
sed -i "s/^version = \".*\"/version = \"$1\"/g" Cargo.toml
cargo fetch --offline
git add CHANGELOG.rst Cargo.toml Cargo.lock
git commit -m "$2
Created by ./build_tools/release.sh $version"
}
CommitVersion "$version" "Release $version"
# N.B. this is not GPG-signed.
git tag --annotate --message="Release $version" $version
git push $remote $version
TIMEOUT=
gh() {
command ${TIMEOUT:+timeout $TIMEOUT} \
gh --repo "$repository_owner/fish-shell" "$@"
}
gh workflow run release.yml --ref="$version" \
--raw-field="version=$version"
run_id=
while [ -z "$run_id" ] && sleep 5
do
run_id=$(gh run list \
--json=databaseId --jq=.[].databaseId \
--workflow=release.yml --limit=1 \
--commit="$(git rev-parse "$version^{commit}")")
done
# Update fishshell.com
tag_oid=$(git rev-parse "$version")
tmpdir=$(mktemp -d)
# TODO This works on draft releases only if "gh" is configured to
# have write access to the fish-shell repository. Unless we are fine
# publishing the release at this point, we should at least fail if
# "gh" doesn't have write access.
while ! \
gh release download "$version" --dir="$tmpdir" \
--pattern="fish-$version.tar.xz"
do
TIMEOUT=30 gh run watch "$run_id" ||:
sleep 5
done
actual_tag_oid=$(git ls-remote "$remote" |
awk '$2 == "refs/tags/'"$version"'" { print $1 }')
[ "$tag_oid" = "$actual_tag_oid" ]
( cd "$tmpdir" && tar xf fish-$version.tar.xz )
CopyDocs() {
rm -rf "$fish_site/site/docs/$1"
cp -r "$tmpdir/fish-$version/user_doc/html" "$fish_site/site/docs/$1"
git -C $fish_site add "site/docs/$1"
}
minor_version=${version%.*}
CopyDocs "$minor_version"
latest_release=$(
releases=$(git tag | grep '^[0-9]*\.[0-9]*\.[0-9]*.*' |
sed $(: "De-prioritize release candidates (1.2.3-rc0)") \
's/-/~/g' | LC_ALL=C sort --version-sort)
printf %s\\n "$releases" | tail -1
)
if [ "$version" = "$latest_release" ]; then
CopyDocs current
fi
rm -rf "$tmpdir"
(
cd "$fish_site"
make
git add -u
! git ls-files --others --exclude-standard | grep .
git commit --message="$(printf %s "\
| Release $version (docs)
|
| Created by ../fish-shell/build_tools/release.sh
" | sed 's,^\s*| \?,,')"
)
# Approve macos-codesign
# TODO what if current user can't approve?
gh_pending_deployments() {
command gh api \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/$repository_owner/fish-shell/actions/runs/$run_id/pending_deployments" \
"$@"
}
while {
environment_id=$(gh_pending_deployments | jq .[].environment.id)
[ -z "$environment_id" ]
}
do
sleep 5
done
echo '
{
"environment_ids": ['"$environment_id"'],
"state": "approved",
"comment": "Approved via ./build_tools/release.sh"
}
' |
gh_pending_deployments -XPOST --input=-
# Await completion.
gh run watch "$run_id"
while {
! draft=$(gh release view "$version" --json=isDraft --jq=.isDraft) \
|| [ "$draft" = true ]
}
do
sleep 20
done
(
cd "$fish_site"
make new-release
git add -u
! git ls-files --others --exclude-standard | grep .
git commit --message="$(printf %s "\
| Release $version (release list update)
|
| Created by ../fish-shell/build_tools/release.sh
" | sed 's,^\s*| \?,,')"
# This takes care to support remote names that are different from
# fish-shell remote name. Also, support detached HEAD state.
git push git@github.com:$repository_owner/fish-site HEAD:master
)
if [ -n "$integration_branch" ]; then
git push $remote "$version^{commit}":refs/heads/$integration_branch
else
changelog=$(cat - CHANGELOG.rst <<EOF
fish ?.?.? (released ???)
=========================
EOF
)
printf %s\\n "$changelog" >CHANGELOG.rst
CommitVersion ${version}-snapshot "start new cycle"
git push $remote HEAD:master
fi
# TODO This can currently require a TTY for editing and password
# prompts.
if [ "$repository_owner" = fish-shell ]; then {
mail=$(mktemp)
cat >$mail <<EOF
From: $(git var GIT_AUTHOR_IDENT | sed 's/ [0-9]* +[0-9]*$//')
Subject: fish $version released
See https://github.com/fish-shell/fish-shell/releases/tag/$version
EOF
git send-email --suppress-cc=all --confirm=always $mail \
--to="fish-users Mailing List <fish-users@lists.sourceforge.net>"
rm $mail
} fi
exit
}

View File

@@ -1,53 +1,38 @@
#!/usr/bin/env fish
#
# This runs Python files, fish scripts (*.fish), and Rust files
# through their respective code formatting programs.
# This runs C++ files and fish scripts (*.fish) through their respective code
# formatting programs.
#
# `--all`: Format all eligible files instead of the ones specified as arguments.
# `--check`: Instead of reformatting, fail if a file is not formatted correctly.
# `--force`: Proceed without asking if uncommitted changes are detected.
# Only relevant if `--all` is specified but `--check` is not specified.
set -l fish_files
set -l python_files
set -l rust_files
set -l all no
argparse all check force -- $argv
or exit $status
if set -l -q _flag_all
if test "$argv[1]" = --all
set all yes
if set -q argv[1]
echo "Unexpected arguments: '$argv'"
exit 1
end
set -e argv[1]
end
set -l repo_root (status dirname)/..
if set -q argv[1]
echo "Unexpected arguments: '$argv'"
exit 1
end
if test $all = yes
if not set -l -q _flag_force; and not set -l -q _flag_check
# Potential for false positives: Not all fish files are formatted, see the `fish_files`
# definition below.
set -l relevant_uncommitted_changes (git status --porcelain --short --untracked-files=all | sed -e 's/^ *[^ ]* *//' | grep -E '.*\.(fish|py|rs)$')
if set -q relevant_uncommitted_changes[1]
for changed_file in $relevant_uncommitted_changes
echo $changed_file
end
echo
echo 'You have uncommitted changes (listed above). Are you sure you want to restyle?'
read -P 'y/N? ' -n1 -l ans
if not string match -qi y -- $ans
exit 1
end
set -l files (git status --porcelain --short --untracked-files=all | sed -e 's/^ *[^ ]* *//')
if set -q files[1]
echo
echo 'You have uncommitted changes. Are you sure you want to restyle?'
read -P 'y/N? ' -n1 -l ans
if not string match -qi y -- $ans
exit 1
end
end
set fish_files $repo_root/{benchmarks,build_tools,etc,share}/**.fish
set fish_files share/**.fish
set python_files {doc_src,share,tests}/**.py
set rust_files fish-rust/src/**.rs
else
# Format the files specified as arguments.
set -l files $argv
# Extract just the fish files.
set fish_files (string match -r '^.*\.fish$' -- $files)
set python_files (string match -r '^.*\.py$' -- $files)
set rust_files (string match -r '^.*\.rs$' -- $files)
@@ -55,70 +40,37 @@ end
set -l red (set_color red)
set -l green (set_color green)
set -l yellow (set_color yellow)
set -l blue (set_color blue)
set -l normal (set_color normal)
# Run the fish reformatter if we have any fish files.
if set -q fish_files[1]
if not type -q fish_indent
echo
echo $yellow'Could not find `fish_indent` in `$PATH`.'$normal
exit 127
make fish_indent
set PATH . $PATH
end
echo === Running "$green"fish_indent"$normal"
if set -l -q _flag_check
if not fish_indent --check -- $fish_files
echo $red"Fish files are not formatted correctly."$normal
exit 1
end
else
fish_indent -w -- $fish_files
end
fish_indent -w -- $fish_files
end
if set -q python_files[1]
if not type -q black
echo
echo $yellow'Please install `black` to style python'$normal
exit 127
end
echo === Running "$green"black"$normal"
if set -l -q _flag_check
if not black --check $python_files
echo $red"Python files are not formatted correctly."$normal
exit 1
end
echo Please install "`black`" to style python
echo
else
echo === Running "$blue"black"$normal"
black $python_files
end
end
if not cargo fmt --version >/dev/null
echo
echo $yellow'Please install "rustfmt" to style Rust, e.g. via:'
echo "rustup component add rustfmt"$normal
exit 127
end
echo === Running "$green"rustfmt"$normal"
if set -l -q _flag_check
if set -l -q _flag_all
if not cargo fmt --check
echo $red"Rust files are not formatted correctly."$normal
exit 1
end
if set -q rust_files[1]
if not type -q rustfmt
echo
echo Please install "`rustfmt`" to style rust
echo
else
if set -q rust_files[1]
if not rustfmt --check --files-with-diff $rust_files
echo $red"Rust files are not formatted correctly."
exit 1
end
end
end
else
if set -l -q _flag_all
cargo fmt
else
if set -q rust_files[1]
rustfmt $rust_files
end
echo === Running "$blue"rustfmt"$normal"
rustfmt $rust_files
end
end

View File

@@ -1,145 +0,0 @@
#!/usr/bin/env fish
# Updates the files used for gettext translations.
# By default, the whole xgettext, msgmerge, msgfmt pipeline runs,
# which extracts the messages from the source files into $template_file,
# updates the PO files for each language from that
# (changed line numbers, added messages, removed messages),
# and finally generates a machine-readable MO file for each language,
# which is stored in share/locale/$LANG/LC_MESSAGES/fish.mo (relative to the repo root).
#
# Use cases:
# For developers:
# - Run with args `--no-mo` to update all PO files after making changes to Rust/fish
# sources.
# For translators:
# - Run with `--no-mo` first, to ensure that the strings you are translating are up to date.
# - Specify the language you want to work on as an argument, which must be a file in the po/
# directory. You can specify a language which does not have translations yet by specifying the
# name of a file which does not yet exist. Make sure to follow the naming convention.
# For testing:
# - Specify `--dry-run` to see if any updates to the PO files would by applied by this script.
# If this flag is specified, the script will exit with an error if there are outstanding
# changes, and will display the diff. Do not specify other flags if `--dry-run` is specified.
#
# Specify `--use-existing-template=FILE` to prevent running cargo for extracting an up-to-date
# version of the localized strings. This flag is intended for testing setups which make it
# inconvenient to run cargo here, but run it in an earlier step to ensure up-to-date values.
# This argument is passed on to the `fish_xgettext.fish` script and has no other uses.
# `FILE` must be the path to a gettext template file generated from our compilation process.
# It can be obtained by running:
# set -l FILE (mktemp)
# FISH_GETTEXT_EXTRACTION_FILE=$FILE cargo check
# The sort utility is locale-sensitive.
# Ensure that sorting output is consistent by setting LC_ALL here.
set -gx LC_ALL C.UTF-8
set -l build_tools (status dirname)
set -g tmpdir
set -l po_dir $build_tools/../po
set -l extract
set -l po
set -l mo
argparse --exclusive 'no-mo,only-mo,dry-run' no-mo only-mo dry-run use-existing-template= -- $argv
or exit $status
if test -z $argv[1]
# Update everything if not specified otherwise.
set -g po_files $po_dir/*.po
else
set -l po_dir_id (stat --format='%d:%i' -- $po_dir)
for arg in $argv
set -l arg_dir_id (stat --format='%d:%i' -- (dirname $arg))
if test $po_dir_id != $arg_dir_id
echo "Argument $arg is not a file in the directory $(realpath $po_dir)."
echo "Non-option arguments must specify paths to files in this directory."
echo ""
echo "If you want to add a new language to the translations not the following:"
echo "The filename must identify a language, with a two letter ISO 639-1 language code of the target language (e.g. 'pt' for Portuguese), and use the file extension '.po'."
echo "Optionally, you can specify a regional variant (e.g. 'pt_BR')."
echo "So valid filenames are of the shape 'll.po' or 'll_CC.po'."
exit 1
end
if not basename $arg | grep -qE '^[a-z]{2}(_[A-Z]{2})?\.po$'
echo "Filename does not match the expected format ('ll.po' or 'll_CC.po')."
exit 1
end
end
set -g po_files $argv
end
if set -l --query _flag_no_mo
set -l --erase mo
end
if set -l --query _flag_only_mo
set -l --erase extract
set -l --erase po
end
set -g template_file (mktemp)
# Protect from externally set $tmpdir leaking into this script.
set -g tmpdir
function cleanup_exit
set -l exit_status $status
rm $template_file
if set -g --query tmpdir[1]
rm -r $tmpdir
end
exit $exit_status
end
if set -l --query extract
set -l xgettext_args
if set -l --query _flag_use_existing_template
set xgettext_args --use-existing-template=$_flag_use_existing_template
end
$build_tools/fish_xgettext.fish $xgettext_args >$template_file
or cleanup_exit
end
if set -l --query _flag_dry_run
# On a dry run, we do not modify po/ but write to a temporary directory instead and check if
# there is a difference between po/ and the tmpdir after re-generating the PO files.
set -g tmpdir (mktemp -d)
# On a dry-run, we do not update the MO files.
set -l --erase mo
# Ensure tmpdir has the same initial state as the po dir.
cp -r $po_dir/* $tmpdir
end
for po_file in $po_files
if set --query tmpdir[1]
set po_file $tmpdir/(basename $po_file)
end
if set -l --query po
if test -e $po_file
msgmerge --no-wrap --update --no-fuzzy-matching --backup=none --quiet $po_file $template_file
and msgattrib --no-wrap --no-obsolete -o $po_file $po_file
or cleanup_exit
else
cp $template_file $po_file
end
end
if set -l --query mo
set -l locale_dir $build_tools/../share/locale
set -l out_dir $locale_dir/(basename $po_file .po)/LC_MESSAGES
mkdir -p $out_dir
msgfmt --check-format --output-file=$out_dir/fish.mo $po_file
end
end
if set -g --query tmpdir[1]
diff -ur $po_dir $tmpdir
or cleanup_exit
end
cleanup_exit

View File

@@ -29,7 +29,7 @@ add_custom_target(sphinx-docs
# sphinx-manpages needs the fish_indent binary for the version number
add_custom_target(sphinx-manpages
env FISH_BUILD_VERSION_FILE=${CMAKE_CURRENT_BINARY_DIR}/${FBVF}
env FISH_BUILD_VERSION_FILE="${CMAKE_CURRENT_BINARY_DIR}/${FBVF}"
${SPHINX_EXECUTABLE}
-j auto
-q -b man

View File

@@ -1,18 +1,286 @@
#[=======================================================================[.rst:
FindRust
--------
Find Rust
This module finds an installed rustc compiler and the cargo build tool. If Rust
is managed by rustup it determines the available toolchains and returns a
concrete Rust version, not a rustup proxy.
Imported from Corrosion https://github.com/corrosion-rs/corrosion/
Copyright (c) 2018 Andrew Gaspar
Licensed under the MIT license
However this is absolutely gutted and reduced to the bare minimum.
#]=======================================================================]
include(FindPackageHandleStandardArgs)
cmake_minimum_required(VERSION 3.12)
# search for Cargo here and set up a bunch of cool flags and stuff
include(FindPackageHandleStandardArgs)
list(APPEND CMAKE_MESSAGE_CONTEXT "FindRust")
# Print error message and return.
macro(_findrust_failed)
if("${Rust_FIND_REQUIRED}")
message(FATAL_ERROR ${ARGN})
elseif(NOT "${Rust_FIND_QUIETLY}")
message(WARNING ${ARGN})
endif()
# Note: PARENT_SCOPE is the scope of the caller of the caller of this macro.
set(Rust_FOUND "" PARENT_SCOPE)
return()
endmacro()
# Checks if the actual version of a Rust toolchain matches the VERSION requirements specified in find_package.
function(_findrust_version_ok ACTUAL_VERSION OUT_IS_OK)
if(DEFINED Rust_FIND_VERSION_RANGE)
if(Rust_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE")
set(COMPARSION_OPERATOR "VERSION_LESS_EQUAL")
elseif(Rust_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE")
set(COMPARSION_OPERATOR "VERSION_LESS")
else()
message(FATAL_ERROR "Unexpected value in `<PackageName>_FIND_VERSION_RANGE_MAX`: "
"`${Rust_FIND_VERSION_RANGE_MAX}`.")
endif()
if(("${ACTUAL_VERSION}" VERSION_GREATER_EQUAL "${Rust_FIND_VERSION_RANGE_MIN}")
AND
( "${ACTUAL_VERSION}" ${COMPARSION_OPERATOR} "${Rust_FIND_VERSION_RANGE_MAX}" )
)
set("${OUT_IS_OK}" TRUE PARENT_SCOPE)
else()
set("${OUT_IS_OK}" FALSE PARENT_SCOPE)
endif()
elseif(DEFINED Rust_FIND_VERSION)
if(Rust_VERSION_EXACT)
set(COMPARISON_OPERATOR VERSION_EQUAL)
else()
set(COMPARISON_OPERATOR VERSION_GREATER_EQUAL)
endif()
if(_TOOLCHAIN_${_TOOLCHAIN_SELECTED}_VERSION "${COMPARISON_OPERATOR}" Rust_FIND_VERSION)
set("${OUT_IS_OK}" TRUE PARENT_SCOPE)
else()
set("${OUT_IS_OK}" FALSE PARENT_SCOPE)
endif()
else()
# if no VERSION requirement was specified, the version is always okay.
set("${OUT_IS_OK}" TRUE PARENT_SCOPE)
endif()
endfunction()
function(_corrosion_strip_target_triple input_triple_or_path output_triple)
# If the target_triple is a path to a custom target specification file, then strip everything
# except the filename from `target_triple`.
get_filename_component(target_triple_ext "${input_triple_or_path}" EXT)
set(target_triple "${input_triple_or_path}")
if(target_triple_ext)
if(target_triple_ext STREQUAL ".json")
get_filename_component(target_triple "${input_triple_or_path}" NAME_WE)
endif()
endif()
set(${output_triple} "${target_triple}" PARENT_SCOPE)
endfunction()
function(_corrosion_parse_target_triple target_triple out_arch out_vendor out_os out_env)
_corrosion_strip_target_triple(${target_triple} target_triple)
# The vendor part may be left out from the target triple, and since `env` is also optional,
# we determine if vendor is present by matching against a list of known vendors.
set(known_vendors
"apple"
"esp[a-z0-9]*" # espressif, e.g. riscv32imc-esp-espidf or xtensa-esp32s3-none-elf
"fortanix"
"kmc"
"pc"
"nintendo"
"nvidia"
"openwrt"
"alpine"
"chimera"
"unikraft"
"unknown"
"uwp" # aarch64-uwp-windows-msvc
"wrs" # e.g. aarch64-wrs-vxworks
"sony"
"sun"
)
# todo: allow users to add additional vendors to the list via a cmake variable.
list(JOIN known_vendors "|" known_vendors_joined)
# vendor is optional - We detect if vendor is present by matching against a known list of
# vendors. The next field is the OS, which we assume to always be present, while the last field
# is again optional and contains the environment.
string(REGEX MATCH
"^([a-z0-9_\.]+)-((${known_vendors_joined})-)?([a-z0-9_]+)(-([a-z0-9_]+))?$"
whole_match
"${target_triple}"
)
if((NOT whole_match) AND (NOT CORROSION_NO_WARN_PARSE_TARGET_TRIPLE_FAILED))
message(WARNING "Failed to parse target-triple `${target_triple}`."
"Corrosion determines some information about the output artifacts based on OS "
"specified in the Rust target-triple.\n"
"Currently this is relevant for windows and darwin (mac) targets, since file "
"extensions differ.\n"
"Note: If you are targeting a different OS you can suppress this warning by"
" setting the CMake cache variable "
"`CORROSION_NO_WARN_PARSE_TARGET_TRIPLE_FAILED`."
"Please consider opening an issue on github if you you need to add a new vendor to the list."
)
endif()
message(DEBUG "Parsed Target triple: arch: ${CMAKE_MATCH_1}, vendor: ${CMAKE_MATCH_3}, "
"OS: ${CMAKE_MATCH_4}, env: ${CMAKE_MATCH_6}")
set("${out_arch}" "${CMAKE_MATCH_1}" PARENT_SCOPE)
set("${out_vendor}" "${CMAKE_MATCH_3}" PARENT_SCOPE)
set("${out_os}" "${CMAKE_MATCH_4}" PARENT_SCOPE)
set("${out_env}" "${CMAKE_MATCH_6}" PARENT_SCOPE)
endfunction()
function(_corrosion_determine_libs_new target_triple out_libs)
set(package_dir "${CMAKE_BINARY_DIR}/corrosion/required_libs")
# Cleanup on reconfigure to get a cleans state (in case we change something in the future)
file(REMOVE_RECURSE "${package_dir}")
file(MAKE_DIRECTORY "${package_dir}")
set(manifest "[package]\nname = \"required_libs\"\nedition = \"2018\"\nversion = \"0.1.0\"\n")
string(APPEND manifest "\n[lib]\ncrate-type=[\"staticlib\"]\npath = \"lib.rs\"\n")
string(APPEND manifest "\n[workspace]\n")
file(WRITE "${package_dir}/Cargo.toml" "${manifest}")
file(WRITE "${package_dir}/lib.rs" "pub fn add(left: usize, right: usize) -> usize {left + right}\n")
execute_process(
COMMAND ${CMAKE_COMMAND} -E env
"CARGO_BUILD_RUSTC=${Rust_COMPILER_CACHED}"
${Rust_CARGO_CACHED} rustc --verbose --color never --target=${target_triple} -- --print=native-static-libs
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/corrosion/required_libs"
RESULT_VARIABLE cargo_build_result
ERROR_VARIABLE cargo_build_error_message
)
if(cargo_build_result)
message(DEBUG "Determining required native libraries - failed: ${cargo_build_result}.")
message(TRACE "The cargo build error was: ${cargo_build_error_message}")
message(DEBUG "Note: This is expected for Rust targets without std support")
return()
else()
# The pattern starts with `native-static-libs:` and goes to the end of the line.
if(cargo_build_error_message MATCHES "native-static-libs: ([^\r\n]+)\r?\n")
string(REPLACE " " ";" "libs_list" "${CMAKE_MATCH_1}")
set(stripped_lib_list "")
set(was_last_framework OFF)
foreach(lib ${libs_list})
# merge -framework;lib -> "-framework lib" as CMake does de-duplication of link libraries, and -framework prefix is required
if (lib STREQUAL "-framework")
set(was_last_framework ON)
continue()
endif()
if (was_last_framework)
list(APPEND stripped_lib_list "-framework ${lib}")
set(was_last_framework OFF)
continue()
endif()
# Strip leading `-l` (unix) and potential .lib suffix (windows)
string(REGEX REPLACE "^-l" "" "stripped_lib" "${lib}")
string(REGEX REPLACE "\.lib$" "" "stripped_lib" "${stripped_lib}")
list(APPEND stripped_lib_list "${stripped_lib}")
endforeach()
set(libs_list "${stripped_lib_list}")
# Special case `msvcrt` to link with the debug version in Debug mode.
list(TRANSFORM libs_list REPLACE "^msvcrt$" "\$<\$<CONFIG:Debug>:msvcrtd>")
else()
message(DEBUG "Determining required native libraries - failed: Regex match failure.")
message(DEBUG "`native-static-libs` not found in: `${cargo_build_error_message}`")
return()
endif()
endif()
set("${out_libs}" "${libs_list}" PARENT_SCOPE)
endfunction()
if (NOT "${Rust_TOOLCHAIN}" STREQUAL "$CACHE{Rust_TOOLCHAIN}")
# Promote Rust_TOOLCHAIN to a cache variable if it is not already a cache variable
set(Rust_TOOLCHAIN ${Rust_TOOLCHAIN} CACHE STRING "Requested rustup toolchain" FORCE)
endif()
set(_RESOLVE_RUSTUP_TOOLCHAINS_DESC "Indicates whether to descend into the toolchain pointed to by rustup")
set(Rust_RESOLVE_RUSTUP_TOOLCHAINS ON CACHE BOOL ${_RESOLVE_RUSTUP_TOOLCHAINS_DESC})
# This block checks to see if we're prioritizing a rustup-managed toolchain.
if (DEFINED Rust_TOOLCHAIN)
# If the user specifies `Rust_TOOLCHAIN`, then look for `rustup` first, rather than `rustc`.
find_program(Rust_RUSTUP rustup PATHS "$ENV{HOME}/.cargo/bin")
if(NOT Rust_RUSTUP)
if(NOT "${Rust_FIND_QUIETLY}")
message(
WARNING "CMake variable `Rust_TOOLCHAIN` specified, but `rustup` was not found. "
"Ignoring toolchain and looking for a Rust toolchain not managed by rustup.")
endif()
endif()
else()
# If we aren't definitely using a rustup toolchain, look for rustc first - the user may have
# a toolchain installed via a method other than rustup higher in the PATH, which should be
# preferred. However, if the first-found rustc is a rustup proxy, then we'll revert to
# finding the preferred toolchain via rustup.
# Uses `Rust_COMPILER` to let user-specified `rustc` win. But we will still "override" the
# user's setting if it is pointing to `rustup`. Default rustup install path is provided as a
# backup if a toolchain cannot be found in the user's PATH.
if (DEFINED Rust_COMPILER)
set(_Rust_COMPILER_TEST "${Rust_COMPILER}")
set(_USER_SPECIFIED_RUSTC ON)
if(NOT (EXISTS "${_Rust_COMPILER_TEST}" AND NOT IS_DIRECTORY "${_Rust_COMPILER_TEST}"))
set(_ERROR_MESSAGE "Rust_COMPILER was set to `${Rust_COMPILER}`, but this file does "
"not exist."
)
_findrust_failed(${_ERROR_MESSAGE})
return()
endif()
else()
find_program(_Rust_COMPILER_TEST rustc PATHS "$ENV{HOME}/.cargo/bin")
if(NOT EXISTS "${_Rust_COMPILER_TEST}")
set(_ERROR_MESSAGE "`rustc` not found in PATH or `$ENV{HOME}/.cargo/bin`.\n"
"Hint: Check if `rustc` is in PATH or manually specify the location "
"by setting `Rust_COMPILER` to the path to `rustc`.")
_findrust_failed(${_ERROR_MESSAGE})
endif()
endif()
# Check if the discovered rustc is actually a "rustup" proxy.
execute_process(
COMMAND
${CMAKE_COMMAND} -E env
RUSTUP_FORCE_ARG0=rustup
"${_Rust_COMPILER_TEST}" --version
OUTPUT_VARIABLE _RUSTC_VERSION_RAW
ERROR_VARIABLE _RUSTC_VERSION_STDERR
RESULT_VARIABLE _RUSTC_VERSION_RESULT
)
if(NOT (_RUSTC_VERSION_RESULT EQUAL "0"))
_findrust_failed("`${_Rust_COMPILER_TEST} --version` failed with ${_RUSTC_VERSION_RESULT}\n"
"rustc stderr:\n${_RUSTC_VERSION_STDERR}"
)
endif()
if (_RUSTC_VERSION_RAW MATCHES "rustup [0-9\\.]+")
# Get `rustup` next to the `rustc` proxy
get_filename_component(_RUST_PROXIES_PATH "${_Rust_COMPILER_TEST}" DIRECTORY)
find_program(Rust_RUSTUP rustup HINTS "${_RUST_PROXIES_PATH}" NO_DEFAULT_PATH)
endif()
unset(_Rust_COMPILER_TEST CACHE)
endif()
# At this point, the only thing we should have evaluated is a path to `rustup` _if that's what the
# best source for a Rust toolchain was determined to be_.
if (NOT Rust_RUSTUP)
set(Rust_RESOLVE_RUSTUP_TOOLCHAINS OFF CACHE BOOL ${_RESOLVE_RUSTUP_TOOLCHAINS_DESC} FORCE)
endif()
# List of user variables that will override any toolchain-provided setting
set(_Rust_USER_VARS Rust_COMPILER Rust_CARGO Rust_CARGO_TARGET)
set(_Rust_USER_VARS Rust_COMPILER Rust_CARGO Rust_CARGO_TARGET Rust_CARGO_HOST_TARGET)
foreach(_VAR ${_Rust_USER_VARS})
if (DEFINED "${_VAR}")
set(${_VAR}_CACHED "${${_VAR}}" CACHE INTERNAL "Internal cache of ${_VAR}")
@@ -21,55 +289,487 @@ foreach(_VAR ${_Rust_USER_VARS})
endif()
endforeach()
if (NOT DEFINED Rust_CARGO_CACHED)
find_program(Rust_CARGO_CACHED cargo PATHS "$ENV{HOME}/.cargo/bin")
endif()
# Discover what toolchains are installed by rustup, if the discovered `rustc` is a proxy from
# `rustup` and the user hasn't explicitly requested to override this behavior, then select either
# the default toolchain, or the requested toolchain Rust_TOOLCHAIN
if (Rust_RESOLVE_RUSTUP_TOOLCHAINS)
execute_process(
COMMAND
"${Rust_RUSTUP}" toolchain list --verbose
OUTPUT_VARIABLE _TOOLCHAINS_RAW
)
if (NOT EXISTS "${Rust_CARGO_CACHED}")
message(FATAL_ERROR "The cargo executable ${Rust_CARGO_CACHED} was not found. "
"Consider setting `Rust_CARGO_CACHED` to the absolute path of `cargo`."
)
endif()
string(REPLACE "\n" ";" _TOOLCHAINS_RAW "${_TOOLCHAINS_RAW}")
set(_DISCOVERED_TOOLCHAINS "")
set(_DISCOVERED_TOOLCHAINS_RUSTC_PATH "")
set(_DISCOVERED_TOOLCHAINS_CARGO_PATH "")
set(_DISCOVERED_TOOLCHAINS_VERSION "")
if (NOT DEFINED Rust_COMPILER_CACHED)
find_program(Rust_COMPILER_CACHED rustc PATHS "$ENV{HOME}/.cargo/bin")
endif()
foreach(_TOOLCHAIN_RAW ${_TOOLCHAINS_RAW})
# We're going to try to parse the output of `rustup toolchain list --verbose`.
# We expect output like this:
# stable-random-toolchain-junk (parenthesized-random-stuff-like-active-or-default) /path/to/toolchain/blah/more-blah
# In the following regex, we capture the toolchain name, any parenthesized stuff, and then the path.
message(STATUS "Parsing toolchain: ${_TOOLCHAIN_RAW}")
if (_TOOLCHAIN_RAW MATCHES "([^\t ]+)[\t ]*(\\(.*\\))?[\t ]*(.+)")
set(_TOOLCHAIN "${CMAKE_MATCH_1}")
set(_TOOLCHAIN_TYPE "${CMAKE_MATCH_2}")
set(_TOOLCHAIN_PATH "${CMAKE_MATCH_3}")
set(_TOOLCHAIN_${_TOOLCHAIN}_PATH "${CMAKE_MATCH_3}")
if (_TOOLCHAIN_TYPE MATCHES "default")
set(_TOOLCHAIN_DEFAULT "${_TOOLCHAIN}")
endif()
if (_TOOLCHAIN_TYPE MATCHES "override")
set(_TOOLCHAIN_OVERRIDE "${_TOOLCHAIN}")
endif()
execute_process(
COMMAND
"${_TOOLCHAIN_PATH}/bin/rustc" --version
OUTPUT_VARIABLE _TOOLCHAIN_RAW_VERSION
)
if (_TOOLCHAIN_RAW_VERSION MATCHES "rustc ([0-9]+)\\.([0-9]+)\\.([0-9]+)(-nightly)?")
list(APPEND _DISCOVERED_TOOLCHAINS "${_TOOLCHAIN}")
list(APPEND _DISCOVERED_TOOLCHAINS_RUSTC_PATH "${_TOOLCHAIN_PATH}/bin/rustc")
list(APPEND _DISCOVERED_TOOLCHAINS_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}")
# We need this variable to determine the default toolchain, since `foreach(... IN ZIP_LISTS ...)`
# requires CMake 3.17. As a workaround we define this variable to lookup the version when iterating
# through the `_DISCOVERED_TOOLCHAINS` lists.
set(_TOOLCHAIN_${_TOOLCHAIN}_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}")
if(CMAKE_MATCH_4)
set(_TOOLCHAIN_${_TOOLCHAIN}_IS_NIGHTLY "TRUE")
else()
set(_TOOLCHAIN_${_TOOLCHAIN}_IS_NIGHTLY "FALSE")
endif()
if(EXISTS "${_TOOLCHAIN_PATH}/bin/cargo")
list(APPEND _DISCOVERED_TOOLCHAINS_CARGO_PATH "${_TOOLCHAIN_PATH}/bin/cargo")
else()
list(APPEND _DISCOVERED_TOOLCHAINS_CARGO_PATH "NOTFOUND")
endif()
else()
message(AUTHOR_WARNING "Unexpected output from `rustc --version` for Toolchain `${_TOOLCHAIN}`: "
"`${_TOOLCHAIN_RAW_VERSION}`.\n"
"Ignoring this toolchain."
)
endif()
else()
message(AUTHOR_WARNING "Didn't recognize toolchain: ${_TOOLCHAIN_RAW}. Ignoring this toolchain.\n"
"Rustup toolchain list output( `${Rust_RUSTUP} toolchain list --verbose`):\n"
"${_TOOLCHAINS_RAW}"
)
endif()
endforeach()
# Expose a list of available rustup toolchains.
list(LENGTH _DISCOVERED_TOOLCHAINS _toolchain_len)
list(LENGTH _DISCOVERED_TOOLCHAINS_RUSTC_PATH _toolchain_rustc_len)
list(LENGTH _DISCOVERED_TOOLCHAINS_CARGO_PATH _toolchain_cargo_len)
list(LENGTH _DISCOVERED_TOOLCHAINS_VERSION _toolchain_version_len)
if(NOT
(_toolchain_len EQUAL _toolchain_rustc_len
AND _toolchain_cargo_len EQUAL _toolchain_version_len
AND _toolchain_len EQUAL _toolchain_cargo_len)
)
message(FATAL_ERROR "Internal error - list length mismatch."
"List lengths: ${_toolchain_len} toolchains, ${_toolchain_rustc_len} rustc, ${_toolchain_cargo_len} cargo,"
" ${_toolchain_version_len} version. The lengths should be the same."
)
endif()
set(Rust_RUSTUP_TOOLCHAINS CACHE INTERNAL "List of available Rustup toolchains" "${_DISCOVERED_TOOLCHAINS}")
set(Rust_RUSTUP_TOOLCHAINS_RUSTC_PATH
CACHE INTERNAL
"List of the rustc paths corresponding to the toolchain at the same index in `Rust_RUSTUP_TOOLCHAINS`."
"${_DISCOVERED_TOOLCHAINS_RUSTC_PATH}"
)
set(Rust_RUSTUP_TOOLCHAINS_CARGO_PATH
CACHE INTERNAL
"List of the cargo paths corresponding to the toolchain at the same index in `Rust_RUSTUP_TOOLCHAINS`. \
May also be `NOTFOUND` if the toolchain does not have a cargo executable."
"${_DISCOVERED_TOOLCHAINS_CARGO_PATH}"
)
set(Rust_RUSTUP_TOOLCHAINS_VERSION
CACHE INTERNAL
"List of the rust toolchain version corresponding to the toolchain at the same index in \
`Rust_RUSTUP_TOOLCHAINS`."
"${_DISCOVERED_TOOLCHAINS_VERSION}"
)
# Rust_TOOLCHAIN is preferred over a requested version if it is set.
if (NOT DEFINED Rust_TOOLCHAIN)
if (NOT DEFINED _TOOLCHAIN_OVERRIDE)
set(_TOOLCHAIN_SELECTED "${_TOOLCHAIN_DEFAULT}")
else()
set(_TOOLCHAIN_SELECTED "${_TOOLCHAIN_OVERRIDE}")
endif()
# Check default toolchain first.
_findrust_version_ok("_TOOLCHAIN_${_TOOLCHAIN_SELECTED}_VERSION" _VERSION_OK)
if(NOT "${_VERSION_OK}")
foreach(_TOOLCHAIN "${_DISCOVERED_TOOLCHAINS}")
_findrust_version_ok("_TOOLCHAIN_${_TOOLCHAIN}_VERSION" _VERSION_OK)
if("${_VERSION_OK}")
set(_TOOLCHAIN_SELECTED "${_TOOLCHAIN}")
break()
endif()
endforeach()
# Check if we found a suitable version in the for loop.
if(NOT "${_VERSION_OK}")
string(REPLACE ";" "\n" _DISCOVERED_TOOLCHAINS "${_DISCOVERED_TOOLCHAINS}")
_findrust_failed("Failed to find a Rust toolchain matching the version requirements of "
"${Rust_FIND_VERSION}. Available toolchains: ${_DISCOVERED_TOOLCHAINS}")
endif()
endif()
endif()
set(Rust_TOOLCHAIN "${_TOOLCHAIN_SELECTED}" CACHE STRING "The rustup toolchain to use")
set_property(CACHE Rust_TOOLCHAIN PROPERTY STRINGS "${_DISCOVERED_TOOLCHAINS}")
if(NOT Rust_FIND_QUIETLY)
message(STATUS "Rust Toolchain: ${Rust_TOOLCHAIN}")
endif()
if (NOT Rust_TOOLCHAIN IN_LIST _DISCOVERED_TOOLCHAINS)
# If the precise toolchain wasn't found, try appending the default host
execute_process(
COMMAND
"${Rust_RUSTUP}" show
RESULT_VARIABLE _SHOW_RESULT
OUTPUT_VARIABLE _SHOW_RAW
)
if(NOT "${_SHOW_RESULT}" EQUAL "0")
_findrust_failed("Command `${Rust_RUSTUP} show` failed")
endif()
if (_SHOW_RAW MATCHES "Default host: ([a-zA-Z0-9_\\-]*)\n")
set(_DEFAULT_HOST "${CMAKE_MATCH_1}")
else()
_findrust_failed("Failed to parse \"Default host\" from `${Rust_RUSTUP} show`. Got: ${_SHOW_RAW}")
endif()
if (NOT "${Rust_TOOLCHAIN}-${_DEFAULT_HOST}" IN_LIST _DISCOVERED_TOOLCHAINS)
set(_NOT_FOUND_MESSAGE "Could not find toolchain '${Rust_TOOLCHAIN}'\n"
"Available toolchains:\n"
)
foreach(_TOOLCHAIN ${_DISCOVERED_TOOLCHAINS})
list(APPEND _NOT_FOUND_MESSAGE " `${_TOOLCHAIN}`\n")
endforeach()
_findrust_failed(${_NOT_FOUND_MESSAGE})
endif()
set(_RUSTUP_TOOLCHAIN_FULL "${Rust_TOOLCHAIN}-${_DEFAULT_HOST}")
else()
set(_RUSTUP_TOOLCHAIN_FULL "${Rust_TOOLCHAIN}")
endif()
set(_RUST_TOOLCHAIN_PATH "${_TOOLCHAIN_${_RUSTUP_TOOLCHAIN_FULL}_PATH}")
if(NOT "${Rust_FIND_QUIETLY}")
message(VERBOSE "Rust toolchain ${_RUSTUP_TOOLCHAIN_FULL}")
message(VERBOSE "Rust toolchain path ${_RUST_TOOLCHAIN_PATH}")
endif()
# Is overridden if the user specifies `Rust_COMPILER` explicitly.
find_program(
Rust_COMPILER_CACHED
rustc
HINTS "${_RUST_TOOLCHAIN_PATH}/bin"
NO_DEFAULT_PATH)
elseif (Rust_RUSTUP)
get_filename_component(_RUST_TOOLCHAIN_PATH "${Rust_RUSTUP}" DIRECTORY)
get_filename_component(_RUST_TOOLCHAIN_PATH "${_RUST_TOOLCHAIN_PATH}" DIRECTORY)
find_program(
Rust_COMPILER_CACHED
rustc
HINTS "${_RUST_TOOLCHAIN_PATH}/bin"
NO_DEFAULT_PATH)
else()
find_program(Rust_COMPILER_CACHED rustc)
if (EXISTS "${Rust_COMPILER_CACHED}")
# rustc is expected to be at `<toolchain_path>/bin/rustc`.
get_filename_component(_RUST_TOOLCHAIN_PATH "${Rust_COMPILER_CACHED}" DIRECTORY)
get_filename_component(_RUST_TOOLCHAIN_PATH "${_RUST_TOOLCHAIN_PATH}" DIRECTORY)
endif()
endif()
if (NOT EXISTS "${Rust_COMPILER_CACHED}")
message(FATAL_ERROR "The rustc executable ${Rust_COMPILER} was not found. "
"Consider setting `Rust_COMPILER` to the absolute path of `rustc`."
set(_NOT_FOUND_MESSAGE "The rustc executable was not found. "
"Rust not installed or ~/.cargo/bin not added to path?\n"
"Hint: Consider setting `Rust_COMPILER` to the absolute path of `rustc`."
)
_findrust_failed(${_NOT_FOUND_MESSAGE})
endif()
if (Rust_RESOLVE_RUSTUP_TOOLCHAINS)
set(_NOT_FOUND_MESSAGE "Rust was detected to be managed by rustup, but failed to find `cargo` "
"next to `rustc` in `${_RUST_TOOLCHAIN_PATH}/bin`. This can happen for custom toolchains, "
"if cargo was not built. "
"Please manually specify the path to a compatible `cargo` by setting `Rust_CARGO`."
)
find_program(
Rust_CARGO_CACHED
cargo
HINTS "${_RUST_TOOLCHAIN_PATH}/bin"
NO_DEFAULT_PATH
)
# note: maybe can use find_package_handle_standard_args here, if we remove the _CACHED postfix.
# not sure why that is here...
if(NOT EXISTS "${Rust_CARGO_CACHED}")
_findrust_failed(${_NOT_FOUND_MESSAGE})
endif()
set(Rust_TOOLCHAIN_IS_RUSTUP_MANAGED TRUE CACHE INTERNAL "" FORCE)
else()
set(_NOT_FOUND_MESSAGE "Failed to find `cargo` in PATH and `${_RUST_TOOLCHAIN_PATH}/bin`.\n"
"Please ensure cargo is in PATH or manually specify the path to a compatible `cargo` by "
"setting `Rust_CARGO`."
)
# On some systems (e.g. NixOS) cargo is not managed by rustup and also not next to rustc.
find_program(
Rust_CARGO_CACHED
cargo
HINTS "${_RUST_TOOLCHAIN_PATH}/bin"
)
# note: maybe can use find_package_handle_standard_args here, if we remove the _CACHED postfix.
# not sure why that is here...
if(NOT EXISTS "${Rust_CARGO_CACHED}")
_findrust_failed(${_NOT_FOUND_MESSAGE})
endif()
endif()
execute_process(
COMMAND "${Rust_CARGO_CACHED}" --version --verbose
OUTPUT_VARIABLE _CARGO_VERSION_RAW
RESULT_VARIABLE _CARGO_VERSION_RESULT
)
# todo: check if cargo is a required component!
if(NOT ( "${_CARGO_VERSION_RESULT}" EQUAL "0" ))
_findrust_failed("Failed to get cargo version.\n"
"`${Rust_CARGO_CACHED} --version` failed with error: `${_CARGO_VERSION_RESULT}"
)
endif()
# todo: don't set cache variables here, but let find_package_handle_standard_args do the promotion
# later.
if (_CARGO_VERSION_RAW MATCHES "cargo ([0-9]+)\\.([0-9]+)\\.([0-9]+)")
set(Rust_CARGO_VERSION_MAJOR "${CMAKE_MATCH_1}" CACHE INTERNAL "" FORCE)
set(Rust_CARGO_VERSION_MINOR "${CMAKE_MATCH_2}" CACHE INTERNAL "" FORCE)
set(Rust_CARGO_VERSION_PATCH "${CMAKE_MATCH_3}" CACHE INTERNAL "" FORCE)
set(Rust_CARGO_VERSION "${Rust_CARGO_VERSION_MAJOR}.${Rust_CARGO_VERSION_MINOR}.${Rust_CARGO_VERSION_PATCH}" CACHE INTERNAL "" FORCE)
# Workaround for the version strings where the `cargo ` prefix is missing.
elseif(_CARGO_VERSION_RAW MATCHES "([0-9]+)\\.([0-9]+)\\.([0-9]+)")
set(Rust_CARGO_VERSION_MAJOR "${CMAKE_MATCH_1}" CACHE INTERNAL "" FORCE)
set(Rust_CARGO_VERSION_MINOR "${CMAKE_MATCH_2}" CACHE INTERNAL "" FORCE)
set(Rust_CARGO_VERSION_PATCH "${CMAKE_MATCH_3}" CACHE INTERNAL "" FORCE)
set(Rust_CARGO_VERSION "${Rust_CARGO_VERSION_MAJOR}.${Rust_CARGO_VERSION_MINOR}.${Rust_CARGO_VERSION_PATCH}" CACHE INTERNAL "" FORCE)
else()
_findrust_failed(
"Failed to parse cargo version. `cargo --version` evaluated to (${_CARGO_VERSION_RAW}). "
"Expected a <Major>.<Minor>.<Patch> version triple."
)
endif()
# Figure out the target by just using the host target.
# If you want to cross-compile, you'll have to set Rust_CARGO_TARGET
if(NOT Rust_CARGO_TARGET_CACHED)
execute_process(
execute_process(
COMMAND "${Rust_COMPILER_CACHED}" --version --verbose
OUTPUT_VARIABLE _RUSTC_VERSION_RAW
RESULT_VARIABLE _RUSTC_VERSION_RESULT
)
)
if(NOT ( "${_RUSTC_VERSION_RESULT}" EQUAL "0" ))
message(FATAL_ERROR "Failed to get rustc version.\n"
"${Rust_COMPILER} --version failed with error: `${_RUSTC_VERSION_RESULT}`")
endif()
if(NOT ( "${_RUSTC_VERSION_RESULT}" EQUAL "0" ))
_findrust_failed("Failed to get rustc version.\n"
"${Rust_COMPILER_CACHED} --version failed with error: `${_RUSTC_VERSION_RESULT}`")
endif()
if (_RUSTC_VERSION_RAW MATCHES "host: ([a-zA-Z0-9_\\-]*)\n")
if (_RUSTC_VERSION_RAW MATCHES "rustc ([0-9]+)\\.([0-9]+)\\.([0-9]+)(-nightly)?")
set(Rust_VERSION_MAJOR "${CMAKE_MATCH_1}" CACHE INTERNAL "" FORCE)
set(Rust_VERSION_MINOR "${CMAKE_MATCH_2}" CACHE INTERNAL "" FORCE)
set(Rust_VERSION_PATCH "${CMAKE_MATCH_3}" CACHE INTERNAL "" FORCE)
set(Rust_VERSION "${Rust_VERSION_MAJOR}.${Rust_VERSION_MINOR}.${Rust_VERSION_PATCH}" CACHE INTERNAL "" FORCE)
if(CMAKE_MATCH_4)
set(Rust_IS_NIGHTLY 1 CACHE INTERNAL "" FORCE)
else()
set(Rust_IS_NIGHTLY 0 CACHE INTERNAL "" FORCE)
endif()
else()
_findrust_failed("Failed to parse rustc version. `${Rust_COMPILER_CACHED} --version --verbose` "
"evaluated to:\n`${_RUSTC_VERSION_RAW}`"
)
endif()
if (_RUSTC_VERSION_RAW MATCHES "host: ([a-zA-Z0-9_\\-]*)\n")
set(Rust_DEFAULT_HOST_TARGET "${CMAKE_MATCH_1}")
else()
message(FATAL_ERROR
"Failed to parse rustc host target. `rustc --version --verbose` evaluated to:\n${_RUSTC_VERSION_RAW}"
set(Rust_CARGO_HOST_TARGET_CACHED "${Rust_DEFAULT_HOST_TARGET}" CACHE STRING "Host triple")
else()
_findrust_failed(
"Failed to parse rustc host target. `rustc --version --verbose` evaluated to:\n${_RUSTC_VERSION_RAW}"
)
endif()
endif()
if(CMAKE_CROSSCOMPILING)
message(FATAL_ERROR "CMake is in cross-compiling mode."
"Manually set `Rust_CARGO_TARGET`."
if (_RUSTC_VERSION_RAW MATCHES "LLVM version: ([0-9]+)\\.([0-9]+)(\\.([0-9]+))?")
set(Rust_LLVM_VERSION_MAJOR "${CMAKE_MATCH_1}" CACHE INTERNAL "" FORCE)
set(Rust_LLVM_VERSION_MINOR "${CMAKE_MATCH_2}" CACHE INTERNAL "" FORCE)
# With the Rust toolchain 1.44.1 the reported LLVM version is 9.0, i.e. without a patch version.
# Since cmake regex does not support non-capturing groups, just ignore Match 3.
set(Rust_LLVM_VERSION_PATCH "${CMAKE_MATCH_4}" CACHE INTERNAL "" FORCE)
set(Rust_LLVM_VERSION "${Rust_LLVM_VERSION_MAJOR}.${Rust_LLVM_VERSION_MINOR}.${Rust_LLVM_VERSION_PATCH}" CACHE INTERNAL "" FORCE)
elseif(NOT Rust_FIND_QUIETLY)
message(
WARNING
"Failed to parse rustc LLVM version. `rustc --version --verbose` evaluated to:\n${_RUSTC_VERSION_RAW}"
)
endif()
set(Rust_CARGO_TARGET_CACHED "${Rust_DEFAULT_HOST_TARGET}" CACHE STRING "Target triple")
endif()
if (NOT Rust_CARGO_TARGET_CACHED)
unset(_CARGO_ARCH)
unset(_CARGO_ABI)
if (WIN32)
if (CMAKE_VS_PLATFORM_NAME)
string(TOLOWER "${CMAKE_VS_PLATFORM_NAME}" LOWER_VS_PLATFORM_NAME)
if ("${LOWER_VS_PLATFORM_NAME}" STREQUAL "win32")
set(_CARGO_ARCH i686)
elseif("${LOWER_VS_PLATFORM_NAME}" STREQUAL "x64")
set(_CARGO_ARCH x86_64)
elseif("${LOWER_VS_PLATFORM_NAME}" STREQUAL "arm64")
set(_CARGO_ARCH aarch64)
else()
message(WARNING "VS Platform '${CMAKE_VS_PLATFORM_NAME}' not recognized")
endif()
endif()
# Fallback path
if(NOT DEFINED _CARGO_ARCH)
# Possible values for windows when not cross-compiling taken from here:
# https://learn.microsoft.com/en-us/windows/win32/winprog64/wow64-implementation-details
# When cross-compiling the user is expected to supply the value, so we match more variants.
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(AMD64|amd64|x86_64)$")
set(_CARGO_ARCH x86_64)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(ARM64|arm64|aarch64)$")
set(_CARGO_ARCH aarch64)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(X86|x86|i686)$")
set(_CARGO_ARCH i686)
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "i586")
set(_CARGO_ARCH i586)
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "IA64")
message(FATAL_ERROR "No rust target for Intel Itanium.")
elseif(NOT "${CMAKE_SYSTEM_PROCESSOR}")
message(WARNING "Failed to detect target architecture. Please set `CMAKE_SYSTEM_PROCESSOR`"
" to your target architecture or set `Rust_CARGO_TARGET` to your cargo target triple."
)
else()
message(WARNING "Failed to detect target architecture. Please set "
"`Rust_CARGO_TARGET` to your cargo target triple."
)
endif()
endif()
set(_CARGO_VENDOR "pc-windows")
# The MSVC Generators will always target the msvc ABI.
# For other generators we check the compiler ID and compiler target (if present)
# If no compiler is set and we are not cross-compiling then we just choose the
# default rust host target.
if(DEFINED MSVC
OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC"
OR "${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC"
OR "${CMAKE_CXX_COMPILER_TARGET}" MATCHES "-msvc$"
OR "${CMAKE_C_COMPILER_TARGET}" MATCHES "-msvc$"
)
set(_CARGO_ABI msvc)
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU"
OR "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU"
OR "${CMAKE_CXX_COMPILER_TARGET}" MATCHES "-gnu$"
OR "${CMAKE_C_COMPILER_TARGET}" MATCHES "-gnu$"
OR (NOT CMAKE_CROSSCOMPILING AND "${Rust_DEFAULT_HOST_TARGET}" MATCHES "-gnu$")
)
set(_CARGO_ABI gnu)
elseif(NOT "${CMAKE_CROSSCOMPILING}" AND "${Rust_DEFAULT_HOST_TARGET}" MATCHES "-msvc$")
# We first check if the gnu branch matches to ensure this fallback is only used
# if no compiler is enabled.
set(_CARGO_ABI msvc)
else()
message(WARNING "Could not determine the target ABI. Please specify `Rust_CARGO_TARGET` manually.")
endif()
if(DEFINED _CARGO_ARCH AND DEFINED _CARGO_VENDOR AND DEFINED _CARGO_ABI)
set(Rust_CARGO_TARGET_CACHED "${_CARGO_ARCH}-${_CARGO_VENDOR}-${_CARGO_ABI}"
CACHE STRING "Target triple")
endif()
elseif (ANDROID)
if (CMAKE_ANDROID_ARCH_ABI STREQUAL armeabi-v7a)
if (CMAKE_ANDROID_ARM_MODE)
set(_Rust_ANDROID_TARGET armv7-linux-androideabi)
else ()
set(_Rust_ANDROID_TARGET thumbv7neon-linux-androideabi)
endif()
elseif (CMAKE_ANDROID_ARCH_ABI STREQUAL arm64-v8a)
set(_Rust_ANDROID_TARGET aarch64-linux-android)
elseif (CMAKE_ANDROID_ARCH_ABI STREQUAL x86)
set(_Rust_ANDROID_TARGET i686-linux-android)
elseif (CMAKE_ANDROID_ARCH_ABI STREQUAL x86_64)
set(_Rust_ANDROID_TARGET x86_64-linux-android)
endif()
if (_Rust_ANDROID_TARGET)
set(Rust_CARGO_TARGET_CACHED "${_Rust_ANDROID_TARGET}" CACHE STRING "Target triple")
endif()
endif()
# Fallback to the default host target
if(NOT Rust_CARGO_TARGET_CACHED)
if(CMAKE_CROSSCOMPILING)
message(WARNING "CMake is in cross-compiling mode, but the cargo target-triple could not be inferred."
"Falling back to the default host target. Please consider manually setting `Rust_CARGO_TARGET`."
)
endif()
set(Rust_CARGO_TARGET_CACHED "${Rust_DEFAULT_HOST_TARGET}" CACHE STRING "Target triple")
endif()
message(STATUS "Rust Target: ${Rust_CARGO_TARGET_CACHED}")
endif()
if(Rust_CARGO_TARGET_CACHED STREQUAL Rust_DEFAULT_HOST_TARGET)
set(Rust_CROSSCOMPILING FALSE CACHE INTERNAL "Rust is configured for cross-compiling")
else()
set(Rust_CROSSCOMPILING TRUE CACHE INTERNAL "Rust is configured for cross-compiling")
endif()
_corrosion_parse_target_triple("${Rust_CARGO_TARGET_CACHED}" rust_arch rust_vendor rust_os rust_env)
_corrosion_parse_target_triple("${Rust_CARGO_HOST_TARGET_CACHED}" rust_host_arch rust_host_vendor rust_host_os rust_host_env)
set(Rust_CARGO_TARGET_ARCH "${rust_arch}" CACHE INTERNAL "Target architecture")
set(Rust_CARGO_TARGET_VENDOR "${rust_vendor}" CACHE INTERNAL "Target vendor")
set(Rust_CARGO_TARGET_OS "${rust_os}" CACHE INTERNAL "Target Operating System")
set(Rust_CARGO_TARGET_ENV "${rust_env}" CACHE INTERNAL "Target environment")
set(Rust_CARGO_HOST_ARCH "${rust_host_arch}" CACHE INTERNAL "Host architecture")
set(Rust_CARGO_HOST_VENDOR "${rust_host_vendor}" CACHE INTERNAL "Host vendor")
set(Rust_CARGO_HOST_OS "${rust_host_os}" CACHE INTERNAL "Host Operating System")
set(Rust_CARGO_HOST_ENV "${rust_host_env}" CACHE INTERNAL "Host environment")
if(NOT DEFINED CACHE{Rust_CARGO_TARGET_LINK_NATIVE_LIBS})
message(STATUS "Determining required link libraries for target ${Rust_CARGO_TARGET_CACHED}")
unset(required_native_libs)
_corrosion_determine_libs_new("${Rust_CARGO_TARGET_CACHED}" required_native_libs)
if(DEFINED required_native_libs)
message(STATUS "Required static libs for target ${Rust_CARGO_TARGET_CACHED}: ${required_native_libs}" )
endif()
# In very recent corrosion versions it is possible to override the rust compiler version
# per target, so to be totally correct we would need to determine the libraries for
# every installed Rust version, that the user could choose from.
# In practice there aren't likely going to be any major differences, so we just do it once
# for the target and once for the host target (if cross-compiling).
set(Rust_CARGO_TARGET_LINK_NATIVE_LIBS "${required_native_libs}" CACHE INTERNAL
"Required native libraries when linking Rust static libraries")
endif()
if(Rust_CROSSCOMPILING AND NOT DEFINED CACHE{Rust_CARGO_HOST_TARGET_LINK_NATIVE_LIBS})
message(STATUS "Determining required link libraries for target ${Rust_CARGO_HOST_TARGET_CACHED}")
unset(host_libs)
_corrosion_determine_libs_new("${Rust_CARGO_HOST_TARGET_CACHED}" host_libs)
if(DEFINED host_libs)
message(STATUS "Required static libs for host target ${Rust_CARGO_HOST_TARGET_CACHED}: ${host_libs}" )
endif()
set(Rust_CARGO_HOST_TARGET_LINK_NATIVE_LIBS "${host_libs}" CACHE INTERNAL
"Required native libraries when linking Rust static libraries for the host target")
endif()
# Set the input variables as non-cache variables so that the variables are available after
@@ -82,6 +782,24 @@ endforeach()
find_package_handle_standard_args(
Rust
REQUIRED_VARS Rust_COMPILER Rust_CARGO Rust_CARGO_TARGET
REQUIRED_VARS Rust_COMPILER Rust_VERSION Rust_CARGO Rust_CARGO_VERSION Rust_CARGO_TARGET Rust_CARGO_HOST_TARGET
VERSION_VAR Rust_VERSION
)
if(NOT TARGET Rust::Rustc)
add_executable(Rust::Rustc IMPORTED GLOBAL)
set_property(
TARGET Rust::Rustc
PROPERTY IMPORTED_LOCATION "${Rust_COMPILER_CACHED}"
)
add_executable(Rust::Cargo IMPORTED GLOBAL)
set_property(
TARGET Rust::Cargo
PROPERTY IMPORTED_LOCATION "${Rust_CARGO_CACHED}"
)
set(Rust_FOUND true)
endif()
list(POP_BACK CMAKE_MESSAGE_CONTEXT)

View File

@@ -164,8 +164,14 @@ if(GETTEXT_FOUND)
endforeach()
endif()
if (NOT APPLE)
install(FILES fish.desktop DESTINATION ${rel_datadir}/applications)
install(FILES ${SPHINX_SRC_DIR}/python_docs_theme/static/fish.png DESTINATION ${rel_datadir}/pixmaps)
endif()
# Group install targets into a InstallTargets folder
set_property(TARGET build_fish_pc CHECK-FISH-BUILD-VERSION-FILE
tests_buildroot_target
PROPERTY FOLDER cmake/InstallTargets)
# Make a target build_root that installs into the buildroot directory, for testing.

View File

@@ -24,7 +24,7 @@ add_executable(fish_macapp EXCLUDE_FROM_ALL
# Compute the version. Note this is done at generation time, not build time,
# so cmake must be re-run after version changes for the app to be updated. But
# generally this will be run by make_pkg.sh which always re-runs cmake.
# generally this will be run by make_macos_pkg.sh which always re-runs cmake.
execute_process(
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build_tools/git_version_gen.sh --stdout
COMMAND cut -d- -f1
@@ -32,7 +32,7 @@ execute_process(
OUTPUT_STRIP_TRAILING_WHITESPACE)
# Note CMake appends .app, so the real output name will be fish.app.
# Note CMake appends .app, so the real output name will be fish.app.
# This target does not include the 'base' resource.
set_target_properties(fish_macapp PROPERTIES OUTPUT_NAME "fish")

View File

@@ -1,3 +1,7 @@
# Trying to build using the resolved toolchain causes all kinds of weird errors
# Just let rustup do its job
set(Rust_RESOLVE_RUSTUP_TOOLCHAINS Off)
include(FindRust)
find_package(Rust REQUIRED)
@@ -22,7 +26,7 @@ set(rust_profile $<IF:$<CONFIG:Debug>,debug,$<IF:$<CONFIG:RelWithDebInfo>,releas
set(rust_debugflags "$<$<CONFIG:Debug>:-g>$<$<CONFIG:RelWithDebInfo>:-g>")
# Temporary hack to propagate CMake flags/options to build.rs. We need to get CMake to evaluate the
# Temporary hack to propogate CMake flags/options to build.rs. We need to get CMake to evaluate the
# truthiness of the strings if they are set.
set(CMAKE_WITH_GETTEXT "1")
if(DEFINED WITH_GETTEXT AND NOT "${WITH_GETTEXT}")
@@ -34,11 +38,16 @@ if(FISH_CRATE_FEATURES)
list(PREPEND FEATURES_ARG "--features")
endif()
get_property(
RUSTC_EXECUTABLE
TARGET Rust::Rustc PROPERTY IMPORTED_LOCATION
)
# Tell Cargo where our build directory is so it can find Cargo.toml.
set(VARS_FOR_CARGO
"FISH_BUILD_DIR=${CMAKE_BINARY_DIR}"
"PREFIX=${CMAKE_INSTALL_PREFIX}"
# Temporary hack to propagate CMake flags/options to build.rs.
# Temporary hack to propogate CMake flags/options to build.rs.
"CMAKE_WITH_GETTEXT=${CMAKE_WITH_GETTEXT}"
# Cheesy so we can tell cmake was used to build
"CMAKE=1"
@@ -48,7 +57,7 @@ set(VARS_FOR_CARGO
"BINDIR=${CMAKE_INSTALL_FULL_BINDIR}"
"LOCALEDIR=${CMAKE_INSTALL_FULL_LOCALEDIR}"
"CARGO_TARGET_DIR=${FISH_RUST_BUILD_DIR}"
"CARGO_BUILD_RUSTC=${Rust_COMPILER}"
"CARGO_BUILD_RUSTC=${RUSTC_EXECUTABLE}"
"${FISH_PCRE2_BUILDFLAG}"
"RUSTFLAGS=$ENV{RUSTFLAGS} ${rust_debugflags}"
)

View File

@@ -1,33 +1,127 @@
add_executable(fish_test_helper tests/fish_test_helper.c)
# This adds ctest support to the project
enable_testing()
# Put in a tests folder to reduce the top level targets in IDEs.
set(CMAKE_FOLDER tests)
# We will use 125 as a reserved exit code to indicate that a test has been skipped, i.e. it did not
# pass but it should not be considered a failed test run, either.
set(SKIP_RETURN_CODE 125)
# Even though we are using CMake's ctest for testing, we still define our own `make fish_run_tests` target
# rather than use its default for many reasons:
# * CMake doesn't run tests in-proc or even add each tests as an individual node in the ninja
# dependency tree, instead it just bundles all tests into a target called `test` that always just
# shells out to `ctest`, so there are no build-related benefits to not doing that ourselves.
# * The only way to have a test depend on a binary is to add a fake test with a name like
# "build_fish" that executes CMake recursively to build the `fish` target.
# * Circling back to the point about individual tests not being actual Makefile targets, CMake does
# not offer any way to execute a named test via the `make`/`ninja`/whatever interface; the only
# way to manually invoke test `foo` is to to manually run `ctest` and specify a regex matching
# `foo` as an argument, e.g. `ctest -R ^foo$`... which is really crazy.
# The top-level test target is "fish_run_tests".
add_custom_target(fish_run_tests
COMMAND env FISH_FORCE_COLOR=1
FISH_SOURCE_DIR=${CMAKE_SOURCE_DIR}
${CMAKE_CTEST_COMMAND} --force-new-ctest-process # --verbose
--output-on-failure --progress
DEPENDS tests_dir funcs_dir tests_buildroot_target
USES_TERMINAL
)
# The "test" directory.
set(TEST_DIR ${CMAKE_CURRENT_BINARY_DIR}/test)
# The directory into which fish is installed.
set(TEST_INSTALL_DIR ${TEST_DIR}/buildroot)
# The directory where the tests expect to find the fish root (./bin, etc)
set(TEST_ROOT_DIR ${TEST_DIR}/root)
# Copy needed directories for out-of-tree builds
if(NOT FISH_IN_TREE_BUILD)
add_custom_target(funcs_dir)
add_custom_command(TARGET funcs_dir
POST_BUILD
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/share
# Don't run ln twice or it will create a new link in the link.
COMMAND test -e ${CMAKE_BINARY_DIR}/share/functions || ln -sf
${CMAKE_SOURCE_DIR}/share/functions/ ${CMAKE_BINARY_DIR}/share/functions
COMMENT "Symlinking fish functions to binary dir"
VERBATIM)
add_custom_target(tests_dir DEPENDS tests)
add_custom_command(TARGET tests_dir
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/tests/ ${CMAKE_BINARY_DIR}/tests/
COMMENT "Copying test files to binary dir"
VERBATIM)
endif()
# Copy littlecheck.py
configure_file(build_tools/littlecheck.py littlecheck.py COPYONLY)
# Copy pexpect_helper.py
configure_file(build_tools/pexpect_helper.py pexpect_helper.py COPYONLY)
# Suppress generating Xcode schemes for all tests, there's too many.
set(CMAKE_XCODE_GENERATE_SCHEME 0)
# CMake being CMake, you can't just add a DEPENDS argument to add_test to make it depend on any of
# your binaries actually being built before `make fish_run_tests` is executed (requiring `make all` first),
# and the only dependency a test can have is on another test. So we make building fish
# prerequisites to our entire top-level `test` target.
function(add_test_target NAME)
string(REPLACE "/" "-" NAME ${NAME})
add_custom_target("test_${NAME}" COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -R "^${NAME}$$"
DEPENDS tests_dir funcs_dir tests_buildroot_target USES_TERMINAL )
endfunction()
add_custom_target(tests_buildroot_target
# Make the directory in which to run tests:
COMMAND ${CMAKE_COMMAND} -E make_directory ${TEST_INSTALL_DIR}
COMMAND env DESTDIR=${TEST_INSTALL_DIR} ${CMAKE_COMMAND}
--build ${CMAKE_CURRENT_BINARY_DIR} --target install
# Put fish_test_helper there too:
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/fish_test_helper
${TEST_INSTALL_DIR}/${CMAKE_INSTALL_PREFIX}/bin
# Also symlink fish to where the tests expect it to be:
COMMAND ${CMAKE_COMMAND} -E create_symlink
${TEST_INSTALL_DIR}/${CMAKE_INSTALL_PREFIX}
${TEST_ROOT_DIR}
DEPENDS fish fish_test_helper)
FILE(GLOB FISH_CHECKS CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/tests/checks/*.fish)
foreach(CHECK ${FISH_CHECKS})
get_filename_component(CHECK_NAME ${CHECK} NAME)
add_custom_target(
test_${CHECK_NAME}
COMMAND ${CMAKE_SOURCE_DIR}/tests/test_driver.py ${CMAKE_CURRENT_BINARY_DIR}
checks/${CHECK_NAME}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
DEPENDS fish fish_indent fish_key_reader fish_test_helper
USES_TERMINAL
get_filename_component(CHECK ${CHECK} NAME_WE)
add_test(NAME ${CHECK_NAME}
COMMAND sh ${CMAKE_CURRENT_BINARY_DIR}/tests/test_driver.sh
${CMAKE_CURRENT_BINARY_DIR}/tests/test.fish ${CHECK}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests
)
set_tests_properties(${CHECK_NAME} PROPERTIES SKIP_RETURN_CODE ${SKIP_RETURN_CODE})
set_tests_properties(${CHECK_NAME} PROPERTIES ENVIRONMENT FISH_FORCE_COLOR=1)
add_test_target("${CHECK_NAME}")
endforeach(CHECK)
FILE(GLOB PEXPECTS CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/tests/pexpects/*.py)
foreach(PEXPECT ${PEXPECTS})
get_filename_component(PEXPECT ${PEXPECT} NAME)
add_custom_target(
test_${PEXPECT}
COMMAND ${CMAKE_SOURCE_DIR}/tests/test_driver.py ${CMAKE_CURRENT_BINARY_DIR}
pexpects/${PEXPECT}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
DEPENDS fish fish_indent fish_key_reader fish_test_helper
USES_TERMINAL
add_test(NAME ${PEXPECT}
COMMAND sh ${CMAKE_CURRENT_BINARY_DIR}/tests/test_driver.sh
${CMAKE_CURRENT_BINARY_DIR}/tests/interactive.fish ${PEXPECT}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests
)
set_tests_properties(${PEXPECT} PROPERTIES SKIP_RETURN_CODE ${SKIP_RETURN_CODE})
set_tests_properties(${PEXPECT} PROPERTIES ENVIRONMENT FISH_FORCE_COLOR=1)
add_test_target("${PEXPECT}")
endforeach(PEXPECT)
# Rust stuff.
set(cargo_test_flags)
# Rust stuff.
if(DEFINED ASAN)
# Rust w/ -Zsanitizer=address requires explicitly specifying the --target triple or else linker
# errors pertaining to asan symbols will ensue.
@@ -48,17 +142,10 @@ if(DEFINED Rust_CARGO_TARGET)
list(APPEND cargo_test_flags "--lib")
endif()
set(max_concurrency_flag)
if(DEFINED ENV{FISH_TEST_MAX_CONCURRENCY})
list(APPEND max_concurrency_flag "--max-concurrency" $ENV{FISH_TEST_MAX_CONCURRENCY})
endif()
# The top-level test target is "fish_run_tests".
add_custom_target(fish_run_tests
# TODO: This should be replaced with a unified solution, possibly build_tools/check.sh.
COMMAND ${CMAKE_SOURCE_DIR}/tests/test_driver.py ${max_concurrency_flag} ${CMAKE_CURRENT_BINARY_DIR}
COMMAND env ${VARS_FOR_CARGO} cargo test --no-default-features ${CARGO_FLAGS} --workspace --target-dir ${rust_target_dir} ${cargo_test_flags}
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
DEPENDS fish fish_indent fish_key_reader fish_test_helper
USES_TERMINAL
add_test(
NAME "cargo-test"
COMMAND env ${VARS_FOR_CARGO} cargo test --no-default-features ${CARGO_FLAGS} --workspace --target-dir ${rust_target_dir} ${cargo_test_flags}
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
)
set_tests_properties("cargo-test" PROPERTIES SKIP_RETURN_CODE ${SKIP_RETURN_CODE})
add_test_target("cargo-test")

6
debian/control vendored
View File

@@ -20,16 +20,12 @@ Vcs-Browser: https://github.com/fish-shell/fish-shell
Package: fish
Architecture: any
# for col and lock - bsdmainutils is required in Ubuntu focal
Depends: bsdextrautils | bsdmainutils,
file,
# for the gettext command
gettext-base,
# for nroff and preconv
groff-base,
# for terminal definitions
man-db,
ncurses-base,
# for kill
procps,
python3 (>=3.5),
${misc:Depends},

4
debian/copyright vendored
View File

@@ -5,12 +5,12 @@ Source: https://fishshell.com/
Files: *
Copyright: 2005-2009 Axel Liljencrantz <axel@liljencrantz.se>
2009- fish-shell contributors
2009-2024 fish-shell contributors
License: GPL-2
Files: doc_src/python_docs_theme/*
Copyright: 2001-2017 Python Software Foundation
2020- fish-shell contributors
2020-2024 fish-shell contributors
License: Python
Files: share/tools/web_config/js/alpine.js

2
debian/rules vendored
View File

@@ -17,7 +17,7 @@ override_dh_auto_configure:
dh_auto_configure --buildsystem=cmake -- -DCMAKE_BUILD_TYPE=RelWithDebInfo
override_dh_clean:
dh_clean
dh_clean --exclude=Cargo.toml.orig
-unlink .cargo
-unlink vendor

View File

@@ -13,11 +13,10 @@ allow = [
"MPL-2.0",
"PSF-2.0",
"Unicode-DFS-2016",
"Unicode-3.0",
"WTFPL",
"Zlib",
]
[sources.allow-org]
# 1 or more github.com organizations to allow git sources for
github = ["fish-shell"]
github = ["fish-shell"]

View File

@@ -17,7 +17,7 @@ Description
It is equivalent to ``gettext fish STRING``, meaning it can only be used to look up fish's own translations.
It requires fish to be built with gettext support. If that support is disabled, or there is no translation it will echo the argument back.
It requires fish to be built with gettext support. If that support is disabled, or there is no translation it will simply echo the argument back.
The language depends on the current locale, set with :envvar:`LANG` and :envvar:`LC_MESSAGES`.

View File

@@ -20,7 +20,7 @@ Each option specification (``OPTION_SPEC``) is written in the :ref:`domain speci
Each option that is seen in the ARG list will result in variables named ``_flag_X``, where **X** is the short flag letter and the long flag name (if they are defined). For example a **--help** option could cause argparse to define one variable called ``_flag_h`` and another called ``_flag_help``.
The variables will be set with local scope (i.e., as if the script had done ``set -l _flag_X``). If the flag is a boolean (that is, it is passed or not, it doesn't have a value) the values are the short and long flags seen. If the option is not a boolean the values will be zero or more values corresponding to the values collected when the ARG list is processed. If the flag was not seen the flag variable will not be set.
The variables will be set with local scope (i.e., as if the script had done ``set -l _flag_X``). If the flag is a boolean (that is, it just is passed or not, it doesn't have a value) the values are the short and long flags seen. If the option is not a boolean the values will be zero or more values corresponding to the values collected when the ARG list is processed. If the flag was not seen the flag variable will not be set.
Options
-------
@@ -165,7 +165,7 @@ This isn't specific to argparse but common to all things using ``getopt(3)`` (if
Flag Value Validation
---------------------
Sometimes you need to validate the option values. For example, that it is a valid integer within a specific range, or an ip address, or something entirely different. You can always do this after ``argparse`` returns but you can also request that ``argparse`` perform the validation by executing arbitrary fish script. To do so append an ``!`` (exclamation-mark) then the fish script to be run. When that code is executed three vars will be defined:
Sometimes you need to validate the option values. For example, that it is a valid integer within a specific range, or an ip address, or something entirely different. You can always do this after ``argparse`` returns but you can also request that ``argparse`` perform the validation by executing arbitrary fish script. To do so simply append an ``!`` (exclamation-mark) then the fish script to be run. When that code is executed three vars will be defined:
- ``_argparse_cmd`` will be set to the value of the value of the ``argparse --name`` value.
@@ -177,7 +177,7 @@ These variables are passed to the function as local exported variables.
The script should write any error messages to stdout, not stderr. It should return a status of zero if the flag value is valid otherwise a non-zero status to indicate it is invalid.
Fish ships with a ``_validate_int`` function that accepts a ``--min`` and ``--max`` flag. Let's say your command accepts a ``-m`` or ``--max`` flag and the minimum allowable value is zero and the maximum is 5. You would define the option like this: ``m/max=!_validate_int --min 0 --max 5``. The default if you call ``_validate_int`` without those flags is to check that the value is a valid integer with no limits on the min or max value allowed.
Fish ships with a ``_validate_int`` function that accepts a ``--min`` and ``--max`` flag. Let's say your command accepts a ``-m`` or ``--max`` flag and the minimum allowable value is zero and the maximum is 5. You would define the option like this: ``m/max=!_validate_int --min 0 --max 5``. The default if you just call ``_validate_int`` without those flags is to simply check that the value is a valid integer with no limits on the min or max value allowed.
Here are some examples of flag validations::
@@ -234,7 +234,7 @@ A simple use::
return 0
end
This supports one option - ``-h`` / ``--help``. Any other option is an error. If it is given it prints help and exits.
This just wants one option - ``-h`` / ``--help``. Any other option is an error. If it is given it prints help and exits.
How :doc:`fish_add_path` parses its args::

View File

@@ -9,7 +9,6 @@ Synopsis
.. synopsis::
begin; [COMMANDS ...]; end
{ [COMMANDS ...] }
Description
-----------
@@ -22,8 +21,6 @@ The block is unconditionally executed. ``begin; ...; end`` is equivalent to ``if
``begin`` does not change the current exit status itself. After the block has completed, ``$status`` will be set to the status returned by the most recent command.
Some other shells only support the ``{ [COMMANDS ...] ; }`` notation.
The **-h** or **--help** option displays help about using this command.
Example

View File

@@ -11,7 +11,6 @@ Synopsis
bind [(-M | --mode) MODE] [--preset] [--user] [KEYS]
bind [-a | --all] [--preset] [--user]
bind (-f | --function-names)
bind (-K | --key-names)
bind (-L | --list-modes)
bind (-e | --erase) [(-M | --mode) MODE] [--preset] [--user] [-a | --all] | KEYS ...
@@ -21,8 +20,7 @@ Description
``bind`` manages key bindings.
If both ``KEYS`` and ``COMMAND`` are given, ``bind`` adds (or replaces) a binding in ``MODE``.
If only ``KEYS`` is given, any existing binding for those keys in the given ``MODE`` will be printed.
If no ``KEYS`` argument is provided, all bindings (in the given ``MODE``) are printed.
If only ``KEYS`` is given, any existing binding in the given ``MODE`` will be printed.
``KEYS`` is a comma-separated list of key names.
Modifier keys can be specified by prefixing a key name with a combination of ``ctrl-``, ``alt-``, ``shift-`` and ``super-`` (i.e. the "windows" or "command" key).
@@ -43,11 +41,9 @@ They are:
- ``f1`` through ``f12``.
- ``home``,
- ``insert``,
- ``menu``,
- ``minus`` (``-``),
- ``pageup``,
- ``pagedown``,
- ``printscreen``,
- ``space`` and
- ``tab``,
@@ -62,7 +58,9 @@ To find the name of a key combination you can use :doc:`fish_key_reader <fish_ke
.. note::
If a script changes the commandline, it should finish by calling the ``repaint`` special input function.
Key bindings may use "modes", which mimics vi's modal input behavior. The default mode is "default" (in vi-mode, that's vi's "normal" mode). Every key binding applies to a single mode; you can specify which one with ``-M MODE``. If the key binding should change the mode, you can specify the new mode with ``-m NEW_MODE``. The mode can be viewed and changed via the ``$fish_bind_mode`` variable. If you want to change the mode from inside a fish function, use ``set fish_bind_mode MODE``.
If no ``KEYS`` argument is provided, all bindings (in the given ``MODE``) are printed. If ``KEYS`` is provided but no ``COMMAND``, just the binding matching that sequence is printed.
Key bindings may use "modes", which mimics vi's modal input behavior. The default mode is "default". Every key binding applies to a single mode; you can specify which one with ``-M MODE``. If the key binding should change the mode, you can specify the new mode with ``-m NEW_MODE``. The mode can be viewed and changed via the ``$fish_bind_mode`` variable. If you want to change the mode from inside a fish function, use ``set fish_bind_mode MODE``.
To save custom key bindings, put the ``bind`` statements into :ref:`config.fish <configuration>`. Alternatively, fish also automatically executes a function called ``fish_user_key_bindings`` if it exists.
@@ -73,16 +71,11 @@ The following options are available:
**-f** or **--function-names**
Display a list of available input functions
**-K** or **--key-names**
Display a list of available named keys such as ``backspace``.
**-L** or **--list-modes**
Display a list of defined bind modes
**-M MODE** or **--mode** *MODE*
Specify a bind mode that the bind is used in. Defaults to "default".
If you use :ref:`vi bindings <vi-mode>`, that's the *command* mode,
what vi calls "normal" mode.
Specify a bind mode that the bind is used in. Defaults to "default"
**-m NEW_MODE** or **--sets-mode** *NEW_MODE*
Change the current mode to *NEW_MODE* after this binding is executed
@@ -106,6 +99,12 @@ The following options are available:
**-s** or **--silent**
Silences some of the error messages, including for unknown key names and unbound sequences.
**-k KEY_NAME** or **--key KEY_NAME**
This looks up KEY_NAME in terminfo and binds that sequence instead of a key that fish would decode.
To view a list of the terminfo keys fish knows about, use ``bind --key-names`` or ``bind -K``.
This is deprecated and provided for compatibility with older fish versions. You should bind the keys directly.
Instead of ``bind -k sright`` use ``bind shift-right``, instead of ``bind -k nul`` use ``bind ctrl-space`` and so on.
**-h** or **--help**
Displays help about using this command.
@@ -169,7 +168,7 @@ The following special input functions are available:
start selecting text
``cancel``
close the pager if it is open, or undo the most recent completion if one was just inserted
close the pager if it is open, or undo the most recent completion if one was just inserted, or otherwise cancel the current commandline and replace it with a new empty one
``cancel-commandline``
cancel the current commandline and replace it with a new empty one, leaving the old one in place with a marker to show that it was cancelled
@@ -181,10 +180,7 @@ The following special input functions are available:
empty the entire commandline
``clear-screen``
clears the screen and redraws the prompt.
``scrollback-push``
pushes earlier output to the terminal scrollback, positioning the prompt at the top.
clears the screen and redraws the prompt. if the terminal doesn't support clearing the screen it is the same as ``repaint``.
``complete``
guess the remainder of the current token
@@ -250,7 +246,7 @@ The following special input functions are available:
``history-pager``
invoke the searchable pager on history (incremental search); or if the history pager is already active, search further backwards in time.
``history-delete``
``history-pager-delete``
permanently delete the current history item, either from the history pager or from an active up-arrow history search
``history-search-backward``
@@ -271,12 +267,6 @@ The following special input functions are available:
``history-token-search-forward``
search the history for the next matching argument
``history-last-token-search-backward``
search the history for the previous matching last argument
``history-last-token-search-forward``
search the history for the next matching last argument
``forward-jump`` and ``backward-jump``
read another character and jump to its next occurrence after/before the cursor
@@ -425,24 +415,6 @@ Launch ``git diff`` and repaint the commandline afterwards when :kbd:`ctrl-g` is
bind ctrl-g 'git diff' repaint
Swap :kbd:`tab` and :kbd:`shift-tab`, making tab focus the search field.
But if the search field is already active, keep the behavior (:kbd:`tab` cycles forward, :kbd:`shift-tab` backward).::
bind tab '
if commandline --search-field >/dev/null
commandline -f complete
else
commandline -f complete-and-search
end
'
bind shift-tab '
if commandline --search-field >/dev/null
commandline -f complete-and-search
else
commandline -f complete
end
'
.. _cmd-bind-termlimits:
Terminal Limitations

View File

@@ -45,9 +45,8 @@ The following options change the way ``commandline`` updates the command line bu
**-a** or **--append**
Do not remove the current commandline, append the specified string at the end of it.
**-i**, **--insert** or **--insert-smart**
Do not remove the current commandline, insert the specified string at the current cursor position.
The **--insert-smart** option turns on a Do-What-I-Mean (DWIM) mode: it strips any **$** prefix from the first command on each line.
**-i** or **--insert**
Do not remove the current commandline, insert the specified string at the current cursor position
**-r** or **--replace**
Remove the current commandline and replace it with the specified string (default)
@@ -74,9 +73,6 @@ The following options change what part of the commandline is printed or updated:
**--search-field**
Use the pager search field instead of the command line. Returns false if the search field is not shown.
**--input=INPUT**
Operate on this string instead of the commandline. Useful for using options like **--tokens-expanded**.
The following options change the way ``commandline`` prints the current commandline buffer:
**-c** or **--cut-at-cursor**
@@ -90,7 +86,10 @@ The following options change the way ``commandline`` prints the current commandl
Perform argument expansion on the selection and print one argument per line.
Command substitutions are not expanded but forwarded as-is.
**-o**, **tokenize**, **--tokens-raw**
**--tokens-raw**
Print arguments in the selection as they appear on the command line, one per line.
**-o** or **tokenize**
Deprecated; do not use.
If ``commandline`` is called during a call to complete a given string using ``complete -C STRING``, ``commandline`` will consider the specified string to be the current contents of the command line.

View File

@@ -63,9 +63,7 @@ The following options are available:
Add a description for this completion, to be shown in the completion pager.
**-w** or **--wraps** *WRAPPED_COMMAND*
Causes the specified command to inherit completions from *WRAPPED_COMMAND*.
This is used for "this command completes like that other command" kinds of relationships.
See below for details.
Causes the specified command to inherit completions from *WRAPPED_COMMAND* (see below for details).
**-n** or **--condition** *CONDITION*
This completion should only be used if the *CONDITION* (a shell command) returns 0. This makes it possible to specify completions that should only be used in some cases. If multiple conditions are specified, fish will try them in the order they are specified until one fails or all succeeded.

View File

@@ -24,8 +24,7 @@ The :ref:`tutorial <tutorial>` is available as HTML via ``help tutorial`` or in
The following options are available:
**-c** or **--command=COMMAND**
Evaluate the specified commands instead of reading from the commandline.
Any additional positional arguments are used as ``$argv``.
Evaluate the specified commands instead of reading from the commandline, passing additional positional arguments through ``$argv``.
**-C** or **--init-command=COMMANDS**
Evaluate specified commands after reading the configuration but before executing command specified by **-c** or reading interactive input.
@@ -41,6 +40,12 @@ The following options are available:
**-i** or **--interactive**
The shell is interactive.
**--install[=PATH]**
When built as self-installable (via cargo), this will unpack fish's data files and place them in ``~/.local/share/fish/install/``.
fish will also ask to do this automatically when run interactively.
If PATH is given, fish will install itself into a relocatable directory tree rooted at that path.
That means it will install the data files to PATH/share/fish and copy itself to PATH/bin/fish.
**-l** or **--login**
Act as if invoked as a login shell.
@@ -101,33 +106,3 @@ These options can also be changed via the :envvar:`FISH_DEBUG` and :envvar:`FISH
The categories enabled via **--debug** are *added* to the ones enabled by $FISH_DEBUG, so they can be disabled by prefixing them with **-** (**reader-*,-ast*** enables reader debugging and disables ast debugging).
The file given in **--debug-output** takes precedence over the file in :envvar:`FISH_DEBUG_OUTPUT`.
Examples
--------
To just start fish::
fish
To run a file with fish::
fish /path/to/script.fish
To run some commands with fish::
fish -c 'echo Hi there!'
You can also pass arguments to those commands::
> fish -c 'printf %s\n $argv' "first line" "second line"
first line
second line
To run a script, except read this other file first::
fish --init-cmd "source otherfile" script.fish
To :ref:`profile <profiling>` fish's startup and find what takes the most time in your configuration::
fish --profile-startup /tmp/start.prof -ic exit
sort -nk2 /tmp/start.prof

View File

@@ -29,7 +29,6 @@ Currently supported are:
- ``wl-copy`` using wayland
- ``xsel`` and ``xclip`` for X11
- ``clip.exe`` on Windows.
- The OSC 52 clipboard sequence, which your terminal might support
See also
--------

View File

@@ -8,7 +8,7 @@ Synopsis
.. synopsis::
fish_git_prompt [FORMAT]
fish_git_prompt
::
@@ -24,8 +24,6 @@ The ``fish_git_prompt`` function displays information about the current git repo
`Git <https://git-scm.com>`_ must be installed.
It is possible to modify the output format by passing an argument. The default value is ``" (%s)"``.
There are numerous customization options, which can be controlled with git options or fish variables. git options, where available, take precedence over the fish variable with the same function. git options can be set on a per-repository or global basis. git options can be set with the ``git config`` command, while fish variables can be set as usual with the :doc:`set <set>` command.
Boolean options (those which enable or disable something) understand "1", "yes" or "true" to mean true and every other value to mean false.

View File

@@ -38,7 +38,7 @@ The following options are available:
Displays the current :program:`fish` version and then exits.
**--ansi**
Colorizes the output using ANSI escape sequences using the colors defined in the environment (such as :envvar:`fish_color_command`).
Colorizes the output using ANSI escape sequences, appropriate for the current :envvar:`TERM`, using the colors defined in the environment (such as :envvar:`fish_color_command`).
**--html**
Outputs HTML, which supports syntax highlighting if the appropriate CSS is defined. The CSS class names are the same as the variable names, such as ``fish_color_command``.

View File

@@ -22,7 +22,7 @@ Description
The ``fish_mode_prompt`` function outputs the mode indicator for use in vi mode.
The default ``fish_mode_prompt`` function will output indicators about the current vi editor mode displayed to the left of the regular prompt. Define your own function to customize the appearance of the mode indicator. The ``$fish_bind_mode variable`` can be used to determine the current mode. It will be one of ``default``, ``insert``, ``replace_one``, ``replace``, or ``visual``.
The default ``fish_mode_prompt`` function will output indicators about the current vi editor mode displayed to the left of the regular prompt. Define your own function to customize the appearance of the mode indicator. The ``$fish_bind_mode variable`` can be used to determine the current mode. It will be one of ``default``, ``insert``, ``replace_one``, or ``visual``.
You can also define an empty ``fish_mode_prompt`` function to remove the vi mode indicators::
@@ -31,8 +31,6 @@ You can also define an empty ``fish_mode_prompt`` function to remove the vi mode
``fish_mode_prompt`` will be executed when the vi mode changes. If it produces any output, it is displayed and used. If it does not, the other prompt functions (:doc:`fish_prompt <fish_prompt>` and :doc:`fish_right_prompt <fish_right_prompt>`) will be executed as well in case they contain a mode display.
If :envvar:`fish_transient_prompt` is set to 1, ``fish_mode_prompt --final-rendering`` is run before executing the commandline.
Example
-------
@@ -51,9 +49,6 @@ Example
case replace_one
set_color --bold green
echo 'R'
case replace
set_color --bold bryellow
echo 'R'
case visual
set_color --bold brmagenta
echo 'V'

View File

@@ -24,8 +24,6 @@ The ``fish_prompt`` function is executed when the prompt is to be shown, and the
The exit status of commands within ``fish_prompt`` will not modify the value of :ref:`$status <variables-status>` outside of the ``fish_prompt`` function.
If :envvar:`fish_transient_prompt` is set to 1, ``fish_prompt --final-rendering`` is run before executing the commandline.
``fish`` ships with a number of example prompts that can be chosen with the ``fish_config`` command.

View File

@@ -20,8 +20,6 @@ Description
Multiple lines are not supported in ``fish_right_prompt``.
If :envvar:`fish_transient_prompt` is set to 1, ``fish_right_prompt --final-rendering`` is run before executing the commandline.
Example
-------

View File

@@ -27,11 +27,7 @@ The following options are available:
A description of what the function does, suitable as a completion description.
**-w** *WRAPPED_COMMAND* or **--wraps** *WRAPPED_COMMAND*
Inherit completions from the given *WRAPPED_COMMAND*.
This is used to say that this function completes like that command,
for example if you're creating an alias.
See the documentation for :doc:`complete <complete>` for more information.
If the wrapped command is the same as the function name, this will be ignored.
Inherit completions from the given *WRAPPED_COMMAND*. See the documentation for :doc:`complete <complete>` for more information.
**-e** *EVENT_NAME* or **--on-event** *EVENT_NAME*
Run this function when the specified named event is emitted. Fish internally generates named events, for example, when showing the prompt. Custom events can be emitted using the :doc:`emit <emit>` command.

View File

@@ -27,10 +27,10 @@ Description
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 unless you use the ``--reverse`` flag. If stdout is attached to a tty the output will be piped through your pager by the history function. The history builtin writes the results to stdout.
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 unless you use the ``--reverse`` flag. 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.
**delete**
Deletes history items. The ``--contains`` search option will be used if you don't specify a different search option. If you don't specify ``--exact`` a prompt will be displayed before any items are deleted asking you which entries are to be deleted. You can enter the word "all" to delete all matching entries. You can enter a single ID (the number in square brackets) to delete just that single entry. You can enter more than one ID, or an ID range separated by a space to delete multiple entries. Press [enter] to not delete anything. Note that the interactive delete behavior is a feature of the history function. The history builtin only supports ``--exact --case-sensitive`` deletion.
Deletes history items. The ``--contains`` search option will be used if you don't specify a different search option. If you don't specify ``--exact`` a prompt will be displayed before any items are deleted asking you which entries are to be deleted. You can enter the word "all" to delete all matching entries. You can enter a single ID (the number in square brackets) to delete just that single entry. You can enter more than one ID, or an ID range separated by a space to delete multiple entries. Just press [enter] to not delete anything. Note that the interactive delete behavior is a feature of the history function. The history builtin only supports ``--exact --case-sensitive`` deletion.
**merge**
Immediately incorporates history changes from other sessions. Ordinarily ``fish`` ignores history changes from sessions started after the current one. This command applies those changes immediately.
@@ -52,7 +52,7 @@ The following options are available:
These flags can appear before or immediately after one of the sub-commands listed above.
**-C** or **--case-sensitive**
Does a case-sensitive search. The default is case-insensitive.
Does a case-sensitive search. The default is case-insensitive. Note that prior to fish 2.4.0 the default was case-sensitive.
**-c** or **--contains**
Searches items in the history that contain the specified text string. This is the default for the **--search** flag. This is not currently supported by the **delete** subcommand.

View File

@@ -13,7 +13,7 @@ Synopsis
path extension GENERAL_OPTIONS [PATH ...]
path filter GENERAL_OPTIONS [-v | --invert]
[-d] [-f] [-l] [-r] [-w] [-x]
[(-t | --type) TYPE] [(-p | --perm) PERMISSION] [--all] [PATH ...]
[(-t | --type) TYPE] [(-p | --perm) PERMISSION] [PATH ...]
path is GENERAL_OPTIONS [(-v | --invert)] [(-t | --type) TYPE]
[-d] [-f] [-l] [-r] [-w] [-x]
[(-p | --perm) PERMISSION] [PATH ...]
@@ -22,7 +22,7 @@ Synopsis
path resolve GENERAL_OPTIONS [PATH ...]
path change-extension GENERAL_OPTIONS EXTENSION [PATH ...]
path sort GENERAL_OPTIONS [-r | --reverse]
[-u | --unique] [--key=(basename | dirname | path)] [PATH ...]
[-u | --unique] [--key=basename|dirname|path] [PATH ...]
GENERAL_OPTIONS
[-z | --null-in] [-Z | --null-out] [-q | --quiet]
@@ -148,7 +148,7 @@ Examples
> echo $path$extension
# reconstructs the original path again.
./foo.mp4
.. _cmd-path-filter:
"filter" subcommand
@@ -158,7 +158,7 @@ Examples
path filter [-z | --null-in] [-Z | --null-out] [-q | --quiet] \
[-d] [-f] [-l] [-r] [-w] [-x] \
[-v | --invert] [(-t | --type) TYPE] [(-p | --perm) PERMISSION] [--all] [PATH ...]
[-v | --invert] [(-t | --type) TYPE] [(-p | --perm) PERMISSION] [PATH ...]
``path filter`` returns all of the given paths that match the given checks. In all cases, the paths need to exist, nonexistent paths are always filtered.
@@ -180,10 +180,6 @@ When a path starts with ``-``, ``path filter`` will prepend ``./`` to avoid it b
It returns 0 if at least one path passed the filter.
With ``--all``, return status 0 (true) if all paths pass the filter, and status 1 (false) if any path fails. This is equivalent to ``not path filter -v``. It produces no output, only a status.
When ``--all`` combined with ``--invert``, it returns status 0 (true) if all paths fail the filter and status 1 (false) if any path passes.
``path is`` is shorthand for ``path filter -q``, i.e. just checking without producing output, see :ref:`The is subcommand <cmd-path-is>`.
Examples
@@ -215,9 +211,6 @@ Examples
>_ path filter -fx $PATH/*
# Prints all possible commands - the first entry of each name is what fish would execute!
>_ path filter --all /usr/bin /usr/argagagji
# This returns 1 (false) because not all paths pass the filter.
.. _cmd-path-is:
"is" subcommand
@@ -353,7 +346,7 @@ Examples
path change-extension [-z | --null-in] [-Z | --null-out] \
[-q | --quiet] EXTENSION [PATH ...]
``path change-extension`` returns the given paths, with their extension changed to the given new extension. The extension is the part after (and including) the last ".", unless that "." followed a "/" or the basename is "." or "..", in which case there is no previous extension and the new one is added.
``path change-extension`` returns the given paths, with their extension changed to the given new extension. The extension is the part after (and including) the last ".", unless that "." followed a "/" or the basename is "." or "..", in which case there is no previous extension and the new one is simply added.
If the extension is empty, any previous extension is stripped, along with the ".". This is, of course, the inverse of ``path extension``.

View File

@@ -101,7 +101,7 @@ If no option to determine how to split like ``--delimiter``, ``--line`` or ``--t
With the ``--line`` option, ``read`` reads a line of input from standard input into each provided variable, stopping when each variable has been filled. The line is not tokenized.
If no variable names are provided, ``read`` enters a special case that provides redirection from standard input to standard output, useful for command substitution. For instance, the fish shell command below can be used to read a password from the console instead of hardcoding it in the command itself, which prevents it from showing up in fish's history::
If no variable names are provided, ``read`` enters a special case that simply provides redirection from standard input to standard output, useful for command substitution. For instance, the fish shell command below can be used to read a password from the console instead of hardcoding it in the command itself, which prevents it from showing up in fish's history::
mysql -uuser -p(read)

View File

@@ -22,25 +22,15 @@ Valid colors include:
The *br*- (as in 'bright') forms are full-brightness variants of the 8 standard-brightness colors on many terminals. **brblack** has higher brightness than **black** - towards gray.
An RGB value with three or six hex digits, such as A0FF33 or f2f can be used.
A three digit value is equivalent to specifying each digit twice; e.g., ``set_color 2BC`` is the same as ``set_color 22BBCC``.
Hexadecimal RGB values can be in lower or uppercase.
An RGB value with three or six hex digits, such as A0FF33 or f2f can be used. Fish will choose the closest supported color. A three digit value is equivalent to specifying each digit twice; e.g., ``set_color 2BC`` is the same as ``set_color 22BBCC``. Hexadecimal RGB values can be in lower or uppercase. Depending on the capabilities of your terminal (and the level of support ``set_color`` has for it) the actual color may be approximated by a nearby matching reserved color name or ``set_color`` may not have an effect on color.
If :envvar:`fish_term24bit` is set to 0, fish will translate RGB values to the nearest color on the 256-color palette.
If :envvar:`fish_term256` is also set to 0, fish will translate them to the 16-color palette instead.
Fish launched as ``fish -d term_support`` will include diagnostic messages that indicate the color support mode in use.
If multiple colors are specified, fish prefers the first RGB one.
However if :envvar:`fish_term256` is set to 0, fish prefers the first named color specified.
A second color may be given as a desired fallback color. e.g. ``set_color 124212 brblue`` will instruct set_color to use *brblue* if a terminal is not capable of the exact shade of grey desired. This is very useful when an 8 or 16 color terminal might otherwise not use a color.
The following options are available:
**-b** or **--background** *COLOR*
Sets the background color.
**--underline-color** *COLOR*
Set the underline color.
**-c** or **--print-colors**
Prints the given colors or a colored list of the 16 named colors.
@@ -56,16 +46,18 @@ The following options are available:
**-r** or **--reverse**
Sets reverse mode.
**-u** or **--underline**, or **-uSTYLE** or **--underline=STYLE**
Set the underline mode; supported styles are **single** (default), **double**, **curly**, **dotted** and **dashed**.
**-u** or **--underline**
Sets underlined mode.
**-h** or **--help**
Displays help about using this command.
Using the **normal** keyword will reset foreground, background, and all formatting back to default.
Notes
-----
1. Using **set_color normal** will reset all colors and modes to the terminal's default.
1. Using the **normal** keyword will reset both background and foreground colors to whatever is the default for the terminal.
2. Setting the background color only affects subsequently written characters. Fish provides no way to set the background color for the entire terminal window. Configuring the window background color (and other attributes such as its opacity) has to be done using whatever mechanisms the terminal provides. Look for a config option.
3. Some terminals use the ``--bold`` escape sequence to switch to a brighter color set rather than increasing the weight of text.
4. ``set_color`` works by printing sequences of characters to standard output. If used in command substitution or a pipe, these characters will also be captured. This may or may not be desirable. Checking the exit status of ``isatty stdout`` before using ``set_color`` can be useful to decide not to colorize output in a script.
@@ -80,3 +72,24 @@ Examples
set_color blue; echo "Violets are blue"
set_color 62A; echo "Eggplants are dark purple"
set_color normal; echo "Normal is nice" # Resets the background too
Terminal Capability Detection
-----------------------------
Fish uses some heuristics to determine what colors a terminal supports to avoid sending sequences that it won't understand.
In particular it will:
- Enable 256 colors if :envvar:`TERM` contains "xterm", except for known exceptions (like MacOS 10.6 Terminal.app)
- Enable 24-bit ("true-color") even if the $TERM entry only reports 256 colors. This includes modern xterm, VTE-based terminals like Gnome Terminal, Konsole and iTerm2.
- Detect support for italics, dim, reverse and other modes.
If terminfo reports 256 color support for a terminal, 256 color support will always be enabled.
To force true-color support on or off, set :envvar:`fish_term24bit` to "1" for on and 0 for off - ``set -g fish_term24bit 1``.
To debug color palette problems, ``tput colors`` may be useful to see the number of colors in terminfo for a terminal. Fish launched as ``fish -d term_support`` will include diagnostic messages that indicate the color support mode in use.
The ``set_color`` command uses the terminfo database to look up how to change terminal colors on whatever terminal is in use. Some systems have old and incomplete terminfo databases, and lack color information for terminals that support it. Fish assumes that all terminals can use the `ANSI X3.64 <https://en.wikipedia.org/wiki/ANSI_escape_code>`_ escape sequences if the terminfo definition indicates a color below 16 is not supported.

View File

@@ -41,3 +41,8 @@ Example
source ~/.config/fish/config.fish
# Causes fish to re-read its initialization file.
Caveats
-------
In fish versions prior to 2.3.0, the :envvar:`argv` variable would have a single element (the name of the sourced file) if no arguments are present. Otherwise, it would contain arguments without the name of the sourced file. That behavior was very confusing and unlike other shells such as bash and zsh.

View File

@@ -31,8 +31,6 @@ Synopsis
status features
status test-feature FEATURE
status buildinfo
status get-file FILE
status list-files [PATH]
Description
-----------
@@ -108,15 +106,6 @@ The following operations (subcommands) are available:
This prints information on how fish was build - which architecture, which build system or profile was used, etc.
This is mainly useful for debugging.
**get-file** *FILE*
This prints a file embedded in the fish binary at compile time. This includes the default set of functions and completions,
as well as the man pages and themes. Which files are included depends on build settings.
Returns 0 if the file was included, 1 otherwise.
**list-files** *FILE*
This lists the files embedded in the fish binary at compile time. Only files where the path starts with the optional *FILE* argument are shown.
Returns 0 if something was printed, 1 otherwise.
Notes
-----

View File

@@ -8,8 +8,8 @@ Synopsis
.. synopsis::
string join [-q | --quiet] [-n | --no-empty] [--] SEP [STRING ...]
string join0 [-q | --quiet] [-n | --no-empty] [--] [STRING ...]
string join [-q | --quiet] SEP [STRING ...]
string join0 [-q | --quiet] [STRING ...]
.. END SYNOPSIS
@@ -18,28 +18,11 @@ Description
.. BEGIN DESCRIPTION
Joins its *STRING* arguments into a single string separated by *SEP* (for ``string join``) or by the
zero byte (NUL) (for ``string join0``).
Exit status: 0 if at least one join was performed, or 1 otherwise.
``string join`` joins its *STRING* arguments into a single string separated by *SEP*, which can be an empty string. Exit status: 0 if at least one join was performed, or 1 otherwise. If ``-n`` or ``--no-empty`` is specified, empty strings are excluded from consideration (e.g. ``string join -n + a b "" c`` would expand to ``a+b+c`` not ``a+b++c``).
**-n**, **--no-empty**
Exclude empty strings from consideration (e.g. ``string join -n + a b "" c`` would expand to ``a+b+c`` not ``a+b++c``).
``string join0`` joins its *STRING* arguments into a single string separated by the zero byte (NUL), and adds a trailing NUL. This is most useful in conjunction with tools that accept NUL-delimited input, such as ``sort -z``. Exit status: 0 if at least one join was performed, or 1 otherwise.
**-q**, **--quiet**
Do not print the strings, only set the exit status as described above.
**WARNING**:
Insert a ``--`` before positional arguments to prevent them from being interpreted as flags.
Otherwise, any strings starting with ``-`` will be treated as flag arguments, meaning they will most likely result in the command failing.
This is also true if you specify a variable which expands to such a string instead of a literal string.
If you don't need to append flag arguments at the end of the command,
just always use ``--`` to avoid unwelcome surprises.
``string join0`` adds a trailing NUL. This is most useful in conjunction with tools that accept NUL-delimited input, such as ``sort -z``.
Because Unix uses NUL as the string terminator, passing the output of ``string join0`` as an *argument* to a command (via a :ref:`command substitution <expand-command-substitution>`) won't actually work.
Fish will pass the correct bytes along, but the command won't be able to tell where the argument ends.
This is a limitation of Unix' argument passing.
Because Unix uses NUL as the string terminator, passing the output of ``string join0`` as an *argument* to a command (via a :ref:`command substitution <expand-command-substitution>`) won't actually work. Fish will pass the correct bytes along, but the command won't be able to tell where the argument ends. This is a limitation of Unix' argument passing.
.. END DESCRIPTION
@@ -60,14 +43,4 @@ Examples
>_ string join '' a b c
abc
>_ set -l markdown_list '- first' '- second' '- third'
# Strings with leading hyphens (also in variable expansions) are interpreted as flag arguments by default.
>_ string join \n $markdown_list
string join: - first: unknown option
# Use '--' to prevent this.
>_ string join -- \n $markdown_list
- first
- second
- third
.. END EXAMPLES

View File

@@ -22,11 +22,11 @@ Description
``string match`` tests each *STRING* against *PATTERN* and prints matching substrings. Only the first match for each *STRING* is reported unless **-a** or **--all** is given, in which case all matches are reported.
If you specify the **-e** or **--entire** then each matching string is printed including any prefix or suffix not matched by the pattern (equivalent to ``grep`` without the **-o** flag). You can, obviously, achieve the same result by prepending and appending **\*** or **.*** depending on whether or not you have specified the **--regex** flag. The **--entire** flag is a way to avoid having to complicate the pattern in that fashion and make the intent of the ``string match`` clearer. Without **--entire** and **--regex**, a *PATTERN* will need to match the entire *STRING* before it will be reported.
If you specify the **-e** or **--entire** then each matching string is printed including any prefix or suffix not matched by the pattern (equivalent to ``grep`` without the **-o** flag). You can, obviously, achieve the same result by prepending and appending **\*** or **.*** depending on whether or not you have specified the **--regex** flag. The **--entire** flag is simply a way to avoid having to complicate the pattern in that fashion and make the intent of the ``string match`` clearer. Without **--entire** and **--regex**, a *PATTERN* will need to match the entire *STRING* before it will be reported.
Matching can be made case-insensitive with **--ignore-case** or **-i**.
If **--groups-only** or **-g** is given, only the capturing groups will be reported - meaning the full match will be skipped. This is incompatible with **--entire** and **--invert**, and requires **--regex**. It is useful as a simple cutting tool instead of ``string replace``, so you can choose "this part" of a string.
If **--groups-only** or **-g** is given, only the capturing groups will be reported - meaning the full match will be skipped. This is incompatible with **--entire** and **--invert**, and requires **--regex**. It is useful as a simple cutting tool instead of ``string replace``, so you can simply choose "this part" of a string.
If **--index** or **-n** is given, each match is reported as a 1-based start position and a length. By default, PATTERN is interpreted as a glob pattern matched against each entire *STRING* argument. A glob pattern is only considered a valid match if it matches the entire *STRING*.

View File

@@ -30,7 +30,6 @@ See also the **--delimiter** option of the :doc:`read <read>` command.
``split0`` has the important property that its output is not further split when used in a command substitution, allowing for the command substitution to produce elements containing newlines. This is most useful when used with Unix tools that produce zero bytes, such as ``find -print0`` or ``sort -z``. See split0 examples below.
Be aware that commandline arguments cannot include NULs, so you likely want to pass to ``string split0`` via a pipe, not a command substitution.
.. END DESCRIPTION
@@ -66,7 +65,6 @@ NUL Delimited Examples
::
>_ # Count files in a directory, without being confused by newlines.
>_ # Note: Don't use `string split0 (find . -print0)`, because arguments cannot include NUL.
>_ count (find . -print0 | string split0)
42

View File

@@ -11,7 +11,7 @@ Synopsis
string collect [-a | --allow-empty] [-N | --no-trim-newlines] [STRING ...]
string escape [-n | --no-quoted] [--style=] [STRING ...]
string join [-q | --quiet] [-n | --no-empty] SEP [STRING ...]
string join0 [-q | --quiet] [-n | --no-empty] [STRING ...]
string join0 [-q | --quiet] [STRING ...]
string length [-q | --quiet] [STRING ...]
string lower [-q | --quiet] [STRING ...]
string match [-a | --all] [-e | --entire] [-i | --ignore-case]
@@ -27,7 +27,7 @@ Synopsis
[-r | --regex] [-q | --quiet] PATTERN REPLACE [STRING ...]
string shorten [(-c | --char) CHARS] [(-m | --max) INTEGER]
[-N | --no-newline] [-l | --left] [-q | --quiet] [STRING ...]
string split [(-f | --fields) FIELDS] [(-m | --max) MAX] [-n | --no-empty]
string split [(-f | --fields) FIELDS] [(-m | --max) MAX] [-n | --no-empty]
[-q | --quiet] [-r | --right] SEP [STRING ...]
string split0 [(-f | --fields) FIELDS] [(-m | --max) MAX] [-n | --no-empty]
[-q | --quiet] [-r | --right] [STRING ...]

View File

@@ -203,7 +203,7 @@ Parentheses and the ``-o`` and ``-a`` operators can be combined to produce more
end
Numerical comparisons will fail if one of the operands is not a number:
Numerical comparisons will simply fail if one of the operands is not a number:
::

View File

@@ -10,9 +10,19 @@ import glob
import os.path
import subprocess
import sys
from sphinx.highlighting import lexers
from sphinx.errors import SphinxWarning
from docutils import nodes
try:
import sphinx_markdown_builder
extensions = [
"sphinx_markdown_builder",
]
except ImportError:
pass
# -- Helper functions --------------------------------------------------------
@@ -35,11 +45,14 @@ def issue_role(name, rawtext, text, lineno, inliner, options=None, content=None)
return [link], []
def remove_fish_indent_lexer(app):
if app.builder.name in ("man", "markdown"):
del lexers["fish-docs-samples"]
# -- Load our extensions -------------------------------------------------
def setup(app):
# Our own pygments lexers
from sphinx.highlighting import lexers
this_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.insert(0, this_dir)
from fish_indent_lexer import FishIndentLexer
@@ -52,6 +65,8 @@ def setup(app):
app.add_config_value("issue_url", default=None, rebuild="html")
app.add_role("issue", issue_role)
app.connect("builder-inited", remove_fish_indent_lexer)
# The default language to assume
highlight_language = "fish-docs-samples"
@@ -72,7 +87,7 @@ elif "FISH_BUILD_VERSION" in os.environ:
ret = os.environ["FISH_BUILD_VERSION"]
else:
ret = subprocess.check_output(
("fish_indent", "--version"), stderr=subprocess.STDOUT
("../build_tools/git_version_gen.sh", "--stdout"), stderr=subprocess.STDOUT
).decode("utf-8")
# The full version, including alpha/beta/rc tags
@@ -195,7 +210,6 @@ man_pages = [
("language", "fish-language", "", [author], 1),
("interactive", "fish-interactive", "", [author], 1),
("relnotes", "fish-releasenotes", "", [author], 1),
("terminal-compatibility", "fish-terminal-compatibility", "", [author], 1),
("completions", "fish-completions", "", [author], 1),
("prompt", "fish-prompt-tutorial", "", [author], 1),
(

View File

@@ -13,7 +13,7 @@ Use the :doc:`set <cmds/set>` command::
set -x key value # typically set -gx key value
set -e key
Since fish 3.1 you can set an environment variable for one command using the ``key=value some command`` syntax, like in other shells. The two lines below behave identically - unlike other shells, fish will output ``value`` both times::
Since fish 3.1 you can set an environment variable for just one command using the ``key=value some command`` syntax, like in other shells. The two lines below behave identically - unlike other shells, fish will output ``value`` both times::
key=value echo $key
begin; set -lx key value; echo $key; end
@@ -162,11 +162,11 @@ Why doesn't history substitution ("!$" etc.) work?
--------------------------------------------------
Because history substitution is an awkward interface that was invented before interactive line editing was even possible. Instead of adding this pseudo-syntax, fish opts for nice history searching and recall features. Switching requires a small change of habits: if you want to modify an old line/word, first recall it, then edit.
As a special case, most of the time history substitution is used as ``sudo !!``. In that case press :kbd:`alt-s`, and it will recall your last commandline with ``sudo`` prefixed (or toggle a ``sudo`` prefix on the current commandline if there is anything).
As a special case, most of the time history substitution is used as ``sudo !!``. In that case just press :kbd:`alt-s`, and it will recall your last commandline with ``sudo`` prefixed (or toggle a ``sudo`` prefix on the current commandline if there is anything).
In general, fish's history recall works like this:
- Like other shells, the Up arrow, ``up`` recalls whole lines, starting from the last executed line. So instead of typing ``!!``, you would hit the up-arrow.
- Like other shells, the Up arrow, ``up`` recalls whole lines, starting from the last executed line. So instead of typing ``!!``, you would just hit the up-arrow.
- If the line you want is far back in the history, type any part of the line and then press Up one or more times. This will filter the recalled lines to ones that include this text, and you will get to the line you want much faster. This replaces "!vi", "!?bar.c" and the like. If you want to see more context, you can press ``ctrl-r`` to open the history in the pager.
@@ -174,7 +174,7 @@ In general, fish's history recall works like this:
See :ref:`documentation <editor>` for more details about line editing in fish.
That being said, you can use :ref:`abbreviations` to implement history substitution. Here's ``!!`` only::
That being said, you can use :ref:`abbreviations` to implement history substitution. Here's just ``!!``::
function last_history_item; echo $history[1]; end
abbr -a !! --position anywhere --function last_history_item
@@ -232,7 +232,7 @@ Use the ``$status`` variable. This replaces the ``$?`` variable used in other sh
end
If you are only interested in success or failure, you can run the command directly as the if-condition::
If you are just interested in success or failure, you can run the command directly as the if-condition::
if somecommand
echo "Command succeeded"
@@ -330,7 +330,7 @@ This is more important to fish than other shells because features like syntax hi
Sometimes, there is disagreement on the width. There are numerous causes and fixes for this:
- It is possible the character is too new for your system to know - in this case you need to refrain from using it.
- It is possible the character is simply too new for your system to know - in this case you need to refrain from using it.
- Fish or your terminal might not know about the character or handle it wrong - in this case fish or your terminal needs to be fixed, or you need to update to a fixed version.
- The character has an "ambiguous" width and fish thinks that means a width of X while your terminal thinks it's Y. In this case you either need to change your terminal's configuration or set $fish_ambiguous_width to the correct value.
- The character is an emoji and the host system only supports Unicode 8, while you are running the terminal on a system that uses Unicode >= 9. In this case set $fish_emoji_width to 2.
@@ -340,21 +340,13 @@ This also means that a few things are unsupportable:
- Non-monospace fonts - there is *no way* for fish to figure out what width a specific character has as it has no influence on the terminal's font rendering.
- Different widths for multiple ambiguous width characters - there is no way for fish to know which width you assign to each character.
.. _faq-terminal-compatibility:
fish does not work in a specific terminal
-----------------------------------------
The terminal might not meet all of :doc:`fish's requirements <terminal-compatibility>`.
Please report this to your terminal's and to fish's issue tracker.
.. _faq-uninstalling:
Uninstalling fish
-----------------
If you want to uninstall fish, first make sure fish is not set as your shell. Run ``chsh -s /bin/bash`` if you are not sure.
If you installed it with a package manager, use that package manager's uninstall function. If you built fish yourself, assuming you installed it to /usr/local, do this::
If you installed it with a package manager, just use that package manager's uninstall function. If you built fish yourself, assuming you installed it to /usr/local, do this::
rm -Rf /usr/local/etc/fish /usr/local/share/fish ~/.config/fish
rm /usr/local/share/man/man1/fish*.1

View File

@@ -192,7 +192,7 @@ Note that both of these are bashisms, and most things can easily be expressed wi
source (command | psub)
Use::
just use::
command | source
@@ -246,7 +246,7 @@ is mostly the same as
foo
EOF
Like with heredocs, the command has to be prepared to read from stdin. Sometimes this requires special options to be used, often giving a filename of ``-`` turns it on.
Just like with heredocs, the command has to be prepared to read from stdin. Sometimes this requires special options to be used, often giving a filename of ``-`` turns it on.
For example::
@@ -266,7 +266,7 @@ and could be written in other shells as
rxvt-unicode
EOF
So heredocs really are minor syntactical sugar that introduces a lot of special rules, which is why fish doesn't have them. Pipes are a core concept, and are simpler and compose nicer.
So heredocs really are just minor syntactical sugar that introduces a lot of special rules, which is why fish doesn't have them. Pipes are a core concept, and are simpler and compose nicer.
.. [#] For example, the "EOF" is just a convention, the terminator can be an arbitrary string, something like "THISISTHEEND" also works. And using ``<<-`` trims leading *tab* characters (but not other whitespace), so you can indent the lines, but only with tabs. Substitutions (variables, commands) are done on the heredoc by default, but not if the terminator is quoted: ``cat << "EOF"``.
@@ -326,7 +326,7 @@ and a rough fish equivalent::
This shows a few differences:
- Fish provides :doc:`set_color <cmds/set_color>` to color text. It can use the 16 named colors and also RGB sequences (so you could also use ``set_color 5555FF``)
- Instead of introducing specific escapes like ``\h`` for the hostname, the prompt is a function. To achieve the effect of ``\h``, fish provides helper functions like :doc:`prompt_hostname <cmds/prompt_hostname>`, which prints a shortened version of the hostname.
- Instead of introducing specific escapes like ``\h`` for the hostname, the prompt is simply a function. To achieve the effect of ``\h``, fish provides helper functions like :doc:`prompt_hostname <cmds/prompt_hostname>`, which prints a shortened version of the hostname.
- Fish offers other helper functions for adding things to the prompt, like :doc:`fish_vcs_prompt <cmds/fish_vcs_prompt>` for adding a display for common version control systems (git, mercurial, svn), and :doc:`prompt_pwd <cmds/prompt_pwd>` for showing a shortened ``$PWD`` (the user's home directory becomes ``~`` and any path component is shortened).
The default prompt is reasonably full-featured and its code can be read via ``type fish_prompt``.
@@ -417,7 +417,7 @@ This includes things like:
baz &
done
Fish does not currently have subshells. You will have to find a different solution. The isolation can usually be achieved by scoping variables (with ``set -l``), but if you really do need to run your code in a new shell environment you can use ``fish -c 'your code here'`` to do so explicitly.
Fish does not currently have subshells. You will have to find a different solution. The isolation can usually be achieved by just scoping variables (with ``set -l``), but if you really do need to run your code in a new shell environment you can use ``fish -c 'your code here'`` to do so explicitly.
``()`` subshells are often confused with ``{}`` grouping, which does *not* use a subshell. When you just need to group, you can use ``begin; end`` in fish::
@@ -427,7 +427,7 @@ Fish does not currently have subshells. You will have to find a different soluti
# becomes
begin; foo; bar; end | baz
The pipe will be run in the same process, so ``while read`` loops can set variables outside::
The pipe will simply be run in the same process, so ``while read`` loops can set variables outside::
foo | while read bar
set -g VAR VAL

View File

@@ -53,7 +53,7 @@ lexer_rules = [
# Hack: treat the "[ expr ]" alias of builtin test as command token (not as grammar
# metacharacter). This works because we write it without spaces in the grammar (like
# "[OPTIONS]").
(r"\. |! |\[ | \]|\{ | \}", Name.Constant),
(r"\. |! |\[ | \]", Name.Constant),
# Statement separators.
(r"\n", Text.Whitespace),
(r";", Punctuation),

View File

@@ -150,7 +150,7 @@ Resources
- The `GitHub page <https://github.com/fish-shell/fish-shell/>`_
- The official `Matrix room <https://matrix.to/#/#fish-shell:matrix.org>`_
- The official `Gitter channel <https://gitter.im/fish-shell/fish-shell>`_
- The official mailing list at `fish-users@lists.sourceforge.net <https://lists.sourceforge.net/lists/listinfo/fish-users>`_
@@ -174,6 +174,5 @@ Other help pages
prompt
design
relnotes
terminal-compatibility
contributing
license

View File

@@ -25,7 +25,7 @@ Autosuggestions
fish suggests commands as you type, based on :ref:`command history <history-search>`, completions, and valid file paths. As you type commands, you will see a suggestion offered after the cursor, in a muted gray color (which can be changed with the ``fish_color_autosuggestion`` variable).
To accept the autosuggestion (replacing the command line contents), press :kbd:`right` (````) or :kbd:`ctrl-f`. To accept the first suggested word, press :kbd:`alt-right` (````) or :kbd:`alt-f`. If the autosuggestion is not what you want, ignore it: it won't execute unless you accept it.
To accept the autosuggestion (replacing the command line contents), press :kbd:`right` (````) or :kbd:`ctrl-f`. To accept the first suggested word, press :kbd:`alt-right` (````) or :kbd:`alt-f`. If the autosuggestion is not what you want, just ignore it: it won't execute unless you accept it.
Autosuggestions are a powerful way to quickly summon frequently entered commands, by typing the first few characters. They are also an efficient technique for navigating through directory hierarchies.
@@ -38,7 +38,7 @@ If you don't like autosuggestions, you can disable them by setting ``$fish_autos
Tab Completion
--------------
Tab completion is a time saving feature of any modern shell. When you type :kbd:`tab`, fish tries to guess the rest of the word under the cursor. If it finds exactly one possibility, it inserts it. If it finds more, it inserts the longest unambiguous part and then opens a menu (the "pager") that you can navigate to find what you're looking for.
Tab completion is a time saving feature of any modern shell. When you type :kbd:`tab`, fish tries to guess the rest of the word under the cursor. If it finds just one possibility, it inserts it. If it finds more, it inserts the longest unambiguous part and then opens a menu (the "pager") that you can navigate to find what you're looking for.
The pager can be navigated with the arrow keys, :kbd:`pageup` / :kbd:`pagedown`, :kbd:`tab` or :kbd:`shift-tab`. Pressing :kbd:`ctrl-s` (the ``pager-toggle-search`` binding - :kbd:`/` in vi mode) opens up a search menu that you can use to filter the list.
@@ -56,7 +56,7 @@ It also provides a large number of program specific scripted completions. Most o
You can also write your own completions or install some you got from someone else. For that, see :ref:`Writing your own completions <completion-own>`.
Completion scripts are loaded on demand, like :ref:`functions are <syntax-function-autoloading>`. The difference is the ``$fish_complete_path`` :ref:`list <variables-lists>` is used instead of ``$fish_function_path``. Typically you can drop new completions in ~/.config/fish/completions/name-of-command.fish and fish will find them automatically.
Completion scripts are loaded on demand, just like :ref:`functions are <syntax-function-autoloading>`. The difference is the ``$fish_complete_path`` :ref:`list <variables-lists>` is used instead of ``$fish_function_path``. Typically you can drop new completions in ~/.config/fish/completions/name-of-command.fish and fish will find them automatically.
.. _color:
@@ -89,16 +89,7 @@ Or, to see all themes, right in your terminal::
Syntax highlighting variables
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The colors used by fish for syntax highlighting can be configured by changing the values of various variables. The value of these variables can be one of the colors accepted by the :doc:`set_color <cmds/set_color>` command.
Options accepted by ``set_color`` like
``--background=``,
``--bold``,
``--dim``,
``--italics``,
``--reverse``,
``--underline`` and
``--underline-color=``
are also accepted.
The colors used by fish for syntax highlighting can be configured by changing the values of various variables. The value of these variables can be one of the colors accepted by the :doc:`set_color <cmds/set_color>` command. The modifier switches accepted by ``set_color`` like ``--bold``, ``--dim``, ``--italics``, ``--reverse`` and ``--underline`` are also accepted.
Example: to make errors highlighted and red, use::
@@ -226,8 +217,6 @@ This prompt is determined by running the :doc:`fish_prompt <cmds/fish_prompt>` a
The output of the former is displayed on the left and the latter's output on the right side of the terminal.
For :ref:`vi mode <vi-mode>`, the output of :doc:`fish_mode_prompt <cmds/fish_mode_prompt>` will be prepended on the left.
If :envvar:`fish_transient_prompt` is set to 1, fish will redraw the prompt with a ``--final-rendering`` argument before running a commandline, allowing you to change it before pushing it to the scrollback.
Fish ships with a few prompts which you can see with :doc:`fish_config <cmds/fish_config>`. If you run just ``fish_config`` it will open a web interface [#]_ where you'll be shown the prompts and can pick which one you want. ``fish_config prompt show`` will show you the prompts right in your terminal.
For example ``fish_config prompt choose disco`` will temporarily select the "disco" prompt. If you like it and decide to keep it, run ``fish_config prompt save``.
@@ -314,11 +303,9 @@ Some bindings are common across Emacs and vi mode, because they aren't text edit
- :kbd:`alt-enter` inserts a newline at the cursor position. This is useful to add a line to a commandline that's already complete.
- :kbd:`alt-left` (````) and :kbd:`alt-right` (````) move the cursor left or right by one argument (or one word on macOS).
If the command line is empty, they move forward/backward in the directory history.
If the cursor is already at the end of the line, and an autosuggestion is available, :kbd:`alt-right` (````) (or :kbd:`alt-f`) accepts the first argument (or word on macOS) in the suggestion.
- :kbd:`alt-left` (````) and :kbd:`alt-right` (````) move the cursor one word left or right (to the next space or punctuation mark), or moves forward/backward in the directory history if the command line is empty. If the cursor is already at the end of the line, and an autosuggestion is available, :kbd:`alt-right` (````) (or :kbd:`alt-f`) accepts the first word in the suggestion.
- :kbd:`ctrl-left` (````) and :kbd:`ctrl-right` (````) move the cursor left or right by one word. These accept one word of the autosuggestion - the part they'd move over.
- :kbd:`ctrl-left` (````) and :kbd:`ctrl-right` (````) move the cursor one word left or right. These accept one word of the autosuggestion - the part they'd move over.
- :kbd:`shift-left` (````) and :kbd:`shift-right` (````) move the cursor one word left or right, without stopping on punctuation. These accept one big word of the autosuggestion.
@@ -338,13 +325,11 @@ Some bindings are common across Emacs and vi mode, because they aren't text edit
- :kbd:`ctrl-x` copies the current buffer to the system's clipboard, :kbd:`ctrl-v` inserts the clipboard contents. (see :doc:`fish_clipboard_copy <cmds/fish_clipboard_copy>` and :doc:`fish_clipboard_paste <cmds/fish_clipboard_paste>`)
- :kbd:`alt-d` moves the next word to the :ref:`killring`.
- :kbd:`ctrl-delete` moves the next word (or next argument on macOS) to the :ref:`killring`.
- :kbd:`alt-d` or :kbd:`ctrl-delete` moves the next word to the :ref:`killring`.
- :kbd:`alt-d` lists the directory history if the command line is empty.
- :kbd:`alt-delete` moves the next argument (or word on macOS) to the :ref:`killring`.
- :kbd:`alt-delete` moves the next argument to the :ref:`killring`.
- :kbd:`shift-delete` removes the current history item or autosuggestion from the command history.
@@ -354,7 +339,7 @@ Some bindings are common across Emacs and vi mode, because they aren't text edit
- :kbd:`alt-o` opens the file at the cursor in a pager. If the cursor is in command position and the command is a script, it will instead open that script in your editor. The editor is chosen from the first available of the ``$VISUAL`` or ``$EDITOR`` variables.
- :kbd:`alt-p` adds the string ``&| less;`` to the end of the job under the cursor. The result is that the output of the command will be paged. If you set the ``PAGER`` variable, its value is used instead of ``less``.
- :kbd:`alt-p` adds the string ``&| less;`` to the end of the job under the cursor. The result is that the output of the command will be paged.
- :kbd:`alt-w` prints a short description of the command under the cursor.
@@ -362,7 +347,7 @@ Some bindings are common across Emacs and vi mode, because they aren't text edit
- :kbd:`alt-v` Same as :kbd:`alt-e`.
- :kbd:`alt-s` Prepends ``sudo`` to the current commandline. If the commandline is empty, prepend ``sudo`` to the last commandline. If ``sudo`` is not installed, various similar commands are tried: ``doas``, ``please``, and ``run0``.
- :kbd:`alt-s` Prepends ``sudo`` to the current commandline. If the commandline is empty, prepend ``sudo`` to the last commandline.
- :kbd:`ctrl-space` Inserts a space without expanding an :ref:`abbreviation <abbreviations>`. For vi mode, this only applies to insert-mode.
@@ -385,8 +370,7 @@ To enable emacs mode, use :doc:`fish_default_key_bindings <cmds/fish_default_key
- :kbd:`delete` or :kbd:`backspace` or :kbd:`ctrl-h` removes one character forwards or backwards respectively.
- :kbd:`ctrl-backspace` removes one word backwards and :kbd:`alt-backspace` removes one argument backwards.
On macOS, it's the other way round.
- :kbd:`alt-backspace` removes one word backwards. If supported by the terminal, :kbd:`ctrl-backspace` does the same.
- :kbd:`alt-<` moves to the beginning of the commandline, :kbd:`alt->` moves to the end.
@@ -507,13 +491,7 @@ Command mode is also known as normal mode.
- :kbd:`backspace` moves the cursor left.
- :kbd:`g,g` / :kbd:`G` moves the cursor to the beginning/end of the commandline, respectively.
- :kbd:`~` toggles the case (upper/lower) of the character and moves to the next character.
- :kbd:`g,u` lowercases to the end of the word.
- :kbd:`g,U` uppercases to the end of the word.
- :kbd:`g` / :kbd:`G` moves the cursor to the beginning/end of the commandline, respectively.
- :kbd:`:,q` exits fish.
@@ -557,10 +535,6 @@ Visual mode
- :kbd:`~` toggles the case (upper/lower) on the selection, and enters :ref:`command mode <vi-mode-command>`.
- :kbd:`g,u` lowercases the selection, and enters :ref:`command mode <vi-mode-command>`.
- :kbd:`g,U` uppercases the selection, and enters :ref:`command mode <vi-mode-command>`.
- :kbd:`",*,y` copies the selection to the clipboard, and enters :ref:`command mode <vi-mode-command>`.
.. _custom-binds:
@@ -570,12 +544,12 @@ Custom bindings
In addition to the standard bindings listed here, you can also define your own with :doc:`bind <cmds/bind>`::
# Prints ``^C`` and a new prompt
bind ctrl-c cancel-commandline
# Just clear the commandline on control-c
bind ctrl-c 'commandline -r ""'
Put ``bind`` statements into :ref:`config.fish <configuration>` or a function called ``fish_user_key_bindings``.
If you change your mind on a binding and want to go back to fish's default, you can erase it again::
If you change your mind on a binding and want to go back to fish's default, you can simply erase it again::
bind --erase ctrl-c
@@ -627,7 +601,7 @@ Copy and paste (Kill Ring)
Fish uses an Emacs-style kill ring for copy and paste functionality. For example, use :kbd:`ctrl-k` (`kill-line`) to cut from the current cursor position to the end of the line. The string that is cut (a.k.a. killed in emacs-ese) is inserted into a list of kills, called the kill ring. To paste the latest value from the kill ring (emacs calls this "yanking") use :kbd:`ctrl-y` (the ``yank`` input function). After pasting, use :kbd:`alt-y` (``yank-pop``) to rotate to the previous kill.
Copy and paste from outside are also supported, both via the :kbd:`ctrl-x` / :kbd:`ctrl-v` bindings (the ``fish_clipboard_copy`` and ``fish_clipboard_paste`` functions [#]_) and via the terminal's paste function, for which fish enables "Bracketed Paste Mode", so it can tell a paste from manually entered text.
In addition, when pasting inside single quotes, pasted single quotes and backslashes are automatically escaped so that the result can be used as a single token by closing the quote after.
In addition, when pasting inside single quotes, pasted single quotes and backslashes are automatically escaped so that the result can be used as a single token simply by closing the quote after.
Kill ring entries are stored in ``fish_killring`` variable.
The commands ``begin-selection`` and ``end-selection`` (unbound by default; used for selection in vi visual mode) control text selection together with cursor movement commands that extend the current selection.
@@ -657,7 +631,7 @@ Searchable command history
After a command has been executed, it is remembered in the history list. Any duplicate history items are automatically removed. By pressing the up and down keys, you can search forwards and backwards in the history. If the current command line is not empty when starting a history search, only the commands containing the string entered into the command line are shown.
By pressing :kbd:`alt-up` (````) and :kbd:`alt-down` (````), a history search is also performed, but instead of searching for a complete commandline, each commandline is broken into separate elements like it would be before execution, and the history is searched for an element matching that under the cursor.
By pressing :kbd:`alt-up` (````) and :kbd:`alt-down` (````), a history search is also performed, but instead of searching for a complete commandline, each commandline is broken into separate elements just like it would be before execution, and the history is searched for an element matching that under the cursor.
For more complicated searches, you can press :kbd:`ctrl-r` to open a pager that allows you to search the history. It shows a limited number of entries in one page, press :kbd:`ctrl-r` [#]_ again to move to the next page and :kbd:`ctrl-s` [#]_ to move to the previous page. You can change the text to refine your search.

View File

@@ -257,7 +257,7 @@ This is important when any redirections reference other file descriptors with th
Consider this helper function::
# Make a function that prints something to stdout and stderr
# Just make a function that prints something to stdout and stderr
function print
echo out
echo err >&2
@@ -281,7 +281,7 @@ Now let's see a few cases::
Job control
-----------
When you start a job in fish, fish itself will pause, and give control of the terminal to the program it just started. Sometimes, you want to continue using the commandline, and have the job run in the background. To create a background job, append an ``&`` (ampersand) to your command. This will tell fish to run the job in the background. Background jobs are very useful when running programs that have a graphical user interface.
When you start a job in fish, fish itself will pause, and give control of the terminal to the program just started. Sometimes, you want to continue using the commandline, and have the job run in the background. To create a background job, append an ``&`` (ampersand) to your command. This will tell fish to run the job in the background. Background jobs are very useful when running programs that have a graphical user interface.
Example::
@@ -314,7 +314,7 @@ For example, here's a simple function to list directories::
ls -l $argv
end
The first line tells fish to define a function by the name of ``ll``, so it can be used by writing ``ll`` on the commandline. The second line tells fish that the command ``ls -l $argv`` should be called when ``ll`` is invoked. :ref:`$argv <variables-argv>` is a :ref:`list variable <variables-lists>`, which always contains all arguments sent to the function. In the example above, these are passed on to the ``ls`` command. The ``end`` on the third line ends the definition.
The first line tells fish to define a function by the name of ``ll``, so it can be used by simply writing ``ll`` on the commandline. The second line tells fish that the command ``ls -l $argv`` should be called when ``ll`` is invoked. :ref:`$argv <variables-argv>` is a :ref:`list variable <variables-lists>`, which always contains all arguments sent to the function. In the example above, these are simply passed on to the ``ls`` command. The ``end`` on the third line ends the definition.
Calling this as ``ll /tmp/`` will end up running ``ls -l /tmp/``, which will list the contents of /tmp.
@@ -408,7 +408,7 @@ This is useful to explain what and why you are doing something::
command ls --color=auto $argv
end
There are no multiline comments. If you want to make a comment span multiple lines, start each line with a ``#``.
There are no multiline comments. If you want to make a comment span multiple lines, simply start each line with a ``#``.
Comments can also appear after a line like so::
@@ -436,7 +436,7 @@ Like other shells, but unlike typical programming languages you might know, the
This uses the :doc:`test <cmds/test>` command to see if the file /etc/os-release exists. If it does, it runs ``cat``, which prints it on the screen.
Unlike other shells, the condition command ends after the first job, there is no ``then`` here. Combiners like ``and`` and ``or`` extend the condition.
Unlike other shells, the condition command just ends after the first job, there is no ``then`` here. Combiners like ``and`` and ``or`` extend the condition.
A more complicated example with a :ref:`command substitution <expand-command-substitution>`::
@@ -460,7 +460,7 @@ Because ``test`` can be used for many different tests, it is important to quote
The :doc:`not <cmds/not>` keyword can be used to invert the status::
# Check if the file contains the string "fish" anywhere.
# Just see if the file contains the string "fish" anywhere.
# This executes the `grep` command, which searches for a string,
# and if it finds it returns a status of 0.
# The `not` then turns 0 into 1 or anything else into 0.
@@ -530,7 +530,7 @@ Or you can have a case where it is necessary to stop early::
If this went on after seeing that the command "foo" doesn't exist, it would try to run ``foo`` and error because it wasn't found!
Combiners execute step-by-step, so it isn't recommended to build longer chains of them because they might do something you don't want. Consider::
Combiners really just execute step-by-step, so it isn't recommended to build longer chains of them because they might do something you don't want. Consider::
test -e /etc/my.config
or echo "OH NO WE NEED A CONFIG FILE"
@@ -567,7 +567,7 @@ will print "Still running" once a second. You can abort it with ctrl-c.
echo file: $file
end
will print each file in the current directory. The part after the ``in`` is a list of arguments, so you can use any :ref:`expansions <expand>` there::
will print each file in the current directory. The part after the ``in`` is just a list of arguments, so you can use any :ref:`expansions <expand>` there::
set moreanimals bird fox
for animal in {cat,}fish dog $moreanimals
@@ -620,7 +620,7 @@ When a parameter includes an :ref:`unquoted <quotes>` ``*`` star (or "asterisk")
- ``**`` matches any number of characters (including zero), and also descends into subdirectories. If ``**`` is a segment by itself, that segment may match zero times, for compatibility with other shells.
- ``?`` can match any single character except ``/``. This is deprecated and can be disabled via the ``qmark-noglob`` :ref:`feature flag<featureflags>`, so ``?`` will be an ordinary character.
- ``?`` can match any single character except ``/``. This is deprecated and can be disabled via the ``qmark-noglob`` :ref:`feature flag<featureflags>`, so ``?`` will just be an ordinary character.
Wildcard matches are sorted case insensitively. When sorting matches containing numbers, they are naturally sorted, so that the strings '1' '5' and '12' would be sorted like 1, 5, 12.
@@ -658,7 +658,7 @@ Variable expansion
One of the most important expansions in fish is the "variable expansion". This is the replacing of a dollar sign (``$``) followed by a variable name with the _value_ of that variable.
A simple example::
In the simplest case, this is just something like::
echo $HOME
@@ -788,10 +788,11 @@ Some more examples::
# Output is 1 2 3
echo $$var[2][3]
# $var[2] is listtwo, third element of that is 6, output is 6
# $var[1] is listtwo, third element of that is 6, output is 6
echo $$var[..][2]
# The second element of every variable, so output is 2 5
# The second element of every variable, so output is
# 2 5
Variables as command
''''''''''''''''''''
@@ -858,18 +859,18 @@ Examples::
# Set ``$data`` to the contents of data, splitting on NUL-bytes.
set data (cat data | string split0)
Sometimes you want to pass the output of a command to another command that only accepts files. If it's just one file, you can usually pass it via a pipe, like::
Sometimes you want to pass the output of a command to another command that only accepts files. If it's just one file, you can usually just pass it via a pipe, like::
grep fish myanimallist1 | wc -l
but if you need multiple or the command doesn't read from standard input, "process substitution" is useful. Other shells allow this via ``foo <(bar) <(baz)``, and fish uses the :doc:`psub <cmds/psub>` command::
# Compare only the lines containing "fish" in two files:
# Compare just the lines containing "fish" in two files:
diff -u (grep fish myanimallist1 | psub) (grep fish myanimallist2 | psub)
This creates a temporary file, stores the output of the command in that file and prints the filename, so it is given to the outer command.
Fish has a default limit of 1 GiB on the data it will read in a command substitution. If that limit is reached the command (all of it, not just the command substitution - the outer command won't be executed at all) fails and ``$status`` is set to 122. This is so command substitutions can't cause the system to go out of memory, because typically your operating system has a much lower limit, so reading more than that would be useless and harmful. This limit can be adjusted with the ``fish_read_limit`` variable (`0` meaning no limit). This limit also affects the :doc:`read <cmds/read>` command.
Fish has a default limit of 100 MiB on the data it will read in a command substitution. If that limit is reached the command (all of it, not just the command substitution - the outer command won't be executed at all) fails and ``$status`` is set to 122. This is so command substitutions can't cause the system to go out of memory, because typically your operating system has a much lower limit, so reading more than that would be useless and harmful. This limit can be adjusted with the ``fish_read_limit`` variable (`0` meaning no limit). This limit also affects the :doc:`read <cmds/read>` command.
.. [#] One exception: Setting ``$IFS`` to empty will disable line splitting. This is deprecated, use :doc:`string split <cmds/string-split>` instead.
@@ -908,7 +909,7 @@ If there is no "," or variable expansion between the curly braces, they will not
If after expansion there is nothing between the braces, the argument will be removed (see :ref:`the Combining Lists <cartesian-product>` section)::
> echo foo-{$undefinedvar}
# Output is an empty line, like a bare `echo`.
# Output is an empty line, just like a bare `echo`.
If there is nothing between a brace and a comma or two commas, it's interpreted as an empty element::
@@ -917,12 +918,6 @@ If there is nothing between a brace and a comma or two commas, it's interpreted
To use a "," as an element, :ref:`quote <quotes>` or :ref:`escape <escapes>` it.
The very first character of a command token is never interpreted as expanding brace, because it's the beginning of a :ref:`compound statement <cmd-begin>`::
> {echo hello, && echo world}
hello,
world
.. _cartesian-product:
Combining lists
@@ -1331,7 +1326,7 @@ To see universal variables in action, start two fish sessions side by side, and
:ref:`Universal variables <variables-universal>` are stored in the file ``.config/fish/fish_variables``. Do not edit this file directly, as your edits may be overwritten. Edit the variables through fish scripts or by using fish interactively instead.
Do not append to universal variables in :ref:`config.fish <configuration>`, because these variables will then get longer with each new shell instance. Instead, set them once at the command line.
Do not append to universal variables in :ref:`config.fish <configuration>`, because these variables will then get longer with each new shell instance. Instead, simply set them once at the command line.
.. _variables-export:
@@ -1374,7 +1369,7 @@ To access one element of a list, use the index of the element inside of square b
echo $PATH[3]
List indices start at 1 in fish, not 0 like in other languages. This is because it requires less subtracting of 1 and many common Unix tools like ``seq`` work better with it (``seq 5`` prints 1 to 5, not 0 to 5). An invalid index is silently ignored resulting in no value (not even an empty string, no argument at all).
List indices start at 1 in fish, not 0 like in other languages. This is because it requires less subtracting of 1 and many common Unix tools like ``seq`` work better with it (``seq 5`` prints 1 to 5, not 0 to 5). An invalid index is silently ignored resulting in no value (not even an empty string, just no argument at all).
If you don't use any brackets, all the elements of the list will be passed to the command as separate items. This means you can iterate over a list with ``for``::
@@ -1384,7 +1379,7 @@ If you don't use any brackets, all the elements of the list will be passed to th
This goes over every directory in :envvar:`PATH` separately and prints a line saying it is in the path.
To create a variable ``smurf``, containing the items ``blue`` and ``small``, write::
To create a variable ``smurf``, containing the items ``blue`` and ``small``, simply write::
set smurf blue small
@@ -1446,7 +1441,7 @@ Lists can be inspected with the :doc:`count <cmds/count>` or the :doc:`contains
> contains -i blue $smurf
1
A nice thing about lists is that they are passed to commands one element as one argument, so once you've set your list, you can pass it::
A nice thing about lists is that they are passed to commands one element as one argument, so once you've set your list, you can just pass it::
set -l grep_args -r "my string"
grep $grep_args . # will run the same as `grep -r "my string"` .
@@ -1571,12 +1566,13 @@ You can change the settings of fish by changing the values of certain variables.
.. envvar:: fish_term24bit
If this is set to 0, fish will not output 24-bit RGB true-color sequences but the nearest color on the 256 color palette (or the 16 color palette, if :envvar:`fish_term256` is 0).
If this is set to 1, fish will assume the terminal understands 24-bit RGB color sequences, and won't translate them to the 256 or 16 color palette.
This is often detected automatically.
.. envvar:: fish_term256
If this is set to 0 and :envvar:`fish_term24bit` is 0, translate RGB colors down to the 16 color palette.
Also, if this is set to 0, :doc:`set_color <cmds/set_color>`/` commands such as ``set_color ff0000 red`` will prefer the named color.
If this is set to 1, fish will assume the terminal understands 256 colors, and won't translate matching colors down to the 16 color palette.
This is usually autodetected.
.. envvar:: fish_ambiguous_width
@@ -1590,10 +1586,6 @@ You can change the settings of fish by changing the values of certain variables.
controls if :ref:`autosuggestions` are enabled. Set it to 0 to disable, anything else to enable. By default they are on.
.. envvar:: fish_transient_prompt
If this is set to 1, fish will redraw prompts with a ``--final-rendering`` argument before running a commandline, allowing you to change it before pushing it to the scrollback. This enables :ref:`transient prompts <transient-prompt>`.
.. envvar:: fish_handle_reflow
determines whether fish should try to repaint the commandline when the terminal resizes. In terminals that reflow text this should be disabled. Set it to 1 to enable, anything else to disable.
@@ -1723,7 +1715,7 @@ Fish also provides additional information through the values of certain environm
.. ENVVAR:: SHLVL
the level of nesting of shells. Fish increments this in interactive shells, otherwise it only passes it along.
the level of nesting of shells. Fish increments this in interactive shells, otherwise it simply passes it along.
.. envvar:: status
@@ -1733,6 +1725,12 @@ Fish also provides additional information through the values of certain environm
the "generation" count of ``$status``. This will be incremented only when the previous command produced an explicit status. (For example, background jobs will not increment this).
.. ENVVAR:: TERM
the type of the current terminal. When fish tries to determine how the terminal works - how many colors it supports, what sequences it sends for keys and other things - it looks at this variable and the corresponding information in the terminfo database (see ``man terminfo``).
Note: Typically this should not be changed as the terminal sets it to the correct value.
.. ENVVAR:: USER
the current username. This variable can be changed.
@@ -1956,7 +1954,7 @@ Let's make up an example. This function will :ref:`glob <expand-wildcard>` the f
printf '%s\n' $files
end
If you run this as ``show_files /``, it will most likely ask you until you press Y/y or N/n. If you run this as ``show_files / | cat``, it will print the files without asking. If you run this as ``show_files .``, it might print something without asking because there are fewer than five files.
If you run this as ``show_files /``, it will most likely ask you until you press Y/y or N/n. If you run this as ``show_files / | cat``, it will print the files without asking. If you run this as ``show_files .``, it might just print something without asking because there are fewer than five files.
.. _identifiers:
@@ -2026,17 +2024,19 @@ You can see the current list of features via ``status features``::
ampersand-nobg-in-token on 3.4 & only backgrounds if followed by a separating character
remove-percent-self off 4.0 %self is no longer expanded (use $fish_pid)
test-require-arg off 4.0 builtin test requires an argument
ignore-terminfo on 4.1 do not look up $TERM in terminfo database
keyboard-protocols on 4.0 Use keyboard protocols (kitty, xterm's modifyotherkeys
Here is what they mean:
- ``stderr-nocaret`` was introduced in fish 3.0 and cannot be turned off since fish 3.5. It can still be tested for compatibility, but a ``no-stderr-nocaret`` value will be ignored. The flag made ``^`` an ordinary character instead of denoting an stderr redirection. Use ``2>`` instead.
- ``stderr-nocaret`` was introduced in fish 3.0 and cannot be turned off since fish 3.5. It can still be tested for compatibility, but a ``no-stderr-nocaret`` value will simply be ignored. The flag made ``^`` an ordinary character instead of denoting an stderr redirection. Use ``2>`` instead.
- ``qmark-noglob`` was also introduced in fish 3.0 (and made the default in 4.0). It makes ``?`` an ordinary character instead of a single-character glob. Use a ``*`` instead (which will match multiple characters) or find other ways to match files like ``find``.
- ``regex-easyesc`` was introduced in 3.1 (and made the default in 3.5). It makes it so the replacement expression in ``string replace -r`` does one fewer round of escaping. Before, to escape a backslash you would have to use ``string replace -ra '([ab])' '\\\\\\\\$1'``. After, just ``'\\\\$1'`` is enough. Check your ``string replace`` calls if you use this anywhere.
- ``ampersand-nobg-in-token`` was introduced in fish 3.4 (and made the default in 3.5). It makes it so a ``&`` i no longer interpreted as the backgrounding operator in the middle of a token, so dealing with URLs becomes easier. Either put spaces or a semicolon after the ``&``. This is recommended formatting anyway, and ``fish_indent`` will have done it for you already.
- ``remove-percent-self`` turns off the special ``%self`` expansion. It was introduced in 4.0. To get fish's pid, you can use the :envvar:`fish_pid` variable.
- ``test-require-arg`` removes :doc:`builtin test <cmds/test>`'s one-argument form (``test "string"``. It was introduced in 4.0. To test if a string is non-empty, use ``test -n "string"``. If disabled, any call to ``test`` that would change sends a :ref:`debug message <debugging-fish>` of category "deprecated-test", so starting fish with ``fish --debug=deprecated-test`` can be used to find offending calls.
- ``ignore-terminfo`` disables lookup of $TERM in the terminfo database. Use ``no-ignore-terminfo`` to turn it back on.
- ``keyboard-protocols`` lets fish turn on various keyboard protocols including the kitty keyboard protocol.
It was introduced in 4.0 and is on by default.
Disable it with ``no-keyboard-protocols`` to work around bugs in your terminal.
These changes are introduced off by default. They can be enabled on a per session basis::
@@ -2120,14 +2120,12 @@ For more information on how to define new event handlers, see the documentation
Debugging fish scripts
----------------------
Fish includes basic built-in debugging facilities that allow you to stop execution of a script at an arbitrary point. When this happens you are presented with an interactive prompt where you can execute any fish command to inspect or change state (there are no debug commands as such). For example, you can check or change the value of any variables using :doc:`printf <cmds/printf>` and :doc:`set <cmds/set>`. As another example, you can run :doc:`status print-stack-trace <cmds/status>` to see how the current breakpoint was reached. To resume normal execution of the script, type :doc:`exit <cmds/exit>` or :kbd:`ctrl-d`.
Fish includes basic built-in debugging facilities that allow you to stop execution of a script at an arbitrary point. When this happens you are presented with an interactive prompt where you can execute any fish command to inspect or change state (there are no debug commands as such). For example, you can check or change the value of any variables using :doc:`printf <cmds/printf>` and :doc:`set <cmds/set>`. As another example, you can run :doc:`status print-stack-trace <cmds/status>` to see how the current breakpoint was reached. To resume normal execution of the script, simply type :doc:`exit <cmds/exit>` or :kbd:`ctrl-d`.
To start a debug session insert the :doc:`builtin command <cmds/breakpoint>` ``breakpoint`` at the point in a function or script where you wish to gain control, then run the function or script. Also, the default action of the ``TRAP`` signal is to call this builtin, meaning a running script can be actively debugged by sending it the ``TRAP`` signal (``kill -s TRAP <PID>``). There is limited support for interactively setting or modifying breakpoints from this debug prompt: it is possible to insert new breakpoints in (or remove old ones from) other functions by using the ``funced`` function to edit the definition of a function, but it is not possible to add or remove a breakpoint from the function/script currently loaded and being executed.
To start a debug session simply insert the :doc:`builtin command <cmds/breakpoint>` ``breakpoint`` at the point in a function or script where you wish to gain control, then run the function or script. Also, the default action of the ``TRAP`` signal is to call this builtin, meaning a running script can be actively debugged by sending it the ``TRAP`` signal (``kill -s TRAP <PID>``). There is limited support for interactively setting or modifying breakpoints from this debug prompt: it is possible to insert new breakpoints in (or remove old ones from) other functions by using the ``funced`` function to edit the definition of a function, but it is not possible to add or remove a breakpoint from the function/script currently loaded and being executed.
Another way to debug script issues is to set the :envvar:`fish_trace` variable, e.g. ``fish_trace=1 fish_prompt`` to see which commands fish executes when running the :doc:`fish_prompt <cmds/fish_prompt>` function.
.. _profiling:
Profiling fish scripts
^^^^^^^^^^^^^^^^^^^^^^

View File

@@ -6,7 +6,7 @@ License
License for fish
----------------
``fish`` Copyright © 2005-2009 Axel Liljencrantz, 2009- fish-shell contributors. ``fish`` is released under the GNU General Public License, version 2.
``fish`` Copyright © 2005-2009 Axel Liljencrantz, 2009-2024 fish-shell contributors. ``fish`` is released under the GNU General Public License, version 2.
``fish`` includes other code licensed under the GNU General Public License, version 2, including GNU ``printf``.

View File

@@ -148,51 +148,10 @@ And it looks like:
.. parsed-literal::
:class: highlight
:green:`~/M/L/Oneknowing`>false
:green:`~/M/L/Oneknowing`\ :red:`[1]`>_
after we run ``false`` (which returns 1).
.. _transient-prompt:
Transient prompt
----------------
To enable transient prompt functionality, set the :envvar:`fish_transient_prompt` variable to 1::
set -g fish_transient_prompt 1
With this set, fish re-runs prompt functions with a ``--final-rendering`` argument before running a commandline.
So you can use it to declutter your old prompts. For example if you want to see only the current directory name when you scroll up::
function fish_prompt
set -l last_status $status
set -l stat
set -l pwd
# Check if it's a transient or final prompt
if contains -- --final-rendering $argv
set pwd (path basename $PWD)
else
set pwd (prompt_pwd)
# Prompt status only if it's not 0
if test $last_status -ne 0
set stat (set_color red)"[$last_status]"(set_color normal)
end
end
string join '' -- (set_color green) $pwd (set_color normal) $stat '>'
end
Now running two commands in the same directory could result in this screen:
.. role:: green
.. role:: red
.. parsed-literal::
:class: highlight
:green:`Oneknowing`>false
:green:`~/M/L/Oneknowing`\ :red:`[1]`>_
Save the prompt
---------------

View File

@@ -1,286 +0,0 @@
Terminal Compatibility
======================
fish writes various control sequences to the terminal.
Some must be implemented to enable basic functionality,
while others enable optional features and may be ignored by the terminal.
The terminal must be able to parse Control Sequence Introducer (CSI) commands, Operating System Commands (OSC) and optionally Device Control Strings (DCS).
These are defined by ECMA-48.
If a valid CSI, OSC or DCS sequence does not represent a command implemented by the terminal, the terminal must ignore it.
Control sequences are denoted in a fish-like syntax.
Special characters other than ``\`` are not escaped.
Spaces are only added for readability and are not part of the sequence.
Placeholders are written as ``<Ps>`` for a number or ``<Pt>`` for an arbitrary printable string.
**NOTE:** fish does not rely on your system's terminfo database.
In this document, terminfo (TI) codes are included for reference only.
Required Commands
-----------------
.. list-table::
:widths: auto
:header-rows: 1
* - Sequence
- TI
- Description
- Origin
* - ``\r``
- n/a
- Move cursor to the beginning of the line
-
* - ``\n``
- cud1
- Move cursor down one line.
-
* - ``\e[ Ps A``
- cuu
- Move cursor up Ps columns, or one column if no parameter.
- VT100
* - ``\e[ Ps C``
- cuf
- Move cursor to the right Ps columns, or one column if no parameter.
- VT100
* - ``\x08``
- cub1
- Move cursor one column to the left.
- VT100
* - ``\e[ Ps D``
- cub
- Move cursor to the left Ps times.
- VT100
* - ``\e[H``
- cup
- Set cursor position (no parameters means: move to row 1, column 1).
- VT100
* - ``\e[K``
- el
- Clear to end of line.
- VT100
* - ``\e[J``
- ed
- Clear to the end of screen.
- VT100
* - ``\e[2J``
- clear
- Clear the screen.
- VT100
* - ``\e[0c``
-
- Request primary device attribute.
The terminal must respond with a CSI command that starts with the ``?`` parameter byte (so a sequence starting with ``\e[?``) and has ``c`` as final byte.
- VT100
* - n/a
- am
- Soft wrap text at screen width.
-
* - n/a
- xenl
- Printing to the last column does not move the cursor to the next line.
Verify this by running ``printf %0"$COLUMNS"d 0; sleep 3``
-
Optional Commands
-----------------
.. list-table::
:widths: auto
:header-rows: 1
* - Sequence
- TI
- Description
- Origin
* - ``\t``
- it
- Move the cursor to the next tab stop (à 8 columns).
This is mainly relevant if your prompt includes tabs.
-
* - ``\e[m``
- sgr0
- Turn off bold/dim/italic/underline/reverse attribute modes and select default colors.
-
* - ``\e[1m``
- bold
- Enter bold mode.
-
* - ``\e[2m``
- dim
- Enter dim mode.
-
* - ``\e[3m``
- sitm
- Enter italic mode.
-
* - ``\e[4m``
- smul
- Enter underline mode.
-
* - ``\e[4:2m``
- Su
- Enter double underline mode.
- kitty
* - ``\e[4:3m``
- Su
- Enter curly underline mode.
- kitty
* - ``\e[4:4m``
- Su
- Enter dotted underline mode.
- kitty
* - ``\e[4:5m``
- Su
- Enter dashed underline mode.
- kitty
* - ``\e[7m``
- rev
- Enter reverse video mode (swap foreground and background colors).
-
* - ``\e[23m``
- ritm
- Exit italic mode.
-
* - ``\e[24m``
- rmul
- Exit underline mode.
-
* - ``\e[38;5; Ps m``
- setaf
- Select foreground color Ps from the 256-color-palette.
-
* - ``\e[48;5; Ps m``
- setab
- Select background color Ps from the 256-color-palette.
-
* - ``\e[58:5: Ps m`` (note: colons not semicolons)
- Su
- Select underline color Ps from the 256-color-palette.
- kitty
* - ``\e[ Ps m``
- setaf
setab
- Select foreground/background color. This uses a color in the aforementioned 256-color-palette, based on the range that contains the parameter:
30-37 maps to foreground 0-7,
40-47 maps to background 0-7,
90-97 maps to foreground 8-15 and
100-107 maps to background 8-15.
-
* - ``\e[38;2; Ps ; Ps ; Ps m``
-
- Select foreground color from 24-bit RGB colors.
-
* - ``\e[48;2; Ps ; Ps ; Ps m``
-
- Select background color from 24-bit RGB colors.
-
* - ``\e[49m``
-
- Reset background color to the terminal's default.
-
* - ``\e[58:2:: Ps : Ps : Ps m`` (note: colons not semicolons)
- Su
- Select underline color from 24-bit RGB colors.
- kitty
* - ``\e[59m``
- Su
- Reset underline color to the default (follow the foreground color).
- kitty
* - ``\e[ Ps S``
- indn
- Scroll forward Ps lines.
-
* - ``\e[= Ps u``, ``\e[? Ps u``
- n/a
- Enable the kitty keyboard protocol.
- kitty
* - ``\e[6n``
- n/a
- Request cursor position report.
- VT100
* - ``\e[ \x20 q``
- Se
- Reset cursor style to the terminal's default. This is not used as of today but may be
in future.
- VT520
* - ``\e[ Ps \x20 q``
- Ss
- Set cursor style (DECSCUSR); Ps is 2, 4 or 6 for block, underscore or line shape.
- VT520
* - ``\e[ Ps q``
- n/a
- Request terminal name and version (XTVERSION).
- XTerm
* - ``\e[?25h``
- cvvis
- Enable cursor visibility (DECTCEM).
- VT220
* - ``\e[?1000l``
- n/a
- Disable mouse reporting.
- XTerm
* - ``\e[?1004h``
- n/a
- Enable focus reporting.
-
* - ``\e[?1004l``
- n/a
- Disable focus reporting.
-
* - ``\e[?1049h``
- n/a
- Enable alternate screen buffer.
- XTerm
* - ``\e[?1049l``
- n/a
- Disable alternate screen buffer.
- XTerm
* - ``\e[?2004h``
-
- Enable bracketed paste.
- XTerm
* - ``\e[?2004l``
-
- Disable bracketed paste.
- XTerm
* - ``\e]0; Pt \x07``
- ts
- Set window title (OSC 0).
- XTerm
* - ``\e]7;file:// Pt / Pt \x07``
-
- Report working directory (OSC 7).
Since the terminal may be running on a different system than a (remote) shell,
the hostname (first parameter) will *not* be ``localhost``.
- iTerm2
* - ``\e]8;; Pt \e\\``
-
- Create a `hyperlink (OSC 8) <https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda>`_.
This is used in fish's man pages.
- GNOME Terminal
* - ``\e]52;c; Pt \x07``
-
- Copy to clipboard (OSC 52).
- XTerm
* - .. _click-events:
``\e]133;A; click_events=1\x07``
-
- Mark prompt start (OSC 133), with kitty's ``click_events`` extension.
- FinalTerm, kitty
* - ``\e]133;C; cmdline_url= Pt \x07``
-
- Mark command start (OSC 133), with kitty's ``cmdline_url`` extension whose parameter is the URL-encoded command line.
- FinalTerm, kitty
* - ``\e]133;D; Ps \x07``
-
- Mark command end (OSC 133); Ps is the exit status.
- FinalTerm
* - ``\eP+q Pt \e\\``
-
- Request terminfo capability (XTGETTCAP). The parameter is the capability's hex-encoded terminfo code.
Specifically, fish asks for the ``indn`` string capability. At the time of writing string capabilities are supported by kitty and foot.
- XTerm, kitty, foot

View File

@@ -115,7 +115,7 @@ These colors, and many more, can be changed by running ``fish_config``, or by mo
For example, if you want to disable (almost) all coloring::
fish_config theme choose None
fish_config theme choose none
This picks the "none" theme. To see all themes::
@@ -631,12 +631,12 @@ You can define your own prompt from the command line:
Then, if you are happy with it, you can save it to disk by typing ``funcsave fish_prompt``. This saves the prompt in ``~/.config/fish/functions/fish_prompt.fish``. (Or, if you want, you can create that file manually from the start.)
Multiple lines are OK. Colors can be set via :doc:`set_color <cmds/set_color>` by passing it named ANSI colors, or hex RGB values::
Multiple lines are OK. Colors can be set via :doc:`set_color <cmds/set_color>`, passing it named ANSI colors, or hex RGB values::
function fish_prompt
set_color purple
date "+%m/%d/%y"
set_color FF0000
set_color F00
echo (pwd) '>' (set_color normal)
end
@@ -650,9 +650,7 @@ This prompt would look like:
:red:`/home/tutorial >` _
See also :doc:`Writing your own prompt <prompt>`.
You can choose among sample prompts by running ``fish_config`` for a web UI or ``fish_config prompt`` for a simpler version inside your terminal.
You can choose among some sample prompts by running ``fish_config`` for a web UI or ``fish_config prompt`` for a simpler version inside your terminal.
$PATH
-----

View File

@@ -1,17 +1,19 @@
FROM alpine:3.19
LABEL org.opencontainers.image.source=https://github.com/fish-shell/fish-shell
ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
ENV LANG C.UTF-8
ENV LC_ALL C.UTF-8
RUN apk add --no-cache \
bash \
cargo \
cmake \
g++ \
gettext-dev \
git \
libintl \
musl-dev \
ninja \
pcre2-dev \
py3-pexpect \
python3 \
@@ -38,6 +40,4 @@ WORKDIR /home/fishuser
COPY fish_run_tests.sh /
ENV FISH_CHECK_LINT=false
CMD /fish_run_tests.sh

View File

@@ -8,13 +8,17 @@ RUN cd /etc/yum.repos.d/ && \
sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
# install powertools to get ninja-build
RUN dnf -y install dnf-plugins-core \
&& dnf config-manager --set-enabled powertools \
&& yum install --assumeyes epel-release \
&& yum install --assumeyes \
cargo \
cmake \
diffutils \
gcc-c++ \
git \
ninja-build \
python3 \
python3-pexpect \
openssl \
@@ -35,6 +39,4 @@ WORKDIR /home/fishuser
COPY fish_run_tests.sh /
ENV FISH_CHECK_LINT=false
CMD /fish_run_tests.sh

View File

@@ -1,38 +1,24 @@
#!/bin/sh
set -e
#!/bin/bash
# This script is copied into the root directory of our Docker tests.
# It is the entry point for running Docker-based tests.
echo build_tools/check.sh >>~/.bash_history
cd /fish-source
cd ~/fish-build
git config --global --add safe.directory /fish-source
export CARGO_TARGET_DIR="$HOME"/fish-build
interactive_shell() {
echo
echo "+ export=CARGO_TARGET_DIR=$CARGO_TARGET_DIR"
echo
bash -i
}
cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug /fish-source "$@"
# Spawn a shell if FISH_RUN_SHELL_BEFORE_TESTS is set.
if test -n "$FISH_RUN_SHELL_BEFORE_TESTS"
then
interactive_shell
bash -i || exit
fi
set +e
build_tools/check.sh
ninja && ninja fish_run_tests
RES=$?
set -e
# Drop the user into a shell if FISH_RUN_SHELL_AFTER_TESTS is set.
if test -n "$FISH_RUN_SHELL_AFTER_TESTS"; then
interactive_shell
bash -i
fi
exit $RES

View File

@@ -1,12 +1,11 @@
#!/bin/sh
#!/bin/bash
usage() {
cat << EOF
Usage: $(basename "$0") [--shell-before] [--shell-after] DOCKERFILE
Usage: $(basename $0) [--shell-before] [--shell-after] DOCKERFILE
Options:
--shell-before Before the tests start, run a bash shell
--shell-after After the tests end, run a bash shell
--lint, --no-lint Enable/disable linting and failure on warnings
--shell-before Before the tests start, run a bash shell
--shell-after After the tests end, run a bash shell
EOF
exit 1
}
@@ -19,7 +18,7 @@ export DOCKER_BUILDKIT=1
set -e
# Get fish source directory.
FISH_SRC_DIR=$(cd "$( dirname "$0" )"/.. >/dev/null && pwd)
FISH_SRC_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )"/.. >/dev/null && pwd)
# Parse args.
while [ $# -gt 1 ]; do
@@ -30,12 +29,6 @@ while [ $# -gt 1 ]; do
--shell-after)
DOCKER_EXTRA_ARGS="$DOCKER_EXTRA_ARGS --env FISH_RUN_SHELL_AFTER_TESTS=1"
;;
--lint)
DOCKER_EXTRA_ARGS="$DOCKER_EXTRA_ARGS --env FISH_CHECK_LINT=true"
;;
--no-lint)
DOCKER_EXTRA_ARGS="$DOCKER_EXTRA_ARGS --env FISH_CHECK_LINT=false"
;;
*)
usage
;;
@@ -43,7 +36,7 @@ while [ $# -gt 1 ]; do
shift
done
DOCKERFILE="$1"
DOCKERFILE=${@:$OPTIND:1}
test -n "$DOCKERFILE" || usage
# Construct a docker image.
@@ -54,7 +47,6 @@ docker build \
"$FISH_SRC_DIR"/docker/context/
# Run tests in it, allowing them to fail without failing this script.
# shellcheck disable=SC2086 # $DOCKER_EXTRA_ARGS should have globbing and splitting applied.
docker run -it \
--mount type=bind,source="$FISH_SRC_DIR",target=/fish-source,readonly \
$DOCKER_EXTRA_ARGS \

View File

@@ -2,9 +2,11 @@ FROM fedora:latest
LABEL org.opencontainers.image.source=https://github.com/fish-shell/fish-shell
RUN dnf install --assumeyes \
cmake \
diffutils \
gcc-c++ \
git-core \
ninja-build \
pcre2-devel \
python3 \
python3-pip \
@@ -26,6 +28,4 @@ WORKDIR /home/fishuser
COPY fish_run_tests.sh /
ENV FISH_CHECK_LINT=false
CMD /fish_run_tests.sh

View File

@@ -1,17 +1,20 @@
FROM ubuntu:20.04
LABEL org.opencontainers.image.source=https://github.com/fish-shell/fish-shell
ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
ENV LANG C.UTF-8
ENV LC_ALL C.UTF-8
ENV CFLAGS="-m32"
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get -y install \
build-essential \
cmake \
g++-multilib \
gettext \
git \
locales \
ninja-build \
pkg-config \
python3 \
python3-pexpect \
@@ -35,13 +38,6 @@ RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > /tmp/rustup.sh \
COPY fish_run_tests.sh /
ENV \
CFLAGS=-m32 \
PCRE2_SYS_STATIC=1 \
FISH_CHECK_TARGET_TRIPLE=i686-unknown-linux-gnu
ENV FISH_CHECK_LINT=false
CMD . ~/.cargo/env \
&& rustup target add ${FISH_CHECK_TARGET_TRIPLE} \
&& /fish_run_tests.sh
&& rustup target add i686-unknown-linux-gnu \
&& /fish_run_tests.sh -DFISH_USE_SYSTEM_PCRE2=OFF -DRust_CARGO_TARGET=i686-unknown-linux-gnu

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