tessl install tessl/npm-coc-nvim@0.0.0LSP based intellisense engine for neovim & vim8.
Complexity: Intermediate | Category: Reference | Keywords: search, grep, ripgrep, find, workspace
Common Tasks: Search codebase | Find patterns | Search by filetype | Context search | Save results
Workspace-wide code search with ripgrep integration. Search across your entire project with powerful filtering and context options.
:CocSearch TODOSearch for pattern across workspace.
:CocSearch --glob '*.js' importSearch only in JavaScript files.
:CocSearch -i errorSearch ignoring case.
nnoremap <leader>sw :exe 'CocSearch '.expand('<cword>')<CR>Quick search for word at cursor.
:CocList grepOpen fuzzy-searchable grep interface.
:CocSearch [options] {pattern}Search workspace for pattern using ripgrep.
Parameters:
pattern - Pattern to search for (required)Options:
-e, --regexp PATTERN - Use regexp pattern (default)-F, --fixed-strings - Use fixed string matching (literal)-w, --word-regexp - Match whole words only-S, --smart-case - Smart case matching (case insensitive unless pattern has uppercase)-i, --ignore-case - Case insensitive search-s, --case-sensitive - Case sensitive matching-g, --glob PATTERN - Include files matching glob pattern--hidden - Search hidden files and directories--no-ignore - Don't respect .gitignore and other ignore files-x, --context NUM - Show NUM lines of context around matches-A, --after-context NUM - Show NUM lines after each match-B, --before-context NUM - Show NUM lines before each matchReturns: Opens search results in quickfix or location list
Example:
" Basic search
:CocSearch TODO
" Whole word search
:CocSearch -w function
" Case insensitive
:CocSearch -i error
" Search with glob
:CocSearch --glob '*.js' import
" Search with context
:CocSearch -A 3 -B 3 error
" Search hidden files
:CocSearch --hidden config
" Multiple globs
:CocSearch --glob '*.{js,ts}' exportAdvanced Usage:
" Regex search
:CocSearch -e 'function \w+\('
" Fixed string (escape special chars)
:CocSearch -F 'import * from'
" Smart case (case insensitive unless uppercase present)
:CocSearch -S Pattern
" Exclude files
:CocSearch --glob '!*.test.js' function
" Search in specific directory
:CocSearch --glob 'src/**/*.ts' interface:CocList grep [pattern]Interactive grep interface with fuzzy matching and preview.
Parameters:
pattern - Initial search pattern (optional)Features:
Example:
" Open grep list
:CocList grep
" Grep with initial pattern
:CocList grep TODO
" Grep word under cursor
:exe 'CocList --input='.expand('<cword>').' grep'
" Grep in normal mode (non-interactive start)
:CocList --normal grepKeybindings in List:
<Tab> - Select/deselect item<C-s> - Open in split<C-v> - Open in vertical split<C-t> - Open in new tab<C-p> / <C-n> - Navigate up/down<Esc> - Exit listConfigure search behavior in coc-settings.json:
{
"list.source.grep.command": "rg",
"list.source.grep.args": [
"--color", "never",
"--line-number",
"--smart-case",
"--no-heading"
],
"list.source.grep.defaultArgs": [],
"search.followSymlinks": true
}Settings:
list.source.grep.command
string"rg"list.source.grep.args
array<string>["--color", "never", "--line-number", "--smart-case", "--no-heading"]list.source.grep.defaultArgs
array<string>[]search.followSymlinks
booleantrueExample Configuration:
{
"list.source.grep.command": "rg",
"list.source.grep.args": [
"--color", "never",
"--line-number",
"--smart-case",
"--no-heading",
"--hidden",
"--glob", "!.git/*"
],
"search.followSymlinks": true
}Common search mappings:
" Search word under cursor
nnoremap <leader>sw :exe 'CocSearch '.expand('<cword>')<CR>
" Search visual selection
vnoremap <leader>sw :<C-u>call <SID>SearchVisual()<CR>
function! s:SearchVisual() abort
let saved = @"
normal! gvy
let pattern = escape(@", '\')
let @" = saved
execute 'CocSearch ' . pattern
endfunction
" Interactive grep
nnoremap <leader>fg :CocList grep<CR>
" Grep word under cursor interactively
nnoremap <leader>fw :exe 'CocList --input='.expand('<cword>').' grep'<CR>
" Search in current buffer
nnoremap <leader>fb :exe 'CocList --input='.bufname('%').' grep'<CR>Helper functions for filetype-specific search:
function! SearchInFileType(pattern, filetype) abort
let glob = '*.' . a:filetype
execute 'CocSearch --glob ' . shellescape(glob) . ' ' . shellescape(a:pattern)
endfunction
" Define commands for common filetypes
command! -nargs=+ SearchJS call SearchInFileType(<f-args>, 'js')
command! -nargs=+ SearchTS call SearchInFileType(<f-args>, 'ts')
command! -nargs=+ SearchPY call SearchInFileType(<f-args>, 'py')
command! -nargs=+ SearchRB call SearchInFileType(<f-args>, 'rb')
command! -nargs=+ SearchGO call SearchInFileType(<f-args>, 'go')
" Usage:
" :SearchJS import
" :SearchPY classShow surrounding lines:
" Show 3 lines before and after matches
:CocSearch -A 3 -B 3 error
" Show 5 lines of context
:CocSearch -x 5 TODO
" Search with custom context mapping
nnoremap <leader>sc :call <SID>SearchWithContext()<CR>
function! s:SearchWithContext() abort
let pattern = input('Search: ')
if empty(pattern)
return
endif
let context = input('Context lines [3]: ')
let context = empty(context) ? 3 : str2nr(context)
execute printf('CocSearch -A %d -B %d %s', context, context, shellescape(pattern))
endfunctionExclude files and directories:
function! SearchExclude(pattern, ...) abort
let cmd = 'CocSearch'
" Add exclusion globs
for exclude in a:000
let cmd .= ' --glob !' . shellescape(exclude)
endfor
let cmd .= ' ' . shellescape(a:pattern)
execute cmd
endfunction
command! -nargs=+ SearchExclude call SearchExclude(<f-args>)
" Usage:
" :SearchExclude TODO '*.min.js' 'node_modules/**' 'dist/**'
" Common exclusions function
function! SearchClean(pattern) abort
call SearchExclude(a:pattern,
\ '*.min.js',
\ '*.min.css',
\ 'node_modules/**',
\ 'dist/**',
\ 'build/**',
\ '.git/**'
\ )
endfunction
command! -nargs=1 SearchClean call SearchClean(<q-args>)Advanced pattern matching:
" Search for pattern with regex
function! RegexSearch(pattern) abort
execute 'CocSearch -e ' . shellescape(a:pattern)
endfunction
command! -nargs=1 RgxSearch call RegexSearch(<q-args>)
" Examples:
" :RgxSearch 'function \w+\('
" :RgxSearch 'class \w+ extends'
" :RgxSearch 'import.*from'
" Common patterns
command! SearchFunctions RgxSearch 'function \w+\s*\('
command! SearchClasses RgxSearch 'class \w+'
command! SearchImports RgxSearch 'import.*from'
command! SearchTODOs RgxSearch 'TODO|FIXME|HACK|XXX|NOTE'Search for multiple patterns:
function! SearchMultiple(...) abort
let results = {}
for pattern in a:000
let output = system('rg --count ' . shellescape(pattern))
let count = 0
for line in split(output, '\n')
let parts = split(line, ':')
if len(parts) >= 2
let count += str2nr(parts[-1])
endif
endfor
let results[pattern] = count
endfor
echo '=== Search Results ==='
for [pattern, count] in items(results)
echo pattern . ': ' . count . ' occurrences'
endfor
endfunction
command! -nargs=+ MultiSearch call SearchMultiple(<f-args>)
" Usage:
" :MultiSearch TODO FIXME HACKCount occurrences and file statistics:
function! CountSearchResults(pattern) abort
let output = system('rg --count ' . shellescape(a:pattern))
let lines = split(output, '\n')
let total = 0
let files = 0
for line in lines
let parts = split(line, ':')
if len(parts) >= 2
let count = str2nr(parts[-1])
if count > 0
let total += count
let files += 1
endif
endif
endfor
echo printf('Found %d occurrences in %d files', total, files)
endfunction
command! -nargs=1 SearchCount call CountSearchResults(<q-args>)
" Search statistics by file type
function! SearchStatsByType(pattern) abort
let types = ['js', 'ts', 'py', 'rb', 'go', 'java', 'c', 'cpp']
let results = {}
echo 'Counting...'
for type in types
let cmd = 'rg --type ' . type . ' --count ' . shellescape(a:pattern)
let output = system(cmd)
let count = 0
for line in split(output, '\n')
let parts = split(line, ':')
if len(parts) >= 2
let count += str2nr(parts[-1])
endif
endfor
if count > 0
let results[type] = count
endif
endfor
echo '=== Results by File Type ==='
for [type, count] in items(results)
echo type . ': ' . count . ' occurrences'
endfor
endfunction
command! -nargs=1 SearchStats call SearchStatsByType(<q-args>)Track recent searches:
let g:search_history = []
function! AddToSearchHistory(pattern) abort
" Don't add duplicates
let idx = index(g:search_history, a:pattern)
if idx >= 0
call remove(g:search_history, idx)
endif
call insert(g:search_history, a:pattern)
" Keep only last 20 searches
if len(g:search_history) > 20
call remove(g:search_history, 20, -1)
endif
endfunction
function! ShowSearchHistory() abort
if len(g:search_history) == 0
echo 'No search history'
return
endif
echo '=== Recent Searches ==='
for i in range(len(g:search_history))
echo (i + 1) . '. ' . g:search_history[i]
endfor
endfunction
command! SearchHistory call ShowSearchHistory()
" Repeat last search
function! RepeatLastSearch() abort
if len(g:search_history) == 0
echo 'No previous search'
return
endif
execute 'CocSearch ' . shellescape(g:search_history[0])
endfunction
command! SearchRepeat call RepeatLastSearch()
nnoremap <leader>sr :SearchRepeat<CR>
" Track CocSearch commands
autocmd CmdlineLeave : if getcmdtype() ==# ':' && getcmdline() =~# '^CocSearch' |
\ let pattern = matchstr(getcmdline(), 'CocSearch\s\+\zs.*') |
\ if !empty(pattern) | call AddToSearchHistory(pattern) | endif |
\ endifSearch only in modified files:
function! SearchInGitModified(pattern) abort
let files = system('git diff --name-only')
let file_list = join(split(files, '\n'), ' ')
if empty(file_list)
echo 'No modified files'
return
endif
execute '!rg ' . shellescape(a:pattern) . ' ' . file_list
endfunction
command! -nargs=1 SearchModified call SearchInGitModified(<q-args>)
" Search in git staged files
function! SearchInGitStaged(pattern) abort
let files = system('git diff --cached --name-only')
let file_list = join(split(files, '\n'), ' ')
if empty(file_list)
echo 'No staged files'
return
endif
execute '!rg ' . shellescape(a:pattern) . ' ' . file_list
endfunction
command! -nargs=1 SearchStaged call SearchInGitStaged(<q-args>)Export search results to file:
function! SaveSearchResults(pattern, filename) abort
let output = system('rg ' . shellescape(a:pattern))
if v:shell_error != 0
echohl ErrorMsg
echo 'Search failed or no results found'
echohl None
return
endif
call writefile(split(output, '\n'), a:filename)
echo 'Search results saved to ' . a:filename
endfunction
command! -nargs=+ SaveSearch call SaveSearchResults(<f-args>)
" Usage:
" :SaveSearch TODO todo-list.txt
" Save with timestamp
function! SaveSearchWithTimestamp(pattern) abort
let timestamp = strftime('%Y%m%d_%H%M%S')
let filename = 'search_' . timestamp . '.txt'
call SaveSearchResults(a:pattern, filename)
endfunction
command! -nargs=1 SaveSearchTS call SaveSearchWithTimestamp(<q-args>)Search based on current context:
function! ContextSearch(pattern) abort
let ft = &filetype
let globs = {
\ 'javascript': '*.{js,jsx}',
\ 'typescript': '*.{ts,tsx}',
\ 'python': '*.py',
\ 'ruby': '*.rb',
\ 'go': '*.go',
\ 'rust': '*.rs',
\ 'java': '*.java'
\ }
if has_key(globs, ft)
execute 'CocSearch --glob ' . shellescape(globs[ft]) . ' ' . shellescape(a:pattern)
else
execute 'CocSearch ' . shellescape(a:pattern)
endif
endfunction
command! -nargs=1 CtxSearch call ContextSearch(<q-args>)
" Map to context search word under cursor
nnoremap <leader>cs :exe 'CtxSearch '.expand('<cword>')<CR>Find all TODO markers:
function! SearchTODOs() abort
execute 'CocSearch -w "TODO\|FIXME\|HACK\|XXX\|NOTE\|BUG"'
endfunction
command! SearchTODOs call SearchTODOs()
nnoremap <leader>st :SearchTODOs<CR>
" By author
function! SearchTODOsByAuthor(author) abort
let pattern = printf('TODO.*%s\|FIXME.*%s', a:author, a:author)
execute 'CocSearch -e ' . shellescape(pattern)
endfunction
command! -nargs=1 SearchMyTODOs call SearchTODOsByAuthor(<q-args>)Verify ripgrep is available:
function! CheckRipgrep() abort
if !executable('rg')
echohl ErrorMsg
echo 'Error: ripgrep (rg) not found in PATH'
echo 'Install from: https://github.com/BurntSushi/ripgrep'
echohl None
return 0
endif
return 1
endfunction
" Check before searching
function! SafeSearch(pattern) abort
if !CheckRipgrep()
return
endif
execute 'CocSearch ' . shellescape(a:pattern)
endfunctionCheck for empty results:
function! SearchWithFeedback(pattern) abort
execute 'CocSearch ' . shellescape(a:pattern)
" Check if results found
let qflist = getqflist()
if empty(qflist)
echohl WarningMsg
echo 'No matches found for: ' . a:pattern
echohl None
else
echo 'Found ' . len(qflist) . ' matches'
endif
endfunctionCheck pattern is valid:
function! ValidatedSearch(pattern) abort
if empty(a:pattern)
echohl ErrorMsg
echo 'Error: empty search pattern'
echohl None
return
endif
" Check for problematic patterns
if a:pattern =~# '^\s*$'
echohl ErrorMsg
echo 'Error: pattern is only whitespace'
echohl None
return
endif
execute 'CocSearch ' . shellescape(a:pattern)
endfunctionProblem: :CocSearch fails with command not found.
Solutions:
Install ripgrep:
# macOS
brew install ripgrep
# Ubuntu/Debian
sudo apt install ripgrep
# Windows
choco install ripgrepVerify installation:
:!rg --versionCheck PATH:
:echo $PATHProblem: Search doesn't find expected files.
Solutions:
Check .gitignore:
" Search hidden/ignored files
:CocSearch --hidden --no-ignore patternVerify glob pattern:
" Test glob
:CocSearch --glob '*.js' importCheck file permissions:
# Ensure files are readable
ls -laProblem: Search returns overwhelming number of results.
Solutions:
Use more specific patterns:
" Whole word only
:CocSearch -w pattern
" Add context to pattern
:CocSearch 'import.*component'Exclude directories:
:CocSearch --glob '!node_modules/**' --glob '!dist/**' patternUse file type filters:
:CocSearch --glob '*.js' patternProblem: Search takes too long in large codebases.
Solutions:
Exclude build artifacts:
{
"list.source.grep.args": [
"--glob", "!node_modules/**",
"--glob", "!dist/**",
"--glob", "!build/**",
"--glob", "!*.min.js"
]
}Use .ignore file:
# Create .ignore in project root
echo "node_modules/" >> .ignore
echo "dist/" >> .ignoreSearch specific directories:
:CocSearch --glob 'src/**/*.js' patternProblem: Regex patterns don't match as expected.
Solutions:
Use -e flag explicitly:
:CocSearch -e 'pattern.*with.*regex'Escape special characters:
:CocSearch 'import \* from'Test regex with ripgrep directly:
rg -e 'your.*pattern'Problem: Search doesn't respect case preferences.
Solutions:
Use smart case:
:CocSearch -S patternForce case insensitive:
:CocSearch -i patternConfigure default in settings:
{
"list.source.grep.args": [
"--smart-case"
]
}