Skip to content
vic

skim-rs/skim.json
{
"createdAt": "2016-05-29T06:24:46Z",
"defaultBranch": "master",
"description": "Fuzzy Finder in rust!",
"fullName": "skim-rs/skim",
"homepage": "",
"language": "Rust",
"name": "skim",
"pushedAt": "2025-11-16T14:08:15Z",
"stargazersCount": 6116,
"topics": [
"fuzzyfinder",
"rust",
"skim"
],
"updatedAt": "2025-11-26T10:59:11Z",
"url": "https://github.com/skim-rs/skim"
}

Crates.io Build & Test Packaging status Skim Discord

Life is short, skim!

We spend so much of our time navigating through files, lines, and commands. That’s where Skim comes in! It’s a powerful fuzzy finder designed to make your workflow faster and more efficient.

skim demo

Skim provides a single executable called sk. Think of it as a smarter alternative to tools like grep - once you try it, you’ll wonder how you ever lived without it!

The skim project contains several components:

  1. sk executable - the core program
  2. sk-tmux - a script for launching sk in a tmux pane
  3. Vim/Nvim plugin - to call sk inside Vim/Nvim. Check skim.vim for Vim support.
OSPackage ManagerCommand
macOSHomebrewbrew install sk
macOSMacPortssudo port install skim
Fedoradnfdnf install skim
Alpineapkapk add skim
Archpacmanpacman -S skim
GentooPortageemerge --ask app-misc/skim
Guixguixguix install skim
VoidXBPSxbps-install -S skim
Packaging status

Any of the following applies:

  • Using Git
    Terminal window
    $ git clone --depth 1 git@github.com:skim-rs/skim.git ~/.skim
    $ ~/.skim/install
  • Using Binary: Simply download the sk executable directly.
  • Install from crates.io: Run cargo install skim
  • Build Manually:
    Terminal window
    $ git clone --depth 1 git@github.com:skim-rs/skim.git ~/.skim
    $ cd ~/.skim
    $ cargo install
    $ cargo build --release
    $ # Add the resulting `target/release/sk` executable to your PATH

Skim can be used either as a general filter (similar to grep) or as an interactive interface for running commands.

Via vim-plug (recommended):

Plug 'skim-rs/skim', { 'dir': '~/.skim', 'do': './install' }

Here are some examples to get you started:

Terminal window
# directly invoke skim
sk
# Or pipe some input to it (press TAB key to select multiple items when -m is enabled)
vim $(find . -name "*.rs" | sk -m)

This last command lets you select files with the “.rs” extension and opens your selections in Vim - a great time-saver for developers!

skim can invoke other commands dynamically. Normally you would want to integrate it with grep, ack, ag, or rg for searching contents in a project directory:

Terminal window
# works with grep
sk --ansi -i -c 'grep -rI --color=always --line-number "{}" .'
# works with ack
sk --ansi -i -c 'ack --color "{}"'
# works with ag
sk --ansi -i -c 'ag --color "{}"'
# works with rg
sk --ansi -i -c 'rg --color=always --line-number "{}"'

Note: In these examples, {} will be literally expanded to the current input query. This means these examples will search for the exact query string, not fuzzily. For fuzzy searching, pipe the command output into sk without using interactive mode.

interactive mode demo

Bindings for Fish, Bash and Zsh are available in the shell directory:

  • completion.{shell} contains the completion scripts for sk cli usage
  • key-bindings.{shell} contains key-binds and shell integrations:
    • ctrl-t to select a file through sk
    • ctrl-r to select an history entry through sk
    • alt-c to cd into a directory selected through sk
    • (not available in fish) ** to complete file paths, for example ls **<tab> will show a sk widget to select a folder

To enable these features, source the key-bindings.{shell} file and set up completions according to your shell’s documentation or see below.

You can generate shell completions for your preferred shell using the --shell flag with one of the supported shells: bash, zsh, fish, powershell, or elvish:

Note: While PowerShell completions are supported, Windows is not supported for now.

Option 1: Source directly in your current shell session

Section titled “Option 1: Source directly in your current shell session”
Terminal window
# For bash
source <(sk --shell bash)
# For zsh
source <(sk --shell zsh)
# For fish
sk --shell fish | source

Option 2: Save to a file to be loaded automatically on shell startup

Section titled “Option 2: Save to a file to be loaded automatically on shell startup”
Terminal window
# For bash, add to ~/.bashrc
echo 'source <(sk --shell bash)' >> ~/.bashrc # Or save to ~/.bash_completion
# For zsh, add to ~/.zshrc
sk --shell zsh > ~/.zfunc/_sk # Create ~/.zfunc directory and add to fpath in ~/.zshrc
# For fish, add to ~/.config/fish/completions/
sk --shell fish > ~/.config/fish/completions/sk.fish

Some commonly used key bindings:

KeyAction
EnterAccept (select current one and quit)
ESC/Ctrl-GAbort
Ctrl-P/UpMove cursor up
Ctrl-N/DownMove cursor Down
TABToggle selection and move down (with -m)
Shift-TABToggle selection and move up (with -m)

For a complete list of key bindings, refer to the man page (man sk).

skim borrows fzf’s syntax for matching items:

TokenMatch typeDescription
textfuzzy-matchitems that match text
^musicprefix-exact-matchitems that start with music
.mp3$suffix-exact-matchitems that end with .mp3
'wildexact-match (quoted)items that include wild
!fireinverse-exact-matchitems that do not include fire
!.mp3$inverse-suffix-exact-matchitems that do not end with .mp3

skim also supports the combination of tokens.

  • Whitespace has the meaning of AND. With the term src main, skim will search for items that match both src and main.
  • | means OR (note the spaces around |). With the term .md$ | .markdown$, skim will search for items ends with either .md or .markdown.
  • OR has higher precedence. For example, readme .md$ | .markdown$ is interpreted as readme AND (.md$ OR .markdown$).

If you prefer using regular expressions, skim offers a regex mode:

Terminal window
sk --regex

You can switch to regex mode dynamically by pressing Ctrl-R (Rotate Mode).

Exit CodeMeaning
0Exited normally
1No Match found
130Aborted by Ctrl-C/Ctrl-G/ESC/etc…

These tools are or aim to be compatible with skim:

A neovim plugin allowing fzf and skim to be used in a to navigate your code.

Install it with your package manager, following the README. For instance, with lazy.nvim:

{
"ibhagwan/fzf-lua",
-- enable `sk` support instead of the default `fzf`
opts = {'skim'}
}

A nushell plugin to allow for better interaction between skim and nushell.

Following the instruction in the plugin’s README, you can install it with cargo:

Terminal window
cargo install nu_plugin_skim
plugin add ~/.cargo/bin/nu_plugin_skim

The doc here is only a preview, please check the man page (man sk) for a full list of options.

Specify the bindings with comma separated pairs (no space allowed). For example:

Terminal window
sk --bind 'alt-a:select-all,alt-d:deselect-all'

Additionally, use + to concatenate actions, such as execute-silent(echo {} | pbcopy)+abort.

See the KEY BINDINGS section of the man page for details.

There are five sort keys for results: score, index, begin, end, length. You can specify how the records are sorted by sk --tiebreak score,index,-begin or any other order you want.

You probably have your own aesthetic preferences! Fortunately, you aren’t limited to the default appearance - Skim supports comprehensive customization of its color scheme.

Terminal window
--color=[BASE_SCHEME][,COLOR:ANSI]

Skim also respects the NO_COLOR environment variable. Set it to anything and sk (and many other terminal apps) will disable all colored output. See no-color.org for more details.

Skim comes with several built-in color schemes that you can use as a starting point:

Terminal window
sk --color=dark # Default dark theme (256 colors)
sk --color=light # Light theme (256 colors)
sk --color=16 # Simple 16-color theme
sk --color=bw # Minimal black & white theme (no colors, just styles)
sk --color=none # Minimal black & white theme (no colors, no styles)
sk --color=molokai # Molokai-inspired theme (256 colors)

You can customize individual UI elements by specifying color values after the base scheme:

Terminal window
sk --color=light,fg:232,bg:255,current_bg:116,info:27

Colors can be specified in several ways:

  • ANSI colors (0-255): sk --color=fg:232,bg:255
  • RGB hex values: sk --color=fg:#FF0000 (red text)

The following UI elements can be customized:

ElementDescriptionExample
fgNormal text foreground color--color=fg:232
bgNormal text background color--color=bg:255
matchedMatched text in search results--color=matched:108
matched_bgBackground of matched text--color=matched_bg:0
currentCurrent line foreground color--color=current:254
current_bgCurrent line background color--color=current_bg:236
current_matchMatched text in current line--color=current_match:151
current_match_bgBackground of matched text in current line--color=current_match_bg:236
spinnerProgress indicator color--color=spinner:148
infoInformation line color--color=info:144
promptPrompt color--color=prompt:110
cursorCursor color--color=cursor:161
selectedSelected item marker color--color=selected:168
headerHeader text color--color=header:109
borderBorder color for preview/layout--color=border:59
Terminal window
# Use light theme but change the current line background
sk --color=light,current_bg:24
# Custom theme with multiple colors
sk --color=dark,matched:#00FF00,current:#FFFFFF,current_bg:#000080
# High contrast theme
sk --color=fg:232,bg:255,matched:160,current:255,current_bg:20

For more details, check the man page (man sk).

  • --ansi: to parse ANSI color codes (e.g., \e[32mABC) of the data source
  • --regex: use the query as regular expression to match the data source

In interactive mode, you can invoke a command dynamically. Try it out:

Terminal window
sk --ansi -i -c 'rg --color=always --line-number "{}"'

How Skim's interactive mode works

  • Skim accepts two kinds of sources: Command output or piped input
  • Skim has two kinds of prompts: A query prompt to specify the query pattern and a command prompt to specify the “arguments” of the command
  • -c is used to specify the command to execute and defaults to SKIM_DEFAULT_COMMAND
  • -i tells skim to open command prompt on startup, which will show c> by default.

To further narrow down the results returned by the command, press Ctrl-Q to toggle interactive mode.

You can configure key bindings to start external processes without leaving Skim (execute, execute-silent).

Terminal window
# Press F1 to open the file with less without leaving skim
# Press CTRL-Y to copy the line to clipboard and aborts skim (requires pbcopy)
sk --bind 'f1:execute(less -f {}),ctrl-y:execute-silent(echo {} | pbcopy)+abort'

This is a great feature of fzf that skim borrows. For example, we use ‘ag’ to find the matched lines, and once we narrow down to the target lines, we want to finally decide which lines to pick by checking the context around the line. grep and ag have the option --context, and skim can make use of --context for a better preview window. For example:

Terminal window
sk --ansi -i -c 'ag --color "{}"' --preview "preview.sh {}"

(Note that preview.sh is a script to print the context given filename:lines:columns)

You get things like this:

preview demo

If the preview command is given by the --preview option, skim will replace the {} with the current highlighted line surrounded by single quotes, call the command to get the output, and print the output on the preview window.

Sometimes you don’t need the whole line for invoking the command. In this case you can use {}, {1..}, {..3} or {1..5} to select the fields. The syntax is explained in the section Fields Support.

Lastly, you might want to configure the position of preview window with --preview-window:

  • --preview-window up:30% to put the window in the up position with height 30% of the total height of skim.
  • --preview-window left:10:wrap to specify the wrap allows the preview window to wrap the output of the preview command.
  • --preview-window wrap:hidden to hide the preview window at startup, later it can be shown by the action toggle-preview.

Normally only plugin users need to understand this.

For example, you have the data source with the format:

Terminal window
<filename>:<line number>:<column number>

However, you want to search <filename> only when typing in queries. That means when you type 21, you want to find a <filename> that contains 21, but not matching line number or column number.

You can use sk --delimiter ':' --nth 1 to achieve this.

You can also use --with-nth to re-arrange the order of fields.

Range Syntax

  • <num> — to specify the num-th fields, starting with 1.
  • start.. — starting from the start-th fields and the rest.
  • ..end — starting from the 0-th field, all the way to end-th field, including end.
  • start..end — starting from start-th field, all the way to end-th field, including end.

Skim can be used as a library in your Rust crates.

First, add skim into your Cargo.toml:

[dependencies]
skim = "*"

Then try to run this simple example:

extern crate skim;
use skim::prelude::*;
use std::io::Cursor;
pub fn main() {
let options = SkimOptionsBuilder::default()
.height(String::from("50%"))
.multi(true)
.build()
.unwrap();
let input = "aaaaa\nbbbb\nccc".to_string();
// `SkimItemReader` is a helper to turn any `BufRead` into a stream of `SkimItem`
// `SkimItem` was implemented for `AsRef<str>` by default
let item_reader = SkimItemReader::default();
let items = item_reader.of_bufread(Cursor::new(input));
// `run_with` would read and show items from the stream
let selected_items = Skim::run_with(&options, Some(items))
.map(|out| out.selected_items)
.unwrap_or_else(|| Vec::new());
for item in selected_items.iter() {
println!("{}", item.output());
}
}

Given an Option<SkimItemReceiver>, skim will read items accordingly, do its job and bring us back the user selection including the selected items, the query, etc. Note that:

  • SkimItemReceiver is crossbeam::channel::Receiver<Arc<dyn SkimItem>>
  • If it is none, it will invoke the given command and read items from command output
  • Otherwise, it will read the items from the (crossbeam) channel.

Trait SkimItem is provided to customize how a line could be displayed, compared and previewed. It is implemented by default for AsRef<str>

Plus, SkimItemReader is a helper to convert a BufRead into SkimItemReceiver (we can easily turn a File or String into BufRead), so that you could deal with strings or files easily.

Check out more examples under the examples/ directory.

tuikit is the TUI framework used in skim. It is available from the library as skim::tuikit.

Check [the README]!(./skim-tuikit/README.md) for more details.

Skim invokes find . to fetch a list of files for filtering. You can override this by setting the environment variable SKIM_DEFAULT_COMMAND. For example:

Terminal window
$ SKIM_DEFAULT_COMMAND="fd --type f || git ls-tree -r --name-only HEAD || rg --files || find ."
$ sk

You could put it in your .bashrc or .zshrc if you like it to be default.

If you use the Vim plugin and execute the :SK command, you may find some of your files not shown.

As described in #3, in the Vim plugin, SKIM_DEFAULT_COMMAND is set to the command by default:

let $SKIM_DEFAULT_COMMAND = "git ls-tree -r --name-only HEAD || rg --files || ag -l -g \"\" || find ."

This means files not recognized by git won’t be shown. You can either override the default with let $SKIM_DEFAULT_COMMAND = '' or locate the missing files by yourself.

fzf is a command-line fuzzy finder written in Go and skim tries to implement a new one in Rust!

This project is written from scratch. Some decisions of implementation are different from fzf. For example:

  1. skim has an interactive mode.
  2. skim supports pre-selection.
  3. The fuzzy search algorithm is different.

More generally, skim’s maintainers allow themselves some freedom of implementation. The goal is to keep skim as feature-full as fzf is, but the command flags might differ.

Create new issues if you encounter any bugs or have any ideas. Pull requests are warmly welcomed.

No line feed issues with nix, FreeBSD, termux

Section titled “No line feed issues with nix, FreeBSD, termux”

If you encounter display issues like:

Terminal window
$ for n in {1..10}; do echo "$n"; done | sk
0/10 0/0.> 10/10 10 9 8 7 6 5 4 3 2> 1

For example

You need to set TERMINFO or TERMINFO_DIRS to the path of a correct terminfo database path

For example, with termux, you can add this in your bashrc:

export TERMINFO=/data/data/com.termux/files/usr/share/terminfo