From 7bf18c7c5c6afcb23fea4d61cfd7733c38669f67 Mon Sep 17 00:00:00 2001 From: Strahinja Val Markovic Date: Sat, 21 Jul 2012 12:06:18 -0700 Subject: [PATCH] Improving IdentifierCompleter performance We limit the number of candidates returned to Vim to 20 and also make sure that we are not returning any duplicate candidates. This provides a noticeable improvement in latency. --- cpp/ycm/CandidateRepository.cpp | 7 +++++++ cpp/ycm/CandidateRepository.h | 2 ++ cpp/ycm/ClangCompleter.cpp | 2 ++ cpp/ycm/IdentifierCompleter.cpp | 9 +++++++++ cpp/ycm/tests/IdentifierCompleter_test.cpp | 9 +++++++++ python/ycm.py | 15 +++++++++++---- 6 files changed, 40 insertions(+), 4 deletions(-) diff --git a/cpp/ycm/CandidateRepository.cpp b/cpp/ycm/CandidateRepository.cpp index b1689a9b..4f629b9a 100644 --- a/cpp/ycm/CandidateRepository.cpp +++ b/cpp/ycm/CandidateRepository.cpp @@ -43,6 +43,13 @@ CandidateRepository& CandidateRepository::Instance() } +int CandidateRepository::NumStoredCandidates() +{ + boost::lock_guard< boost::mutex > locker( holder_mutex_ ); + return candidate_holder_.size(); +} + + std::vector< const Candidate* > CandidateRepository::GetCandidatesForStrings( const std::vector< std::string > &strings ) { diff --git a/cpp/ycm/CandidateRepository.h b/cpp/ycm/CandidateRepository.h index 8b108b59..b1ac8e9f 100644 --- a/cpp/ycm/CandidateRepository.h +++ b/cpp/ycm/CandidateRepository.h @@ -39,6 +39,8 @@ class CandidateRepository : boost::noncopyable public: static CandidateRepository& Instance(); + int NumStoredCandidates(); + std::vector< const Candidate* > GetCandidatesForStrings( const std::vector< std::string > &strings ); diff --git a/cpp/ycm/ClangCompleter.cpp b/cpp/ycm/ClangCompleter.cpp index b7e11d3a..95cf644b 100644 --- a/cpp/ycm/ClangCompleter.cpp +++ b/cpp/ycm/ClangCompleter.cpp @@ -128,6 +128,8 @@ bool IsChunkKindForExtraMenuInfo( CXCompletionChunkKind kind ) char CursorKindToVimKind( CXCursorKind kind ) { + // TODO: actually it appears that Vim will show returned kinds even when they + // do not match the "approved" list, so let's use that switch ( kind ) { case CXCursor_UnexposedDecl: diff --git a/cpp/ycm/IdentifierCompleter.cpp b/cpp/ycm/IdentifierCompleter.cpp index 7939cfa4..f7790158 100644 --- a/cpp/ycm/IdentifierCompleter.cpp +++ b/cpp/ycm/IdentifierCompleter.cpp @@ -21,6 +21,7 @@ #include "Candidate.h" #include "Utils.h" +#include #include #include #include @@ -173,11 +174,19 @@ void IdentifierCompleter::ResultsForQueryAndType( Bitset query_bitset = LetterBitsetFromString( query ); + boost::unordered_set< const Candidate* > seen_candidates; + seen_candidates.reserve( candidate_repository_.NumStoredCandidates() ); + foreach ( const FilepathToCandidates::value_type &path_and_candidates, *it->second ) { foreach ( const Candidate* candidate, *path_and_candidates.second ) { + if ( ContainsKey( seen_candidates, candidate ) ) + continue; + else + seen_candidates.insert( candidate ); + if ( !candidate->MatchesQueryBitset( query_bitset ) ) continue; diff --git a/cpp/ycm/tests/IdentifierCompleter_test.cpp b/cpp/ycm/tests/IdentifierCompleter_test.cpp index 37371ee6..b972673a 100644 --- a/cpp/ycm/tests/IdentifierCompleter_test.cpp +++ b/cpp/ycm/tests/IdentifierCompleter_test.cpp @@ -73,6 +73,15 @@ TEST( IdentifierCompleterTest, EmptyQueryNoResults ) ElementsAre() ); } +TEST( IdentifierCompleterTest, NoDuplicatesReturned ) +{ + EXPECT_THAT( IdentifierCompleter( Candidates( + "foobar", + "foobar", + "foobar" ) ).CandidatesForQuery( "foo" ), + ElementsAre( "foobar" ) ); +} + TEST( IdentifierCompleterTest, OneCandidate ) { diff --git a/python/ycm.py b/python/ycm.py index cb0db427..175ad666 100644 --- a/python/ycm.py +++ b/python/ycm.py @@ -21,8 +21,10 @@ import re import vim import indexer -min_num_chars = int( vim.eval( "g:ycm_min_num_of_chars_for_completion" ) ) -clang_filetypes = set( [ 'c', 'cpp', 'objc', 'objcpp' ] ) +MIN_NUM_CHARS = int( vim.eval( "g:ycm_min_num_of_chars_for_completion" ) ) +CLANG_FILETYPES = set( [ 'c', 'cpp', 'objc', 'objcpp' ] ) +MAX_IDENTIFIER_COMPLETIONS_RETURNED = 20 + class Completer( object ): def __init__( self ): @@ -89,6 +91,11 @@ class IdentifierCompleter( Completer ): filepath, True ) + def CandidatesFromStoredRequest( self ): + if not self.future: + return [] + return self.future.GetResults()[ : MAX_IDENTIFIER_COMPLETIONS_RETURNED ] + class ClangCompleter( Completer ): def __init__( self ): @@ -181,7 +188,7 @@ def CurrentLineAndColumn(): def ShouldUseClang( start_column ): filetype = vim.eval( "&filetype" ) - if filetype not in clang_filetypes: + if filetype not in CLANG_FILETYPES: return False line = vim.current.line @@ -253,7 +260,7 @@ def PreviousIdentifier(): while start_column > 0 and IsIdentifierChar( line[ start_column - 1 ] ): start_column -= 1 - if end_column - start_column < min_num_chars: + if end_column - start_column < MIN_NUM_CHARS: return "" return line[ start_column : end_column ]