Auto merge of #3023 - micbou:mutable-user-options, r=puremourning

[READY] Allow users to change the options by restarting the server

Closes https://github.com/Valloric/YouCompleteMe/issues/3021.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/valloric/youcompleteme/3023)
<!-- Reviewable:end -->
This commit is contained in:
zzbot 2018-05-15 15:05:55 -07:00 committed by GitHub
commit 8e448920c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 233 additions and 227 deletions

View File

@ -2021,7 +2021,8 @@ let g:ycm_min_num_of_chars_for_completion = 1
```
Note that after changing an option in your [vimrc script][vimrc] you have to
restart Vim for the changes to take effect.
restart [ycmd][] with the `:YcmRestartServer` command for the changes to take
effect.
### The `g:ycm_min_num_of_chars_for_completion` option

View File

@ -98,15 +98,7 @@ function! s:ReceiveMessages( timer_id )
endfunction
function! youcompleteme#Enable()
call s:SetUpBackwardsCompatibility()
" This can be 0 if YCM libs are old or -1 if an exception occured while
" executing the function.
if s:SetUpPython() != 1
return
endif
function! s:SetUpOptions()
call s:SetUpCommands()
call s:SetUpCpoptions()
call s:SetUpCompleteopt()
@ -118,6 +110,17 @@ function! youcompleteme#Enable()
call s:SetUpSigns()
call s:SetUpSyntaxHighlighting()
endfunction
function! youcompleteme#Enable()
call s:SetUpBackwardsCompatibility()
if !s:SetUpPython()
return
endif
call s:SetUpOptions()
call youcompleteme#EnableCursorMovedAutocommands()
augroup youcompleteme
@ -191,17 +194,20 @@ import vim
# Add python sources folder to the system path.
script_folder = vim.eval( 's:script_folder_path' )
sys.path.insert( 0, os.path.join( script_folder, '..', 'python' ) )
from ycm.setup import SetUpSystemPaths, SetUpYCM
sys.path.insert( 0, os.path.join( script_folder, '..', 'third_party', 'ycmd' ) )
# We enclose this code in a try/except block to avoid backtraces in Vim.
try:
SetUpSystemPaths()
from ycmd import server_utils as su
su.AddNearestThirdPartyFoldersToSysPath( script_folder )
# We need to import ycmd's third_party folders as well since we import and
# use ycmd code in the client.
su.AddNearestThirdPartyFoldersToSysPath( su.__file__ )
# Import the modules used in this file.
from ycm import base, vimsupport
from ycm import base, vimsupport, youcompleteme
ycm_state = SetUpYCM()
ycm_state = youcompleteme.YouCompleteMe()
except Exception as error:
# We don't use PostVimMessage or EchoText from the vimsupport module because
# importing this module may fail.
@ -849,6 +855,8 @@ endfunction
function! s:RestartServer()
call s:SetUpOptions()
exec s:python_command "ycm_state.RestartServer()"
call timer_stop( s:pollers.receive_messages.id )

View File

@ -718,10 +718,9 @@ Make sure you have Vim 7.4.1578 with Python 2 or Python 3 support.
OpenBSD 5.5 and later have a Vim that's recent enough. You can see the version
of Vim installed by running 'vim --version'.
FreeBSD 10.x comes with clang compiler but not the libraries needed to install.
For FreeBSD 11.x, the requirement is cmake:
>
pkg install llvm38 boost-all boost-python-libs clang38
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/llvm38/lib/
pkg install cmake
<
Install YouCompleteMe with Vundle [26].
@ -729,17 +728,20 @@ Install YouCompleteMe with Vundle [26].
using Vundle and the ycm_core library APIs have changed (happens rarely), YCM
will notify you to recompile it. You should then rerun the install process.
Install dependencies and CMake: 'sudo pkg_add llvm boost cmake'
Compiling YCM **with** semantic support for C-family languages:
>
cd ~/.vim/bundle/YouCompleteMe
./install.py --clang-completer --system-libclang --system-boost
./install.py --clang-completer
<
Compiling YCM **without** semantic support for C-family languages:
>
cd ~/.vim/bundle/YouCompleteMe
./install.py --system-boost
./install.py
<
If the 'python' executable is not present, or the default 'python' is not the
one that should be compiled against, specify the python interpreter explicitly:
>
python3 install.py --clang-completer
<
The following additional language support options are available:
@ -2309,7 +2311,8 @@ vimrc script [38] by including a line like this:
let g:ycm_min_num_of_chars_for_completion = 1
<
Note that after changing an option in your vimrc script [38] you have to
restart Vim for the changes to take effect.
restart ycmd [49] with the |:YcmRestartServer| command for the changes to take
effect.
-------------------------------------------------------------------------------
The *g:ycm_min_num_of_chars_for_completion* option

View File

@ -1,4 +1,4 @@
# Copyright (C) 2013 Google Inc.
# Copyright (C) 2013-2018 YouCompleteMe contributors
#
# This file is part of YouCompleteMe.
#
@ -36,7 +36,6 @@ class DiagnosticInterface( object ):
self._diag_filter = DiagnosticFilter.CreateFromOptions( user_options )
# Line and column numbers are 1-based
self._line_to_diags = defaultdict( list )
self._next_sign_id = vimsupport.SIGN_BUFFER_ID_INITIAL_VALUE
self._previous_diag_line_number = -1
self._diag_message_needs_clearing = False
@ -183,16 +182,12 @@ class DiagnosticInterface( object ):
# are sorted by errors in priority and Vim can only display one sign by
# line.
name = 'YcmError' if _DiagnosticIsError( diags[ 0 ] ) else 'YcmWarning'
sign = vimsupport.DiagnosticSign( self._next_sign_id,
line,
name,
self._bufnr )
sign = vimsupport.CreateSign( line, name, self._bufnr )
try:
signs_to_unplace.remove( sign )
except ValueError:
vimsupport.PlaceSign( sign )
self._next_sign_id += 1
for sign in signs_to_unplace:
vimsupport.UnplaceSign( sign )

View File

@ -1,53 +0,0 @@
# Copyright (C) 2016 YouCompleteMe contributors
#
# This file is part of YouCompleteMe.
#
# YouCompleteMe is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# YouCompleteMe is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
# No imports from `future` because when this is loaded, sys.path hasn't been set
# up yet!
import sys
import os
# Can't import these from paths.py because that uses `future` imports
DIR_OF_CURRENT_SCRIPT = os.path.dirname( os.path.abspath( __file__ ) )
DIR_OF_YCMD = os.path.join( DIR_OF_CURRENT_SCRIPT, '..', '..', 'third_party',
'ycmd' )
def SetUpSystemPaths():
sys.path.insert( 0, os.path.join( DIR_OF_YCMD ) )
from ycmd import server_utils as su
su.AddNearestThirdPartyFoldersToSysPath( DIR_OF_CURRENT_SCRIPT )
# We need to import ycmd's third_party folders as well since we import and
# use ycmd code in the client.
su.AddNearestThirdPartyFoldersToSysPath( su.__file__ )
def SetUpYCM():
from ycm import base
from ycmd import user_options_store
from ycm.youcompleteme import YouCompleteMe
base.LoadJsonDefaultsIntoVim()
user_options_store.SetAll( base.BuildServerConf() )
return YouCompleteMe( user_options_store.GetAll() )

View File

@ -1,4 +1,4 @@
# Copyright (C) 2016 YouCompleteMe contributors
# Copyright (C) 2016-2018 YouCompleteMe contributors
#
# This file is part of YouCompleteMe.
#
@ -25,6 +25,7 @@ from builtins import * # noqa
from ycm.tests.test_utils import MockVimModule
MockVimModule()
import contextlib
import functools
import os
import requests
@ -32,22 +33,23 @@ import time
import warnings
from ycm.client.base_request import BaseRequest
from ycm.tests import test_utils
from ycm.youcompleteme import YouCompleteMe
from ycmd import user_options_store
from ycmd.utils import CloseStandardStreams, WaitUntilProcessIsTerminated
# The default options which are only relevant to the client, not the server and
# thus are not part of default_options.json, but are required for a working
# YouCompleteMe object.
DEFAULT_CLIENT_OPTIONS = {
'log_level': 'info',
'keep_logfiles': 0,
'extra_conf_vim_data': [],
'show_diagnostics_ui': 1,
'echo_current_diagnostic': 1,
'enable_diagnostic_signs': 1,
'enable_diagnostic_highlighting': 0,
'always_populate_location_list': 0,
'g:ycm_server_python_interpreter': '',
'g:ycm_log_level': 'info',
'g:ycm_keep_logfiles': 0,
'g:ycm_extra_conf_vim_data': [],
'g:ycm_show_diagnostics_ui': 1,
'g:ycm_echo_current_diagnostic': 1,
'g:ycm_enable_diagnostic_signs': 1,
'g:ycm_enable_diagnostic_highlighting': 0,
'g:ycm_always_populate_location_list': 0,
}
@ -56,11 +58,15 @@ def PathToTestFile( *args ):
return os.path.join( dir_of_current_script, 'testdata', *args )
def MakeUserOptions( custom_options = {} ):
options = dict( user_options_store.DefaultOptions() )
options.update( DEFAULT_CLIENT_OPTIONS )
options.update( custom_options )
return options
@contextlib.contextmanager
def UserOptions( options ):
old_vim_options = test_utils.VIM_OPTIONS.copy()
test_utils.VIM_OPTIONS.update( DEFAULT_CLIENT_OPTIONS )
test_utils.VIM_OPTIONS.update( options )
try:
yield
finally:
test_utils.VIM_OPTIONS = old_vim_options
def _IsReady():
@ -123,12 +129,13 @@ def YouCompleteMeInstance( custom_options = {} ):
def Decorator( test ):
@functools.wraps( test )
def Wrapper( *args, **kwargs ):
ycm = YouCompleteMe( MakeUserOptions( custom_options ) )
WaitUntilReady()
ycm.CheckIfServerIsReady()
try:
test( ycm, *args, **kwargs )
finally:
StopServer( ycm )
with UserOptions( custom_options ):
ycm = YouCompleteMe()
WaitUntilReady()
ycm.CheckIfServerIsReady()
try:
test( ycm, *args, **kwargs )
finally:
StopServer( ycm )
return Wrapper
return Decorator

View File

@ -31,7 +31,7 @@ from mock import patch
from ycm.tests import YouCompleteMeInstance
@YouCompleteMeInstance( { 'extra_conf_vim_data': [ 'tempname()' ] } )
@YouCompleteMeInstance( { 'g:ycm_extra_conf_vim_data': [ 'tempname()' ] } )
def SendCommandRequest_ExtraConfVimData_Works_test( ycm ):
current_buffer = VimBuffer( 'buffer' )
with MockVimBuffers( [ current_buffer ], current_buffer ):
@ -56,7 +56,7 @@ def SendCommandRequest_ExtraConfVimData_Works_test( ycm ):
)
@YouCompleteMeInstance( { 'extra_conf_vim_data': [ 'undefined_value' ] } )
@YouCompleteMeInstance( { 'g:ycm_extra_conf_vim_data': [ 'undefined_value' ] } )
def SendCommandRequest_ExtraConfData_UndefinedValue_test( ycm ):
current_buffer = VimBuffer( 'buffer' )
with MockVimBuffers( [ current_buffer ], current_buffer ):

View File

@ -351,7 +351,7 @@ def _Check_FileReadyToParse_Diagnostic_Warning( ycm ):
assert_that(
test_utils.VIM_SIGNS,
contains(
VimSign( SIGN_BUFFER_ID_INITIAL_VALUE + 1, 2, 'YcmWarning', 1 )
VimSign( SIGN_BUFFER_ID_INITIAL_VALUE + 2, 2, 'YcmWarning', 1 )
)
)
eq_( ycm.GetErrorCount(), 0 )
@ -363,7 +363,7 @@ def _Check_FileReadyToParse_Diagnostic_Warning( ycm ):
assert_that(
test_utils.VIM_SIGNS,
contains(
VimSign( SIGN_BUFFER_ID_INITIAL_VALUE + 1, 2, 'YcmWarning', 1 )
VimSign( SIGN_BUFFER_ID_INITIAL_VALUE + 2, 2, 'YcmWarning', 1 )
)
)
eq_( ycm.GetErrorCount(), 0 )
@ -390,7 +390,7 @@ def _Check_FileReadyToParse_Diagnostic_Clean( ycm ):
@patch( 'ycm.youcompleteme.YouCompleteMe._AddUltiSnipsDataIfNeeded' )
@YouCompleteMeInstance( { 'collect_identifiers_from_tags_files': 1 } )
@YouCompleteMeInstance( { 'g:ycm_collect_identifiers_from_tags_files': 1 } )
def EventNotification_FileReadyToParse_TagFiles_UnicodeWorkingDirectory_test(
ycm, *args ):
unicode_dir = PathToTestFile( 'uni¢𐍈d€' )
@ -534,7 +534,7 @@ def EventNotification_BufferUnload_BuildRequestForDeletedAndUnsavedBuffers_test(
@patch( 'ycm.vimsupport.CaptureVimCommand', return_value = """
fooGroup xxx foo bar
links to Statement""" )
@YouCompleteMeInstance( { 'seed_identifiers_with_syntax': 1 } )
@YouCompleteMeInstance( { 'g:ycm_seed_identifiers_with_syntax': 1 } )
def EventNotification_FileReadyToParse_SyntaxKeywords_SeedWithCache_test(
ycm, *args ):
@ -569,7 +569,7 @@ def EventNotification_FileReadyToParse_SyntaxKeywords_SeedWithCache_test(
@patch( 'ycm.vimsupport.CaptureVimCommand', return_value = """
fooGroup xxx foo bar
links to Statement""" )
@YouCompleteMeInstance( { 'seed_identifiers_with_syntax': 1 } )
@YouCompleteMeInstance( { 'g:ycm_seed_identifiers_with_syntax': 1 } )
def EventNotification_FileReadyToParse_SyntaxKeywords_ClearCacheIfRestart_test(
ycm, *args ):

View File

@ -1,6 +1,6 @@
# encoding: utf-8
#
# Copyright (C) 2016 YouCompleteMe contributors
# Copyright (C) 2016-2018 YouCompleteMe contributors
#
# This file is part of YouCompleteMe.
#
@ -39,7 +39,8 @@ TRIGGERS = {
}
@YouCompleteMeInstance( { 'cache_omnifunc': 1, 'semantic_triggers': TRIGGERS } )
@YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 1,
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_Cache_List_test( ycm ):
def Omnifunc( findstart, base ):
if findstart:
@ -62,7 +63,8 @@ def OmniCompleter_GetCompletions_Cache_List_test( ycm ):
)
@YouCompleteMeInstance( { 'cache_omnifunc': 1, 'semantic_triggers': TRIGGERS } )
@YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 1,
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_Cache_ListFilter_test( ycm ):
def Omnifunc( findstart, base ):
if findstart:
@ -85,7 +87,8 @@ def OmniCompleter_GetCompletions_Cache_ListFilter_test( ycm ):
)
@YouCompleteMeInstance( { 'cache_omnifunc': 0, 'semantic_triggers': TRIGGERS } )
@YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 0,
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_NoCache_List_test( ycm ):
def Omnifunc( findstart, base ):
if findstart:
@ -108,7 +111,8 @@ def OmniCompleter_GetCompletions_NoCache_List_test( ycm ):
)
@YouCompleteMeInstance( { 'cache_omnifunc': 0, 'semantic_triggers': TRIGGERS } )
@YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 0,
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_NoCache_ListFilter_test( ycm ):
def Omnifunc( findstart, base ):
if findstart:
@ -133,7 +137,8 @@ def OmniCompleter_GetCompletions_NoCache_ListFilter_test( ycm ):
)
@YouCompleteMeInstance( { 'cache_omnifunc': 0, 'semantic_triggers': TRIGGERS } )
@YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 0,
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_NoCache_UseFindStart_test( ycm ):
def Omnifunc( findstart, base ):
if findstart:
@ -158,7 +163,8 @@ def OmniCompleter_GetCompletions_NoCache_UseFindStart_test( ycm ):
)
@YouCompleteMeInstance( { 'cache_omnifunc': 1, 'semantic_triggers': TRIGGERS } )
@YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 1,
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_Cache_UseFindStart_test( ycm ):
def Omnifunc( findstart, base ):
if findstart:
@ -183,7 +189,8 @@ def OmniCompleter_GetCompletions_Cache_UseFindStart_test( ycm ):
)
@YouCompleteMeInstance( { 'cache_omnifunc': 1, 'semantic_triggers': TRIGGERS } )
@YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 1,
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_Cache_Object_test( ycm ):
def Omnifunc( findstart, base ):
if findstart:
@ -206,7 +213,8 @@ def OmniCompleter_GetCompletions_Cache_Object_test( ycm ):
)
@YouCompleteMeInstance( { 'cache_omnifunc': 1, 'semantic_triggers': TRIGGERS } )
@YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 1,
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_Cache_ObjectList_test( ycm ):
def Omnifunc( findstart, base ):
if findstart:
@ -250,7 +258,8 @@ def OmniCompleter_GetCompletions_Cache_ObjectList_test( ycm ):
)
@YouCompleteMeInstance( { 'cache_omnifunc': 0, 'semantic_triggers': TRIGGERS } )
@YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 0,
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_NoCache_ObjectList_test( ycm ):
def Omnifunc( findstart, base ):
if findstart:
@ -302,7 +311,8 @@ def OmniCompleter_GetCompletions_NoCache_ObjectList_test( ycm ):
)
@YouCompleteMeInstance( { 'cache_omnifunc': 1, 'semantic_triggers': TRIGGERS } )
@YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 1,
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_Cache_ObjectListObject_test( ycm ):
def Omnifunc( findstart, base ):
if findstart:
@ -346,7 +356,8 @@ def OmniCompleter_GetCompletions_Cache_ObjectListObject_test( ycm ):
)
@YouCompleteMeInstance( { 'cache_omnifunc': 0, 'semantic_triggers': TRIGGERS } )
@YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 0,
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_NoCache_ObjectListObject_test( ycm ):
def Omnifunc( findstart, base ):
if findstart:
@ -398,7 +409,8 @@ def OmniCompleter_GetCompletions_NoCache_ObjectListObject_test( ycm ):
)
@YouCompleteMeInstance( { 'cache_omnifunc': 1, 'semantic_triggers': TRIGGERS } )
@YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 1,
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_Cache_List_Unicode_test( ycm ):
def Omnifunc( findstart, base ):
if findstart:
@ -423,7 +435,8 @@ def OmniCompleter_GetCompletions_Cache_List_Unicode_test( ycm ):
)
@YouCompleteMeInstance( { 'cache_omnifunc': 0, 'semantic_triggers': TRIGGERS } )
@YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 0,
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_NoCache_List_Unicode_test( ycm ):
def Omnifunc( findstart, base ):
if findstart:
@ -448,7 +461,8 @@ def OmniCompleter_GetCompletions_NoCache_List_Unicode_test( ycm ):
)
@YouCompleteMeInstance( { 'cache_omnifunc': 1, 'semantic_triggers': TRIGGERS } )
@YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 1,
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_Cache_List_Filter_Unicode_test( ycm ):
def Omnifunc( findstart, base ):
if findstart:
@ -471,7 +485,8 @@ def OmniCompleter_GetCompletions_Cache_List_Filter_Unicode_test( ycm ):
)
@YouCompleteMeInstance( { 'cache_omnifunc': 0, 'semantic_triggers': TRIGGERS } )
@YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 0,
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_NoCache_List_Filter_Unicode_test( ycm ):
def Omnifunc( findstart, base ):
if findstart:
@ -494,7 +509,8 @@ def OmniCompleter_GetCompletions_NoCache_List_Filter_Unicode_test( ycm ):
)
@YouCompleteMeInstance( { 'cache_omnifunc': 1, 'semantic_triggers': TRIGGERS } )
@YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 1,
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_Cache_ObjectList_Unicode_test( ycm ):
def Omnifunc( findstart, base ):
if findstart:
@ -538,7 +554,8 @@ def OmniCompleter_GetCompletions_Cache_ObjectList_Unicode_test( ycm ):
)
@YouCompleteMeInstance( { 'cache_omnifunc': 1, 'semantic_triggers': TRIGGERS } )
@YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 1,
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_Cache_ObjectListObject_Unicode_test( ycm ):
def Omnifunc( findstart, base ):
if findstart:
@ -597,7 +614,8 @@ def OmniCompleter_GetCompletions_Cache_ObjectListObject_Unicode_test( ycm ):
)
@YouCompleteMeInstance( { 'cache_omnifunc': 1, 'semantic_triggers': TRIGGERS } )
@YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 1,
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_RestoreCursorPositionAfterOmnifuncCall_test(
ycm ):
@ -631,7 +649,8 @@ def OmniCompleter_GetCompletions_RestoreCursorPositionAfterOmnifuncCall_test(
)
@YouCompleteMeInstance( { 'cache_omnifunc': 0, 'semantic_triggers': TRIGGERS } )
@YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 0,
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_NoCache_NoSemanticTrigger_test( ycm ):
def Omnifunc( findstart, base ):
if findstart:
@ -654,7 +673,8 @@ def OmniCompleter_GetCompletions_NoCache_NoSemanticTrigger_test( ycm ):
)
@YouCompleteMeInstance( { 'cache_omnifunc': 0, 'semantic_triggers': TRIGGERS } )
@YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 0,
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_NoCache_ForceSemantic_test( ycm ):
def Omnifunc( findstart, base ):
if findstart:
@ -678,9 +698,9 @@ def OmniCompleter_GetCompletions_NoCache_ForceSemantic_test( ycm ):
@YouCompleteMeInstance( {
'cache_omnifunc': 0,
'filetype_specific_completion_to_disable': { FILETYPE: 1 },
'semantic_triggers': TRIGGERS } )
'g:ycm_cache_omnifunc': 0,
'g:ycm_filetype_specific_completion_to_disable': { FILETYPE: 1 },
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_FiletypeDisabled_SemanticTrigger_test( ycm ):
def Omnifunc( findstart, base ):
if findstart:
@ -704,9 +724,9 @@ def OmniCompleter_GetCompletions_FiletypeDisabled_SemanticTrigger_test( ycm ):
@YouCompleteMeInstance( {
'cache_omnifunc': 0,
'filetype_specific_completion_to_disable': { '*': 1 },
'semantic_triggers': TRIGGERS } )
'g:ycm_cache_omnifunc': 0,
'g:ycm_filetype_specific_completion_to_disable': { '*': 1 },
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_AllFiletypesDisabled_SemanticTrigger_test(
ycm ):
@ -732,9 +752,9 @@ def OmniCompleter_GetCompletions_AllFiletypesDisabled_SemanticTrigger_test(
@YouCompleteMeInstance( {
'cache_omnifunc': 0,
'filetype_specific_completion_to_disable': { FILETYPE: 1 },
'semantic_triggers': TRIGGERS } )
'g:ycm_cache_omnifunc': 0,
'g:ycm_filetype_specific_completion_to_disable': { FILETYPE: 1 },
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_FiletypeDisabled_ForceSemantic_test( ycm ):
def Omnifunc( findstart, base ):
if findstart:
@ -758,9 +778,9 @@ def OmniCompleter_GetCompletions_FiletypeDisabled_ForceSemantic_test( ycm ):
@YouCompleteMeInstance( {
'cache_omnifunc': 0,
'filetype_specific_completion_to_disable': { '*': 1 },
'semantic_triggers': TRIGGERS } )
'g:ycm_cache_omnifunc': 0,
'g:ycm_filetype_specific_completion_to_disable': { '*': 1 },
'g:ycm_semantic_triggers': TRIGGERS } )
def OmniCompleter_GetCompletions_AllFiletypesDisabled_ForceSemantic_test( ycm ):
def Omnifunc( findstart, base ):
if findstart:

View File

@ -22,11 +22,12 @@ from __future__ import absolute_import
# Not installing aliases from python-future; it's unreliable and slow.
from builtins import * # noqa
from future.utils import PY2
from future.utils import iteritems, PY2
from mock import DEFAULT, MagicMock, patch
from hamcrest import assert_that, equal_to
import contextlib
import functools
import json
import nose
import os
import re
@ -56,6 +57,8 @@ SIGN_UNPLACE_REGEX = re.compile(
'^sign unplace (?P<id>\d+) buffer=(?P<bufnr>\d+)$' )
REDIR_START_REGEX = re.compile( '^redir => (?P<variable>[\w:]+)$' )
REDIR_END_REGEX = re.compile( '^redir END$' )
EXISTS_REGEX = re.compile( '^exists\( \'(?P<option>[\w:]+)\' \)$' )
LET_REGEX = re.compile( '^let (?P<option>[\w:]+) = (?P<value>.*)$' )
# One-and only instance of mocked Vim object. The first 'import vim' that is
# executed binds the vim module to the instance of MagicMock that is created,
@ -70,6 +73,15 @@ VIM_MOCK = MagicMock()
VIM_MATCHES = []
VIM_SIGNS = []
VIM_OPTIONS = {
'&previewheight': 12,
'&columns': 80,
'&ruler': 0,
'&showcmd': 1,
'&hidden': 0,
'&expandtab': 1
}
REDIR = {
'status': False,
'variable': '',
@ -153,23 +165,21 @@ def _MockVimBufferEval( value ):
def _MockVimOptionsEval( value ):
if value == '&previewheight':
return 12
result = VIM_OPTIONS.get( value )
if result is not None:
return result
if value == '&columns':
return 80
if value == 'keys( g: )':
global_options = {}
for key, value in iteritems( VIM_OPTIONS ):
if key.startswith( 'g:' ):
global_options[ key[ 2: ] ] = value
return global_options
if value == '&ruler':
return 0
if value == '&showcmd':
return 1
if value == '&hidden':
return 0
if value == '&expandtab':
return 1
match = EXISTS_REGEX.search( value )
if match:
option = match.group( 'option' )
return option in VIM_OPTIONS
return None
@ -213,23 +223,12 @@ def _MockVimMatchEval( value ):
return None
# This variable exists to easily mock the 'g:ycm_server_python_interpreter'
# option in tests.
server_python_interpreter = ''
def _MockVimEval( value ):
if value == 'g:ycm_min_num_of_chars_for_completion':
return 0
if value == 'g:ycm_server_python_interpreter':
return server_python_interpreter
result = _MockVimFunctionsEval( value )
result = _MockVimOptionsEval( value )
if result is not None:
return result
result = _MockVimOptionsEval( value )
result = _MockVimFunctionsEval( value )
if result is not None:
return result
@ -317,6 +316,13 @@ def _MockVimCommand( command ):
if result:
return
match = LET_REGEX.search( command )
if match:
option = match.group( 'option' )
value = json.loads( match.group( 'value' ) )
VIM_OPTIONS[ option ] = value
return
return DEFAULT

View File

@ -33,11 +33,11 @@ from hamcrest import ( assert_that, contains, empty, equal_to, is_in, is_not,
from mock import call, MagicMock, patch
from ycm.paths import _PathToPythonUsedDuringBuild
from ycm.vimsupport import SIGN_BUFFER_ID_INITIAL_VALUE
from ycm.youcompleteme import YouCompleteMe
from ycm.tests import ( MakeUserOptions, StopServer, test_utils,
WaitUntilReady, YouCompleteMeInstance )
from ycm.vimsupport import SetVariableValue, SIGN_BUFFER_ID_INITIAL_VALUE
from ycm.tests import ( StopServer, test_utils, UserOptions, WaitUntilReady,
YouCompleteMeInstance )
from ycm.client.base_request import _LoadExtraConfFile
from ycm.youcompleteme import YouCompleteMe
from ycmd.responses import ServerError
from ycm.tests.mock_utils import ( MockAsyncServerResponseDone,
MockAsyncServerResponseInProgress,
@ -54,10 +54,11 @@ def YouCompleteMe_YcmCoreNotImported_test( ycm ):
@patch( 'ycm.vimsupport.PostVimMessage' )
def YouCompleteMe_InvalidPythonInterpreterPath_test( post_vim_message ):
try:
with patch( 'ycm.tests.test_utils.server_python_interpreter',
'/invalid/path/to/python' ):
ycm = YouCompleteMe( MakeUserOptions() )
with UserOptions( {
'g:ycm_server_python_interpreter': '/invalid/python/path' } ):
try:
ycm = YouCompleteMe()
assert_that( ycm.IsServerAlive(), equal_to( False ) )
post_vim_message.assert_called_once_with(
"Unable to start the ycmd server. "
@ -65,27 +66,28 @@ def YouCompleteMe_InvalidPythonInterpreterPath_test( post_vim_message ):
"to a valid Python 2.7 or 3.4+. "
"Correct the error then restart the server with ':YcmRestartServer'." )
post_vim_message.reset_mock()
post_vim_message.reset_mock()
with patch( 'ycm.tests.test_utils.server_python_interpreter',
_PathToPythonUsedDuringBuild() ):
SetVariableValue( 'g:ycm_server_python_interpreter',
_PathToPythonUsedDuringBuild() )
ycm.RestartServer()
assert_that( ycm.IsServerAlive(), equal_to( True ) )
post_vim_message.assert_called_once_with( 'Restarting ycmd server...' )
finally:
WaitUntilReady()
StopServer( ycm )
assert_that( ycm.IsServerAlive(), equal_to( True ) )
post_vim_message.assert_called_once_with( 'Restarting ycmd server...' )
finally:
WaitUntilReady()
StopServer( ycm )
@patch( 'ycmd.utils.PathToFirstExistingExecutable', return_value = None )
@patch( 'ycm.paths._EndsWithPython', return_value = False )
@patch( 'ycm.vimsupport.PostVimMessage' )
def YouCompleteMe_NoPythonInterpreterFound_test( post_vim_message, *args ):
try:
with patch( 'ycmd.utils.ReadFile', side_effect = IOError ):
with UserOptions( {} ):
try:
with patch( 'ycmd.utils.ReadFile', side_effect = IOError ):
ycm = YouCompleteMe()
ycm = YouCompleteMe( MakeUserOptions() )
assert_that( ycm.IsServerAlive(), equal_to( False ) )
post_vim_message.assert_called_once_with(
"Unable to start the ycmd server. Cannot find Python 2.7 or 3.4+. "
@ -93,17 +95,17 @@ def YouCompleteMe_NoPythonInterpreterFound_test( post_vim_message, *args ):
"interpreter path. "
"Correct the error then restart the server with ':YcmRestartServer'." )
post_vim_message.reset_mock()
post_vim_message.reset_mock()
with patch( 'ycm.tests.test_utils.server_python_interpreter',
_PathToPythonUsedDuringBuild() ):
SetVariableValue( 'g:ycm_server_python_interpreter',
_PathToPythonUsedDuringBuild() )
ycm.RestartServer()
assert_that( ycm.IsServerAlive(), equal_to( True ) )
post_vim_message.assert_called_once_with( 'Restarting ycmd server...' )
finally:
WaitUntilReady()
StopServer( ycm )
assert_that( ycm.IsServerAlive(), equal_to( True ) )
post_vim_message.assert_called_once_with( 'Restarting ycmd server...' )
finally:
WaitUntilReady()
StopServer( ycm )
@YouCompleteMeInstance()
@ -185,7 +187,7 @@ def YouCompleteMe_NotifyUserIfServerCrashed_UnexpectedExitCode_test():
} )
@YouCompleteMeInstance( { 'extra_conf_vim_data': [ 'tempname()' ] } )
@YouCompleteMeInstance( { 'g:ycm_extra_conf_vim_data': [ 'tempname()' ] } )
def YouCompleteMe_DebugInfo_ServerRunning_test( ycm ):
dir_of_script = os.path.dirname( os.path.abspath( __file__ ) )
buf_name = os.path.join( dir_of_script, 'testdata', 'test.cpp' )
@ -246,7 +248,7 @@ def YouCompleteMe_OnVimLeave_RemoveClientLogfileByDefault_test( ycm ):
'Logfile {0} was not removed.'.format( client_logfile ) )
@YouCompleteMeInstance( { 'keep_logfiles': 1 } )
@YouCompleteMeInstance( { 'g:ycm_keep_logfiles': 1 } )
def YouCompleteMe_OnVimLeave_KeepClientLogfile_test( ycm ):
client_logfile = ycm._client_logfile
assert_that( os.path.isfile( client_logfile ),
@ -421,9 +423,9 @@ def YouCompleteMe_ShowDiagnostics_NoDiagnosticsDetected_test(
set_location_list_for_window.assert_called_once_with( 0, [] )
@YouCompleteMeInstance( { 'log_level': 'debug',
'keep_logfiles': 1,
'open_loclist_on_ycm_diags': 0 } )
@YouCompleteMeInstance( { 'g:ycm_log_level': 'debug',
'g:ycm_keep_logfiles': 1,
'g:ycm_open_loclist_on_ycm_diags': 0 } )
@patch( 'ycm.youcompleteme.YouCompleteMe.FiletypeCompleterExistsForFiletype',
return_value = True )
@patch( 'ycm.vimsupport.PostVimMessage', new_callable = ExtendedMock )
@ -465,7 +467,7 @@ def YouCompleteMe_ShowDiagnostics_DiagnosticsFound_DoNotOpenLocationList_test(
} ] )
@YouCompleteMeInstance( { 'open_loclist_on_ycm_diags': 1 } )
@YouCompleteMeInstance( { 'g:ycm_open_loclist_on_ycm_diags': 1 } )
@patch( 'ycm.youcompleteme.YouCompleteMe.FiletypeCompleterExistsForFiletype',
return_value = True )
@patch( 'ycm.vimsupport.PostVimMessage', new_callable = ExtendedMock )
@ -513,9 +515,9 @@ def YouCompleteMe_ShowDiagnostics_DiagnosticsFound_OpenLocationList_test(
open_location_list.assert_called_once_with( focus = True )
@YouCompleteMeInstance( { 'echo_current_diagnostic': 1,
'enable_diagnostic_signs': 1,
'enable_diagnostic_highlighting': 1 } )
@YouCompleteMeInstance( { 'g:ycm_echo_current_diagnostic': 1,
'g:ycm_enable_diagnostic_signs': 1,
'g:ycm_enable_diagnostic_highlighting': 1 } )
@patch( 'ycm.youcompleteme.YouCompleteMe.FiletypeCompleterExistsForFiletype',
return_value = True )
@patch( 'ycm.vimsupport.PostVimMessage', new_callable = ExtendedMock )
@ -665,7 +667,7 @@ def YouCompleteMe_UpdateDiagnosticInterface_PrioritizeErrorsOverWarnings_test(
)
@YouCompleteMeInstance( { 'enable_diagnostic_highlighting': 1 } )
@YouCompleteMeInstance( { 'g:ycm_enable_diagnostic_highlighting': 1 } )
def YouCompleteMe_UpdateMatches_ClearDiagnosticMatchesInNewBuffer_test( ycm ):
current_buffer = VimBuffer( 'buffer',
filetype = 'c',
@ -684,8 +686,8 @@ def YouCompleteMe_UpdateMatches_ClearDiagnosticMatchesInNewBuffer_test( ycm ):
assert_that( test_utils.VIM_MATCHES, empty() )
@YouCompleteMeInstance( { 'echo_current_diagnostic': 1,
'always_populate_location_list': 1 } )
@YouCompleteMeInstance( { 'g:ycm_echo_current_diagnostic': 1,
'g:ycm_always_populate_location_list': 1 } )
@patch.object( ycm_buffer_module,
'DIAGNOSTIC_UI_ASYNC_FILETYPES',
[ 'ycmtest' ] )
@ -799,8 +801,8 @@ def YouCompleteMe_AsyncDiagnosticUpdate_SingleFile_test( ycm,
] )
@YouCompleteMeInstance( { 'echo_current_diagnostic': 1,
'always_populate_location_list': 1 } )
@YouCompleteMeInstance( { 'g:ycm_echo_current_diagnostic': 1,
'g:ycm_always_populate_location_list': 1 } )
@patch.object( ycm_buffer_module,
'DIAGNOSTIC_UI_ASYNC_FILETYPES',
[ 'ycmtest' ] )

View File

@ -49,6 +49,8 @@ NO_SELECTION_MADE_MSG = "No valid selection was made; aborting."
# value is then incremented for each new sign. This should prevent conflicts
# with other plugins using signs.
SIGN_BUFFER_ID_INITIAL_VALUE = 100000000
# This holds the next sign's id to assign for each buffer.
SIGN_ID_FOR_BUFFER = defaultdict( lambda: SIGN_BUFFER_ID_INITIAL_VALUE )
SIGN_PLACE_REGEX = re.compile(
r"^.*=(?P<line>\d+).*=(?P<id>\d+).*=(?P<name>Ycm\w+)$" )
@ -204,6 +206,12 @@ def GetSignsInBuffer( buffer_number ):
return signs
def CreateSign( line, name, buffer_number ):
sign_id = SIGN_ID_FOR_BUFFER[ buffer_number ]
SIGN_ID_FOR_BUFFER[ buffer_number ] += 1
return DiagnosticSign( sign_id, line, name, buffer_number )
def UnplaceSign( sign ):
vim.command( 'sign unplace {0} buffer={1}'.format( sign.id,
sign.buffer_number ) )

View File

@ -35,8 +35,7 @@ from ycm import base, paths, vimsupport
from ycm.buffer import ( BufferDict,
DIAGNOSTIC_UI_FILETYPES,
DIAGNOSTIC_UI_ASYNC_FILETYPES )
from ycmd import utils
from ycmd import server_utils
from ycmd import server_utils, user_options_store, utils
from ycmd.request_wrap import RequestWrap
from ycm.omni_completer import OmniCompleter
from ycm import syntax_parse
@ -107,12 +106,12 @@ HANDLE_FLAG_INHERIT = 0x00000001
class YouCompleteMe( object ):
def __init__( self, user_options ):
def __init__( self ):
self._available_completers = {}
self._user_options = user_options
self._user_options = None
self._user_notified_about_crash = False
self._omnicomp = OmniCompleter( user_options )
self._buffers = BufferDict( user_options )
self._omnicomp = None
self._buffers = None
self._latest_completion_request = None
self._logger = logging.getLogger( 'ycm' )
self._client_logfile = None
@ -134,6 +133,14 @@ class YouCompleteMe( object ):
self._server_is_ready_with_cache = False
self._message_poll_request = None
base.LoadJsonDefaultsIntoVim()
user_options_store.SetAll( base.BuildServerConf() )
self._user_options = user_options_store.GetAll()
self._omnicomp = OmniCompleter( self._user_options )
self._buffers = BufferDict( self._user_options )
self._SetLogLevel()
hmac_secret = os.urandom( HMAC_SECRET_LENGTH )
options_dict = dict( self._user_options )
options_dict[ 'hmac_secret' ] = utils.ToUnicode(
@ -196,12 +203,6 @@ class YouCompleteMe( object ):
self._client_logfile = utils.CreateLogfile( CLIENT_LOGFILE_FORMAT )
log_level = self._user_options[ 'log_level' ]
numeric_level = getattr( logging, log_level.upper(), None )
if not isinstance( numeric_level, int ):
raise ValueError( 'Invalid log level: {0}'.format( log_level ) )
self._logger.setLevel( numeric_level )
handler = logging.FileHandler( self._client_logfile )
# On Windows and Python prior to 3.4, file handles are inherited by child
@ -221,6 +222,14 @@ class YouCompleteMe( object ):
self._logger.addHandler( handler )
def _SetLogLevel( self ):
log_level = self._user_options[ 'log_level' ]
numeric_level = getattr( logging, log_level.upper(), None )
if not isinstance( numeric_level, int ):
raise ValueError( 'Invalid log level: {0}'.format( log_level ) )
self._logger.setLevel( numeric_level )
def IsServerAlive( self ):
# When the process hasn't finished yet, poll() returns None.
return bool( self._server_popen ) and self._server_popen.poll() is None