vim-lsp
vim-lsp copied to clipboard
Merge hovers
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.
@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)}),
\ )
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(),
\ )

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.
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.
:LspHover --server=gopls and :LspHover --server=efm-langserver for each commands seems to be working good.

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.
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(),
\ )
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(),
\ )
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.
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.