Jedi-vim: Show documentation on (neovim) floating window?

Created on 19 Dec 2019  ยท  11Comments  ยท  Source: davidhalter/jedi-vim

Hello,
Do you have a plan to implement show doc on (nvim) floating window?
Like vim-go has a setting called g:go_doc_popup_window.
Show doc on Floating window or Popup window may be more comfortable than preview~

Thanks.

Most helpful comment

In the mean time I am using this hack:

image

```vim

autocmd FileType python nnoremap K :call PyDocVim()

function! PyDocVim()
python3 << EOF
import jedi

curfile = vim.current.buffer.name
row = vim.current.window.cursor[0]
col= vim.current.window.cursor[1]

script = jedi.Script(
source=None,
path=curfile,
line=row,
column=col)

try:
definitions = script.goto_definitions()
except Exception:
# print to stdout, will be in :messages
definitions = []
print("Exception, this shouldn't happen.")
print(traceback.format_exc())

if not definitions:
    echo_highlight("No documentation found for that.")
    vim.command("return")

docs = []
for d in definitions:
doc = d.docstring()
if doc:
title = "Docstring for %s" % d.desc_with_module
underline = "=" * len(title)
docs.append("%s\n%s\n%s" % (title, underline, doc))
else:
docs.append("|No Docstring for %s|" % d)
text = ("\n" + "-" * 79 + "\n").join(docs)
vim.command("let docWidth = %s" % len(title))
vim.command("let doc_lines = %s" % len(text.split("\n")))
EOF
"Scroll
function! s:popup_filter(winid, key)
if a:key ==# "\"
call win_execute(a:winid, "normal! \")
return v:true
elseif a:key ==# "\"
call win_execute(a:winid, "normal! \")
return v:true
elseif a:key ==# 'q' || a:key ==# 'x'
return popup_filter_menu(a:winid, 'x')
endif
return v:false
endfunction

let lines = py3eval('text')
let winid = popup_create(lines->split('\n'), #{
        \ filter: function('s:popup_filter'),
        \ pos: 'botleft',
        \ line: 'cursor-1',
        \ col: 'cursor',
        \ moved: 'any',
        \ border: [1,1,1,1,1,1,1,1],
        \ borderchars: ['โ”€', 'โ”‚', 'โ”€', 'โ”‚', 'โ”Œ', 'โ”', 'โ”˜', 'โ””'],
        \ borderhighlight: ['Todo'],    
        \ padding: [0,1,0,1],
        \ firstline: 1,
        \ scrollbar: 1,
        \ minwidth: docWidth,
        \ maxwidth: 74,
        \ minheight: doc_lines,
        \ maxheight: 20,
        \ mapping: 0,
        \ })

call setbufvar(winbufnr(winid), '&syntax','rst')
call setwinvar(winid, '&wincolor', 'Normal')

endfunction

All 11 comments

This is what #652 is about. Please try it and let us know if it works.

This is what #652 is about. Please try it and let us know if it works.

I test it on Plug 'blueyed/jedi-vim', {'branch': 'call-signatures'} ,
and set

let g:jedi#show_call_signatures = 3
let g:jedi#show_call_signatures_modes = 'ni'

It doesn't work. No floating window doc.

Some Info:
NVIM v0.4.3
MacOS 10.15.2

@blueyed

@blueyed is the goal to have this:

652 is only for call signatures, not docs.

@blayz3r something like this could be done. We should keep that in mind with #652 (so that functions can be shared etc).

In the mean time I am using this hack:

image

```vim

autocmd FileType python nnoremap K :call PyDocVim()

function! PyDocVim()
python3 << EOF
import jedi

curfile = vim.current.buffer.name
row = vim.current.window.cursor[0]
col= vim.current.window.cursor[1]

script = jedi.Script(
source=None,
path=curfile,
line=row,
column=col)

try:
definitions = script.goto_definitions()
except Exception:
# print to stdout, will be in :messages
definitions = []
print("Exception, this shouldn't happen.")
print(traceback.format_exc())

if not definitions:
    echo_highlight("No documentation found for that.")
    vim.command("return")

docs = []
for d in definitions:
doc = d.docstring()
if doc:
title = "Docstring for %s" % d.desc_with_module
underline = "=" * len(title)
docs.append("%s\n%s\n%s" % (title, underline, doc))
else:
docs.append("|No Docstring for %s|" % d)
text = ("\n" + "-" * 79 + "\n").join(docs)
vim.command("let docWidth = %s" % len(title))
vim.command("let doc_lines = %s" % len(text.split("\n")))
EOF
"Scroll
function! s:popup_filter(winid, key)
if a:key ==# "\"
call win_execute(a:winid, "normal! \")
return v:true
elseif a:key ==# "\"
call win_execute(a:winid, "normal! \")
return v:true
elseif a:key ==# 'q' || a:key ==# 'x'
return popup_filter_menu(a:winid, 'x')
endif
return v:false
endfunction

let lines = py3eval('text')
let winid = popup_create(lines->split('\n'), #{
        \ filter: function('s:popup_filter'),
        \ pos: 'botleft',
        \ line: 'cursor-1',
        \ col: 'cursor',
        \ moved: 'any',
        \ border: [1,1,1,1,1,1,1,1],
        \ borderchars: ['โ”€', 'โ”‚', 'โ”€', 'โ”‚', 'โ”Œ', 'โ”', 'โ”˜', 'โ””'],
        \ borderhighlight: ['Todo'],    
        \ padding: [0,1,0,1],
        \ firstline: 1,
        \ scrollbar: 1,
        \ minwidth: docWidth,
        \ maxwidth: 74,
        \ minheight: doc_lines,
        \ maxheight: 20,
        \ mapping: 0,
        \ })

call setbufvar(winbufnr(winid), '&syntax','rst')
call setwinvar(winid, '&wincolor', 'Normal')

endfunction

@blayz3r thanks for this hack then. And to think i was on the verge to see what all that cocvim was about.
Edit: Although I think it would be better if the fucntion allowed to be called in insertmode, so we could hit a bind, uppon selecting completion options.

Hi, just for the record, here is the hack of @blayz3r for neovim:

if has('nvim')
    autocmd FileType python nnoremap <buffer> K :call PyDocVim()<CR>

   function! PyDocVim()
python3 << EOF
import jedi

curfile = vim.current.buffer.name
row = vim.current.window.cursor[0]
col= vim.current.window.cursor[1]

script = jedi.Script(
   source=None,
   path=curfile,
   line=row,
   column=col)

try:
   definitions = script.goto_definitions()
except Exception:
   # print to stdout, will be in :messages
   definitions = []
   print("Exception, this shouldn't happen.")
   print(traceback.format_exc())

   if not definitions:
       echo_highlight("No documentation found for that.")
       vim.command("return")

docs = []
for d in definitions:
   doc = d.docstring()
   if doc:
       title = "Docstring for %s" % d.desc_with_module
       underline = "=" * len(title)
       docs.append("%s\n%s\n%s" % (title, underline, doc))
   else:
       docs.append("|No Docstring for %s|" % d)
   text = ("\n" + "-" * 79 + "\n").join(docs)
vim.command("let docWidth = %s" % len(title))
vim.command("let doc_lines = %s" % len(text.split("\n")))
EOF
       "Scroll
       function! s:popup_filter(winid, key)
           if a:key ==# "\<c-k>"
               call win_execute(a:winid, "normal! \<c-y>")
               return v:true
           elseif a:key ==# "\<c-j>"
               call win_execute(a:winid, "normal! \<c-e>")
               return v:true
           elseif a:key ==# 'q' || a:key ==# 'x'
               return popup_filter_menu(a:winid, 'x')
           endif
           return v:false
       endfunction

       let $FZF_DEFAULT_OPTS .= ' --border --margin=0,2'
       let width = float2nr(&columns * 0.9)
       let height = float2nr(&lines * 0.6)
       let opts = { 'relative': 'editor',
                  \ 'row': (&lines - height) / 2,
                  \ 'col': (&columns - width) / 2,
                  \ 'width': width,
                  \ 'height': height }


       let buf = nvim_create_buf(v:false, v:true)
       let lines = py3eval('text')
       call nvim_buf_set_lines(buf, 0, -1, v:true, split(lines, '\n'))
       let winid = nvim_open_win(buf, v:true, opts)
       call setwinvar(winid, '&winhighlight', 'NormalFloat:Normal')
    endfunction
endif

@montanier / @blayz3r I'm wondering if your hack still work? I'm getting errors when running it on Neovim 0.4.4 even though checkhealth shows my floathing window feture works fine, any ideas what it could be?

Error message

Error detected while processing function PyDocVim[38]..provider#python3#Call:                         
line   18:
Error invoking 'python_execute' on channel 3 (python3-script-host):
Traceback (most recent call last):
  File "<string>", line 11, in <module>
TypeError: __init__() got an unexpected keyword argument 'source'
Error detected while processing function PyDocVim[53]..provider#python3#Call:
line   18:
Error invoking 'python_eval' on channel 3 (python3-script-host):
error caught in request handler 'python_eval ['text']':
Traceback (most recent call last):
  File "/home/bruno/.local/lib/python3.6/site-packages/pynvim/plugin/script_host.py", line 169, in python_eval
    return eval(expr, self.module.__dict__)
  File "<string>", line 1, in <module>
NameError: name 'text' is not defined
Error detected while processing function PyDocVim:
line   54:
E15: Invalid expression: >split('\n'), #{ filter: function('s:popup_filter'), pos: 'botleft', line: 'cursor-1', 
col: 'cursor', moved: 'any', border: [1,1,1,1,1,1,1,1], borderchars: ['โ”€', 'โ”‚', 'โ”€', 'โ”‚', 'โ”Œ', 'โ”', 'โ”˜', 'โ””'], b
orderhighlight: ['Todo'],     padding: [0,1,0,1], firstline: 1, scrollbar: 1, minwidth: docWidth, maxwidth: 74, 
minheight: doc_lines, maxheight: 20, mapping: 0, })
E116: Invalid arguments for function popup_create
E15: Invalid expression: popup_create(lines->split('\n'), #{ filter: function('s:popup_filter'), pos: 'botleft',
 line: 'cursor-1', col: 'cursor', moved: 'any', border: [1,1,1,1,1,1,1,1], borderchars: ['โ”€', 'โ”‚', 'โ”€', 'โ”‚', 'โ”Œ'
, 'โ”', 'โ”˜', 'โ””'], borderhighlight: ['Todo'],     padding: [0,1,0,1], firstline: 1, scrollbar: 1, minwidth: docWi
dth, maxwidth: 74, minheight: doc_lines, maxheight: 20, mapping: 0, })
line   73:
E121: Undefined variable: winid
E116: Invalid arguments for function winbufnr
E116: Invalid arguments for function setbufvar
line   74:
E121: Undefined variable: winid
E116: Invalid arguments for function setwinvar

@montanier / @blayz3r I'm wondering if your hack still work? I'm getting errors when running it on Neovim 0.4.4 even though checkhealth shows my floathing window feture works fine, any ideas what it could be?
Error message

Error detected while processing function PyDocVim[38]..provider#python3#Call:                         
line   18:
Error invoking 'python_execute' on channel 3 (python3-script-host):
Traceback (most recent call last):
  File "<string>", line 11, in <module>
TypeError: __init__() got an unexpected keyword argument 'source'
Error detected while processing function PyDocVim[53]..provider#python3#Call:
line   18:
Error invoking 'python_eval' on channel 3 (python3-script-host):
error caught in request handler 'python_eval ['text']':
Traceback (most recent call last):
  File "/home/bruno/.local/lib/python3.6/site-packages/pynvim/plugin/script_host.py", line 169, in python_eval
    return eval(expr, self.module.__dict__)
  File "<string>", line 1, in <module>
NameError: name 'text' is not defined
Error detected while processing function PyDocVim:
line   54:
E15: Invalid expression: >split('\n'), #{ filter: function('s:popup_filter'), pos: 'botleft', line: 'cursor-1', 
col: 'cursor', moved: 'any', border: [1,1,1,1,1,1,1,1], borderchars: ['โ”€', 'โ”‚', 'โ”€', 'โ”‚', 'โ”Œ', 'โ”', 'โ”˜', 'โ””'], b
orderhighlight: ['Todo'],     padding: [0,1,0,1], firstline: 1, scrollbar: 1, minwidth: docWidth, maxwidth: 74, 
minheight: doc_lines, maxheight: 20, mapping: 0, })
E116: Invalid arguments for function popup_create
E15: Invalid expression: popup_create(lines->split('\n'), #{ filter: function('s:popup_filter'), pos: 'botleft',
 line: 'cursor-1', col: 'cursor', moved: 'any', border: [1,1,1,1,1,1,1,1], borderchars: ['โ”€', 'โ”‚', 'โ”€', 'โ”‚', 'โ”Œ'
, 'โ”', 'โ”˜', 'โ””'], borderhighlight: ['Todo'],     padding: [0,1,0,1], firstline: 1, scrollbar: 1, minwidth: docWi
dth, maxwidth: 74, minheight: doc_lines, maxheight: 20, mapping: 0, })
line   73:
E121: Undefined variable: winid
E116: Invalid arguments for function winbufnr
E116: Invalid arguments for function setbufvar
line   74:
E121: Undefined variable: winid
E116: Invalid arguments for function setwinvar

Jedi replaced "source" with code

script = jedi.Script(
    code=None,
    path=curfile)

try:
    definitions = script.help(line=row,
    column=col)
except Exception:
    # print to stdout, will be in :messages
    definitions = []
    print("Exception, this shouldn't happen.")
    print(traceback.format_exc())

    if not definitions:
        echo_highlight("No documentation found for that.")
        vim.command("return")

Thank you very much, that was indeed the problem!

I also had to change title = "Docstring for %s" % d.desc_with_module to title = "Docstring for %s" % d.full_name to make it work;

I added a line for color support in neovim since it didn't have any color syntaxing without: call setbufvar(winbufnr(winid), '&syntax','rst')

Here's my current full code for nvim if useful

"----- show documentation in floaterm window from https://github.com/neovim/neovim/issues/1004
if has('nvim')
    autocmd FileType python nnoremap <buffer> K :call PyDocVim()<CR>

   function! PyDocVim()
python3 << EOF
import jedi

curfile = vim.current.buffer.name
row = vim.current.window.cursor[0]
col= vim.current.window.cursor[1]

script = jedi.Script(
    code=None,
    path=curfile)

try:
   definitions = script.help(line=row, column=col)
   # definitions = script.goto_definitions()
except Exception:
   # print to stdout, will be in :messages
   definitions = []
   print("Exception, this shouldn't happen.")
   print(traceback.format_exc())

   if not definitions:
       echo_highlight("No documentation found for that.")
       vim.command("return")

docs = []
for d in definitions:
   doc = d.docstring()
   if doc:
       title = "Docstring for %s" % d.full_name
       underline = "=" * len(title)
       docs.append("%s\n%s\n%s" % (title, underline, doc))
   else:
       docs.append("|No Docstring for %s|" % d)
   text = ("\n" + "-" * 79 + "\n").join(docs)
vim.command("let docWidth = %s" % len(title))
vim.command("let doc_lines = %s" % len(text.split("\n")))
EOF
       "Scroll
       function! s:popup_filter(winid, key)
           if a:key ==# "\<c-k>"
               call win_execute(a:winid, "normal! \<c-y>")
               return v:true
           elseif a:key ==# "\<c-j>"
               call win_execute(a:winid, "normal! \<c-e>")
               return v:true
           elseif a:key ==# 'q' || a:key ==# 'x'
               return popup_filter_menu(a:winid, 'x')
           endif
           return v:false
       endfunction

       let $FZF_DEFAULT_OPTS .= ' --border --margin=0,2'
       let width = float2nr(&columns * 0.9)
       let height = float2nr(&lines * 0.6)
       let opts = { 'relative': 'editor',
                  \ 'row': (&lines - height) / 2,
                  \ 'col': (&columns - width) / 2,
                  \ 'width': width,
                  \ 'height': height }


       let buf = nvim_create_buf(v:false, v:true)
       let lines = py3eval('text')
       call nvim_buf_set_lines(buf, 0, -1, v:true, split(lines, '\n'))
       let winid = nvim_open_win(buf, v:true, opts)
       " call setwinvar(winid, '&wincolor', 'Normal')
        call setbufvar(winbufnr(winid), '&syntax','rst')
       call setwinvar(winid, '&winhighlight', 'NormalFloat:Normal')
    endfunction
endif

Was this page helpful?
0 / 5 - 0 ratings