Home

Awesome

nvim-spectre

A search panel for neovim.

Spectre find the enemy and replace them with dark power.

demo

Why Use Spectre?

Installation

Plug 'nvim-lua/plenary.nvim'
Plug 'nvim-pack/nvim-spectre'

You may also need to install the following:

MacOs

You may need run brew install gnu-sed.

Usage

vim.keymap.set('n', '<leader>S', '<cmd>lua require("spectre").toggle()<CR>', {
    desc = "Toggle Spectre"
})
vim.keymap.set('n', '<leader>sw', '<cmd>lua require("spectre").open_visual({select_word=true})<CR>', {
    desc = "Search current word"
})
vim.keymap.set('v', '<leader>sw', '<esc><cmd>lua require("spectre").open_visual()<CR>', {
    desc = "Search current word"
})
vim.keymap.set('n', '<leader>sp', '<cmd>lua require("spectre").open_file_search({select_word=true})<CR>', {
    desc = "Search on current file"
})

Use command: :Spectre

Warnings

Regex Issues

Replace

You can replace groups with \0-9 similar to vim and sed, if you run a replace command and don't see the change you may need to reload file with :e because sed is replace outside vim.

Customization

require('spectre').setup()
<details> <summary>Config</summary> Change any settings if you don't like them. **Don't just copy all** as settings may change as the plugin is updated so it may be better use the default settings.
require('spectre').setup({

  color_devicons = true,
  open_cmd = 'vnew',
  live_update = false, -- auto execute search again when you write to any file in vim
  lnum_for_results = true, -- show line number for search/replace results
  line_sep_start = '┌-----------------------------------------',
  result_padding = '¦  ',
  line_sep       = '└-----------------------------------------',
  highlight = {
      ui = "String",
      search = "DiffChange",
      replace = "DiffDelete"
  },
  mapping={
    ['tab'] = {
        map = '<Tab>',
        cmd = "<cmd>lua require('spectre').tab()<cr>",
        desc = 'next query'
    },
    ['shift-tab'] = {
        map = '<S-Tab>',
        cmd = "<cmd>lua require('spectre').tab_shift()<cr>",
        desc = 'previous query'
    },
    ['toggle_line'] = {
        map = "dd",
        cmd = "<cmd>lua require('spectre').toggle_line()<CR>",
        desc = "toggle item"
    },
    ['enter_file'] = {
        map = "<cr>",
        cmd = "<cmd>lua require('spectre.actions').select_entry()<CR>",
        desc = "open file"
    },
    ['send_to_qf'] = {
        map = "<leader>q",
        cmd = "<cmd>lua require('spectre.actions').send_to_qf()<CR>",
        desc = "send all items to quickfix"
    },
    ['replace_cmd'] = {
        map = "<leader>c",
        cmd = "<cmd>lua require('spectre.actions').replace_cmd()<CR>",
        desc = "input replace command"
    },
    ['show_option_menu'] = {
        map = "<leader>o",
        cmd = "<cmd>lua require('spectre').show_options()<CR>",
        desc = "show options"
    },
    ['run_current_replace'] = {
      map = "<leader>rc",
      cmd = "<cmd>lua require('spectre.actions').run_current_replace()<CR>",
      desc = "replace current line"
    },
    ['run_replace'] = {
        map = "<leader>R",
        cmd = "<cmd>lua require('spectre.actions').run_replace()<CR>",
        desc = "replace all"
    },
    ['change_view_mode'] = {
        map = "<leader>v",
        cmd = "<cmd>lua require('spectre').change_view()<CR>",
        desc = "change result view mode"
    },
    ['change_replace_sed'] = {
      map = "trs",
      cmd = "<cmd>lua require('spectre').change_engine_replace('sed')<CR>",
      desc = "use sed to replace"
    },
    ['change_replace_oxi'] = {
      map = "tro",
      cmd = "<cmd>lua require('spectre').change_engine_replace('oxi')<CR>",
      desc = "use oxi to replace"
    },
    ['toggle_live_update']={
      map = "tu",
      cmd = "<cmd>lua require('spectre').toggle_live_update()<CR>",
      desc = "update when vim writes to file"
    },
    ['toggle_ignore_case'] = {
      map = "ti",
      cmd = "<cmd>lua require('spectre').change_options('ignore-case')<CR>",
      desc = "toggle ignore case"
    },
    ['toggle_ignore_hidden'] = {
      map = "th",
      cmd = "<cmd>lua require('spectre').change_options('hidden')<CR>",
      desc = "toggle search hidden"
    },
    ['resume_last_search'] = {
      map = "<leader>l",
      cmd = "<cmd>lua require('spectre').resume_last_search()<CR>",
      desc = "repeat last search"
    },
    ['select_template'] = {
        map = '<leader>rp',
        cmd = "<cmd>lua require('spectre.actions').select_template()<CR>",
        desc = 'pick template',
    },
    ['delete_line'] = {
        map = '<leader>rd',
        cmd = "<cmd>lua require('spectre.actions').run_delete_line()<CR>",
        desc = 'delete line',
    }
    -- you can put your mapping here it only use normal mode
  },
  find_engine = {
    -- rg is map with finder_cmd
    ['rg'] = {
      cmd = "rg",
      -- default args
      args = {
        '--color=never',
        '--no-heading',
        '--with-filename',
        '--line-number',
        '--column',
      },
      options = {
        ['ignore-case'] = {
          value= "--ignore-case",
          icon="[I]",
          desc="ignore case"
        },
        ['hidden'] = {
          value="--hidden",
          desc="hidden file",
          icon="[H]"
        },
        -- you can put any rg search option you want here it can toggle with
        -- show_option function
      }
    },
    ['ag'] = {
      cmd = "ag",
      args = {
        '--vimgrep',
        '-s'
      } ,
      options = {
        ['ignore-case'] = {
          value= "-i",
          icon="[I]",
          desc="ignore case"
        },
        ['hidden'] = {
          value="--hidden",
          desc="hidden file",
          icon="[H]"
        },
      },
    },
  },
  replace_engine={
      ['sed']={
          cmd = "sed",
          args = nil,
          options = {
            ['ignore-case'] = {
              value= "--ignore-case",
              icon="[I]",
              desc="ignore case"
            },
          }
      },
      -- call rust code by nvim-oxi to replace
      ['oxi'] = {
        cmd = 'oxi',
        args = {},
        options = {
          ['ignore-case'] = {
            value = "i",
            icon = "[I]",
            desc = "ignore case"
          },
        }
      },
      ['sd'] = {
        cmd = "sd",
        options = { },
      },
  },
  default = {
      find = {
          --pick one of item in find_engine
          cmd = "rg",
          options = {"ignore-case"}
      },
      replace={
          --pick one of item in replace_engine
          cmd = "sed"
      }
  },
  replace_vim_cmd = "cdo",
  use_trouble_qf = false, -- use trouble.nvim as quickfix list
  is_open_target_win = true, --open file on opener window
  is_insert_mode = false,  -- start open panel on is_insert_mode
  is_block_ui_break = false -- mapping backspace and enter key to avoid ui break
  open_template      = {
    -- an template to use on open function
    -- see the 'custom function' section below to learn how to configure the template
    -- { search_text = 'text1', replace_text = '', path = "" }
  }
})

</details>

Custom Functions

-- if you want to get items from spectre panel you can use some of the
-- following functions to get data from spectre.
require('spectre.actions').get_current_entry()
require('spectre.actions').get_all_entries()
require('spectre.actions').get_state()

-- write your custom open function
require('spectre').open({
  is_insert_mode = true,
  -- the directory where the search tool will be started in
  cwd = "~/.config/nvim",
  search_text="test",
  replace_text="test",
  -- the pattern of files to consider for searching
  path="lua/**/*.lua",
  -- the directories or files to search in
  search_paths = {"lua/", "plugin/"},
  is_close = false, -- close an exists instance of spectre and open new
})
-- you can use all variables above on command line
-- for example: Spectre % is_insert_mode=true cwd=~/.config/nvim
-- in this example `%` will expand to current file.

Search paths

By default, searching is performed in the current working directory, which can also be customized using the cwd option in the example above.

The path option limits the search only to the files matching the provided pattern. Note, however, that even if you provide the path, all files in the cwd still need to be listed, and this could be quite slow if cwd is a large directory.

To limit the search paths further, you can also provide the search_paths option. This is the list of directories or files to search in, regardless of the cwd.

Replace Method

There are three replace methods sed, oxi and sd.

Sedoxi
group number by '\0'group number by '${0}'
use vim to highlight on UIuse rust to highlight on UI
use sed to replaceuse rust to replace
run sed commandcall rust code directly by nvim-oxi

Install oxi:

require('spectre').setup({
    default = {
        replace = {
            cmd = "oxi"
       }
    }
})

Sponsors

Thanks to everyone who sponsors my projects and makes continued development and maintenance possible!

<!-- patreon --><a href="https://github.com/t4t5"><img src="https://github.com/t4t5.png" width="60px" alt="" /></a><!-- patreon-->

FAQ

    require('windline').add_status(
        require('spectre.state_utils').status_line()
    )
require('spectre').setup({ is_block_ui_break = true })

Spectre hardcodes some mappings in order to work correctly. You can remap them as described above. You are allowed to create as many mappings as you want. For name and description choose any value. 'map' and 'cmd' are the only important fields.

Yes, but only if you set opts = { open = { enable = false } } on mini.animate, otherwise it will cause serious issues preventing spectre from opening/closing.

I wanted to call it Search Panel but this name is not cool. I got the name of a hero on a game. Spectre has a skill to find enemy on global map so I use it:)