diff --git a/.cirrus.yml b/.cirrus.yml index 22590139e..55cf5b1f4 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -51,7 +51,8 @@ linux_task: - ninja -j 6 fish fish_tests - ninja fish_run_tests - only_if: $CIRRUS_REPO_OWNER == 'fish-shell' + # CI task disabled during RIIR transition + only_if: false && $CIRRUS_REPO_OWNER == 'fish-shell' linux_arm_task: matrix: @@ -74,21 +75,24 @@ linux_arm_task: - file ./fish - ninja fish_run_tests - only_if: $CIRRUS_REPO_OWNER == 'fish-shell' + # CI task disabled during RIIR transition + only_if: false && $CIRRUS_REPO_OWNER == 'fish-shell' freebsd_task: matrix: - - name: FreeBSD 14 - freebsd_instance: - image_family: freebsd-14-0-snap + # - name: FreeBSD 14 + # freebsd_instance: + # image_family: freebsd-14-0-snap - name: FreeBSD 13 freebsd_instance: - image: freebsd-13-1-release-amd64 - - name: FreeBSD 12.3 - freebsd_instance: - image: freebsd-12-3-release-amd64 + 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 misc/py-pexpect git-lite + # 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 # the mode bits would otherwise disallow it. For example root may open() # a file with write privileges even if the file has mode 400. This breaks @@ -99,8 +103,16 @@ freebsd_task: - mkdir build && cd build - chown -R fish-user .. - sudo -u fish-user -s whoami + # FreeBSD's pkg currently has rust 1.66.0 while we need rust 1.67.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 -s ninja -j 6 fish fish_tests - - sudo -u fish-user -s ninja fish_run_tests + - sudo -u fish-user sh -c '. $HOME/.cargo/env; ninja -j 6 fish fish_tests' + - sudo -u fish-user sh -c '. $HOME/.cargo/env; ninja fish_run_tests' only_if: $CIRRUS_REPO_OWNER == 'fish-shell' diff --git a/.editorconfig b/.editorconfig index 647fb3a89..053c57353 100644 --- a/.editorconfig +++ b/.editorconfig @@ -22,7 +22,7 @@ indent_size = 2 indent_size = 2 [share/{completions,functions}/**.fish] -max_line_length = none +max_line_length = off [{COMMIT_EDITMSG,git-revise-todo}] max_line_length = 80 diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 29168a105..a6185c813 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -8,7 +8,7 @@ Please tell us which operating system and terminal you are using. The output of Please tell us if you tried fish without third-party customizations by executing this command and whether it affected the behavior you are reporting: - sh -c 'env HOME=$(mktemp -d) fish' + sh -c 'env HOME=$(mktemp -d) XDG_CONFIG_HOME= fish' Tell us how to reproduce the problem. Including an asciinema.org recording is useful for problems that involve the visual display of fish output such as its prompt. --> diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c39741e20..3ae1b2dee 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,6 +16,7 @@ jobs: steps: - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@1.67 - name: Install deps run: | sudo apt install gettext libncurses5-dev libpcre2-dev python3-pip tmux @@ -42,6 +43,9 @@ jobs: steps: - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@1.67 + with: + targets: "i686-unknown-linux-gnu" # rust-toolchain wants this comma-separated - name: Install deps run: | sudo apt update @@ -53,10 +57,10 @@ jobs: CFLAGS: "-m32" run: | mkdir build && cd build - cmake -DFISH_USE_SYSTEM_PCRE2=OFF .. + cmake -DFISH_USE_SYSTEM_PCRE2=OFF -DRust_CARGO_TARGET=i686-unknown-linux-gnu .. - name: make run: | - make + make VERBOSE=1 - name: make test run: | make test @@ -64,13 +68,29 @@ jobs: ubuntu-asan: runs-on: ubuntu-latest + env: + # Rust has two different memory sanitizers of interest; they can't be used at the same time: + # * AddressSanitizer detects out-of-bound access, use-after-free, use-after-return, + # use-after-scope, double-free, invalid-free, and memory leaks. + # * MemorySanitizer detects uninitialized reads. + # + RUSTFLAGS: "-Zsanitizer=address" + # RUSTFLAGS: "-Zsanitizer=memory -Zsanitizer-memory-track-origins" steps: - uses: actions/checkout@v3 + # All -Z options require running nightly + - uses: dtolnay/rust-toolchain@nightly + with: + # ASAN uses `cargo build -Zbuild-std` which requires the rust-src component + # this is comma-separated + components: rust-src - name: Install deps run: | sudo apt install gettext libncurses5-dev libpcre2-dev python3-pip tmux - sudo pip3 install pexpect + # Don't install pexpect here because this constantly blows the time budget. + # Try again once the rust port is done and we're hopefully not as slow anymore. + # sudo pip3 install pexpect - name: cmake env: CC: clang @@ -78,48 +98,57 @@ jobs: CXXFLAGS: "-fno-omit-frame-pointer -fsanitize=undefined -fsanitize=address -DFISH_CI_SAN" run: | mkdir build && cd build - cmake .. + # Rust's ASAN requires the build system to explicitly pass a --target triple. We read that + # value from CMake variable Rust_CARGO_TARGET (shared with corrosion). + env CXXFLAGS="$CXXFLAGS -fsanitize-blacklist=$PWD/../build_tools/asan_blacklist.txt" \ + cmake .. -DASAN=1 -DRust_CARGO_TARGET=x86_64-unknown-linux-gnu -DCMAKE_BUILD_TYPE=Debug - name: make run: | make - name: make test env: FISH_CI_SAN: 1 - ASAN_OPTIONS: check_initialization_order=1:detect_stack_use_after_return=1:detect_leaks=1 + ASAN_OPTIONS: check_initialization_order=1:detect_stack_use_after_return=1:detect_leaks=1:fast_unwind_on_malloc=0 UBSAN_OPTIONS: print_stacktrace=1:report_error_type=1 # use_tls=0 is a workaround for LSAN crashing with "Tracer caught signal 11" (SIGSEGV), # which seems to be an issue with TLS support in newer glibc versions under virtualized # environments. Follow https://github.com/google/sanitizers/issues/1342 and # https://github.com/google/sanitizers/issues/1409 to track this issue. - LSAN_OPTIONS: verbosity=0:log_threads=0:use_tls=0 + # 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: | - make test + env LSAN_OPTIONS="$LSAN_OPTIONS:suppressions=$PWD/build_tools/lsan_suppressions.txt" make test - ubuntu-threadsan: + # Our clang++ tsan builds are not recognizing safe rust patterns (such as the fact that Drop + # cannot be called while a thread is using the object in question). Rust has its own way of + # running TSAN, but for the duration of the port from C++ to Rust, we'll keep this disabled. - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - name: Install deps - run: | - sudo apt install gettext libncurses5-dev libpcre2-dev python3-pip tmux - sudo pip3 install pexpect - - name: cmake - env: - FISH_CI_SAN: 1 - CC: clang - CXX: clang++ - CXXFLAGS: "-fsanitize=thread" - run: | - mkdir build && cd build - cmake .. - - name: make - run: | - make - - name: make test - run: | - make test + # ubuntu-threadsan: + # + # runs-on: ubuntu-latest + # + # steps: + # - uses: actions/checkout@v3 + # - uses: dtolnay/rust-toolchain@1.67 + # - name: Install deps + # run: | + # sudo apt install gettext libncurses5-dev libpcre2-dev python3-pip tmux + # sudo pip3 install pexpect + # - name: cmake + # env: + # FISH_CI_SAN: 1 + # CC: clang + # CXX: clang++ + # CXXFLAGS: "-fsanitize=thread" + # run: | + # mkdir build && cd build + # cmake .. + # - name: make + # run: | + # make + # - name: make test + # run: | + # make test macos: @@ -127,6 +156,7 @@ jobs: steps: - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@1.67 - name: Install deps run: | sudo pip3 install pexpect diff --git a/.github/workflows/rust_checks.yml b/.github/workflows/rust_checks.yml new file mode 100644 index 000000000..a5661832a --- /dev/null +++ b/.github/workflows/rust_checks.yml @@ -0,0 +1,32 @@ +name: Rust checks + +on: [push, pull_request] + +permissions: + contents: read + +jobs: + rustfmt: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - name: cargo fmt + run: cargo fmt --check --all + + clippy: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - name: Install deps + run: | + sudo apt install gettext libncurses5-dev libpcre2-dev python3-pip tmux + sudo pip3 install pexpect + - name: cmake + run: | + cmake -B build + - name: cargo clippy + run: cargo clippy --workspace --all-targets -- --deny=warnings diff --git a/.gitignore b/.gitignore index 917c3ac4d..a55c179e8 100644 --- a/.gitignore +++ b/.gitignore @@ -89,3 +89,16 @@ __pycache__ /tags xcuserdata/ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +# Generated by clangd +/.cache diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 847a2444c..19676e382 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,53 +3,71 @@ fish 3.7.0 (released ???) .. ignore: 9439 9440 9442 9452 9469 9480 9482 +Notable backwards-incompatible changes +-------------------------------------- +fish is being (once you are reading this hopefully "has been") ported to rust, which unfortunately involves a few backwards-incompatible changes. +We have tried to keep these to a minimum, but in some cases it is unavoidable. + +- ``random`` now uses a different random number generator and so the values you get even with the same seed have changed. + Notably, it will now work much more sensibly with very small seeds. + The seed was never guaranteed to give the same result across systems, + so we do not expect this to have a large impact (:issue:`9593`). +- ``functions --handlers`` will now list handlers in a different order. + Now it is definition order, first to last, where before it was last to first. + This was never specifically defined, and we recommend not relying on a specific order (:issue:`9944`). + Notable improvements and fixes ------------------------------ -- ``abbr --erase`` now also erases the universal variables used by the old abbr function. That means:: - abbr --erase (abbr --list) - - can now be used to clean out all old abbreviations (:issue:`9468`). -- ``abbr --add --universal`` now warns about --universal being non-functional, to make it easier to detect old-style ``abbr`` calls (:issue:`9475`). +- ``functions --handlers-type caller-exit`` once again lists functions defined as ``function --on-job-exit caller``, rather than them being listed by ``functions --handlers-type process-exit``. Deprecations and removed features --------------------------------- Scripting improvements ---------------------- -- ``abbr --list`` no longer escapes the abbr name, which is necessary to be able to pass it to ``abbr --erase`` (:issue:`9470`). -- ``read`` will now print an error if told to set a read-only variable instead of silently doing nothing (:issue:`9346`). +- ``functions`` and ``type`` now show where a function was copied and where it originally was instead of saying ``Defined interactively``. +- Stack trace now shows line numbers for copied functions. Interactive improvements ------------------------ -- Using ``fish_vi_key_bindings`` in combination with fish's ``--no-config`` mode works without locking up the shell (:issue:`9443`). -- The history pager now uses more screen space, usually half the screen (:issue:`9458`). - The history pager now shows fuzzy (subsequence) matches in the absence of exact substring matches (:issue:`9476`). -- Variables that were set while the locale was C (i.e. ASCII) will now properly be encoded if the locale is switched (:issue:`2613`, :issue:`9473`). -- Escape during history search restores the original commandline again (regressed in 3.6.0). -- Using ``--help`` on builtins now respects the $MANPAGER variable in preference to $PAGER (:issue:`9488`). +- Command-specific tab completions may now offer results whose first character is a period. For example, it is now possible to tab-complete ``git add`` for files with leading periods. The default file completions hide these files, unless the token itself has a leading period (:issue:`3707`). +- A new variable, :envvar:`fish_cursor_external`, can be used to specify to cursor shape when a command is launched. When unspecified, the value defaults to the value of :envvar:`fish_cursor_default` (:issue:`4656`). +- Selected text (for example, in vi visual mode) now respects the foreground color and other options such as bold (:issue:`9717`). +- An issue where the pager would not show the last item after pressing the up arrow key has been fixed (:issue:`9833`). New or improved bindings ^^^^^^^^^^^^^^^^^^^^^^^^ +- The ``E`` binding in vi mode now correctly handles the last character of the word, by jumping to the next word (:issue:`9700`). Improved prompts ^^^^^^^^^^^^^^^^ Completions ^^^^^^^^^^^ -- Added completions for: - - - ``otool`` - - ``mix phx`` - -- git's completion for ``git-foo``-style commands was fixed (:issue:`9457`) -- File completion now offers ``../`` and ``./`` again (:issue:`9477`) +- Added or improved completions for: + - ``ar`` (:issue:`9719`) +- ``gcc`` completion descriptions have been clarified and shortened (:issue:`9722`). +- ``qdbus`` completions now properly handle tags (:issue:`9776`). +- ``age`` (:issue:`9813`). +- ``age-keygen`` (:issue:`9813`). +- ``curl`` (:issue:`9863`). +- ``krita`` (:issue:`9903`). +- ``blender`` (:issue:`9905`). +- ``gimp`` (:issue:`9904`). +- ``horcrux`` (:issue:`9922`). Improved terminal support ^^^^^^^^^^^^^^^^^^^^^^^^^ Other improvements ------------------ - +- A bug that prevented certain executables from being offered in tab-completions when root has been fixed (:issue:`9639`). +- Builin `jobs` will print commands with non-printable chars escaped (:issue:`9808`) +- An integer overflow in `string repeat` leading to a near-infinite loop has been fixed (:issue:`9899`). +- `string shorten` behaves better in the presence of non-printable characters, including fixing an integer overflow that shortened strings more than intended. (:issue:`9854`) +- `string pad` no longer allows non-printable characters as padding. (:issue:`9854`) +- PWD reporting via OSC 7 is now enabled by default for iTerm2. For distributors ---------------- @@ -57,6 +75,77 @@ For distributors -------------- +fish 3.6.1 (released March 25, 2023) +==================================== + +This release of fish contains a number of fixes for problems identified in fish 3.6.0, as well as some enhancements. + +Notable improvements and fixes +------------------------------ +- ``abbr --erase`` now also erases the universal variables used by the old abbr function. That means:: + abbr --erase (abbr --list) + + can now be used to clean out all old abbreviations (:issue:`9468`). +- ``abbr --add --universal`` now warns about ``--universal`` being non-functional, to make it easier to detect old-style ``abbr`` calls (:issue:`9475`). + +Deprecations and removed features +--------------------------------- +- The Web-based configuration for abbreviations has been removed, as it was not functional with the changes abbreviations introduced in 3.6.0 (:issue:`9460`). + +Scripting improvements +---------------------- +- ``abbr --list`` no longer escapes the abbr name, which is necessary to be able to pass it to ``abbr --erase`` (:issue:`9470`). +- ``read`` will now print an error if told to set a read-only variable, instead of silently doing nothing (:issue:`9346`). +- ``set_color -v`` no longer crashes fish (:issue:`9640`). + +Interactive improvements +------------------------ +- Using ``fish_vi_key_bindings`` in combination with fish's ``--no-config`` mode works without locking up the shell (:issue:`9443`). +- The history pager now uses more screen space, usually half the screen (:issue:`9458`) +- Variables that were set while the locale was C (the default ASCII-only locale) will now properly be encoded if the locale is switched (:issue:`2613`, :issue:`9473`). +- Escape during history search restores the original command line again (fixing a regression in 3.6.0). +- Using ``--help`` on builtins now respects the ``$MANPAGER`` variable, in preference to ``$PAGER`` (:issue:`9488`). +- :kbd:`Control-G` closes the history pager, like other shells (:issue:`9484`). +- The documentation for the ``:``, ``[`` and ``.`` builtin commands can now be looked up with ``man`` (:issue:`9552`). +- fish no longer crashes when searching history for non-ASCII codepoints case-insensitively (:issue:`9628`). +- The :kbd:`Alt-S` binding will now also use ``please`` if available (:issue:`9635`). +- Themes that don't specify every color option can be installed correctly in the Web-based configuration (:issue:`9590`). +- Compatibility with Midnight Commander's prompt integration has been improved (:issue:`9540`). +- A spurious error, noted when using fish in Google Drive directories under WSL 2, has been silenced (:issue:`9550`). +- Using ``read`` in ``fish_greeting`` or similar functions will not trigger an infinite loop (:issue:`9564`). +- Compatibility when upgrading from old versions of fish (before 3.4.0) has been improved (:issue:`9569`). + +Improved prompts +^^^^^^^^^^^^^^^^ +- The git prompt will compute the stash count to be used independently of the informative status (:issue:`9572`). + +Completions +^^^^^^^^^^^ +- Added completions for: + - ``apkanalyzer`` (:issue:`9558`) + - ``neovim`` (:issue:`9543`) + - ``otool`` + - ``pre-commit`` (:issue:`9521`) + - ``proxychains`` (:issue:`9486`) + - ``scrypt`` (:issue:`9583`) + - ``stow`` (:issue:`9571`) + - ``trash`` and helper utilities ``trash-empty``, ``trash-list``, ``trash-put``, ``trash-restore`` (:issue:`9560`) + - ``ssh-copy-id`` (:issue:`9675`) +- Improvements to many completions, including the speed of completing directories in WSL 2 (:issue:`9574`). +- Completions using ``__fish_complete_suffix`` are now offered in the correct order, fixing a regression in 3.6.0 (:issue:`8924`). +- ``git`` completions for ``git-foo``-style commands was restored, fixing a regression in 3.6.0 (:issue:`9457`). +- File completion now offers ``../`` and ``./`` again, fixing a regression in 3.6.0 (:issue:`9477`). +- The behaviour of completions using ``__fish_complete_path`` matches standard path completions (:issue:`9285`). + +Other improvements +------------------ +- Improvements and corrections to the documentation. + +For distributors +---------------- +- fish 3.6.1 builds correctly on Cygwin (:issue:`9502`). + +-------------- fish 3.6.0 (released January 7, 2023) ===================================== diff --git a/CMakeLists.txt b/CMakeLists.txt index 08d7c54e3..dcf7edb40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,8 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}") endif() +include(cmake/Rust.cmake) + # Error out when linking statically, it doesn't work. if (CMAKE_EXE_LINKER_FLAGS MATCHES ".*-static.*") message(FATAL_ERROR "Fish does not support static linking") @@ -43,6 +45,9 @@ endif() # - address, because that occurs for our mkostemp check (weak-linking requires us to compare `&mkostemp == nullptr`). add_compile_options(-Wall -Wextra -Wno-comment -Wno-address) +# Get extra C++ files from Rust. +get_property(FISH_EXTRA_SOURCES TARGET fish-rust PROPERTY fish_extra_cpp_files) + if ((CMAKE_CXX_COMPILER_ID STREQUAL "Clang") OR (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")) add_compile_options(-Wunused-template -Wunused-local-typedef -Wunused-macros) endif() @@ -53,6 +58,9 @@ add_compile_options(-fno-exceptions) # Undefine NDEBUG to keep assert() in release builds. add_definitions(-UNDEBUG) +# Allow including Rust headers in normal (not bindgen) builds. +add_definitions(-DINCLUDE_RUST_HEADERS) + # Enable large files on GNU. add_definitions(-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE @@ -91,36 +99,32 @@ endif() # List of sources for builtin functions. set(FISH_BUILTIN_SRCS - src/builtin.cpp src/builtins/abbr.cpp src/builtins/argparse.cpp - src/builtins/bg.cpp src/builtins/bind.cpp src/builtins/block.cpp - src/builtins/builtin.cpp src/builtins/cd.cpp src/builtins/command.cpp - src/builtins/commandline.cpp src/builtins/complete.cpp src/builtins/contains.cpp - src/builtins/disown.cpp src/builtins/echo.cpp src/builtins/emit.cpp - src/builtins/eval.cpp src/builtins/exit.cpp src/builtins/fg.cpp - src/builtins/function.cpp src/builtins/functions.cpp src/builtins/history.cpp - src/builtins/jobs.cpp src/builtins/math.cpp src/builtins/printf.cpp src/builtins/path.cpp - src/builtins/pwd.cpp src/builtins/random.cpp src/builtins/read.cpp - src/builtins/realpath.cpp src/builtins/return.cpp src/builtins/set.cpp - src/builtins/set_color.cpp src/builtins/source.cpp src/builtins/status.cpp - src/builtins/string.cpp src/builtins/test.cpp src/builtins/type.cpp src/builtins/ulimit.cpp - src/builtins/wait.cpp) + src/builtin.cpp src/builtins/bind.cpp + src/builtins/commandline.cpp src/builtins/complete.cpp + src/builtins/disown.cpp + src/builtins/eval.cpp src/builtins/fg.cpp + src/builtins/history.cpp + src/builtins/jobs.cpp + src/builtins/read.cpp src/builtins/set.cpp + src/builtins/source.cpp + src/builtins/ulimit.cpp +) # List of other sources. set(FISH_SRCS - src/ast.cpp src/abbrs.cpp src/autoload.cpp src/color.cpp src/common.cpp src/complete.cpp - src/env.cpp src/env_dispatch.cpp src/env_universal_common.cpp src/event.cpp - src/exec.cpp src/expand.cpp src/fallback.cpp src/fd_monitor.cpp src/fish_version.cpp - src/flog.cpp src/function.cpp src/future_feature_flags.cpp src/highlight.cpp + src/ast.cpp src/autoload.cpp src/color.cpp src/common.cpp src/complete.cpp + src/env.cpp src/env_universal_common.cpp src/event.cpp + src/exec.cpp src/expand.cpp src/fallback.cpp src/fish_indent_common.cpp src/fish_version.cpp + src/flog.cpp src/function.cpp src/highlight.cpp src/history.cpp src/history_file.cpp src/input.cpp src/input_common.cpp - src/io.cpp src/iothread.cpp src/job_group.cpp src/kill.cpp + src/io.cpp src/null_terminated_array.cpp src/operation_context.cpp src/output.cpp - src/pager.cpp src/parse_execution.cpp src/parse_tree.cpp src/parse_util.cpp + src/pager.cpp src/parse_execution.cpp src/parse_util.cpp src/parser.cpp src/parser_keywords.cpp src/path.cpp src/postfork.cpp - src/proc.cpp src/re.cpp src/reader.cpp src/redirection.cpp src/screen.cpp - src/signal.cpp src/termsize.cpp src/timer.cpp src/tinyexpr.cpp - src/tokenizer.cpp src/topic_monitor.cpp src/trace.cpp src/utf8.cpp src/util.cpp - src/wait_handle.cpp src/wcstringutil.cpp src/wgetopt.cpp src/wildcard.cpp - src/wutil.cpp src/fds.cpp + src/proc.cpp src/reader.cpp src/screen.cpp + src/signals.cpp src/utf8.cpp + src/wcstringutil.cpp src/wgetopt.cpp src/wildcard.cpp + src/wutil.cpp src/fds.cpp src/rustffi.cpp ) # Header files are just globbed. @@ -133,6 +137,11 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config_cmake.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) include_directories(${CMAKE_CURRENT_BINARY_DIR}) +# Pull in our src directory for headers searches, but only quoted ones. +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -iquote ${CMAKE_CURRENT_SOURCE_DIR}/src") + + + # Set up standard directories. include(GNUInstallDirs) add_definitions(-D_UNICODE=1 @@ -175,8 +184,10 @@ endfunction(FISH_LINK_DEPS_AND_SIGN) add_library(fishlib STATIC ${FISH_SRCS} ${FISH_BUILTIN_SRCS}) target_sources(fishlib PRIVATE ${FISH_HEADERS}) target_link_libraries(fishlib + fish-rust ${CURSES_LIBRARY} ${CURSES_EXTRA_LIBRARY} Threads::Threads ${CMAKE_DL_LIBS} - ${PCRE2_LIB} ${Intl_LIBRARIES} ${ATOMIC_LIBRARY}) + ${PCRE2_LIB} ${Intl_LIBRARIES} ${ATOMIC_LIBRARY} + "fish-rust") target_include_directories(fishlib PRIVATE ${CURSES_INCLUDE_DIRS}) @@ -186,12 +197,12 @@ fish_link_deps_and_sign(fish) # Define fish_indent. add_executable(fish_indent - src/fish_indent.cpp src/print_help.cpp) + src/fish_indent.cpp) fish_link_deps_and_sign(fish_indent) # Define fish_key_reader. add_executable(fish_key_reader - src/fish_key_reader.cpp src/print_help.cpp) + src/fish_key_reader.cpp) fish_link_deps_and_sign(fish_key_reader) # Set up the docs. diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 6bfc24ba5..2844be013 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -1,9 +1,46 @@ -Guidelines For Developers -========================= +#################### +Contributing To Fish +#################### -This document provides guidelines for making changes to the fish-shell -project. This includes rules for how to format the code, naming -conventions, et cetera. +This document tells you how you can contribute to fish. + +Fish is free and open source software, distributed under the terms of the GPLv2. + +Contributions are welcome, and there are many ways to contribute! + +Whether you want to change some of the core rust/C++ source, enhance or add a completion script or function, +improve the documentation or translate something, this document will tell you how. + +Getting Set Up +============== + +Fish is developed on Github, at https://github.com/fish-shell/fish-shell. + +First, you'll need an account there, and you'll need a git clone of fish. +Fork it on Github and then run:: + + git clone https://github.com//fish-shell.git + +This will create a copy of the fish repository in the directory fish-shell in your current working directory. + +Also, for most changes you want to run the tests and so you'd get a setup to compile fish. +For that, you'll require: + +- Rust (version 1.67 or later) - when in doubt, try rustup +- a C++11 compiler (g++ 4.8 or later, or clang 3.3 or later) +- CMake (version 3.5 or later) +- a curses implementation such as ncurses (headers and libraries) +- PCRE2 (headers and libraries) - optional, this will be downloaded if missing +- gettext (headers and libraries) - optional, for translation support +- Sphinx - optional, to build the documentation + +Of course not everything is required always - if you just want to contribute something to the documentation you'll just need Sphinx, +and if the change is very simple and obvious you can just send it in. Use your judgement! + +Once you have your changes, open a pull request on https://github.com/fish-shell/fish-shell/pulls. + +Guidelines +========== In short: @@ -11,7 +48,7 @@ In short: - Use automated tools to help you (including ``make test``, ``build_tools/style.fish`` and ``make lint``) Contributing completions ------------------------- +======================== Completion scripts are the most common contribution to fish, and they are very welcome. @@ -42,16 +79,29 @@ Put your completion script into share/completions/name-of-command.fish. If you h If you want to add tests, you probably want to add a littlecheck test. See below for details. -Contributing to fish's C++ core -------------------------------- +Contributing documentation +========================== -Fish uses C++11. Newer C++ features should not be used to make it possible to use on older systems. +The documentation is stored in ``doc_src/``, and written in ReStructured Text and built with Sphinx. -It does not use exceptions, they are disabled at build time with ``-fno-exceptions``. +To build it locally, run from the main fish-shell directory:: -Don't introduce new dependencies unless absolutely necessary, and if you do, -please make it optional with graceful failure if possible. -Add any new dependencies to the README.rst under the *Running* and/or *Building* sections. + sphinx-build -j 8 -b html -n doc_src/ /tmp/fish-doc/ + +which will build the docs as html in /tmp/fish-doc. You can open it in a browser and see that it looks okay. + +The builtins and various functions shipped with fish are documented in doc_src/cmds/. + +Contributing to fish's Rust/C++ core +==================================== + +As of now, fish is in the process of switching from C++11 to Rust, so this is in flux. + +See doc_internal/rust-devel.md for some information on the port. + +Importantly, the initial port strives for fidelity with the existing C++ codebase, +so it won't be 100% idiomatic rust - in some cases it'll have some awkward interface code +in order to interact with the C++. Linters ------- @@ -70,29 +120,10 @@ help catch mistakes such as using ``wcwidth()`` rather than ``fish_wcwidth()``. Please add a new rule if you find similar mistakes being made. -Suppressing Lint Warnings -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Once in a while the lint tools emit a false positive warning. For -example, cppcheck might suggest a memory leak is present when that is -not the case. To suppress that cppcheck warning you should insert a line -like the following immediately prior to the line cppcheck warned about: - -:: - - // cppcheck-suppress memleak // addr not really leaked - -The explanatory portion of the suppression comment is optional. For -other types of warnings replace “memleak” with the value inside the -parenthesis (e.g., “nullPointerRedundantCheck”) from a warning like the -following: - -:: - - [src/complete.cpp:1727]: warning (nullPointerRedundantCheck): Either the condition 'cmd_node' is redundant or there is possible null pointer dereference: cmd_node. +We use ``clippy`` for Rust. Code Style ----------- +========== To ensure your changes conform to the style rules run @@ -122,6 +153,20 @@ If you want to check the style of the entire code base run That command will refuse to restyle any files if you have uncommitted changes. +Fish Script Style Guide +----------------------- + +1. All fish scripts, such as those in the *share/functions* and *tests* + directories, should be formatted using the ``fish_indent`` command. + +2. Function names should be in all lowercase with words separated by + underscores. Private functions should begin with an underscore. The + first word should be ``fish`` if the function is unique to fish. + +3. The first word of global variable names should generally be ``fish`` + for public vars or ``_fish`` for private vars to minimize the + possibility of name clashes with user defined vars. + Configuring Your Editor for Fish Scripts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -158,20 +203,6 @@ made to run fish_indent via e.g. (add-hook 'fish-mode-hook (lambda () (add-hook 'before-save-hook 'fish_indent-before-save))) -Fish Script Style Guide ------------------------ - -1. All fish scripts, such as those in the *share/functions* and *tests* - directories, should be formatted using the ``fish_indent`` command. - -2. Function names should be in all lowercase with words separated by - underscores. Private functions should begin with an underscore. The - first word should be ``fish`` if the function is unique to fish. - -3. The first word of global variable names should generally be ``fish`` - for public vars or ``_fish`` for private vars to minimize the - possibility of name clashes with user defined vars. - C++ Style Guide --------------- @@ -215,8 +246,13 @@ or /// brief description of somefunction() void somefunction() { +Rust Style Guide +---------------- + +Use ``cargo fmt`` and ``cargo clippy``. Clippy warnings can be turned off if there's a good reason to. + Testing -------- +======= The source code for fish includes a large collection of tests. If you are making any changes to fish, running these tests is a good way to make @@ -241,7 +277,7 @@ fish_tests.cpp is mostly useful for unit tests - if you wish to test that a func 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 -~~~~~~~~~~~~~ +------------- The tests can be run on your local computer on all operating systems. @@ -251,7 +287,7 @@ The tests can be run on your local computer on all operating systems. make test Git hooks -~~~~~~~~~ +--------- Since developers sometimes forget to run the tests, it can be helpful to use git hooks (see githooks(5)) to automate it. @@ -294,7 +330,7 @@ To install the hook, place the code in a new file ``.git/hooks/pre-push`` and make it executable. Coverity Scan -~~~~~~~~~~~~~ +------------- We use Coverity’s static analysis tool which offers free access to open source projects. While access to the tool itself is restricted, @@ -304,46 +340,64 @@ with their GitHub account. Currently, tests are triggered upon merging the ``master`` branch into ``coverity_scan_master``. Even if you are not a fish developer, you can keep an eye on our statistics there. -Installing the Required Tools ------------------------------ - -Installing the Linting Tools -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -To install the lint checkers on Mac OS X using Homebrew: - -:: - - brew install cppcheck - -To install the lint checkers on Debian-based Linux distributions: - -:: - - sudo apt-get install clang - sudo apt-get install cppcheck - -Installing the Formatting Tools -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Mac OS X: - -:: - - brew install clang-format - -Debian-based: - -:: - - sudo apt-get install clang-format - -Message Translations --------------------- +Contributing Translations +========================= Fish uses the GNU gettext library to translate messages from English to other languages. +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 (eg ``de`` for +German). + +To create a new translation: + +* generate a ``messages.pot`` file by running ``build_tools/fish_xgettext.fish`` from + the source tree +* copy ``messages.pot`` to ``po/LANG.po`` + +To update a translation: + +* generate a ``messages.pot`` file by running + ``build_tools/fish_xgettext.fish`` from the source tree + +* update the existing translation by running + ``msgmerge --update --no-fuzzy-matching po/LANG.po messages.pot`` + +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 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 "" + +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:: + + msgid "%ls: No suitable job\n" + msgstr "%ls: Inget passande jobb\n" + +Any ``%s`` / ``%ls`` or ``%d`` are placeholders that fish will use for formatting at runtime. It is important that they match - the translated string should have the same placeholders in the same order. + +Also any escaped characters, like that ``\n`` newline at the end, should be kept so the translation has the same behavior. + +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. 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 +-------------------------------- + All non-debug messages output for user consumption should be marked for translation. In C++, this requires the use of the ``_`` (underscore) macro: @@ -353,7 +407,8 @@ macro: streams.out.append_format(_(L"%ls: There are no jobs\n"), argv[0]); All messages in fish script must be enclosed in single or double quote -characters. They must also be translated via a subcommand. This means +characters for our message extraction script to find them. +They must also be translated via a command substitution. This means that the following are **not** valid: :: @@ -368,82 +423,15 @@ Above should be written like this instead: echo (_ "hello") echo (_ "goodbye") -Note that you can use either single or double quotes to enclose the +You can use either single or double quotes to enclose the message to be translated. You can also optionally include spaces after -the opening parentheses and once again before the closing parentheses. - -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 (eg ``de`` for -German). - -To create a new translation, for example for German: - -* generate a ``messages.pot`` file by running ``build_tools/fish_xgettext.fish`` from - the source tree -* copy ``messages.pot`` to ``po/LANG.po`` - -To update a translation: - -* generate a ``messages.pot`` file by running - ``build_tools/fish_xgettext.fish`` from the source tree - -* update the existing translation by running - ``msgmerge --update --no-fuzzy-matching po/LANG.po messages.pot`` - -Many tools are available for editing translation files, including -command-line and graphical user interface programs. - -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. - -Read the `translations -wiki `__ for -more information. +the opening parentheses or before the closing parentheses. Versioning ----------- +========== The fish version is constructed by the *build_tools/git_version_gen.sh* script. For developers the version is the branch name plus the output of ``git describe --always --dirty``. Normally the main part of the version will be the closest annotated tag. Which itself is usually the most recent release number (e.g., ``2.6.0``). - -Include What You Use --------------------- - -You should not depend on symbols being visible to a ``*.cpp`` module -from ``#include`` statements inside another header file. In other words -if your module does ``#include "common.h"`` and that header does -``#include "signal.h"`` your module should not assume the sub-include is -present. It should instead directly ``#include "signal.h"`` if it needs -any symbol from that header. That makes the actual dependencies much -clearer. It also makes it easy to modify the headers included by a -specific header file without having to worry that will break any module -(or header) that includes a particular header. - -To help enforce this rule the ``make lint`` (and ``make lint-all``) -command will run the -`include-what-you-use `__ tool. You -can find the IWYU project on -`github `__. - -To install the tool on OS X you’ll need to add a -`formula `__ then install -it: - -:: - - brew tap jasonmp85/iwyu - brew install iwyu - -On Ubuntu you can install it via ``apt-get``: - -:: - - sudo apt-get install iwyu diff --git a/COPYING b/COPYING index 6d7be3d85..448c5b46d 100644 --- a/COPYING +++ b/COPYING @@ -9,8 +9,9 @@ Most of fish is licensed under the GNU General Public License version 2, and you can redistribute it and/or modify it under the terms of the GNU GPL as published by the Free Software Foundation. -fish also includes software licensed under the GNU Lesser General Public -License version 2, the OpenBSD license, the ISC license, and the NetBSD license. +fish also includes software licensed under the CMake license, the Python +Software Foundation License version 2, the OpenBSD license, the ISC license, +the NetBSD license, and the MIT license. Full licensing information is contained in doc_src/license.rst. diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 000000000..629693d50 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1126 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8f9420f797f2d9e935edf629310eb938a0d839f984e25327f3c7eed22300c" +dependencies = [ + "memchr", +] + +[[package]] +name = "aquamarine" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a941c39708478e8eea39243b5983f1c42d2717b3620ee91f4a52115fd02ac43f" +dependencies = [ + "itertools 0.9.0", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "autocxx" +version = "0.23.1" +source = "git+https://github.com/fish-shell/autocxx?branch=fish#f9ed164fed6a35a572d19f1495b0691e4b3fd92b" +dependencies = [ + "aquamarine", + "autocxx-macro", + "cxx", + "moveit", +] + +[[package]] +name = "autocxx-bindgen" +version = "0.62.0" +source = "git+https://github.com/fish-shell/autocxx-bindgen?branch=fish#a229d3473bd90d2d10fc61a244408cfc1958934a" +dependencies = [ + "bitflags 1.3.2", + "cexpr", + "clang-sys", + "itertools 0.10.5", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 1.0.109", + "which", +] + +[[package]] +name = "autocxx-build" +version = "0.23.1" +source = "git+https://github.com/fish-shell/autocxx?branch=fish#f9ed164fed6a35a572d19f1495b0691e4b3fd92b" +dependencies = [ + "autocxx-engine", + "env_logger", + "indexmap", + "syn 1.0.109", +] + +[[package]] +name = "autocxx-engine" +version = "0.23.1" +source = "git+https://github.com/fish-shell/autocxx?branch=fish#f9ed164fed6a35a572d19f1495b0691e4b3fd92b" +dependencies = [ + "aquamarine", + "autocxx-bindgen", + "autocxx-parser", + "cc", + "cxx-gen", + "indexmap", + "indoc", + "itertools 0.10.5", + "log", + "miette", + "once_cell", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustversion", + "serde_json", + "strum_macros", + "syn 1.0.109", + "tempfile", + "thiserror", + "version_check", +] + +[[package]] +name = "autocxx-macro" +version = "0.23.1" +source = "git+https://github.com/fish-shell/autocxx?branch=fish#f9ed164fed6a35a572d19f1495b0691e4b3fd92b" +dependencies = [ + "autocxx-parser", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "autocxx-parser" +version = "0.23.1" +source = "git+https://github.com/fish-shell/autocxx?branch=fish#f9ed164fed6a35a572d19f1495b0691e4b3fd92b" +dependencies = [ + "indexmap", + "itertools 0.10.5", + "log", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn 1.0.109", + "thiserror", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + +[[package]] +name = "cc" +version = "1.0.79" +source = "git+https://github.com/mqudsi/cc-rs?branch=fish#cdc3a376eb0f56c2fb2cf640cc0e9192feaa621b" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clang-sys" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "cxx" +version = "1.0.81" +source = "git+https://github.com/fish-shell/cxx?branch=fish#3064cb46c16fa1eb5398870f2f4e830c4ca071b8" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", + "widestring", +] + +[[package]] +name = "cxx-build" +version = "1.0.81" +source = "git+https://github.com/fish-shell/cxx?branch=fish#3064cb46c16fa1eb5398870f2f4e830c4ca071b8" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn 1.0.109", +] + +[[package]] +name = "cxx-gen" +version = "0.7.81" +source = "git+https://github.com/fish-shell/cxx?branch=fish#3064cb46c16fa1eb5398870f2f4e830c4ca071b8" +dependencies = [ + "codespan-reporting", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.81" +source = "git+https://github.com/fish-shell/cxx?branch=fish#3064cb46c16fa1eb5398870f2f4e830c4ca071b8" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.81" +source = "git+https://github.com/fish-shell/cxx?branch=fish#3064cb46c16fa1eb5398870f2f4e830c4ca071b8" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fast-float" +version = "0.2.0" +source = "git+https://github.com/fish-shell/fast-float-rust?branch=fish#9590c33a3f166a3533ba1cbb7a03e1105acec034" + +[[package]] +name = "fastrand" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" + +[[package]] +name = "fish-rust" +version = "0.1.0" +dependencies = [ + "autocxx", + "autocxx-build", + "bitflags 1.3.2", + "cc", + "cxx", + "cxx-build", + "cxx-gen", + "errno 0.2.8", + "fast-float", + "hexponent", + "inventory", + "lazy_static", + "libc", + "lru", + "moveit", + "nix", + "num-derive", + "num-traits", + "once_cell", + "pcre2", + "printf-compat", + "rand", + "rand_pcg", + "rsconf", + "unixstring", + "widestring", + "widestring-suffix", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hexponent" +version = "0.3.1" +source = "git+https://github.com/fish-shell/hexponent?branch=fish#71febaf2ffa3c63ea50a70aa4308293d69bd709c" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indoc" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" + +[[package]] +name = "inventory" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a53088c87cf71c9d4f3372a2cb9eea1e7b8a0b1bf8b7f7d23fe5b76dbb07e63b" + +[[package]] +name = "itertools" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "jobserver" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +dependencies = [ + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "link-cplusplus" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" +dependencies = [ + "cc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "lru" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "718e8fae447df0c7e1ba7f5189829e63fd536945c8988d61444c19039f16b670" +dependencies = [ + "hashbrown 0.13.2", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "miette" +version = "5.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" +dependencies = [ + "miette-derive", + "once_cell", + "thiserror", + "unicode-width", +] + +[[package]] +name = "miette-derive" +version = "5.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "moveit" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d756ffe4e38013507d35bf726a93fcdae2cae043ab5ce477f13857a335030d" +dependencies = [ + "cxx", +] + +[[package]] +name = "nix" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "libc", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num-traits" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "pcre2" +version = "0.2.3" +source = "git+https://github.com/fish-shell/rust-pcre2?branch=master#813a4267546e5ca8ff349c9c67d65e52a82172d2" +dependencies = [ + "libc", + "log", + "pcre2-sys", + "thread_local", +] + +[[package]] +name = "pcre2-sys" +version = "0.2.4" +source = "git+https://github.com/fish-shell/rust-pcre2?branch=master#813a4267546e5ca8ff349c9c67d65e52a82172d2" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "prettyplease" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +dependencies = [ + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "printf-compat" +version = "0.1.1" +source = "git+https://github.com/fish-shell/printf-compat.git?branch=fish#ff460021ba11e2a2c69e1fe04cb1961d6a75be15" +dependencies = [ + "bitflags 1.3.2", + "itertools 0.9.0", + "libc", + "widestring", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_pcg" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59cad018caf63deb318e5a4586d99a24424a364f40f1e5778c29aca23f4fc73e" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" + +[[package]] +name = "rsconf" +version = "0.1.0" +source = "git+https://github.com/mqudsi/rsconf?branch=master#0790778ef5ec521bfc15a34a6b07caf25aa0a0db" +dependencies = [ + "cc", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustix" +version = "0.38.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" +dependencies = [ + "bitflags 2.4.0", + "errno 0.3.2", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "scratch" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" + +[[package]] +name = "serde" +version = "1.0.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "serde_json" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "shlex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys", +] + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "unixstring" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "366c5c5657cbe7a684b3476acc7b96d4087e953bf750b1eab4dfbffeda32b2f3" +dependencies = [ + "libc", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "which" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" +dependencies = [ + "either", + "libc", + "once_cell", +] + +[[package]] +name = "widestring" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" + +[[package]] +name = "widestring-suffix" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 000000000..8b1375868 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,31 @@ +[workspace] +resolver = "2" +members = [ + "fish-rust", + "fish-rust/widestring-suffix", +] +default-members = ["fish-rust"] + +[workspace.package] +rust-version = "1.67" +edition = "2021" + +# TODO: Move fish-rust to src, make it the root package of this workspace + +[patch.crates-io] +cc = { git = "https://github.com/mqudsi/cc-rs", branch = "fish" } +cxx = { git = "https://github.com/fish-shell/cxx", branch = "fish" } +cxx-gen = { git = "https://github.com/fish-shell/cxx", branch = "fish" } +autocxx = { git = "https://github.com/fish-shell/autocxx", branch = "fish" } +autocxx-build = { git = "https://github.com/fish-shell/autocxx", branch = "fish" } +autocxx-bindgen = { git = "https://github.com/fish-shell/autocxx-bindgen", branch = "fish" } + +[patch.'https://github.com/fish-shell/cxx'] +cc = { git = "https://github.com/mqudsi/cc-rs", branch = "fish" } + +[patch.'https://github.com/fish-shell/autocxx'] +cc = { git = "https://github.com/mqudsi/cc-rs", branch = "fish" } + + +[profile.release] +overflow-checks = true diff --git a/README.rst b/README.rst index d13e9e5f0..b02da5ad4 100644 --- a/README.rst +++ b/README.rst @@ -146,7 +146,7 @@ Building Dependencies ~~~~~~~~~~~~ -Compiling fish requires: +Compiling fish from a tarball requires: - a C++11 compiler (g++ 4.8 or later, or clang 3.3 or later) - CMake (version 3.5 or later) @@ -159,6 +159,20 @@ cloned git repository. Additionally, running the test suite requires Python 3.5+ and the pexpect package. +Dependencies, git master +~~~~~~~~~~~~~~~~~~~~~~~~ + +Building from git master currently requires, in addition to the dependencies for a tarball: + +- Rust (version 1.67 or later) +- libclang, even if you are compiling with GCC +- an Internet connection + +fish is in the process of being ported to Rust, replacing all C++ code, and as such these dependencies are a bit awkward and in flux. + +In general, we would currently not recommend running from git master if you just want to *use* fish. +Given the nature of the port, what is currently there is mostly a slower and buggier version of the last C++-based release. + Building from source (all platforms) - Makefile generator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -174,34 +188,12 @@ To install into ``/usr/local``, run: The install directory can be changed using the ``-DCMAKE_INSTALL_PREFIX`` parameter for ``cmake``. -Building from source (macOS) - Xcode -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Note: The minimum supported macOS version is 10.10 "Yosemite". - -.. code:: bash - - mkdir build; cd build - cmake .. -G Xcode - -An Xcode project will now be available in the ``build`` subdirectory. -You can open it with Xcode, or run the following to build and install in -``/usr/local``: - -.. code:: bash - - xcodebuild - xcodebuild -scheme install - -The install directory can be changed using the -``-DCMAKE_INSTALL_PREFIX`` parameter for ``cmake``. - Build options ~~~~~~~~~~~~~ -In addition to the normal cmake build options (like ``CMAKE_INSTALL_PREFIX``), fish has some other options available to customize it. +In addition to the normal CMake build options (like ``CMAKE_INSTALL_PREFIX``), fish has some other options available to customize it. -- BUILD_DOCS=ON|OFF - whether to build the documentation. This is automatically set to OFF when sphinx isn't installed. +- 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. - MAC_CODESIGN_ID=String|OFF - the codesign ID to use on Mac, or "OFF" to disable codesigning. diff --git a/benchmarks/benchmarks/load_completions.fish b/benchmarks/benchmarks/load_completions.fish new file mode 100644 index 000000000..504dcb47f --- /dev/null +++ b/benchmarks/benchmarks/load_completions.fish @@ -0,0 +1,12 @@ +set -l compdir (status dirname)/../../share/completions +cd $compdir +for file in *.fish + set -l bname (string replace -r '.fish$' '' -- $file) + if type -q $bname + source $file >/dev/null + if test $status -gt 0 + echo FAILING FILE $file + end + end + +end diff --git a/benchmarks/benchmarks/no_execute.fish b/benchmarks/benchmarks/no_execute.fish new file mode 100644 index 000000000..633826c0b --- /dev/null +++ b/benchmarks/benchmarks/no_execute.fish @@ -0,0 +1,6 @@ +set -l path (status dirname) +set -l fish (status fish-path) +for f in (seq 100) + echo $fish -n $path/aliases.fish + $fish -n $path/aliases.fish +end diff --git a/benchmarks/benchmarks/printf-escapes.fish b/benchmarks/benchmarks/printf-escapes.fish new file mode 100644 index 000000000..c882ed0bb --- /dev/null +++ b/benchmarks/benchmarks/printf-escapes.fish @@ -0,0 +1 @@ +printf (string repeat -n 200 \\x7f)%s\n (string repeat -n 2000 aaa\n) diff --git a/benchmarks/benchmarks/printf.fish b/benchmarks/benchmarks/printf.fish new file mode 100644 index 000000000..9b1887990 --- /dev/null +++ b/benchmarks/benchmarks/printf.fish @@ -0,0 +1,5 @@ +for i in (seq 100000) + printf '%f\n' $i.$i +end + +exit 0 diff --git a/benchmarks/benchmarks/read.fish b/benchmarks/benchmarks/read.fish new file mode 100644 index 000000000..de86c5ef3 --- /dev/null +++ b/benchmarks/benchmarks/read.fish @@ -0,0 +1,7 @@ +set -l tmp (mktemp) +string repeat -n 2000 >$tmp +for i in (seq 1000) + cat $tmp | read -l foo +end + +true diff --git a/benchmarks/benchmarks/set_long.fish b/benchmarks/benchmarks/set_long.fish new file mode 100644 index 000000000..4b6b2e19c --- /dev/null +++ b/benchmarks/benchmarks/set_long.fish @@ -0,0 +1,3 @@ +for abc in (seq 100000) + set -l def +end diff --git a/benchmarks/benchmarks/string-repeat.fish b/benchmarks/benchmarks/string-repeat.fish new file mode 100644 index 000000000..38af9119d --- /dev/null +++ b/benchmarks/benchmarks/string-repeat.fish @@ -0,0 +1,3 @@ +for i in (string repeat -n 100 \n) + string repeat -n 50000 a\n +end diff --git a/benchmarks/benchmarks/string-wildcard.fish b/benchmarks/benchmarks/string-wildcard.fish new file mode 100644 index 000000000..12590f0ab --- /dev/null +++ b/benchmarks/benchmarks/string-wildcard.fish @@ -0,0 +1,3 @@ +for i in (seq 100000) + string match '*o' fooooooo +end diff --git a/benchmarks/benchmarks/string.fish b/benchmarks/benchmarks/string.fish new file mode 100644 index 000000000..94baebbc1 --- /dev/null +++ b/benchmarks/benchmarks/string.fish @@ -0,0 +1,3 @@ +for i in (seq 100000) + string match -r '^.*$' fooooooo +end | string match -re o diff --git a/build_tools/asan_blacklist.txt b/build_tools/asan_blacklist.txt new file mode 100644 index 000000000..f9e2129b6 --- /dev/null +++ b/build_tools/asan_blacklist.txt @@ -0,0 +1,3 @@ +# Ignore a one-off leak in __cxa_thread_atexit_impl that isn't under our control. +# See https://github.com/fish-shell/fish-shell/pull/9754#issuecomment-1523782989 +fun:__cxa_thread_atexit_impl diff --git a/build_tools/find_globals.fish b/build_tools/find_globals.fish index 1fa1d44ed..7cee77ab4 100755 --- a/build_tools/find_globals.fish +++ b/build_tools/find_globals.fish @@ -39,7 +39,7 @@ end function cleanup_syname set -l symname $argv[1] set symname (string replace --all 'std::__1::basic_string, std::__1::allocator >' 'wcstring' $symname) - set symname (string replace --all 'std::__1::vector >' 'wcstring_list_t' $symname) + set symname (string replace --all 'std::__1::vector >' 'std::vector' $symname) echo $symname end diff --git a/build_tools/iwyu.osx.imp b/build_tools/iwyu.osx.imp index 342d8f301..b6f4bba7f 100644 --- a/build_tools/iwyu.osx.imp +++ b/build_tools/iwyu.osx.imp @@ -92,10 +92,7 @@ { symbol: ["assert", "private", '"../common.h"', "public"] }, { symbol: ["wcstring", "private", '"common.h"', "public"] }, { symbol: ["wcstring", "private", '"../common.h"', "public"] }, - { symbol: ["wcstring_list_t", "private", '"common.h"', "public"] }, - { symbol: ["wcstring_list_t", "private", '"../common.h"', "public"] }, { symbol: ["wcstring", "private", '"flog.h"', "public"] }, - { symbol: ["wcstring_list_t", "private", '"flog.h"', "public"] }, { symbol: ["size_t", "private", "", "public"] }, { symbol: ["mutex", "private", "", "public"] }, { symbol: ["sig_atomic_t", "private", "", "public"] }, diff --git a/build_tools/lsan_suppressions.txt b/build_tools/lsan_suppressions.txt new file mode 100644 index 000000000..2ba5ddae6 --- /dev/null +++ b/build_tools/lsan_suppressions.txt @@ -0,0 +1,6 @@ +# LSAN can detect leaks tracing back to __asan::AsanThread::ThreadStart (probably caused by our +# threads not exiting before their TLS dtors are called). Just ignore it. +leak:AsanThread + +# ncurses leaks allocations freely as it assumes it will be running throughout. Ignore these. +leak:tparm diff --git a/build_tools/make_tarball.sh b/build_tools/make_tarball.sh index 663078e06..57c118c3d 100755 --- a/build_tools/make_tarball.sh +++ b/build_tools/make_tarball.sh @@ -14,6 +14,14 @@ set -e # but to get the documentation in, we need to make a symlink called "fish-VERSION" # and tar from that, so that the documentation gets the right prefix +# Use Ninja if available, as it automatically paralellises +BUILD_TOOL="make" +BUILD_GENERATOR="Unix Makefiles" +if command -v ninja >/dev/null; then + 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 @@ -51,8 +59,8 @@ git archive --format=tar --prefix="$prefix"/ HEAD > "$path" PREFIX_TMPDIR=$(mktemp -d) cd "$PREFIX_TMPDIR" echo "$VERSION" > version -cmake "$wd" -make doc +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\//" @@ -60,12 +68,17 @@ $TAR_APPEND --no-recursion user_doc $TAR_APPEND user_doc/html user_doc/man $TAR_APPEND version +if [ -n "$VENDOR_TARBALLS" ]; then + $BUILD_TOOL corrosion-vendor.tar.gz + mv corrosion-vendor.tar.gz ${FISH_ARTEFACT_PATH:-~/fish_built}/"${prefix}"_corrosion-vendor.tar.gz +fi + cd - rm -r "$PREFIX_TMPDIR" # xz it xz "$path" -# Output what we did, and the sha1 hash +# Output what we did, and the sha256 hash echo "Tarball written to $path".xz openssl dgst -sha256 "$path".xz diff --git a/build_tools/style.fish b/build_tools/style.fish index 31b0d1b64..19d466c64 100755 --- a/build_tools/style.fish +++ b/build_tools/style.fish @@ -7,6 +7,7 @@ set -l git_clang_format no set -l c_files set -l fish_files set -l python_files +set -l rust_files set -l all no if test "$argv[1]" = --all @@ -25,13 +26,14 @@ if test $all = yes 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 + if not string match -qi y -- $ans exit 1 end end set c_files src/*.h src/*.cpp src/*.c set fish_files share/**.fish set python_files {doc_src,share,tests}/**.py + set rust_files fish-rust/src/**.rs else # We haven't been asked to reformat all the source. If there are uncommitted changes reformat # those using `git clang-format`. Else reformat the files in the most recent commit. @@ -52,6 +54,7 @@ else # 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) end set -l red (set_color red) @@ -82,9 +85,9 @@ if set -q c_files[1] if set -q c_files[1] printf "Reformat those %d files?\n" (count $c_files) read -P 'y/N? ' -n1 -l ans - if string match -qi "y" -- $ans + if string match -qi y -- $ans clang-format -i --verbose $c_files - else if string match -qi "n" -- $ans + else if string match -qi n -- $ans echo Skipping else # like they ctrl-C'd or something. exit 1 @@ -117,3 +120,14 @@ if set -q python_files[1] black $python_files end end + +if set -q rust_files[1] + if not type -q rustfmt + echo + echo Please install "`rustfmt`" to style rust + echo + else + echo === Running "$blue"rustfmt"$normal" + rustfmt $rust_files + end +end diff --git a/cmake/ConfigureChecks.cmake b/cmake/ConfigureChecks.cmake index b2b47c0d3..db7ba5757 100644 --- a/cmake/ConfigureChecks.cmake +++ b/cmake/ConfigureChecks.cmake @@ -1,8 +1,6 @@ # The following defines affect the environment configuration tests are run in: # CMAKE_REQUIRED_DEFINITIONS, CMAKE_REQUIRED_FLAGS, CMAKE_REQUIRED_LIBRARIES, # and CMAKE_REQUIRED_INCLUDES -# `wcstod_l` is a GNU-extension, sometimes hidden behind GNU-related defines. -# This is the case for at least Cygwin and Newlib. list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE=1) include(CheckCXXCompilerFlag) include(CMakePushCheckState) @@ -79,6 +77,12 @@ list(APPEND CMAKE_REQUIRED_INCLUDES ${CURSES_INCLUDE_DIRS}) find_library(CURSES_TINFO tinfo) if (CURSES_TINFO) set(CURSES_LIBRARY ${CURSES_LIBRARY} ${CURSES_TINFO}) +else() + # on NetBSD, libtinfo has a longer name (libterminfo) + find_library(CURSES_TINFO terminfo) + if (CURSES_TINFO) + set(CURSES_LIBRARY ${CURSES_LIBRARY} ${CURSES_TINFO}) + endif() endif() # Get threads. @@ -161,16 +165,7 @@ if(NOT HAVE_WCSNCASECMP) check_cxx_symbol_exists(std::wcsncasecmp wchar.h HAVE_STD__WCSNCASECMP) endif() -# `xlocale.h` is required to find `wcstod_l` in `wchar.h` under FreeBSD, -# but it's not present under Linux. check_include_files("xlocale.h" HAVE_XLOCALE_H) -if(HAVE_XLOCALE_H) - list(APPEND WCSTOD_L_INCLUDES "xlocale.h") -endif() -list(APPEND WCSTOD_L_INCLUDES "wchar.h") -check_cxx_symbol_exists(wcstod_l "${WCSTOD_L_INCLUDES}" HAVE_WCSTOD_L) - -check_cxx_symbol_exists(uselocale "locale.h;xlocale.h" HAVE_USELOCALE) cmake_push_check_state() check_struct_has_member("struct winsize" ws_row "termios.h;sys/ioctl.h" _HAVE_WINSIZE) diff --git a/cmake/Mac.cmake b/cmake/Mac.cmake index e02ba97a5..fde2255ea 100644 --- a/cmake/Mac.cmake +++ b/cmake/Mac.cmake @@ -1,5 +1,3 @@ -set(CMAKE_OSX_DEPLOYMENT_TARGET "10.10" CACHE STRING "Minimum OS X deployment version") - # Code signing ID on Mac. # If this is falsey, codesigning is disabled. # '-' is ad-hoc codesign. diff --git a/cmake/Rust.cmake b/cmake/Rust.cmake new file mode 100644 index 000000000..99ceb6b6c --- /dev/null +++ b/cmake/Rust.cmake @@ -0,0 +1,86 @@ +if(EXISTS "${CMAKE_SOURCE_DIR}/corrosion-vendor/") + add_subdirectory("${CMAKE_SOURCE_DIR}/corrosion-vendor/") +else() + include(FetchContent) + + # Don't let Corrosion's tests interfere with ours. + set(CORROSION_TESTS OFF CACHE BOOL "" FORCE) + + FetchContent_Declare( + Corrosion + GIT_REPOSITORY https://github.com/mqudsi/corrosion + GIT_TAG fish + ) + + FetchContent_MakeAvailable(Corrosion) + + add_custom_target(corrosion-vendor.tar.gz + COMMAND git archive --format tar.gz --output "${CMAKE_BINARY_DIR}/corrosion-vendor.tar.gz" + --prefix corrosion-vendor/ HEAD + WORKING_DIRECTORY ${corrosion_SOURCE_DIR} + ) +endif() + +set(fish_rust_target "fish-rust") + +set(fish_autocxx_gen_dir "${CMAKE_BINARY_DIR}/fish-autocxx-gen/") + +set(FISH_CRATE_FEATURES "fish-ffi-tests") +if(NOT DEFINED CARGO_FLAGS) + # Corrosion doesn't like an empty string as FLAGS. This is basically a no-op alternative. + # See https://github.com/corrosion-rs/corrosion/issues/356 + set(CARGO_FLAGS "--config" "foo=0") +endif() +if(DEFINED ASAN) + list(APPEND CARGO_FLAGS "-Z" "build-std") + list(APPEND FISH_CRATE_FEATURES "asan") +endif() + +corrosion_import_crate( + MANIFEST_PATH "${CMAKE_SOURCE_DIR}/Cargo.toml" + CRATES "fish-rust" + FEATURES "${FISH_CRATE_FEATURES}" + FLAGS "${CARGO_FLAGS}" +) + +# We need the build dir because cxx puts our headers in there. +# Corrosion doesn't expose the build dir, so poke where we shouldn't. +if (Rust_CARGO_TARGET) + set(rust_target_dir "${CMAKE_BINARY_DIR}/cargo/build/${_CORROSION_RUST_CARGO_TARGET}") +else() + set(rust_target_dir "${CMAKE_BINARY_DIR}/cargo/build/${_CORROSION_RUST_CARGO_HOST_TARGET}") + corrosion_set_hostbuild(${fish_rust_target}) +endif() + +# 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}") + set(CMAKE_WITH_GETTEXT "0") +endif() + +# Tell Cargo where our build directory is so it can find config.h. +corrosion_set_env_vars(${fish_rust_target} + "FISH_BUILD_DIR=${CMAKE_BINARY_DIR}" + "FISH_AUTOCXX_GEN_DIR=${fish_autocxx_gen_dir}" + "FISH_RUST_TARGET_DIR=${rust_target_dir}" + "PREFIX=${CMAKE_INSTALL_PREFIX}" + # Temporary hack to propogate CMake flags/options to build.rs. + "CMAKE_WITH_GETTEXT=${CMAKE_WITH_GETTEXT}" +) + +target_include_directories(${fish_rust_target} INTERFACE + "${rust_target_dir}/cxxbridge/${fish_rust_target}/src/" + "${fish_autocxx_gen_dir}/include/" +) + +# Tell fish what extra C++ files to compile. +define_property( + TARGET PROPERTY fish_extra_cpp_files + BRIEF_DOCS "Extra C++ files to compile for fish." + FULL_DOCS "Extra C++ files to compile for fish." +) + +set_property(TARGET ${fish_rust_target} PROPERTY fish_extra_cpp_files + "${fish_autocxx_gen_dir}/cxx/gen0.cxx" +) diff --git a/cmake/Tests.cmake b/cmake/Tests.cmake index ed745b4ce..4061a6b20 100644 --- a/cmake/Tests.cmake +++ b/cmake/Tests.cmake @@ -175,3 +175,34 @@ foreach(PEXPECT ${PEXPECTS}) set_tests_properties(${PEXPECT} PROPERTIES ENVIRONMENT FISH_FORCE_COLOR=1) add_test_target("${PEXPECT}") endforeach(PEXPECT) + +# 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. + if(NOT DEFINED Rust_CARGO_TARGET) + message(FATAL_ERROR "ASAN requires defining the CMake variable Rust_CARGO_TARGET to the + intended target triple") + endif() + set(cargo_target_opt "--target" ${Rust_CARGO_TARGET}) +endif() + +# cargo-test is failing to link w/ ASAN enabled. For some reason it is picking up autocxx ffi +# dependencies, even though `carg test` is supposed to be for rust-only code w/ no ffi dependencies. +# TODO: Figure this out and fix it. +if(NOT DEFINED ASAN) + add_test( + NAME "cargo-test" + COMMAND cargo test ${CARGO_FLAGS} --package fish-rust --target-dir target ${cargo_target_opt} + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + ) + set_tests_properties("cargo-test" PROPERTIES SKIP_RETURN_CODE ${SKIP_RETURN_CODE}) + add_test_target("cargo-test") +endif() + +add_test( + NAME "cargo-test-widestring" + COMMAND cargo test ${CARGO_FLAGS} --package widestring-suffix --target-dir target ${cargo_target_opt} + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" +) +add_test_target("cargo-test-widestring") diff --git a/config_cmake.h.in b/config_cmake.h.in index b9ea96f15..a53d8a11e 100644 --- a/config_cmake.h.in +++ b/config_cmake.h.in @@ -94,9 +94,6 @@ /* Define to 1 if you have the `wcsncasecmp' function. */ #cmakedefine HAVE_WCSNCASECMP 1 -/* Define to 1 if you have the `wcstod_l' function. */ -#cmakedefine HAVE_WCSTOD_L 1 - /* Define to 1 if the status that wait returns and WEXITSTATUS expects is signal and then ret instead of the other way around. */ #cmakedefine HAVE_WAITSTATUS_SIGNAL_RET 1 @@ -144,9 +141,6 @@ /* Define if xlocale.h is required for locale_t or wide character support */ #cmakedefine HAVE_XLOCALE_H 1 -/* Define if uselocale is available */ -#cmakedefine HAVE_USELOCALE 1 - /* Enable large inode numbers on Mac OS X 10.5. */ #ifndef _DARWIN_USE_64_BIT_INODE # define _DARWIN_USE_64_BIT_INODE 1 diff --git a/debian/control b/debian/control index 401a51de3..75714a105 100644 --- a/debian/control +++ b/debian/control @@ -6,7 +6,7 @@ Uploaders: David Adam # Debhelper should be bumped to >= 10 once Ubuntu Xenial is no longer supported Build-Depends: debhelper (>= 9.20160115), libncurses5-dev, cmake (>= 3.5.0), gettext, libpcre2-dev, # Test dependencies - locales-all, python3 + locales-all, python3, rustc (>= 1.67) | rustc-mozilla (>= 1.67), cargo Standards-Version: 4.1.5 Homepage: https://fishshell.com/ Vcs-Git: https://github.com/fish-shell/fish-shell.git diff --git a/debian/copyright b/debian/copyright index 57a818de3..990db34af 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,101 +1,226 @@ -This work was packaged for Debian by David Adam -on Thu, 14 Jun 2012 20:33:34 +0800, based on work by James Vega -. Modifications from the downstream Debian maintainer, -Tristan Seligmann , have also been included. +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: fish +Upstream-Contact: corydoras@ridiculousfish.com +Source: https://fishshell.com/ -It was downloaded from: +Files: * +Copyright: 2005-2009 Axel Liljencrantz + 2009-2023 fish-shell contributors +License: GPL-2 - https://github.com/fish-shell/fish-shell +Files: cmake/CheckIncludeFiles.cmake +Copyright: 2000-2017 Kitware, Inc. and Contributors +License: BSD-3-clause -Upstream Authors: +Files: doc_src/python_docs_theme/* +Copyright: 2001-2017 Python Software Foundation + 2020-2023 fish-shell contributors +License: Python - Axel Liljencrantz - ridiculous_fish +Files: share/tools/web_config/js/angular*.js +Copyright: 2010-2020 Google LLC +License: MIT -Copyright: +Files: share/tools/web_config/themes/Dracula.theme +Copyright: 2018 Dracula Team +License: MIT - Copyright (C) 2005-2008 Axel Liljencrantz - Copyright (C) 2011-2012 ridiculous_fish +Files: fish-rust/src/builtins/printf.rs +Copyright: 1990-2007 Free Software Foundation, Inc. + 2022 fish-shell contributors +License: GPL-2+ -License: +Files: src/env.cpp +Copyright: 2005-2009 Axel Liljencrantz + 2007 Nicholas Marriott + 2009-2023 fish-shell contributors +License: GPL-2 and OpenBSD -Copyright (C) 2005-2008 Axel Liljencrantz +Files: src/fallback.cpp +Copyright: 2001 The NetBSD Foundation, Inc. + 2005-2009 Axel Liljencrantz + 2009-2023 fish-shell contributors +License: GPL-2 and NetBSD - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation. +Files: src/utf8.c +Copyright: 2007 Alexey Vatchenko +License: ISC - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. +Files: debian/* +Copyright: 2005-2009 James Vega + 2012 David Adam + 2015 Tristan Seligmann + 2019-2022 Mo Zhou +License: GPL-2 - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - MA 02110-1301, USA. +License: BSD-3-clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + . + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + . + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + . + * Neither the name of Kitware, Inc. nor the names of Contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + . + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -On Debian systems, the complete text of the GNU General -Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". +License: GPL-2 + Most of fish is licensed under the GNU General Public License version 2, and + you can redistribute it and/or modify it under the terms of the GNU GPL as + published by the Free Software Foundation. + . + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + . + On Debian systems, the complete text of the GNU General Public License can be + found in `/usr/share/common-licenses/GPL-2'. -Fish contains code from the PCRE2 library to support regular expressions. This -code, created by Philip Hazel, is distributed under the terms of the BSD -license. Copyright © 1997-2015 University of Cambridge. +License: GPL-2+ + This program is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free Software + Foundation; either version 2, or (at your option) any later version. + . + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + . + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., 51 Franklin + Street, Fifth Floor, Boston, MA 02110-1301, USA. + . + On Debian systems, the complete text of the GNU General Public License can be + found in `/usr/share/common-licenses/GPL-2'. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: +License: ISC + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + . + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. +License: MIT + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + . + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. +License: NetBSD + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + . + THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. - - Neither the name of the University of Cambridge nor the names of any - contributors may be used to endorse or promote products derived from this - software without specific prior written permission. +License: OpenBSD + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + . + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. - -Fish also contains small amounts of code under the OpenBSD license, namely a -version of the function strlcpy, modified for use with wide character strings. -This code is copyrighted by Todd C. Miller (1998). It also contains code from -tmux, copyrighted by Nicholas Marriott (2007), and -made available under an identical license. - - Permission to use, copy, modify, and distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -Fish contains code from the glibc library, namely the wcstok function -in fallback.c. This code is licensed under the LGPL. - -On Debian systems, the complete text of the GNU Lesser General -Public License can be found in `/usr/share/common-licenses/LGPL'. - -The Debian packaging is: - - Copyright (C) 2005 James Vega - Copyright (C) 2012 David Adam - Copyright (C) 2015 Tristan Seligmann - -and is licensed under the GPL version 2, see above. +License: Python + 1. This LICENSE AGREEMENT is between the Python Software Foundation + ("PSF"), and the Individual or Organization ("Licensee") accessing and + otherwise using this software ("Python") in source or binary form and + its associated documentation. + . + 2. Subject to the terms and conditions of this License Agreement, PSF + hereby grants Licensee a nonexclusive, royalty-free, world-wide + license to reproduce, analyze, test, perform and/or display publicly, + prepare derivative works, distribute, and otherwise use Python alone + or in any derivative version, provided, however, that PSF's License + Agreement and PSF's notice of copyright, i.e., "Copyright (c) 2001, + 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, + 2013, 2014 Python Software Foundation; All Rights Reserved" are + retained in Python alone or in any derivative version prepared by + Licensee. + . + 3. In the event Licensee prepares a derivative work that is based on + or incorporates Python or any part thereof, and wants to make + the derivative work available to others as provided herein, then + Licensee hereby agrees to include in any such work a brief summary of + the changes made to Python. + . + 4. PSF is making Python available to Licensee on an "AS IS" + basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR + IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND + DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS + FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT + INFRINGE ANY THIRD PARTY RIGHTS. + . + 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON + FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS + A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, + OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + . + 6. This License Agreement will automatically terminate upon a material + breach of its terms and conditions. + . + 7. Nothing in this License Agreement shall be deemed to create any + relationship of agency, partnership, or joint venture between PSF and + Licensee. This License Agreement does not grant permission to use PSF + trademarks or trade name in a trademark sense to endorse or promote + products or services of Licensee, or any third party. + . + 8. By copying, installing or otherwise using Python, Licensee + agrees to be bound by the terms and conditions of this License + Agreement. diff --git a/doc_internal/fish-riir-plan.md b/doc_internal/fish-riir-plan.md new file mode 100644 index 000000000..32572ac34 --- /dev/null +++ b/doc_internal/fish-riir-plan.md @@ -0,0 +1,79 @@ +These is a proposed port of fish-shell from C++ to Rust, and from CMake to cargo or related. This document is high level - see the [Development Guide] for more details. + +## Why Port + +- Gain access to more contributors and enable easier contributions. C++ is becoming a legacy language. +- Free us from the annoyances of C++/CMake, and old toolchains. +- Ensure fish continues to be perceived as modern and relevant. +- Unlock concurrent mode (see below). + +## Why Rust + +- Rust is a systems programming language with broad platform support, a large community, and a relatively high probability of still being relevant in a decade. +- Rust has a unique strength in its thread safety features, which is the missing piece to enable concurrent mode - see below. +- Other languages considered: + - Java, Python and the scripting family are ruled out for startup latency and memory usage reasons. + - Go would be an awkward fit. fork is [quite the problem](https://stackoverflow.com/questions/28370646/how-do-i-fork-a-go-process/28371586#28371586) in Go. + - Other system languages (D, Nim, Zig...) are too niche: fewer contributors, higher risk of the language becoming irrelevant. + +## Risks + +- Large amount of work with possible introduction of new bugs. +- Long period of complicated builds. +- Existing contributors will have to learn Rust. +- As of yet unknown compatibility story for Tier 2+ platforms (Cygwin, etc). + +## Approach + +We will do an **incremental port** in the span of one release. We will have a period of using both C++ and Rust, and both cargo and CMake, leveraging FFI tools (see below). + +The work will **proceed on master**: no long-lived branches. Tests and CI continue to pass at every commit for recent Linux and Mac. Centos7, \*BSD, etc may be temporarily disabled if they prove problematic. + +The Rust code will initially resemble the replaced C++. Fidelity to existing code is more important than Rust idiomaticity, to aid review and bisecting. But don't take this to extremes - use judgement. + +The port will proceed "outside in." We'll start with leaf components (e.g. builtins) and proceed towards the core. Some components will have both a Rust and C++ implementation (e.g. FLOG), in other cases we'll change the existing C++ to invoke the new Rust implementations (builtins). + +After porting the C++, we'll replace CMake. + +We will continue to use wide chars, locales, gettext, printf format strings, and PCRE2. We will not change the fish scripting language at all. We will _not_ use this as an opportunity to fix existing design flaws, with a few carefully chosen exceptions. See [Strings](#strings). + +We will not use tokio, serde, async, or other fancy Rust frameworks initially. + +### FFI + +Rust/C++ interop will use [autocxx](https://github.com/google/autocxx), [Cxx](https://cxx.rs), and possibly [bindgen](https://rust-lang.github.io/rust-bindgen/). I've forked these for fish (see the [Development Guide]). Once the port is done, we will stop using them, except perhaps bindgen for PCRE2. + +We will use [corrosion](https://github.com/corrosion-rs/corrosion) for CMake integration. + +Inefficiencies (e.g. extra string copying) at the FFI layer are fine, since it will all get thrown away. + +Tests can stay in fish_tests.cpp or be moved into Rust .rs files; either is fine. + +### Strings + +Rust's `String` / `&str` types cannot represent non-UTF8 filenames or data using the default encoding scheme. That's why all string conversions must go through fish's encoding scheme (using the private-use area to encode invalid sequences). For example, fish cannot use `File::open` with a `&str` because the decoding will be incorrect. + +So instead of `String`, fish will use its own string type, and manage encoding and decoding as it does today. However we will make some specific changes: + +1. Drop the nul-terminated requirement. When passing `const wchar_t*` back to C++, we will allocate and copy into a nul-terminated buffer. +2. Drop support for 16-bit wchar. fish will use UTF32 on all platforms, and manage conversions itself. + +After the port we can consider moving to UTF-8, for memory usage reasons. + +See the [Rust Development Guide][Development Guide] for more on strings. + +### Thread Safety + +Allowing [background functions](https://github.com/fish-shell/fish-shell/issues/238) and concurrent functions has been a goal for many years. I have been nursing [a long-lived branch](https://github.com/ridiculousfish/fish-shell/tree/concurrent_even_simpler) which allows full threaded execution. But though the changes are small, I have been reluctant to propose them, because they will make reasoning about the shell internals too complex: it is difficult in C++ to check and enforce what crosses thread boundaries. + +This is Rust's bread and butter: we will encode thread requirements into our types, making it explicit and compiler-checked, via Send and Sync. Rust will allow turning on concurrent mode in a safe way, with a manageable increase in complexity, finally enabling this feature. + +## Timeline + +Handwaving, 6 months? Frankly unknown - there's 102 remaining .cpp files of various lengths. It'll go faster as we get better at it. Peter (ridiculous_fish) is motivated to work on this, other current contributors have some Rust as well, and we may also get new contributors from the Rust community. Part of the point is to make contribution easier. + +## Links + +- [Packaging Rust projects](https://wiki.archlinux.org/title/Rust_package_guidelines) from Arch Linux + +[Development Guide]: rust-devel.md diff --git a/doc_internal/rust-devel.md b/doc_internal/rust-devel.md new file mode 100644 index 000000000..ac7d9545e --- /dev/null +++ b/doc_internal/rust-devel.md @@ -0,0 +1,192 @@ +# fish-shell Rust Development Guide + +This describes how to get started building fish-shell in its partial Rust state, and how to contribute to the port. + +## Overview + +fish is in the process of transitioning from C++ to Rust. The fish project has a Rust crate embedded at path `fish-rust`. This crate builds a Rust library `libfish_rust.a` which is linked with the C++ `libfish.a`. Existing C++ code will be incrementally migrated to this crate; then CMake will be replaced with cargo and other Rust-native tooling. + +Important tools used during this transition: + +1. [Corrosion](https://github.com/corrosion-rs/corrosion) to invoke cargo from CMake. +2. [cxx](http://cxx.rs) for basic C++ <-> Rust interop. +3. [autocxx](https://google.github.io/autocxx/) for using C++ types in Rust. + +We use forks of the last two - see the [FFI section](#ffi) below. No special action is required to obtain these packages. They're downloaded by cargo. + +## Building + +### Build Dependencies + +fish-shell currently depends on Rust 1.67 or later. To install Rust, follow https://rustup.rs. + +### Build via CMake + +It is recommended to build inside `fish-shell/build`. This will make it easier for Rust to find the `config.h` file. + +Build via CMake as normal (use any generator, here we use Ninja): + +```shell +$ cd fish-shell +$ mkdir build && cd build +$ cmake -G Ninja .. +$ ninja +``` + +This will create the usual fish executables. + +### Build just libfish_rust.a with Cargo + +The directory `fish-rust` contains the Rust sources. These require that CMake has been run to produce `config.h` which is necessary for autocxx to succeed. + +Follow the "Build from CMake" steps above, and then: + +```shell +$ cd fish-shell/fish-rust +$ cargo build +``` + +This will build only the library, not a full working fish, but it allows faster iteration for Rust development. That is, after running `cmake` you can open the `fish-rust` as the root of a Rust crate, and tools like rust-analyzer will work. + +## Development + +The basic development loop for this port: + +1. Pick a .cpp (or in some cases .h) file to port, say `util.cpp`. +2. Add the corresponding `util.rs` file to `fish-rust/`. +3. Reimplement it in Rust, along with its dependencies as needed. Match the existing C++ code where practical, including propagating any relevant comments. + - Do this even if it results in less idiomatic Rust, but avoid being super-dogmatic either way. + - One technique is to paste the C++ into the Rust code, commented out, and go line by line. +4. Decide whether any existing C++ callers should invoke the Rust implementation, or whether we should keep the C++ one. + - Utility functions may have both a Rust and C++ implementation. An example is `FLOG` where interop is too hard. + - Major components (e.g. builtin implementations) should _not_ be duplicated; instead the Rust should call C++ or vice-versa. +5. Remember to run `cargo fmt` and `cargo clippy` to keep the codebase somewhat clean (otherwise CI will fail). If you use rust-analyzer, you can run clippy automatically by setting `rust-analyzer.checkOnSave.command = "clippy"`. + +You will likely run into limitations of [`autocxx`](https://google.github.io/autocxx/) and to a lesser extent [`cxx`](https://cxx.rs/). See the [FFI sections](#ffi) below. + +## Type Mapping + +### Constants & Type Aliases + +The FFI does not support constants (`#define` or `static const`) or type aliases (`typedef`, `using`). Duplicate them using their Rust equivalent (`pub const` and `type`/`struct`/`enum`). + +### Non-POD types + +Many types cannot currently be passed across the language boundary by value or occur in shared structs. As a workaround, use references, raw pointers or smart pointers (`cxx` provides `SharedPtr` and `UniquePtr`). Try to keep workarounds on the C++ side and the FFI layer of the Rust code. This ensures we will get rid of the workarounds as we peel off the FFI layer. + +### Strings + +Fish will mostly _not_ use Rust's `String/&str` types as these cannot represent non-UTF8 data using the default encoding. + +fish's primary string types will come from the [`widestring` crate](https://docs.rs/widestring). The two main string types are `WString` and `&wstr`, which are renamed [Utf32String](https://docs.rs/widestring/latest/widestring/utfstring/struct.Utf32String.html) and [Utf32Str](https://docs.rs/widestring/latest/widestring/utfstr/struct.Utf32Str.html). `WString` is an owned, heap-allocated UTF32 string, `&wstr` a borrowed UTF32 slice. + +In general, follow this mapping when porting from C++: + +- `wcstring` -> `WString` +- `const wcstring &` -> `&wstr` +- `const wchar_t *` -> `&wstr` + +None of the Rust string types are nul-terminated. We're taking this opportunity to drop the nul-terminated aspect of wide string handling. + +#### Creating strings + +One may create a `&wstr` from a string literal using the `wchar::L!` macro: + +```rust +use crate::wchar::prelude::*; +// This imports wstr, the L! macro, WString, a ToWString trait that supplies .to_wstring() along with other things + +fn get_shell_name() -> &'static wstr { + L!("fish") +} +``` + +There is also a `widestrs` proc-macro which enables L as a _suffix_, to reduce the noise. This can be applied to any block, including modules and individual functions: + +```rust +use crate::wchar::{wstr, widestrs} +// also imported by the prelude + +#[widestrs] +fn get_shell_name() -> &'static wstr { + "fish"L // equivalent to L!("fish") +} +``` + +#### The wchar prelude + +We have a prelude to make working with these string types a whole lot more ergonomic. In particular `WExt` supplies the null-terminated-compatible `.char_at(usize)`, +and a whole lot more methods that makes porting C++ code easier. It is also preferred to use char-based-methods like `.char_count()` and `.slice_{from,to}()` +of the `WExt` trait over directly calling `.len()` and `[usize..]/[..usize]`, as that makes the code compatible with a potential future change to UTF8-strings. + +```rust +pub(crate) mod prelude { + pub(crate) use crate::{ + wchar::{wstr, IntoCharIter, WString, L}, + wchar_ext::{ToWString, WExt}, + wutil::{sprintf, wgettext, wgettext_fmt, wgettext_str}, + }; + pub(crate) use widestring_suffix::widestrs; +} +``` + +### Strings for FFI + +`WString` and `&wstr` are the common strings used by Rust components. At the FII boundary there are some additional strings for interop. _All of these are temporary for the duration of the port._ + +- `CxxWString` is the Rust binding of `std::wstring`. It is the wide-string analog to [`CxxString`](https://cxx.rs/binding/cxxstring.html) and is [added in our fork of cxx](https://github.com/ridiculousfish/cxx/blob/fish/src/cxx_wstring.rs). This is useful for functions which return e.g. `const wcstring &`. +- `W0String` is renamed [U32CString](https://docs.rs/widestring/latest/widestring/ucstring/struct.U32CString.html). This is basically `WString` except it _is_ nul-terminated. This is useful for getting a nul-terminated `const wchar_t *` to pass to C++ implementations. +- `wcharz_t` is an annoying C++ struct which merely wraps a `const wchar_t *`, used for passing these pointers from C++ to Rust. We would prefer to use `const wchar_t *` directly but `autocxx` refuses to generate bindings for types such as `std::vector` so we wrap it in this silly struct. + +Note C++ `wchar_t`, Rust `char`, and `u32` are effectively interchangeable: you can cast pointers to them back and forth (except we check upon u32->char conversion). However be aware of which types are nul-terminated. + +These types should be confined to the FFI modules, in particular `wchar_ffi`. They should not "leak" into other modules. See the `wchar_ffi` module. + +### Format strings + +Rust's builtin `std::fmt` modules do not accept runtime-provided format strings, so we mostly won't use them, except perhaps for FLOG / other non-translated text. + +Instead we'll continue to use printf-style strings, with a Rust printf implementation. + +### Vectors + +See [`Vec`](https://cxx.rs/binding/vec.html) and [`CxxVector`](https://cxx.rs/binding/cxxvector.html). + +In many cases, `autocxx` refuses to allow vectors of certain types. For example, autocxx supports `std::vector` and `std::shared_ptr` but NOT `std::vector>`. To work around this one can create a helper (pointer, length) struct. Example: + +```cpp +struct RustFFIJobList { + std::shared_ptr *jobs; + size_t count; +}; +``` + +This is just a POD (plain old data) so autocxx can generate bindings for it. Then it is trivial to convert it to a Rust slice: + +``` +pub fn get_jobs(ffi_jobs: &ffi::RustFFIJobList) -> &[SharedPtr] { + unsafe { slice::from_raw_parts(ffi_jobs.jobs, ffi_jobs.count) } +} +``` + +Another workaround is to define a struct that contains the shared pointer, and create a vector of that struct. + +## Development Tooling + +The [autocxx guidance](https://google.github.io/autocxx/workflow.html#how-can-i-see-what-bindings-autocxx-has-generated) is helpful: + +1. Install cargo expand (`cargo install cargo-expand`). Then you can use `cargo expand` to see the generated Rust bindings for C++. In particular this is useful for seeing failed expansions for C++ types that autocxx cannot handle. +2. In rust-analyzer, enable Proc Macro and Proc Macro Attributes. + +## FFI + +The boundary between Rust and C++ is referred to as the Foreign Function Interface, or FFI. + +`autocxx` and `cxx` both are designed for long-term interop: C++ and Rust coexisting for years. To this end, both emphasize safety: requiring lots of `unsafe`, `Pin`, etc. + +fish plans to use them only temporarily, with a focus on getting things working. To this end, both cxx and autocxx have been forked to support fish: + +1. Relax the requirement that all functions taking pointers are `unsafe` (this just added noise). +2. Add support for `wchar_t` as a recognized type, and `CxxWString` analogous to `CxxString`. + +See the `Cargo.toml` file for the locations of the forks. diff --git a/doc_src/cmds/abbr.rst b/doc_src/cmds/abbr.rst index af497760c..3fc86662e 100644 --- a/doc_src/cmds/abbr.rst +++ b/doc_src/cmds/abbr.rst @@ -49,6 +49,13 @@ Combining these features, it is possible to create custom syntaxes, where a regu > abbr >> ~/.config/fish/config.fish > abbr --erase (abbr --list) + Alternatively you can keep them in a separate :ref:`configuration file ` by doing something like the following:: + + > abbr > ~/.config/fish/conf.d/myabbrs.fish + + This will save all your abbrevations in "myabbrs.fish", overwriting the whole file so it doesn't leave any duplicates, + or restore abbreviations you had erased. + Of course any functions will have to be saved separately, see :doc:`funcsave `. "add" subcommand -------------------- diff --git a/doc_src/cmds/bg.rst b/doc_src/cmds/bg.rst index 8736d33e0..1ea3c8ee6 100644 --- a/doc_src/cmds/bg.rst +++ b/doc_src/cmds/bg.rst @@ -17,10 +17,9 @@ Description A background job is executed simultaneously with fish, and does not have access to the keyboard. If no job is specified, the last job to be used is put in the background. If ``PID`` is specified, the jobs containing the specified process IDs are put in the background. -For compatibility with other shells, job expansion syntax is supported for ``bg``. A PID of the format ``%1`` will be interpreted as the PID of job 1. Job numbers can be seen in the output of :doc:`jobs `. +A PID of the format ``%n``, where n is an integer, will be interpreted as the PID of job number n. Job numbers can be seen in the output of :doc:`jobs `. -When at least one of the arguments isn't a valid job specifier, -``bg`` will print an error without backgrounding anything. +When at least one of the arguments isn't a valid job specifier, ``bg`` will print an error without backgrounding anything. When all arguments are valid job specifiers, ``bg`` will background all matching jobs that exist. @@ -29,10 +28,20 @@ The **-h** or **--help** option displays help about using this command. Example ------- +The typical use is to run something, stop it with ctrl-z, and then continue it in the background with bg:: + + > find / -name "*.js" >/tmp/jsfiles 2>/dev/null # oh no, this takes too long, let's press Ctrl-z! + fish: Job 1, 'find / -name "*.js" >/tmp/jsfil…' has stopped + > bg + Send job 1 'find / -name "*.js" >/tmp/jsfiles 2>/dev/null' to background + > # I can continue using this shell! + > # Eventually: + fish: Job 1, 'find / -name "*.js" >/tmp/jsfil…' has ended + ``bg 123 456 789`` will background the jobs that contain processes 123, 456 and 789. If only 123 and 789 exist, it will still background them and print an error about 456. ``bg 123 banana`` or ``bg banana 123`` will complain that "banana" is not a valid job specifier. -``bg %1`` will background job 1. +``bg %2`` will background job 2. diff --git a/doc_src/cmds/bind.rst b/doc_src/cmds/bind.rst index 3a481f40c..20984ba8a 100644 --- a/doc_src/cmds/bind.rst +++ b/doc_src/cmds/bind.rst @@ -23,26 +23,23 @@ It can add bindings if given a SEQUENCE of characters to bind to. These should b For example, :kbd:`Alt`\ +\ :kbd:`W` can be written as ``\ew``, and :kbd:`Control`\ +\ :kbd:`X` (^X) can be written as ``\cx``. Note that Alt-based key bindings are case sensitive and Control-based key bindings are not. This is a constraint of text-based terminals, not ``fish``. -The generic key binding that matches if no other binding does can be set by specifying a ``SEQUENCE`` of the empty string (that is, ``''`` ). For most key bindings, it makes sense to bind this to the ``self-insert`` function (i.e. ``bind '' self-insert``). This will insert any keystrokes not specifically bound to into the editor. Non-printable characters are ignored by the editor, so this will not result in control sequences being inserted. +The generic key binding that matches if no other binding does can be set by specifying a ``SEQUENCE`` of the empty string (``''``). For most key bindings, it makes sense to bind this to the ``self-insert`` function (i.e. ``bind '' self-insert``). This will insert any keystrokes not specifically bound to into the editor. Non-printable characters are ignored by the editor, so this will not result in control sequences being inserted. If the ``-k`` switch is used, the name of a key (such as 'down', 'up' or 'backspace') is used instead of a sequence. The names used are the same as the corresponding curses variables, but without the 'key\_' prefix. (See ``terminfo(5)`` for more information, or use ``bind --key-names`` for a list of all available named keys). Normally this will print an error if the current ``$TERM`` entry doesn't have a given key, unless the ``-s`` switch is given. To find out what sequence a key combination sends, you can use :doc:`fish_key_reader `. -``COMMAND`` can be any fish command, but it can also be one of a set of special input functions. These include functions for moving the cursor, operating on the kill-ring, performing tab completion, etc. Use ``bind --function-names`` for a complete list of these input functions. - -When ``COMMAND`` is a shellscript command, it is a good practice to put the actual code into a :ref:`function ` and simply bind to the function name. This way it becomes significantly easier to test the function while editing, and the result is usually more readable as well. - +``COMMAND`` can be any fish command, but it can also be one of a set of special input functions. These include functions for moving the cursor, operating on the kill-ring, performing tab completion, etc. Use ``bind --function-names`` or :ref:`see below ` for a list of these input functions. .. note:: - Special input functions cannot be combined with ordinary shell script commands. The commands must be entirely a sequence of special input functions (from ``bind -f``) or all shell script commands (i.e., valid fish script). To run special input functions from regular fish script, use ``commandline -f`` (see also :doc:`commandline `). If a script produces output, it should finish by calling ``commandline -f repaint`` to tell fish that a repaint is in order. + The commands must be entirely a sequence of special input functions (from ``bind -f``) or all shell script commands (i.e., valid fish script). To run special input functions from regular fish script, use ``commandline -f`` (see also :doc:`commandline `). If a script produces output, it should finish by calling ``commandline -f repaint`` so that fish knows to redraw the prompt. If no ``SEQUENCE`` is provided, all bindings (or just the bindings in the given ``MODE``) are printed. If ``SEQUENCE`` is provided but no ``COMMAND``, just the binding matching that sequence is printed. -To save custom key bindings, put the ``bind`` statements into :ref:`config.fish `. Alternatively, fish also automatically executes a function called ``fish_user_key_bindings`` if it exists. - 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 `. Alternatively, fish also automatically executes a function called ``fish_user_key_bindings`` if it exists. + Options ------- The following options are available: @@ -87,6 +84,8 @@ The following options are available: **-h** or **--help** Displays help about using this command. +.. _special-input-functions: + Special input functions ----------------------- The following special input functions are available: @@ -199,6 +198,9 @@ 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-pager-delete`` + permanently delete the history item selected in the history pager + ``history-search-backward`` search the history for the previous match diff --git a/doc_src/cmds/command.rst b/doc_src/cmds/command.rst index 24f6147a4..d4f046835 100644 --- a/doc_src/cmds/command.rst +++ b/doc_src/cmds/command.rst @@ -15,6 +15,8 @@ Description **command** forces the shell to execute the program *COMMANDNAME* and ignore any functions or builtins with the same name. +In ``command foo``, ``command`` is a keyword. + The following options are available: **-a** or **--all** diff --git a/doc_src/cmds/complete.rst b/doc_src/cmds/complete.rst index 0a79ffd4e..4d69dce90 100644 --- a/doc_src/cmds/complete.rst +++ b/doc_src/cmds/complete.rst @@ -1,6 +1,6 @@ .. _cmd-complete: -complete - edit command specific tab-completions +complete - edit command-specific tab-completions ================================================ Synopsis @@ -8,7 +8,7 @@ Synopsis .. synopsis:: - complete ((-c | --command) | (-p | --path)) COMMAND [OPTIONS] + complete ((-c | --command) | (-p | --path)) COMMAND [OPTIONS] complete (-C | --do-complete) [--escape] STRING Description @@ -72,7 +72,7 @@ The following options are available: **-h** or **--help** Displays help about using this command. -Command specific tab-completions in ``fish`` are based on the notion of options and arguments. An option is a parameter which begins with a hyphen, such as ``-h``, ``-help`` or ``--help``. Arguments are parameters that do not begin with a hyphen. Fish recognizes three styles of options, the same styles as the GNU getopt library. These styles are: +Command-specific tab-completions in ``fish`` are based on the notion of options and arguments. An option is a parameter which begins with a hyphen, such as ``-h``, ``-help`` or ``--help``. Arguments are parameters that do not begin with a hyphen. Fish recognizes three styles of options, the same styles as the GNU getopt library. These styles are: - Short options, like ``-a``. Short options are a single character long, are preceded by a single hyphen and can be grouped together (like ``-la``, which is equivalent to ``-l -a``). Option arguments may be specified by appending the option with the value (``-w32``), or, if ``--require-parameter`` is given, in the following parameter (``-w 32``). diff --git a/doc_src/cmds/fish_add_path.rst b/doc_src/cmds/fish_add_path.rst index e28b75a26..0f3a70cb3 100644 --- a/doc_src/cmds/fish_add_path.rst +++ b/doc_src/cmds/fish_add_path.rst @@ -22,7 +22,9 @@ It is (by default) safe to use :program:`fish_add_path` in config.fish, or it ca Components are normalized by :doc:`realpath `. Trailing slashes are ignored and relative paths are made absolute (but symlinks are not resolved). If a component already exists, it is not added again and stays in the same place unless the ``--move`` switch is given. -Components are added in the order they are given, and they are prepended to the path unless ``--append`` is given (if $fish_user_paths is used, that means they are last in $fish_user_paths, which is itself prepended to :envvar:`PATH`, so they still stay ahead of the system paths). +Components are added in the order they are given, and they are prepended to the path unless ``--append`` is given. If $fish_user_paths is used, that means they are last in $fish_user_paths, which is itself prepended to :envvar:`PATH`, so they still stay ahead of the system paths. If the ``--path`` option is used, the paths are appended/prepended to :envvar:`PATH` directly, so this doesn't happen. + +With ``--path``, because :envvar:`PATH` must be a global variable instead of a universal one, the changes won't persist, so those calls need to be stored in :ref:`config.fish `. If no component is new, the variable (:envvar:`fish_user_paths` or :envvar:`PATH`) is not set again or otherwise modified, so variable handlers are not triggered. @@ -68,18 +70,26 @@ Example :: # I just installed mycoolthing and need to add it to the path to use it. + # It is at /opt/mycoolthing/bin/mycoolthing, + # so let's add the directory: /opt/mycoolthing/bin. > fish_add_path /opt/mycoolthing/bin - # I want my ~/.local/bin to be checked first. + # I want my ~/.local/bin to be checked first, + # even if it was already added. > fish_add_path -m ~/.local/bin # I prefer using a global fish_user_paths + # This isn't saved automatically, I need to add this to config.fish + # if I want it to stay. > fish_add_path -g ~/.local/bin ~/.otherbin /usr/local/sbin # I want to append to the entire $PATH because this directory contains fallbacks - > fish_add_path -aP /opt/fallback/bin + # This needs --path/-P because otherwise it appends to $fish_user_paths, + # which is added to the front of $PATH. + > fish_add_path --append --path /opt/fallback/bin # I want to add the bin/ directory of my current $PWD (say /home/nemo/) + # -v/--verbose shows what fish_add_path did. > fish_add_path -v bin/ set fish_user_paths /home/nemo/bin /usr/bin /home/nemo/.local/bin diff --git a/doc_src/cmds/fish_config.rst b/doc_src/cmds/fish_config.rst index a47d09e82..9fbe63485 100644 --- a/doc_src/cmds/fish_config.rst +++ b/doc_src/cmds/fish_config.rst @@ -41,10 +41,46 @@ Available subcommands for the ``theme`` command: - ``save`` saves the given theme to :ref:`universal variables `. - ``show`` shows what the given sample theme (or all) would look like. -The themes are loaded from the theme directory shipped with fish or a ``themes`` directory in the fish configuration directory (typically ``~/.config/fish/themes``). - The **-h** or **--help** option displays help about using this command. +Theme Files +----------- + +``fish_config theme`` and the theme selector in the web config tool load their themes from theme files. These are stored in the fish configuration directory, typically ``~/.config/fish/themes``, with a .theme ending. + +You can add your own theme by adding a file in that directory. + +To get started quickly:: + + fish_config theme dump > ~/.config/fish/themes/my.theme + +which will save your current theme in .theme format. + +The format looks like this: + +.. highlight:: none + +:: + + # name: 'Cool Beans' + # preferred_background: black + + fish_color_autosuggestion 666 + fish_color_cancel -r + fish_color_command normal + fish_color_comment '888' '--italics' + fish_color_cwd 0A0 + fish_color_cwd_root A00 + fish_color_end 009900 + +The two comments at the beginning are the name and background that the web config tool shows. + +The other lines are just like ``set variable value``, except that no expansions are allowed. Quotes are, but aren't necessary. + +Any color variable fish knows about that the theme doesn't set will be set to empty when it is loaded, so the old theme is completely overwritten. + +Other than that, .theme files can contain any variable with a name that matches the regular expression ``'^fish_(?:pager_)?color.*$'`` - starts with ``fish_``, an optional ``pager_``, then ``color`` and then anything. + Example ------- diff --git a/doc_src/cmds/fish_default_key_bindings.rst b/doc_src/cmds/fish_default_key_bindings.rst new file mode 100644 index 000000000..88691893b --- /dev/null +++ b/doc_src/cmds/fish_default_key_bindings.rst @@ -0,0 +1,27 @@ +.. _cmd-fish_default_key_bindings: + +fish_default_key_bindings - set emacs key bindings for fish +=============================================================== + +Synopsis +-------- + +.. synopsis:: + + fish_default_key_bindings + +Description +----------- + +``fish_default_key_bindings`` sets the emacs key bindings for ``fish`` shell. + +Some of the Emacs key bindings are defined :ref:`here `. + +There are no parameters for ``fish_default_key_bindings``. + +Examples +-------- + +To start using vi key bindings:: + + fish_default_key_bindings diff --git a/doc_src/cmds/fish_key_reader.rst b/doc_src/cmds/fish_key_reader.rst index cfe967874..851ff3daa 100644 --- a/doc_src/cmds/fish_key_reader.rst +++ b/doc_src/cmds/fish_key_reader.rst @@ -56,7 +56,7 @@ Example > fish_key_reader --verbose Press a key: # press alt+enter - hex: 1B char: \c[ (or \e) + hex: 1B char: \e ( 0.027 ms) hex: D char: \cM (or \r) bind \e\r 'do something' diff --git a/doc_src/cmds/fish_vi_key_bindings.rst b/doc_src/cmds/fish_vi_key_bindings.rst new file mode 100644 index 000000000..67f4b0a41 --- /dev/null +++ b/doc_src/cmds/fish_vi_key_bindings.rst @@ -0,0 +1,36 @@ +.. _cmd-fish_vi_key_bindings: + +fish_vi_key_bindings - set vi key bindings for fish +=============================================================== + +Synopsis +-------- + +.. synopsis:: + + fish_vi_key_bindings + fish_vi_key_bindings [--no-erase] [INIT_MODE] + +Description +----------- + +``fish_vi_key_bindings`` sets the vi key bindings for ``fish`` shell. + +If a valid *INIT_MODE* is provided (insert, default, visual), then that mode will become the default +. If no *INIT_MODE* is given, the mode defaults to insert mode. + +The following parameters are available: + +**--no-erase** + Does not clear previous set bindings + +Further information on how to use :ref:`vi-mode `. + +Examples +-------- + +To start using vi key bindings:: + + fish_vi_key_bindings + +or ``set -g fish_key_bindings fish_vi_key_bindings`` in :ref:`config.fish `. diff --git a/doc_src/cmds/functions.rst b/doc_src/cmds/functions.rst index b2ff9368b..269f302a3 100644 --- a/doc_src/cmds/functions.rst +++ b/doc_src/cmds/functions.rst @@ -34,10 +34,10 @@ The following options are available: Causes the specified functions to be erased. This also means that it is prevented from autoloading in the current session. Use :doc:`funcsave ` to remove the saved copy. **-D** or **--details** - Reports the path name where the specified function is defined or could be autoloaded, ``stdin`` if the function was defined interactively or on the command line or by reading standard input, **-** if the function was created via :doc:`source `, and ``n/a`` if the function isn't available. (Functions created via :doc:`alias ` will return **-**, because ``alias`` uses ``source`` internally.) If the **--verbose** option is also specified then five lines are written: + Reports the path name where the specified function is defined or could be autoloaded, ``stdin`` if the function was defined interactively or on the command line or by reading standard input, **-** if the function was created via :doc:`source `, and ``n/a`` if the function isn't available. (Functions created via :doc:`alias ` will return **-**, because ``alias`` uses ``source`` internally. Copied functions will return where the function was copied.) If the **--verbose** option is also specified then five lines are written: - - the pathname as already described, - - ``autoloaded``, ``not-autoloaded`` or ``n/a``, + - the path name as already described, + - if the function was copied, the path name to where the function was originally defined, otherwise ``autoloaded``, ``not-autoloaded`` or ``n/a``, - the line number within the file or zero if not applicable, - ``scope-shadowing`` if the function shadows the vars in the calling function (the normal case if it wasn't defined with **--no-scope-shadowing**), else ``no-scope-shadowing``, or ``n/a`` if the function isn't defined, - the function description minimally escaped so it is a single line, or ``n/a`` if the function isn't defined or has no description. diff --git a/doc_src/cmds/history.rst b/doc_src/cmds/history.rst index 959d8ce30..0deebd795 100644 --- a/doc_src/cmds/history.rst +++ b/doc_src/cmds/history.rst @@ -29,7 +29,7 @@ The following operations (sub-commands) are available: 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 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. + 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. diff --git a/doc_src/cmds/if.rst b/doc_src/cmds/if.rst index 18ad8582e..274845afe 100644 --- a/doc_src/cmds/if.rst +++ b/doc_src/cmds/if.rst @@ -29,8 +29,6 @@ Example The following code will print ``foo.txt exists`` if the file foo.txt exists and is a regular file, otherwise it will print ``bar.txt exists`` if the file bar.txt exists and is a regular file, otherwise it will print ``foo.txt and bar.txt do not exist``. - - :: if test -f foo.txt @@ -44,7 +42,6 @@ The following code will print ``foo.txt exists`` if the file foo.txt exists and The following code will print "foo.txt exists and is readable" if foo.txt is a regular file and readable - :: if test -f foo.txt @@ -52,3 +49,15 @@ The following code will print "foo.txt exists and is readable" if foo.txt is a r echo "foo.txt exists and is readable" end + +See also +-------- + +``if`` is only as useful as the command used as the condition. + +Fish ships a few: + +- :doc:`test` can compare numbers, strings and check paths +- :doc:`string` can perform string operations including wildcard and regular expression matches +- :doc:`path` can check paths for permissions, existence or type +- :doc:`contains` can check if an element is in a list diff --git a/doc_src/cmds/math.rst b/doc_src/cmds/math.rst index 82c376d33..ed84b0e07 100644 --- a/doc_src/cmds/math.rst +++ b/doc_src/cmds/math.rst @@ -17,8 +17,9 @@ Description ``math`` performs mathematical calculations. It supports simple operations such as addition, subtraction, and so on, as well as functions like ``abs()``, ``sqrt()`` and ``ln()``. -By default, the output is a floating-point number with trailing zeroes trimmed. -To get a fixed representation, the ``--scale`` option can be used, including ``--scale=0`` for integer output. +By default, the output shows up to 6 decimal places. +To change the number of decimal places, use the ``--scale`` option, including ``--scale=0`` for integer output. +Trailing zeroes will always be trimmed. Keep in mind that parameter expansion happens before expressions are evaluated. This can be very useful in order to perform calculations involving shell variables or the output of command substitutions, but it also means that parenthesis (``()``) and the asterisk (``*``) glob character have to be escaped or quoted. diff --git a/doc_src/cmds/path.rst b/doc_src/cmds/path.rst index bf764839c..ff819af92 100644 --- a/doc_src/cmds/path.rst +++ b/doc_src/cmds/path.rst @@ -365,19 +365,15 @@ Examples >_ path change-extension '' ../banana ../banana - # but status 1, because there was no extension. >_ path change-extension '' ~/.config /home/alfa/.config - # status 1 >_ path change-extension '' ~/.config.d /home/alfa/.config - # status 0 >_ path change-extension '' ~/.config. /home/alfa/.config - # status 0 "sort" subcommand ----------------------------- diff --git a/doc_src/cmds/read.rst b/doc_src/cmds/read.rst index b26f92a81..ab19e063a 100644 --- a/doc_src/cmds/read.rst +++ b/doc_src/cmds/read.rst @@ -106,7 +106,7 @@ The following code stores the value 'hello' in the shell variable :envvar:`foo`. echo hello|read foo -While this is a neat way to handle command output line-by-line:: +The :doc:`while ` command is a neat way to handle command output line-by-line:: printf '%s\n' line1 line2 line3 line4 | while read -l foo echo "This is another line: $foo" diff --git a/doc_src/cmds/set.rst b/doc_src/cmds/set.rst index a16e04c74..07dc21758 100644 --- a/doc_src/cmds/set.rst +++ b/doc_src/cmds/set.rst @@ -66,7 +66,7 @@ These options modify how variables operate: Treat specified variable as a :ref:`path variable `; variable will be split on colons (``:``) and will be displayed joined by colons colons when quoted (``echo "$PATH"``) or exported. **--unpath** - Causes variable to no longer be tred as a :ref:`path variable `. + Causes variable to no longer be treated as a :ref:`path variable `. Note: variables ending in "PATH" are automatically path variables. Further options: @@ -175,7 +175,7 @@ Remove _$smurf_ from the scope:: > set -e smurf -Remove _$smurf_ from the global and universal scoeps:: +Remove _$smurf_ from the global and universal scopes:: > set -e -Ug smurf diff --git a/doc_src/cmds/string-pad.rst b/doc_src/cmds/string-pad.rst index d9f707eed..5a255d487 100644 --- a/doc_src/cmds/string-pad.rst +++ b/doc_src/cmds/string-pad.rst @@ -48,13 +48,13 @@ Examples >_ string pad -w$COLUMNS (date) # Prints the current time on the right edge of the screen. - +.. END EXAMPLES See Also -------- +.. BEGIN SEEALSO + - The :doc:`printf ` command can do simple padding, for example ``printf %10s\n`` works like ``string pad -w10``. - :doc:`string length ` with the ``--visible`` option can be used to show what fish thinks the width is. - -.. END EXAMPLES diff --git a/doc_src/cmds/string-shorten.rst b/doc_src/cmds/string-shorten.rst index ebb402deb..fe5700f7e 100644 --- a/doc_src/cmds/string-shorten.rst +++ b/doc_src/cmds/string-shorten.rst @@ -81,13 +81,15 @@ Examples # Taking 20 columns from the right instead: …in-path-with-expand +.. END EXAMPLES + See Also -------- +.. BEGIN SEEALSO + - :ref:`string`'s ``pad`` subcommand does the inverse of this command, adding padding to a specific width instead. - The :doc:`printf ` command can do simple padding, for example ``printf %10s\n`` works like ``string pad -w10``. - :doc:`string length ` with the ``--visible`` option can be used to show what fish thinks the width is. - -.. END EXAMPLES diff --git a/doc_src/cmds/string.rst b/doc_src/cmds/string.rst index 65692643c..621e8e083 100644 --- a/doc_src/cmds/string.rst +++ b/doc_src/cmds/string.rst @@ -154,8 +154,8 @@ Examples :start-after: BEGIN EXAMPLES :end-before: END EXAMPLES -"pad" and "shorten" subcommands ---------------------------------- +"pad" subcommand +---------------- .. include:: string-pad.rst :start-after: BEGIN SYNOPSIS @@ -165,10 +165,22 @@ Examples :start-after: BEGIN DESCRIPTION :end-before: END DESCRIPTION +Examples +^^^^^^^^ + .. include:: string-pad.rst :start-after: BEGIN EXAMPLES :end-before: END EXAMPLES +See also +^^^^^^^^ + +.. include:: string-pad.rst + :start-after: BEGIN SEEALSO + +"shorten" subcommand +-------------------- + .. include:: string-shorten.rst :start-after: BEGIN SYNOPSIS :end-before: END SYNOPSIS @@ -177,10 +189,19 @@ Examples :start-after: BEGIN DESCRIPTION :end-before: END DESCRIPTION +Examples +^^^^^^^^ + .. include:: string-shorten.rst :start-after: BEGIN EXAMPLES :end-before: END EXAMPLES +See also +^^^^^^^^ + +.. include:: string-shorten.rst + :start-after: BEGIN SEEALSO + "repeat" subcommand ------------------- diff --git a/doc_src/cmds/test.rst b/doc_src/cmds/test.rst index e2178958e..47a27afb9 100644 --- a/doc_src/cmds/test.rst +++ b/doc_src/cmds/test.rst @@ -11,7 +11,6 @@ Synopsis test [EXPRESSION] [ [EXPRESSION] ] - Description ----------- @@ -21,13 +20,13 @@ Description To see the documentation on the ``test`` command you might have, use ``command man test``. -Tests the expression given and sets the exit status to 0 if true, and 1 if false. An expression is made up of one or more operators and their arguments. +``test`` checks the given conditions and sets the exit status to 0 if they are true, 1 if they are false. The first form (``test``) is preferred. For compatibility with other shells, the second form is available: a matching pair of square brackets (``[ [EXPRESSION] ]``). -This test is mostly POSIX-compatible. +When using a variable or command substitution as an argument with ``test`` you should almost always enclose it in double-quotes, as variables expanding to zero or more than one argument will most likely interact badly with ``test``. -When using a variable as an argument for a test operator you should almost always enclose it in double-quotes. There are only two situations it is safe to omit the quote marks. The first is when the argument is a literal string with no whitespace or other characters special to the shell (e.g., semicolon). For example, ``test -b /my/file``. The second is using a variable that expands to exactly one element including if that element is the empty string (e.g., ``set x ''``). If the variable is not set, set but with no value, or set to more than one value you must enclose it in double-quotes. For example, ``test "$x" = "$y"``. Since it is always safe to enclose variables in double-quotes when used as ``test`` arguments that is the recommended practice. +For historical reasons, ``test`` supports the one-argument form (``test foo``), and this will also be triggered by e.g. ``test -n $foo`` if $foo is unset. We recommend you don't use the one-argument form and quote all variables or command substitutions used with ``test``. Operators for files and directories ----------------------------------- @@ -155,7 +154,7 @@ Expressions can be grouped using parentheses. **(** *EXPRESSION* **)** Returns the value of *EXPRESSION*. -Note that parentheses will usually require escaping with ``\(`` to avoid being interpreted as a command substitution. +Note that parentheses will usually require escaping with ``\`` (so they appear as ``\(`` and ``\)``) to avoid being interpreted as a command substitution. Examples @@ -163,8 +162,6 @@ Examples If the ``/tmp`` directory exists, copy the ``/etc/motd`` file to it: - - :: if test -d /tmp @@ -174,19 +171,22 @@ If the ``/tmp`` directory exists, copy the ``/etc/motd`` file to it: If the variable :envvar:`MANPATH` is defined and not empty, print the contents. (If :envvar:`MANPATH` is not defined, then it will expand to zero arguments, unless quoted.) - - :: if test -n "$MANPATH" echo $MANPATH end +Be careful with unquoted variables:: + + if test -n $MANPATH + # This will also be reached if $MANPATH is unset, + # because in that case we have `test -n`, so it checks if "-n" is non-empty, and it is. + echo $MANPATH + end Parentheses and the ``-o`` and ``-a`` operators can be combined to produce more complicated expressions. In this example, success is printed if there is a ``/foo`` or ``/bar`` file as well as a ``/baz`` or ``/bat`` file. - - :: if test \( -f /foo -o -f /bar \) -a \( -f /baz -o -f /bat \) @@ -196,30 +196,22 @@ Parentheses and the ``-o`` and ``-a`` operators can be combined to produce more Numerical comparisons will simply fail if one of the operands is not a number: - - :: if test 42 -eq "The answer to life, the universe and everything" echo So long and thanks for all the fish # will not be executed end - A common comparison is with :envvar:`status`: - - :: if test $status -eq 0 echo "Previous command succeeded" end - The previous test can likewise be inverted: - - :: if test ! $status -eq 0 @@ -229,8 +221,6 @@ The previous test can likewise be inverted: which is logically equivalent to the following: - - :: if test $status -ne 0 @@ -241,10 +231,16 @@ which is logically equivalent to the following: Standards --------- -``test`` implements a subset of the `IEEE Std 1003.1-2008 (POSIX.1) standard `__. The following exceptions apply: +Unlike many things in fish, ``test`` implements a subset of the `IEEE Std 1003.1-2008 (POSIX.1) standard `__. The following exceptions apply: - The ``<`` and ``>`` operators for comparing strings are not implemented. -- Because this test is a shell builtin and not a standalone utility, using the -c flag on a special file descriptors like standard input and output may not return the same result when invoked from within a pipe as one would expect when invoking the ``test`` utility in another shell. - In cases such as this, one can use ``command`` ``test`` to explicitly use the system's standalone ``test`` rather than this ``builtin`` ``test``. + +See also +-------- + +Other commands that may be useful as a condition, and are often easier to use: + +- :doc:`string`, which can do string operations including wildcard and regular expression matching +- :doc:`path`, which can do file checks and operations, including filters on multiple paths at once diff --git a/doc_src/cmds/type.rst b/doc_src/cmds/type.rst index 763e12a47..1e1b8e0e0 100644 --- a/doc_src/cmds/type.rst +++ b/doc_src/cmds/type.rst @@ -21,10 +21,10 @@ The following options are available: Prints all of possible definitions of the specified names. **-s** or **--short** - Suppresses function expansion when used with no options or with **-a**/**--all**. + Don't print function definitions when used with no options or with **-a**/**--all**. **-f** or **--no-functions** - Suppresses function and builtin lookup. + Suppresses function lookup. **-t** or **--type** Prints ``function``, ``builtin``, or ``file`` if *NAME* is a shell function, builtin, or disk file, respectively. diff --git a/doc_src/commands.rst b/doc_src/commands.rst index 3242e59e7..69454f8ab 100644 --- a/doc_src/commands.rst +++ b/doc_src/commands.rst @@ -35,6 +35,7 @@ Builtins to do a task, like - :doc:`set ` to set, query or erase variables. - :doc:`read ` to read input. - :doc:`string ` for string manipulation. +- :doc:`path ` for filtering paths and handling their components. - :doc:`math ` does arithmetic. - :doc:`argparse ` to make arguments easier to handle. - :doc:`count ` to count arguments. diff --git a/doc_src/completions.rst b/doc_src/completions.rst index 86501aa00..0272c48d4 100644 --- a/doc_src/completions.rst +++ b/doc_src/completions.rst @@ -5,14 +5,57 @@ Writing your own completions To specify a completion, use the ``complete`` command. ``complete`` takes as a parameter the name of the command to specify a completion for. For example, to add a completion for the program ``myprog``, one would start the completion command with ``complete -c myprog ...`` -To provide a list of possible completions for myprog, use the ``-a`` switch. If ``myprog`` accepts the arguments start and stop, this can be specified as ``complete -c myprog -a 'start stop'``. The argument to the ``-a`` switch is always a single string. At completion time, it will be tokenized on spaces and tabs, and variable expansion, command substitution and other forms of parameter expansion will take place. +To provide a list of possible completions for myprog, use the ``-a`` switch. If ``myprog`` accepts the arguments start and stop, this can be specified as ``complete -c myprog -a 'start stop'``. The argument to the ``-a`` switch is always a single string. At completion time, it will be tokenized on spaces and tabs, and variable expansion, command substitution and other forms of parameter expansion will take place:: + + # If myprog can list the valid outputs with the list-outputs subcommand: + complete -c myprog -l output -a '(myprog list-outputs)' ``fish`` has a special syntax to support specifying switches accepted by a command. The switches ``-s``, ``-l`` and ``-o`` are used to specify a short switch (single character, such as ``-l``), a gnu style long switch (such as ``--color``) and an old-style long switch (like ``-shuffle``), respectively. If the command 'myprog' has an option '-o' which can also be written as ``--output``, and which can take an additional value of either 'yes' or 'no', this can be specified by writing:: complete -c myprog -s o -l output -a "yes no" +For a complete description of the various switches accepted by the ``complete`` command, see the documentation for the :doc:`complete ` builtin, or write ``complete --help`` inside the ``fish`` shell. -There are also special switches for specifying that a switch requires an argument, to disable filename completion, to create completions that are only available in some combinations, etc.. For a complete description of the various switches accepted by the ``complete`` command, see the documentation for the :doc:`complete ` builtin, or write ``complete --help`` inside the ``fish`` shell. +In the complete call above, the ``-a`` arguments apply when the option -o/--output has been given, so this offers them for:: + + > myprog -o + > myprog --output= + +By default, option arguments are *optional*, so the candidates are only offered directly attached like that, so they aren't given in this case:: + + > myprog -o + +Usually options *require* a parameter, so you would give ``--require-parameter`` / ``-r``:: + + complete -c myprog -s o -l output -ra "yes no" + +which offers yes/no in these cases:: + + > myprog -o + > myprog --output= + > myprog -o + > myprog --output + +In the latter two cases, files will also be offered because file completion is enabled by default. + +You would either inhibit file completion for a single option:: + + complete -c myprog -s o -l output --no-files -ra "yes no" + +or with a specific condition:: + + complete -c myprog -f --condition '__fish_seen_subcommand_from somesubcommand' + +or you can disable file completions globally for the command:: + + complete -c myprog -f + +If you have disabled them globally, you can enable them just for a specific condition or option with the ``--force-files`` / ``-F`` option:: + + # Disable files by default + complete -c myprog -f + # but reenable them for --config-file + complete -c myprog -l config-file --force-files -r As a more comprehensive example, here's a commented excerpt of the completions for systemd's ``timedatectl``:: @@ -38,7 +81,7 @@ As a more comprehensive example, here's a commented excerpt of the completions f # The `-n`/`--condition` option takes script as a string, which it executes. # If it returns true, the completion is offered. # Here the condition is the `__fish_seen_subcommands_from` helper function. - # If returns true if any of the given commands is used on the commandline, + # It returns true if any of the given commands is used on the commandline, # as determined by a simple heuristic. # For more complex uses, you can write your own function. # See e.g. the git completions for an example. @@ -76,7 +119,7 @@ For examples of how to write your own complex completions, study the completions Useful functions for writing completions ---------------------------------------- -``fish`` ships with several functions that are very useful when writing command specific completions. Most of these functions name begins with the string ``__fish_``. Such functions are internal to ``fish`` and their name and interface may change in future fish versions. Still, some of them may be very useful when writing completions. A few of these functions are described here. Be aware that they may be removed or changed in future versions of fish. +``fish`` ships with several functions that may be useful when writing command-specific completions. Most of these function names begin with the string ``__fish_``. Such functions are internal to ``fish`` and their name and interface may change in future fish versions. A few of these functions are described here. Functions beginning with the string ``__fish_print_`` print a newline separated list of strings. For example, ``__fish_print_filesystems`` prints a list of all known file systems. Functions beginning with ``__fish_complete_`` print out a newline separated list of completions with descriptions. The description is separated from the completion by a tab character. @@ -98,8 +141,6 @@ Functions beginning with the string ``__fish_print_`` print a newline separated - ``__fish_print_interfaces`` prints a list of all known network interfaces. -- ``__fish_print_packages`` prints a list of all installed packages. This function currently handles Debian, rpm and Gentoo packages. - .. _completion-path: Where to put completions @@ -120,7 +161,7 @@ These paths are controlled by parameters set at build, install, or run time, and This wide search may be confusing. If you are unsure, your completions probably belong in ``~/.config/fish/completions``. -If you have written new completions for a common Unix command, please consider sharing your work by submitting it via the instructions in :ref:`Further help and development ` +If you have written new completions for a common Unix command, please consider sharing your work by submitting it via the instructions in :ref:`Further help and development `. If you are developing another program and would like to ship completions with your program, install them to the "vendor" completions directory. As this path may vary from system to system, the ``pkgconfig`` framework should be used to discover this path with the output of ``pkg-config --variable completionsdir fish``. diff --git a/doc_src/conf.py b/doc_src/conf.py index b5aeb5e95..893256db5 100644 --- a/doc_src/conf.py +++ b/doc_src/conf.py @@ -113,7 +113,7 @@ html_theme_path = ["."] html_theme = "python_docs_theme" # Shared styles across all doc versions. -html_css_files = ["/docs/shared/style.css"] +html_css_files = [] # Don't add a weird "_sources" directory html_copy_source = False @@ -187,6 +187,7 @@ man_pages = [ ("interactive", "fish-interactive", "", [author], 1), ("relnotes", "fish-releasenotes", "", [author], 1), ("completions", "fish-completions", "", [author], 1), + ("prompt", "fish-prompt-tutorial", "", [author], 1), ( "fish_for_bash_users", "fish-for-bash-users", diff --git a/doc_src/contributing.rst b/doc_src/contributing.rst new file mode 100644 index 000000000..e582053ea --- /dev/null +++ b/doc_src/contributing.rst @@ -0,0 +1 @@ +.. include:: ../CONTRIBUTING.rst diff --git a/doc_src/faq.rst b/doc_src/faq.rst index 1a41a4300..defce4a29 100644 --- a/doc_src/faq.rst +++ b/doc_src/faq.rst @@ -166,18 +166,21 @@ As a special case, most of the time history substitution is used as ``sudo !!``. In general, fish's history recall works like this: -- Like other shells, the Up arrow, :kbd:`↑` recalls whole lines, starting from the last executed line. A single press replaces "!!", later presses replace "!-3" and the like. +- Like other shells, the Up arrow, :kbd:`↑` 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 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 :kbd:`Ctrl`\ +\ :kbd:`R` to open the history in the pager. -- :kbd:`Alt`\ +\ :kbd:`↑` recalls individual arguments, starting from the last argument in the last executed line. A single press replaces "!$", later presses replace "!!:4" and such. As an alternate key binding, :kbd:`Alt`\ +\ :kbd:`.` can be used. - -- If the argument you want is far back in history (e.g. 2 lines back - that's a lot of words!), type any part of it and then press :kbd:`Alt`\ +\ :kbd:`↑`. This will show only arguments containing that part and you will get what you want much faster. Try it out, this is very convenient! - -- If you want to reuse several arguments from the same line ("!!:3*" and the like), consider recalling the whole line and removing what you don't need (:kbd:`Alt`\ +\ :kbd:`D` and :kbd:`Alt`\ +\ :kbd:`Backspace` are your friends). +- :kbd:`Alt`\ +\ :kbd:`↑` recalls individual arguments, starting from the last argument in the last executed line. This can be used instead of "!$". See :ref:`documentation ` for more details about line editing in fish. +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 + +Run this and ``!!`` will be replaced with the last history entry, anywhere on the commandline. Put it into :ref:`config.fish ` to keep it. + How do I run a subcommand? The backtick doesn't work! ----------------------------------------------------- ``fish`` uses parentheses for subcommands. For example:: @@ -294,14 +297,6 @@ For these reasons, fish does not do this, and instead expects asterisks to be qu This is similar to bash's "failglob" option. -I accidentally entered a directory path and fish changed directory. What happened? ----------------------------------------------------------------------------------- -If fish is unable to locate a command with a given name, and it starts with ``.``, ``/`` or ``~``, fish will test if a directory of that name exists. If it does, it assumes that you want to change your directory. For example, the fastest way to switch to your home directory is to simply press ``~`` and enter. - -The open command doesn't work. ------------------------------- -The ``open`` command uses the MIME type database and the ``.desktop`` files used by Gnome and KDE to identify filetypes and default actions. If at least one of these environments is installed, but the open command is not working, this probably means that the relevant files are installed in a non-standard location. Consider :ref:`asking for more help `. - .. _faq-ssh-interactive: Why won't SSH/SCP/rsync connect properly when fish is my login shell? @@ -357,14 +352,3 @@ If you installed it with a package manager, just use that package manager's unin rm /usr/local/share/man/man1/fish*.1 cd /usr/local/bin rm -f fish fish_indent - -Where can I find extra tools for fish? --------------------------------------- -The fish user community extends fish in unique and useful ways via scripts that aren't always appropriate for bundling with the fish package. Typically because they solve a niche problem unlikely to appeal to a broad audience. You can find those extensions, including prompts, themes and useful functions, in various third-party repositories. These include: - -- `Fisher `_ -- `Fundle `_ -- `Oh My Fish `_ -- `Tacklebox `_ - -This is not an exhaustive list and the fish project has no opinion regarding the merits of the repositories listed above or the scripts found therein. diff --git a/doc_src/fish_for_bash_users.rst b/doc_src/fish_for_bash_users.rst index 81aa12686..44ae4e8a0 100644 --- a/doc_src/fish_for_bash_users.rst +++ b/doc_src/fish_for_bash_users.rst @@ -60,7 +60,8 @@ And here is fish:: > set foo "bar baz" > printf '"%s"\n' $foo - # foo was set as one element, so it will be passed as one element, so this is one line + # foo was set as one element, + # so it will be passed as one element, so this is one line "bar baz" All variables are "arrays" (we use the term "lists"), and expanding a variable expands to all its elements, with each element as its own argument (like bash's ``"${var[@]}"``:: diff --git a/doc_src/fish_synopsis.py b/doc_src/fish_synopsis.py index 51df271e1..d0caff7ca 100644 --- a/doc_src/fish_synopsis.py +++ b/doc_src/fish_synopsis.py @@ -28,7 +28,7 @@ class FishSynopsisDirective(CodeBlock): return CodeBlock.run(self) lexer = FishSynopsisLexer() result = nodes.line_block() - for (start, tok, text) in lexer.get_tokens_unprocessed("\n".join(self.content)): + for start, tok, text in lexer.get_tokens_unprocessed("\n".join(self.content)): if ( # Literal text. (tok in (Name.Function, Name.Constant) and not text.isupper()) or text.startswith("-") # Literal option, even if it's uppercase. diff --git a/doc_src/index.rst b/doc_src/index.rst index a7bbf0058..488a0b3a9 100644 --- a/doc_src/index.rst +++ b/doc_src/index.rst @@ -25,9 +25,9 @@ If this is your first time using fish, see the :ref:`tutorial `. If you are already familiar with other shells like bash and want to see the scripting differences, see :ref:`Fish For Bash Users `. -For a comprehensive overview of fish's scripting language, see :ref:`The Fish Language `. +For an overview of fish's scripting language, see :ref:`The Fish Language `. If it would be useful in a script file, it's here. -For information on using fish interactively, see :ref:`Interactive use `. +For information on using fish interactively, see :ref:`Interactive use `. If it's about key presses, syntax highlighting or anything else that needs an interactive terminal session, look here. If you need to install fish first, read on, the rest of this document will tell you how to get, install and configure fish. @@ -107,11 +107,11 @@ If you want to share your script with others, you might want to use :command:`en #!/usr/bin/env fish echo Hello from fish $version -This will call ``env``, which then goes through :envvar:`PATH` to find a program called "fish". This makes it work, whether fish is installed in /usr/local/bin/fish or /usr/bin/fish or ~/.local/bin/fish, as long as that directory is in :envvar:`PATH`. +This will call ``env``, which then goes through :envvar:`PATH` to find a program called "fish". This makes it work, whether fish is installed in (for example) ``/usr/local/bin/fish``, ``/usr/bin/fish``, or ``~/.local/bin/fish``, as long as that directory is in :envvar:`PATH`. The shebang line is only used when scripts are executed without specifying the interpreter. For functions inside fish or when executing a script with ``fish /path/to/script``, a shebang is not required (but it doesn't hurt!). -When executing files without an interpreter, fish, like other shells, tries your system shell, typically /bin/sh. This is needed because some scripts are shipped without a shebang line. +When executing files without an interpreter, fish, like other shells, tries your system shell, typically ``/bin/sh``. This is needed because some scripts are shipped without a shebang line. Configuration ============= @@ -171,6 +171,8 @@ Other help pages fish_for_bash_users tutorial completions + prompt design relnotes + contributing license diff --git a/doc_src/interactive.rst b/doc_src/interactive.rst index 8c9b99e13..2d474d95d 100644 --- a/doc_src/interactive.rst +++ b/doc_src/interactive.rst @@ -125,6 +125,7 @@ Variable Meaning .. envvar:: fish_color_status the last command's nonzero exit code in the default prompt .. envvar:: fish_color_cancel the '^C' indicator on a canceled command .. envvar:: fish_color_search_match history search matches and selected pager items (background only) +.. envvar:: fish_color_history_current the current position in the history for commands like ``dirh`` and ``cdh`` ========================================== ===================================================================== @@ -189,7 +190,7 @@ To avoid needless typing, a frequently-run command like ``git checkout`` can be After entering ``gco`` and pressing :kbd:`Space` or :kbd:`Enter`, a ``gco`` in command position will turn into ``git checkout`` in the command line. If you want to use a literal ``gco`` sometimes, use :kbd:`Control`\ +\ :kbd:`Space` [#]_. -This is a lot more powerful, for example you can make going up a number of directories easier with this:: +Abbreviations are a lot more powerful than just replacing literal strings. For example you can make going up a number of directories easier with this:: function multicd echo cd (string repeat -n (math (string length -- $argv[1]) - 1) ../) @@ -202,40 +203,34 @@ The advantage over aliases is that you can see the actual command before using i .. [#] Any binding that executes the ``expand-abbr`` or ``execute`` :doc:`bind function ` will expand abbreviations. By default :kbd:`Control`\ +\ :kbd:`Space` is bound to just inserting a space. -.. _title: - -Programmable title ------------------- - -When using most virtual terminals, it is possible to set the message displayed in the titlebar of the terminal window. This can be done automatically in fish by defining the :doc:`fish_title ` function. The :doc:`fish_title ` function is executed before and after a new command is executed or put into the foreground and the output is used as a titlebar message. The :doc:`status current-command ` builtin will always return the name of the job to be put into the foreground (or ``fish`` if control is returning to the shell) when the :doc:`fish_prompt ` function is called. The first argument to fish_title will contain the most recently executed foreground command as a string. - -The default fish title shows the hostname if connected via ssh, the currently running command (unless it is fish) and the current working directory. All of this is shortened to not make the tab too wide. - -Examples: - -To show the last command and working directory in the title:: - - function fish_title - # `prompt_pwd` shortens the title. This helps prevent tabs from becoming very wide. - echo $argv[1] (prompt_pwd) - pwd - end - .. _prompt: Programmable prompt ------------------- -When it is fish's turn to ask for input (like after it started or the command ended), it will show a prompt. It does this by running the :doc:`fish_prompt ` and :doc:`fish_right_prompt ` functions. +When it is fish's turn to ask for input (like after it started or the command ended), it will show a prompt. Often this looks something like:: -The output of the former is displayed on the left and the latter's output on the right side of the terminal. The output of :doc:`fish_mode_prompt ` will be prepended on the left, though the default function only does this when in :ref:`vi-mode `. + you@hostname ~> + +This prompt is determined by running the :doc:`fish_prompt ` and :doc:`fish_right_prompt ` functions. + +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 `, the output of :doc:`fish_mode_prompt ` will be prepended on the left. + +Fish ships with a few prompts which you can see with :doc:`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``. + +You can also change these functions yourself by running ``funced fish_prompt`` and ``funcsave fish_prompt`` once you are happy with the result (or ``fish_right_prompt`` if you want to change that). + +.. [#] The web interface runs purely locally on your computer and requires python to be installed. .. _greeting: Configurable greeting --------------------- -When it is started interactively, fish tries to run the :doc:`fish_greeting ` function. The default fish_greeting prints a simple greeting. You can change its text by changing the ``$fish_greeting`` variable, for instance using a :ref:`universal variable `:: +When it is started interactively, fish tries to run the :doc:`fish_greeting ` function. The default fish_greeting prints a simple message. You can change its text by changing the ``$fish_greeting`` variable, for instance using a :ref:`universal variable `:: set -U fish_greeting @@ -251,16 +246,26 @@ or you can script it by changing the function:: save this in config.fish or :ref:`a function file `. You can also use :doc:`funced ` and :doc:`funcsave ` to edit it easily. -.. _private-mode: +.. _title: -Private mode -------------- +Programmable title +------------------ -If ``$fish_private_mode`` is set to a non-empty value, commands will not be written to the history file on disk. +When using most terminals, it is possible to set the text displayed in the titlebar of the terminal window. Fish does this by running the :doc:`fish_title ` function. It is executed before and after a command and the output is used as a titlebar message. -You can also launch with ``fish --private`` (or ``fish -P`` for short). This both hides old history and prevents writing history to disk. This is useful to avoid leaking personal information (e.g. for screencasts) or when dealing with sensitive information. +The :doc:`status current-command ` builtin will always return the name of the job to be put into the foreground (or ``fish`` if control is returning to the shell) when the :doc:`fish_title ` function is called. The first argument will contain the most recently executed foreground command as a string. -You can query the variable ``fish_private_mode`` (``if test -n "$fish_private_mode" ...``) if you would like to respect the user's wish for privacy and alter the behavior of your own fish scripts. +The default title shows the hostname if connected via ssh, the currently running command (unless it is fish) and the current working directory. All of this is shortened to not make the tab too wide. + +Examples: + +To show the last command and working directory in the title:: + + function fish_title + # `prompt_pwd` shortens the title. This helps prevent tabs from becoming very wide. + echo $argv[1] (prompt_pwd) + pwd + end .. _editor: @@ -269,7 +274,7 @@ Command line editor The fish editor features copy and paste, a :ref:`searchable history ` and many editor functions that can be bound to special keyboard shortcuts. -Like bash and other shells, fish includes two sets of keyboard shortcuts (or key bindings): one inspired by the Emacs text editor, and one by the Vi text editor. The default editing mode is Emacs. You can switch to Vi mode by running ``fish_vi_key_bindings`` and switch back with ``fish_default_key_bindings``. You can also make your own key bindings by creating a function and setting the ``fish_key_bindings`` variable to its name. For example:: +Like bash and other shells, fish includes two sets of keyboard shortcuts (or key bindings): one inspired by the Emacs text editor, and one by the Vi text editor. The default editing mode is Emacs. You can switch to Vi mode by running :doc:`fish_vi_key_bindings ` and switch back with :doc:`fish_default_key_bindings `. You can also make your own key bindings by creating a function and setting the ``fish_key_bindings`` variable to its name. For example:: function fish_hybrid_key_bindings --description \ @@ -296,7 +301,7 @@ Some bindings are common across Emacs and Vi mode, because they aren't text edit - :kbd:`Enter` executes the current commandline or inserts a newline if it's not complete yet (e.g. a ``)`` or ``end`` is missing). -- :kbd:`Alt`\ +\ :kbd:`Enter` inserts a newline at the cursor position. +- :kbd:`Alt`\ +\ :kbd:`Enter` inserts a newline at the cursor position. This is useful to add a line to a commandline that's already complete. - :kbd:`Alt`\ +\ :kbd:`←` and :kbd:`Alt`\ +\ :kbd:`→` 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`\ +\ :kbd:`→` (or :kbd:`Alt`\ +\ :kbd:`F`) accepts the first word in the suggestion. @@ -308,9 +313,9 @@ Some bindings are common across Emacs and Vi mode, because they aren't text edit - :kbd:`Alt`\ +\ :kbd:`↑` and :kbd:`Alt`\ +\ :kbd:`↓` search the command history for the previous/next token containing the token under the cursor before the search was started. If the commandline was not on a token when the search started, all tokens match. See the :ref:`history ` section for more information on history searching. -- :kbd:`Control`\ +\ :kbd:`C` interrupt/kill whatever is running (SIGINT). +- :kbd:`Control`\ +\ :kbd:`C` interrupts/kills whatever is running (SIGINT). -- :kbd:`Control`\ +\ :kbd:`D` delete one character to the right of the cursor. If the command line is empty, :kbd:`Control`\ +\ :kbd:`D` will exit fish. +- :kbd:`Control`\ +\ :kbd:`D` deletes one character to the right of the cursor. If the command line is empty, :kbd:`Control`\ +\ :kbd:`D` will exit fish. - :kbd:`Control`\ +\ :kbd:`U` removes contents from the beginning of line to the cursor (moving it to the :ref:`killring `). @@ -332,7 +337,7 @@ Some bindings are common across Emacs and Vi mode, because they aren't text edit - :kbd:`Alt`\ +\ :kbd:`W` prints a short description of the command under the cursor. -- :kbd:`Alt`\ +\ :kbd:`E` edit the current command line in an external editor. The editor is chosen from the first available of the ``$VISUAL`` or ``$EDITOR`` variables. +- :kbd:`Alt`\ +\ :kbd:`E` edits the current command line in an external editor. The editor is chosen from the first available of the ``$VISUAL`` or ``$EDITOR`` variables. - :kbd:`Alt`\ +\ :kbd:`V` Same as :kbd:`Alt`\ +\ :kbd:`E`. @@ -345,7 +350,7 @@ Some bindings are common across Emacs and Vi mode, because they aren't text edit Emacs mode commands ^^^^^^^^^^^^^^^^^^^ -To enable emacs mode, use ``fish_default_key_bindings``. This is also the default. +To enable emacs mode, use :doc:`fish_default_key_bindings `. This is also the default. - :kbd:`Home` or :kbd:`Control`\ +\ :kbd:`A` moves the cursor to the beginning of the line. @@ -390,8 +395,7 @@ Vi mode commands Vi mode allows for the use of Vi-like commands at the prompt. Initially, :ref:`insert mode ` is active. :kbd:`Escape` enters :ref:`command mode `. The commands available in command, insert and visual mode are described below. Vi mode shares :ref:`some bindings ` with :ref:`Emacs mode `. -To enable vi mode, use ``fish_vi_key_bindings``. - +To enable vi mode, use :doc:`fish_vi_key_bindings `. It is also possible to add all emacs-mode bindings to vi-mode by using something like:: @@ -418,14 +422,20 @@ The ``fish_vi_cursor`` function will be used to change the cursor's shape depend set fish_cursor_default block # Set the insert mode cursor to a line set fish_cursor_insert line - # Set the replace mode cursor to an underscore + # Set the replace mode cursors to an underscore set fish_cursor_replace_one underscore + set fish_cursor_replace underscore + # Set the external cursor to a line. The external cursor appears when a command is started. + # The cursor shape takes the value of fish_cursor_default when fish_cursor_external is not specified. + set fish_cursor_external line # The following variable can be used to configure cursor shape in # visual mode, but due to fish_cursor_default, is redundant here set fish_cursor_visual block Additionally, ``blink`` can be added after each of the cursor shape parameters to set a blinking cursor in the specified shape. +Fish knows the shapes "block", "line" and "underscore", other values will be ignored. + If the cursor shape does not appear to be changing after setting the above variables, it's likely your terminal emulator does not support the capabilities necessary to do this. It may also be the case, however, that ``fish_vi_cursor`` has not detected your terminal's features correctly (for example, if you are using ``tmux``). If this is the case, you can force ``fish_vi_cursor`` to set the cursor shape by setting ``$fish_vi_force_cursor`` in ``config.fish``. You'll have to restart fish for any changes to take effect. If cursor shape setting remains broken after this, it's almost certainly an issue with your terminal emulator, and not fish. .. _vi-mode-command: @@ -443,7 +453,7 @@ Command mode is also known as normal mode. - :kbd:`i` enters :ref:`insert mode ` at the current cursor position. -- :kbd:`Shift`\ +\ :kbd:`R` enters :ref:`insert mode ` at the beginning of the line. +- :kbd:`Shift`\ +\ :kbd:`I` enters :ref:`insert mode ` at the beginning of the line. - :kbd:`v` enters :ref:`visual mode ` at the current cursor position. @@ -534,6 +544,10 @@ If you change your mind on a binding and want to go back to fish's default, you Fish remembers its preset bindings and so it will take effect again. This saves you from having to remember what it was before and add it again yourself. +If you use :ref:`vi bindings `, note that ``bind`` will by default bind keys in :ref:`command mode `. To bind something in :ref:`insert mode `:: + + bind --mode insert \cc 'commandline -r ""' + Key sequences """"""""""""" @@ -620,6 +634,17 @@ If the commandline reads ``cd m``, place the cursor over the ``m`` character and .. [#] Or another binding that triggers the ``history-pager`` input function. See :doc:`bind ` for a list. .. [#] Or another binding that triggers the ``pager-toggle-search`` input function. +.. _private-mode: + +Private mode +------------- + +Fish has a private mode, in which command history will not be written to the history file on disk. To enable it, either set ``$fish_private_mode`` to a non-empty value, or launch with ``fish --private`` (or ``fish -P`` for short). + +If you launch fish with ``-P``, it both hides old history and prevents writing history to disk. This is useful to avoid leaking personal information (e.g. for screencasts) or when dealing with sensitive information. + +You can query the variable ``fish_private_mode`` (``if test -n "$fish_private_mode" ...``) if you would like to respect the user's wish for privacy and alter the behavior of your own fish scripts. + Navigating directories ---------------------- diff --git a/doc_src/language.rst b/doc_src/language.rst index 16558cc88..a990b7553 100644 --- a/doc_src/language.rst +++ b/doc_src/language.rst @@ -91,7 +91,7 @@ searches for lines ending in ``enabled)`` in ``foo.txt`` (the ``$`` is special t :: - apt install "postgres-*" + apt install "postgres-*" installs all packages with a name starting with "postgres-", instead of looking through the current directory for files named "postgres-something". @@ -238,6 +238,37 @@ As a convenience, the pipe ``&|`` redirects both stdout and stderr to the same p .. [#] A "pager" here is a program that takes output and "paginates" it. ``less`` doesn't just do pages, it allows arbitrary scrolling (even back!). + +Combining pipes and redirections +-------------------------------- + +It is possible to use multiple redirections and a pipe at the same time. In that case, they are read in this order: + +1. First the pipe is set up. +2. Then the redirections are evaluated from left-to-right. + +This is important when any redirections reference other file descriptors with the ``&N`` syntax. When you say ``>&2``, that will redirect stdout to where stderr is pointing to *at that time*. + +Consider this helper function:: + + # Just make a function that prints something to stdout and stderr + function print + echo out + echo err >&2 + end + +Now let's see a few cases:: + + # Redirect both stderr and stdout to less + # (can also be spelt as `&|`) + print 2>&1 | less + + # Show the "out" on stderr, silence the "err" + print >&2 2>/dev/null + + # Silence both + print >/dev/null 2>&1 + .. _syntax-job-control: Job control @@ -398,12 +429,14 @@ This uses the :doc:`test ` command to see if the file /etc/os-release 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. -``if`` is commonly used with the :doc:`test ` command that can check conditions.:: +A more complicated example with a :ref:`command substitution `:: - if test 5 -gt 2 - echo "Yes, 5 is greater than 2" + if test "$(uname)" = Linux + echo I like penguins end +Because ``test`` can be used for many different tests, it is important to quote variables and command substitutions. If the ``$(uname)`` was not quoted, and ``uname`` printed nothing it would run ``test = Linux``, which is an error. + ``if`` can also take ``else if`` clauses with additional conditions and an :doc:`else ` clause that is executed when everything else was false:: if test "$number" -gt 10 @@ -429,6 +462,13 @@ The :doc:`not ` keyword can be used to invert the status:: echo "You have fish!" end +Other things commonly used in if-conditions: + +- :doc:`contains ` - to see if a list contains a specific element (``if contains -- /usr/bin $PATH``) +- :doc:`string ` - to e.g. match strings (``if string match -q -- '*-' $arg``) +- :doc:`path ` - to check if paths of some criteria exist (``if path is -rf -- ~/.config/fish/config.fish``) +- :doc:`type ` - to see if a command, function or builtin exists (``if type -q git``) + The ``switch`` statement ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -503,7 +543,7 @@ Loops and blocks Like most programming language, fish also has the familiar :doc:`while ` and :doc:`for ` loops. -``while`` works like a repeated :doc:`if `:: +``while`` works like a repeated :ref:`if `:: while true echo Still running @@ -652,7 +692,7 @@ Unlike all the other expansions, variable expansion also happens in double quote Outside of double quotes, variables will expand to as many arguments as they have elements. That means an empty list will expand to nothing, a variable with one element will expand to that element, and a variable with multiple elements will expand to each of those elements separately. -If a variable expands to nothing, it will cancel out any other strings attached to it. See the :ref:`cartesian product ` section for more information. +If a variable expands to nothing, it will cancel out any other strings attached to it. See the :ref:`Combining Lists ` section for more information. Unlike other shells, fish doesn't do what is known as "Word Splitting". Once a variable is set to a particular set of elements, those elements expand as themselves. They aren't split on spaces or newlines or anything:: @@ -693,10 +733,51 @@ The ``$`` symbol can also be used multiple times, as a kind of "dereference" ope # 20 # 30 -``$$foo[$i]`` is "the value of the variable named by ``$foo[$i]``. +``$$foo[$i]`` is "the value of the variable named by ``$foo[$i]``". When using this feature together with list brackets, the brackets will be used from the inside out. ``$$foo[5]`` will use the fifth element of ``$foo`` as a variable name, instead of giving the fifth element of all the variables $foo refers to. That would instead be expressed as ``$$foo[1..-1][5]`` (take all elements of ``$foo``, use them as variable names, then give the fifth element of those). +Some more examples:: + + set listone 1 2 3 + set listtwo 4 5 6 + set var listone listtwo + + echo $$var + # Output is 1 2 3 4 5 6 + + echo $$var[1] + # Output is 1 2 3 + + echo $$var[2][3] + # $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 + +Variables as command +'''''''''''''''''''' + +Like other shells, you can run the value of a variable as a command. + +:: + + > set -g EDITOR emacs + > $EDITOR foo # opens emacs, possibly the GUI version + +If you want to give the command an argument inside the variable it needs to be a separate element:: + + > set EDITOR emacs -nw + > $EDITOR foo # opens emacs in the terminal even if the GUI is installed + > set EDITOR "emacs -nw" + > $EDITOR foo # tries to find a command called "emacs -nw" + +Also like other shells, this only works with commands, builtins and functions - it will not work with keywords because they have syntactical importance. + +For instance ``set if $if`` won't allow you to make an if-block, and ``set cmd command`` won't allow you to use the :doc:`command ` decorator, but only uses like ``$cmd -q foo``. + + .. _expand-command-substitution: Command substitution @@ -781,7 +862,7 @@ If there is no "," or variable expansion between the curly braces, they will not > echo {{a,b}} {a} {b} # because the inner brace pair is expanded, but the outer isn't. -If after expansion there is nothing between the braces, the argument will be removed (see :ref:`the cartesian product section `):: +If after expansion there is nothing between the braces, the argument will be removed (see :ref:`the Combining Lists ` section):: > echo foo-{$undefinedvar} # Output is an empty line, just like a bare `echo`. @@ -795,49 +876,44 @@ To use a "," as an element, :ref:`quote ` or :ref:`escape ` it. .. _cartesian-product: -Combining lists (Cartesian Product) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Combining lists +^^^^^^^^^^^^^^^ -When lists are expanded with other parts attached, they are expanded with these parts still attached. Even if two lists are attached to each other, they are expanded in all combinations. This is referred to as the "cartesian product" (like in mathematics), and works basically like :ref:`brace expansion `. +When lists are expanded with other parts attached, they are expanded with these parts still attached. That means any string before a list will be concatenated to each element, and two lists will be expanded in all combinations - every element of the first with every element of the second. + +This works basically like :ref:`brace expansion `. Examples:: # Brace expansion is the most familiar: - # All elements in the brace combine with the parts outside of the braces + # All elements in the brace combine with + # the parts outside of the braces >_ echo {good,bad}" apples" good apples bad apples # The same thing happens with variable expansion. - >_ set -l a x y z - >_ set -l b 1 2 3 - - # $a is {x,y,z}, $b is {1,2,3}, - # so this is `echo {x,y,z}{1,2,3}` - >_ echo $a$b + >_ set -l a x y z; set -l b 1 2 3 + >_ echo $a$b # same as {x,y,z}{1,2,3} x1 y1 z1 x2 y2 z2 x3 y3 z3 - # Same thing if something is between the lists - >_ echo $a"-"$b - x-1 y-1 z-1 x-2 y-2 z-2 x-3 y-3 z-3 +A result of this is that, if a list has no elements, this combines the string with no elements, which means the entire token is removed! - # Or a brace expansion and a variable - >_ echo {x,y,z}$b - x1 y1 z1 x2 y2 z2 x3 y3 z3 +:: - # A combined brace-variable expansion - >_ echo {$b}word - 1word 2word 3word - - # Special case: If $c has no elements, this expands to nothing + >_ set -l c # <- this list is empty! >_ echo {$c}word - # Output is an empty line + # Output is an empty line - the "word" part is gone + +This can be quite useful. For example, if you want to go through all the files in all the directories in :envvar:`PATH`, use +:: + + for file in $PATH/* + +Because :envvar:`PATH` is a list, this expands to all the files in all the directories in it. And if there are no directories in :envvar:`PATH`, the right answer here is to expand to no files. Sometimes this may be unwanted, especially that tokens can disappear after expansion. In those cases, you should double-quote variables - ``echo "$c"word``. -This also happens after :ref:`command substitution `. To avoid tokens disappearing there, make the inner command return a trailing newline, or store the output in a variable and double-quote it. - -E.g. -:: +This also happens after :ref:`command substitution `. To avoid tokens disappearing there, make the inner command return a trailing newline, or double-quote it:: >_ set b 1 2 3 >_ echo (echo x)$b @@ -850,13 +926,8 @@ E.g. # so the command substitution expands to an empty string, # so this is `''banana` banana - -This can be quite useful. For example, if you want to go through all the files in all the directories in :envvar:`PATH`, use -:: - - for file in $PATH/* - -Because :envvar:`PATH` is a list, this expands to all the files in all the directories in it. And if there are no directories in :envvar:`PATH`, the right answer here is to expand to no files. + >_ echo "$(printf '%s' '')"banana + # quotes mean this is one argument, the banana stays .. _expand-slices: @@ -1009,7 +1080,37 @@ So you set a variable with ``set``, and use it with a ``$`` and the name. Variable Scope ^^^^^^^^^^^^^^ -There are four kinds of variables in fish: universal, global, function and local variables. +All variables in fish have a scope. For example they can be global or local to a function or block:: + + # This variable is global, we can use it everywhere. + set --global name Patrick + # This variable is local, it will not be visible in a function we call from here. + set --local place "at the Krusty Krab" + + function local + # This can find $name, but not $place + echo Hello this is $name $place + + # This variable is local, it will not be available + # outside of this function + set --local instrument mayonnaise + echo My favorite instrument is $instrument + # This creates a local $name, and won't touch the global one + set --local name Spongebob + echo My best friend is $name + end + + local + # Will print: + # Hello this is Patrick + # My favorite instrument is mayonnaise + # My best friend is Spongebob + + echo $name, I am $place and my instrument is $instrument + # Will print: + # Patrick, I am at the Krusty Krab and my instrument is + +There are four kinds of variable scopes in fish: universal, global, function and local variables. - Universal variables are shared between all fish sessions a user is running on one computer. They are stored on disk and persist even after reboot. - Global variables are specific to the current fish session. They can be erased by explicitly requesting ``set -e``. @@ -1080,12 +1181,13 @@ Here is an example of local vs function-scoped variables:: set gnu "In the beginning there was nothing, which exploded" end - echo $pirate # This will not output anything, since the pirate was local + echo $pirate + # This will output the good Captain's speech + # since $captain had function-scope. echo $captain - # This will output the good Captain's speech since $captain had function-scope. + # This will output Sir Terry's wisdom. echo $gnu - # Will output Sir Terry's wisdom. end When a function calls another, local variables aren't visible:: @@ -1122,7 +1224,8 @@ If you want to override a variable for a single command, you can use "var=val" s Unlike other shells, fish will first set the variable and then perform other expansions on the line, so:: set foo banana - foo=gagaga echo $foo # prints gagaga, while in other shells it might print "banana" + foo=gagaga echo $foo + # prints gagaga, while in other shells it might print "banana" Multiple elements can be given in a :ref:`brace expansion`:: @@ -1299,10 +1402,14 @@ That covers the positional arguments, but commandline tools often get various op A more robust approach to option handling is :doc:`argparse `, which checks the defined options and puts them into various variables, leaving only the positional arguments in $argv. Here's a simple example:: function mybetterfunction - # We tell argparse about -h/--help and -s/--second - these are short and long forms of the same option. - # The "--" here is mandatory, it tells it from where to read the arguments. + # We tell argparse about -h/--help and -s/--second + # - these are short and long forms of the same option. + # The "--" here is mandatory, + # it tells it from where to read the arguments. argparse h/help s/second -- $argv - # exit if argparse failed because it found an option it didn't recognize - it will print an error + # exit if argparse failed because + # it found an option it didn't recognize + # - it will print an error or return # If -h or --help is given, we print a little help text and return @@ -1741,7 +1848,8 @@ Let's make up an example. This function will :ref:`glob ` the f # If there are more than 5 files if test (count $files) -gt 5 - # and both stdin (for reading input) and stdout (for writing the prompt) + # and both stdin (for reading input) + # and stdout (for writing the prompt) # are terminals and isatty stdin and isatty stdout @@ -1882,7 +1990,7 @@ To specify a signal handler for the WINCH signal, write:: echo Got WINCH signal! end -Fish already the following named events for the ``--on-event`` switch: +Fish already has the following named events for the ``--on-event`` switch: - ``fish_prompt`` is emitted whenever a new fish prompt is about to be displayed. @@ -1927,4 +2035,24 @@ To start a debug session simply insert the :doc:`builtin command ` function. -If you specifically want to debug performance issues, :program:`fish` can be run with the ``--profile /path/to/profile.log`` option to save a profile to the specified path. This profile log includes a breakdown of how long each step in the execution took. See :doc:`fish ` for more information. +Profiling fish scripts +^^^^^^^^^^^^^^^^^^^^^^ + +If you specifically want to debug performance issues, :program:`fish` can be run with the ``--profile /path/to/profile.log`` option to save a profile to the specified path. This profile log includes a breakdown of how long each step in the execution took. + +For example:: + + > fish --profile /tmp/sleep.prof -ic 'sleep 3s' + > cat /tmp/sleep.prof + Time Sum Command + 3003419 3003419 > sleep 3s + +This will show the time for each command itself in the first column, the time for the command and every subcommand (like any commands inside of a :ref:`function ` or :ref:`command substitutions `) in the second and the command itself in the third, separated with tabs. + +The time is given in microseconds. + +To see the slowest commands last, ``sort -nk2 /path/to/logfile`` is useful. + +For profiling fish's startup there is also ``--profile-startup /path/to/logfile``. + +See :doc:`fish ` for more information. diff --git a/doc_src/license.rst b/doc_src/license.rst index 5e503768f..5740b513d 100644 --- a/doc_src/license.rst +++ b/doc_src/license.rst @@ -175,3 +175,112 @@ products or services of Licensee, or any third party. 8. By copying, installing or otherwise using Python, Licensee agrees to be bound by the terms and conditions of this License Agreement. + +---- + +**License for CMake** + +The ``fish`` source code contains files from [CMake](https://cmake.org) to support the build system. +This code is distributed under the terms of a BSD-style license. Copyright 2000-2017 Kitware, Inc. +and Contributors. + +The BSD license for CMake follows. + +CMake - Cross Platform Makefile Generator +Copyright 2000-2017 Kitware, Inc. and Contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Kitware, Inc. nor the names of Contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---- + +**License for code derived from tmux** + +``fish`` contains code from [tmux](http://tmux.sourceforge.net), copyrighted by Nicholas Marriott (2007), and made available under the OpenBSD license. + +The OpenBSD license is included below. + +Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---- + +**License for UTF8** + +``fish`` also contains small amounts of code under the ISC license, namely the UTF-8 conversion functions. This code is copyright © 2007 Alexey Vatchenko \. + +The ISC license agreement follows. + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---- + +**License for flock** + +``fish`` also contains small amounts of code from NetBSD, namely the ``flock`` fallback function. This code is copyright 2001 The NetBSD Foundation, Inc., and derived from software contributed to The NetBSD Foundation by Todd Vierling. + +The NetBSD license follows. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +---- + +**MIT License** + +``fish`` includes a copy of AngularJS, which is copyright 2010-2012 Google, Inc. and licensed under the MIT License. It also includes the Dracula theme, which is copyright 2018 Dracula Team, and is licensed under the same license. + +The MIT license follows. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/doc_src/prompt.rst b/doc_src/prompt.rst new file mode 100644 index 000000000..94c806fe3 --- /dev/null +++ b/doc_src/prompt.rst @@ -0,0 +1,174 @@ +Writing your own prompt +======================= + +.. only:: builder_man + + .. warning:: + This document uses formatting to show what a prompt would look like. If you are viewing this in the man page, + you probably want to switch to looking at the html version instead. Run ``help custom-prompt`` to view it in a web browser. + +Fish ships a number of prompts that you can view with the :doc:`fish_config ` command, and many users have shared their prompts online. + +However, you can also write your own, or adjust an existing prompt. This is a good way to get used to fish's :doc:`scripting language `. + +Unlike other shells, fish's prompt is built by running a function - :doc:`fish_prompt `. Or, more specifically, three functions: + +- :doc:`fish_prompt `, which is the main prompt function +- :doc:`fish_right_prompt `, which is shown on the right side of the terminal. +- :doc:`fish_mode_prompt `, which is shown if :ref:`vi-mode ` is used. + +These functions are run, and whatever they print is displayed as the prompt (minus one trailing newline). + +Here, we will just be writing a simple fish_prompt. + +Our first prompt +---------------- + +Let's look at a very simple example:: + + function fish_prompt + echo $PWD '>' + end + +This prints the current working directory (:envvar:`PWD`) and a ``>`` symbol to show where the prompt ends. The ``>`` is :ref:`quoted ` because otherwise it would signify a :ref:`redirection `. + +Because we've used :doc:`echo `, it adds spaces between the two so it ends up looking like (assuming ``_`` is your cursor): + +.. role:: white +.. parsed-literal:: + :class: highlight + + :white:`/home/tutorial >`\ _ + +Formatting +---------- + +``echo`` adds spaces between its arguments. If you don't want those, you can use :doc:`string join ` like this:: + + function fish_prompt + string join '' -- $PWD '>' + end + +The ``--`` indicates to ``string`` that no options can come after it, in case we extend this with something that can start with a ``-``. + +There are other ways to remove the space, including ``echo -s`` and :doc:`printf `. + +Adding color +------------ + +This prompt is functional, but a bit boring. We could add some color. + +Fortunately, fish offers the :doc:`set_color ` command, so you can do:: + + echo (set_color red)foo + +``set_color`` can also handle RGB colors like ``set_color 23b455``, and other formatting options including bold and italics. + +So, taking our previous prompt and adding some color:: + + function fish_prompt + string join '' -- (set_color green) $PWD (set_color normal) '>' + end + +A "normal" color tells the terminal to go back to its normal formatting options. + +``set_color`` works by producing an escape sequence, which is a special piece of text that terminals +interpret as instructions - for example, to change color. So ``set_color red`` produces the same +effect as:: + + echo \e\[31mfoo + +Although you can write your own escape sequences by hand, it's much easier to use ``set_color``. + +Shortening the working directory +-------------------------------- + +This is fine, but our :envvar:`PWD` can be a bit long, and we are typically only interested in the last few directories. We can shorten this with the :doc:`prompt_pwd ` helper that will give us a shortened working directory:: + + function fish_prompt + string join '' -- (set_color green) (prompt_pwd) (set_color normal) '>' + end + +``prompt_pwd`` takes options to control how much to shorten. For instance, if we want to display the last two directories, we'd use ``prompt_pwd --full-length-dirs 2``:: + + function fish_prompt + string join '' -- (set_color green) (prompt_pwd --full-length-dirs 2) (set_color normal) '>' + end + +With a current directory of "/home/tutorial/Music/Lena Raine/Oneknowing", this would print + +.. role:: green +.. parsed-literal:: + :class: highlight + + :green:`~/M/Lena Raine/Oneknowing`>_ + +Status +------ + +One important bit of information that every command returns is the :ref:`status `. This is a whole number from 0 to 255, and usually it is used as an error code - 0 if the command returned successfully, or a number from 1 to 255 if not. + +It's useful to display this in your prompt, but showing it when it's 0 seems kind of wasteful. + +First of all, since every command (except for :doc:`set `) changes the status, you need to store it for later use as the first thing in your prompt. Use a :ref:`local variable ` so it will be confined to your prompt function:: + + set -l last_status $status + +And after that, you can set a string if it not zero:: + + # Prompt status only if it's not 0 + set -l stat + if test $last_status -ne 0 + set stat (set_color red)"[$last_status]"(set_color normal) + end + +And to print it, we add it to our ``string join``:: + + string join '' -- (set_color green) (prompt_pwd) (set_color normal) $stat '>' + +If ``$last_status`` was 0, ``$stat`` is empty, and so it will simply disappear. + +So our entire prompt is now:: + + function fish_prompt + set -l last_status $status + # Prompt status only if it's not 0 + set -l stat + if test $last_status -ne 0 + set stat (set_color red)"[$last_status]"(set_color normal) + end + + string join '' -- (set_color green) (prompt_pwd) (set_color normal) $stat '>' + end + +And it looks like: + +.. role:: green +.. role:: red +.. parsed-literal:: + :class: highlight + + :green:`~/M/L/Oneknowing`\ :red:`[1]`>_ + +after we run ``false`` (which returns 1). + +Where to go from here? +---------------------- + +We have now built a simple but working and usable prompt, but of course more can be done. + +- Fish offers more helper functions: + - ``prompt_login`` to describe the user/hostname/container or ``prompt_hostname`` to describe just the host + - ``fish_is_root_user`` to help with changing the symbol for root. + - ``fish_vcs_prompt`` to show version control information (or ``fish_git_prompt`` / ``fish_hg_prompt`` / ``fish_svn_prompt`` to limit it to specific systems) +- You can add a right prompt by changing :doc:`fish_right_prompt ` or a vi-mode prompt by changing :doc:`fish_mode_prompt `. +- Some prompts have interesting or advanced features + - Add the time when the prompt was printed + - Show various integrations like python's venv + - Color the parts differently. + +You can look at fish's sample prompts for inspiration. Open up :doc:`fish_config `, find one you like and pick it. For example:: + + fish_config prompt show # <- shows all the sample prompts + fish_config prompt choose disco # <- this picks the "disco" prompt for this session + funced fish_prompt # <- opens fish_prompt in your editor, and reloads it once the editor exits diff --git a/doc_src/python_docs_theme/layout.html b/doc_src/python_docs_theme/layout.html index 213faa6bc..518e71549 100644 --- a/doc_src/python_docs_theme/layout.html +++ b/doc_src/python_docs_theme/layout.html @@ -14,7 +14,7 @@ {%- macro searchbox() %} {# modified from sphinx/themes/basic/searchbox.html #} {%- if builder != "htmlhelp" %} -