A simple terminal UI for search and replace, ala VS Code.
[!WARNING]
This project needs maintainers, if you are interested please contact me at github@yasbr.com
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
- Prerequisites - Steps - Binaries - OS Specific Installation - Basic Commands - Key Bindings - Configuration - Search Input - Replace Input - Search Results Pane - Preview Pane- Quick Hints
- Neovim Integration using toggleterm
- Helix Integration
- License
- Contributing
- Acknowledgements
- Similar Projects
Features
- Search for keywords across an entire project folder, with options for case sensitivity, AST Grep and more.
- Replace keywords with options for preserving case, AST Grep and more.
- Interactive preview of search results.
- Keyboard navigation for efficient workflow.
- Configurable key bindings and search modes.
Installation and Update
Prerequisites
- ripgrep installed on your system.
- (Optional) ast-grep installed on your system, if you want to use the AST Grep functionality.
Steps
- Install the application using Cargo:
cargo install serpl
- If you want to install the application with the AST Grep functionality, you can use the following command:
cargo install serpl --features ast_grep
- 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
- Start the application in the current directory:
serpl
- Start the application and provide the project root path:
serpl --project-root /path/to/project
Key Bindings
Default key bindings can be customized through the config.json file.
Default Key Bindings
| Key Combination | Action | | ---------------------------- | ----------------------------------------- | | Ctrl + c | Quit | | Ctrl + d | Quit | | Ctrl + b | Help | | Tab | Switch between tabs | | Backtab | Switch to previous tabs | | Ctrl + o | Process replace for all files | | r | Process replace for selected file or line | | Ctrl + n | Toggle search and replace modes | | Enter | Execute search (for large folders) | | g / Left / h | Go to top of the list | | G / Right / l | Go to bottom of the list | | j / Down | Move to the next item | | k / Up | Move to the previous item | | / | Search results list | | d | Delete selected file or line | | Esc | Exit the current pane or dialog | | Enter (in dialogs) / y | Confirm action | | Esc (in dialogs) / n | Cancel 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
JSON
{ "keybindings": { "<Ctrl-d>": "Quit", "<Ctrl-c>": "Quit", "<Tab>": "LoopOverTabs", "<Backtab>": "BackLoopOverTabs", "<Ctrl-o>": "ProcessReplace", "<Ctrl-b>": "ShowHelp" } }JSON5
{ keybindings: { "<Ctrl-d>": "Quit", "<Ctrl-c>": "Quit", "<Tab>": "LoopOverTabs", "<Backtab>": "BackLoopOverTabs", "<Ctrl-o>": "ProcessReplace", "<Ctrl-b>": "ShowHelp", }, }YAML
keybindings: "<Ctrl-d>": "Quit" "<Ctrl-c>": "Quit" "<Tab>": "LoopOverTabs" "<Backtab>": "BackLoopOverTabs" "<Ctrl-o>": "ProcessReplace" "<Ctrl-b>": "ShowHelp"TOML
[keybindings] "<Ctrl-d>" = "Quit" "<Ctrl-c>" = "Quit" "<Tab>" = "LoopOverTabs" "<Backtab>" = "BackLoopOverTabs" "<Ctrl-o>" = "ProcessReplace" "<Ctrl-b>" = "ShowHelp"INI
[keybindings] <Ctrl-d> = Quit <Ctrl-c> = Quit <Tab> = LoopOverTabs <Backtab> = BackLoopOverTabs <Ctrl-o> = ProcessReplace <Ctrl-b> = ShowHelp
You can customize the key bindings by modifying the configuration file in the format of your choice.
Panes
Search Input
- Input field for entering search keywords.
- Toggle search modes (Simple, Match Case, Match Whole Word, Match Case Whole Word, Regex, AST Grep).
[!TIP]
If current directory is considerebly large, you have to click Enter to start the search.
Replace Input
- Input field for entering replacement text.
- Toggle replace modes (Simple, Preserve Case, AST Grep).
Search Results Pane
- List of files with search results.
- Navigation to select and view files.
- Option to delete files from the search results.
- Search results count and current file count.
- Ability to search the list using the
/key.
Preview Pane
- Display of the selected file with highlighted search results, and context.
- Navigation to view different matches within the file.
- Option to delete individual lines containing matches.
Quick Hints
- Use the
Ctrl + bkey combination to display the help dialog. - Use the
Ctrl + okey combination to process the replace for all files. - Use the
rkey to process the replace for the selected file or line. - Use the
Ctrl + nkey combination to toggle between search and replace modes. - Use the
g,G,j, andkkeys to navigate through the search results. - Use the
dkey to delete the selected file or line.
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.tblget(opts, "map_sections", "t")
local serpl = { callback = function() astro.toggletermcmd "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" }, }, }
Helix integration
You can add a keybinding like the following to open Serpl inside Helix:
[keys.normal.ret]
t = [":write-all", ":insert-output serpl >/dev/tty", ":redraw", ":reload-all"]
License
This project is licensed under the MIT License. See the LICENSE file for details.
Contributing
(WIP)Acknowledgements
- This project was inspired by the VS Code search and replace functionality.
- This project is built using the awesome ratatui.rs library, and build on top of their Component Template.
- Thanks to the ripgrep project for providing the search functionality.
- Thanks to the ast-grep project for providing the AST Grep functionality.
Similar Projects
- repgrep: An interactive replacer for ripgrep that makes it easy to find and replace across files on the command line.