skim

repository·master·Indexed 27 days ago

https://github.com/skim-rs/skim

A fast fuzzy finder written in Rust (sk) designed to improve developer workflows by navigating files, lines, and commands. It can be used as a standalone interactive interface, a command filter, or integrated into editors like Vim/Neovim and Nushell. Version 5.6.1 supports various matching tokens, custom color schemes, and interactive command execution.

Tokens
17.8K
Snippets
34
Records
108
Agent score
91%

What's inside skim

  1. Understand the Skim Item Ingestion Pipeline

    master

    Skim uses a unified parallel pipeline (parallel_bufread) to ingest all inputs, including plain stdin, shell commands, and flags like --ansi or --nth.

    Pipeline Stages:

    1. I/O Reader: Reads 256 KB chunks, splits at line boundaries, and assigns sequence numbers.
    2. Workers: Validate UTF-8 and create DefaultSkimItem instances. This stage handles ANSI stripping and field transformations (e.g., --nth, --hide-nth).
    3. Reorder: Collects items and emits them in the correct sequence.
    4. Killer: Ensures child processes are terminated if the pipeline is interrupted.

    Item Construction Behavior: When using --ansi and --nth (transformed fields), the text field contains the transformed content, while orig_text preserves the original line for output purposes.

  2. Understand Skim's TUI Backend and Terminal Setup

    master

    Skim uses a TUI subsystem built on ratatui and crossterm. It is designed to draw exclusively to stderr, ensuring that stdout remains clean for piped output (e.g., find | sk | grep ...).

    Viewport Selection

    When initializing the TUI, the viewport size can be configured using several modes:

    • Size::Percent(100): Enters fullscreen mode using the terminal's alternate screen.
    • Size::Fixed(lines): Uses a fixed number of rows.
    • Size::Percent(p): Uses a percentage of the terminal height (terminal_height * p / 100).
    • Size::Neg(lines): Uses the terminal height minus a specific number of lines (terminal_height - lines).

    Fixed viewports are anchored at the current cursor position, and the terminal scrolls automatically to accommodate them.

  3. Skim Crate Layout and Features

    master

    The skim repository is organized as a single crate containing both a library and a binary.

    Library vs Binary

    • Library (lib): Provides all types under the skim::* namespace, intended for embedding in other Rust projects.
    • Binary (sk): A clap-based CLI tool (requires the cli feature).

    Key Features

    • cli feature: Enables CLI functionality via clap, clap_complete, shlex, env_logger, and clap_mangen.
    • image feature (enabled by default): Enables image preview support using the image and ratatui-image crates. It supports png, jpeg, gif, and webp decoders. When disabled, the --image flag and related code are compiled out.
    • listen feature (enabled by default): Enables an IPC socket via the interprocess crate, allowing other processes to drive skim using the --listen or --remote flags.
  4. High-Level Architecture of Skim

    master

    Skim (sk) is a terminal fuzzy-finder that operates using four concurrent activities to process data from input to output:

    1. Reader: Pulls raw text from stdin or a shell command, converts it into Arc<dyn SkimItem> batches, and deposits them into the ItemPool.
    2. ItemPool: A shared storage (Arc<...>) that holds batched items.
    3. Matcher: A parallel worker that picks items from the ItemPool, evaluates them against the current query string using a configured engine, and produces ranked MatchedItem results.
    4. TUI (Terminal User Interface): A crossterm-based event loop that renders composable widgets (Input, ItemList, Preview, Header) and converts user keystrokes into Action values to drive the application state machine.

    The final result is emitted as SkimOutput.

    stdin / command
          │
          ▼
     ┌──────────┐   batched items   ┌──────────────┐
     │  Reader  │──────────────────▶│  ItemPool    │
     └──────────┘                   │  (Arc<…>)    │
                                    └──────┬───────┘
                                           │ take()
                                           ▼
                                    ┌──────────────┐
                                    │   Matcher    │◀── query string
                                    │  (parallel)  │
                                    └──────┬───────┘
                                           │ ProcessedItems
                                           ▼
                       ┌──────────────────────────────────┐
                       │              TUI                  │
                       │  ┌────────┐  ┌────────┐           │
                       │  │ Input  │  │Preview │           │
                       │  ├────────┤  ├────────┤           │
                       │  │ItemList│  │ Header │           │
                       │  └────────┘  └────────┘           │
                       └──────────────────────────────────┘
                                           │
                                           ▼
                                      SkimOutput
  5. Install skim on Debian/Ubuntu

    master

    To install skim on Debian or Ubuntu systems using the official APT repository:

    1. Import the signing key using wget:

      sudo mkdir -p /etc/apt/keyrings
      sudo wget -O /etc/apt/keyrings/skim.asc https://skim-rs.github.io/skim/apt/skim-archive-keyring.asc

      Or using curl:

      sudo mkdir -p /etc/apt/keyrings
      curl -fsSL https://skim-rs.github.io/skim/apt/skim-archive-keyring.asc | sudo tee /etc/apt/keyrings/skim.asc > /dev/null
    2. Add the repository:

      echo 'deb [signed-by=/etc/apt/keyrings/skim.asc] https://skim-rs.github.io/skim/apt ./' | sudo tee /etc/apt/sources.list.d/skim.list
      sudo apt-get update
    3. Install:

      sudo apt-get install skim

    Alternatively, you can download .deb packages from the releases page and install them using sudo dpkg -i skim_*_amd64.deb.

    sudo apt-get install skim
  6. Reproduce a fuzzing crash

    master

    When a crash is detected, cargo fuzz run saves the failing input to fuzz/artifacts/<target>/. To replay a specific crash, provide the path to the artifact as an argument to the fuzz command.

    cargo +nightly fuzz run <target> fuzz/artifacts/<target>/crash-<hash>
  7. Execute commands in the foreground from Skim

    master

    Skim supports executing commands (like editors or interactive TUIs) in the foreground. When a command is triggered via execute, Skim performs the following to ensure a smooth transition:

    1. Stops the TUI reader: It cancels the background event-pump task and blocks until the EventStream is dropped. This prevents Skim from competing with the child process for keystrokes.
    2. Handles Stdin: The child process is spawned with its own stdin opened from the controlling terminal (/dev/tty or CONIN$ on Windows). This allows interactive commands to work even when Skim's own stdin is a pipe (e.g., find | sk).
    3. Restores Terminal: Skim leaves the alternate screen/raw mode, runs the command, waits for it to finish, restores terminal modes, and then restarts the TUI reader.

    Note: execute-silent(cmd) spawns the command directly without needing a terminal, sending its stdout/stderr to /dev/null.

  8. Use skim as a Rust library

    master

    You can integrate skim directly into your Rust projects. Add skim to your Cargo.toml. Note that the cli feature is required for the standalone CLI tool but should not be needed when using it as a library.

    To use it, you can use SkimOptionsBuilder to configure the interface and Skim::run_with to execute the fuzzy finder with a stream of items.

    [dependencies]
    skim = { version = "<version>", default-features = false, features = [..] }
    extern crate skim;
    use skim::prelude::*;
    use std::io::Cursor;
    
    pub fn main() {
        let options = SkimOptionsBuilder::default()
            .height("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());
        }
    }
  9. Integrate Skim with fzf-lua (Neovim)

    master

    To use skim instead of fzf in the fzf-lua Neovim plugin, configure the opts to use the skim profile.

    Example using lazy.nvim:

    {
      "ibhagwan/fzf-lua",
      -- enable `sk` support instead of the default `fzf`
      opts = {'skim'}
    }
    {
      "ibhagwan/fzf-lua",
      -- enable `sk` support instead of the default `fzf`
      opts = {'skim'}
    }
  10. Customize item previews with placeholders

    master

    When using the --preview command, you can use placeholders to inject context from the currently focused or selected items into your command string:

    • {}: The text of the focused item.
    • {q}: The current query string.
    • {n}: The index of the focused item.
    • {+}: Space-separated texts of all selected items.
    • {+n}: Space-separated indices of all selected items.
  11. Install skim via Package Managers

    master

    You can install the sk executable using various package managers depending on your operating system:

    OSPackage ManagerCommand
    macOSHomebrewbrew install sk
    macOSMacPortssudo port install skim
    Alpineapkapk add skim
    Archpacmanpacman -S skim
    GentooPortageemerge --ask app-misc/skim
    Guixguixguix install skim
    VoidXBPSxbps-install -S skim
    Windowswingetwinget install skim
    WindowsScoopscoop install skim