coc.nvim icon indicating copy to clipboard operation
coc.nvim copied to clipboard

Add support for object movement

Open JS-Zheng opened this issue 3 years ago • 3 comments

Is your feature request related to a problem? Please describe. I'm always frustrated on object (e.g., function, method, class) movements in Vim, Vim has ]], [[,..., ]m mappings; however it's very weak and only suit on some limited cases. I know CoC provides :CocCommand document.jumpToPrevSymbol, but it only works on variable-like symbols.

Describe the solution you'd like Provide some commands or actions or mappings to jump to next object, for example:

" users may map to `]f`
:CocCommand document.jumpToNextFunction

" users may map to `]m` 
" (I think CoC can provide better version than Vim's)
:CocCommand document.jumpToNextMethod 

" users may map to `]c`
:CocCommand document.jumpToNextClass

" users may map to `]n`
:CocCommand document.jumpToNextNamespace

I thinks it will be very useful and more convenient than moving by outline list/window.

JS-Zheng avatar Oct 19 '22 17:10 JS-Zheng

I have wrote a next/prev-function function for C; however it cannot works in C++ or Java, which may need LSP/AST-support to parse syntax (e.g., namespace, class, sub-class, macro-expanded function):

" @param is_visual
function! utils#next_func(...) abort
  let is_visual = a:0 > 0 ? a:1 : 0

  " Save the cursor position
  let saved_cursor = getcurpos()
  execute "normal! m'"

  if (is_visual)
    execute "normal! gv"
  endif

  call searchpair('{', '', '}', 'rW', function('utils#c_pair_skip'))

  let ret = search('{', 'W', 0, 500, function('utils#c_pair_skip'))
  if (!ret)
    echohl WarningMsg | echo "Can't find next function" | echohl None
    " Restore the cursor position
    call cursor(saved_cursor[1:])
    if (is_visual)
      execute "normal! gv"
    endif
  endif

  return ret
endfunction


" Adapt from:
" plugin/matchparen.vim
function! utils#get_syntax_name_stack() abort
  let line = line('.')
  let col = col('.')
  let syntax_stack = synstack(line, col)
  return map(syntax_stack, 'synIDattr(v:val, "name")')
endfunction


function! utils#c_pair_skip() abort
  let syntax_name_stack = utils#get_syntax_name_stack()
  let filtered_stack = filter(syntax_name_stack, 'v:val =~? "string\\|character\\|singlequote\\|escape\\|symbol\\|comment"')
  return !empty(filtered_stack)
endfunction

JS-Zheng avatar Oct 19 '22 17:10 JS-Zheng

The LSP don't provide information for AST, but only select ranges from symbols, you should use something based on treesister, like nvim-treesitter

chemzqm avatar Oct 20 '22 06:10 chemzqm

Yes, I know LSP doesn’t provide AST, I mean this feature need LSP or AST support 😅

IMHO, LSP provides outline feature, so maybe this feature can based on it to implement?

JS-Zheng avatar Oct 20 '22 06:10 JS-Zheng