When the start parameter is missing, the behabiour is arbitary

It seems that the behaviour of the start parameter being missing is
server (or perhaps a specific client) dependent. The specification
clearely says that it should be inserted at the column of the original
request, but the servers clearly expect either for that column to be the
beginning of an identifier or for the client to ignore the spec and
request from that position anyway.

Reading the VSCode code, we see that the 'word' before the cursor is
guessed, and if only if BOTH 'start' AND 'length' are supplied, then
they are used to determine where insertion starts, otherwise the current
'word' is used. Unclear what 'word' means in the specific contexts, but
we're relying on iskeyword.
This commit is contained in:
Ben Jackson 2020-09-03 23:44:18 +01:00
commit 2710ee2bfa
2 changed files with 50 additions and 10 deletions

View file

@ -19,6 +19,13 @@ let s:save_cpo = &cpoptions
set cpoptions&vim
" }}}
function! s:Debug( ... )
py3 <<EOF
if _vimspector_session is not None:
_vimspector_session._logger.debug( *vim.eval( 'a:000' ) )
EOF
endfunction
let s:enabled = vimspector#internal#state#Reset()
@ -271,28 +278,37 @@ function! vimspector#CompleteFuncSync( prompt, find_start, query ) abort
let line = getline( line( '.' ) )[ len( a:prompt ) : ]
let col = col( '.' ) - len( a:prompt )
" It seems that most servers don't implement the 'start' parameter, which is
" clearly necessary, as they all seem to assume a specific behaviour, which
" is undocumented.
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 prev_non_keyword_char = match( line[ 0 : col - 1 ], '\k*$' ) + 1
let query_len = col - prev_non_keyword_char
let start_pos = col
for item in s:latest_completion_request.items
if !has_key( item, 'start' )
let item.start = col
if !has_key( item, 'start' ) || !has_key( item, 'length' )
" The specification states that if start is not supplied, isertion
" should be at the requested column. But about 0 of the servers actually
" implement that
" (https://github.com/microsoft/debug-adapter-protocol/issues/138)
let item.start = prev_non_keyword_char
let item.length = query_len
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
@ -305,6 +321,14 @@ function! vimspector#CompleteFuncSync( prompt, find_start, query ) abort
let s:latest_completion_request.start_pos = start_pos
let s:latest_completion_request.prompt = a:prompt
call s:Debug( 'FindStart: %s', {
\ 'line': line,
\ 'col': col,
\ 'prompt': len( a:prompt ),
\ 'start_pos': start_pos,
\ 'returning': ( start_pos + len( a:prompt ) ) - 1,
\ } )
" start_pos is 1-based and the return of findstart is 0-based
return ( start_pos + len( a:prompt ) ) - 1
else
@ -316,11 +340,18 @@ function! vimspector#CompleteFuncSync( prompt, find_start, query ) abort
" 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[
let item.text = s:latest_completion_request.line[
\ s:latest_completion_request.start_pos + pfxlen - 1 :
\ item.start + pfxlen - 1 ] . item.text
endif
if item.length > len( a:query )
call s:Debug( 'Rejecting %s, length is greater than %s',
\ item,
\ len( a:query ) )
continue
endif
call add( items, { 'word': item.text,
\ 'abbr': item.label,
\ 'menu': get( item, 'type', '' ),
@ -328,6 +359,8 @@ function! vimspector#CompleteFuncSync( prompt, find_start, query ) abort
\ } )
endfor
let s:latest_completion_request = {}
call s:Debug( 'Items: %s', items )
return { 'words': items, 'refresh': 'always' }
endif
endfunction

View file

@ -1,3 +1,10 @@
var msg = 'Hello, world!'
console.log( "OK stuff happened" )
var obj = {
test: 'testing',
toast: function() {
return 'toasty' . this.test;
}
}
console.log( "OK stuff happened " + obj.toast() )