Decoupling completers from Vim; still WIP & broken
Note to self: squash this commit before merging into master.
This commit is contained in:
parent
bd374a7096
commit
29bb90a6b4
@ -41,6 +41,7 @@ function! youcompleteme#Enable()
|
|||||||
py import vim
|
py import vim
|
||||||
exe 'python sys.path.insert( 0, "' . s:script_folder_path . '/../python" )'
|
exe 'python sys.path.insert( 0, "' . s:script_folder_path . '/../python" )'
|
||||||
py from ycm import base
|
py from ycm import base
|
||||||
|
py from ycm import vimsupport
|
||||||
py from ycm import user_options_store
|
py from ycm import user_options_store
|
||||||
py user_options_store.SetAll( base.BuildServerConf() )
|
py user_options_store.SetAll( base.BuildServerConf() )
|
||||||
py from ycm import extra_conf_store
|
py from ycm import extra_conf_store
|
||||||
@ -260,7 +261,7 @@ function! s:OnCursorHold()
|
|||||||
call s:SetUpCompleteopt()
|
call s:SetUpCompleteopt()
|
||||||
" Order is important here; we need to extract any done diagnostics before
|
" Order is important here; we need to extract any done diagnostics before
|
||||||
" reparsing the file again
|
" reparsing the file again
|
||||||
call s:UpdateDiagnosticNotifications()
|
" call s:UpdateDiagnosticNotifications()
|
||||||
call s:OnFileReadyToParse()
|
call s:OnFileReadyToParse()
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
@ -327,7 +328,7 @@ function! s:OnCursorMovedNormalMode()
|
|||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
call s:UpdateDiagnosticNotifications()
|
" call s:UpdateDiagnosticNotifications()
|
||||||
call s:OnFileReadyToParse()
|
call s:OnFileReadyToParse()
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
@ -338,7 +339,7 @@ function! s:OnInsertLeave()
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
let s:omnifunc_mode = 0
|
let s:omnifunc_mode = 0
|
||||||
call s:UpdateDiagnosticNotifications()
|
" call s:UpdateDiagnosticNotifications()
|
||||||
call s:OnFileReadyToParse()
|
call s:OnFileReadyToParse()
|
||||||
py ycm_state.OnInsertLeave()
|
py ycm_state.OnInsertLeave()
|
||||||
if g:ycm_autoclose_preview_window_after_completion ||
|
if g:ycm_autoclose_preview_window_after_completion ||
|
||||||
@ -572,7 +573,9 @@ command! YcmShowDetailedDiagnostic call s:ShowDetailedDiagnostic()
|
|||||||
" required (currently that's on buffer save) OR when the SyntasticCheck command
|
" required (currently that's on buffer save) OR when the SyntasticCheck command
|
||||||
" is invoked
|
" is invoked
|
||||||
function! youcompleteme#CurrentFileDiagnostics()
|
function! youcompleteme#CurrentFileDiagnostics()
|
||||||
return pyeval( 'ycm_state.GetDiagnosticsForCurrentFile()' )
|
" TODO: Make this work again.
|
||||||
|
" return pyeval( 'ycm_state.GetDiagnosticsForCurrentFile()' )
|
||||||
|
return []
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
@ -595,28 +598,24 @@ function! s:CompleterCommand(...)
|
|||||||
" to select the omni completer or "ft=ycm:ident" to select the identifier
|
" to select the omni completer or "ft=ycm:ident" to select the identifier
|
||||||
" completer. The remaining arguments will passed to the completer.
|
" completer. The remaining arguments will passed to the completer.
|
||||||
let arguments = copy(a:000)
|
let arguments = copy(a:000)
|
||||||
|
let completer = ''
|
||||||
|
|
||||||
if a:0 > 0 && strpart(a:1, 0, 3) == 'ft='
|
if a:0 > 0 && strpart(a:1, 0, 3) == 'ft='
|
||||||
if a:1 == 'ft=ycm:omni'
|
if a:1 == 'ft=ycm:omni'
|
||||||
py completer = ycm_state.GetOmniCompleter()
|
let completer = 'omni'
|
||||||
elseif a:1 == 'ft=ycm:ident'
|
elseif a:1 == 'ft=ycm:ident'
|
||||||
py completer = ycm_state.GetGeneralCompleter()
|
let completer = 'identifier'
|
||||||
else
|
|
||||||
py completer = ycm_state.GetFiletypeCompleterForFiletype(
|
|
||||||
\ vim.eval('a:1').lstrip('ft=') )
|
|
||||||
endif
|
endif
|
||||||
let arguments = arguments[1:]
|
let arguments = arguments[1:]
|
||||||
elseif pyeval( 'ycm_state.NativeFiletypeCompletionAvailable()' )
|
|
||||||
py completer = ycm_state.GetFiletypeCompleter()
|
|
||||||
else
|
|
||||||
echohl WarningMsg |
|
|
||||||
\ echomsg "No native completer found for current buffer." |
|
|
||||||
\ echomsg "Use ft=... as the first argument to specify a completer." |
|
|
||||||
\ echohl None
|
|
||||||
return
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
py completer.OnUserCommand( vim.eval( 'l:arguments' ) )
|
py << EOF
|
||||||
|
response = ycm_state.SendCommandRequest( vim.eval( 'l:arguments' ),
|
||||||
|
vim.eval( 'l:completer' ) )
|
||||||
|
if not response.Valid():
|
||||||
|
vimsupport.PostVimMessage( 'No native completer found for current buffer. ' +
|
||||||
|
'Use ft=... as the first argument to specify a completer.')
|
||||||
|
EOF
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ void ClangCompleter::EnableThreading() {
|
|||||||
|
|
||||||
|
|
||||||
std::vector< Diagnostic > ClangCompleter::DiagnosticsForFile(
|
std::vector< Diagnostic > ClangCompleter::DiagnosticsForFile(
|
||||||
const std::string &filename ) {
|
std::string filename ) {
|
||||||
shared_ptr< TranslationUnit > unit = translation_unit_store_.Get( filename );
|
shared_ptr< TranslationUnit > unit = translation_unit_store_.Get( filename );
|
||||||
|
|
||||||
if ( !unit )
|
if ( !unit )
|
||||||
@ -127,9 +127,9 @@ bool ClangCompleter::UpdatingTranslationUnit( const std::string &filename ) {
|
|||||||
|
|
||||||
|
|
||||||
void ClangCompleter::UpdateTranslationUnit(
|
void ClangCompleter::UpdateTranslationUnit(
|
||||||
const std::string &filename,
|
std::string filename,
|
||||||
const std::vector< UnsavedFile > &unsaved_files,
|
std::vector< UnsavedFile > unsaved_files,
|
||||||
const std::vector< std::string > &flags ) {
|
std::vector< std::string > flags ) {
|
||||||
bool translation_unit_created;
|
bool translation_unit_created;
|
||||||
shared_ptr< TranslationUnit > unit = translation_unit_store_.GetOrCreate(
|
shared_ptr< TranslationUnit > unit = translation_unit_store_.GetOrCreate(
|
||||||
filename,
|
filename,
|
||||||
@ -182,11 +182,11 @@ Future< void > ClangCompleter::UpdateTranslationUnitAsync(
|
|||||||
|
|
||||||
std::vector< CompletionData >
|
std::vector< CompletionData >
|
||||||
ClangCompleter::CandidatesForLocationInFile(
|
ClangCompleter::CandidatesForLocationInFile(
|
||||||
const std::string &filename,
|
std::string filename,
|
||||||
int line,
|
int line,
|
||||||
int column,
|
int column,
|
||||||
const std::vector< UnsavedFile > &unsaved_files,
|
std::vector< UnsavedFile > unsaved_files,
|
||||||
const std::vector< std::string > &flags ) {
|
std::vector< std::string > flags ) {
|
||||||
shared_ptr< TranslationUnit > unit =
|
shared_ptr< TranslationUnit > unit =
|
||||||
translation_unit_store_.GetOrCreate( filename, unsaved_files, flags );
|
translation_unit_store_.GetOrCreate( filename, unsaved_files, flags );
|
||||||
|
|
||||||
@ -201,12 +201,12 @@ ClangCompleter::CandidatesForLocationInFile(
|
|||||||
|
|
||||||
Future< AsyncCompletions >
|
Future< AsyncCompletions >
|
||||||
ClangCompleter::CandidatesForQueryAndLocationInFileAsync(
|
ClangCompleter::CandidatesForQueryAndLocationInFileAsync(
|
||||||
const std::string &query,
|
std::string query,
|
||||||
const std::string &filename,
|
std::string filename,
|
||||||
int line,
|
int line,
|
||||||
int column,
|
int column,
|
||||||
const std::vector< UnsavedFile > &unsaved_files,
|
std::vector< UnsavedFile > unsaved_files,
|
||||||
const std::vector< std::string > &flags ) {
|
std::vector< std::string > flags ) {
|
||||||
// TODO: throw exception when threading is not enabled and this is called
|
// TODO: throw exception when threading is not enabled and this is called
|
||||||
if ( !threading_enabled_ )
|
if ( !threading_enabled_ )
|
||||||
return Future< AsyncCompletions >();
|
return Future< AsyncCompletions >();
|
||||||
@ -238,7 +238,11 @@ ClangCompleter::CandidatesForQueryAndLocationInFileAsync(
|
|||||||
CreateSortingTask( query, future );
|
CreateSortingTask( query, future );
|
||||||
|
|
||||||
if ( skip_clang_result_cache ) {
|
if ( skip_clang_result_cache ) {
|
||||||
CreateClangTask( filename, line, column, unsaved_files, flags );
|
CreateClangTask( boost::move( filename ),
|
||||||
|
line,
|
||||||
|
column,
|
||||||
|
boost::move( unsaved_files ),
|
||||||
|
boost::move( flags ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
return Future< AsyncCompletions >( boost::move( future ) );
|
return Future< AsyncCompletions >( boost::move( future ) );
|
||||||
@ -246,11 +250,11 @@ ClangCompleter::CandidatesForQueryAndLocationInFileAsync(
|
|||||||
|
|
||||||
|
|
||||||
Location ClangCompleter::GetDeclarationLocation(
|
Location ClangCompleter::GetDeclarationLocation(
|
||||||
const std::string &filename,
|
std::string filename,
|
||||||
int line,
|
int line,
|
||||||
int column,
|
int column,
|
||||||
const std::vector< UnsavedFile > &unsaved_files,
|
std::vector< UnsavedFile > unsaved_files,
|
||||||
const std::vector< std::string > &flags ) {
|
std::vector< std::string > flags ) {
|
||||||
shared_ptr< TranslationUnit > unit =
|
shared_ptr< TranslationUnit > unit =
|
||||||
translation_unit_store_.GetOrCreate( filename, unsaved_files, flags );
|
translation_unit_store_.GetOrCreate( filename, unsaved_files, flags );
|
||||||
|
|
||||||
@ -263,11 +267,11 @@ Location ClangCompleter::GetDeclarationLocation(
|
|||||||
|
|
||||||
|
|
||||||
Location ClangCompleter::GetDefinitionLocation(
|
Location ClangCompleter::GetDefinitionLocation(
|
||||||
const std::string &filename,
|
std::string filename,
|
||||||
int line,
|
int line,
|
||||||
int column,
|
int column,
|
||||||
const std::vector< UnsavedFile > &unsaved_files,
|
std::vector< UnsavedFile > unsaved_files,
|
||||||
const std::vector< std::string > &flags ) {
|
std::vector< std::string > flags ) {
|
||||||
shared_ptr< TranslationUnit > unit =
|
shared_ptr< TranslationUnit > unit =
|
||||||
translation_unit_store_.GetOrCreate( filename, unsaved_files, flags );
|
translation_unit_store_.GetOrCreate( filename, unsaved_files, flags );
|
||||||
|
|
||||||
@ -279,7 +283,7 @@ Location ClangCompleter::GetDefinitionLocation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ClangCompleter::DeleteCachesForFileAsync( const std::string &filename ) {
|
void ClangCompleter::DeleteCachesForFileAsync( std::string filename ) {
|
||||||
file_cache_delete_stack_.Push( filename );
|
file_cache_delete_stack_.Push( filename );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,18 +59,23 @@ public:
|
|||||||
|
|
||||||
void EnableThreading();
|
void EnableThreading();
|
||||||
|
|
||||||
std::vector< Diagnostic > DiagnosticsForFile( const std::string &filename );
|
std::vector< Diagnostic > DiagnosticsForFile( std::string filename );
|
||||||
|
|
||||||
bool UpdatingTranslationUnit( const std::string &filename );
|
bool UpdatingTranslationUnit( const std::string &filename );
|
||||||
|
|
||||||
|
// NOTE: params are taken by value on purpose! With a C++11 compiler we can
|
||||||
|
// avoid internal copies if params are taken by value (move ctors FTW), and we
|
||||||
|
// need to ensure we own the memory.
|
||||||
|
// TODO: Change some of these params back to const ref where possible after we
|
||||||
|
// get the server up.
|
||||||
|
// TODO: Remove the async methods and the threads when the server is ready.
|
||||||
|
|
||||||
// Public because of unit tests (gtest is not very thread-friendly)
|
// Public because of unit tests (gtest is not very thread-friendly)
|
||||||
void UpdateTranslationUnit(
|
void UpdateTranslationUnit(
|
||||||
const std::string &filename,
|
std::string filename,
|
||||||
const std::vector< UnsavedFile > &unsaved_files,
|
std::vector< UnsavedFile > unsaved_files,
|
||||||
const std::vector< std::string > &flags );
|
std::vector< std::string > flags );
|
||||||
|
|
||||||
// NOTE: params are taken by value on purpose! With a C++11 compiler we can
|
|
||||||
// avoid internal copies if params are taken by value (move ctors FTW)
|
|
||||||
Future< void > UpdateTranslationUnitAsync(
|
Future< void > UpdateTranslationUnitAsync(
|
||||||
std::string filename,
|
std::string filename,
|
||||||
std::vector< UnsavedFile > unsaved_files,
|
std::vector< UnsavedFile > unsaved_files,
|
||||||
@ -78,35 +83,35 @@ public:
|
|||||||
|
|
||||||
// Public because of unit tests (gtest is not very thread-friendly)
|
// Public because of unit tests (gtest is not very thread-friendly)
|
||||||
std::vector< CompletionData > CandidatesForLocationInFile(
|
std::vector< CompletionData > CandidatesForLocationInFile(
|
||||||
const std::string &filename,
|
std::string filename,
|
||||||
int line,
|
int line,
|
||||||
int column,
|
int column,
|
||||||
const std::vector< UnsavedFile > &unsaved_files,
|
std::vector< UnsavedFile > unsaved_files,
|
||||||
const std::vector< std::string > &flags );
|
std::vector< std::string > flags );
|
||||||
|
|
||||||
Future< AsyncCompletions > CandidatesForQueryAndLocationInFileAsync(
|
Future< AsyncCompletions > CandidatesForQueryAndLocationInFileAsync(
|
||||||
const std::string &query,
|
std::string query,
|
||||||
const std::string &filename,
|
std::string filename,
|
||||||
int line,
|
int line,
|
||||||
int column,
|
int column,
|
||||||
const std::vector< UnsavedFile > &unsaved_files,
|
std::vector< UnsavedFile > unsaved_files,
|
||||||
const std::vector< std::string > &flags );
|
std::vector< std::string > flags );
|
||||||
|
|
||||||
Location GetDeclarationLocation(
|
Location GetDeclarationLocation(
|
||||||
const std::string &filename,
|
std::string filename,
|
||||||
int line,
|
int line,
|
||||||
int column,
|
int column,
|
||||||
const std::vector< UnsavedFile > &unsaved_files,
|
std::vector< UnsavedFile > unsaved_files,
|
||||||
const std::vector< std::string > &flags );
|
std::vector< std::string > flags );
|
||||||
|
|
||||||
Location GetDefinitionLocation(
|
Location GetDefinitionLocation(
|
||||||
const std::string &filename,
|
std::string filename,
|
||||||
int line,
|
int line,
|
||||||
int column,
|
int column,
|
||||||
const std::vector< UnsavedFile > &unsaved_files,
|
std::vector< UnsavedFile > unsaved_files,
|
||||||
const std::vector< std::string > &flags );
|
std::vector< std::string > flags );
|
||||||
|
|
||||||
void DeleteCachesForFileAsync( const std::string &filename );
|
void DeleteCachesForFileAsync( std::string filename );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -143,8 +143,8 @@ let g:ycm_extra_conf_globlist =
|
|||||||
let g:ycm_filepath_completion_use_working_dir =
|
let g:ycm_filepath_completion_use_working_dir =
|
||||||
\ get( g:, 'ycm_filepath_completion_use_working_dir', 0 )
|
\ get( g:, 'ycm_filepath_completion_use_working_dir', 0 )
|
||||||
|
|
||||||
" Default semantic triggers are in python/ycm/completers/completer.py, these
|
" Default semantic triggers are in python/ycm/completers/completer_utils.py
|
||||||
" just append new triggers to the default dict.
|
" these just append new triggers to the default dict.
|
||||||
let g:ycm_semantic_triggers =
|
let g:ycm_semantic_triggers =
|
||||||
\ get( g:, 'ycm_semantic_triggers', {} )
|
\ get( g:, 'ycm_semantic_triggers', {} )
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ from ycm.completers.general_completer import GeneralCompleter
|
|||||||
from ycm.completers.general import syntax_parse
|
from ycm.completers.general import syntax_parse
|
||||||
from ycm import vimsupport
|
from ycm import vimsupport
|
||||||
from ycm import utils
|
from ycm import utils
|
||||||
|
from ycm import server_responses
|
||||||
|
|
||||||
MAX_IDENTIFIER_COMPLETIONS_RETURNED = 10
|
MAX_IDENTIFIER_COMPLETIONS_RETURNED = 10
|
||||||
SYNTAX_FILENAME = 'YCM_PLACEHOLDER_FOR_SYNTAX'
|
SYNTAX_FILENAME = 'YCM_PLACEHOLDER_FOR_SYNTAX'
|
||||||
@ -39,15 +40,14 @@ class IdentifierCompleter( GeneralCompleter ):
|
|||||||
self.filetypes_with_keywords_loaded = set()
|
self.filetypes_with_keywords_loaded = set()
|
||||||
|
|
||||||
|
|
||||||
def ShouldUseNow( self, start_column, unused_current_line ):
|
def ShouldUseNow( self, request_data ):
|
||||||
return self.QueryLengthAboveMinThreshold( start_column )
|
return self.QueryLengthAboveMinThreshold( request_data )
|
||||||
|
|
||||||
|
|
||||||
def CandidatesForQueryAsync( self, query, unused_start_column ):
|
def CandidatesForQueryAsync( self, request_data ):
|
||||||
filetype = vim.eval( "&filetype" )
|
|
||||||
self.completions_future = self.completer.CandidatesForQueryAndTypeAsync(
|
self.completions_future = self.completer.CandidatesForQueryAndTypeAsync(
|
||||||
utils.SanitizeQuery( query ),
|
utils.SanitizeQuery( request_data[ 'query' ] ),
|
||||||
filetype )
|
request_data[ 'filetypes' ][ 0 ] )
|
||||||
|
|
||||||
|
|
||||||
def AddIdentifier( self, identifier ):
|
def AddIdentifier( self, identifier ):
|
||||||
@ -83,17 +83,16 @@ class IdentifierCompleter( GeneralCompleter ):
|
|||||||
self.AddIdentifier( stripped_cursor_identifier )
|
self.AddIdentifier( stripped_cursor_identifier )
|
||||||
|
|
||||||
|
|
||||||
def AddBufferIdentifiers( self ):
|
def AddBufferIdentifiers( self, request_data ):
|
||||||
# TODO: use vimsupport.GetFiletypes; also elsewhere in file
|
filetype = request_data[ 'filetypes' ][ 0 ]
|
||||||
filetype = vim.eval( "&filetype" )
|
filepath = request_data[ 'filepath' ]
|
||||||
filepath = vim.eval( "expand('%:p')" )
|
|
||||||
collect_from_comments_and_strings = bool( self.user_options[
|
collect_from_comments_and_strings = bool( self.user_options[
|
||||||
'collect_identifiers_from_comments_and_strings' ] )
|
'collect_identifiers_from_comments_and_strings' ] )
|
||||||
|
|
||||||
if not filetype or not filepath:
|
if not filetype or not filepath:
|
||||||
return
|
return
|
||||||
|
|
||||||
text = "\n".join( vim.current.buffer )
|
text = request_data[ 'file_data' ][ filepath ][ 'contents' ]
|
||||||
self.completer.AddIdentifiersToDatabaseFromBufferAsync(
|
self.completer.AddIdentifiersToDatabaseFromBufferAsync(
|
||||||
text,
|
text,
|
||||||
filetype,
|
filetype,
|
||||||
@ -147,14 +146,15 @@ class IdentifierCompleter( GeneralCompleter ):
|
|||||||
filepath )
|
filepath )
|
||||||
|
|
||||||
|
|
||||||
def OnFileReadyToParse( self ):
|
def OnFileReadyToParse( self, request_data ):
|
||||||
self.AddBufferIdentifiers()
|
self.AddBufferIdentifiers( request_data )
|
||||||
|
|
||||||
if self.user_options[ 'collect_identifiers_from_tags_files' ]:
|
# TODO: make these work again
|
||||||
self.AddIdentifiersFromTagFiles()
|
# if self.user_options[ 'collect_identifiers_from_tags_files' ]:
|
||||||
|
# self.AddIdentifiersFromTagFiles()
|
||||||
|
|
||||||
if self.user_options[ 'seed_identifiers_with_syntax' ]:
|
# if self.user_options[ 'seed_identifiers_with_syntax' ]:
|
||||||
self.AddIdentifiersFromSyntax()
|
# self.AddIdentifiersFromSyntax()
|
||||||
|
|
||||||
|
|
||||||
def OnInsertLeave( self ):
|
def OnInsertLeave( self ):
|
||||||
@ -174,11 +174,7 @@ class IdentifierCompleter( GeneralCompleter ):
|
|||||||
completions = _RemoveSmallCandidates(
|
completions = _RemoveSmallCandidates(
|
||||||
completions, self.user_options[ 'min_num_identifier_candidate_chars' ] )
|
completions, self.user_options[ 'min_num_identifier_candidate_chars' ] )
|
||||||
|
|
||||||
# We will never have duplicates in completions so with 'dup':1 we tell Vim
|
return [ server_responses.BuildCompletionData( x ) for x in completions ]
|
||||||
# to add this candidate even if it's a duplicate of an existing one (which
|
|
||||||
# will never happen). This saves us some expensive string matching
|
|
||||||
# operations in Vim.
|
|
||||||
return [ { 'word': x, 'dup': 1 } for x in completions ]
|
|
||||||
|
|
||||||
|
|
||||||
def _PreviousIdentifier( min_num_completion_start_chars ):
|
def _PreviousIdentifier( min_num_completion_start_chars ):
|
||||||
|
@ -40,29 +40,27 @@ class OmniCompleter( Completer ):
|
|||||||
return bool( self.user_options[ 'cache_omnifunc' ] )
|
return bool( self.user_options[ 'cache_omnifunc' ] )
|
||||||
|
|
||||||
|
|
||||||
def ShouldUseNow( self, start_column, current_line ):
|
def ShouldUseNow( self, request_data ):
|
||||||
if self.ShouldUseCache():
|
if self.ShouldUseCache():
|
||||||
return super( OmniCompleter, self ).ShouldUseNow( start_column,
|
return super( OmniCompleter, self ).ShouldUseNow( request_data )
|
||||||
current_line )
|
return self.ShouldUseNowInner( request_data )
|
||||||
return self.ShouldUseNowInner( start_column, current_line )
|
|
||||||
|
|
||||||
|
|
||||||
def ShouldUseNowInner( self, start_column, current_line ):
|
def ShouldUseNowInner( self, request_data ):
|
||||||
if not self.omnifunc:
|
if not self.omnifunc:
|
||||||
return False
|
return False
|
||||||
return super( OmniCompleter, self ).ShouldUseNowInner( start_column,
|
return super( OmniCompleter, self ).ShouldUseNowInner( request_data )
|
||||||
current_line )
|
|
||||||
|
|
||||||
|
|
||||||
def CandidatesForQueryAsync( self, query, unused_start_column ):
|
def CandidatesForQueryAsync( self, request_data ):
|
||||||
if self.ShouldUseCache():
|
if self.ShouldUseCache():
|
||||||
return super( OmniCompleter, self ).CandidatesForQueryAsync(
|
return super( OmniCompleter, self ).CandidatesForQueryAsync(
|
||||||
query, unused_start_column )
|
request_data )
|
||||||
else:
|
else:
|
||||||
return self.CandidatesForQueryAsyncInner( query, unused_start_column )
|
return self.CandidatesForQueryAsyncInner( request_data )
|
||||||
|
|
||||||
|
|
||||||
def CandidatesForQueryAsyncInner( self, query, unused_start_column ):
|
def CandidatesForQueryAsyncInner( self, request_data ):
|
||||||
if not self.omnifunc:
|
if not self.omnifunc:
|
||||||
self.stored_candidates = None
|
self.stored_candidates = None
|
||||||
return
|
return
|
||||||
@ -75,7 +73,7 @@ class OmniCompleter( Completer ):
|
|||||||
|
|
||||||
omnifunc_call = [ self.omnifunc,
|
omnifunc_call = [ self.omnifunc,
|
||||||
"(0,'",
|
"(0,'",
|
||||||
vimsupport.EscapeForVim( query ),
|
vimsupport.EscapeForVim( request_data[ 'query' ] ),
|
||||||
"')" ]
|
"')" ]
|
||||||
|
|
||||||
items = vim.eval( ''.join( omnifunc_call ) )
|
items = vim.eval( ''.join( omnifunc_call ) )
|
||||||
@ -98,7 +96,7 @@ class OmniCompleter( Completer ):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def OnFileReadyToParse( self ):
|
def OnFileReadyToParse( self, request_data ):
|
||||||
self.omnifunc = vim.eval( '&omnifunc' )
|
self.omnifunc = vim.eval( '&omnifunc' )
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
import abc
|
import abc
|
||||||
import ycm_core
|
import ycm_core
|
||||||
from ycm import vimsupport
|
|
||||||
from ycm.completers.completer_utils import TriggersForFiletype
|
from ycm.completers.completer_utils import TriggersForFiletype
|
||||||
|
|
||||||
NO_USER_COMMANDS = 'This completer does not define any commands.'
|
NO_USER_COMMANDS = 'This completer does not define any commands.'
|
||||||
@ -116,32 +115,35 @@ class Completer( object ):
|
|||||||
def __init__( self, user_options ):
|
def __init__( self, user_options ):
|
||||||
self.user_options = user_options
|
self.user_options = user_options
|
||||||
self.min_num_chars = user_options[ 'min_num_of_chars_for_completion' ]
|
self.min_num_chars = user_options[ 'min_num_of_chars_for_completion' ]
|
||||||
self.triggers_for_filetype = TriggersForFiletype()
|
self.triggers_for_filetype = TriggersForFiletype(
|
||||||
|
user_options[ 'semantic_triggers' ] )
|
||||||
self.completions_future = None
|
self.completions_future = None
|
||||||
self.completions_cache = None
|
self.completions_cache = None
|
||||||
self.completion_start_column = None
|
|
||||||
|
|
||||||
|
|
||||||
# It's highly likely you DON'T want to override this function but the *Inner
|
# It's highly likely you DON'T want to override this function but the *Inner
|
||||||
# version of it.
|
# version of it.
|
||||||
def ShouldUseNow( self, start_column, current_line ):
|
def ShouldUseNow( self, request_data ):
|
||||||
inner_says_yes = self.ShouldUseNowInner( start_column, current_line )
|
inner_says_yes = self.ShouldUseNowInner( request_data )
|
||||||
if not inner_says_yes:
|
if not inner_says_yes:
|
||||||
self.completions_cache = None
|
self.completions_cache = None
|
||||||
|
|
||||||
previous_results_were_empty = ( self.completions_cache and
|
previous_results_were_empty = ( self.completions_cache and
|
||||||
self.completions_cache.CacheValid(
|
self.completions_cache.CacheValid(
|
||||||
start_column ) and
|
request_data[ 'line_num' ],
|
||||||
|
request_data[ 'start_column' ] ) and
|
||||||
not self.completions_cache.raw_completions )
|
not self.completions_cache.raw_completions )
|
||||||
return inner_says_yes and not previous_results_were_empty
|
return inner_says_yes and not previous_results_were_empty
|
||||||
|
|
||||||
|
|
||||||
def ShouldUseNowInner( self, start_column, current_line ):
|
def ShouldUseNowInner( self, request_data ):
|
||||||
|
current_line = request_data[ 'line_value' ]
|
||||||
|
start_column = request_data[ 'start_column' ]
|
||||||
line_length = len( current_line )
|
line_length = len( current_line )
|
||||||
if not line_length or start_column - 1 >= line_length:
|
if not line_length or start_column - 1 >= line_length:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
filetype = self._CurrentFiletype()
|
filetype = self._CurrentFiletype( request_data[ 'filetypes' ] )
|
||||||
triggers = self.triggers_for_filetype[ filetype ]
|
triggers = self.triggers_for_filetype[ filetype ]
|
||||||
|
|
||||||
for trigger in triggers:
|
for trigger in triggers:
|
||||||
@ -158,52 +160,61 @@ class Completer( object ):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def QueryLengthAboveMinThreshold( self, start_column ):
|
def QueryLengthAboveMinThreshold( self, request_data ):
|
||||||
query_length = vimsupport.CurrentColumn() - start_column
|
query_length = request_data[ 'column_num' ] - request_data[ 'start_column' ]
|
||||||
return query_length >= self.min_num_chars
|
return query_length >= self.min_num_chars
|
||||||
|
|
||||||
|
|
||||||
# It's highly likely you DON'T want to override this function but the *Inner
|
# It's highly likely you DON'T want to override this function but the *Inner
|
||||||
# version of it.
|
# version of it.
|
||||||
def CandidatesForQueryAsync( self, query, start_column ):
|
def CandidatesForQueryAsync( self, request_data ):
|
||||||
self.completion_start_column = start_column
|
self.request_data = request_data
|
||||||
|
|
||||||
if query and self.completions_cache and self.completions_cache.CacheValid(
|
if ( request_data[ 'query' ] and
|
||||||
start_column ):
|
self.completions_cache and
|
||||||
|
self.completions_cache.CacheValid( request_data[ 'line_num' ],
|
||||||
|
request_data[ 'start_column' ] ) ):
|
||||||
self.completions_cache.filtered_completions = (
|
self.completions_cache.filtered_completions = (
|
||||||
self.FilterAndSortCandidates(
|
self.FilterAndSortCandidates(
|
||||||
self.completions_cache.raw_completions,
|
self.completions_cache.raw_completions,
|
||||||
query ) )
|
request_data[ 'query' ] ) )
|
||||||
else:
|
else:
|
||||||
self.completions_cache = None
|
self.completions_cache = None
|
||||||
self.CandidatesForQueryAsyncInner( query, start_column )
|
self.CandidatesForQueryAsyncInner( request_data )
|
||||||
|
|
||||||
|
|
||||||
def DefinedSubcommands( self ):
|
def DefinedSubcommands( self ):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def EchoUserCommandsHelpMessage( self ):
|
def UserCommandsHelpMessage( self ):
|
||||||
subcommands = self.DefinedSubcommands()
|
subcommands = self.DefinedSubcommands()
|
||||||
if subcommands:
|
if subcommands:
|
||||||
vimsupport.EchoText( 'Supported commands are:\n' +
|
return ( 'Supported commands are:\n' +
|
||||||
'\n'.join( subcommands ) +
|
'\n'.join( subcommands ) +
|
||||||
'\nSee the docs for information on what they do.' )
|
'\nSee the docs for information on what they do.' )
|
||||||
else:
|
else:
|
||||||
vimsupport.EchoText( 'No supported subcommands' )
|
return 'No supported subcommands'
|
||||||
|
|
||||||
|
|
||||||
def FilterAndSortCandidates( self, candidates, query ):
|
def FilterAndSortCandidates( self, candidates, query ):
|
||||||
if not candidates:
|
if not candidates:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
if hasattr( candidates, 'words' ):
|
# We need to handle both an omni_completer style completer and a server
|
||||||
candidates = candidates.words
|
# style completer
|
||||||
items_are_objects = 'word' in candidates[ 0 ]
|
if 'words' in candidates:
|
||||||
|
candidates = candidates[ 'words' ]
|
||||||
|
|
||||||
|
sort_property = ''
|
||||||
|
if 'word' in candidates[ 0 ]:
|
||||||
|
sort_property = 'word'
|
||||||
|
elif 'insertion_text' in candidates[ 0 ]:
|
||||||
|
sort_property = 'insertion_text'
|
||||||
|
|
||||||
matches = ycm_core.FilterAndSortCandidates(
|
matches = ycm_core.FilterAndSortCandidates(
|
||||||
candidates,
|
candidates,
|
||||||
'word' if items_are_objects else '',
|
sort_property,
|
||||||
query )
|
query )
|
||||||
|
|
||||||
return matches
|
return matches
|
||||||
@ -238,8 +249,8 @@ class Completer( object ):
|
|||||||
else:
|
else:
|
||||||
self.completions_cache = CompletionsCache()
|
self.completions_cache = CompletionsCache()
|
||||||
self.completions_cache.raw_completions = self.CandidatesFromStoredRequestInner()
|
self.completions_cache.raw_completions = self.CandidatesFromStoredRequestInner()
|
||||||
self.completions_cache.line, _ = vimsupport.CurrentLineAndColumn()
|
self.completions_cache.line = self.request_data[ 'line_num' ]
|
||||||
self.completions_cache.column = self.completion_start_column
|
self.completions_cache.column = self.request_data[ 'start_column' ]
|
||||||
return self.completions_cache.raw_completions
|
return self.completions_cache.raw_completions
|
||||||
|
|
||||||
|
|
||||||
@ -249,7 +260,7 @@ class Completer( object ):
|
|||||||
return self.completions_future.GetResults()
|
return self.completions_future.GetResults()
|
||||||
|
|
||||||
|
|
||||||
def OnFileReadyToParse( self ):
|
def OnFileReadyToParse( self, request_data ):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@ -269,8 +280,8 @@ class Completer( object ):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def OnUserCommand( self, arguments ):
|
def OnUserCommand( self, arguments, request_data ):
|
||||||
vimsupport.PostVimMessage( NO_USER_COMMANDS )
|
raise NotImplementedError( NO_USER_COMMANDS )
|
||||||
|
|
||||||
|
|
||||||
def OnCurrentIdentifierFinished( self ):
|
def OnCurrentIdentifierFinished( self ):
|
||||||
@ -285,7 +296,7 @@ class Completer( object ):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def ShowDetailedDiagnostic( self ):
|
def GetDetailedDiagnostic( self ):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@ -293,8 +304,7 @@ class Completer( object ):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def _CurrentFiletype( self ):
|
def _CurrentFiletype( self, filetypes ):
|
||||||
filetypes = vimsupport.CurrentFiletypes()
|
|
||||||
supported = self.SupportedFiletypes()
|
supported = self.SupportedFiletypes()
|
||||||
|
|
||||||
for filetype in filetypes:
|
for filetype in filetypes:
|
||||||
@ -321,9 +331,7 @@ class CompletionsCache( object ):
|
|||||||
self.filtered_completions = []
|
self.filtered_completions = []
|
||||||
|
|
||||||
|
|
||||||
def CacheValid( self, start_column ):
|
def CacheValid( self, current_line, start_column ):
|
||||||
completion_line, _ = vimsupport.CurrentLineAndColumn()
|
return current_line == self.line and start_column == self.column
|
||||||
completion_column = start_column
|
|
||||||
return completion_line == self.line and completion_column == self.column
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
import vim
|
|
||||||
|
|
||||||
DEFAULT_FILETYPE_TRIGGERS = {
|
DEFAULT_FILETYPE_TRIGGERS = {
|
||||||
'c' : ['->', '.'],
|
'c' : ['->', '.'],
|
||||||
@ -58,12 +57,9 @@ def _FiletypeDictUnion( dict_one, dict_two ):
|
|||||||
return final_dict
|
return final_dict
|
||||||
|
|
||||||
|
|
||||||
def TriggersForFiletype():
|
def TriggersForFiletype( user_triggers ):
|
||||||
user_triggers = _FiletypeTriggerDictFromSpec(
|
|
||||||
vim.eval( 'g:ycm_semantic_triggers' ) )
|
|
||||||
|
|
||||||
default_triggers = _FiletypeTriggerDictFromSpec(
|
default_triggers = _FiletypeTriggerDictFromSpec(
|
||||||
DEFAULT_FILETYPE_TRIGGERS )
|
DEFAULT_FILETYPE_TRIGGERS )
|
||||||
|
|
||||||
return _FiletypeDictUnion( default_triggers, user_triggers )
|
return _FiletypeDictUnion( default_triggers, dict( user_triggers ) )
|
||||||
|
|
||||||
|
@ -18,14 +18,23 @@
|
|||||||
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
|
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
import vim
|
|
||||||
import ycm_core
|
import ycm_core
|
||||||
from ycm import vimsupport
|
import logging
|
||||||
|
from ycm import server_responses
|
||||||
from ycm import extra_conf_store
|
from ycm import extra_conf_store
|
||||||
from ycm.completers.completer import Completer
|
from ycm.completers.completer import Completer
|
||||||
from ycm.completers.cpp.flags import Flags
|
from ycm.completers.cpp.flags import Flags
|
||||||
|
|
||||||
CLANG_FILETYPES = set( [ 'c', 'cpp', 'objc', 'objcpp' ] )
|
CLANG_FILETYPES = set( [ 'c', 'cpp', 'objc', 'objcpp' ] )
|
||||||
|
MIN_LINES_IN_FILE_TO_PARSE = 5
|
||||||
|
PARSING_FILE_MESSAGE = 'Still parsing file, no completions yet.'
|
||||||
|
NO_COMPILE_FLAGS_MESSAGE = 'Still no compile flags, no completions yet.'
|
||||||
|
NO_COMPLETIONS_MESSAGE = 'No completions found; errors in the file?'
|
||||||
|
INVALID_FILE_MESSAGE = 'File is invalid.'
|
||||||
|
FILE_TOO_SHORT_MESSAGE = (
|
||||||
|
'File is less than {} lines long; not compiling.'.format(
|
||||||
|
MIN_LINES_IN_FILE_TO_PARSE ) )
|
||||||
|
NO_DIAGNOSTIC_MESSAGE = 'No diagnostic for current line!'
|
||||||
|
|
||||||
|
|
||||||
class ClangCompleter( Completer ):
|
class ClangCompleter( Completer ):
|
||||||
@ -35,12 +44,11 @@ class ClangCompleter( Completer ):
|
|||||||
'max_diagnostics_to_display' ]
|
'max_diagnostics_to_display' ]
|
||||||
self.completer = ycm_core.ClangCompleter()
|
self.completer = ycm_core.ClangCompleter()
|
||||||
self.completer.EnableThreading()
|
self.completer.EnableThreading()
|
||||||
self.contents_holder = []
|
|
||||||
self.filename_holder = []
|
|
||||||
self.last_prepared_diagnostics = []
|
self.last_prepared_diagnostics = []
|
||||||
self.parse_future = None
|
self.parse_future = None
|
||||||
self.flags = Flags()
|
self.flags = Flags()
|
||||||
self.diagnostic_store = None
|
self.diagnostic_store = None
|
||||||
|
self._logger = logging.getLogger( __name__ )
|
||||||
|
|
||||||
# We set this flag when a compilation request comes in while one is already
|
# We set this flag when a compilation request comes in while one is already
|
||||||
# in progress. We use this to trigger the pending request after the previous
|
# in progress. We use this to trigger the pending request after the previous
|
||||||
@ -53,63 +61,52 @@ class ClangCompleter( Completer ):
|
|||||||
return CLANG_FILETYPES
|
return CLANG_FILETYPES
|
||||||
|
|
||||||
|
|
||||||
def GetUnsavedFilesVector( self ):
|
def GetUnsavedFilesVector( self, request_data ):
|
||||||
# CAREFUL HERE! For UnsavedFile filename and contents we are referring
|
|
||||||
# directly to Python-allocated and -managed memory since we are accepting
|
|
||||||
# pointers to data members of python objects. We need to ensure that those
|
|
||||||
# objects outlive our UnsavedFile objects. This is why we need the
|
|
||||||
# contents_holder and filename_holder lists, to make sure the string objects
|
|
||||||
# are still around when we call CandidatesForQueryAndLocationInFile. We do
|
|
||||||
# this to avoid an extra copy of the entire file contents.
|
|
||||||
|
|
||||||
files = ycm_core.UnsavedFileVec()
|
files = ycm_core.UnsavedFileVec()
|
||||||
self.contents_holder = []
|
for filename, file_data in request_data[ 'file_data' ].iteritems():
|
||||||
self.filename_holder = []
|
if not ClangAvailableForFiletypes( file_data[ 'filetypes' ] ):
|
||||||
for buffer in vimsupport.GetUnsavedBuffers():
|
|
||||||
if not ClangAvailableForBuffer( buffer ):
|
|
||||||
continue
|
continue
|
||||||
contents = '\n'.join( buffer )
|
contents = file_data[ 'contents' ]
|
||||||
name = buffer.name
|
if not contents or not filename:
|
||||||
if not contents or not name:
|
|
||||||
continue
|
continue
|
||||||
self.contents_holder.append( contents )
|
|
||||||
self.filename_holder.append( name )
|
|
||||||
|
|
||||||
unsaved_file = ycm_core.UnsavedFile()
|
unsaved_file = ycm_core.UnsavedFile()
|
||||||
unsaved_file.contents_ = self.contents_holder[ -1 ]
|
unsaved_file.contents_ = contents
|
||||||
unsaved_file.length_ = len( self.contents_holder[ -1 ] )
|
unsaved_file.length_ = len( contents )
|
||||||
unsaved_file.filename_ = self.filename_holder[ -1 ]
|
unsaved_file.filename_ = filename
|
||||||
|
|
||||||
files.append( unsaved_file )
|
files.append( unsaved_file )
|
||||||
|
|
||||||
return files
|
return files
|
||||||
|
|
||||||
|
|
||||||
def CandidatesForQueryAsync( self, query, start_column ):
|
def CandidatesForQueryAsync( self, request_data ):
|
||||||
filename = vim.current.buffer.name
|
filename = request_data[ 'filepath' ]
|
||||||
|
|
||||||
if not filename:
|
if not filename:
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.completer.UpdatingTranslationUnit( filename ):
|
if self.completer.UpdatingTranslationUnit( filename ):
|
||||||
vimsupport.PostVimMessage( 'Still parsing file, no completions yet.' )
|
|
||||||
self.completions_future = None
|
self.completions_future = None
|
||||||
return
|
self._logger.info( PARSING_FILE_MESSAGE )
|
||||||
|
return server_responses.BuildDisplayMessageResponse(
|
||||||
|
PARSING_FILE_MESSAGE )
|
||||||
|
|
||||||
flags = self.flags.FlagsForFile( filename )
|
flags = self.flags.FlagsForFile( filename )
|
||||||
if not flags:
|
if not flags:
|
||||||
vimsupport.PostVimMessage( 'Still no compile flags, no completions yet.' )
|
|
||||||
self.completions_future = None
|
self.completions_future = None
|
||||||
return
|
self._logger.info( NO_COMPILE_FLAGS_MESSAGE )
|
||||||
|
return server_responses.BuildDisplayMessageResponse(
|
||||||
|
NO_COMPILE_FLAGS_MESSAGE )
|
||||||
|
|
||||||
# TODO: sanitize query, probably in C++ code
|
# TODO: sanitize query, probably in C++ code
|
||||||
|
|
||||||
files = ycm_core.UnsavedFileVec()
|
files = ycm_core.UnsavedFileVec()
|
||||||
|
query = request_data[ 'query' ]
|
||||||
if not query:
|
if not query:
|
||||||
files = self.GetUnsavedFilesVector()
|
files = self.GetUnsavedFilesVector( request_data )
|
||||||
|
|
||||||
line, _ = vim.current.window.cursor
|
line = request_data[ 'line_num' ] + 1
|
||||||
column = start_column + 1
|
column = request_data[ 'start_column' ] + 1
|
||||||
self.completions_future = (
|
self.completions_future = (
|
||||||
self.completer.CandidatesForQueryAndLocationInFileAsync(
|
self.completer.CandidatesForQueryAndLocationInFileAsync(
|
||||||
query,
|
query,
|
||||||
@ -123,10 +120,11 @@ class ClangCompleter( Completer ):
|
|||||||
def CandidatesFromStoredRequest( self ):
|
def CandidatesFromStoredRequest( self ):
|
||||||
if not self.completions_future:
|
if not self.completions_future:
|
||||||
return []
|
return []
|
||||||
results = [ CompletionDataToDict( x ) for x in
|
results = [ ConvertCompletionData( x ) for x in
|
||||||
self.completions_future.GetResults() ]
|
self.completions_future.GetResults() ]
|
||||||
if not results:
|
if not results:
|
||||||
vimsupport.PostVimMessage( 'No completions found; errors in the file?' )
|
self._logger.warning( NO_COMPLETIONS_MESSAGE )
|
||||||
|
raise RuntimeError( NO_COMPLETIONS_MESSAGE )
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
@ -137,37 +135,37 @@ class ClangCompleter( Completer ):
|
|||||||
'ClearCompilationFlagCache']
|
'ClearCompilationFlagCache']
|
||||||
|
|
||||||
|
|
||||||
def OnUserCommand( self, arguments ):
|
def OnUserCommand( self, arguments, request_data ):
|
||||||
if not arguments:
|
if not arguments:
|
||||||
self.EchoUserCommandsHelpMessage()
|
raise ValueError( self.UserCommandsHelpMessage() )
|
||||||
return
|
|
||||||
|
|
||||||
command = arguments[ 0 ]
|
command = arguments[ 0 ]
|
||||||
if command == 'GoToDefinition':
|
if command == 'GoToDefinition':
|
||||||
self._GoToDefinition()
|
self._GoToDefinition( request_data )
|
||||||
elif command == 'GoToDeclaration':
|
elif command == 'GoToDeclaration':
|
||||||
self._GoToDeclaration()
|
self._GoToDeclaration( request_data )
|
||||||
elif command == 'GoToDefinitionElseDeclaration':
|
elif command == 'GoToDefinitionElseDeclaration':
|
||||||
self._GoToDefinitionElseDeclaration()
|
self._GoToDefinitionElseDeclaration( request_data )
|
||||||
elif command == 'ClearCompilationFlagCache':
|
elif command == 'ClearCompilationFlagCache':
|
||||||
self._ClearCompilationFlagCache()
|
self._ClearCompilationFlagCache( request_data )
|
||||||
|
|
||||||
|
|
||||||
def _LocationForGoTo( self, goto_function ):
|
def _LocationForGoTo( self, goto_function, request_data ):
|
||||||
filename = vim.current.buffer.name
|
filename = request_data[ 'filepath' ]
|
||||||
if not filename:
|
if not filename:
|
||||||
return None
|
self._logger.warning( INVALID_FILE_MESSAGE )
|
||||||
|
return server_responses.BuildDisplayMessageResponse(
|
||||||
|
INVALID_FILE_MESSAGE )
|
||||||
|
|
||||||
flags = self.flags.FlagsForFile( filename )
|
flags = self.flags.FlagsForFile( filename )
|
||||||
if not flags:
|
if not flags:
|
||||||
vimsupport.PostVimMessage( 'Still no compile flags, can\'t compile.' )
|
self._logger.info( NO_COMPILE_FLAGS_MESSAGE )
|
||||||
return None
|
return server_responses.BuildDisplayMessageResponse(
|
||||||
|
NO_COMPILE_FLAGS_MESSAGE )
|
||||||
|
|
||||||
files = self.GetUnsavedFilesVector()
|
files = self.GetUnsavedFilesVector()
|
||||||
line, column = vimsupport.CurrentLineAndColumn()
|
line = request_data[ 'line_num' ] + 1
|
||||||
# Making the line & column 1-based instead of 0-based
|
column = request_data[ 'start_column' ] + 1
|
||||||
line += 1
|
|
||||||
column += 1
|
|
||||||
return getattr( self.completer, goto_function )(
|
return getattr( self.completer, goto_function )(
|
||||||
filename,
|
filename,
|
||||||
line,
|
line,
|
||||||
@ -176,39 +174,37 @@ class ClangCompleter( Completer ):
|
|||||||
flags )
|
flags )
|
||||||
|
|
||||||
|
|
||||||
def _GoToDefinition( self ):
|
def _GoToDefinition( self, request_data ):
|
||||||
location = self._LocationForGoTo( 'GetDefinitionLocation' )
|
location = self._LocationForGoTo( 'GetDefinitionLocation' )
|
||||||
if not location or not location.IsValid():
|
if not location or not location.IsValid():
|
||||||
vimsupport.PostVimMessage( 'Can\'t jump to definition.' )
|
raise RuntimeError( 'Can\'t jump to definition.' )
|
||||||
return
|
|
||||||
|
|
||||||
vimsupport.JumpToLocation( location.filename_,
|
return server_responses.BuildGoToResponse( location.filename_,
|
||||||
location.line_number_,
|
location.line_number_,
|
||||||
location.column_number_ )
|
location.column_number_ )
|
||||||
|
|
||||||
|
|
||||||
def _GoToDeclaration( self ):
|
def _GoToDeclaration( self, request_data ):
|
||||||
location = self._LocationForGoTo( 'GetDeclarationLocation' )
|
location = self._LocationForGoTo( 'GetDeclarationLocation' )
|
||||||
if not location or not location.IsValid():
|
if not location or not location.IsValid():
|
||||||
vimsupport.PostVimMessage( 'Can\'t jump to declaration.' )
|
raise RuntimeError( 'Can\'t jump to declaration.' )
|
||||||
return
|
|
||||||
|
|
||||||
vimsupport.JumpToLocation( location.filename_,
|
return server_responses.BuildGoToResponse( location.filename_,
|
||||||
location.line_number_,
|
location.line_number_,
|
||||||
location.column_number_ )
|
location.column_number_ )
|
||||||
|
|
||||||
|
|
||||||
def _GoToDefinitionElseDeclaration( self ):
|
def _GoToDefinitionElseDeclaration( self, request_data ):
|
||||||
location = self._LocationForGoTo( 'GetDefinitionLocation' )
|
location = self._LocationForGoTo( 'GetDefinitionLocation' )
|
||||||
if not location or not location.IsValid():
|
if not location or not location.IsValid():
|
||||||
location = self._LocationForGoTo( 'GetDeclarationLocation' )
|
location = self._LocationForGoTo( 'GetDeclarationLocation' )
|
||||||
if not location or not location.IsValid():
|
if not location or not location.IsValid():
|
||||||
vimsupport.PostVimMessage( 'Can\'t jump to definition or declaration.' )
|
raise RuntimeError( 'Can\'t jump to definition or declaration.' )
|
||||||
return
|
|
||||||
|
return server_responses.BuildGoToResponse( location.filename_,
|
||||||
|
location.line_number_,
|
||||||
|
location.column_number_ )
|
||||||
|
|
||||||
vimsupport.JumpToLocation( location.filename_,
|
|
||||||
location.line_number_,
|
|
||||||
location.column_number_ )
|
|
||||||
|
|
||||||
|
|
||||||
def _ClearCompilationFlagCache( self ):
|
def _ClearCompilationFlagCache( self ):
|
||||||
@ -216,14 +212,18 @@ class ClangCompleter( Completer ):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def OnFileReadyToParse( self ):
|
def OnFileReadyToParse( self, request_data ):
|
||||||
if vimsupport.NumLinesInBuffer( vim.current.buffer ) < 5:
|
filename = request_data[ 'filepath' ]
|
||||||
|
contents = request_data[ 'file_data' ][ filename ][ 'contents' ]
|
||||||
|
if contents.count( '\n' ) < MIN_LINES_IN_FILE_TO_PARSE:
|
||||||
self.parse_future = None
|
self.parse_future = None
|
||||||
return
|
self._logger.warning( FILE_TOO_SHORT_MESSAGE )
|
||||||
|
raise ValueError( FILE_TOO_SHORT_MESSAGE )
|
||||||
|
|
||||||
filename = vim.current.buffer.name
|
|
||||||
if not filename:
|
if not filename:
|
||||||
return
|
self._logger.warning( INVALID_FILE_MESSAGE )
|
||||||
|
return server_responses.BuildDisplayMessageResponse(
|
||||||
|
INVALID_FILE_MESSAGE )
|
||||||
|
|
||||||
if self.completer.UpdatingTranslationUnit( filename ):
|
if self.completer.UpdatingTranslationUnit( filename ):
|
||||||
self.extra_parse_desired = True
|
self.extra_parse_desired = True
|
||||||
@ -232,11 +232,13 @@ class ClangCompleter( Completer ):
|
|||||||
flags = self.flags.FlagsForFile( filename )
|
flags = self.flags.FlagsForFile( filename )
|
||||||
if not flags:
|
if not flags:
|
||||||
self.parse_future = None
|
self.parse_future = None
|
||||||
return
|
self._logger.info( NO_COMPILE_FLAGS_MESSAGE )
|
||||||
|
return server_responses.BuildDisplayMessageResponse(
|
||||||
|
NO_COMPILE_FLAGS_MESSAGE )
|
||||||
|
|
||||||
self.parse_future = self.completer.UpdateTranslationUnitAsync(
|
self.parse_future = self.completer.UpdateTranslationUnitAsync(
|
||||||
filename,
|
filename,
|
||||||
self.GetUnsavedFilesVector(),
|
self.GetUnsavedFilesVector( request_data ),
|
||||||
flags )
|
flags )
|
||||||
|
|
||||||
self.extra_parse_desired = False
|
self.extra_parse_desired = False
|
||||||
@ -253,16 +255,18 @@ class ClangCompleter( Completer ):
|
|||||||
return self.parse_future.ResultsReady()
|
return self.parse_future.ResultsReady()
|
||||||
|
|
||||||
|
|
||||||
def GettingCompletions( self ):
|
def GettingCompletions( self, request_data ):
|
||||||
return self.completer.UpdatingTranslationUnit( vim.current.buffer.name )
|
return self.completer.UpdatingTranslationUnit( request_data[ 'filepath' ] )
|
||||||
|
|
||||||
|
|
||||||
def GetDiagnosticsForCurrentFile( self ):
|
def GetDiagnosticsForCurrentFile( self, request_data ):
|
||||||
|
filename = request_data[ 'filepath' ]
|
||||||
if self.DiagnosticsForCurrentFileReady():
|
if self.DiagnosticsForCurrentFileReady():
|
||||||
diagnostics = self.completer.DiagnosticsForFile( vim.current.buffer.name )
|
diagnostics = self.completer.DiagnosticsForFile( filename )
|
||||||
self.diagnostic_store = DiagnosticsToDiagStructure( diagnostics )
|
self.diagnostic_store = DiagnosticsToDiagStructure( diagnostics )
|
||||||
self.last_prepared_diagnostics = [ DiagnosticToDict( x ) for x in
|
self.last_prepared_diagnostics = [
|
||||||
diagnostics[ : self.max_diagnostics_to_display ] ]
|
server_responses.BuildDiagnosticData( x ) for x in
|
||||||
|
diagnostics[ : self.max_diagnostics_to_display ] ]
|
||||||
self.parse_future = None
|
self.parse_future = None
|
||||||
|
|
||||||
if self.extra_parse_desired:
|
if self.extra_parse_desired:
|
||||||
@ -271,23 +275,19 @@ class ClangCompleter( Completer ):
|
|||||||
return self.last_prepared_diagnostics
|
return self.last_prepared_diagnostics
|
||||||
|
|
||||||
|
|
||||||
def ShowDetailedDiagnostic( self ):
|
def GetDetailedDiagnostic( self, request_data ):
|
||||||
current_line, current_column = vimsupport.CurrentLineAndColumn()
|
current_line = request_data[ 'line_num' ] + 1
|
||||||
|
current_column = request_data[ 'column_num' ] + 1
|
||||||
# CurrentLineAndColumn() numbers are 0-based, clang numbers are 1-based
|
current_file = request_data[ 'filepath' ]
|
||||||
current_line += 1
|
|
||||||
current_column += 1
|
|
||||||
|
|
||||||
current_file = vim.current.buffer.name
|
|
||||||
|
|
||||||
if not self.diagnostic_store:
|
if not self.diagnostic_store:
|
||||||
vimsupport.PostVimMessage( "No diagnostic for current line!" )
|
return server_responses.BuildDisplayMessageResponse(
|
||||||
return
|
NO_DIAGNOSTIC_MESSAGE )
|
||||||
|
|
||||||
diagnostics = self.diagnostic_store[ current_file ][ current_line ]
|
diagnostics = self.diagnostic_store[ current_file ][ current_line ]
|
||||||
if not diagnostics:
|
if not diagnostics:
|
||||||
vimsupport.PostVimMessage( "No diagnostic for current line!" )
|
return server_responses.BuildDisplayMessageResponse(
|
||||||
return
|
NO_DIAGNOSTIC_MESSAGE )
|
||||||
|
|
||||||
closest_diagnostic = None
|
closest_diagnostic = None
|
||||||
distance_to_closest_diagnostic = 999
|
distance_to_closest_diagnostic = 999
|
||||||
@ -298,50 +298,61 @@ class ClangCompleter( Completer ):
|
|||||||
distance_to_closest_diagnostic = distance
|
distance_to_closest_diagnostic = distance
|
||||||
closest_diagnostic = diagnostic
|
closest_diagnostic = diagnostic
|
||||||
|
|
||||||
vimsupport.EchoText( closest_diagnostic.long_formatted_text_ )
|
return server_responses.BuildDisplayMessageResponse(
|
||||||
|
closest_diagnostic.long_formatted_text_ )
|
||||||
|
|
||||||
|
|
||||||
def ShouldUseNow( self, start_column, current_line ):
|
def ShouldUseNow( self, request_data ):
|
||||||
# We don't want to use the Completer API cache, we use one in the C++ code.
|
# We don't want to use the Completer API cache, we use one in the C++ code.
|
||||||
return self.ShouldUseNowInner( start_column, current_line )
|
return self.ShouldUseNowInner( request_data )
|
||||||
|
|
||||||
|
|
||||||
def DebugInfo( self ):
|
def DebugInfo( self, request_data ):
|
||||||
filename = vim.current.buffer.name
|
filename = request_data[ 'filepath' ]
|
||||||
if not filename:
|
if not filename:
|
||||||
return ''
|
return ''
|
||||||
flags = self.flags.FlagsForFile( filename ) or []
|
flags = self.flags.FlagsForFile( filename ) or []
|
||||||
source = extra_conf_store.ModuleFileForSourceFile( filename )
|
source = extra_conf_store.ModuleFileForSourceFile( filename )
|
||||||
return 'Flags for {0} loaded from {1}:\n{2}'.format( filename,
|
return server_responses.BuildDisplayMessageResponse(
|
||||||
source,
|
'Flags for {0} loaded from {1}:\n{2}'.format( filename,
|
||||||
list( flags ) )
|
source,
|
||||||
|
list( flags ) ) )
|
||||||
|
|
||||||
|
|
||||||
# TODO: make these functions module-local
|
# TODO: make these functions module-local
|
||||||
def CompletionDataToDict( completion_data ):
|
# def CompletionDataToDict( completion_data ):
|
||||||
# see :h complete-items for a description of the dictionary fields
|
# # see :h complete-items for a description of the dictionary fields
|
||||||
return {
|
# return {
|
||||||
'word' : completion_data.TextToInsertInBuffer(),
|
# 'word' : completion_data.TextToInsertInBuffer(),
|
||||||
'abbr' : completion_data.MainCompletionText(),
|
# 'abbr' : completion_data.MainCompletionText(),
|
||||||
'menu' : completion_data.ExtraMenuInfo(),
|
# 'menu' : completion_data.ExtraMenuInfo(),
|
||||||
'kind' : completion_data.kind_,
|
# 'kind' : completion_data.kind_,
|
||||||
'info' : completion_data.DetailedInfoForPreviewWindow(),
|
# 'info' : completion_data.DetailedInfoForPreviewWindow(),
|
||||||
'dup' : 1,
|
# 'dup' : 1,
|
||||||
}
|
# }
|
||||||
|
|
||||||
|
|
||||||
def DiagnosticToDict( diagnostic ):
|
# def DiagnosticToDict( diagnostic ):
|
||||||
# see :h getqflist for a description of the dictionary fields
|
# # see :h getqflist for a description of the dictionary fields
|
||||||
return {
|
# return {
|
||||||
# TODO: wrap the bufnr generation into a function
|
# # TODO: wrap the bufnr generation into a function
|
||||||
'bufnr' : int( vim.eval( "bufnr('{0}', 1)".format(
|
# 'bufnr' : int( vim.eval( "bufnr('{0}', 1)".format(
|
||||||
diagnostic.filename_ ) ) ),
|
# diagnostic.filename_ ) ) ),
|
||||||
'lnum' : diagnostic.line_number_,
|
# 'lnum' : diagnostic.line_number_,
|
||||||
'col' : diagnostic.column_number_,
|
# 'col' : diagnostic.column_number_,
|
||||||
'text' : diagnostic.text_,
|
# 'text' : diagnostic.text_,
|
||||||
'type' : diagnostic.kind_,
|
# 'type' : diagnostic.kind_,
|
||||||
'valid' : 1
|
# 'valid' : 1
|
||||||
}
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
def ConvertCompletionData( completion_data ):
|
||||||
|
return server_responses.BuildCompletionData(
|
||||||
|
insertion_text = completion_data.TextToInsertInBuffer(),
|
||||||
|
menu_text = completion_data.MainCompletionText(),
|
||||||
|
extra_menu_info = completion_data.ExtraMenuInfo(),
|
||||||
|
kind = completion_data.kind_,
|
||||||
|
detailed_info = completion_data.DetailedInfoForPreviewWindow() )
|
||||||
|
|
||||||
|
|
||||||
def DiagnosticsToDiagStructure( diagnostics ):
|
def DiagnosticsToDiagStructure( diagnostics ):
|
||||||
@ -352,12 +363,9 @@ def DiagnosticsToDiagStructure( diagnostics ):
|
|||||||
return structure
|
return structure
|
||||||
|
|
||||||
|
|
||||||
def ClangAvailableForBuffer( buffer_object ):
|
def ClangAvailableForFiletypes( filetypes ):
|
||||||
filetypes = vimsupport.FiletypesForBuffer( buffer_object )
|
|
||||||
return any( [ filetype in CLANG_FILETYPES for filetype in filetypes ] )
|
return any( [ filetype in CLANG_FILETYPES for filetype in filetypes ] )
|
||||||
|
|
||||||
|
|
||||||
def InCFamilyFile():
|
def InCFamilyFile( filetypes ):
|
||||||
return any( [ filetype in CLANG_FILETYPES for filetype in
|
return ClangAvailableForFiletypes( filetypes )
|
||||||
vimsupport.CurrentFiletypes() ] )
|
|
||||||
|
|
||||||
|
@ -19,12 +19,11 @@
|
|||||||
|
|
||||||
import ycm_core
|
import ycm_core
|
||||||
import os
|
import os
|
||||||
from ycm import vimsupport
|
|
||||||
from ycm import extra_conf_store
|
from ycm import extra_conf_store
|
||||||
|
|
||||||
NO_EXTRA_CONF_FILENAME_MESSAGE = ('No {0} file detected, so no compile flags '
|
NO_EXTRA_CONF_FILENAME_MESSAGE = ( 'No {0} file detected, so no compile flags '
|
||||||
'are available. Thus no semantic support for C/C++/ObjC/ObjC++. Go READ THE '
|
'are available. Thus no semantic support for C/C++/ObjC/ObjC++. Go READ THE '
|
||||||
'DOCS *NOW*, DON\'T file a bug report.').format(
|
'DOCS *NOW*, DON\'T file a bug report.' ).format(
|
||||||
extra_conf_store.YCM_EXTRA_CONF_FILENAME )
|
extra_conf_store.YCM_EXTRA_CONF_FILENAME )
|
||||||
|
|
||||||
|
|
||||||
@ -37,7 +36,6 @@ class Flags( object ):
|
|||||||
# It's caches all the way down...
|
# It's caches all the way down...
|
||||||
self.flags_for_file = {}
|
self.flags_for_file = {}
|
||||||
self.special_clang_flags = _SpecialClangIncludes()
|
self.special_clang_flags = _SpecialClangIncludes()
|
||||||
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 ):
|
||||||
@ -46,10 +44,7 @@ class Flags( object ):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
module = extra_conf_store.ModuleForSourceFile( filename )
|
module = extra_conf_store.ModuleForSourceFile( filename )
|
||||||
if not module:
|
if not module:
|
||||||
if not self.no_extra_conf_file_warning_posted:
|
raise RuntimeError( NO_EXTRA_CONF_FILENAME_MESSAGE )
|
||||||
vimsupport.PostVimMessage( NO_EXTRA_CONF_FILENAME_MESSAGE )
|
|
||||||
self.no_extra_conf_file_warning_posted = True
|
|
||||||
return None
|
|
||||||
|
|
||||||
results = module.FlagsForFile( filename )
|
results = module.FlagsForFile( filename )
|
||||||
|
|
||||||
|
@ -18,18 +18,18 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
|
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import vim
|
|
||||||
import os
|
import os
|
||||||
from sys import platform
|
from sys import platform
|
||||||
import glob
|
import glob
|
||||||
from ycm.completers.threaded_completer import ThreadedCompleter
|
from ycm.completers.threaded_completer import ThreadedCompleter
|
||||||
from ycm import vimsupport
|
from ycm import server_responses
|
||||||
import urllib2
|
import urllib2
|
||||||
import urllib
|
import urllib
|
||||||
import urlparse
|
import urlparse
|
||||||
import json
|
import json
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
SERVER_NOT_FOUND_MSG = ( 'OmniSharp server binary not found at {0}. ' +
|
SERVER_NOT_FOUND_MSG = ( 'OmniSharp server binary not found at {0}. ' +
|
||||||
@ -44,9 +44,10 @@ class CsharpCompleter( ThreadedCompleter ):
|
|||||||
def __init__( self, user_options ):
|
def __init__( self, user_options ):
|
||||||
super( CsharpCompleter, self ).__init__( user_options )
|
super( CsharpCompleter, self ).__init__( user_options )
|
||||||
self._omnisharp_port = None
|
self._omnisharp_port = None
|
||||||
|
self._logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
if self.user_options[ 'auto_start_csharp_server' ]:
|
# if self.user_options[ 'auto_start_csharp_server' ]:
|
||||||
self._StartServer()
|
# self._StartServer()
|
||||||
|
|
||||||
|
|
||||||
def OnVimLeave( self ):
|
def OnVimLeave( self ):
|
||||||
@ -60,11 +61,12 @@ class CsharpCompleter( ThreadedCompleter ):
|
|||||||
return [ 'cs' ]
|
return [ 'cs' ]
|
||||||
|
|
||||||
|
|
||||||
def ComputeCandidates( self, unused_query, unused_start_column ):
|
def ComputeCandidates( self, request_data ):
|
||||||
return [ { 'word': str( completion[ 'CompletionText' ] ),
|
return [ server_responses.BuildCompletionData(
|
||||||
'menu': str( completion[ 'DisplayText' ] ),
|
completion[ 'CompletionText' ],
|
||||||
'info': str( completion[ 'Description' ] ) }
|
completion[ 'DisplayText' ],
|
||||||
for completion in self._GetCompletions() ]
|
completion[ 'Description' ] )
|
||||||
|
for completion in self._GetCompletions( request_data ) ]
|
||||||
|
|
||||||
|
|
||||||
def DefinedSubcommands( self ):
|
def DefinedSubcommands( self ):
|
||||||
@ -76,24 +78,23 @@ class CsharpCompleter( ThreadedCompleter ):
|
|||||||
'GoToDefinitionElseDeclaration' ]
|
'GoToDefinitionElseDeclaration' ]
|
||||||
|
|
||||||
|
|
||||||
def OnUserCommand( self, arguments ):
|
def OnUserCommand( self, arguments, request_data ):
|
||||||
if not arguments:
|
if not arguments:
|
||||||
self.EchoUserCommandsHelpMessage()
|
raise ValueError( self.UserCommandsHelpMessage() )
|
||||||
return
|
|
||||||
|
|
||||||
command = arguments[ 0 ]
|
command = arguments[ 0 ]
|
||||||
if command == 'StartServer':
|
if command == 'StartServer':
|
||||||
self._StartServer()
|
self._StartServer( request_data )
|
||||||
elif command == 'StopServer':
|
elif command == 'StopServer':
|
||||||
self._StopServer()
|
self._StopServer()
|
||||||
elif command == 'RestartServer':
|
elif command == 'RestartServer':
|
||||||
if self._ServerIsRunning():
|
if self._ServerIsRunning():
|
||||||
self._StopServer()
|
self._StopServer()
|
||||||
self._StartServer()
|
self._StartServer( request_data )
|
||||||
elif command in [ 'GoToDefinition',
|
elif command in [ 'GoToDefinition',
|
||||||
'GoToDeclaration',
|
'GoToDeclaration',
|
||||||
'GoToDefinitionElseDeclaration' ]:
|
'GoToDefinitionElseDeclaration' ]:
|
||||||
self._GoToDefinition()
|
return self._GoToDefinition( request_data )
|
||||||
|
|
||||||
|
|
||||||
def DebugInfo( self ):
|
def DebugInfo( self ):
|
||||||
@ -104,35 +105,27 @@ class CsharpCompleter( ThreadedCompleter ):
|
|||||||
return 'Server is not running'
|
return 'Server is not running'
|
||||||
|
|
||||||
|
|
||||||
def _StartServer( self ):
|
def _StartServer( self, request_data ):
|
||||||
""" Start the OmniSharp server """
|
""" Start the OmniSharp server """
|
||||||
self._omnisharp_port = self._FindFreePort()
|
self._omnisharp_port = self._FindFreePort()
|
||||||
solutionfiles, folder = _FindSolutionFiles()
|
solutionfiles, folder = _FindSolutionFiles( request_data[ 'filepath' ] )
|
||||||
|
|
||||||
if len( solutionfiles ) == 0:
|
if len( solutionfiles ) == 0:
|
||||||
vimsupport.PostVimMessage(
|
raise RuntimeError(
|
||||||
'Error starting OmniSharp server: no solutionfile found' )
|
'Error starting OmniSharp server: no solutionfile found' )
|
||||||
return
|
|
||||||
elif len( solutionfiles ) == 1:
|
elif len( solutionfiles ) == 1:
|
||||||
solutionfile = solutionfiles[ 0 ]
|
solutionfile = solutionfiles[ 0 ]
|
||||||
else:
|
else:
|
||||||
choice = vimsupport.PresentDialog(
|
raise RuntimeError(
|
||||||
'Which solutionfile should be loaded?',
|
'Found multiple solution files instead of one!\n{}'.format(
|
||||||
[ str( i ) + " " + solution for i, solution in
|
solutionfiles ) )
|
||||||
enumerate( solutionfiles ) ] )
|
|
||||||
if choice == -1:
|
|
||||||
vimsupport.PostVimMessage( 'OmniSharp not started' )
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
solutionfile = solutionfiles[ choice ]
|
|
||||||
|
|
||||||
omnisharp = os.path.join(
|
omnisharp = os.path.join(
|
||||||
os.path.abspath( os.path.dirname( __file__ ) ),
|
os.path.abspath( os.path.dirname( __file__ ) ),
|
||||||
'OmniSharpServer/OmniSharp/bin/Debug/OmniSharp.exe' )
|
'OmniSharpServer/OmniSharp/bin/Debug/OmniSharp.exe' )
|
||||||
|
|
||||||
if not os.path.isfile( omnisharp ):
|
if not os.path.isfile( omnisharp ):
|
||||||
vimsupport.PostVimMessage( SERVER_NOT_FOUND_MSG.format( omnisharp ) )
|
raise RuntimeError( SERVER_NOT_FOUND_MSG.format( omnisharp ) )
|
||||||
return
|
|
||||||
|
|
||||||
if not platform.startswith( 'win' ):
|
if not platform.startswith( 'win' ):
|
||||||
omnisharp = 'mono ' + omnisharp
|
omnisharp = 'mono ' + omnisharp
|
||||||
@ -154,40 +147,44 @@ class CsharpCompleter( ThreadedCompleter ):
|
|||||||
with open( self._filename_stdout, 'w' ) as fstdout:
|
with open( self._filename_stdout, 'w' ) as fstdout:
|
||||||
subprocess.Popen( command, stdout=fstdout, stderr=fstderr, shell=True )
|
subprocess.Popen( command, stdout=fstdout, stderr=fstderr, shell=True )
|
||||||
|
|
||||||
vimsupport.PostVimMessage( 'Starting OmniSharp server' )
|
self._logger.info( 'Starting OmniSharp server' )
|
||||||
|
|
||||||
|
|
||||||
def _StopServer( self ):
|
def _StopServer( self ):
|
||||||
""" Stop the OmniSharp server """
|
""" Stop the OmniSharp server """
|
||||||
self._GetResponse( '/stopserver' )
|
self._GetResponse( '/stopserver' )
|
||||||
self._omnisharp_port = None
|
self._omnisharp_port = None
|
||||||
vimsupport.PostVimMessage( 'Stopping OmniSharp server' )
|
self._logger.info( 'Stopping OmniSharp server' )
|
||||||
|
|
||||||
|
|
||||||
def _GetCompletions( self ):
|
def _GetCompletions( self, request_data ):
|
||||||
""" Ask server for completions """
|
""" Ask server for completions """
|
||||||
completions = self._GetResponse( '/autocomplete', self._DefaultParameters() )
|
completions = self._GetResponse( '/autocomplete',
|
||||||
|
self._DefaultParameters( request_data ) )
|
||||||
return completions if completions != None else []
|
return completions if completions != None else []
|
||||||
|
|
||||||
|
|
||||||
def _GoToDefinition( self ):
|
def _GoToDefinition( self, request_data ):
|
||||||
""" Jump to definition of identifier under cursor """
|
""" Jump to definition of identifier under cursor """
|
||||||
definition = self._GetResponse( '/gotodefinition', self._DefaultParameters() )
|
definition = self._GetResponse( '/gotodefinition',
|
||||||
|
self._DefaultParameters( request_data ) )
|
||||||
if definition[ 'FileName' ] != None:
|
if definition[ 'FileName' ] != None:
|
||||||
vimsupport.JumpToLocation( definition[ 'FileName' ],
|
return server_responses.BuildGoToResponse( definition[ 'FileName' ],
|
||||||
definition[ 'Line' ],
|
definition[ 'Line' ],
|
||||||
definition[ 'Column' ] )
|
definition[ 'Column' ] )
|
||||||
else:
|
else:
|
||||||
vimsupport.PostVimMessage( 'Can\'t jump to definition' )
|
raise RuntimeError( 'Can\'t jump to definition' )
|
||||||
|
|
||||||
|
|
||||||
def _DefaultParameters( self ):
|
def _DefaultParameters( self, request_data ):
|
||||||
""" Some very common request parameters """
|
""" Some very common request parameters """
|
||||||
line, column = vimsupport.CurrentLineAndColumn()
|
|
||||||
parameters = {}
|
parameters = {}
|
||||||
parameters[ 'line' ], parameters[ 'column' ] = line + 1, column + 1
|
parameters[ 'line' ] = request_data[ 'line_num' ] + 1
|
||||||
parameters[ 'buffer' ] = '\n'.join( vim.current.buffer )
|
parameters[ 'column' ] = request_data[ 'column_num' ] + 1
|
||||||
parameters[ 'filename' ] = vim.current.buffer.name
|
filepath = request_data[ 'filepath' ]
|
||||||
|
parameters[ 'buffer' ] = request_data[ 'file_data' ][ filepath ][
|
||||||
|
'contents' ]
|
||||||
|
parameters[ 'filename' ] = filepath
|
||||||
return parameters
|
return parameters
|
||||||
|
|
||||||
|
|
||||||
@ -215,20 +212,16 @@ class CsharpCompleter( ThreadedCompleter ):
|
|||||||
|
|
||||||
def _GetResponse( self, endPoint, parameters={}, silent=False, port=None ):
|
def _GetResponse( self, endPoint, parameters={}, silent=False, port=None ):
|
||||||
""" Handle communication with server """
|
""" Handle communication with server """
|
||||||
|
# TODO: Replace usage of urllib with Requests
|
||||||
target = urlparse.urljoin( self._PortToHost( port ), endPoint )
|
target = urlparse.urljoin( self._PortToHost( port ), endPoint )
|
||||||
parameters = urllib.urlencode( parameters )
|
parameters = urllib.urlencode( parameters )
|
||||||
try:
|
response = urllib2.urlopen( target, parameters )
|
||||||
response = urllib2.urlopen( target, parameters )
|
return json.loads( response.read() )
|
||||||
return json.loads( response.read() )
|
|
||||||
except Exception:
|
|
||||||
# TODO: Add logging for this case. We can't post a Vim message because Vim
|
|
||||||
# crashes when that's done from a no-GUI thread.
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def _FindSolutionFiles():
|
def _FindSolutionFiles( filepath ):
|
||||||
""" Find solution files by searching upwards in the file tree """
|
""" Find solution files by searching upwards in the file tree """
|
||||||
folder = os.path.dirname( vim.current.buffer.name )
|
folder = os.path.dirname( filepath )
|
||||||
solutionfiles = glob.glob1( folder, '*.sln' )
|
solutionfiles = glob.glob1( folder, '*.sln' )
|
||||||
while not solutionfiles:
|
while not solutionfiles:
|
||||||
lastfolder = folder
|
lastfolder = folder
|
||||||
|
@ -16,13 +16,13 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
|
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import vim
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from ycm.completers.threaded_completer import ThreadedCompleter
|
from ycm.completers.threaded_completer import ThreadedCompleter
|
||||||
from ycm.completers.cpp.clang_completer import InCFamilyFile
|
from ycm.completers.cpp.clang_completer import InCFamilyFile
|
||||||
from ycm.completers.cpp.flags import Flags
|
from ycm.completers.cpp.flags import Flags
|
||||||
|
from ycm import server_responses
|
||||||
|
|
||||||
class FilenameCompleter( ThreadedCompleter ):
|
class FilenameCompleter( ThreadedCompleter ):
|
||||||
"""
|
"""
|
||||||
@ -52,23 +52,32 @@ class FilenameCompleter( ThreadedCompleter ):
|
|||||||
self._include_regex = re.compile( include_regex_common )
|
self._include_regex = re.compile( include_regex_common )
|
||||||
|
|
||||||
|
|
||||||
def AtIncludeStatementStart( self, start_column ):
|
def AtIncludeStatementStart( self, request_data ):
|
||||||
return ( InCFamilyFile() and
|
start_column = request_data[ 'start_column' ]
|
||||||
|
current_line = request_data[ 'line_value' ]
|
||||||
|
filepath = request_data[ 'filepath' ]
|
||||||
|
filetypes = request_data[ 'file_data' ][ filepath ][ 'filetypes' ]
|
||||||
|
return ( InCFamilyFile( filetypes ) and
|
||||||
self._include_start_regex.match(
|
self._include_start_regex.match(
|
||||||
vim.current.line[ :start_column ] ) )
|
current_line[ :start_column ] ) )
|
||||||
|
|
||||||
|
|
||||||
def ShouldUseNowInner( self, start_column, current_line ):
|
def ShouldUseNowInner( self, request_data ):
|
||||||
|
start_column = request_data[ 'start_column' ]
|
||||||
|
current_line = request_data[ 'line_value' ]
|
||||||
return ( start_column and ( current_line[ start_column - 1 ] == '/' or
|
return ( start_column and ( current_line[ start_column - 1 ] == '/' or
|
||||||
self.AtIncludeStatementStart( start_column ) ) )
|
self.AtIncludeStatementStart( request_data ) ) )
|
||||||
|
|
||||||
|
|
||||||
def SupportedFiletypes( self ):
|
def SupportedFiletypes( self ):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def ComputeCandidates( self, unused_query, start_column ):
|
def ComputeCandidates( self, request_data ):
|
||||||
line = vim.current.line[ :start_column ]
|
current_line = request_data[ 'line_value' ]
|
||||||
|
start_column = request_data[ 'start_column' ]
|
||||||
|
filepath = request_data[ 'filepath' ]
|
||||||
|
line = current_line[ :start_column ]
|
||||||
|
|
||||||
if InCFamilyFile():
|
if InCFamilyFile():
|
||||||
include_match = self._include_regex.search( line )
|
include_match = self._include_regex.search( line )
|
||||||
@ -78,22 +87,26 @@ class FilenameCompleter( ThreadedCompleter ):
|
|||||||
# http://gcc.gnu.org/onlinedocs/cpp/Include-Syntax.html
|
# http://gcc.gnu.org/onlinedocs/cpp/Include-Syntax.html
|
||||||
include_current_file_dir = '<' not in include_match.group()
|
include_current_file_dir = '<' not in include_match.group()
|
||||||
return _GenerateCandidatesForPaths(
|
return _GenerateCandidatesForPaths(
|
||||||
self.GetPathsIncludeCase( path_dir, include_current_file_dir ) )
|
self.GetPathsIncludeCase( path_dir,
|
||||||
|
include_current_file_dir,
|
||||||
|
filepath ) )
|
||||||
|
|
||||||
path_match = self._path_regex.search( line )
|
path_match = self._path_regex.search( line )
|
||||||
path_dir = os.path.expanduser( path_match.group() ) if path_match else ''
|
path_dir = os.path.expanduser( path_match.group() ) if path_match else ''
|
||||||
|
|
||||||
return _GenerateCandidatesForPaths(
|
return _GenerateCandidatesForPaths(
|
||||||
_GetPathsStandardCase( path_dir, self.user_options[
|
_GetPathsStandardCase(
|
||||||
'filepath_completion_use_working_dir' ] ) )
|
path_dir,
|
||||||
|
self.user_options[ 'filepath_completion_use_working_dir' ],
|
||||||
|
filepath ) )
|
||||||
|
|
||||||
|
|
||||||
def GetPathsIncludeCase( self, path_dir, include_current_file_dir ):
|
def GetPathsIncludeCase( self, path_dir, include_current_file_dir, filepath ):
|
||||||
paths = []
|
paths = []
|
||||||
include_paths = self._flags.UserIncludePaths( vim.current.buffer.name )
|
include_paths = self._flags.UserIncludePaths( filepath )
|
||||||
|
|
||||||
if include_current_file_dir:
|
if include_current_file_dir:
|
||||||
include_paths.append( os.path.dirname( vim.current.buffer.name ) )
|
include_paths.append( os.path.dirname( filepath ) )
|
||||||
|
|
||||||
for include_path in include_paths:
|
for include_path in include_paths:
|
||||||
try:
|
try:
|
||||||
@ -107,9 +120,9 @@ class FilenameCompleter( ThreadedCompleter ):
|
|||||||
return sorted( set( paths ) )
|
return sorted( set( paths ) )
|
||||||
|
|
||||||
|
|
||||||
def _GetPathsStandardCase( path_dir, use_working_dir ):
|
def _GetPathsStandardCase( path_dir, use_working_dir, filepath ):
|
||||||
if not use_working_dir and not path_dir.startswith( '/' ):
|
if not use_working_dir and not path_dir.startswith( '/' ):
|
||||||
path_dir = os.path.join( os.path.dirname( vim.current.buffer.name ),
|
path_dir = os.path.join( os.path.dirname( filepath ),
|
||||||
path_dir )
|
path_dir )
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -132,8 +145,8 @@ def _GenerateCandidatesForPaths( absolute_paths ):
|
|||||||
seen_basenames.add( basename )
|
seen_basenames.add( basename )
|
||||||
|
|
||||||
is_dir = os.path.isdir( absolute_path )
|
is_dir = os.path.isdir( absolute_path )
|
||||||
completion_dicts.append( { 'word': basename,
|
completion_dicts.append(
|
||||||
'dup': 1,
|
server_responses.BuildCompletionData( basename,
|
||||||
'menu': '[Dir]' if is_dir else '[File]' } )
|
'[Dir]' if is_dir else '[File]' ) )
|
||||||
|
|
||||||
return completion_dicts
|
return completion_dicts
|
||||||
|
@ -58,18 +58,17 @@ class GeneralCompleterStore( Completer ):
|
|||||||
return set()
|
return set()
|
||||||
|
|
||||||
|
|
||||||
def ShouldUseNow( self, start_column, current_line ):
|
def ShouldUseNow( self, request_data ):
|
||||||
self._current_query_completers = []
|
self._current_query_completers = []
|
||||||
|
|
||||||
if self._filename_completer.ShouldUseNow( start_column, current_line ):
|
if self._filename_completer.ShouldUseNow( request_data ):
|
||||||
self._current_query_completers = [ self._filename_completer ]
|
self._current_query_completers = [ self._filename_completer ]
|
||||||
return True
|
return True
|
||||||
|
|
||||||
should_use_now = False
|
should_use_now = False
|
||||||
|
|
||||||
for completer in self._non_filename_completers:
|
for completer in self._non_filename_completers:
|
||||||
should_use_this_completer = completer.ShouldUseNow( start_column,
|
should_use_this_completer = completer.ShouldUseNow( request_data )
|
||||||
current_line )
|
|
||||||
should_use_now = should_use_now or should_use_this_completer
|
should_use_now = should_use_now or should_use_this_completer
|
||||||
|
|
||||||
if should_use_this_completer:
|
if should_use_this_completer:
|
||||||
@ -78,9 +77,9 @@ class GeneralCompleterStore( Completer ):
|
|||||||
return should_use_now
|
return should_use_now
|
||||||
|
|
||||||
|
|
||||||
def CandidatesForQueryAsync( self, query, start_column ):
|
def CandidatesForQueryAsync( self, request_data ):
|
||||||
for completer in self._current_query_completers:
|
for completer in self._current_query_completers:
|
||||||
completer.CandidatesForQueryAsync( query, start_column )
|
completer.CandidatesForQueryAsync( request_data )
|
||||||
|
|
||||||
|
|
||||||
def AsyncCandidateRequestReady( self ):
|
def AsyncCandidateRequestReady( self ):
|
||||||
@ -96,9 +95,9 @@ class GeneralCompleterStore( Completer ):
|
|||||||
return candidates
|
return candidates
|
||||||
|
|
||||||
|
|
||||||
def OnFileReadyToParse( self ):
|
def OnFileReadyToParse( self, request_data ):
|
||||||
for completer in self._all_completers:
|
for completer in self._all_completers:
|
||||||
completer.OnFileReadyToParse()
|
completer.OnFileReadyToParse( request_data )
|
||||||
|
|
||||||
|
|
||||||
def OnBufferVisit( self ):
|
def OnBufferVisit( self ):
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
from ycm.completers.general_completer import GeneralCompleter
|
from ycm.completers.general_completer import GeneralCompleter
|
||||||
from UltiSnips import UltiSnips_Manager
|
from UltiSnips import UltiSnips_Manager
|
||||||
|
from ycm import server_responses
|
||||||
|
|
||||||
|
|
||||||
class UltiSnipsCompleter( GeneralCompleter ):
|
class UltiSnipsCompleter( GeneralCompleter ):
|
||||||
@ -33,13 +34,13 @@ class UltiSnipsCompleter( GeneralCompleter ):
|
|||||||
self._filtered_candidates = None
|
self._filtered_candidates = None
|
||||||
|
|
||||||
|
|
||||||
def ShouldUseNowInner( self, start_column, unused_current_line ):
|
def ShouldUseNowInner( self, request_data ):
|
||||||
return self.QueryLengthAboveMinThreshold( start_column )
|
return self.QueryLengthAboveMinThreshold( request_data )
|
||||||
|
|
||||||
|
|
||||||
def CandidatesForQueryAsync( self, query, unused_start_column ):
|
def CandidatesForQueryAsync( self, request_data ):
|
||||||
self._filtered_candidates = self.FilterAndSortCandidates( self._candidates,
|
self._filtered_candidates = self.FilterAndSortCandidates(
|
||||||
query )
|
self._candidates, request_data[ 'query' ] )
|
||||||
|
|
||||||
|
|
||||||
def AsyncCandidateRequestReady( self ):
|
def AsyncCandidateRequestReady( self ):
|
||||||
@ -61,8 +62,9 @@ def _GetCandidates():
|
|||||||
# UltiSnips_Manager._snips() returns a class instance where:
|
# UltiSnips_Manager._snips() returns a class instance where:
|
||||||
# class.trigger - name of snippet trigger word ( e.g. defn or testcase )
|
# class.trigger - name of snippet trigger word ( e.g. defn or testcase )
|
||||||
# class.description - description of the snippet
|
# class.description - description of the snippet
|
||||||
return [ { 'word': str( snip.trigger ),
|
return [ server_responses.BuildCompletionData(
|
||||||
'menu': str( '<snip> ' + snip.description.encode('utf-8') ) }
|
str( snip.trigger ),
|
||||||
for snip in rawsnips ]
|
str( '<snip> ' + snip.description.encode( 'utf-8' ) ) )
|
||||||
|
for snip in rawsnips ]
|
||||||
except:
|
except:
|
||||||
return []
|
return []
|
||||||
|
@ -19,9 +19,8 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
|
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import vim
|
|
||||||
from ycm.completers.threaded_completer import ThreadedCompleter
|
from ycm.completers.threaded_completer import ThreadedCompleter
|
||||||
from ycm import vimsupport
|
from ycm import server_responses
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
from os.path import join, abspath, dirname
|
from os.path import join, abspath, dirname
|
||||||
@ -33,7 +32,7 @@ sys.path.insert( 0, join( abspath( dirname( __file__ ) ), 'jedi' ) )
|
|||||||
try:
|
try:
|
||||||
import jedi
|
import jedi
|
||||||
except ImportError:
|
except ImportError:
|
||||||
vimsupport.PostVimMessage(
|
raise ImportError(
|
||||||
'Error importing jedi. Make sure the jedi submodule has been checked out. '
|
'Error importing jedi. Make sure the jedi submodule has been checked out. '
|
||||||
'In the YouCompleteMe folder, run "git submodule update --init --recursive"')
|
'In the YouCompleteMe folder, run "git submodule update --init --recursive"')
|
||||||
sys.path.pop( 0 )
|
sys.path.pop( 0 )
|
||||||
@ -54,113 +53,108 @@ class JediCompleter( ThreadedCompleter ):
|
|||||||
return [ 'python' ]
|
return [ 'python' ]
|
||||||
|
|
||||||
|
|
||||||
def _GetJediScript( self ):
|
def _GetJediScript( self, request_data ):
|
||||||
contents = '\n'.join( vim.current.buffer )
|
filename = request_data[ 'filepath' ]
|
||||||
line, column = vimsupport.CurrentLineAndColumn()
|
contents = request_data[ 'file_data' ][ filename ][ 'contents' ]
|
||||||
# Jedi expects lines to start at 1, not 0
|
# Jedi expects lines to start at 1, not 0
|
||||||
line += 1
|
line = request_data[ 'line_num' ] + 1
|
||||||
filename = vim.current.buffer.name
|
column = request_data[ 'column_num' ]
|
||||||
|
print contents
|
||||||
|
|
||||||
return jedi.Script( contents, line, column, filename )
|
return jedi.Script( contents, line, column, filename )
|
||||||
|
|
||||||
|
|
||||||
def ComputeCandidates( self, unused_query, unused_start_column ):
|
def ComputeCandidates( self, request_data ):
|
||||||
script = self._GetJediScript()
|
script = self._GetJediScript( request_data )
|
||||||
|
return [ server_responses.BuildCompletionData( completion.name,
|
||||||
return [ { 'word': str( completion.name ),
|
completion.description,
|
||||||
'menu': str( completion.description ),
|
completion.doc )
|
||||||
'info': str( completion.doc ) }
|
|
||||||
for completion in script.completions() ]
|
for completion in script.completions() ]
|
||||||
|
|
||||||
|
|
||||||
def DefinedSubcommands( self ):
|
def DefinedSubcommands( self ):
|
||||||
return [ "GoToDefinition",
|
return [ "GoToDefinition",
|
||||||
"GoToDeclaration",
|
"GoToDeclaration",
|
||||||
"GoToDefinitionElseDeclaration" ]
|
"GoToDefinitionElseDeclaration" ]
|
||||||
|
|
||||||
|
|
||||||
def OnUserCommand( self, arguments ):
|
def OnUserCommand( self, arguments, request_data ):
|
||||||
if not arguments:
|
if not arguments:
|
||||||
self.EchoUserCommandsHelpMessage()
|
raise ValueError( self.UserCommandsHelpMessage() )
|
||||||
return
|
|
||||||
|
|
||||||
command = arguments[ 0 ]
|
command = arguments[ 0 ]
|
||||||
if command == 'GoToDefinition':
|
if command == 'GoToDefinition':
|
||||||
self._GoToDefinition()
|
return self._GoToDefinition( request_data )
|
||||||
elif command == 'GoToDeclaration':
|
elif command == 'GoToDeclaration':
|
||||||
self._GoToDeclaration()
|
return self._GoToDeclaration( request_data )
|
||||||
elif command == 'GoToDefinitionElseDeclaration':
|
elif command == 'GoToDefinitionElseDeclaration':
|
||||||
self._GoToDefinitionElseDeclaration()
|
return self._GoToDefinitionElseDeclaration( request_data )
|
||||||
|
|
||||||
|
|
||||||
def _GoToDefinition( self ):
|
def _GoToDefinition( self, request_data ):
|
||||||
definitions = self._GetDefinitionsList()
|
definitions = self._GetDefinitionsList( request_data )
|
||||||
if definitions:
|
if definitions:
|
||||||
self._JumpToLocation( definitions )
|
return self._BuildGoToResponse( definitions )
|
||||||
else:
|
else:
|
||||||
vimsupport.PostVimMessage( 'Can\'t jump to definition.' )
|
raise RuntimeError( 'Can\'t jump to definition.' )
|
||||||
|
|
||||||
|
|
||||||
def _GoToDeclaration( self ):
|
def _GoToDeclaration( self, request_data ):
|
||||||
definitions = self._GetDefinitionsList( declaration = True )
|
definitions = self._GetDefinitionsList( request_data, declaration = True )
|
||||||
if definitions:
|
if definitions:
|
||||||
self._JumpToLocation( definitions )
|
return self._BuildGoToResponse( definitions )
|
||||||
else:
|
else:
|
||||||
vimsupport.PostVimMessage( 'Can\'t jump to declaration.' )
|
raise RuntimeError( 'Can\'t jump to declaration.' )
|
||||||
|
|
||||||
|
|
||||||
def _GoToDefinitionElseDeclaration( self ):
|
def _GoToDefinitionElseDeclaration( self, request_data ):
|
||||||
definitions = self._GetDefinitionsList() or \
|
definitions = self._GetDefinitionsList() or \
|
||||||
self._GetDefinitionsList( declaration = True )
|
self._GetDefinitionsList( request_data, declaration = True )
|
||||||
if definitions:
|
if definitions:
|
||||||
self._JumpToLocation( definitions )
|
return self._BuildGoToResponse( definitions )
|
||||||
else:
|
else:
|
||||||
vimsupport.PostVimMessage( 'Can\'t jump to definition or declaration.' )
|
raise RuntimeError( 'Can\'t jump to definition or declaration.' )
|
||||||
|
|
||||||
|
|
||||||
def _GetDefinitionsList( self, declaration = False ):
|
def _GetDefinitionsList( self, request_data, declaration = False ):
|
||||||
definitions = []
|
definitions = []
|
||||||
script = self._GetJediScript()
|
script = self._GetJediScript( request_data )
|
||||||
try:
|
try:
|
||||||
if declaration:
|
if declaration:
|
||||||
definitions = script.goto_definitions()
|
definitions = script.goto_definitions()
|
||||||
else:
|
else:
|
||||||
definitions = script.goto_assignments()
|
definitions = script.goto_assignments()
|
||||||
except jedi.NotFoundError:
|
except jedi.NotFoundError:
|
||||||
vimsupport.PostVimMessage(
|
raise RuntimeError(
|
||||||
"Cannot follow nothing. Put your cursor on a valid name." )
|
'Cannot follow nothing. Put your cursor on a valid name.' )
|
||||||
except Exception as e:
|
|
||||||
vimsupport.PostVimMessage(
|
|
||||||
"Caught exception, aborting. Full error: " + str( e ) )
|
|
||||||
|
|
||||||
return definitions
|
return definitions
|
||||||
|
|
||||||
|
|
||||||
def _JumpToLocation( self, definition_list ):
|
def _BuildGoToResponse( self, definition_list ):
|
||||||
if len( definition_list ) == 1:
|
if len( definition_list ) == 1:
|
||||||
definition = definition_list[ 0 ]
|
definition = definition_list[ 0 ]
|
||||||
if definition.in_builtin_module():
|
if definition.in_builtin_module():
|
||||||
if definition.is_keyword:
|
if definition.is_keyword:
|
||||||
vimsupport.PostVimMessage(
|
raise RuntimeError(
|
||||||
"Cannot get the definition of Python keywords." )
|
'Cannot get the definition of Python keywords.' )
|
||||||
else:
|
else:
|
||||||
vimsupport.PostVimMessage( "Builtin modules cannot be displayed." )
|
raise RuntimeError( 'Builtin modules cannot be displayed.' )
|
||||||
else:
|
else:
|
||||||
vimsupport.JumpToLocation( definition.module_path,
|
return server_responses.BuildGoToResponse( definition.module_path,
|
||||||
definition.line,
|
definition.line -1,
|
||||||
definition.column + 1 )
|
definition.column )
|
||||||
else:
|
else:
|
||||||
# multiple definitions
|
# multiple definitions
|
||||||
defs = []
|
defs = []
|
||||||
for definition in definition_list:
|
for definition in definition_list:
|
||||||
if definition.in_builtin_module():
|
if definition.in_builtin_module():
|
||||||
defs.append( {'text': 'Builtin ' + \
|
defs.append( server_responses.BuildDescriptionOnlyGoToResponse(
|
||||||
definition.description.encode( 'utf-8' ) } )
|
'Builting ' + definition.description ) )
|
||||||
else:
|
else:
|
||||||
defs.append( {'filename': definition.module_path.encode( 'utf-8' ),
|
defs.append(
|
||||||
'lnum': definition.line,
|
server_responses.BuildGoToResponse( definition.module_path,
|
||||||
'col': definition.column + 1,
|
definition.line -1,
|
||||||
'text': definition.description.encode( 'utf-8' ) } )
|
definition.column,
|
||||||
|
definition.description ) )
|
||||||
|
return defs
|
||||||
|
|
||||||
vim.eval( 'setqflist( %s )' % repr( defs ) )
|
|
||||||
vim.eval( 'youcompleteme#OpenGoToList()' )
|
|
||||||
|
@ -52,11 +52,10 @@ class ThreadedCompleter( Completer ):
|
|||||||
self._completion_thread.start()
|
self._completion_thread.start()
|
||||||
|
|
||||||
|
|
||||||
def CandidatesForQueryAsyncInner( self, query, start_column ):
|
def CandidatesForQueryAsyncInner( self, request_data ):
|
||||||
self._candidates = None
|
self._candidates = None
|
||||||
self._candidates_ready.clear()
|
self._candidates_ready.clear()
|
||||||
self._query = query
|
self._request_data = request_data
|
||||||
self._start_column = start_column
|
|
||||||
self._query_ready.set()
|
self._query_ready.set()
|
||||||
|
|
||||||
|
|
||||||
@ -69,7 +68,7 @@ class ThreadedCompleter( Completer ):
|
|||||||
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def ComputeCandidates( self, query, start_column ):
|
def ComputeCandidates( self, request_data ):
|
||||||
"""This function should compute the candidates to show to the user.
|
"""This function should compute the candidates to show to the user.
|
||||||
The return value should be of the same type as that for
|
The return value should be of the same type as that for
|
||||||
CandidatesFromStoredRequest()."""
|
CandidatesFromStoredRequest()."""
|
||||||
@ -80,8 +79,7 @@ class ThreadedCompleter( Completer ):
|
|||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
WaitAndClearIfSet( self._query_ready )
|
WaitAndClearIfSet( self._query_ready )
|
||||||
self._candidates = self.ComputeCandidates( self._query,
|
self._candidates = self.ComputeCandidates( self._request_data )
|
||||||
self._start_column )
|
|
||||||
except:
|
except:
|
||||||
self._query_ready.clear()
|
self._query_ready.clear()
|
||||||
self._candidates = []
|
self._candidates = []
|
||||||
|
@ -68,6 +68,7 @@ def CallExtraConfVimCloseIfExists():
|
|||||||
def _CallExtraConfMethod( function_name ):
|
def _CallExtraConfMethod( function_name ):
|
||||||
vim_current_working_directory = vim.eval( 'getcwd()' )
|
vim_current_working_directory = vim.eval( 'getcwd()' )
|
||||||
path_to_dummy = os.path.join( vim_current_working_directory, 'DUMMY_FILE' )
|
path_to_dummy = os.path.join( vim_current_working_directory, 'DUMMY_FILE' )
|
||||||
|
# The dummy file in the Vim CWD ensures we find the correct extra conf file
|
||||||
module = ModuleForSourceFile( path_to_dummy )
|
module = ModuleForSourceFile( path_to_dummy )
|
||||||
if not module or not hasattr( module, function_name ):
|
if not module or not hasattr( module, function_name ):
|
||||||
return
|
return
|
||||||
|
76
python/ycm/server_responses.py
Normal file
76
python/ycm/server_responses.py
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright (C) 2013 Strahinja Val Markovic <val@markovic.io>
|
||||||
|
#
|
||||||
|
# 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/>.
|
||||||
|
|
||||||
|
|
||||||
|
def BuildGoToResponse( filepath, line_num, column_num, description = None ):
|
||||||
|
response = {
|
||||||
|
'filepath': filepath,
|
||||||
|
'line_num': line_num,
|
||||||
|
'column_num': column_num
|
||||||
|
}
|
||||||
|
|
||||||
|
if description:
|
||||||
|
response[ 'description' ] = description
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
def BuildDescriptionOnlyGoToResponse( text ):
|
||||||
|
return {
|
||||||
|
'description': text,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def BuildDisplayMessageResponse( text ):
|
||||||
|
return {
|
||||||
|
'message': text
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def BuildCompletionData( insertion_text,
|
||||||
|
extra_menu_info = None,
|
||||||
|
detailed_info = None,
|
||||||
|
menu_text = None,
|
||||||
|
kind = None ):
|
||||||
|
completion_data = {
|
||||||
|
'insertion_text': insertion_text
|
||||||
|
}
|
||||||
|
|
||||||
|
if extra_menu_info:
|
||||||
|
completion_data[ 'extra_menu_info' ] = extra_menu_info
|
||||||
|
if menu_text:
|
||||||
|
completion_data[ 'menu_text' ] = menu_text
|
||||||
|
if detailed_info:
|
||||||
|
completion_data[ 'detailed_info' ] = detailed_info
|
||||||
|
if kind:
|
||||||
|
completion_data[ 'kind' ] = kind
|
||||||
|
return completion_data
|
||||||
|
|
||||||
|
|
||||||
|
def BuildDiagnosticData( filepath,
|
||||||
|
line_num,
|
||||||
|
column_num,
|
||||||
|
text,
|
||||||
|
kind ):
|
||||||
|
return {
|
||||||
|
'filepath': filepath,
|
||||||
|
'line_num': line_num,
|
||||||
|
'column_num': column_num,
|
||||||
|
'text': text,
|
||||||
|
'kind': kind
|
||||||
|
}
|
@ -46,12 +46,33 @@ def TextAfterCursor():
|
|||||||
return vim.current.line[ CurrentColumn(): ]
|
return vim.current.line[ CurrentColumn(): ]
|
||||||
|
|
||||||
|
|
||||||
def GetUnsavedBuffers():
|
# Note the difference between buffer OPTIONS and VARIABLES; the two are not
|
||||||
def BufferModified( buffer_number ):
|
# the same.
|
||||||
to_eval = 'getbufvar({0}, "&mod")'.format( buffer_number )
|
def GetBufferOption( buffer_object, option ):
|
||||||
return GetBoolValue( to_eval )
|
# The 'options' property is only available in recent (7.4+) Vim builds
|
||||||
|
if hasattr( buffer_object, 'options' ):
|
||||||
|
return buffer_object.options[ option ]
|
||||||
|
|
||||||
return ( x for x in vim.buffers if BufferModified( x.number ) )
|
to_eval = 'getbufvar({0}, "&{1}")'.format( buffer.number, option )
|
||||||
|
return GetVariableValue( to_eval )
|
||||||
|
|
||||||
|
|
||||||
|
def GetUnsavedAndCurrentBufferData():
|
||||||
|
def BufferModified( buffer_object ):
|
||||||
|
return bool( int( GetBufferOption( buffer_object, 'mod' ) ) )
|
||||||
|
|
||||||
|
buffers_data = {}
|
||||||
|
for buffer_object in vim.buffers:
|
||||||
|
if not ( BufferModified( buffer_object ) or
|
||||||
|
buffer_object == vim.current.buffer ):
|
||||||
|
continue
|
||||||
|
|
||||||
|
buffers_data[ buffer_object.name ] = {
|
||||||
|
'contents': '\n'.join( buffer_object ),
|
||||||
|
'filetypes': FiletypesForBuffer( buffer_object )
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffers_data
|
||||||
|
|
||||||
|
|
||||||
# Both |line| and |column| need to be 1-based
|
# Both |line| and |column| need to be 1-based
|
||||||
@ -73,9 +94,9 @@ def JumpToLocation( filename, line, column ):
|
|||||||
vim.command( 'normal! zz' )
|
vim.command( 'normal! zz' )
|
||||||
|
|
||||||
|
|
||||||
def NumLinesInBuffer( buffer ):
|
def NumLinesInBuffer( buffer_object ):
|
||||||
# This is actually less than obvious, that's why it's wrapped in a function
|
# This is actually less than obvious, that's why it's wrapped in a function
|
||||||
return len( buffer )
|
return len( buffer_object )
|
||||||
|
|
||||||
|
|
||||||
def PostVimMessage( message ):
|
def PostVimMessage( message ):
|
||||||
@ -128,15 +149,13 @@ def EscapeForVim( text ):
|
|||||||
|
|
||||||
|
|
||||||
def CurrentFiletypes():
|
def CurrentFiletypes():
|
||||||
ft_string = vim.eval( "&filetype" )
|
return vim.eval( "&filetype" ).split( '.' )
|
||||||
return ft_string.split( '.' )
|
|
||||||
|
|
||||||
|
|
||||||
def FiletypesForBuffer( buffer_object ):
|
def FiletypesForBuffer( buffer_object ):
|
||||||
# NOTE: Getting &ft for other buffers only works when the buffer has been
|
# NOTE: Getting &ft for other buffers only works when the buffer has been
|
||||||
# visited by the user at least once, which is true for modified buffers
|
# visited by the user at least once, which is true for modified buffers
|
||||||
ft_string = vim.eval( 'getbufvar({0}, "&ft")'.format( buffer_object.number ) )
|
return GetBufferOption( buffer_object, 'ft' ).split( '.' )
|
||||||
return ft_string.split( '.' )
|
|
||||||
|
|
||||||
|
|
||||||
def GetVariableValue( variable ):
|
def GetVariableValue( variable ):
|
||||||
|
@ -19,20 +19,25 @@
|
|||||||
|
|
||||||
import imp
|
import imp
|
||||||
import os
|
import os
|
||||||
|
import time
|
||||||
import vim
|
import vim
|
||||||
import ycm_core
|
import ycm_core
|
||||||
|
import logging
|
||||||
|
import tempfile
|
||||||
from ycm import vimsupport
|
from ycm import vimsupport
|
||||||
from ycm import base
|
from ycm import base
|
||||||
from ycm.completers.all.omni_completer import OmniCompleter
|
from ycm.completers.all.omni_completer import OmniCompleter
|
||||||
from ycm.completers.general.general_completer_store import GeneralCompleterStore
|
from ycm.completers.general.general_completer_store import GeneralCompleterStore
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: Put the Request classes in separate files
|
||||||
class CompletionRequest( object ):
|
class CompletionRequest( object ):
|
||||||
def __init__( self, ycm_state ):
|
def __init__( self, ycm_state ):
|
||||||
self._completion_start_column = base.CompletionStartColumn()
|
self._completion_start_column = base.CompletionStartColumn()
|
||||||
self._ycm_state = ycm_state
|
self._ycm_state = ycm_state
|
||||||
|
self._request_data = _BuildRequestData( self._completion_start_column )
|
||||||
self._do_filetype_completion = self._ycm_state.ShouldUseFiletypeCompleter(
|
self._do_filetype_completion = self._ycm_state.ShouldUseFiletypeCompleter(
|
||||||
self._completion_start_column )
|
self._request_data )
|
||||||
self._completer = ( self._ycm_state.GetFiletypeCompleter() if
|
self._completer = ( self._ycm_state.GetFiletypeCompleter() if
|
||||||
self._do_filetype_completion else
|
self._do_filetype_completion else
|
||||||
self._ycm_state.GetGeneralCompleter() )
|
self._ycm_state.GetGeneralCompleter() )
|
||||||
@ -40,8 +45,7 @@ class CompletionRequest( object ):
|
|||||||
|
|
||||||
def ShouldComplete( self ):
|
def ShouldComplete( self ):
|
||||||
return ( self._do_filetype_completion or
|
return ( self._do_filetype_completion or
|
||||||
self._ycm_state.ShouldUseGeneralCompleter(
|
self._ycm_state.ShouldUseGeneralCompleter( self._request_data ) )
|
||||||
self._completion_start_column ) )
|
|
||||||
|
|
||||||
|
|
||||||
def CompletionStartColumn( self ):
|
def CompletionStartColumn( self ):
|
||||||
@ -49,20 +53,80 @@ class CompletionRequest( object ):
|
|||||||
|
|
||||||
|
|
||||||
def Start( self, query ):
|
def Start( self, query ):
|
||||||
self._completer.CandidatesForQueryAsync( query,
|
self._request_data[ 'query' ] = query
|
||||||
self._completion_start_column )
|
self._completer.CandidatesForQueryAsync( self._request_data )
|
||||||
|
|
||||||
def Done( self ):
|
def Done( self ):
|
||||||
return self._completer.AsyncCandidateRequestReady()
|
return self._completer.AsyncCandidateRequestReady()
|
||||||
|
|
||||||
|
|
||||||
def Results( self ):
|
def Results( self ):
|
||||||
return self._completer.CandidatesFromStoredRequest()
|
try:
|
||||||
|
return [ _ConvertCompletionDataToVimData( x )
|
||||||
|
for x in self._completer.CandidatesFromStoredRequest() ]
|
||||||
|
except Exception as e:
|
||||||
|
vimsupport.PostVimMessage( str( e ) )
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class CommandRequest( object ):
|
||||||
|
class ServerResponse( object ):
|
||||||
|
def __init__( self ):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def Valid( self ):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __init__( self, ycm_state, arguments, completer_target = None ):
|
||||||
|
if not completer_target:
|
||||||
|
completer_target = 'filetpe_default'
|
||||||
|
|
||||||
|
if completer_target == 'omni':
|
||||||
|
self._completer = ycm_state.GetOmniCompleter()
|
||||||
|
elif completer_target == 'identifier':
|
||||||
|
self._completer = ycm_state.GetGeneralCompleter()
|
||||||
|
else:
|
||||||
|
self._completer = ycm_state.GetFiletypeCompleter()
|
||||||
|
self._arguments = arguments
|
||||||
|
|
||||||
|
|
||||||
|
def Start( self ):
|
||||||
|
self._completer.OnUserCommand( self._arguments,
|
||||||
|
_BuildRequestData() )
|
||||||
|
|
||||||
|
def Done( self ):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def Response( self ):
|
||||||
|
# TODO: Call vimsupport.JumpToLocation if the user called a GoTo command...
|
||||||
|
# we may want to have specific subclasses of CommandRequest so that a
|
||||||
|
# GoToRequest knows it needs to jump after the data comes back.
|
||||||
|
#
|
||||||
|
# Also need to run the following on GoTo data:
|
||||||
|
# CAREFUL about line/column number 0-based/1-based confusion!
|
||||||
|
#
|
||||||
|
# defs = []
|
||||||
|
# defs.append( {'filename': definition.module_path.encode( 'utf-8' ),
|
||||||
|
# 'lnum': definition.line,
|
||||||
|
# 'col': definition.column + 1,
|
||||||
|
# 'text': definition.description.encode( 'utf-8' ) } )
|
||||||
|
# vim.eval( 'setqflist( %s )' % repr( defs ) )
|
||||||
|
# vim.eval( 'youcompleteme#OpenGoToList()' )
|
||||||
|
return self.ServerResponse()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class YouCompleteMe( object ):
|
class YouCompleteMe( object ):
|
||||||
def __init__( self, user_options ):
|
def __init__( self, user_options ):
|
||||||
|
# TODO: This should go into the server
|
||||||
|
# TODO: Use more logging like we do in cs_completer
|
||||||
|
self._logfile = tempfile.NamedTemporaryFile()
|
||||||
|
logging.basicConfig( format='%(asctime)s - %(levelname)s - %(message)s',
|
||||||
|
filename=self._logfile.name,
|
||||||
|
level=logging.DEBUG )
|
||||||
|
|
||||||
self._user_options = user_options
|
self._user_options = user_options
|
||||||
self._gencomp = GeneralCompleterStore( user_options )
|
self._gencomp = GeneralCompleterStore( user_options )
|
||||||
self._omnicomp = OmniCompleter( user_options )
|
self._omnicomp = OmniCompleter( user_options )
|
||||||
@ -78,6 +142,16 @@ class YouCompleteMe( object ):
|
|||||||
return self._current_completion_request
|
return self._current_completion_request
|
||||||
|
|
||||||
|
|
||||||
|
def SendCommandRequest( self, arguments, completer ):
|
||||||
|
# TODO: This should be inside a method in a command_request module
|
||||||
|
request = CommandRequest( self, arguments, completer )
|
||||||
|
request.Start()
|
||||||
|
while not request.Done():
|
||||||
|
time.sleep( 0.1 )
|
||||||
|
|
||||||
|
return request.Response()
|
||||||
|
|
||||||
|
|
||||||
def GetCurrentCompletionRequest( self ):
|
def GetCurrentCompletionRequest( self ):
|
||||||
return self._current_completion_request
|
return self._current_completion_request
|
||||||
|
|
||||||
@ -131,14 +205,13 @@ class YouCompleteMe( object ):
|
|||||||
return completer
|
return completer
|
||||||
|
|
||||||
|
|
||||||
def ShouldUseGeneralCompleter( self, start_column ):
|
def ShouldUseGeneralCompleter( self, request_data ):
|
||||||
return self._gencomp.ShouldUseNow( start_column, vim.current.line )
|
return self._gencomp.ShouldUseNow( request_data )
|
||||||
|
|
||||||
|
|
||||||
def ShouldUseFiletypeCompleter( self, start_column ):
|
def ShouldUseFiletypeCompleter( self, request_data ):
|
||||||
if self.FiletypeCompletionUsable():
|
if self.FiletypeCompletionUsable():
|
||||||
return self.GetFiletypeCompleter().ShouldUseNow(
|
return self.GetFiletypeCompleter().ShouldUseNow( request_data )
|
||||||
start_column, vim.current.line )
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@ -162,10 +235,10 @@ class YouCompleteMe( object ):
|
|||||||
|
|
||||||
|
|
||||||
def OnFileReadyToParse( self ):
|
def OnFileReadyToParse( self ):
|
||||||
self._gencomp.OnFileReadyToParse()
|
self._gencomp.OnFileReadyToParse( _BuildRequestData() )
|
||||||
|
|
||||||
if self.FiletypeCompletionUsable():
|
if self.FiletypeCompletionUsable():
|
||||||
self.GetFiletypeCompleter().OnFileReadyToParse()
|
self.GetFiletypeCompleter().OnFileReadyToParse( _BuildRequestData() )
|
||||||
|
|
||||||
|
|
||||||
def OnBufferUnload( self, deleted_buffer_file ):
|
def OnBufferUnload( self, deleted_buffer_file ):
|
||||||
@ -208,9 +281,9 @@ class YouCompleteMe( object ):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def ShowDetailedDiagnostic( self ):
|
def GetDetailedDiagnostic( self ):
|
||||||
if self.FiletypeCompletionUsable():
|
if self.FiletypeCompletionUsable():
|
||||||
return self.GetFiletypeCompleter().ShowDetailedDiagnostic()
|
return self.GetFiletypeCompleter().GetDetailedDiagnostic()
|
||||||
|
|
||||||
|
|
||||||
def GettingCompletions( self ):
|
def GettingCompletions( self ):
|
||||||
@ -263,3 +336,37 @@ def _PathToFiletypeCompleterPluginLoader( filetype ):
|
|||||||
return os.path.join( _PathToCompletersFolder(), filetype, 'hook.py' )
|
return os.path.join( _PathToCompletersFolder(), filetype, 'hook.py' )
|
||||||
|
|
||||||
|
|
||||||
|
def _BuildRequestData( start_column = None, query = None ):
|
||||||
|
line, column = vimsupport.CurrentLineAndColumn()
|
||||||
|
request_data = {
|
||||||
|
'filetypes': vimsupport.CurrentFiletypes(),
|
||||||
|
'line_num': line,
|
||||||
|
'column_num': column,
|
||||||
|
'start_column': start_column,
|
||||||
|
'line_value': vim.current.line,
|
||||||
|
'filepath': vim.current.buffer.name,
|
||||||
|
'file_data': vimsupport.GetUnsavedAndCurrentBufferData()
|
||||||
|
}
|
||||||
|
|
||||||
|
if query:
|
||||||
|
request_data[ 'query' ] = query
|
||||||
|
|
||||||
|
return request_data
|
||||||
|
|
||||||
|
def _ConvertCompletionDataToVimData( completion_data ):
|
||||||
|
# see :h complete-items for a description of the dictionary fields
|
||||||
|
vim_data = {
|
||||||
|
'word' : completion_data[ 'insertion_text' ],
|
||||||
|
'dup' : 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
if 'menu_text' in completion_data:
|
||||||
|
vim_data[ 'abbr' ] = completion_data[ 'menu_text' ]
|
||||||
|
if 'extra_menu_info' in completion_data:
|
||||||
|
vim_data[ 'menu' ] = completion_data[ 'extra_menu_info' ]
|
||||||
|
if 'kind' in completion_data:
|
||||||
|
vim_data[ 'kind' ] = completion_data[ 'kind' ]
|
||||||
|
if 'detailed_info' in completion_data:
|
||||||
|
vim_data[ 'info' ] = completion_data[ 'detailed_info' ]
|
||||||
|
|
||||||
|
return vim_data
|
||||||
|
Loading…
Reference in New Issue
Block a user