Home

Awesome

Serpl

serpl is a terminal user interface (TUI) application that allows users to search and replace keywords in an entire folder, similar to the functionality available in VS Code.

https://github.com/yassinebridi/serpl/assets/18403595/348506704-73336074-bfaf-4a9a-849c-bd4aa4e24afc

Table of Contents

  1. Features
  2. Installation
  3. Usage
  4. Panes
  5. Quick Hints
  6. Neovim Integration using toggleterm
  7. License
  8. Contributing
  9. Acknowledgements
  10. Similar Projects

Features

Installation and Update

Prerequisites

Steps

  1. Install the application using Cargo:
cargo install serpl
  1. Run the application:
serpl

Binaries

Check the releases page for the latest binaries.

OS Specific Installation

Brew

serpl can be installed using Homebrew:

brew install serpl

Arch Linux

serpl can be installed from the official repositories using pacman:

pacman -S serpl

Nix/NixOS

serpl is included in nixpkgs since 24.11, and can be installed via Nix in different ways:

On standalone Nix setups:

nix profile install nixpkgs#serpl

On NixOS (via configuration.nix or similar):

{pkgs, ...}: {
  environment.systemPackages = [pkgs.serpl];
}

On Home-Manager:

{pkgs, ...}: {
  home.packages = [pkgs.serpl];
}

Usage

Basic Commands

Key Bindings

Default key bindings can be customized through the config.json file.

Default Key Bindings

Key CombinationAction
Ctrl + cQuit
Ctrl + bHelp
TabSwitch between tabs
BacktabSwitch to previous tabs
Ctrl + oProcess replace for all files
rProcess replace for selected file or line
Ctrl + nToggle search and replace modes
EnterExecute search (for large folders)
g / Left / hGo to top of the list
G / Right / lGo to bottom of the list
j / DownMove to the next item
k / UpMove to the previous item
/Search results list
dDelete selected file or line
EscExit the current pane or dialog
Enter (in dialogs) / yConfirm action
Esc (in dialogs) / nCancel action
h, l, Tab (in dialogs)Navigate dialog options

Configuration

serpl uses a configuration file to manage key bindings and other settings. By default, the path to the configuration file can be found by running serpl --version. You can use various file formats for the configuration, such as JSON, JSON5, YAML, TOML, or INI.

Example Configurations

<details> <summary>JSON</summary>
{
  "keybindings": {
    "<Ctrl-d>": "Quit",
    "<Ctrl-c>": "Quit",
    "<Tab>": "LoopOverTabs",
    "<Backtab>": "BackLoopOverTabs",
    "<Ctrl-o>": "ProcessReplace",
    "<Ctrl-b>": "ShowHelp"
  }
}
</details> <details> <summary>JSON5</summary>
{
  keybindings: {
    "<Ctrl-d>": "Quit",
    "<Ctrl-c>": "Quit",
    "<Tab>": "LoopOverTabs",
    "<Backtab>": "BackLoopOverTabs",
    "<Ctrl-o>": "ProcessReplace",
    "<Ctrl-b>": "ShowHelp",
  },
}
</details> <details> <summary>YAML</summary>
keybindings:
  "<Ctrl-d>": "Quit"
  "<Ctrl-c>": "Quit"
  "<Tab>": "LoopOverTabs"
  "<Backtab>": "BackLoopOverTabs"
  "<Ctrl-o>": "ProcessReplace"
  "<Ctrl-b>": "ShowHelp"
</details> <details> <summary>TOML</summary>
[keybindings]
"<Ctrl-d>" = "Quit"
"<Ctrl-c>" = "Quit"
"<Tab>" = "LoopOverTabs"
"<Backtab>" = "BackLoopOverTabs"
"<Ctrl-o>" = "ProcessReplace"
"<Ctrl-b>" = "ShowHelp"
</details> <details> <summary>INI</summary>
[keybindings]
<Ctrl-d> = Quit
<Ctrl-c> = Quit
<Tab> = LoopOverTabs
<Backtab> = BackLoopOverTabs
<Ctrl-o> = ProcessReplace
<Ctrl-b> = ShowHelp
</details>

You can customize the key bindings by modifying the configuration file in the format of your choice.

Panes

Search Input

[!TIP] If current directory is considerebly large, you have to click Enter to start the search.

Replace Input

Search Results Pane

Preview Pane

Quick Hints

Neovim Integration using toggleterm

Check out the toggleterm.nvim plugin for Neovim, which provides a terminal that can be toggled with a key binding. Or you can use the following configuration, if you are using AstroNvim:

return {
  "akinsho/toggleterm.nvim",
  cmd = { "ToggleTerm", "TermExec" },
  dependencies = {
    {
      "AstroNvim/astrocore",
      opts = function(_, opts)
        local maps = opts.mappings
        local astro = require "astrocore"
        maps.n["<Leader>t"] = vim.tbl_get(opts, "_map_sections", "t")

        local serpl = {
          callback = function()
            astro.toggle_term_cmd "serpl"
          end,
          desc = "ToggleTerm serpl",
        }
        maps.n["<Leader>sr"] = { serpl.callback, desc = serpl.desc }

        maps.n["<Leader>tf"] = { "<Cmd>ToggleTerm direction=float<CR>", desc = "ToggleTerm float" }
        maps.n["<Leader>th"] = { "<Cmd>ToggleTerm size=10 direction=horizontal<CR>", desc = "ToggleTerm horizontal split" }
        maps.n["<Leader>tv"] = { "<Cmd>ToggleTerm size=80 direction=vertical<CR>", desc = "ToggleTerm vertical split" }
        maps.n["<F7>"] = { '<Cmd>execute v:count . "ToggleTerm"<CR>', desc = "Toggle terminal" }
        maps.t["<F7>"] = { "<Cmd>ToggleTerm<CR>", desc = "Toggle terminal" }
        maps.i["<F7>"] = { "<Esc><Cmd>ToggleTerm<CR>", desc = "Toggle terminal" }
        maps.n["<C-'>"] = { '<Cmd>execute v:count . "ToggleTerm"<CR>', desc = "Toggle terminal" }
        maps.t["<C-'>"] = { "<Cmd>ToggleTerm<CR>", desc = "Toggle terminal" }
        maps.i["<C-'>"] = { "<Esc><Cmd>ToggleTerm<CR>", desc = "Toggle terminal" }
      end,
    },
  },
  opts = {
    highlights = {
      Normal = { link = "Normal" },
      NormalNC = { link = "NormalNC" },
      NormalFloat = { link = "NormalFloat" },
      FloatBorder = { link = "FloatBorder" },
      StatusLine = { link = "StatusLine" },
      StatusLineNC = { link = "StatusLineNC" },
      WinBar = { link = "WinBar" },
      WinBarNC = { link = "WinBarNC" },
    },
    size = 10,
    ---@param t Terminal
    on_create = function(t)
      vim.opt_local.foldcolumn = "0"
      vim.opt_local.signcolumn = "no"
      if t.hidden then
        local toggle = function() t:toggle() end
        vim.keymap.set({ "n", "t", "i" }, "<C-'>", toggle, { desc = "Toggle terminal", buffer = t.bufnr })
        vim.keymap.set({ "n", "t", "i" }, "<F7>", toggle, { desc = "Toggle terminal", buffer = t.bufnr })
      end
    end,
    shading_factor = 2,
    direction = "float",
    float_opts = { border = "rounded" },
  },
}

License

This project is licensed under the MIT License. See the LICENSE file for details.

Contributing

(WIP)

Acknowledgements

Similar Projects