or run

tessl search
Log in

Version

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/coc.nvim@0.0.x

docs

index.md
tile.json

tessl/npm-coc-nvim

tessl install tessl/npm-coc-nvim@0.0.0

LSP based intellisense engine for neovim & vim8.

symbols-outline.mddocs/navigation/

Symbols & Outline [Intermediate]

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.

Table of Contents

  • Common Tasks
  • Commands
  • CocAction API
  • Buffer Variables
  • Configuration
  • Highlight Groups
  • Examples
  • Error Handling
  • Troubleshooting
  • See Also

Common Tasks

Show Document Outline

:CocOutline

Toggle document outline in side panel.

Get Document Symbols

let symbols = CocAction('documentSymbols')
for symbol in symbols
  echo symbol.kind . ': ' . symbol.name
endfor

Show Current Function

echo get(b:, 'coc_current_function', 'Not in function')

Navigate to Symbol

:CocList outline

Interactive symbol navigation.

Commands

:CocOutline

:CocOutline

Show 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 CocOutline

CocAction API

documentSymbols

CocAction('documentSymbols')
" Returns: list

Get list of all symbols in the current document.

Returns: List of symbol objects with properties:

  • name: Symbol name
  • kind: Symbol kind (Function, Class, Variable, etc.)
  • range: Symbol range (LSP Range object)
  • selectionRange: Selection range
  • children: Child symbols (for hierarchical symbols)
  • detail: Additional symbol details

Example:

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
endfor

showOutline

CocAction('showOutline', [keep])

Show document outline.

Parameters:

  • keep: Optional boolean - if 1, keep cursor position

Example:

" 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>

hideOutline

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>

selectSymbolRange

CocAction('selectSymbolRange', inner, mode, kinds)

Select range of a symbol.

Parameters:

  • inner: Boolean - select inner range if 1
  • mode: Visual mode ('v', 'V', or '')
  • kinds: Array of symbol kinds to target

Symbol Kinds:

  • Function, Method, Class, Interface, Enum
  • Variable, Constant, Property, Field
  • Constructor, Namespace, Module

Example:

" 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)

getCurrentFunctionSymbol

CocAction('getCurrentFunctionSymbol')
" Returns: string

Get 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')}

Buffer Variables

b:coc_current_function

b:coc_current_function

Runtime 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()}

Configuration

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 cursor
  • outline.sortBy: Sort by "position", "name", or "category"
  • outline.expandLevel: Default expansion depth (0 = collapsed)
  • outline.autoPreview: Preview symbol on selection

Highlight Groups

CocTreeTitle

CocTreeTitle

Highlight for outline tree title.

Example:

highlight CocTreeTitle guifg=#61afef gui=bold

CocTreeDescription

CocTreeDescription

Highlight for outline tree descriptions.

CocTreeOpenClose

CocTreeOpenClose

Highlight for outline tree expand/collapse icons.

CocTreeSelected

CocTreeSelected

Highlight for selected outline item.

Example:

highlight CocTreeSelected guibg=#3e4452

Examples

Basic Outline Usage

" 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! CocOutline

Show Symbol List

function! 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()

Filter Symbols by Kind

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')

Current Function in Statusline

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'
  \ }
  \ }

Navigate to Symbol

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>)

Symbol Tree Builder

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()

Quick Symbol Jump

" 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>

Symbol Statistics

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-Update Outline

" 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 END

Symbol Search

function! 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>)

Symbol Breadcrumb

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()}

Export Symbols

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>)

Error Handling

No Symbols Available

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"
endif

Language Server Not Supporting Symbols

Check if LSP supports document symbols:

if CocHasProvider('documentSymbol')
  let symbols = CocAction('documentSymbols')
else
  echo "Current language server doesn't support document symbols"
endif

Troubleshooting

Outline Not Showing

Problem: :CocOutline doesn't display anything.

Solutions:

  1. Check if language server supports symbols: echo CocHasProvider('documentSymbol')
  2. Verify file is attached: call CocAction('ensureDocument')
  3. Check logs: :CocOpenLog
  4. Try refreshing: Close and reopen outline
  5. Restart language server: :CocRestart

Current Function Not Updating

Problem: b:coc_current_function doesn't update.

Solutions:

  1. Enable auto-update: "coc.preferences.currentFunctionSymbolAutoUpdate": true
  2. Check if variable exists: echo exists('b:coc_current_function')
  3. Manually trigger: call CocAction('getCurrentFunctionSymbol')
  4. Verify language server supports symbols

Symbol Navigation Slow

Problem: Symbol operations are sluggish.

Solutions:

  1. Reduce outline expand level: "outline.expandLevel": 1
  2. Disable auto-preview: "outline.autoPreview": false
  3. Check document size (large files may be slow)
  4. Disable follow cursor: "outline.followCursor": false

Wrong Symbols Displayed

Problem: Outline shows incorrect or outdated symbols.

Solutions:

  1. Save file to trigger refresh
  2. Manually refresh outline: :CocOutline (toggle)
  3. Check if file has syntax errors
  4. Restart language server: :CocRestart

See Also

  • Code Navigation - Jump to symbol definitions
  • Call Hierarchy - View function call relationships
  • Workspace - Workspace-wide symbol search
  • List Interface - Using CocList for symbol browsing