diff --git a/.githooks/pre-commit b/.githooks/pre-commit index 600b2cab..6da0ea99 100755 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -2,6 +2,4 @@ set -xeuo pipefail cargo fmt --check --all cargo clippy --all-targets --features test-utils -cargo +stable check --no-default-features -cargo +stable check --no-default-features --features cli -cargo check --no-default-features --features nightly-frizbee +cargo check --no-default-features diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 73b901c4..3f356114 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -113,11 +113,4 @@ jobs: uses: Swatinem/rust-cache@v2 - name: Build without any feature run: | - cargo +stable build --no-default-features - - name: Build with cli feature - run: | - cargo +stable build --no-default-features --features cli - - name: Build with frizbee feature - # Do not use +nightly to make sure we use the correct toolchain date - run: | - cargo build --no-default-features --features nightly-frizbee + cargo build --no-default-features diff --git a/Cargo.lock b/Cargo.lock index 41888f18..197a4395 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -903,12 +903,12 @@ checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] name = "frizbee" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d024031f1a5bc5f19917baa0b618f1067610e35ba23e9f105653fcb27e74f5c" +checksum = "e18c9ce192254be384afc9266228d57adf987a893a0dd61d049b1fca489c2e61" dependencies = [ - "multiversion", - "rayon", + "itertools 0.14.0", + "raw-cpuid", ] [[package]] @@ -1375,28 +1375,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "multiversion" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edb7f0ff51249dfda9ab96b5823695e15a052dc15074c9dbf3d118afaf2c201" -dependencies = [ - "multiversion-macros", - "target-features", -] - -[[package]] -name = "multiversion-macros" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b093064383341eb3271f42e381cb8f10a01459478446953953c75d24bd339fc0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.116", - "target-features", -] - [[package]] name = "nix" version = "0.28.0" @@ -1896,6 +1874,15 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "raw-cpuid" +version = "11.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" +dependencies = [ + "bitflags 2.11.0", +] + [[package]] name = "rayon" version = "1.11.0" @@ -2324,12 +2311,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "target-features" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1bbb9f3c5c463a01705937a24fdabc5047929ac764b2d5b9cf681c1f5041ed5" - [[package]] name = "tempfile" version = "3.25.0" diff --git a/Cargo.toml b/Cargo.toml index 589cdd20..d710bd34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,7 +62,7 @@ clap_complete_nushell = "4.5.10" interprocess = { version = "2.3.1", features = ["tokio"] } serde = { version = "1.0.228", features = ["derive"] } ron = "0.12.0" -frizbee = { version = "0.7.0", optional = true } +frizbee = { version = "0.8.0" } roff = "1.0.0" unicode-display-width = "0.3.0" unicode-normalization = "0.1.25" @@ -72,11 +72,9 @@ tui-term = "0.3.1" kanal = "0.1.1" [features] -default = ["cli", "nightly-frizbee"] +default = ["cli"] # Everyting needed to use skim as a cli (argument parsing, shell integrations...) cli = ["dep:clap", "dep:clap_complete", "dep:shlex", "dep:env_logger", "dep:clap_mangen"] -# The frizbee matcher, which requires cargo nightly -nightly-frizbee = ["dep:frizbee"] # Enable test utilities (e.g., Tui::new_for_test) test-utils = [] diff --git a/README.md b/README.md index d9a2c7f2..52b43e6a 100644 --- a/README.md +++ b/README.md @@ -102,9 +102,7 @@ Any of the following applies: $ curl --proto '=https' --tlsv1.2 -LsSf https://github.com/skim-rs/skim/releases/latest/download/skim-installer.sh | sh ``` - Using Binary: Simply [download the sk executable](https://github.com/skim-rs/skim/releases) directly. -- Install from [crates.io](https://crates.io/): - - For the frizbee typo-resistant matcher, we need nightly rust: `cargo +nightly-2026-02-11 install skim` (run `rustup toolchain install nightly-2026-02-11` if needed) - - Otherwise, use `cargo install skim --no-default-features --features cli` +- Install from [crates.io](https://crates.io/): `cargo install skim` - Build Manually: ```sh $ git clone --depth 1 git@github.com:skim-rs/skim.git ~/.skim @@ -521,7 +519,6 @@ skim = { version = "", default-features = false, features = [..] } _Note on features_: - the `cli` feature is required to use skim as a cli, it *should* not be needed when using it as a library. - - the `nightly-frizbee` feature adds the frizbee algorithm, but requires cargo nigthly. ### Basic usage diff --git a/man/man1/sk.1 b/man/man1/sk.1 index 6823b101..fcb157b5 100644 --- a/man/man1/sk.1 +++ b/man/man1/sk.1 @@ -8,7 +8,7 @@ sk \- Fuzzy Finder in rust! .ie \n(.g .ds Aq \(aq .el .ds Aq ' .SH SYNOPSIS -\fBsk\fR [\fB\-\-tac\fR] [\fB\-\-min\-query\-length\fR] [\fB\-\-no\-sort\fR] [\fB\-t\fR|\fB\-\-tiebreak\fR] [\fB\-n\fR|\fB\-\-nth\fR] [\fB\-\-with\-nth\fR] [\fB\-d\fR|\fB\-\-delimiter\fR] [\fB\-e\fR|\fB\-\-exact\fR] [\fB\-\-regex\fR] [\fB\-\-algo\fR] [\fB\-\-case\fR] [\fB\-\-normalize\fR] [\fB\-\-split\-match\fR] [\fB\-b\fR|\fB\-\-bind\fR] [\fB\-m\fR|\fB\-\-multi\fR] [\fB\-\-no\-multi\fR] [\fB\-\-no\-mouse\fR] [\fB\-c\fR|\fB\-\-cmd\fR] [\fB\-i\fR|\fB\-\-interactive\fR] [\fB\-I \fR] [\fB\-\-color\fR] [\fB\-\-no\-hscroll\fR] [\fB\-\-keep\-right\fR] [\fB\-\-skip\-to\-pattern\fR] [\fB\-\-no\-clear\-if\-empty\fR] [\fB\-\-no\-clear\-start\fR] [\fB\-\-no\-clear\fR] [\fB\-\-show\-cmd\-error\fR] [\fB\-\-cycle\fR] [\fB\-\-disabled\fR] [\fB\-\-layout\fR] [\fB\-\-reverse\fR] [\fB\-\-height\fR] [\fB\-\-no\-height\fR] [\fB\-\-min\-height\fR] [\fB\-\-margin\fR] [\fB\-p\fR|\fB\-\-prompt\fR] [\fB\-\-cmd\-prompt\fR] [\fB\-\-selector\fR] [\fB\-\-multi\-selector\fR] [\fB\-\-ansi\fR] [\fB\-\-tabstop\fR] [\fB\-\-info\fR] [\fB\-\-no\-info\fR] [\fB\-\-inline\-info\fR] [\fB\-\-header\fR] [\fB\-\-header\-lines\fR] [\fB\-\-border\fR] [\fB\-\-wrap\fR] [\fB\-\-history\fR] [\fB\-\-history\-size\fR] [\fB\-\-cmd\-history\fR] [\fB\-\-cmd\-history\-size\fR] [\fB\-\-preview\fR] [\fB\-\-preview\-window\fR] [\fB\-q\fR|\fB\-\-query\fR] [\fB\-\-cmd\-query\fR] [\fB\-\-read0\fR] [\fB\-\-print0\fR] [\fB\-\-print\-query\fR] [\fB\-\-print\-cmd\fR] [\fB\-\-print\-score\fR] [\fB\-\-print\-header\fR] [\fB\-\-no\-strip\-ansi\fR] [\fB\-1\fR|\fB\-\-select\-1\fR] [\fB\-0\fR|\fB\-\-exit\-0\fR] [\fB\-\-sync\fR] [\fB\-\-pre\-select\-n\fR] [\fB\-\-pre\-select\-pat\fR] [\fB\-\-pre\-select\-items\fR] [\fB\-\-pre\-select\-file\fR] [\fB\-f\fR|\fB\-\-filter\fR] [\fB\-\-shell\fR] [\fB\-\-shell\-bindings\fR] [\fB\-\-man\fR] [\fB\-\-listen\fR] [\fB\-\-remote\fR] [\fB\-\-tmux\fR] [\fB\-\-log\-file\fR] [\fB\-\-expect\fR] [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] +\fBsk\fR [\fB\-\-tac\fR] [\fB\-\-min\-query\-length\fR] [\fB\-\-no\-sort\fR] [\fB\-t\fR|\fB\-\-tiebreak\fR] [\fB\-n\fR|\fB\-\-nth\fR] [\fB\-\-with\-nth\fR] [\fB\-d\fR|\fB\-\-delimiter\fR] [\fB\-e\fR|\fB\-\-exact\fR] [\fB\-\-regex\fR] [\fB\-\-algo\fR] [\fB\-\-case\fR] [\fB\-\-normalize\fR] [\fB\-\-split\-match\fR] [\fB\-b\fR|\fB\-\-bind\fR] [\fB\-m\fR|\fB\-\-multi\fR] [\fB\-\-no\-multi\fR] [\fB\-\-no\-mouse\fR] [\fB\-c\fR|\fB\-\-cmd\fR] [\fB\-i\fR|\fB\-\-interactive\fR] [\fB\-I \fR] [\fB\-\-color\fR] [\fB\-\-no\-hscroll\fR] [\fB\-\-keep\-right\fR] [\fB\-\-skip\-to\-pattern\fR] [\fB\-\-no\-clear\-if\-empty\fR] [\fB\-\-no\-clear\-start\fR] [\fB\-\-no\-clear\fR] [\fB\-\-show\-cmd\-error\fR] [\fB\-\-cycle\fR] [\fB\-\-disabled\fR] [\fB\-\-layout\fR] [\fB\-\-reverse\fR] [\fB\-\-height\fR] [\fB\-\-no\-height\fR] [\fB\-\-min\-height\fR] [\fB\-\-margin\fR] [\fB\-p\fR|\fB\-\-prompt\fR] [\fB\-\-cmd\-prompt\fR] [\fB\-\-selector\fR] [\fB\-\-multi\-selector\fR] [\fB\-\-ansi\fR] [\fB\-\-tabstop\fR] [\fB\-\-info\fR] [\fB\-\-no\-info\fR] [\fB\-\-inline\-info\fR] [\fB\-\-header\fR] [\fB\-\-header\-lines\fR] [\fB\-\-border\fR] [\fB\-\-wrap\fR] [\fB\-\-history\fR] [\fB\-\-history\-size\fR] [\fB\-\-cmd\-history\fR] [\fB\-\-cmd\-history\-size\fR] [\fB\-\-preview\fR] [\fB\-\-preview\-window\fR] [\fB\-q\fR|\fB\-\-query\fR] [\fB\-\-cmd\-query\fR] [\fB\-\-read0\fR] [\fB\-\-print0\fR] [\fB\-\-print\-query\fR] [\fB\-\-print\-cmd\fR] [\fB\-\-print\-score\fR] [\fB\-\-print\-header\fR] [\fB\-\-print\-current\fR] [\fB\-\-output\-format\fR] [\fB\-\-no\-strip\-ansi\fR] [\fB\-1\fR|\fB\-\-select\-1\fR] [\fB\-0\fR|\fB\-\-exit\-0\fR] [\fB\-\-sync\fR] [\fB\-\-pre\-select\-n\fR] [\fB\-\-pre\-select\-pat\fR] [\fB\-\-pre\-select\-items\fR] [\fB\-\-pre\-select\-file\fR] [\fB\-f\fR|\fB\-\-filter\fR] [\fB\-\-shell\fR] [\fB\-\-shell\-bindings\fR] [\fB\-\-man\fR] [\fB\-\-listen\fR] [\fB\-\-remote\fR] [\fB\-\-tmux\fR] [\fB\-\-log\-file\fR] [\fB\-\-expect\fR] [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] .ie \n(.g .ds Aq \(aq .el .ds Aq ' .SH OPTIONS @@ -455,6 +455,12 @@ Print the score after each item \fB\-\-print\-header\fR Print the header as the first line (after print\-score) .TP +\fB\-\-print\-current\fR +Print the current (highlighted) item as the first line (after print\-header) +.TP +\fB\-\-output\-format\fR \fI\fR +Set the output format If set, overrides all print_ options Will be expanded the same way as preview or commands +.TP \fB\-\-no\-strip\-ansi\fR Print the ANSI codes, making the output exactly match the input even when \-\-ansi is on .TP diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 71ef4021..555d0cdd 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2026-02-11" +channel = "stable" profile = "default" components = ["rust-analyzer"] diff --git a/shell/completion.bash b/shell/completion.bash index 41569b7b..b168ee7b 100644 --- a/shell/completion.bash +++ b/shell/completion.bash @@ -23,7 +23,7 @@ _sk() { case "${cmd}" in sk) - opts="-t -n -d -e -b -m -c -i -I -p -q -1 -0 -f -x -h -V --tac --min-query-length --no-sort --tiebreak --nth --with-nth --delimiter --exact --regex --algo --case --normalize --split-match --bind --multi --no-multi --no-mouse --cmd --interactive --color --no-hscroll --keep-right --skip-to-pattern --no-clear-if-empty --no-clear-start --no-clear --show-cmd-error --cycle --disabled --layout --reverse --height --no-height --min-height --margin --prompt --cmd-prompt --selector --multi-selector --ansi --tabstop --info --no-info --inline-info --header --header-lines --border --wrap --history --history-size --cmd-history --cmd-history-size --preview --preview-window --query --cmd-query --read0 --print0 --print-query --print-cmd --print-score --print-header --no-strip-ansi --select-1 --exit-0 --sync --pre-select-n --pre-select-pat --pre-select-items --pre-select-file --filter --shell --shell-bindings --man --listen --remote --tmux --log-file --flags --extended --literal --hscroll-off --filepath-word --jump-labels --no-bold --phony --scheme --tail --style --no-color --padding --border-label --border-label-pos --highlight-line --wrap-sign --no-multi-line --raw --track --gap --gap-line --freeze-left --freeze-right --scroll-off --gutter --gutter-raw --marker-multi-line --ellipsis --scrollbar --no-scrollbar --list-border --list-label --list-label-pos --no-input --info-command --separator --no-separator --ghost --input-border --input-label --input-label-pos --preview-label --preview-label-pos --header-first --header-border --header-lines-border --footer --footer-border --footer-label --footer-label-pos --with-shell --expect --help --version" + opts="-t -n -d -e -b -m -c -i -I -p -q -1 -0 -f -x -h -V --tac --min-query-length --no-sort --tiebreak --nth --with-nth --delimiter --exact --regex --algo --case --normalize --split-match --bind --multi --no-multi --no-mouse --cmd --interactive --color --no-hscroll --keep-right --skip-to-pattern --no-clear-if-empty --no-clear-start --no-clear --show-cmd-error --cycle --disabled --layout --reverse --height --no-height --min-height --margin --prompt --cmd-prompt --selector --multi-selector --ansi --tabstop --ellipsis --info --no-info --inline-info --header --header-lines --border --wrap --history --history-size --cmd-history --cmd-history-size --preview --preview-window --query --cmd-query --read0 --print0 --print-query --print-cmd --print-score --print-header --print-current --output-format --no-strip-ansi --select-1 --exit-0 --sync --pre-select-n --pre-select-pat --pre-select-items --pre-select-file --filter --shell --shell-bindings --man --listen --remote --tmux --log-file --flags --extended --literal --hscroll-off --filepath-word --jump-labels --no-bold --phony --scheme --tail --style --no-color --padding --border-label --border-label-pos --highlight-line --wrap-sign --no-multi-line --raw --track --gap --gap-line --freeze-left --freeze-right --scroll-off --gutter --gutter-raw --marker-multi-line --scrollbar --no-scrollbar --list-border --list-label --list-label-pos --no-input --info-command --separator --no-separator --ghost --input-border --input-label --input-label-pos --preview-label --preview-label-pos --header-first --header-border --header-lines-border --footer --footer-border --footer-label --footer-label-pos --with-shell --expect --help --version" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -141,6 +141,10 @@ _sk() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --ellipsis) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --info) COMPREPLY=($(compgen -W "default inline hidden" -- "${cur}")) return 0 @@ -193,6 +197,10 @@ _sk() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --output-format) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --pre-select-n) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -309,10 +317,6 @@ _sk() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --ellipsis) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --scrollbar) COMPREPLY=($(compgen -f "${cur}")) return 0 diff --git a/shell/completion.fish b/shell/completion.fish index eb558ed4..ccf9e24f 100644 --- a/shell/completion.fish +++ b/shell/completion.fish @@ -36,6 +36,7 @@ complete -c sk -l cmd-prompt -d 'Set prompt in command mode' -r complete -c sk -l selector -d 'Set selected item icon' -r complete -c sk -l multi-selector -d 'Set selected item icon' -r complete -c sk -l tabstop -d 'Number of spaces that make up a tab' -r +complete -c sk -l ellipsis -d 'The characters used to display truncated lines' -r complete -c sk -l info -d 'Set matching result count display position' -r -f -a "default\t'' inline\t'' hidden\t''" @@ -61,6 +62,7 @@ complete -c sk -l preview -d 'Preview command' -r complete -c sk -l preview-window -d 'Preview window layout' -r complete -c sk -s q -l query -d 'Initial query' -r complete -c sk -l cmd-query -d 'Initial query in interactive mode' -r +complete -c sk -l output-format -d 'Set the output format If set, overrides all print_ options Will be expanded the same way as preview or commands' -r complete -c sk -l pre-select-n -d 'Pre-select the first n items in multi-selection mode' -r complete -c sk -l pre-select-pat -d 'Pre-select the matched items in multi-selection mode' -r complete -c sk -l pre-select-items -d 'Pre-select the items separated by newline character' -r @@ -94,7 +96,6 @@ complete -c sk -l scroll-off -r complete -c sk -l gutter -r complete -c sk -l gutter-raw -r complete -c sk -l marker-multi-line -r -complete -c sk -l ellipsis -r complete -c sk -l scrollbar -r complete -c sk -l list-border -r complete -c sk -l list-label -r @@ -144,6 +145,7 @@ complete -c sk -l print-query -d 'Print the query as the first line' complete -c sk -l print-cmd -d 'Print the command as the first line (after print-query)' complete -c sk -l print-score -d 'Print the score after each item' complete -c sk -l print-header -d 'Print the header as the first line (after print-score)' +complete -c sk -l print-current -d 'Print the current (highlighted) item as the first line (after print-header)' complete -c sk -l no-strip-ansi -d 'Print the ANSI codes, making the output exactly match the input even when --ansi is on' complete -c sk -s 1 -l select-1 -d 'Do not enter the TUI if the query passed in -q matches only one item and return it' complete -c sk -s 0 -l exit-0 -d 'Do not enter the TUI if the query passed in -q does not match any item' diff --git a/shell/completion.nu b/shell/completion.nu index 1e52827e..af626e74 100644 --- a/shell/completion.nu +++ b/shell/completion.nu @@ -76,6 +76,7 @@ module completions { --multi-selector: string # Set selected item icon --ansi # Parse ANSI color codes in input strings --tabstop: string # Number of spaces that make up a tab + --ellipsis: string # The characters used to display truncated lines --info: string@"nu-complete sk info" # Set matching result count display position --no-info # Alias for --info=hidden --inline-info # Alias for --info=inline @@ -97,6 +98,8 @@ module completions { --print-cmd # Print the command as the first line (after print-query) --print-score # Print the score after each item --print-header # Print the header as the first line (after print-score) + --print-current # Print the current (highlighted) item as the first line (after print-header) + --output-format: string # Set the output format If set, overrides all print_ options Will be expanded the same way as preview or commands --no-strip-ansi # Print the ANSI codes, making the output exactly match the input even when --ansi is on --select-1(-1) # Do not enter the TUI if the query passed in -q matches only one item and return it --exit-0(-0) # Do not enter the TUI if the query passed in -q does not match any item @@ -141,7 +144,6 @@ module completions { --gutter: string --gutter-raw: string --marker-multi-line: string - --ellipsis: string --scrollbar: string --no-scrollbar --list-border: string diff --git a/shell/completion.zsh b/shell/completion.zsh index 611cbf84..2ff1f36f 100644 --- a/shell/completion.zsh +++ b/shell/completion.zsh @@ -50,6 +50,7 @@ reverse-list\:"Display from the top of the screen, prompt at the bottom"))' \ '--selector=[Set selected item icon]:SELECTOR_ICON:_default' \ '--multi-selector=[Set selected item icon]:MULTI_SELECT_ICON:_default' \ '--tabstop=[Number of spaces that make up a tab]:TABSTOP:_default' \ +'--ellipsis=[The characters used to display truncated lines]:ELLIPSIS:_default' \ '--info=[Set matching result count display position]:INFO:(default inline hidden)' \ '--header=[Set header, displayed next to the info]:HEADER:_default' \ '--header-lines=[Number of lines of the input treated as header]:HEADER_LINES:_default' \ @@ -63,6 +64,7 @@ reverse-list\:"Display from the top of the screen, prompt at the bottom"))' \ '-q+[Initial query]:QUERY:_default' \ '--query=[Initial query]:QUERY:_default' \ '--cmd-query=[Initial query in interactive mode]:CMD_QUERY:_default' \ +'--output-format=[Set the output format If set, overrides all print_ options Will be expanded the same way as preview or commands]:OUTPUT_FORMAT:_default' \ '--pre-select-n=[Pre-select the first n items in multi-selection mode]:PRE_SELECT_N:_default' \ '--pre-select-pat=[Pre-select the matched items in multi-selection mode]:PRE_SELECT_PAT:_default' \ '--pre-select-items=[Pre-select the items separated by newline character]:PRE_SELECT_ITEMS:_default' \ @@ -97,7 +99,6 @@ zsh\:"Zsh"))' \ '--gutter=[]:GUTTER:_default' \ '--gutter-raw=[]:GUTTER_RAW:_default' \ '--marker-multi-line=[]:MARKER_MULTI_LINE:_default' \ -'--ellipsis=[]:ELLIPSIS:_default' \ '--scrollbar=[]:SCROLLBAR:_default' \ '--list-border=[]:LIST_BORDER:_default' \ '--list-label=[]:LIST_LABEL:_default' \ @@ -150,6 +151,7 @@ zsh\:"Zsh"))' \ '--print-cmd[Print the command as the first line (after print-query)]' \ '--print-score[Print the score after each item]' \ '--print-header[Print the header as the first line (after print-score)]' \ +'--print-current[Print the current (highlighted) item as the first line (after print-header)]' \ '--no-strip-ansi[Print the ANSI codes, making the output exactly match the input even when --ansi is on]' \ '-1[Do not enter the TUI if the query passed in -q matches only one item and return it]' \ '--select-1[Do not enter the TUI if the query passed in -q matches only one item and return it]' \ diff --git a/src/binds.rs b/src/binds.rs index 5136811a..f31f19f3 100644 --- a/src/binds.rs +++ b/src/binds.rs @@ -235,7 +235,6 @@ pub fn parse_keymap(key_action: &str) -> Result<(&str, Vec)> { } #[cfg(test)] -#[cfg_attr(coverage, coverage(off))] mod tests { use super::*; use event::Action::*; diff --git a/src/completions.rs b/src/completions.rs index c2022a18..57869c71 100644 --- a/src/completions.rs +++ b/src/completions.rs @@ -1,4 +1,3 @@ -#![cfg_attr(coverage, coverage(off))] //! Provides helpers to easily generate shell completions use clap::CommandFactory; diff --git a/src/engine/factory.rs b/src/engine/factory.rs index f855a342..6453553f 100644 --- a/src/engine/factory.rs +++ b/src/engine/factory.rs @@ -226,7 +226,6 @@ impl MatchEngineFactory for RegexEngineFactory { } #[cfg(test)] -#[cfg_attr(coverage, coverage(off))] mod test { #[test] fn test_engine_factory() { diff --git a/src/engine/fuzzy.rs b/src/engine/fuzzy.rs index 2526f02f..c3f1cbf9 100644 --- a/src/engine/fuzzy.rs +++ b/src/engine/fuzzy.rs @@ -2,7 +2,6 @@ use std::cmp::min; use std::fmt::{Display, Error, Formatter}; use std::sync::Arc; -#[cfg(feature = "nightly-frizbee")] use crate::fuzzy_matcher::frizbee::FrizbeeMatcher; use crate::fuzzy_matcher::{FuzzyMatcher, IndexType, ScoreType, clangd::ClangdMatcher, skim::SkimMatcherV2}; @@ -66,11 +65,6 @@ impl FuzzyEngineBuilder { use crate::fuzzy_matcher::skim::SkimMatcher; #[allow(unused_mut)] let mut algorithm = self.algorithm; - #[cfg(not(feature = "nightly-frizbee"))] - if algorithm == FuzzyAlgorithm::Frizbee { - warn!("Frizbee algorithm not enabled, using SkimV2"); - algorithm = FuzzyAlgorithm::SkimV2; - } let matcher: Box = match algorithm { FuzzyAlgorithm::SkimV1 => { debug!("Initialized SkimV1 algorithm"); @@ -96,12 +90,7 @@ impl FuzzyEngineBuilder { debug!("Initialized Clangd algorithm"); Box::new(matcher) } - FuzzyAlgorithm::Frizbee => { - #[cfg(not(feature = "nightly-frizbee"))] - unreachable!(); - #[cfg(feature = "nightly-frizbee")] - Box::new(FrizbeeMatcher::default()) - } + FuzzyAlgorithm::Frizbee => Box::new(FrizbeeMatcher { case: self.case }), }; FuzzyEngine { diff --git a/src/field.rs b/src/field.rs index af4a00fd..96e4f507 100644 --- a/src/field.rs +++ b/src/field.rs @@ -179,7 +179,6 @@ pub fn parse_transform_fields(delimiter: &Regex, text: &str, fields: &[FieldRang } #[cfg(test)] -#[cfg_attr(coverage, coverage(off))] mod test { use super::FieldRange::*; #[test] diff --git a/src/fuzzy_matcher/clangd.rs b/src/fuzzy_matcher/clangd.rs index 01315b16..59754ddd 100644 --- a/src/fuzzy_matcher/clangd.rs +++ b/src/fuzzy_matcher/clangd.rs @@ -452,7 +452,6 @@ fn print_dp(line: &str, pattern: &str, dp: &[Vec]) { } #[cfg(test)] -#[cfg_attr(coverage, coverage(off))] mod tests { use super::*; use crate::fuzzy_matcher::util::{assert_order, wrap_matches}; diff --git a/src/fuzzy_matcher/frizbee.rs b/src/fuzzy_matcher/frizbee.rs index 6b85e507..4085b693 100644 --- a/src/fuzzy_matcher/frizbee.rs +++ b/src/fuzzy_matcher/frizbee.rs @@ -1,37 +1,57 @@ //! Matcher using https://crates.io/crates/frizbee -use frizbee::{Config, Scoring, match_indices}; +use frizbee::{Scoring, smith_waterman::simd::SmithWatermanMatcher}; -use crate::fuzzy_matcher::{FuzzyMatcher, IndexType, ScoreType}; +use crate::{ + CaseMatching, + fuzzy_matcher::{FuzzyMatcher, IndexType, ScoreType}, +}; + +const RESPECT_CASE_BONUS: u16 = 10000; /// Matcher using frizbee, /// the same one that `blink.cmp` uses in neovim /// credits to @saghen #[derive(Default)] -pub struct FrizbeeMatcher {} - -fn adaptive(pattern: &str) -> Config { - Config { - max_typos: Some(pattern.chars().count().saturating_div(4).try_into().unwrap()), - prefilter: true, - sort: false, - scoring: Scoring::default(), - } +pub struct FrizbeeMatcher { + /// The case for matching + /// Will be translated into a matching_case_bonus + pub case: CaseMatching, } impl FuzzyMatcher for FrizbeeMatcher { fn fuzzy_indices(&self, choice: &str, pattern: &str) -> Option<(ScoreType, Vec)> { - let matches = match_indices(pattern, choice, &adaptive(pattern))?; - - let mut indices = Vec::new(); - for matched_idx in matches.indices { - for (char_idx, (byte_idx, _)) in choice.char_indices().enumerate() { - if byte_idx == matched_idx { - indices.push(char_idx); - break; + let max_typos: u16 = pattern.chars().count().saturating_div(4).try_into().unwrap(); + let scoring = Scoring { + matching_case_bonus: match self.case { + CaseMatching::Respect => RESPECT_CASE_BONUS, + CaseMatching::Ignore => 0, + CaseMatching::Smart => { + if pattern.chars().any(|c| c.is_uppercase()) { + RESPECT_CASE_BONUS + } else { + 0 + } } - } - } - - Some((matches.score.into(), indices)) + }, + ..Default::default() + }; + let mut matcher = SmithWatermanMatcher::new(pattern.as_bytes(), &scoring); + matcher + .match_haystack_indices(choice.as_bytes(), 0, Some(max_typos)) + .and_then(|(m, indices)| { + debug!("{choice}: {m} ({})", scoring.matching_case_bonus); + if m > scoring.matching_case_bonus.saturating_mul( + pattern + .chars() + .count() + .saturating_sub(max_typos as usize) + .try_into() + .unwrap(), + ) { + Some((m.into(), indices)) + } else { + None + } + }) } } diff --git a/src/fuzzy_matcher/mod.rs b/src/fuzzy_matcher/mod.rs index 249931e7..50a8f298 100644 --- a/src/fuzzy_matcher/mod.rs +++ b/src/fuzzy_matcher/mod.rs @@ -5,7 +5,6 @@ /// Clangd fuzzy matching algorithm pub mod clangd; -#[cfg(feature = "nightly-frizbee")] pub mod frizbee; /// Skim fuzzy matching algorithm pub mod skim; diff --git a/src/fuzzy_matcher/skim.rs b/src/fuzzy_matcher/skim.rs index cc12825d..6081aff5 100644 --- a/src/fuzzy_matcher/skim.rs +++ b/src/fuzzy_matcher/skim.rs @@ -1043,7 +1043,6 @@ impl FuzzyMatcher for SkimMatcherV2 { } #[cfg(test)] -#[cfg_attr(coverage, coverage(off))] mod tests { use crate::fuzzy_matcher::util::{assert_order, wrap_matches}; diff --git a/src/helper/item.rs b/src/helper/item.rs index 49097d70..0c89ca58 100644 --- a/src/helper/item.rs +++ b/src/helper/item.rs @@ -537,7 +537,6 @@ fn escape_ansi(raw: &str) -> String { } #[cfg(test)] -#[cfg_attr(coverage, coverage(off))] mod test { use super::*; diff --git a/src/helper/selector.rs b/src/helper/selector.rs index b0997e03..77c633d2 100644 --- a/src/helper/selector.rs +++ b/src/helper/selector.rs @@ -67,7 +67,6 @@ impl Selector for DefaultSkimSelector { } #[cfg(test)] -#[cfg_attr(coverage, coverage(off))] mod tests { use super::*; diff --git a/src/lib.rs b/src/lib.rs index 74cee99f..315fe846 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,6 @@ //! let output = Skim::run_with(options, Some(items)).unwrap(); //! ``` #![warn(missing_docs)] -#![cfg_attr(coverage, feature(coverage_attribute))] #[macro_use] extern crate log; diff --git a/src/manpage.rs b/src/manpage.rs index 1815c2e9..77708f9e 100644 --- a/src/manpage.rs +++ b/src/manpage.rs @@ -1,4 +1,3 @@ -#![cfg_attr(coverage, coverage(off))] //! Provides what's needed to generate skim's man page use std::io::Write; diff --git a/src/spinlock.rs b/src/spinlock.rs index 2f9d25ea..a00c4737 100644 --- a/src/spinlock.rs +++ b/src/spinlock.rs @@ -85,7 +85,6 @@ impl Drop for SpinLockGuard<'_, T> { } #[cfg(test)] -#[cfg_attr(coverage, coverage(off))] mod tests { use super::*; use std::sync::Arc; diff --git a/src/theme.rs b/src/theme.rs index 7d287126..b3ce09c0 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -321,17 +321,15 @@ impl ColorTheme { let g = u8::from_str_radix(&raw_color[3..5], 16).unwrap_or(255); let b = u8::from_str_radix(&raw_color[5..7], 16).unwrap_or(255); Some(Color::Rgb(r, g, b)) + } else if raw_color == "-1" { + Some(Color::Reset) } else { - if raw_color == "-1" { - Some(Color::Reset) - } else { - raw_color.parse::().ok().map(Color::Indexed).or_else(|| { - if !raw_color.is_empty() { - debug!("Unknown color '{}'", spec_parts[0]); - } - None - }) - } + raw_color.parse::().ok().map(Color::Indexed).or_else(|| { + if !raw_color.is_empty() { + debug!("Unknown color '{}'", spec_parts[0]); + } + None + }) }; let layer_override = if component_name == "bg+" { "bg" } else { layer }; @@ -379,7 +377,6 @@ fn set_style(s: &mut Style, layer: &str, color: Option, modifier: Modifie } #[cfg(test)] -#[cfg_attr(coverage, coverage(off))] mod tests { use super::*; diff --git a/src/tmux.rs b/src/tmux.rs index d7d0dec1..024f8eca 100644 --- a/src/tmux.rs +++ b/src/tmux.rs @@ -358,7 +358,6 @@ fn sanitize_value(value: String) -> String { } #[cfg(test)] -#[cfg_attr(coverage, coverage(off))] mod tests { use super::*; diff --git a/src/tui/backend.rs b/src/tui/backend.rs index aea7e639..f0a65405 100644 --- a/src/tui/backend.rs +++ b/src/tui/backend.rs @@ -104,7 +104,6 @@ where /// raw mode, scrolling) that don't work with `TestBackend`. Use this when /// writing snapshot tests or other tests that need to render the UI. #[cfg(any(test, feature = "test-utils"))] - #[cfg_attr(coverage, coverage(off))] pub fn new_for_test(backend: B) -> Result { let event_channel = channel(1024 * 1024); Ok(Self { diff --git a/src/tui/mod.rs b/src/tui/mod.rs index baeb77c6..a85dc218 100644 --- a/src/tui/mod.rs +++ b/src/tui/mod.rs @@ -152,7 +152,6 @@ impl From for ratatui::widgets::BorderType { } #[cfg(test)] -#[cfg_attr(coverage, coverage(off))] mod size_test { use super::*; use std::num::IntErrorKind; diff --git a/src/tui/options.rs b/src/tui/options.rs index 8264fe85..31407e40 100644 --- a/src/tui/options.rs +++ b/src/tui/options.rs @@ -88,7 +88,6 @@ impl From<&str> for PreviewLayout { // } #[cfg(test)] -#[cfg_attr(coverage, coverage(off))] mod tests { use super::*; diff --git a/src/tui/util.rs b/src/tui/util.rs index 14acccae..2f077927 100644 --- a/src/tui/util.rs +++ b/src/tui/util.rs @@ -275,7 +275,6 @@ pub(crate) fn cursor_pos_from_tty() -> io::Result<(u16, u16)> { } #[cfg(test)] -#[cfg_attr(coverage, coverage(off))] mod tests { use super::*; use ansi_to_tui::IntoText as _; diff --git a/src/util.rs b/src/util.rs index 3844c633..a4e5af1f 100644 --- a/src/util.rs +++ b/src/util.rs @@ -201,15 +201,13 @@ pub fn printf( log::warn!("Failed to build multi-item field range from {content}"); replaced.push_str(&format!("{{{s}}}")); } + } else if let Some(range) = FieldRange::from_str(stripped) { + let replacement = + get_string_by_field(delimiter, &item_text, &range).unwrap_or_default(); + replaced.push_str(&escape_arg(replacement, true)); } else { - if let Some(range) = FieldRange::from_str(stripped) { - let replacement = - get_string_by_field(delimiter, &item_text, &range).unwrap_or_default(); - replaced.push_str(&escape_arg(replacement, true)); - } else { - log::warn!("Failed to build field range from {content}"); - replaced.push_str(&format!("{{{s}}}")); - } + log::warn!("Failed to build field range from {content}"); + replaced.push_str(&format!("{{{s}}}")); } } } @@ -238,7 +236,6 @@ pub fn printf( } #[cfg(test)] -#[cfg_attr(coverage, coverage(off))] mod test { use super::*; use crate::SkimItem; diff --git a/tests/snapshots/matcher__matcher_frizbee.snap b/tests/snapshots/matcher__matcher_frizbee.snap index 511f3a51..0a040f75 100644 --- a/tests/snapshots/matcher__matcher_frizbee.snap +++ b/tests/snapshots/matcher__matcher_frizbee.snap @@ -2,16 +2,15 @@ source: tests/matcher.rs expression: buf + & cursor_pos --- -" src/helper/item_reader.rs " +" src/skim_item.rs " +" src/output.rs " +" src/item.rs " " src/fuzzy_matcher/clangd.rs " " src/fuzzy_matcher/frizbee.rs " " src/fuzzy_matcher/skim.rs " " src/fuzzy_matcher/util.rs " " src/fuzzy_matcher/mod.rs " -" src/output.rs " " src/theme.rs " -" src/item.rs " -" src/tmux.rs " " src/tui/header.rs " " src/tui/statusline.rs " " src/tui/input.rs " @@ -22,6 +21,7 @@ expression: buf + & cursor_pos " src/tui/widget.rs " " src/tui/options.rs " " src/tui/util.rs " +" src/tmux.rs " " src/tui/item_list.rs " "> src/tui/mod.rs " " 24/49 0/0"