vim-lsp icon indicating copy to clipboard operation
vim-lsp copied to clipboard

Merge hovers

Open mattn opened this issue 2 years ago • 9 comments

On current implementation, hovers are shown per the servers.

    call lsp#callbag#pipe(
        \ lsp#callbag#fromList(l:servers),
        \ lsp#callbag#flatMap({server->
        \   lsp#request(server, l:request)
        \ }),
        \ lsp#callbag#tap({x->s:show_hover(l:ui, x['server_name'], x['request'], x['response'])}),
        \ lsp#callbag#takeUntil(lsp#callbag#pipe(
        \   lsp#stream(),
        \   lsp#callbag#filter({x->has_key(x, 'command')}),
        \ )),
        \ lsp#callbag#subscribe(),
        \ )

Hope to merge them.

mattn avatar Apr 18 '22 00:04 mattn

@prabirshrestha I'm not good at callbag. Is there way to get all result of the pipes like below?

    call lsp#callbag#pipe(
        \ lsp#callbag#fromList(l:servers),
        \ lsp#callbag#flatMap({server->
        \   lsp#request(server, l:request)
        \ }),
        \ lsp#callbag#takeUntil(lsp#callbag#pipe(
        \   lsp#stream(),
        \   lsp#callbag#filter({x->has_key(x, 'command')}),
        \ )),
        \ lsp#callbag#subscribe({xx -> s:show_hovers(l:ui, xx)}),
        \ )

mattn avatar Apr 18 '22 01:04 mattn

There are different ways to solve this.

function! s:log(...) abort
    echom json_encode(a:000)
endfunction

call callbag#pipe(
    \ callbag#fromList([1, 2, 3]),
    \ callbag#scan({acc, curr -> add(acc, curr)}, []),
    \ callbag#tap({x->s:log('scan tap', x)}),
    \ callbag#subscribe(),
    \ )

call callbag#pipe(
    \ callbag#fromList([1, 2, 3]),
    \ callbag#reduce({acc, curr -> add(acc, curr)}, []),
    \ callbag#tap({x->s:log('reduce tap', x)}),
    \ callbag#subscribe(),
    \ )

image

I would primarily use scan operator for this. The reason I like scan here is that it calls next as we get the value including all the previous values without waiting for all requests to finish i.e. a slow server will not impact others.

reduce works similar to scan but it will wait for all to complete so a slow server may impact. Ideally we should have a toList() that does this for you automatically but currently toList() needs to be renamed to toBlockingList() so we can create a new `toList(). I was delaying this rename until we need to use it.

I don't have a strong preference currently thought reduce is lot easier to work with. We already use reduce in codelens.

You can also create your own using create function. Unlike vim9script, vim8 script doesn't support |inline-functions| so you need to keep creating function outside.

function! s:create(next, error, complete) abort
    call a:next(1)
    call a:next(2)
    call a:complete()
endfunction

call callbag#create(function('s:create'))

Some of the callbag.vim implementation could be quiet daunting and I have been thinking of using callbag-doki style pattern instead. https://github.com/Epimodev/callbag-doki/blob/master/src/sources/index.ts.

RxJS docs are the best to refer to.

prabirshrestha avatar Apr 18 '22 06:04 prabirshrestha

I tried to implement with reduce, but seems not work.

    call lsp#callbag#pipe(
        \ lsp#callbag#fromList(l:servers),
        \ lsp#callbag#flatMap({server->
        \   lsp#request(server, l:request)
        \ }),
        \ lsp#callbag#reduce({acc, curr -> add(acc, curr)}, []),
        \ lsp#callbag#tap({xx->s:show_hovers(l:ui, xx)}),
        \ lsp#callbag#takeUntil(lsp#callbag#pipe(
        \   lsp#stream(),
        \   lsp#callbag#filter({x->has_key(x, 'command')}),
        \ )),
        \ lsp#callbag#subscribe(),
        \ )
function! s:show_hovers(ui, hovers) abort
    echo ''
    if s:FloatingWindow.is_available() && a:ui ==? 'float'
        call s:show_floating_window(a:hovers)
    else
        call s:show_preview_window(a:hovers)
    endif
endfunction

Length of a:hovers always be 1.

mattn avatar Apr 18 '22 07:04 mattn

:LspHover --server=gopls and :LspHover --server=efm-langserver for each commands seems to be working good.

screenshot

mattn avatar Apr 18 '22 08:04 mattn

Wondering if there is a bug with async ones.

In the mean can you try using scan and make it behave similar to reduce.

function! s:log(...) abort
    echom json_encode(a:000)
endfunction

let s:seed = srand()
let s:inputArray = [1,2,3,4]
call callbag#pipe(
    \ callbag#fromList(s:inputArray),
    \ callbag#flatMap({x->
    \   callbag#pipe(
    \       callbag#of(x),
    \       callbag#delay(rand(s:seed) % 1000),
    \   )
    \ }),
    \ callbag#scan({acc,curr->add(acc, curr)}, []),
    \ callbag#filter({x->len(x) == len(s:inputArray)}),
    \ callbag#tap({x->s:log('tap', x)}),
    \ callbag#subscribe(),
    \ )

I tried simulating async functions with random delays and it does only call tap once with the final values. The same code with reduce fails so seems like it currently only works with non async funcs.

You can share the efm config settings to configure gopls? I can try fixing reduce.

prabirshrestha avatar Apr 18 '22 21:04 prabirshrestha

You can also use group which is going to be simpler.

function! s:log(...) abort
    echom json_encode(a:000)
endfunction

let s:seed = srand()
let s:inputArray = [1,2,3,4]
call callbag#pipe(
    \ callbag#fromList(s:inputArray),
    \ callbag#flatMap({x->
    \   callbag#pipe(
    \       callbag#of(x),
    \       callbag#delay(rand(s:seed) % 1000),
    \   )
    \ }),
    \ callbag#group(len(s:inputArray)),
    \ callbag#tap({x->s:log('tap', x)}),
    \ callbag#subscribe(),
    \ )

prabirshrestha avatar Apr 18 '22 21:04 prabirshrestha

Hmm, I don't get it.

    call lsp#callbag#pipe(
        \ lsp#callbag#fromList(l:servers),
        \ lsp#callbag#flatMap({server->
        \   callbag#pipe(
        \     lsp#request(server, l:request)
        \   )
        \ }),
        \ lsp#callbag#takeUntil(lsp#callbag#pipe(
        \   lsp#stream(),
        \   lsp#callbag#filter({x->has_key(x, 'command')}),
        \ )),
        \ lsp#callbag#group(len(l:servers)),
        \ lsp#callbag#tap({xx->s:show_hovers(l:ui, xx)}),
        \ lsp#callbag#subscribe(),
        \ )

mattn avatar Apr 19 '22 04:04 mattn

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Jun 19 '22 06:06 stale[bot]

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Sep 21 '22 00:09 stale[bot]