|
@@ -21,12 +21,18 @@ set cpo&vim
|
|
|
|
|
|
" This needs to be called outside of a function
|
|
|
let s:script_folder_path = escape( expand( '<sfile>:p:h' ), '\' )
|
|
|
-let s:omnifunc_mode = 0
|
|
|
-
|
|
|
-let s:old_cursor_position = []
|
|
|
-let s:cursor_moved = 0
|
|
|
+let s:force_semantic = 0
|
|
|
+let s:default_completion = {
|
|
|
+ \ 'start_column': -1,
|
|
|
+ \ 'candidates': []
|
|
|
+ \ }
|
|
|
+let s:completion = s:default_completion
|
|
|
let s:previous_allowed_buffer_number = 0
|
|
|
let s:pollers = {
|
|
|
+ \ 'completion': {
|
|
|
+ \ 'id': -1,
|
|
|
+ \ 'wait_milliseconds': 10
|
|
|
+ \ },
|
|
|
\ 'file_parse_response': {
|
|
|
\ 'id': -1,
|
|
|
\ 'wait_milliseconds': 100
|
|
@@ -100,7 +106,6 @@ function! youcompleteme#Enable()
|
|
|
autocmd BufEnter * call s:OnBufferEnter()
|
|
|
autocmd BufUnload * call s:OnBufferUnload()
|
|
|
autocmd InsertLeave * call s:OnInsertLeave()
|
|
|
- autocmd InsertEnter * call s:OnInsertEnter()
|
|
|
autocmd VimLeave * call s:OnVimLeave()
|
|
|
autocmd CompleteDone * call s:OnCompleteDone()
|
|
|
augroup END
|
|
@@ -119,6 +124,10 @@ function! youcompleteme#EnableCursorMovedAutocommands()
|
|
|
autocmd CursorMoved * call s:OnCursorMovedNormalMode()
|
|
|
autocmd TextChanged * call s:OnTextChangedNormalMode()
|
|
|
autocmd TextChangedI * call s:OnTextChangedInsertMode()
|
|
|
+ " The TextChangedI event is not triggered when inserting a character while
|
|
|
+ " the completion menu is open. We handle this by closing the completion menu
|
|
|
+ " just before inserting a character.
|
|
|
+ autocmd InsertCharPre * call s:OnInsertChar()
|
|
|
augroup END
|
|
|
endfunction
|
|
|
|
|
@@ -221,15 +230,22 @@ function! s:SetUpKeyMappings()
|
|
|
imap <Nul> <C-Space>
|
|
|
endif
|
|
|
|
|
|
- " <c-x><c-o> trigger omni completion, <c-p> deselects the first completion
|
|
|
- " candidate that vim selects by default
|
|
|
- silent! exe 'inoremap <unique> ' . invoke_key . ' <C-X><C-O><C-P>'
|
|
|
+ silent! exe 'inoremap <unique> <silent> ' . invoke_key .
|
|
|
+ \ ' <C-R>=<SID>InvokeSemanticCompletion()<CR>'
|
|
|
endif
|
|
|
|
|
|
if !empty( g:ycm_key_detailed_diagnostics )
|
|
|
silent! exe 'nnoremap <unique> ' . g:ycm_key_detailed_diagnostics .
|
|
|
- \ ' :YcmShowDetailedDiagnostic<cr>'
|
|
|
+ \ ' :YcmShowDetailedDiagnostic<CR>'
|
|
|
endif
|
|
|
+
|
|
|
+ " The TextChangedI event is not triggered when deleting a character while the
|
|
|
+ " completion menu is open. We handle this by closing the completion menu on
|
|
|
+ " the keys that delete a character in insert mode.
|
|
|
+ for key in [ "<BS>", "<C-h>" ]
|
|
|
+ silent! exe 'inoremap <unique> <expr> ' . key .
|
|
|
+ \ ' <SID>OnDeleteChar( "\' . key . '" )'
|
|
|
+ endfor
|
|
|
endfunction
|
|
|
|
|
|
|
|
@@ -406,6 +422,11 @@ function! s:SetUpCompleteopt()
|
|
|
endfunction
|
|
|
|
|
|
|
|
|
+function! s:SetCompleteFunc()
|
|
|
+ let &completefunc = 'youcompleteme#CompleteFunc'
|
|
|
+endfunction
|
|
|
+
|
|
|
+
|
|
|
function! s:OnVimLeave()
|
|
|
exec s:python_command "ycm_state.OnVimLeave()"
|
|
|
endfunction
|
|
@@ -423,7 +444,6 @@ function! s:OnFileTypeSet()
|
|
|
|
|
|
call s:SetUpCompleteopt()
|
|
|
call s:SetCompleteFunc()
|
|
|
- call s:SetOmnicompleteFunc()
|
|
|
|
|
|
exec s:python_command "ycm_state.OnBufferVisit()"
|
|
|
call s:OnFileReadyToParse( 1 )
|
|
@@ -437,7 +457,6 @@ function! s:OnBufferEnter()
|
|
|
|
|
|
call s:SetUpCompleteopt()
|
|
|
call s:SetCompleteFunc()
|
|
|
- call s:SetOmnicompleteFunc()
|
|
|
|
|
|
exec s:python_command "ycm_state.OnBufferVisit()"
|
|
|
" Last parse may be outdated because of changes from other buffers. Force a
|
|
@@ -502,24 +521,20 @@ function! s:PollFileParseResponse( ... )
|
|
|
endfunction
|
|
|
|
|
|
|
|
|
-function! s:SetCompleteFunc()
|
|
|
- let &completefunc = 'youcompleteme#Complete'
|
|
|
- let &l:completefunc = 'youcompleteme#Complete'
|
|
|
+function! s:OnInsertChar()
|
|
|
+ call timer_stop( s:pollers.completion.id )
|
|
|
+ if pumvisible()
|
|
|
+ call feedkeys( "\<C-e>", 'n' )
|
|
|
+ endif
|
|
|
endfunction
|
|
|
|
|
|
|
|
|
-function! s:SetOmnicompleteFunc()
|
|
|
- if s:Pyeval( 'ycm_state.NativeFiletypeCompletionUsable()' )
|
|
|
- let &omnifunc = 'youcompleteme#OmniComplete'
|
|
|
- let &l:omnifunc = 'youcompleteme#OmniComplete'
|
|
|
-
|
|
|
- " If we don't have native filetype support but the omnifunc is set to YCM's
|
|
|
- " omnifunc because the previous file the user was editing DID have native
|
|
|
- " support, we remove our omnifunc.
|
|
|
- elseif &omnifunc == 'youcompleteme#OmniComplete'
|
|
|
- let &omnifunc = ''
|
|
|
- let &l:omnifunc = ''
|
|
|
+function! s:OnDeleteChar( key )
|
|
|
+ call timer_stop( s:pollers.completion.id )
|
|
|
+ if pumvisible()
|
|
|
+ return "\<C-y>" . a:key
|
|
|
endif
|
|
|
+ return a:key
|
|
|
endfunction
|
|
|
|
|
|
|
|
@@ -546,23 +561,28 @@ function! s:OnTextChangedInsertMode()
|
|
|
return
|
|
|
endif
|
|
|
|
|
|
- exec s:python_command "ycm_state.OnCursorMoved()"
|
|
|
- call s:UpdateCursorMoved()
|
|
|
-
|
|
|
call s:IdentifierFinishedOperations()
|
|
|
- if g:ycm_autoclose_preview_window_after_completion
|
|
|
- call s:ClosePreviewWindowIfNeeded()
|
|
|
+
|
|
|
+ " We have to make sure we correctly leave semantic mode even when the user
|
|
|
+ " inserts something like a "operator[]" candidate string which fails
|
|
|
+ " CurrentIdentifierFinished check.
|
|
|
+ if s:force_semantic && !s:Pyeval( 'base.LastEnteredCharIsIdentifierChar()' )
|
|
|
+ let s:force_semantic = 0
|
|
|
endif
|
|
|
|
|
|
- if g:ycm_auto_trigger || s:omnifunc_mode
|
|
|
+ if &completefunc == "youcompleteme#CompleteFunc" &&
|
|
|
+ \ ( g:ycm_auto_trigger || s:force_semantic ) &&
|
|
|
+ \ !s:InsideCommentOrStringAndShouldStop() &&
|
|
|
+ \ !s:OnBlankLine()
|
|
|
+ " Immediately call previous completion to avoid flickers.
|
|
|
+ call s:Complete()
|
|
|
call s:InvokeCompletion()
|
|
|
endif
|
|
|
|
|
|
- " We have to make sure we correctly leave omnifunc mode even when the user
|
|
|
- " inserts something like a "operator[]" candidate string which fails
|
|
|
- " CurrentIdentifierFinished check.
|
|
|
- if s:omnifunc_mode && !s:Pyeval( 'base.LastEnteredCharIsIdentifierChar()')
|
|
|
- let s:omnifunc_mode = 0
|
|
|
+ exec s:python_command "ycm_state.OnCursorMoved()"
|
|
|
+
|
|
|
+ if g:ycm_autoclose_preview_window_after_completion
|
|
|
+ call s:ClosePreviewWindowIfNeeded()
|
|
|
endif
|
|
|
endfunction
|
|
|
|
|
@@ -572,7 +592,8 @@ function! s:OnInsertLeave()
|
|
|
return
|
|
|
endif
|
|
|
|
|
|
- let s:omnifunc_mode = 0
|
|
|
+ let s:force_semantic = 0
|
|
|
+ let s:completion = s:default_completion
|
|
|
call s:OnFileReadyToParse()
|
|
|
exec s:python_command "ycm_state.OnInsertLeave()"
|
|
|
if g:ycm_autoclose_preview_window_after_completion ||
|
|
@@ -582,22 +603,6 @@ function! s:OnInsertLeave()
|
|
|
endfunction
|
|
|
|
|
|
|
|
|
-function! s:OnInsertEnter()
|
|
|
- if !s:AllowedToCompleteInCurrentBuffer()
|
|
|
- return
|
|
|
- endif
|
|
|
-
|
|
|
- let s:old_cursor_position = []
|
|
|
-endfunction
|
|
|
-
|
|
|
-
|
|
|
-function! s:UpdateCursorMoved()
|
|
|
- let current_position = getpos('.')
|
|
|
- let s:cursor_moved = current_position != s:old_cursor_position
|
|
|
- let s:old_cursor_position = current_position
|
|
|
-endfunction
|
|
|
-
|
|
|
-
|
|
|
function! s:ClosePreviewWindowIfNeeded()
|
|
|
let current_buffer_name = bufname('')
|
|
|
|
|
@@ -619,7 +624,8 @@ function! s:IdentifierFinishedOperations()
|
|
|
return
|
|
|
endif
|
|
|
exec s:python_command "ycm_state.OnCurrentIdentifierFinished()"
|
|
|
- let s:omnifunc_mode = 0
|
|
|
+ let s:force_semantic = 0
|
|
|
+ let s:completion = s:default_completion
|
|
|
endfunction
|
|
|
|
|
|
|
|
@@ -662,28 +668,45 @@ endfunction
|
|
|
|
|
|
|
|
|
function! s:InvokeCompletion()
|
|
|
- if &completefunc != "youcompleteme#Complete"
|
|
|
- return
|
|
|
- endif
|
|
|
+ exec s:python_command "ycm_state.SendCompletionRequest(" .
|
|
|
+ \ "vimsupport.GetBoolValue( 's:force_semantic' ) )"
|
|
|
|
|
|
- if s:InsideCommentOrStringAndShouldStop() || s:OnBlankLine()
|
|
|
- return
|
|
|
- endif
|
|
|
+ call s:PollCompletion()
|
|
|
+endfunction
|
|
|
+
|
|
|
+
|
|
|
+function! s:InvokeSemanticCompletion()
|
|
|
+ let s:force_semantic = 1
|
|
|
+ exec s:python_command "ycm_state.SendCompletionRequest( True )"
|
|
|
|
|
|
- " This is tricky. First, having 'refresh' set to 'always' in the dictionary
|
|
|
- " that our completion function returns makes sure that our completion function
|
|
|
- " is called on every keystroke. Second, when the sequence of characters the
|
|
|
- " user typed produces no results in our search an infinite loop can occur. The
|
|
|
- " problem is that our feedkeys call triggers the OnCursorMovedI event which we
|
|
|
- " are tied to. We prevent this infinite loop from starting by making sure that
|
|
|
- " the user has moved the cursor since the last time we provided completion
|
|
|
- " results.
|
|
|
- if !s:cursor_moved
|
|
|
+ call s:PollCompletion()
|
|
|
+ " Since this function is called in a mapping through the expression register
|
|
|
+ " <C-R>=, its return value is inserted (see :h c_CTRL-R_=). We don't want to
|
|
|
+ " insert anything so we return an empty string.
|
|
|
+ return ''
|
|
|
+endfunction
|
|
|
+
|
|
|
+
|
|
|
+function! s:PollCompletion( ... )
|
|
|
+ if !s:Pyeval( 'ycm_state.CompletionRequestReady()' )
|
|
|
+ let s:pollers.completion.id = timer_start(
|
|
|
+ \ s:pollers.completion.wait_milliseconds,
|
|
|
+ \ function( 's:PollCompletion' ) )
|
|
|
return
|
|
|
endif
|
|
|
|
|
|
+ let response = s:Pyeval( 'ycm_state.GetCompletionResponse()' )
|
|
|
+ let s:completion = {
|
|
|
+ \ 'start_column': response.completion_start_column,
|
|
|
+ \ 'candidates': response.completions
|
|
|
+ \ }
|
|
|
+ call s:Complete()
|
|
|
+endfunction
|
|
|
+
|
|
|
+
|
|
|
+function! s:Complete()
|
|
|
" <c-x><c-u> invokes the user's completion function (which we have set to
|
|
|
- " youcompleteme#Complete), and <c-p> tells Vim to select the previous
|
|
|
+ " youcompleteme#CompleteFunc), and <c-p> tells Vim to select the previous
|
|
|
" completion candidate. This is necessary because by default, Vim selects the
|
|
|
" first candidate when completion is invoked, and selecting a candidate
|
|
|
" automatically replaces the current text with it. Calling <c-p> forces Vim to
|
|
@@ -693,43 +716,17 @@ function! s:InvokeCompletion()
|
|
|
endfunction
|
|
|
|
|
|
|
|
|
-" This is our main entry point. This is what vim calls to get completions.
|
|
|
-function! youcompleteme#Complete( findstart, base )
|
|
|
- " After the user types one character after the call to the omnifunc, the
|
|
|
- " completefunc will be called because of our mapping that calls the
|
|
|
- " completefunc on every keystroke. Therefore we need to delegate the call we
|
|
|
- " 'stole' back to the omnifunc
|
|
|
- if s:omnifunc_mode
|
|
|
- return youcompleteme#OmniComplete( a:findstart, a:base )
|
|
|
- endif
|
|
|
-
|
|
|
+function! youcompleteme#CompleteFunc( findstart, base )
|
|
|
if a:findstart
|
|
|
- " InvokeCompletion has this check but we also need it here because of random
|
|
|
- " Vim bugs and unfortunate interactions with the autocommands of other
|
|
|
- " plugins
|
|
|
- if !s:cursor_moved
|
|
|
- " for vim, -2 means not found but don't trigger an error message
|
|
|
- " see :h complete-functions
|
|
|
+ if s:completion.start_column > col( '.' ) ||
|
|
|
+ \ empty( s:completion.candidates )
|
|
|
+ " For vim, -2 means not found but don't trigger an error message.
|
|
|
+ " See :h complete-functions.
|
|
|
return -2
|
|
|
endif
|
|
|
-
|
|
|
- exec s:python_command "ycm_state.CreateCompletionRequest()"
|
|
|
- return s:Pyeval( 'base.CompletionStartColumn()' )
|
|
|
- else
|
|
|
- return s:Pyeval( 'ycm_state.GetCompletions()' )
|
|
|
- endif
|
|
|
-endfunction
|
|
|
-
|
|
|
-
|
|
|
-function! youcompleteme#OmniComplete( findstart, base )
|
|
|
- if a:findstart
|
|
|
- let s:omnifunc_mode = 1
|
|
|
- exec s:python_command "ycm_state.CreateCompletionRequest(" .
|
|
|
- \ "force_semantic = True )"
|
|
|
- return s:Pyeval( 'base.CompletionStartColumn()' )
|
|
|
- else
|
|
|
- return s:Pyeval( 'ycm_state.GetCompletions()' )
|
|
|
+ return s:completion.start_column - 1
|
|
|
endif
|
|
|
+ return s:completion.candidates
|
|
|
endfunction
|
|
|
|
|
|
|