Auto merge of #2151 - micbou:avoid-eval-vim-globals, r=Valloric
[READY] Avoid evaluating Vim globals in Python ### Problem See the commit message and issue #2127. ### How to reproduce Make Vim to use Python 3 for YCM by either using Vim with only Python 3 support or by editing the `s:UsingPython2` function in `autoload/youcompleteme.vim` to always return 0. Create the following `vimrc`: ``` set nocompatible set runtimepath+=~/.vim/bundle/YouCompleteMe set encoding=utf8 filetype plugin indent on let g:dummy_variable = '€'[0] ``` and start Vim with it. The following error will occur: ``` YouCompleteMe unavailable: 'utf-8' codec can't decode byte 0xe2 in position 0: unexpected end of data ``` with the traceback in `:messages`: ```python Traceback (most recent call last): File "<string>", line 24, in <module> File "C:\\Users\\micbou\\.vim\\bundle\\YouCompleteMe\\autoload\..\python\ycm\setup.py", line 49, in SetUpYCM base.LoadJsonDefaultsIntoVim() File "C:\\Users\\micbou\\.vim\\bundle\\YouCompleteMe\\autoload\..\python\ycm\base.py", line 60, in LoadJsonDefaultsIntoVim vimsupport.LoadDictIntoVimGlobals( vim_defaults, overwrite = False ) File "C:\\Users\\micbou\\.vim\\bundle\\YouCompleteMe\\autoload\..\python\ycm\vimsupport.py", line 305, in LoadDictIntoVimGlobals extend_option ) ) UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe2 in position 0: unexpected end of data ``` ### Solution Do not evaluate the Vim globals when loading the YCM default options into Vim and when building the options for the ycmd server. Depending on the number of global variables and custom YCM options, this may be slower or faster than the current code but by a negligible margin (~1ms). Fixes #2127 and #2150. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/valloric/youcompleteme/2151) <!-- Reviewable:end -->
This commit is contained in:
commit
73584b2978
@ -35,17 +35,16 @@ YCM_VAR_PREFIX = 'ycm_'
|
||||
def BuildServerConf():
|
||||
"""Builds a dictionary mapping YCM Vim user options to values. Option names
|
||||
don't have the 'ycm_' prefix."""
|
||||
|
||||
vim_globals = vimsupport.GetReadOnlyVimGlobals( force_python_objects = True )
|
||||
# We only evaluate the keys of the vim globals and not the whole dictionary
|
||||
# to avoid unicode issues.
|
||||
# See https://github.com/Valloric/YouCompleteMe/pull/2151 for details.
|
||||
keys = vimsupport.GetVimGlobalsKeys()
|
||||
server_conf = {}
|
||||
for key, value in iteritems( vim_globals ):
|
||||
for key in keys:
|
||||
if not key.startswith( YCM_VAR_PREFIX ):
|
||||
continue
|
||||
try:
|
||||
new_value = int( value )
|
||||
except:
|
||||
new_value = value
|
||||
new_key = key[ len( YCM_VAR_PREFIX ): ]
|
||||
new_value = vimsupport.VimExpressionToPythonType( 'g:' + key )
|
||||
server_conf[ new_key ] = new_value
|
||||
|
||||
return server_conf
|
||||
@ -53,11 +52,10 @@ def BuildServerConf():
|
||||
|
||||
def LoadJsonDefaultsIntoVim():
|
||||
defaults = user_options_store.DefaultOptions()
|
||||
vim_defaults = {}
|
||||
for key, value in iteritems( defaults ):
|
||||
vim_defaults[ 'ycm_' + key ] = value
|
||||
|
||||
vimsupport.LoadDictIntoVimGlobals( vim_defaults, overwrite = False )
|
||||
new_key = 'g:ycm_' + key
|
||||
if not vimsupport.VariableExists( new_key ):
|
||||
vimsupport.SetVariableValue( new_key, value )
|
||||
|
||||
|
||||
def CompletionStartColumn():
|
||||
|
@ -294,27 +294,8 @@ def ConvertDiagnosticsToQfList( diagnostics ):
|
||||
return [ ConvertDiagnosticToQfFormat( x ) for x in diagnostics ]
|
||||
|
||||
|
||||
# Given a dict like {'a': 1}, loads it into Vim as if you ran 'let g:a = 1'
|
||||
# When |overwrite| is True, overwrites the existing value in Vim.
|
||||
def LoadDictIntoVimGlobals( new_globals, overwrite = True ):
|
||||
extend_option = '"force"' if overwrite else '"keep"'
|
||||
|
||||
# We need to use json.dumps because that won't use the 'u' prefix on strings
|
||||
# which Vim would bork on.
|
||||
vim.eval( 'extend( g:, {0}, {1})'.format( json.dumps( new_globals ),
|
||||
extend_option ) )
|
||||
|
||||
|
||||
# Changing the returned dict will NOT change the value in Vim.
|
||||
def GetReadOnlyVimGlobals( force_python_objects = False ):
|
||||
if force_python_objects:
|
||||
return vim.eval( 'g:' )
|
||||
|
||||
try:
|
||||
# vim.vars is fairly new so it might not exist
|
||||
return vim.vars
|
||||
except:
|
||||
return vim.eval( 'g:' )
|
||||
def GetVimGlobalsKeys():
|
||||
return vim.eval( 'keys( g: )' )
|
||||
|
||||
|
||||
def VimExpressionToPythonType( vim_expression ):
|
||||
@ -491,8 +472,8 @@ def EchoTextVimWidth( text ):
|
||||
|
||||
EchoText( truncated_text, False )
|
||||
|
||||
vim.command( 'let &ruler = {0}'.format( old_ruler ) )
|
||||
vim.command( 'let &showcmd = {0}'.format( old_showcmd ) )
|
||||
SetVariableValue( '&ruler', old_ruler )
|
||||
SetVariableValue( '&showcmd', old_showcmd )
|
||||
|
||||
|
||||
def EscapeForVim( text ):
|
||||
@ -514,7 +495,7 @@ def VariableExists( variable ):
|
||||
|
||||
|
||||
def SetVariableValue( variable, value ):
|
||||
vim.command( "let {0} = '{1}'".format( variable, EscapeForVim( value ) ) )
|
||||
vim.command( "let {0} = {1}".format( variable, json.dumps( value ) ) )
|
||||
|
||||
|
||||
def GetVariableValue( variable ):
|
||||
|
Loading…
x
Reference in New Issue
Block a user