Support completion for console and watches.
Add omnifunc for prompt buffers
This synchronous completion can be used with any completion system
including built-in CTRL-X CTRL-O.
The filetype of the prompt buffers is set to VimspectorPrompt so that it
can be identified by completion systems. For example, this works well
with YCM:
let g:ycm_semantic_triggers = {
\ 'VimspectorPrompt': [ '.', '->', ':', '<' ]
\ }
This commit is contained in:
parent
e81be848a1
commit
733843a6d4
5 changed files with 113 additions and 8 deletions
|
|
@ -232,17 +232,114 @@ function! vimspector#CompleteOutput( ArgLead, CmdLine, CursorPos ) abort
|
||||||
return join( buffers, "\n" )
|
return join( buffers, "\n" )
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
py3 <<EOF
|
||||||
|
def _vimspector_GetExprCompletions( CmdLine, CursorPos ):
|
||||||
|
if not _vimspector_session:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# FIXME
|
||||||
|
# Curiously, it seems that CursorPos is 0-based here and that's actually what
|
||||||
|
# the servers want/need ?
|
||||||
|
return [ i.get( 'text' ) or i[ 'label' ]
|
||||||
|
for i in _vimspector_session.GetCompletionsSync( CmdLine,
|
||||||
|
CursorPos ) ]
|
||||||
|
EOF
|
||||||
|
|
||||||
function! vimspector#CompleteExpr( ArgLead, CmdLine, CursorPos ) abort
|
function! vimspector#CompleteExpr( ArgLead, CmdLine, CursorPos ) abort
|
||||||
if !s:enabled
|
if !s:enabled
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
return join( py3eval( '_vimspector_session.GetCompletionsSync( '
|
return join( py3eval( '_vimspector_GetExprCompletions( '
|
||||||
\.' vim.eval( "a:CmdLine" ),'
|
\.' vim.eval( "a:CmdLine" ),'
|
||||||
\.' int( vim.eval( "a:CursorPos" ) ) )'
|
\.' int( vim.eval( "a:CursorPos" ) ) + 1 )' ),
|
||||||
\. ' if _vimspector_session else []' ),
|
|
||||||
\ "\n" )
|
\ "\n" )
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
let s:latest_completion_request = {}
|
||||||
|
|
||||||
|
function! vimspector#CompleteFuncSync( prompt, find_start, query ) abort
|
||||||
|
if py3eval( 'not _vimspector_session' )
|
||||||
|
return []
|
||||||
|
endif
|
||||||
|
|
||||||
|
if a:find_start
|
||||||
|
|
||||||
|
" We're busy
|
||||||
|
if !empty( s:latest_completion_request )
|
||||||
|
return -1
|
||||||
|
endif
|
||||||
|
|
||||||
|
let line = getline( line( '.' ) )[ len( a:prompt ) : ]
|
||||||
|
let col = col( '.' ) - len( a:prompt )
|
||||||
|
let s:latest_completion_request.items =
|
||||||
|
\ py3eval( '_vimspector_session.GetCompletionsSync( '
|
||||||
|
\.' vim.eval( "line" ), '
|
||||||
|
\.' int( vim.eval( "col" ) ) )' )
|
||||||
|
let s:latest_completion_request.line = line
|
||||||
|
let s:latest_completion_request.col = col
|
||||||
|
|
||||||
|
let start_pos = col
|
||||||
|
for item in s:latest_completion_request.items
|
||||||
|
if !has_key( item, 'start' )
|
||||||
|
let item.start = col
|
||||||
|
else
|
||||||
|
" For some reason, the returned start value is 0-indexed even though we
|
||||||
|
" use columnsStartAt1
|
||||||
|
" TODO need to check this with the other servers that exist
|
||||||
|
let item.start += 1
|
||||||
|
endif
|
||||||
|
" TODO/FIXME. I don't think it's possible to implement the 'length'
|
||||||
|
" parameter, using vim's completion system
|
||||||
|
" if !has_key( item, 'length' )
|
||||||
|
" let item.length = 0
|
||||||
|
" endif
|
||||||
|
if !has_key( item, 'text' )
|
||||||
|
let item.text = item.label
|
||||||
|
endif
|
||||||
|
|
||||||
|
if item.start < start_pos
|
||||||
|
let start_pos = item.start
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
let s:latest_completion_request.start_pos = start_pos
|
||||||
|
let s:latest_completion_request.prompt = a:prompt
|
||||||
|
|
||||||
|
" start_pos is 1-based and the return of findstart is 0-based
|
||||||
|
return ( start_pos + len( a:prompt ) ) - 1
|
||||||
|
else
|
||||||
|
let items = []
|
||||||
|
let pfxlen = len( s:latest_completion_request.prompt )
|
||||||
|
for item in s:latest_completion_request.items
|
||||||
|
if item.start > s:latest_completion_request.start_pos
|
||||||
|
" fix up the text (insert anything that is already present in the line
|
||||||
|
" that would be erased by the fixed-up earlier start position)
|
||||||
|
"
|
||||||
|
" both start_pos and item.start are 1-based
|
||||||
|
let item.text = s:latest_completion_request.text[
|
||||||
|
\ s:latest_completion_request.start_pos + pfxlen - 1 :
|
||||||
|
\ item.start + pfxlen - 1 ] . item.text
|
||||||
|
endif
|
||||||
|
|
||||||
|
call add( items, { 'word': item.text,
|
||||||
|
\ 'abbr': item.label,
|
||||||
|
\ 'menu': get( item, 'type', '' ),
|
||||||
|
\ 'icase': 1,
|
||||||
|
\ } )
|
||||||
|
endfor
|
||||||
|
let s:latest_completion_request = {}
|
||||||
|
return { 'words': items, 'refresh': 'always' }
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#OmniFuncWatch( find_start, query ) abort
|
||||||
|
return vimspector#CompleteFuncSync( 'Expression: ', a:find_start, a:query )
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#OmniFuncConsole( find_start, query ) abort
|
||||||
|
return vimspector#CompleteFuncSync( '> ', a:find_start, a:query )
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! vimspector#Install( bang, ... ) abort
|
function! vimspector#Install( bang, ... ) abort
|
||||||
if !s:enabled
|
if !s:enabled
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -554,8 +554,7 @@ class DebugSession( object ):
|
||||||
# TODO:
|
# TODO:
|
||||||
# - start / length
|
# - start / length
|
||||||
# - sortText
|
# - sortText
|
||||||
return [ i.get( 'text' ) or i[ 'label' ]
|
return response[ 'body' ][ 'targets' ]
|
||||||
for i in response[ 'body' ][ 'targets' ] ]
|
|
||||||
|
|
||||||
|
|
||||||
def _SetUpUI( self ):
|
def _SetUpUI( self ):
|
||||||
|
|
|
||||||
|
|
@ -192,7 +192,8 @@ class OutputView( object ):
|
||||||
utils.SetUpPromptBuffer( tab_buffer.buf,
|
utils.SetUpPromptBuffer( tab_buffer.buf,
|
||||||
name,
|
name,
|
||||||
'> ',
|
'> ',
|
||||||
'vimspector#EvaluateConsole' )
|
'vimspector#EvaluateConsole',
|
||||||
|
'vimspector#OmniFuncConsole' )
|
||||||
else:
|
else:
|
||||||
utils.SetUpHiddenBuffer( tab_buffer.buf, name )
|
utils.SetUpHiddenBuffer( tab_buffer.buf, name )
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ def SetUpHiddenBuffer( buf, name ):
|
||||||
buf.name = name
|
buf.name = name
|
||||||
|
|
||||||
|
|
||||||
def SetUpPromptBuffer( buf, name, prompt, callback ):
|
def SetUpPromptBuffer( buf, name, prompt, callback, omnifunc ):
|
||||||
# This feature is _super_ new, so only enable when available
|
# This feature is _super_ new, so only enable when available
|
||||||
if not Exists( '*prompt_setprompt' ):
|
if not Exists( '*prompt_setprompt' ):
|
||||||
return SetUpHiddenBuffer( buf, name )
|
return SetUpHiddenBuffer( buf, name )
|
||||||
|
|
@ -148,6 +148,7 @@ def SetUpPromptBuffer( buf, name, prompt, callback ):
|
||||||
buf.options[ 'buflisted' ] = False
|
buf.options[ 'buflisted' ] = False
|
||||||
buf.options[ 'bufhidden' ] = 'hide'
|
buf.options[ 'bufhidden' ] = 'hide'
|
||||||
buf.options[ 'textwidth' ] = 0
|
buf.options[ 'textwidth' ] = 0
|
||||||
|
buf.options[ 'omnifunc' ] = omnifunc
|
||||||
buf.name = name
|
buf.name = name
|
||||||
|
|
||||||
vim.eval( "prompt_setprompt( {0}, '{1}' )".format( buf.number,
|
vim.eval( "prompt_setprompt( {0}, '{1}' )".format( buf.number,
|
||||||
|
|
@ -156,6 +157,12 @@ def SetUpPromptBuffer( buf, name, prompt, callback ):
|
||||||
buf.number,
|
buf.number,
|
||||||
Escape( callback ) ) )
|
Escape( callback ) ) )
|
||||||
|
|
||||||
|
# This serves a few purposes, mainly to ensure that completion systems have
|
||||||
|
# something to work with. In particular it makes YCM use its identifier engine
|
||||||
|
# and you can config ycm to trigger semantic (annoyingly, synchronously) using
|
||||||
|
# some let g:ycm_auto_trggier
|
||||||
|
Call( 'setbufvar', buf.number, '&filetype', 'VimspectorPrompt' )
|
||||||
|
|
||||||
|
|
||||||
def SetUpUIWindow( win ):
|
def SetUpUIWindow( win ):
|
||||||
win.options[ 'wrap' ] = False
|
win.options[ 'wrap' ] = False
|
||||||
|
|
|
||||||
|
|
@ -147,7 +147,8 @@ class VariablesView( object ):
|
||||||
utils.SetUpPromptBuffer( self._watch.buf,
|
utils.SetUpPromptBuffer( self._watch.buf,
|
||||||
'vimspector.Watches',
|
'vimspector.Watches',
|
||||||
'Expression: ',
|
'Expression: ',
|
||||||
'vimspector#AddWatchPrompt' )
|
'vimspector#AddWatchPrompt',
|
||||||
|
'vimspector#OmniFuncWatch' )
|
||||||
with utils.LetCurrentWindow( watches_win ):
|
with utils.LetCurrentWindow( watches_win ):
|
||||||
vim.command(
|
vim.command(
|
||||||
'nnoremap <buffer> <CR> :call vimspector#ExpandVariable()<CR>' )
|
'nnoremap <buffer> <CR> :call vimspector#ExpandVariable()<CR>' )
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue