tessl install tessl/npm-coc-nvim@0.0.0LSP based intellisense engine for neovim & vim8.
Complexity: Intermediate | Category: Reference | Keywords: autocmd, events, hooks, integration, callbacks
Common Tasks: Initialize on startup | Update statusline | Handle diagnostics | Track navigation | Respond to UI events
Integration points via User autocmd events for responding to coc.nvim lifecycle and state changes. Use these events to customize behavior and integrate with other plugins.
autocmd User CocNvimInit call MyInitFunction()Execute custom setup after coc.nvim starts.
autocmd User CocStatusChange,CocDiagnosticChange call lightline#update()Refresh statusline when status or diagnostics change.
autocmd User CocJumpPlaceholder call CocActionAsync('showSignatureHelp')Display signature help when jumping between snippet placeholders.
autocmd User CocLocationsChange CocList --normal locationOpen location list when jump results are available.
autocmd User CocOpenFloat autocmd CursorMoved * ++once call coc#float#close_all()Automatically close floating windows when cursor moves.
autocmd User CocNvimInit {command}Triggered when coc.nvim has finished initializing and is ready for use.
When Triggered: After service startup completes
Use Cases:
Example:
autocmd User CocNvimInit call s:CocInit()
function! s:CocInit() abort
echo 'Coc initialized'
" Register custom commands
call coc#add_command('mycommand', 'echo "Hello"', 'My custom command')
" Configure settings
call coc#config('suggest.noselect', v:true)
call coc#config('diagnostic.errorSign', '✗')
" Enable extensions
call coc#add_extension('coc-json', 'coc-tsserver')
endfunctionIntegration Examples:
" Initialize custom features
autocmd User CocNvimInit call InitMyFeatures()
" Set up buffer-local mappings
autocmd User CocNvimInit autocmd FileType * call SetupCocMappings()
" Start tracking coc state
autocmd User CocNvimInit let g:coc_ready = 1autocmd User CocStatusChange {command}Triggered when the status string (g:coc_status) changes.
When Triggered: Status line text updates (extension messages, loading indicators)
Use Cases:
Example:
" Lightline integration
autocmd User CocStatusChange call lightline#update()
" Airline integration
autocmd User CocStatusChange call airline#update_statusline()
" Custom statusline (force redraw)
autocmd User CocStatusChange let &ro = &ro
" Log status changes
autocmd User CocStatusChange call s:LogStatus()
function! s:LogStatus() abort
let status = get(g:, 'coc_status', '')
if !empty(status)
echom strftime('%H:%M:%S') . ' - Coc: ' . status
endif
endfunctionStatusline Functions:
function! CocStatusline() abort
let status = get(g:, 'coc_status', '')
let func = get(b:, 'coc_current_function', '')
let parts = []
if !empty(func)
call add(parts, func)
endif
if !empty(status)
call add(parts, status)
endif
return join(parts, ' ')
endfunction
autocmd User CocStatusChange call lightline#update()autocmd User CocDiagnosticChange {command}Triggered when diagnostics are updated for any buffer.
When Triggered:
Use Cases:
Example:
autocmd User CocDiagnosticChange call s:UpdateDiagnostics()
function! s:UpdateDiagnostics() abort
let info = get(b:, 'coc_diagnostic_info', {})
let errors = get(info, 'error', 0)
let warnings = get(info, 'warning', 0)
" Show notification for new errors
if errors > 0
echohl ErrorMsg
echo printf('Errors: %d', errors)
echohl None
endif
" Update statusline
let &ro = &ro
endfunctionDiagnostic Tracking:
" Track diagnostic history
let g:diagnostic_history = []
autocmd User CocDiagnosticChange call s:TrackDiagnostics()
function! s:TrackDiagnostics() abort
let info = get(b:, 'coc_diagnostic_info', {})
call add(g:diagnostic_history, {
\ 'time': strftime('%H:%M:%S'),
\ 'buffer': bufnr('%'),
\ 'errors': get(info, 'error', 0),
\ 'warnings': get(info, 'warning', 0)
\ })
" Keep only last 100 entries
if len(g:diagnostic_history) > 100
call remove(g:diagnostic_history, 0, len(g:diagnostic_history) - 100)
endif
endfunction
command! DiagnosticHistory echo g:diagnostic_historyNotification Example:
let g:diagnostic_notify_threshold = 5
autocmd User CocDiagnosticChange call s:NotifyDiagnostics()
function! s:NotifyDiagnostics() abort
let info = get(b:, 'coc_diagnostic_info', {})
let errors = get(info, 'error', 0)
if errors >= g:diagnostic_notify_threshold
echohl ErrorMsg
echo printf('Warning: %d errors in current buffer!', errors)
echohl None
endif
endfunctionautocmd User CocLocationsChange {command}Triggered when the location list is updated after jump operations (definition, references, etc.).
When Triggered:
:CocList locationUse Cases:
Example:
autocmd User CocLocationsChange call s:HandleLocations()
function! s:HandleLocations() abort
let locations = get(g:, 'coc_jump_locations', [])
if len(locations) > 1
" Multiple locations - open location list
CocList --normal location
elseif len(locations) == 1
" Single location - already jumped
echo 'Jumped to single location'
else
" No locations found
echo 'No locations found'
endif
endfunctionAuto-Open Location List:
" Always open location list for multiple results
autocmd User CocLocationsChange call s:AutoLocationList()
function! s:AutoLocationList() abort
let locations = get(g:, 'coc_jump_locations', [])
if len(locations) > 1
" Show in location list with preview
CocList --normal location
echo printf('Found %d locations', len(locations))
endif
endfunctionNavigation History:
let g:coc_nav_history = []
autocmd User CocLocationsChange call s:TrackNavigation()
function! s:TrackNavigation() abort
let locations = get(g:, 'coc_jump_locations', [])
call add(g:coc_nav_history, {
\ 'time': strftime('%H:%M:%S'),
\ 'count': len(locations),
\ 'file': expand('%:p')
\ })
" Keep last 50
if len(g:coc_nav_history) > 50
call remove(g:coc_nav_history, 0, len(g:coc_nav_history) - 50)
endif
endfunction
command! NavHistory echo g:coc_nav_historyautocmd User CocJumpPlaceholder {command}Triggered when jumping to a snippet placeholder.
When Triggered:
coc#snippet#next() or coc#snippet#prev() calledUse Cases:
Example:
" Auto-show signature help in function parameters
autocmd User CocJumpPlaceholder call CocActionAsync('showSignatureHelp')
" Or with condition
autocmd User CocJumpPlaceholder call s:OnPlaceholderJump()
function! s:OnPlaceholderJump() abort
" Show signature help if available
if CocAction('hasProvider', 'signature')
call CocActionAsync('showSignatureHelp')
endif
" Or trigger completion
" call coc#refresh()
endfunctionAdvanced Snippet Handling:
autocmd User CocJumpPlaceholder call s:SnippetJump()
function! s:SnippetJump() abort
" Show signature help for function parameters
if CocAction('hasProvider', 'signature')
call CocActionAsync('showSignatureHelp')
endif
" Auto-trigger completion if not whitespace
if col('.') > 1 && getline('.')[col('.')-2] !~# '\s'
call coc#refresh()
endif
" Update statusline
let &ro = &ro
endfunctionSnippet Tracking:
let g:snippet_jump_count = 0
autocmd User CocJumpPlaceholder let g:snippet_jump_count += 1
" Show count in statusline
function! SnippetInfo()
if get(b:, 'coc_snippet_active', 0)
return printf('Snippet [%d]', g:snippet_jump_count)
endif
return ''
endfunctionautocmd User CocOpenFloat {command}Triggered when a floating window is opened.
When Triggered:
Use Cases:
Example:
autocmd User CocOpenFloat call s:OnFloatOpen()
function! s:OnFloatOpen() abort
" Get window ID
let winid = get(g:, 'coc_last_float_win', 0)
if winid > 0
" Add custom mappings if needed
" Or customize appearance
echo 'Float window opened: ' . winid
endif
endfunctionAuto-Close Float:
" Close float on cursor move
autocmd User CocOpenFloat call s:AutoCloseFloat()
function! s:AutoCloseFloat() abort
augroup CocFloatAutoClose
autocmd!
autocmd CursorMoved,CursorMovedI * ++once call coc#float#close_all()
augroup END
endfunction
" Or close after timeout
autocmd User CocOpenFloat call timer_start(5000, {-> coc#float#close_all()})Float Scroll Mappings:
autocmd User CocOpenFloat call s:FloatScroll()
function! s:FloatScroll() abort
let winid = get(g:, 'coc_last_float_win', 0)
if winid > 0 && nvim_win_is_valid(winid)
" Add scroll mappings
nnoremap <silent><nowait><buffer> <C-f> :call coc#float#scroll(1)<CR>
nnoremap <silent><nowait><buffer> <C-b> :call coc#float#scroll(0)<CR>
endif
endfunctionautocmd User CocOpenFloatPrompt {command}Triggered when a prompt floating window is opened.
When Triggered:
Use Cases:
Example:
autocmd User CocOpenFloatPrompt call s:OnPromptOpen()
function! s:OnPromptOpen() abort
echo 'Prompt window opened'
" Could add custom prompt handling here
" Or validation logic
endfunctionPrompt Enhancement:
autocmd User CocOpenFloatPrompt call s:EnhancePrompt()
function! s:EnhancePrompt() abort
" Enable autocomplete in prompt if needed
" Or add custom validation
let winid = get(g:, 'coc_last_float_win', 0)
if winid > 0
" Customize prompt window
endif
endfunctionautocmd User CocTerminalOpen {command}Triggered when a coc terminal window is opened.
When Triggered:
Use Cases:
Example:
autocmd User CocTerminalOpen call s:ConfigureTerminal()
function! s:ConfigureTerminal() abort
" Enter insert mode in terminal
if &buftype ==# 'terminal'
startinsert
endif
" Set terminal-specific mappings
tnoremap <buffer> <Esc> <C-\><C-n>
tnoremap <buffer> <C-w> <C-\><C-n><C-w>
endfunctionAdvanced Terminal Setup:
autocmd User CocTerminalOpen call s:SetupTerminal()
function! s:SetupTerminal() abort
if &buftype !=# 'terminal'
return
endif
" Enter insert mode
startinsert
" Terminal mappings
tnoremap <buffer> <Esc> <C-\><C-n>
tnoremap <buffer> <C-w> <C-\><C-n><C-w>
tnoremap <buffer> <C-q> <C-\><C-n>:close<CR>
" Auto-close on exit
autocmd BufLeave <buffer> if &buftype ==# 'terminal' | close | endif
" Track terminal
let g:coc_terminal_count = get(g:, 'coc_terminal_count', 0) + 1
endfunctionFull integration with all events:
augroup CocEvents
autocmd!
" Initialization
autocmd User CocNvimInit call s:CocInit()
" Status updates
autocmd User CocStatusChange call s:UpdateStatus()
autocmd User CocDiagnosticChange call s:UpdateDiagnostics()
" Navigation
autocmd User CocLocationsChange call s:HandleLocations()
" Snippets
autocmd User CocJumpPlaceholder call CocActionAsync('showSignatureHelp')
" UI
autocmd User CocOpenFloat call s:OnFloatOpen()
autocmd User CocOpenFloatPrompt call s:OnPromptOpen()
autocmd User CocTerminalOpen call s:ConfigureTerminal()
augroup END
function! s:CocInit() abort
echo 'Coc initialized'
call coc#config('suggest.noselect', v:true)
endfunction
function! s:UpdateStatus() abort
call lightline#update()
endfunction
function! s:UpdateDiagnostics() abort
let &ro = &ro
endfunction
function! s:HandleLocations() abort
let count = len(get(g:, 'coc_jump_locations', []))
if count > 1
CocList --normal location
endif
endfunction
function! s:OnFloatOpen() abort
" Auto-close on cursor move
augroup CocFloatAutoClose
autocmd!
autocmd CursorMoved * ++once call coc#float#close_all()
augroup END
endfunction
function! s:OnPromptOpen() abort
" Prompt customization
endfunction
function! s:ConfigureTerminal() abort
if &buftype ==# 'terminal'
startinsert
endif
endfunctionComplete statusline with all events:
function! CocStatusline() abort
let status = get(g:, 'coc_status', '')
let info = get(b:, 'coc_diagnostic_info', {})
let func = get(b:, 'coc_current_function', '')
let msgs = []
" Diagnostic counts
if get(info, 'error', 0)
call add(msgs, 'E:' . info.error)
endif
if get(info, 'warning', 0)
call add(msgs, 'W:' . info.warning)
endif
" Current function
if !empty(func)
call add(msgs, func)
endif
" Service status
if !empty(status)
call add(msgs, status)
endif
return join(msgs, ' ')
endfunction
" Update on any change
autocmd User CocStatusChange,CocDiagnosticChange call lightline#update()
" Lightline component
let g:lightline = {
\ 'component_function': {
\ 'coc_status': 'CocStatusline'
\ }
\ }Debug helper to log all events:
let g:coc_event_log = []
function! LogCocEvent(event) abort
call add(g:coc_event_log, {
\ 'event': a:event,
\ 'time': strftime('%H:%M:%S'),
\ 'buffer': bufnr('%'),
\ 'file': expand('%:t')
\ })
" Keep only last 100 events
if len(g:coc_event_log) > 100
call remove(g:coc_event_log, 0, len(g:coc_event_log) - 100)
endif
" Optional: echo events
" echo a:event . ' at ' . strftime('%H:%M:%S')
endfunction
augroup CocEventLogger
autocmd!
autocmd User CocNvimInit call LogCocEvent('Init')
autocmd User CocStatusChange call LogCocEvent('StatusChange')
autocmd User CocDiagnosticChange call LogCocEvent('DiagnosticChange')
autocmd User CocLocationsChange call LogCocEvent('LocationsChange')
autocmd User CocJumpPlaceholder call LogCocEvent('JumpPlaceholder')
autocmd User CocOpenFloat call LogCocEvent('OpenFloat')
autocmd User CocOpenFloatPrompt call LogCocEvent('OpenFloatPrompt')
autocmd User CocTerminalOpen call LogCocEvent('TerminalOpen')
augroup END
command! CocEventLog call s:ShowEventLog()
function! s:ShowEventLog() abort
echo '=== Coc Event Log ==='
for entry in g:coc_event_log
echo printf('[%s] %s in %s', entry.time, entry.event, entry.file)
endfor
endfunctionInitialize based on context:
autocmd User CocNvimInit call s:ConditionalInit()
function! s:ConditionalInit() abort
let ft = &filetype
" Filetype-specific settings
if index(['javascript', 'typescript', 'python'], ft) >= 0
call coc#config('suggest.autoTrigger', 'always')
call coc#config('diagnostic.refreshOnInsertMode', v:true)
else
call coc#config('suggest.autoTrigger', 'trigger')
call coc#config('diagnostic.refreshOnInsertMode', v:false)
endif
" Project-specific settings
if filereadable('.coc-config.vim')
source .coc-config.vim
endif
endfunctionPrevent excessive updates:
let g:status_timer = -1
let g:diagnostic_timer = -1
autocmd User CocStatusChange call s:DebouncedStatusUpdate()
autocmd User CocDiagnosticChange call s:DebouncedDiagnosticUpdate()
function! s:DebouncedStatusUpdate() abort
if g:status_timer != -1
call timer_stop(g:status_timer)
endif
let g:status_timer = timer_start(100, {-> s:UpdateStatusUI()})
endfunction
function! s:DebouncedDiagnosticUpdate() abort
if g:diagnostic_timer != -1
call timer_stop(g:diagnostic_timer)
endif
let g:diagnostic_timer = timer_start(500, {-> s:UpdateDiagnosticUI()})
endfunction
function! s:UpdateStatusUI() abort
let g:status_timer = -1
call lightline#update()
endfunction
function! s:UpdateDiagnosticUI() abort
let g:diagnostic_timer = -1
let &ro = &ro
endfunctionVerify coc is ready:
function! SafeEventHandler() abort
if !get(g:, 'coc_service_initialized', 0)
return
endif
" Handle event
endfunction
autocmd User CocStatusChange call SafeEventHandler()Wrap event handlers:
function! SafeCall(func) abort
try
call call(a:func, [])
catch
echohl ErrorMsg
echo 'Error in ' . a:func . ': ' . v:exception
echohl None
endtry
endfunction
autocmd User CocNvimInit call SafeCall('s:CocInit')Check before using state:
function! UpdateStatus() abort
" Check service is ready
if !exists('g:did_coc_loaded')
return
endif
" Check variable exists
let status = get(g:, 'coc_status', '')
if empty(status)
return
endif
" Update
call lightline#update()
endfunctionProblem: Autocmd events don't trigger.
Solutions:
Check coc is loaded:
:echo exists('g:did_coc_loaded')Verify event name is correct:
" Correct
autocmd User CocNvimInit echo 'Init'
" Wrong
autocmd User CocInit echo 'Init'Check service is initialized:
:echo get(g:, 'coc_service_initialized', 0)Problem: Statusline doesn't refresh on events.
Solutions:
Force redraw:
autocmd User CocStatusChange let &ro = &roUse plugin refresh:
" Lightline
autocmd User CocStatusChange call lightline#update()
" Airline
autocmd User CocStatusChange call airline#update_statusline()Add delay if needed:
autocmd User CocStatusChange call timer_start(50, {-> lightline#update()})Problem: Events trigger excessively causing performance issues.
Solutions:
Use debouncing:
let g:update_timer = -1
function! DebouncedUpdate()
if g:update_timer != -1
call timer_stop(g:update_timer)
endif
let g:update_timer = timer_start(200, {-> lightline#update()})
endfunction
autocmd User CocStatusChange call DebouncedUpdate()Check if update is needed:
let g:last_status = ''
function! UpdateIfChanged()
let status = get(g:, 'coc_status', '')
if status !=# g:last_status
let g:last_status = status
call lightline#update()
endif
endfunctionProblem: Float windows don't close on cursor move.
Solutions:
Use ++once flag:
autocmd User CocOpenFloat autocmd CursorMoved * ++once call coc#float#close_all()Use separate augroup:
autocmd User CocOpenFloat call s:AutoClose()
function! s:AutoClose()
augroup CocFloatClose
autocmd!
autocmd CursorMoved * call coc#float#close_all()
autocmd CursorMoved * autocmd! CocFloatClose
augroup END
endfunctionProblem: Terminal opens but stays in normal mode.
Solutions:
Use startinsert with delay:
autocmd User CocTerminalOpen call timer_start(10, {-> execute('startinsert')})Check buffer type:
autocmd User CocTerminalOpen call s:TerminalInsert()
function! s:TerminalInsert()
if &buftype ==# 'terminal'
startinsert
endif
endfunction