Avoid evaluating Vim globals in Python
On Python 3, evaluating a Vim expression will raise a unicode exception if it contains an invalid sequence of bytes for the current encoding. We can't really do anything about it because this is the way Vim and Python 3 interact. However, we can prevent this situation to occur by not evaluating Vim data that we have no control over: in particular, the Vim globals. This is done by: - adding one by one the YCM default options instead of extending the Vim globals with them; - only evaluating the Vim global variable names (and not their values) when building the YCM options for the ycmd server.
This commit is contained in:
parent
87f0f7e16d
commit
b923431d7d
@ -35,17 +35,16 @@ YCM_VAR_PREFIX = 'ycm_'
|
|||||||
def BuildServerConf():
|
def BuildServerConf():
|
||||||
"""Builds a dictionary mapping YCM Vim user options to values. Option names
|
"""Builds a dictionary mapping YCM Vim user options to values. Option names
|
||||||
don't have the 'ycm_' prefix."""
|
don't have the 'ycm_' prefix."""
|
||||||
|
# We only evaluate the keys of the vim globals and not the whole dictionary
|
||||||
vim_globals = vimsupport.GetReadOnlyVimGlobals( force_python_objects = True )
|
# to avoid unicode issues.
|
||||||
|
# See https://github.com/Valloric/YouCompleteMe/pull/2151 for details.
|
||||||
|
keys = vimsupport.GetVimGlobalsKeys()
|
||||||
server_conf = {}
|
server_conf = {}
|
||||||
for key, value in iteritems( vim_globals ):
|
for key in keys:
|
||||||
if not key.startswith( YCM_VAR_PREFIX ):
|
if not key.startswith( YCM_VAR_PREFIX ):
|
||||||
continue
|
continue
|
||||||
try:
|
|
||||||
new_value = int( value )
|
|
||||||
except:
|
|
||||||
new_value = value
|
|
||||||
new_key = key[ len( YCM_VAR_PREFIX ): ]
|
new_key = key[ len( YCM_VAR_PREFIX ): ]
|
||||||
|
new_value = vimsupport.VimExpressionToPythonType( 'g:' + key )
|
||||||
server_conf[ new_key ] = new_value
|
server_conf[ new_key ] = new_value
|
||||||
|
|
||||||
return server_conf
|
return server_conf
|
||||||
@ -53,11 +52,10 @@ def BuildServerConf():
|
|||||||
|
|
||||||
def LoadJsonDefaultsIntoVim():
|
def LoadJsonDefaultsIntoVim():
|
||||||
defaults = user_options_store.DefaultOptions()
|
defaults = user_options_store.DefaultOptions()
|
||||||
vim_defaults = {}
|
|
||||||
for key, value in iteritems( defaults ):
|
for key, value in iteritems( defaults ):
|
||||||
vim_defaults[ 'ycm_' + key ] = value
|
new_key = 'g:ycm_' + key
|
||||||
|
if not vimsupport.VariableExists( new_key ):
|
||||||
vimsupport.LoadDictIntoVimGlobals( vim_defaults, overwrite = False )
|
vimsupport.SetVariableValue( new_key, value )
|
||||||
|
|
||||||
|
|
||||||
def CompletionStartColumn():
|
def CompletionStartColumn():
|
||||||
|
@ -294,27 +294,8 @@ def ConvertDiagnosticsToQfList( diagnostics ):
|
|||||||
return [ ConvertDiagnosticToQfFormat( x ) for x in 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'
|
def GetVimGlobalsKeys():
|
||||||
# When |overwrite| is True, overwrites the existing value in Vim.
|
return vim.eval( 'keys( g: )' )
|
||||||
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 VimExpressionToPythonType( vim_expression ):
|
def VimExpressionToPythonType( vim_expression ):
|
||||||
@ -491,8 +472,8 @@ def EchoTextVimWidth( text ):
|
|||||||
|
|
||||||
EchoText( truncated_text, False )
|
EchoText( truncated_text, False )
|
||||||
|
|
||||||
vim.command( 'let &ruler = {0}'.format( old_ruler ) )
|
SetVariableValue( '&ruler', old_ruler )
|
||||||
vim.command( 'let &showcmd = {0}'.format( old_showcmd ) )
|
SetVariableValue( '&showcmd', old_showcmd )
|
||||||
|
|
||||||
|
|
||||||
def EscapeForVim( text ):
|
def EscapeForVim( text ):
|
||||||
@ -514,7 +495,7 @@ def VariableExists( variable ):
|
|||||||
|
|
||||||
|
|
||||||
def SetVariableValue( variable, value ):
|
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 ):
|
def GetVariableValue( variable ):
|
||||||
|
Loading…
Reference in New Issue
Block a user