Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,6 @@ profile.json.gz
perf.data.old
perf.data
flamegraph.svg
cachegrind.out.*

/scripts/data/
69 changes: 69 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -76,20 +76,23 @@ portable-pty = "=0.9.0"
tui-term = "=0.3.2"
kanal = "=0.1.1"
mimalloc = { version = "0.1.48", features = ["v3"] }
gungraun = { version = "0.17.2", optional = true }

[features]
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"]
# Enable test utilities (e.g., Tui::new_for_test)
test-utils = []
# Enable gungraun (Valgrind-based) benchmarks
gungraun = ["dep:gungraun"]

[dev-dependencies]
criterion = { version = "0.8.2", features = ["async_tokio"] }
insta = "1.46"

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(feature, values("test-utils"))', 'cfg(coverage, coverage_nightly)'] }
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(feature, values("test-utils", "gungraun"))', 'cfg(coverage, coverage_nightly)'] }

[[bench]]
name = "read_and_match"
Expand All @@ -106,3 +109,8 @@ harness = false
[[bench]]
name = "matcher_micro"
harness = false

[[bench]]
name = "gungraun"
harness = false
required-features = ["gungraun"]
65 changes: 65 additions & 0 deletions benches/gungraun.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
use gungraun::{library_benchmark, library_benchmark_group, main};
use std::fs;
use std::hint::black_box;

use skim::CaseMatching;
use skim::fuzzy_matcher::FuzzyMatcher;
use skim::fuzzy_matcher::arinae::ArinaeMatcher;
use skim::fuzzy_matcher::frizbee::FrizbeeMatcher;
use skim::prelude::SkimMatcherV2;

fn load_lines() -> Vec<String> {
let data = fs::read_to_string("benches/fixtures/1M.txt").expect("1M.txt missing");
data.lines().map(|l| l.to_string()).collect()
}

#[inline(always)]
fn bench_matcher(m: impl FuzzyMatcher, lines: Vec<String>) -> u64 {
let mut count = 0u64;
for line in &lines {
if m.fuzzy_indices(line, "test").is_some() {
count += 1;
}
}
count
}

#[library_benchmark]
fn skim_v2() -> u64 {
bench_matcher(SkimMatcherV2::default().smart_case(), black_box(load_lines()))
}
#[library_benchmark]
fn frizbee() -> u64 {
bench_matcher(
FrizbeeMatcher::default().case(CaseMatching::Smart).max_typos(Some(0)),
black_box(load_lines()),
)
}
#[library_benchmark]
fn frizbee_typos() -> u64 {
bench_matcher(
FrizbeeMatcher::default().case(CaseMatching::Smart).max_typos(Some(1)),
black_box(load_lines()),
)
}
#[library_benchmark]
fn arinae() -> u64 {
bench_matcher(
ArinaeMatcher::new(CaseMatching::Smart, false, false),
black_box(load_lines()),
)
}
#[library_benchmark]
fn arinae_typos() -> u64 {
bench_matcher(
ArinaeMatcher::new(CaseMatching::Smart, true, false),
black_box(load_lines()),
)
}

library_benchmark_group!(
name = benches,
benchmarks = [skim_v2, frizbee, frizbee_typos, arinae, arinae_typos]
);

main!(library_benchmark_groups = benches);
9 changes: 9 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,23 @@
cargo-llvm-cov
cargo-edit
git-cliff
libclang
binutils
tmux
rustup
just
hyperfine
uv
valgrind
python313Packages.matplotlib
python313Packages.requests
];
shellHook = let
pkgs = pkgsFor.${system};
in ''
export LIBCLANG_PATH="${pkgs.libclang.lib}/lib"
export LD_LIBRARY_PATH="${pkgs.valgrind.out}/lib:$LD_LIBRARY_PATH"
'';
};
});

Expand Down
28 changes: 26 additions & 2 deletions man/man1/sk.1
Original file line number Diff line number Diff line change
Expand Up @@ -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\-\-typos\fR] [\fB\-\-no\-typos\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\-level\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\-\-typos\fR] [\fB\-\-no\-typos\fR] [\fB\-\-normalize\fR] [\fB\-\-split\-match\fR] [\fB\-\-last\-match\fR] [\fB\-\-scheme\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\-\-highlight\-line\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\-\-multiline\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\-level\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
Expand Down Expand Up @@ -45,7 +45,7 @@ Comma\-separated list of sort criteria to apply when the scores are tied.
.br

.br
[\fIpossible values: \fRscore, \-score, begin, \-begin, end, \-end, length, \-length, index, \-index]
[\fIpossible values: \fRscore, \-score, begin, \-begin, end, \-end, length, \-length, index, \-index, pathname, \-pathname]
.TP
\fB\-n\fR, \fB\-\-nth\fR \fI<NTH>\fR [default: ]
Fields to be matched
Expand Down Expand Up @@ -139,6 +139,22 @@ When set, normalize accents and other unicode diacritics/others
Enable split matching and set delimiter

Split matching runs the matcher in splits: foo:bar will match all items matching foo, then :, then bar if the delimiter is present, or match normally if not.
.TP
\fB\-\-last\-match\fR
Highlight the last match found, not the first one This makes tiebreak more pertinent on path items where we want to prioritize a match on the last parts
.TP
\fB\-\-scheme\fR \fI<SCHEME>\fR [default: default]

.br
\fIPossible values:\fR
.RS 14
.IP \(bu 2
default: Default scheme, no modifications to the options
.IP \(bu 2
path: Path scheme: will find the furthest match in the item and set pathname as the main tiebreak
.IP \(bu 2
history: History scheme: will force index as the first tiebreak
.RE
.SH INTERFACE
.TP
\fB\-b\fR, \fB\-\-bind\fR [\fI<BIND>...\fR] [default: ]
Expand Down Expand Up @@ -211,6 +227,9 @@ Set color theme
Format: [BASE][,COLOR:ANSI[:ATTR1:ATTR2:..]]
See [THEME] section for details
.TP
\fB\-\-highlight\-line\fR
Highlight the entire current line, not just the text
.TP
\fB\-\-no\-hscroll\fR
Disable horizontal scroll
.TP
Expand Down Expand Up @@ -368,6 +387,11 @@ Draw borders around the UI components
\fB\-\-wrap\fR
Wrap items in the item list
.TP
\fB\-\-multiline\fR [\fI<MULTILINE>\fR]
Split item text into multiple display lines at the given separator character defaults to \\n if read0 is set, and \\\\n if not (matching literal \\n in text)

Each item\*(Aqs text will be split on the separator and each part will be displayed as a separate line within that item\*(Aqs row.
.TP
\fB\-\-tmux\fR [\fI<TMUX>...\fR]
Run in a tmux popup

Expand Down
18 changes: 11 additions & 7 deletions shell/completion.bash
Original file line number Diff line number Diff line change
Expand Up @@ -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 --typos --no-typos --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-level --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"
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 --typos --no-typos --normalize --split-match --last-match --scheme --bind --multi --no-multi --no-mouse --cmd --interactive --color --highlight-line --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 --multiline --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-level --log-file --flags --extended --literal --hscroll-off --filepath-word --jump-labels --no-bold --phony --tail --style --no-color --padding --border-label --border-label-pos --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
Expand All @@ -34,11 +34,11 @@ _sk() {
return 0
;;
--tiebreak)
COMPREPLY=($(compgen -W "score -score begin -begin end -end length -length index -index" -- "${cur}"))
COMPREPLY=($(compgen -W "score -score begin -begin end -end length -length index -index pathname -pathname" -- "${cur}"))
return 0
;;
-t)
COMPREPLY=($(compgen -W "score -score begin -begin end -end length -length index -index" -- "${cur}"))
COMPREPLY=($(compgen -W "score -score begin -begin end -end length -length index -index pathname -pathname" -- "${cur}"))
return 0
;;
--nth)
Expand Down Expand Up @@ -77,6 +77,10 @@ _sk() {
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--scheme)
COMPREPLY=($(compgen -W "default path history" -- "${cur}"))
return 0
;;
--bind)
COMPREPLY=($(compgen -f "${cur}"))
return 0
Expand Down Expand Up @@ -165,6 +169,10 @@ _sk() {
COMPREPLY=($(compgen -W "plain rounded double thick light-double-dashed heavy-double-dashed light-triple-dashed heavy-triple-dashed light-quadruple-dashed heavy-quadruple-dashed quadrant-inside quadrant-outside" -- "${cur}"))
return 0
;;
--multiline)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--history)
COMPREPLY=($(compgen -f "${cur}"))
return 0
Expand Down Expand Up @@ -265,10 +273,6 @@ _sk() {
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--scheme)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--tail)
COMPREPLY=($(compgen -f "${cur}"))
return 0
Expand Down
Loading