diff --git a/cpp/ycm/Result.cpp b/cpp/ycm/Result.cpp index eb7347a4..26b18812 100644 --- a/cpp/ycm/Result.cpp +++ b/cpp/ycm/Result.cpp @@ -19,6 +19,7 @@ #include "standard.h" #include "Utils.h" #include +#include #include using boost::algorithm::istarts_with; @@ -27,6 +28,31 @@ namespace YouCompleteMe { namespace { +char ChangeCharCase( char c ) { + if ( std::isupper( c ) ) + return std::tolower( c ); + return std::toupper( c ); +} + + +bool CharLessThanWithLowercasePriority(const char &first, + const char &second) { + char swap_first = ChangeCharCase( first ); + char swap_second = ChangeCharCase( second ); + return swap_first < swap_second; +} + + +bool StringLessThanWithLowercasePriority(const std::string &first, + const std::string &second) { + return std::lexicographical_compare( + first.begin(), first.end(), + second.begin(), second.end(), + boost::function< bool( const char&, const char& ) >( + &CharLessThanWithLowercasePriority ) ); +} + + int LongestCommonSubsequenceLength( const std::string &first, const std::string &second ) { const std::string &longer = first.size() > second.size() ? first : second; @@ -168,8 +194,9 @@ bool Result::operator< ( const Result &other ) const { return text_is_lowercase_; } - // Lexicographic comparison - return *text_ < *other.text_; + // Lexicographic comparison, but we prioritize lowercase letters over + // uppercase ones. So "foo" < "Foo". + return StringLessThanWithLowercasePriority( *text_, *other.text_ ); } diff --git a/cpp/ycm/tests/IdentifierCompleter_test.cpp b/cpp/ycm/tests/IdentifierCompleter_test.cpp index d3c4d0dc..7b17c1ab 100644 --- a/cpp/ycm/tests/IdentifierCompleter_test.cpp +++ b/cpp/ycm/tests/IdentifierCompleter_test.cpp @@ -206,6 +206,24 @@ TEST( IdentifierCompleterTest, SameLowercaseCandidateWins ) { "Foobar" ) ).CandidatesForQuery( "foo" ), ElementsAre( "foobar", "Foobar" ) ); + +} + +TEST( IdentifierCompleterTest, PreferLowercaseCandidate ) { + EXPECT_THAT( IdentifierCompleter( + StringVector( + "chatContentExtension", + "ChatContentExtension" ) ).CandidatesForQuery( + "chatContent" ), + ElementsAre( "chatContentExtension", + "ChatContentExtension" ) ); + + EXPECT_THAT( IdentifierCompleter( + StringVector( + "fooBar", + "FooBar" ) ).CandidatesForQuery( "oba" ), + ElementsAre( "fooBar", + "FooBar" ) ); } TEST( IdentifierCompleterTest, ShorterAndLowercaseWins ) {