diff --git a/cpp/ycm/ClangUtils.cpp b/cpp/ycm/ClangUtils.cpp index 6175b443..8b148373 100644 --- a/cpp/ycm/ClangUtils.cpp +++ b/cpp/ycm/ClangUtils.cpp @@ -74,7 +74,7 @@ bool CompletionStringAvailable( CXCompletionString completion_string ) } -bool IsChunkKindForExtraMenuInfo( CXCompletionChunkKind kind ) +bool IsMainCompletionTextInfo( CXCompletionChunkKind kind ) { return kind == CXCompletionChunk_Optional || @@ -89,7 +89,6 @@ bool IsChunkKindForExtraMenuInfo( CXCompletionChunkKind kind ) kind == CXCompletionChunk_RightAngle || kind == CXCompletionChunk_LeftAngle || kind == CXCompletionChunk_Comma || - kind == CXCompletionChunk_ResultType || kind == CXCompletionChunk_Colon || kind == CXCompletionChunk_SemiColon || kind == CXCompletionChunk_Equal || @@ -161,20 +160,41 @@ CompletionData CompletionResultToCompletionData( CXCompletionString completion_string = completion_result.CompletionString; uint num_chunks = clang_getNumCompletionChunks( completion_string ); + bool saw_left_paren = false; + bool saw_function_params = false; + for ( uint j = 0; j < num_chunks; ++j ) { CXCompletionChunkKind kind = clang_getCompletionChunkKind( completion_string, j ); - if ( IsChunkKindForExtraMenuInfo( kind ) ) + if ( IsMainCompletionTextInfo( kind ) ) { - data.extra_menu_info_.append( ChunkToString( completion_string, j ) ); + if ( kind == CXCompletionChunk_LeftParen ) + { + saw_left_paren = true; + } - // by default, there's no space after the return type - if ( kind == CXCompletionChunk_ResultType ) - data.extra_menu_info_.append( " " ); + else if ( saw_left_paren && + !saw_function_params && + kind != CXCompletionChunk_RightParen ) + { + saw_function_params = true; + data.everything_except_return_type_.append( " " ); + } + + else if ( saw_function_params && kind == CXCompletionChunk_RightParen ) + { + data.everything_except_return_type_.append( " " ); + } + + data.everything_except_return_type_.append( + ChunkToString( completion_string, j ) ); } + if ( kind == CXCompletionChunk_ResultType ) + data.return_type_ = ChunkToString( completion_string, j ); + if ( kind == CXCompletionChunk_TypedText ) data.original_string_ = ChunkToString( completion_string, j ); @@ -214,9 +234,14 @@ std::vector< CompletionData > ToCompletionDataVector( else { + // If we have already seen this completion, then this is an overload of a + // function we have seen. We add the signature of the overload to the + // detailed information. completions[ index ].detailed_info_ .append( "\n" ) - .append( data.extra_menu_info_ ); + .append( data.return_type_ ) + .append( " " ) + .append( data.everything_except_return_type_ ); } } diff --git a/cpp/ycm/CompletionData.h b/cpp/ycm/CompletionData.h index 41b54f84..7aa572d9 100644 --- a/cpp/ycm/CompletionData.h +++ b/cpp/ycm/CompletionData.h @@ -23,30 +23,67 @@ namespace YouCompleteMe { +// This class holds pieces of information about a single completion coming from +// clang. These pieces are shown in Vim's UI in different ways. +// +// Normally, the completion menu looks like this (without square brackets): +// +// [main completion text] [kind] [extra menu info] +// [main completion text] [kind] [extra menu info] +// [main completion text] [kind] [extra menu info] +// ... (etc.) ... +// +// The user can also enable a "preview" window that will show extra information +// about a completion at the top of the buffer. struct CompletionData { - // What should actually be inserted into the buffer. + // What should actually be inserted into the buffer. For a function like + // "int foo(int x)", this is just "foo". Same for a data member like "foo_": + // we insert just "foo_". std::string TextToInsertInBuffer() { return original_string_; } + // Currently, here we show the full function signature (without the return + // type) if the current completion is a function or just the raw TypedText if + // the completion is, say, a data member. So for a function like "int foo(int + // x)", this would be "foo(int x)". For a data member like "count_", it would + // be just "count_". + std::string MainCompletionText() + { + return everything_except_return_type_; + } + + // This is extra info shown in the pop-up completion menu, after the + // completion text and the kind. Currently we put the return type of the + // function here, if any. + std::string ExtraMenuInfo() + { + return return_type_; + } + + // This is used to show extra information in vim's preview window. This is the + // window that vim usually shows at the top of the buffer. This should be used + // for extra information about the completion. + std::string DetailedInfoForPreviewWindow() + { + return detailed_info_; + } bool operator== ( const CompletionData &other ) const { return kind_ == other.kind_ && - original_string_ == other.original_string_ && - extra_menu_info_ == other.extra_menu_info_; + everything_except_return_type_ == other.everything_except_return_type_ && + return_type_ == other.return_type_ && + original_string_ == other.original_string_; // detailed_info_ doesn't matter } - // This is used to show extra information in vim's preview window std::string detailed_info_; - // This is extra info shown in the pop-up completion menu, after the - // completion text and the kind - std::string extra_menu_info_; + std::string return_type_; // Vim's completion string "kind" // 'v' -> variable @@ -57,9 +94,12 @@ struct CompletionData char kind_; // The original, raw completion string. For a function like "int foo(int x)", - // the original string is "foo". This corresponds to clang's TypedText chunk - // of the completion string. + // the original string is "foo". For a member data variable like "foo_", this + // is just "foo_". This corresponds to clang's TypedText chunk of the + // completion string. std::string original_string_; + + std::string everything_except_return_type_; }; } // namespace YouCompleteMe diff --git a/cpp/ycm/indexer.cpp b/cpp/ycm/indexer.cpp index ffd826c6..563f7bb9 100644 --- a/cpp/ycm/indexer.cpp +++ b/cpp/ycm/indexer.cpp @@ -38,10 +38,11 @@ BOOST_PYTHON_MODULE(indexer) class_< CompletionData >( "CompletionData" ) .def( "TextToInsertInBuffer", &CompletionData::TextToInsertInBuffer ) - .def_readonly( "detailed_info_", &CompletionData::detailed_info_ ) - .def_readonly( "extra_menu_info_", &CompletionData::extra_menu_info_ ) - .def_readonly( "kind_", &CompletionData::kind_ ) - .def_readonly( "original_string_", &CompletionData::original_string_ ); + .def( "MainCompletionText", &CompletionData::MainCompletionText ) + .def( "ExtraMenuInfo", &CompletionData::ExtraMenuInfo ) + .def( "DetailedInfoForPreviewWindow ", + &CompletionData::DetailedInfoForPreviewWindow ) + .def_readonly( "kind_", &CompletionData::kind_ ); class_< std::vector< CompletionData >, boost::shared_ptr< std::vector< CompletionData > > >( diff --git a/python/ycm.py b/python/ycm.py index 10e52084..03d011f5 100644 --- a/python/ycm.py +++ b/python/ycm.py @@ -342,8 +342,8 @@ def CompletionDataToDict( completion_data ): # see :h complete-items for a description of the dictionary fields return { 'word' : completion_data.TextToInsertInBuffer(), - 'abbr' : completion_data.original_string_, - 'menu' : completion_data.extra_menu_info_, + 'abbr' : completion_data.MainCompletionText(), + 'menu' : completion_data.ExtraMenuInfo(), 'kind' : completion_data.kind_, 'dup' : 1, # TODO: add detailed_info_ as 'info'