prabirshrestha / vim-lsp

async language server protocol plugin for vim and neovim
MIT License
3.14k stars 305 forks source link

LspDefinition hook #49

Closed jacwah closed 4 years ago

jacwah commented 7 years ago

I would like to create a script with a goto-stack like what's built in for ctags. To do this, I would be great to have a way to tell programmatically if LspDefinition/lsp#ui#vim#definition succeeded or not, e.g. an on_success callback.

If you're interested, I'll create a PR proposal.

prabirshrestha commented 7 years ago

This is something I have always wanted to have.

Currently the internal APIs are not locked so I would only depend on commands and not functions. But if you can create a generic tag stack it should be easy to just call push and pop easily.

jacwah commented 7 years ago

How will I know if LspDefinition succeeds using only commands?

prabirshrestha commented 7 years ago

@jacwah You need to update this file which will automatically set tags. https://github.com/prabirshrestha/vim-lsp/blob/5ae7a59caa81d37c4aada6c0527e5c9bba064b59/autoload/lsp/ui/vim.vim

Currently I don't want to expose other apis that users will depend on besides commands. I was thining of adding something like let g:lsp_tag_stack = 1 by default so tag stack will automatically work. If the user wants to disable it by default they can set it to 0.

Let me know if you were thininking something different.

jacwah commented 7 years ago

Ok, cool! I was originally thinking about creating a separate plugin, but including it in this one is of course more convenient for users if you think it's a good idea as well.

I'll outline my idea for the interface below:

Base implementation

Extra features

Vim's tag stack has more features that probably see less use, but maybe we want.

If the base implementation looks ok I'll start working on it! We can discuss extra features later, maybe in a separate issue.

bluelightning32 commented 6 years ago

I'm also interested in something like a tagstack for lsp. Is there any update on this issue?

mcepl commented 6 years ago

And it would be nice to somehow link it to the vim jumplist, so that <Ctrl-O> and <Ctrl-I> woudl still work.

jacwah commented 6 years ago

I'm not working on this currently, nor do I have the time in the close future. Feel free to pick it up!

SkyLeach commented 6 years ago

If it's not making this too complicated, the ability to specify a split, vsplit or tab for the target for the command (or new commands if targeting is too much) would be really nice.

mcepl commented 6 years ago

Just noticing this discussion on StackOverflow https://stackoverflow.com/questions/19195160/push-a-location-to-the-jumplist

mcepl commented 6 years ago

If it's not making this too complicated, the ability to specify a split, vsplit or tab for the target for the command (or new commands if targeting is too much) would be really nice.

I think this issue should be about having something to work, and only then we can bikeshed on additional stuff.

mcepl commented 6 years ago

@jacwah how would you expect API of such calbacks? I think it is just a matter of calling on_error function in error handles of https://github.com/mcepl/vim-lsp/blob/11588dae0f0a23048b02f19fda6199cd43ab4639/autoload/lsp/ui/vim.vim#L236 and on_success when it makes a jump. However, we have to get the pointer to these functions there somehow.

mkwork commented 6 years ago

There is nice implementation of such stuff in the LanguageClient-neovim. First argument of functions like lsp#ui#vim#references is optional callback, like s:handle_location if argument is nil, there is default callback used, else used callback passed as argument. With such way, you can easy write the wrapper or just the full own implementation of reply.

Such approach is very useful and can be used for standalone unite/denite integration for example, to avoid main code dependence on this plugins.

mcepl commented 6 years ago

There is nice implementation of such stuff in the LanguageClient-neovim.

Could you locate the particular function there? I am still not sure what's the problem.

mkwork commented 6 years ago

I'm talking about such kind of front end functions interface, here you can see, that callback is configurable.

So behavior which you are looking for, can be obtained with following approach within such interface(pseudocode):

function! my_definition_handler
    call s:handle_location(ctx)
    call do_some_stuff_after(ctx)
endfunction

" this one can be done by end user
command LspDefinition call lsp#ui#vim#definitions(my_definition_handler)

Other way - is make lsp commands mutable objects, with delegate fields with even handlers. It's more complicated but much agile.

Somewhat like this:

let lsp_definition = {'entry' : lsp#ui#vim#definitions, 'handler' :  s:handle_location}
command LspDefinition call lsp_definition['entry'](lsp_definition)

function! lsp#ui#vim#definitions(a:self) 
    ...
    let l:callback = a:self['handler']
    ...
endfunction

" somewhere in plugin code initialization:
let g:wrapee = lsp_definition['handler']
function! wrapper
    call g:wrapee(ctx)
    " do some additional handling
endfunction
prabirshrestha commented 4 years ago

Closing to clean up the issue. This is something I need to think a bit more before we expose public apis since I would like to not avoid breaking the public apis.

In the mean time you can try this.

nmap \gd :LspDefinition<cr>
nmap \gt :tab split<cr>:LspDefinition<cr>
nmap \gs :sp<cr>:LspDefinition<cr>
nmap \gv :vsp<cr>:LspDefinition<cr>