소스 검색

Allow users to change the options by restarting the server

micbou 6 년 전
부모
커밋
d16d3cebc4

+ 2 - 1
README.md

@@ -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
 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
 ### The `g:ycm_min_num_of_chars_for_completion` option
 
 

+ 22 - 14
autoload/youcompleteme.vim

@@ -98,15 +98,7 @@ function! s:ReceiveMessages( timer_id )
 endfunction
 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:SetUpCommands()
   call s:SetUpCpoptions()
   call s:SetUpCpoptions()
   call s:SetUpCompleteopt()
   call s:SetUpCompleteopt()
@@ -118,6 +110,17 @@ function! youcompleteme#Enable()
 
 
   call s:SetUpSigns()
   call s:SetUpSigns()
   call s:SetUpSyntaxHighlighting()
   call s:SetUpSyntaxHighlighting()
+endfunction
+
+
+function! youcompleteme#Enable()
+  call s:SetUpBackwardsCompatibility()
+
+  if !s:SetUpPython()
+    return
+  endif
+
+  call s:SetUpOptions()
 
 
   call youcompleteme#EnableCursorMovedAutocommands()
   call youcompleteme#EnableCursorMovedAutocommands()
   augroup youcompleteme
   augroup youcompleteme
@@ -191,17 +194,20 @@ import vim
 # Add python sources folder to the system path.
 # Add python sources folder to the system path.
 script_folder = vim.eval( 's:script_folder_path' )
 script_folder = vim.eval( 's:script_folder_path' )
 sys.path.insert( 0, os.path.join( script_folder, '..', 'python' ) )
 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.
 # We enclose this code in a try/except block to avoid backtraces in Vim.
 try:
 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.
   # 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:
 except Exception as error:
   # We don't use PostVimMessage or EchoText from the vimsupport module because
   # We don't use PostVimMessage or EchoText from the vimsupport module because
   # importing this module may fail.
   # importing this module may fail.
@@ -849,6 +855,8 @@ endfunction
 
 
 
 
 function! s:RestartServer()
 function! s:RestartServer()
+  call s:SetUpOptions()
+
   exec s:python_command "ycm_state.RestartServer()"
   exec s:python_command "ycm_state.RestartServer()"
 
 
   call timer_stop( s:pollers.receive_messages.id )
   call timer_stop( s:pollers.receive_messages.id )

+ 11 - 8
doc/youcompleteme.txt

@@ -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
 OpenBSD 5.5 and later have a Vim that's recent enough. You can see the version
 of Vim installed by running 'vim --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].
 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
 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.
 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:
 Compiling YCM **with** semantic support for C-family languages:
 >
 >
   cd ~/.vim/bundle/YouCompleteMe
   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:
 Compiling YCM **without** semantic support for C-family languages:
 >
 >
   cd ~/.vim/bundle/YouCompleteMe
   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:
 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
   let g:ycm_min_num_of_chars_for_completion = 1
 <
 <
 Note that after changing an option in your vimrc script [38] you have to
 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
 The *g:ycm_min_num_of_chars_for_completion* option

+ 2 - 7
python/ycm/diagnostic_interface.py

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

+ 0 - 53
python/ycm/setup.py

@@ -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() )

+ 29 - 22
python/ycm/tests/__init__.py

@@ -1,4 +1,4 @@
-# Copyright (C) 2016 YouCompleteMe contributors
+# Copyright (C) 2016-2018 YouCompleteMe contributors
 #
 #
 # This file is part of YouCompleteMe.
 # This file is part of YouCompleteMe.
 #
 #
@@ -25,6 +25,7 @@ from builtins import *  # noqa
 from ycm.tests.test_utils import MockVimModule
 from ycm.tests.test_utils import MockVimModule
 MockVimModule()
 MockVimModule()
 
 
+import contextlib
 import functools
 import functools
 import os
 import os
 import requests
 import requests
@@ -32,22 +33,23 @@ import time
 import warnings
 import warnings
 
 
 from ycm.client.base_request import BaseRequest
 from ycm.client.base_request import BaseRequest
+from ycm.tests import test_utils
 from ycm.youcompleteme import YouCompleteMe
 from ycm.youcompleteme import YouCompleteMe
-from ycmd import user_options_store
 from ycmd.utils import CloseStandardStreams, WaitUntilProcessIsTerminated
 from ycmd.utils import CloseStandardStreams, WaitUntilProcessIsTerminated
 
 
 # The default options which are only relevant to the client, not the server and
 # 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
 # thus are not part of default_options.json, but are required for a working
 # YouCompleteMe object.
 # YouCompleteMe object.
 DEFAULT_CLIENT_OPTIONS = {
 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 )
   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():
 def _IsReady():
@@ -123,12 +129,13 @@ def YouCompleteMeInstance( custom_options = {} ):
   def Decorator( test ):
   def Decorator( test ):
     @functools.wraps( test )
     @functools.wraps( test )
     def Wrapper( *args, **kwargs ):
     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 Wrapper
   return Decorator
   return Decorator

+ 2 - 2
python/ycm/tests/command_test.py

@@ -31,7 +31,7 @@ from mock import patch
 from ycm.tests import YouCompleteMeInstance
 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 ):
 def SendCommandRequest_ExtraConfVimData_Works_test( ycm ):
   current_buffer = VimBuffer( 'buffer' )
   current_buffer = VimBuffer( 'buffer' )
   with MockVimBuffers( [ current_buffer ], current_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 ):
 def SendCommandRequest_ExtraConfData_UndefinedValue_test( ycm ):
   current_buffer = VimBuffer( 'buffer' )
   current_buffer = VimBuffer( 'buffer' )
   with MockVimBuffers( [ current_buffer ], current_buffer ):
   with MockVimBuffers( [ current_buffer ], current_buffer ):

+ 5 - 5
python/ycm/tests/event_notification_test.py

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

+ 53 - 33
python/ycm/tests/omni_completer_test.py

@@ -1,6 +1,6 @@
 # encoding: utf-8
 # encoding: utf-8
 #
 #
-# Copyright (C) 2016 YouCompleteMe contributors
+# Copyright (C) 2016-2018 YouCompleteMe contributors
 #
 #
 # This file is part of YouCompleteMe.
 # 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 OmniCompleter_GetCompletions_Cache_List_test( ycm ):
   def Omnifunc( findstart, base ):
   def Omnifunc( findstart, base ):
     if findstart:
     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 OmniCompleter_GetCompletions_Cache_ListFilter_test( ycm ):
   def Omnifunc( findstart, base ):
   def Omnifunc( findstart, base ):
     if findstart:
     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 OmniCompleter_GetCompletions_NoCache_List_test( ycm ):
   def Omnifunc( findstart, base ):
   def Omnifunc( findstart, base ):
     if findstart:
     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 OmniCompleter_GetCompletions_NoCache_ListFilter_test( ycm ):
   def Omnifunc( findstart, base ):
   def Omnifunc( findstart, base ):
     if findstart:
     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 OmniCompleter_GetCompletions_NoCache_UseFindStart_test( ycm ):
   def Omnifunc( findstart, base ):
   def Omnifunc( findstart, base ):
     if findstart:
     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 OmniCompleter_GetCompletions_Cache_UseFindStart_test( ycm ):
   def Omnifunc( findstart, base ):
   def Omnifunc( findstart, base ):
     if findstart:
     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 OmniCompleter_GetCompletions_Cache_Object_test( ycm ):
   def Omnifunc( findstart, base ):
   def Omnifunc( findstart, base ):
     if findstart:
     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 OmniCompleter_GetCompletions_Cache_ObjectList_test( ycm ):
   def Omnifunc( findstart, base ):
   def Omnifunc( findstart, base ):
     if findstart:
     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 OmniCompleter_GetCompletions_NoCache_ObjectList_test( ycm ):
   def Omnifunc( findstart, base ):
   def Omnifunc( findstart, base ):
     if findstart:
     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 OmniCompleter_GetCompletions_Cache_ObjectListObject_test( ycm ):
   def Omnifunc( findstart, base ):
   def Omnifunc( findstart, base ):
     if findstart:
     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 OmniCompleter_GetCompletions_NoCache_ObjectListObject_test( ycm ):
   def Omnifunc( findstart, base ):
   def Omnifunc( findstart, base ):
     if findstart:
     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 OmniCompleter_GetCompletions_Cache_List_Unicode_test( ycm ):
   def Omnifunc( findstart, base ):
   def Omnifunc( findstart, base ):
     if findstart:
     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 OmniCompleter_GetCompletions_NoCache_List_Unicode_test( ycm ):
   def Omnifunc( findstart, base ):
   def Omnifunc( findstart, base ):
     if findstart:
     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 OmniCompleter_GetCompletions_Cache_List_Filter_Unicode_test( ycm ):
   def Omnifunc( findstart, base ):
   def Omnifunc( findstart, base ):
     if findstart:
     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 OmniCompleter_GetCompletions_NoCache_List_Filter_Unicode_test( ycm ):
   def Omnifunc( findstart, base ):
   def Omnifunc( findstart, base ):
     if findstart:
     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 OmniCompleter_GetCompletions_Cache_ObjectList_Unicode_test( ycm ):
   def Omnifunc( findstart, base ):
   def Omnifunc( findstart, base ):
     if findstart:
     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 OmniCompleter_GetCompletions_Cache_ObjectListObject_Unicode_test( ycm ):
   def Omnifunc( findstart, base ):
   def Omnifunc( findstart, base ):
     if findstart:
     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(
 def OmniCompleter_GetCompletions_RestoreCursorPositionAfterOmnifuncCall_test(
   ycm ):
   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 OmniCompleter_GetCompletions_NoCache_NoSemanticTrigger_test( ycm ):
   def Omnifunc( findstart, base ):
   def Omnifunc( findstart, base ):
     if findstart:
     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 OmniCompleter_GetCompletions_NoCache_ForceSemantic_test( ycm ):
   def Omnifunc( findstart, base ):
   def Omnifunc( findstart, base ):
     if findstart:
     if findstart:
@@ -678,9 +698,9 @@ def OmniCompleter_GetCompletions_NoCache_ForceSemantic_test( ycm ):
 
 
 
 
 @YouCompleteMeInstance( {
 @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 OmniCompleter_GetCompletions_FiletypeDisabled_SemanticTrigger_test( ycm ):
   def Omnifunc( findstart, base ):
   def Omnifunc( findstart, base ):
     if findstart:
     if findstart:
@@ -704,9 +724,9 @@ def OmniCompleter_GetCompletions_FiletypeDisabled_SemanticTrigger_test( ycm ):
 
 
 
 
 @YouCompleteMeInstance( {
 @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(
 def OmniCompleter_GetCompletions_AllFiletypesDisabled_SemanticTrigger_test(
   ycm ):
   ycm ):
 
 
@@ -732,9 +752,9 @@ def OmniCompleter_GetCompletions_AllFiletypesDisabled_SemanticTrigger_test(
 
 
 
 
 @YouCompleteMeInstance( {
 @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 OmniCompleter_GetCompletions_FiletypeDisabled_ForceSemantic_test( ycm ):
   def Omnifunc( findstart, base ):
   def Omnifunc( findstart, base ):
     if findstart:
     if findstart:
@@ -758,9 +778,9 @@ def OmniCompleter_GetCompletions_FiletypeDisabled_ForceSemantic_test( ycm ):
 
 
 
 
 @YouCompleteMeInstance( {
 @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 OmniCompleter_GetCompletions_AllFiletypesDisabled_ForceSemantic_test( ycm ):
   def Omnifunc( findstart, base ):
   def Omnifunc( findstart, base ):
     if findstart:
     if findstart:

+ 35 - 29
python/ycm/tests/test_utils.py

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

+ 43 - 41
python/ycm/tests/youcompleteme_test.py

@@ -33,11 +33,11 @@ from hamcrest import ( assert_that, contains, empty, equal_to, is_in, is_not,
 from mock import call, MagicMock, patch
 from mock import call, MagicMock, patch
 
 
 from ycm.paths import _PathToPythonUsedDuringBuild
 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.client.base_request import _LoadExtraConfFile
+from ycm.youcompleteme import YouCompleteMe
 from ycmd.responses import ServerError
 from ycmd.responses import ServerError
 from ycm.tests.mock_utils import ( MockAsyncServerResponseDone,
 from ycm.tests.mock_utils import ( MockAsyncServerResponseDone,
                                    MockAsyncServerResponseInProgress,
                                    MockAsyncServerResponseInProgress,
@@ -54,10 +54,11 @@ def YouCompleteMe_YcmCoreNotImported_test( ycm ):
 
 
 @patch( 'ycm.vimsupport.PostVimMessage' )
 @patch( 'ycm.vimsupport.PostVimMessage' )
 def YouCompleteMe_InvalidPythonInterpreterPath_test( post_vim_message ):
 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 ) )
       assert_that( ycm.IsServerAlive(), equal_to( False ) )
       post_vim_message.assert_called_once_with(
       post_vim_message.assert_called_once_with(
         "Unable to start the ycmd server. "
         "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+. "
         "to a valid Python 2.7 or 3.4+. "
         "Correct the error then restart the server with ':YcmRestartServer'." )
         "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()
       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( 'ycmd.utils.PathToFirstExistingExecutable', return_value = None )
 @patch( 'ycm.paths._EndsWithPython', return_value = False )
 @patch( 'ycm.paths._EndsWithPython', return_value = False )
 @patch( 'ycm.vimsupport.PostVimMessage' )
 @patch( 'ycm.vimsupport.PostVimMessage' )
 def YouCompleteMe_NoPythonInterpreterFound_test( post_vim_message, *args ):
 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 ) )
       assert_that( ycm.IsServerAlive(), equal_to( False ) )
       post_vim_message.assert_called_once_with(
       post_vim_message.assert_called_once_with(
         "Unable to start the ycmd server. Cannot find Python 2.7 or 3.4+. "
         "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. "
         "interpreter path. "
         "Correct the error then restart the server with ':YcmRestartServer'." )
         "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()
       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()
 @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 ):
 def YouCompleteMe_DebugInfo_ServerRunning_test( ycm ):
   dir_of_script = os.path.dirname( os.path.abspath( __file__ ) )
   dir_of_script = os.path.dirname( os.path.abspath( __file__ ) )
   buf_name = os.path.join( dir_of_script, 'testdata', 'test.cpp' )
   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 ) )
                  'Logfile {0} was not removed.'.format( client_logfile ) )
 
 
 
 
-@YouCompleteMeInstance( { 'keep_logfiles': 1 } )
+@YouCompleteMeInstance( { 'g:ycm_keep_logfiles': 1 } )
 def YouCompleteMe_OnVimLeave_KeepClientLogfile_test( ycm ):
 def YouCompleteMe_OnVimLeave_KeepClientLogfile_test( ycm ):
     client_logfile = ycm._client_logfile
     client_logfile = ycm._client_logfile
     assert_that( os.path.isfile( 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, [] )
   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',
 @patch( 'ycm.youcompleteme.YouCompleteMe.FiletypeCompleterExistsForFiletype',
         return_value = True )
         return_value = True )
 @patch( 'ycm.vimsupport.PostVimMessage', new_callable = ExtendedMock )
 @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',
 @patch( 'ycm.youcompleteme.YouCompleteMe.FiletypeCompleterExistsForFiletype',
         return_value = True )
         return_value = True )
 @patch( 'ycm.vimsupport.PostVimMessage', new_callable = ExtendedMock )
 @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 )
   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',
 @patch( 'ycm.youcompleteme.YouCompleteMe.FiletypeCompleterExistsForFiletype',
         return_value = True )
         return_value = True )
 @patch( 'ycm.vimsupport.PostVimMessage', new_callable = ExtendedMock )
 @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 ):
 def YouCompleteMe_UpdateMatches_ClearDiagnosticMatchesInNewBuffer_test( ycm ):
   current_buffer = VimBuffer( 'buffer',
   current_buffer = VimBuffer( 'buffer',
                               filetype = 'c',
                               filetype = 'c',
@@ -684,8 +686,8 @@ def YouCompleteMe_UpdateMatches_ClearDiagnosticMatchesInNewBuffer_test( ycm ):
     assert_that( test_utils.VIM_MATCHES, empty() )
     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,
 @patch.object( ycm_buffer_module,
                'DIAGNOSTIC_UI_ASYNC_FILETYPES',
                'DIAGNOSTIC_UI_ASYNC_FILETYPES',
                [ 'ycmtest' ] )
                [ '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,
 @patch.object( ycm_buffer_module,
                'DIAGNOSTIC_UI_ASYNC_FILETYPES',
                'DIAGNOSTIC_UI_ASYNC_FILETYPES',
                [ 'ycmtest' ] )
                [ 'ycmtest' ] )

+ 8 - 0
python/ycm/vimsupport.py

@@ -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
 # value is then incremented for each new sign. This should prevent conflicts
 # with other plugins using signs.
 # with other plugins using signs.
 SIGN_BUFFER_ID_INITIAL_VALUE = 100000000
 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(
 SIGN_PLACE_REGEX = re.compile(
   r"^.*=(?P<line>\d+).*=(?P<id>\d+).*=(?P<name>Ycm\w+)$" )
   r"^.*=(?P<line>\d+).*=(?P<id>\d+).*=(?P<name>Ycm\w+)$" )
@@ -204,6 +206,12 @@ def GetSignsInBuffer( buffer_number ):
   return signs
   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 ):
 def UnplaceSign( sign ):
   vim.command( 'sign unplace {0} buffer={1}'.format( sign.id,
   vim.command( 'sign unplace {0} buffer={1}'.format( sign.id,
                                                      sign.buffer_number ) )
                                                      sign.buffer_number ) )

+ 21 - 12
python/ycm/youcompleteme.py

@@ -35,8 +35,7 @@ from ycm import base, paths, vimsupport
 from ycm.buffer import ( BufferDict,
 from ycm.buffer import ( BufferDict,
                          DIAGNOSTIC_UI_FILETYPES,
                          DIAGNOSTIC_UI_FILETYPES,
                          DIAGNOSTIC_UI_ASYNC_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 ycmd.request_wrap import RequestWrap
 from ycm.omni_completer import OmniCompleter
 from ycm.omni_completer import OmniCompleter
 from ycm import syntax_parse
 from ycm import syntax_parse
@@ -107,12 +106,12 @@ HANDLE_FLAG_INHERIT = 0x00000001
 
 
 
 
 class YouCompleteMe( object ):
 class YouCompleteMe( object ):
-  def __init__( self, user_options ):
+  def __init__( self ):
     self._available_completers = {}
     self._available_completers = {}
-    self._user_options = user_options
+    self._user_options = None
     self._user_notified_about_crash = False
     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._latest_completion_request = None
     self._logger = logging.getLogger( 'ycm' )
     self._logger = logging.getLogger( 'ycm' )
     self._client_logfile = None
     self._client_logfile = None
@@ -134,6 +133,14 @@ class YouCompleteMe( object ):
     self._server_is_ready_with_cache = False
     self._server_is_ready_with_cache = False
     self._message_poll_request = None
     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 )
     hmac_secret = os.urandom( HMAC_SECRET_LENGTH )
     options_dict = dict( self._user_options )
     options_dict = dict( self._user_options )
     options_dict[ 'hmac_secret' ] = utils.ToUnicode(
     options_dict[ 'hmac_secret' ] = utils.ToUnicode(
@@ -196,12 +203,6 @@ class YouCompleteMe( object ):
 
 
     self._client_logfile = utils.CreateLogfile( CLIENT_LOGFILE_FORMAT )
     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 )
     handler = logging.FileHandler( self._client_logfile )
 
 
     # On Windows and Python prior to 3.4, file handles are inherited by child
     # 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 )
     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 ):
   def IsServerAlive( self ):
     # When the process hasn't finished yet, poll() returns None.
     # When the process hasn't finished yet, poll() returns None.
     return bool( self._server_popen ) and self._server_popen.poll() is None
     return bool( self._server_popen ) and self._server_popen.poll() is None