diff --git a/cpp/ycm/Result.cpp b/cpp/ycm/Result.cpp index 891f2084..8a83d1f2 100644 --- a/cpp/ycm/Result.cpp +++ b/cpp/ycm/Result.cpp @@ -19,6 +19,7 @@ #include "standard.h" #include "Utils.h" #include +#include using boost::algorithm::istarts_with; @@ -28,19 +29,42 @@ namespace YouCompleteMe namespace { +template< class T > +int LongestCommonSubsequenceLength(const T &first, const T &second) +{ + const T &longer = first.size() > second.size() ? first : second; + const T &shorter = first.size() > second.size() ? second : first; + + int longer_len = longer.size(); + int shorter_len = shorter.size(); + + std::vector previous( shorter_len + 1, 0 ); + std::vector current( shorter_len + 1, 0 ); + + for (int i = 0; i < longer_len; ++i ) + { + for (int j = 0; j < shorter_len; ++j ) + { + if ( longer[ i ] == shorter[ j ] ) + current[ j + 1 ] = previous[ j ] + 1; + else + current[ j + 1 ] = std::max( current[ j ], previous[ j + 1 ] ); + } + + for (int j = 0; j < shorter_len; ++j ) + { + previous[ j + 1 ] = current[ j + 1 ]; + } + } + + return current[ shorter_len ]; +} + + int NumWordBoundaryCharMatches( const std::string &query, const std::string &word_boundary_chars ) { - uint i = 0; - uint j = 0; - while ( j < query.size() && i < word_boundary_chars.size() ) - { - if ( toupper( query[ j ] ) == toupper( word_boundary_chars[ i ] ) ) - ++j; - ++i; - } - - return j; + return LongestCommonSubsequenceLength(query, word_boundary_chars); } } // unnamed namespace diff --git a/cpp/ycm/tests/Completer_test.cpp b/cpp/ycm/tests/Completer_test.cpp index ac9f1c7f..b33d2053 100644 --- a/cpp/ycm/tests/Completer_test.cpp +++ b/cpp/ycm/tests/Completer_test.cpp @@ -128,6 +128,12 @@ TEST( CompleterTest, RatioUtilizationTieBreak ) ElementsAre( "aFooBarQux", "afbq" ) ); + EXPECT_THAT( Completer( Candidates( + "acaaCaaFooGxx", + "aCaafoog" ) ).CandidatesForQuery( "caafoo" ), + ElementsAre( "acaaCaaFooGxx", + "aCaafoog" ) ); + EXPECT_THAT( Completer( Candidates( "FooBarQux", "FooBarQuxZaa" ) ).CandidatesForQuery( "fbq" ),