tessl install tessl/npm-coc-nvim@0.0.0LSP based intellisense engine for neovim & vim8.
Complexity: Intermediate | Category: Navigation
Common Tasks: Show outline | Browse symbols | Navigate to function | Display current function
Navigate and view document structure through symbols and outline views.
:CocOutlineToggle document outline in side panel.
let symbols = CocAction('documentSymbols')
for symbol in symbols
echo symbol.kind . ': ' . symbol.name
endforecho get(b:, 'coc_current_function', 'Not in function'):CocList outlineInteractive symbol navigation.
:CocOutlineShow or toggle document outline in a side panel. The outline displays a hierarchical tree of symbols (functions, classes, variables, etc.) in the current file.
Example:
:CocOutline
" Toggle outline
nnoremap <silent> <leader>o :CocOutline<CR>
" Auto-open outline for code files
autocmd FileType python,javascript,typescript CocOutlineCocAction('documentSymbols')
" Returns: listGet list of all symbols in the current document.
Returns: List of symbol objects with properties:
name: Symbol namekind: Symbol kind (Function, Class, Variable, etc.)range: Symbol range (LSP Range object)selectionRange: Selection rangechildren: Child symbols (for hierarchical symbols)detail: Additional symbol detailsExample:
let symbols = CocAction('documentSymbols')
echo 'Found ' . len(symbols) . ' symbols'
for symbol in symbols
echo symbol.kind . ': ' . symbol.name
" Show children
if has_key(symbol, 'children')
for child in symbol.children
echo ' ' . child.kind . ': ' . child.name
endfor
endif
endforCocAction('showOutline', [keep])Show document outline.
Parameters:
keep: Optional boolean - if 1, keep cursor positionExample:
" Show outline
call CocAction('showOutline')
" Show outline and keep cursor
call CocAction('showOutline', 1)
" Map to key
nnoremap <silent> <leader>o :call CocAction('showOutline')<CR>CocAction('hideOutline')Hide document outline panel.
Example:
call CocAction('hideOutline')
" Toggle outline
function! ToggleOutline() abort
if exists('w:coc_outline_shown')
call CocAction('hideOutline')
else
call CocAction('showOutline')
endif
endfunction
nnoremap <silent> <leader>O :call ToggleOutline()<CR>CocAction('selectSymbolRange', inner, mode, kinds)Select range of a symbol.
Parameters:
inner: Boolean - select inner range if 1mode: Visual mode ('v', 'V', or '')kinds: Array of symbol kinds to targetSymbol Kinds:
Function, Method, Class, Interface, EnumVariable, Constant, Property, FieldConstructor, Namespace, ModuleExample:
" Select inner function
call CocAction('selectSymbolRange', 1, 'v', ['Function', 'Method'])
" Select outer class
call CocAction('selectSymbolRange', 0, 'V', ['Class'])
" Text objects for functions
xmap if <Plug>(coc-funcobj-i)
omap if <Plug>(coc-funcobj-i)
xmap af <Plug>(coc-funcobj-a)
omap af <Plug>(coc-funcobj-a)CocAction('getCurrentFunctionSymbol')
" Returns: stringGet the name of the function containing the cursor.
Returns: Function name or empty string.
Example:
let func = CocAction('getCurrentFunctionSymbol')
if !empty(func)
echo 'Current function: ' . func
else
echo 'Not in a function'
endif
" Show in statusline
set statusline+=%{CocAction('getCurrentFunctionSymbol')}b:coc_current_functionRuntime variable containing the name of the current function (function containing cursor).
Type: String (read-only)
Example:
if exists('b:coc_current_function')
echo 'In function: ' . b:coc_current_function
endif
" Add to statusline
function! StatuslineFunction() abort
return get(b:, 'coc_current_function', '')
endfunction
set statusline+=%{StatuslineFunction()}Outline settings in coc-settings.json:
{
"outline.enable": true,
"outline.autoPreview": true,
"outline.detailAsDescription": true,
"outline.followCursor": true,
"outline.sortBy": "position",
"outline.expandLevel": 2,
"outline.checkBufferSwitch": true,
"outline.switchSortKey": "<C-s>",
"coc.preferences.currentFunctionSymbolAutoUpdate": true
}Key Settings:
outline.followCursor: Auto-select symbol at cursoroutline.sortBy: Sort by "position", "name", or "category"outline.expandLevel: Default expansion depth (0 = collapsed)outline.autoPreview: Preview symbol on selectionCocTreeTitleHighlight for outline tree title.
Example:
highlight CocTreeTitle guifg=#61afef gui=boldCocTreeDescriptionHighlight for outline tree descriptions.
CocTreeOpenCloseHighlight for outline tree expand/collapse icons.
CocTreeSelectedHighlight for selected outline item.
Example:
highlight CocTreeSelected guibg=#3e4452" Toggle outline
nnoremap <silent> <leader>o :CocOutline<CR>
" Close outline
nnoremap <silent> <leader>O :call CocAction('hideOutline')<CR>
" Show outline on specific filetypes
autocmd FileType python,javascript,typescript,rust,go silent! CocOutlinefunction! ShowSymbols() abort
let symbols = CocAction('documentSymbols')
if len(symbols) == 0
echo "No symbols found"
return
endif
echo "=== Document Symbols ==="
for symbol in symbols
echo symbol.kind . ': ' . symbol.name
" Show children
if has_key(symbol, 'children')
for child in symbol.children
echo ' ' . child.kind . ': ' . child.name
endfor
endif
endfor
endfunction
command! ShowSymbols call ShowSymbols()function! GetSymbolsByKind(kind) abort
let all_symbols = CocAction('documentSymbols')
let filtered = []
function! FilterRecursive(symbols, kind, results) abort
for symbol in a:symbols
if symbol.kind ==# a:kind
call add(a:results, symbol)
endif
if has_key(symbol, 'children')
call FilterRecursive(symbol.children, a:kind, a:results)
endif
endfor
endfunction
call FilterRecursive(all_symbols, a:kind, filtered)
return filtered
endfunction
function! ShowFunctions() abort
let functions = GetSymbolsByKind('Function')
echo len(functions) . ' functions:'
for func in functions
echo ' - ' . func.name
endfor
endfunction
function! ShowClasses() abort
let classes = GetSymbolsByKind('Class')
echo len(classes) . ' classes:'
for class in classes
echo ' - ' . class.name
endfor
endfunction
command! ShowFunctions call ShowFunctions()
command! ShowClasses call ShowClasses()
command! ShowMethods call GetSymbolsByKind('Method')function! StatuslineFunction() abort
if !exists('b:coc_current_function')
return ''
endif
return '[' . b:coc_current_function . ']'
endfunction
set statusline+=%{StatuslineFunction()}
" Enable auto-update
let g:coc_user_config = {
\ 'coc.preferences.currentFunctionSymbolAutoUpdate': v:true
\ }
" Lightline integration
let g:lightline = {
\ 'active': {
\ 'right': [['coc_current_function'], ['lineinfo']]
\ },
\ 'component_function': {
\ 'coc_current_function': 'StatuslineFunction'
\ }
\ }function! NavigateToSymbol(name) abort
let symbols = CocAction('documentSymbols')
function! FindSymbol(syms, name) abort
for symbol in a:syms
if symbol.name ==# a:name
return symbol
endif
if has_key(symbol, 'children')
let found = FindSymbol(symbol.children, a:name)
if found isnot v:null
return found
endif
endif
endfor
return v:null
endfunction
let symbol = FindSymbol(symbols, a:name)
if symbol isnot v:null
let range = symbol.selectionRange
let line = range.start.line + 1
let col = range.start.character + 1
call cursor(line, col)
normal! zz
echo 'Navigated to ' . a:name
else
echo 'Symbol not found: ' . a:name
endif
endfunction
command! -nargs=1 NavSymbol call NavigateToSymbol(<q-args>)function! BuildSymbolTree(symbols, indent) abort
let lines = []
for symbol in a:symbols
let line = repeat(' ', a:indent) . symbol.kind . ': ' . symbol.name
if has_key(symbol, 'detail') && !empty(symbol.detail)
let line .= ' (' . symbol.detail . ')'
endif
call add(lines, line)
if has_key(symbol, 'children') && len(symbol.children) > 0
let child_lines = BuildSymbolTree(symbol.children, a:indent + 1)
call extend(lines, child_lines)
endif
endfor
return lines
endfunction
function! ShowSymbolTree() abort
let symbols = CocAction('documentSymbols')
let tree = BuildSymbolTree(symbols, 0)
echo "=== Symbol Tree ==="
for line in tree
echo line
endfor
endfunction
command! SymbolTree call ShowSymbolTree()" Jump to next/previous function
function! NextFunction() abort
let functions = GetSymbolsByKind('Function')
call extend(functions, GetSymbolsByKind('Method'))
let current_line = line('.')
for func in functions
let func_line = func.range.start.line + 1
if func_line > current_line
call cursor(func_line, 1)
normal! zz
echo 'Jumped to: ' . func.name
return
endif
endfor
echo 'No next function'
endfunction
function! PrevFunction() abort
let functions = GetSymbolsByKind('Function')
call extend(functions, GetSymbolsByKind('Method'))
let current_line = line('.')
let target = v:null
for func in functions
let func_line = func.range.start.line + 1
if func_line < current_line
let target = func
else
break
endif
endfor
if target isnot v:null
let func_line = target.range.start.line + 1
call cursor(func_line, 1)
normal! zz
echo 'Jumped to: ' . target.name
else
echo 'No previous function'
endif
endfunction
nnoremap <silent> ]f :call NextFunction()<CR>
nnoremap <silent> [f :call PrevFunction()<CR>
nnoremap <silent> ]c :call GetSymbolsByKind('Class') | NextClass()<CR>
nnoremap <silent> [c :call GetSymbolsByKind('Class') | PrevClass()<CR>function! SymbolStats() abort
let symbols = CocAction('documentSymbols')
let stats = {}
function! CountSymbols(syms, dict) abort
for sym in a:syms
let kind = sym.kind
if !has_key(a:dict, kind)
let a:dict[kind] = 0
endif
let a:dict[kind] += 1
if has_key(sym, 'children')
call CountSymbols(sym.children, a:dict)
endif
endfor
endfunction
call CountSymbols(symbols, stats)
echo "=== Symbol Statistics ==="
echo "Total: " . len(symbols)
echo ""
for [kind, count] in sort(items(stats))
echo printf("%-15s: %d", kind, count)
endfor
endfunction
command! SymbolStats call SymbolStats()" Auto-refresh outline on buffer changes
augroup AutoOutline
autocmd!
autocmd BufWritePost * if exists('*CocAction') | call CocAction('showOutline', 1) | endif
autocmd CursorHold * if exists('b:coc_current_function') | echo b:coc_current_function | endif
augroup ENDfunction! SearchSymbol(pattern) abort
let symbols = CocAction('documentSymbols')
let matches = []
function! SearchInSymbols(syms, pat, results) abort
for sym in a:syms
if sym.name =~? a:pat
call add(a:results, sym)
endif
if has_key(sym, 'children')
call SearchInSymbols(sym.children, a:pat, a:results)
endif
endfor
endfunction
call SearchInSymbols(symbols, a:pattern, matches)
if len(matches) == 0
echo 'No symbols matching: ' . a:pattern
return
endif
echo len(matches) . ' symbols found:'
for match in matches
echo match.kind . ': ' . match.name
let line = match.range.start.line + 1
echo ' Line ' . line
endfor
endfunction
command! -nargs=1 SymbolSearch call SearchSymbol(<q-args>)function! GetSymbolBreadcrumb() abort
let symbols = CocAction('documentSymbols')
let current_line = line('.')
let breadcrumb = []
function! FindContainingSymbol(syms, line, crumbs) abort
for sym in a:syms
let start = sym.range.start.line + 1
let end = sym.range.end.line + 1
if a:line >= start && a:line <= end
call add(a:crumbs, sym.name)
if has_key(sym, 'children')
call FindContainingSymbol(sym.children, a:line, a:crumbs)
endif
endif
endfor
endfunction
call FindContainingSymbol(symbols, current_line, breadcrumb)
return join(breadcrumb, ' > ')
endfunction
function! ShowBreadcrumb() abort
let breadcrumb = GetSymbolBreadcrumb()
if !empty(breadcrumb)
echo breadcrumb
else
echo 'Not in any symbol'
endif
endfunction
nnoremap <silent> <leader>sb :call ShowBreadcrumb()<CR>
" Add to statusline
set statusline+=%{GetSymbolBreadcrumb()}function! ExportSymbols(filename) abort
let symbols = CocAction('documentSymbols')
let lines = BuildSymbolTree(symbols, 0)
" Add header
call insert(lines, 'File: ' . expand('%:p'), 0)
call insert(lines, 'Generated: ' . strftime('%Y-%m-%d %H:%M:%S'), 1)
call insert(lines, '', 2)
call writefile(lines, a:filename)
echo 'Symbols exported to ' . a:filename
endfunction
command! -nargs=1 -complete=file ExportSymbols call ExportSymbols(<q-args>)If documentSymbols returns empty:
let symbols = CocAction('documentSymbols')
if len(symbols) == 0
echo "No symbols available"
echo "Possible reasons:"
echo "- Language server not running"
echo "- File type not supported"
echo "- Document not yet parsed"
endifCheck if LSP supports document symbols:
if CocHasProvider('documentSymbol')
let symbols = CocAction('documentSymbols')
else
echo "Current language server doesn't support document symbols"
endifProblem: :CocOutline doesn't display anything.
Solutions:
echo CocHasProvider('documentSymbol')call CocAction('ensureDocument'):CocOpenLog:CocRestartProblem: b:coc_current_function doesn't update.
Solutions:
"coc.preferences.currentFunctionSymbolAutoUpdate": trueecho exists('b:coc_current_function')call CocAction('getCurrentFunctionSymbol')Problem: Symbol operations are sluggish.
Solutions:
"outline.expandLevel": 1"outline.autoPreview": false"outline.followCursor": falseProblem: Outline shows incorrect or outdated symbols.
Solutions:
:CocOutline (toggle):CocRestart