Skip to main content
  1. Posts/

Search in Vim

·841 words·4 mins
Author
Yang Hu

搜索是开发中最常用也是最重要的操作之一. Vim提供了非常高效和方便的搜索功能. 这篇笔记记录了一些常用的搜索命令,例子以及自定义的key mapping

  • 使用ripgrep搜索文件内容 (:Rg2 or ,gg, ,gw/,gW )
  • 使用git-grep搜索git branch/commit, 以及使用fzf显示git grep的结果 (:Ggrep)
  • 使用fzf/coc list搜索当前文件/buffers中的lines, 实现快速定位/跳转
  • 使用quickfix lists快速访问上述搜索的结果, 以及利用:cdo/:cfdo等命令对结果进行批量操作.

General searching inside files
#

Ripgrep with fzf
#

fzf.vim provides a :Rg command to call ripgrep and search the current directory. However, a more useful variant is built to support specify path and pass other parameters to ripgrep, I used this snippet and mapped this to shortcut <Leader>gg.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
" https://github.com/junegunn/fzf.vim/issues/837#issuecomment-1179386300
" Search with ripgrep and fzf with folder specs. Defult starts in git root folder
" Examples:
"   :Rg2 -w "apple" ./folder_test
"   :Rg2 -w "apple" -g "!themes/*" -g "*.css"
"   :Rg2 --type=js "apple"
"   :Rg2 --fixed-strings "apple"
"   :Rg2 -e -foo
command! -bang -nargs=* Rg2
  \ call fzf#vim#grep(
  \ "rg --column --line-number --no-heading --color=always --smart-case ".<q-args>,
  \ 1, {'dir': system('git -C '.expand('%:p:h').' rev-parse --show-toplevel 2> /dev/null')[:-2]},
  \ <bang>0)

Ripgrep options for search:

  • -w: word search
  • -g: glob to include/exclude(start the pattern with !) files/dirs.
  • --type: filter by file type. Example: --type=js

The results are present with fzf, where you can do fuzzy serach:

  • “!pattern”: exclude results that has the pattern string
  • “pattern”: fuzzy match and only include results that has the pattern string

Select results with tab, or c-a to select all, then enter to open, or c-q to build quickfix list.

Tips:

  • Use <C-r><C-w> to insert under cursor, or <C-r><C-a> for WORD. In tmux, you need to input c-a twice.

Searching inside the current file
#

Fzf provides a convenient way to filter lines of all open buffers or current buffer, with commands :Lines and :BLines. Then just type the word you want to search, and quickly go to the line by enter.

You can also build a quickfix list from the result, by first <C-a> to select all, then <C-q> to build the quickfix list from fzf UI.

Custom keymaps are created for quick access to the buffer searches:

  • <Leader>l*: Search ALL open buffers
  • <Leader>/: Search current buffer. (Like / but with fzf)
  • <Leader>lw: Search the current word under cursor in all open buffers.

CocSearch
#

  • Pros: intuitive to use, results in a buffer window nicely formatted
  • Cons: Not integrated with quickfix list, can’t easily filter results or move fast among results. (compared to fzf or coc-list grep)

Arguments for ripgrep (can be added by using -A in CocSearch comman)

  • -g {GLOB}: Include or exclude files/directories that matches the glob. Precede glob with ! to exlude.
  • -w –word-regexp: Only show matches surrounded by word boundaries.
  • -x –line-regexp: Only show matches surrounded by line boundaries.

Example: search a string but ignore keyboards/ folder and exlude .mk files.

1
:CocSearch STM32F411 ../../.. -g !keyboards/ -g !*.mk

Searching git repositories
#

In git repo, somtimes we want to search stuff beyond the current working directory or version. git grep is a useful tool to search in other branches/commits.

Raw Ggrep with Fugitive
#

fugitive.vim plugin provides Vim integration to use git grep in VIM. The results are sent to quickfix list directly.

Some search query examples:

1
2
3
4
5
:Ggrep "ripgrep" HEAD~
:Ggrep "ripgrep" master
:Ggrep -w "coc" HEAD~ -- "*.md"
:Ggrep --cached findme -- "*.[ch]"
:Ggrep --untracked findme

See section below about quickfix lists for more details on how to access and use the results.

Using fzf to view the results
#

caveat: if searching is on a different branch or commit, FZF’s preview can’t show the file. Using fugitive’s Ggrep command will be more useful.

Snippets borrwed from fzf.vim’s README.

1
2
3
4
command! -bang -nargs=* GGrep
  \ call fzf#vim#grep(
  \   'git grep --line-number -- '.fzf#shellescape(<q-args>),
  \   fzf#vim#with_preview({'dir': systemlist('git rev-parse --show-toplevel')[0]}), <bang>0)

Working with search results in quickfix list
#

Search results are saved in the quickfix list, which can be opened with :cw, and explored with ]q/[q ( with vim-unimparied plugin mappings ), or using j/k by opening the quickfix list. The quickfix list can also be explored/searched using coc-list with custom mapping <leader>lq.

You may have started a search on something like :vimgrep /\<read_file\>/ *.c, working through the quickfix list, then found you need to search something else like :vimgrep /\<msg\>/ *.c. When you’re done with the new search results, you can use :col[der] to go back to the previous quickfix list and continue with the old results.

Coc-lists also provides a quick search list for the quickfix list, can be accessed with :CocList quickfix, or custom mapping <Leader>lq.

Useful resources

  • :h quickfix
  • :h cdo
  • :h cfdo
  • :h ccl - Close the quickfix window
  • :h col[der] - Go to the older quickfix list
  • :h cnew - Go to the newer quickfix list
  • :h chi - Show history of quickfix lists (max 10)

Mappings
#

I created the following mappings to use cocsearch

  • <Leader>gg: In normal mode, it enters :Rg2 and waits for input. In visual mode, it fills the argument with the visual selection. (spaces are escaped)
  • <Leader>g{w|W}: Search the word/WORD under cursor.

Combine this with the shortcut %% (expands to current file’s folder), we can easily start searching.