parent
dda1a83c09
commit
6e782508b3
39
README.md
39
README.md
@ -851,6 +851,31 @@ Default: `0`
|
||||
|
||||
let g:ycm_seed_identifiers_with_syntax = 0
|
||||
|
||||
### The `g:ycm_extra_conf_vim_data` option
|
||||
|
||||
If you're using semantic completion for C-family files, this option might come
|
||||
handy; it's a way of sending data from Vim to your `FlagsForFile` function in
|
||||
your `.ycm_extra_conf.py` file.
|
||||
|
||||
This option is supposed to be a list of VimScript expression strings that are
|
||||
evaluated for every request to the `ycmd` server and then passed to your
|
||||
`FlagsForFile` function as a `client_data` keyword argument.
|
||||
|
||||
For instance, if you set this option to `['v:version']`, your `FlagsForFile`
|
||||
function will be called like this:
|
||||
|
||||
```python
|
||||
# The '704' value is of course contingent on Vim 7.4; in 7.3 it would be '703'
|
||||
FlagsForFile(filename, client_data = {'v:version': 704})
|
||||
```
|
||||
|
||||
So the `client_data` parameter is a dictionary mapping Vim expression strings to
|
||||
their values at the time of the request.
|
||||
|
||||
Default: `[]`
|
||||
|
||||
let g:ycm_extra_conf_vim_data = []
|
||||
|
||||
### The `g:ycm_server_use_vim_stdout` option
|
||||
|
||||
By default, the `ycmd` completion server writes logs to logfiles. When this
|
||||
@ -1162,6 +1187,20 @@ Default: `1`
|
||||
FAQ
|
||||
---
|
||||
|
||||
### I used to be able to `import vim` in `.ycm_extra_conf.py`, but now can't
|
||||
|
||||
YCM was rewritten to use a client-server architecture where most of the logic is
|
||||
in the `ycmd` server. So the magic `vim` module you could have previously
|
||||
imported in your `.ycm_extra_conf.py` files doesn't exist anymore.
|
||||
|
||||
To be fair, importing the magic `vim` module in extra conf files was never
|
||||
supported in the first place; it only ever worked by accident and was never a
|
||||
part of the extra conf API.
|
||||
|
||||
But fear not, you should be able to tweak your extra conf files to continue
|
||||
working by using the `g:ycm_extra_conf_vim_data` option. See the docs on that
|
||||
option for details.
|
||||
|
||||
### I get a linker warning regarding `libpython` on Mac when compiling YCM
|
||||
|
||||
If the warning is `ld: warning: path '/usr/lib/libpython2.7.dylib' following -L
|
||||
|
@ -43,6 +43,8 @@ flags = [
|
||||
'-Wno-variadic-macros',
|
||||
'-fexceptions',
|
||||
'-DNDEBUG',
|
||||
# You 100% do NOT need -DUSE_CLANG_COMPLETER in your flags; only the YCM
|
||||
# source code needs it.
|
||||
'-DUSE_CLANG_COMPLETER',
|
||||
# THIS IS IMPORTANT! Without a "-std=<something>" flag, clang won't know which
|
||||
# language to use when compiling headers. So it will guess. Badly. So C++
|
||||
@ -128,7 +130,7 @@ def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
|
||||
return new_flags
|
||||
|
||||
|
||||
def FlagsForFile( filename ):
|
||||
def FlagsForFile( filename, **kwargs ):
|
||||
if database:
|
||||
# Bear in mind that compilation_info.compiler_flags_ does NOT return a
|
||||
# python list, but a "list-like" StringVec object
|
||||
|
@ -112,6 +112,9 @@ let g:ycm_server_keep_logfiles =
|
||||
let g:ycm_server_idle_suicide_seconds =
|
||||
\ get( g:, 'ycm_server_idle_suicide_seconds', 43200 )
|
||||
|
||||
let g:ycm_extra_conf_vim_data =
|
||||
\ get( g:, 'ycm_extra_conf_vim_data', [] )
|
||||
|
||||
|
||||
" On-demand loading. Let's use the autoload folder and not slow down vim's
|
||||
" startup procedure.
|
||||
|
@ -25,15 +25,15 @@ from ycm.client.base_request import ( BaseRequest, BuildRequestData,
|
||||
TIMEOUT_SECONDS = 0.5
|
||||
|
||||
class CompletionRequest( BaseRequest ):
|
||||
def __init__( self, force_semantic = False ):
|
||||
def __init__( self, extra_data = None ):
|
||||
super( CompletionRequest, self ).__init__()
|
||||
|
||||
self._completion_start_column = base.CompletionStartColumn()
|
||||
|
||||
# This field is also used by the omni_completion_request subclass
|
||||
self.request_data = BuildRequestData( self._completion_start_column )
|
||||
if force_semantic:
|
||||
self.request_data[ 'force_semantic' ] = True
|
||||
if extra_data:
|
||||
self.request_data.update( extra_data )
|
||||
|
||||
|
||||
def CompletionStartColumn( self ):
|
||||
|
@ -247,7 +247,8 @@ class ClangCompleter( Completer ):
|
||||
if 'compilation_flags' in request_data:
|
||||
return PrepareFlagsForClang( request_data[ 'compilation_flags' ],
|
||||
filename )
|
||||
return self._flags.FlagsForFile( filename )
|
||||
client_data = request_data.get( 'extra_conf_data', None )
|
||||
return self._flags.FlagsForFile( filename, client_data = client_data )
|
||||
|
||||
|
||||
def ConvertCompletionData( completion_data ):
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
import ycm_core
|
||||
import os
|
||||
import inspect
|
||||
from ycm import extra_conf_store
|
||||
from ycm.utils import ToUtf8IfNeeded
|
||||
|
||||
@ -40,7 +41,10 @@ class Flags( object ):
|
||||
self.no_extra_conf_file_warning_posted = False
|
||||
|
||||
|
||||
def FlagsForFile( self, filename, add_special_clang_flags = True ):
|
||||
def FlagsForFile( self,
|
||||
filename,
|
||||
add_special_clang_flags = True,
|
||||
client_data = None ):
|
||||
try:
|
||||
return self.flags_for_file[ filename ]
|
||||
except KeyError:
|
||||
@ -51,7 +55,9 @@ class Flags( object ):
|
||||
raise RuntimeError( NO_EXTRA_CONF_FILENAME_MESSAGE )
|
||||
return None
|
||||
|
||||
results = module.FlagsForFile( filename )
|
||||
results = _CallExtraConfFlagsForFile( module,
|
||||
filename,
|
||||
client_data )
|
||||
|
||||
if not results.get( 'flags_ready', True ):
|
||||
return None
|
||||
@ -95,6 +101,15 @@ class Flags( object ):
|
||||
self.flags_for_file.clear()
|
||||
|
||||
|
||||
def _CallExtraConfFlagsForFile( module, filename, client_data ):
|
||||
# For the sake of backwards compatibility, we need to first check whether the
|
||||
# FlagsForFile function in the extra conf module even allows keyword args.
|
||||
if inspect.getargspec( module.FlagsForFile ).keywords:
|
||||
return module.FlagsForFile( filename, client_data = client_data )
|
||||
else:
|
||||
return module.FlagsForFile( filename )
|
||||
|
||||
|
||||
def PrepareFlagsForClang( flags, filename ):
|
||||
flags = _RemoveUnusedFlags( flags, filename )
|
||||
flags = _SanitizeFlags( flags )
|
||||
|
@ -18,8 +18,6 @@
|
||||
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from nose.tools import eq_
|
||||
from ycm.test_utils import MockVimModule
|
||||
vim_mock = MockVimModule()
|
||||
from .. import flags
|
||||
|
||||
|
||||
|
@ -24,7 +24,7 @@ import httplib
|
||||
from .test_utils import Setup, BuildRequest, PathToTestFile
|
||||
from webtest import TestApp
|
||||
from nose.tools import eq_, with_setup
|
||||
from hamcrest import ( assert_that, has_items, has_entry,
|
||||
from hamcrest import ( assert_that, has_item, has_items, has_entry,
|
||||
contains_inanyorder )
|
||||
from ..responses import BuildCompletionData, UnknownExtraConf
|
||||
from .. import handlers
|
||||
@ -211,6 +211,28 @@ def GetCompletions_ForceSemantic_Works_test():
|
||||
CompletionEntryMatcher( 'bool' ) ) )
|
||||
|
||||
|
||||
@with_setup( Setup )
|
||||
def GetCompletions_ClangCompleter_ClientDataGivenToExtraConf_test():
|
||||
app = TestApp( handlers.app )
|
||||
app.post_json( '/load_extra_conf_file',
|
||||
{ 'filepath': PathToTestFile(
|
||||
'client_data/.ycm_extra_conf.py' ) } )
|
||||
|
||||
filepath = PathToTestFile( 'client_data/main.cpp' )
|
||||
completion_data = BuildRequest( filepath = filepath,
|
||||
filetype = 'cpp',
|
||||
contents = open( filepath ).read(),
|
||||
line_num = 8,
|
||||
column_num = 6,
|
||||
start_column = 6,
|
||||
extra_conf_data = {
|
||||
'flags': ['-x', 'c++']
|
||||
})
|
||||
|
||||
results = app.post_json( '/completions', completion_data ).json
|
||||
assert_that( results, has_item( CompletionEntryMatcher( 'x' ) ) )
|
||||
|
||||
|
||||
@with_setup( Setup )
|
||||
def GetCompletions_IdentifierCompleter_SyntaxKeywordsAdded_test():
|
||||
app = TestApp( handlers.app )
|
||||
|
5
python/ycm/server/tests/testdata/client_data/.ycm_extra_conf.py
vendored
Normal file
5
python/ycm/server/tests/testdata/client_data/.ycm_extra_conf.py
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
def FlagsForFile( filename, **kwargs ):
|
||||
return {
|
||||
'flags': kwargs['client_data']['flags'],
|
||||
'do_cache': True
|
||||
}
|
11
python/ycm/server/tests/testdata/client_data/main.cpp
vendored
Normal file
11
python/ycm/server/tests/testdata/client_data/main.cpp
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
struct Foo {
|
||||
int x;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
Foo foo;
|
||||
// The location after the dot is line 9, col 7
|
||||
foo.
|
||||
}
|
||||
|
@ -118,6 +118,16 @@ def GetReadOnlyVimGlobals( force_python_objects = False ):
|
||||
return vim.eval( 'g:' )
|
||||
|
||||
|
||||
def VimExpressionToPythonType( vim_expression ):
|
||||
result = vim.eval( vim_expression )
|
||||
if not isinstance( result, basestring ):
|
||||
return result
|
||||
try:
|
||||
return int( result )
|
||||
except ValueError:
|
||||
return result
|
||||
|
||||
|
||||
# Both |line| and |column| need to be 1-based
|
||||
def JumpToLocation( filename, line, column ):
|
||||
# Add an entry to the jumplist
|
||||
|
@ -132,7 +132,12 @@ class YouCompleteMe( object ):
|
||||
self._omnicomp.ShouldUseNow() ):
|
||||
self._latest_completion_request = OmniCompletionRequest( self._omnicomp )
|
||||
else:
|
||||
self._latest_completion_request = ( CompletionRequest( force_semantic )
|
||||
extra_data = {}
|
||||
self._AddExtraConfDataIfNeeded( extra_data )
|
||||
if force_semantic:
|
||||
extra_data[ 'force_semantic' ] = True
|
||||
|
||||
self._latest_completion_request = ( CompletionRequest( extra_data )
|
||||
if self._IsServerAlive() else
|
||||
None )
|
||||
return self._latest_completion_request
|
||||
@ -176,11 +181,9 @@ class YouCompleteMe( object ):
|
||||
self._NotifyUserIfServerCrashed()
|
||||
|
||||
extra_data = {}
|
||||
if self._user_options[ 'collect_identifiers_from_tags_files' ]:
|
||||
extra_data[ 'tag_files' ] = _GetTagFiles()
|
||||
|
||||
if self._user_options[ 'seed_identifiers_with_syntax' ]:
|
||||
self._AddSyntaxDataIfNeeded( extra_data )
|
||||
self._AddTagsFilesIfNeeded( extra_data )
|
||||
self._AddSyntaxDataIfNeeded( extra_data )
|
||||
self._AddExtraConfDataIfNeeded( extra_data )
|
||||
|
||||
self._latest_file_parse_request = EventNotification( 'FileReadyToParse',
|
||||
extra_data )
|
||||
@ -280,6 +283,8 @@ class YouCompleteMe( object ):
|
||||
|
||||
|
||||
def _AddSyntaxDataIfNeeded( self, extra_data ):
|
||||
if not self._user_options[ 'seed_identifiers_with_syntax' ]:
|
||||
return
|
||||
filetype = vimsupport.CurrentFiletypes()[ 0 ]
|
||||
if filetype in self._filetypes_with_keywords_loaded:
|
||||
return
|
||||
@ -289,10 +294,26 @@ class YouCompleteMe( object ):
|
||||
syntax_parse.SyntaxKeywordsForCurrentBuffer() )
|
||||
|
||||
|
||||
def _GetTagFiles():
|
||||
tag_files = vim.eval( 'tagfiles()' )
|
||||
current_working_directory = os.getcwd()
|
||||
return [ os.path.join( current_working_directory, x ) for x in tag_files ]
|
||||
def _AddTagsFilesIfNeeded( self, extra_data ):
|
||||
def GetTagFiles():
|
||||
tag_files = vim.eval( 'tagfiles()' )
|
||||
current_working_directory = os.getcwd()
|
||||
return [ os.path.join( current_working_directory, x ) for x in tag_files ]
|
||||
|
||||
if not self._user_options[ 'collect_identifiers_from_tags_files' ]:
|
||||
return
|
||||
extra_data[ 'tag_files' ] = GetTagFiles()
|
||||
|
||||
|
||||
def _AddExtraConfDataIfNeeded( self, extra_data ):
|
||||
def BuildExtraConfData( extra_conf_vim_data ):
|
||||
return dict( ( expr, vimsupport.VimExpressionToPythonType( expr ) )
|
||||
for expr in extra_conf_vim_data )
|
||||
|
||||
extra_conf_vim_data = self._user_options[ 'extra_conf_vim_data' ]
|
||||
if extra_conf_vim_data:
|
||||
extra_data[ 'extra_conf_data' ] = BuildExtraConfData(
|
||||
extra_conf_vim_data )
|
||||
|
||||
|
||||
def _PathToServerScript():
|
||||
|
Loading…
Reference in New Issue
Block a user