Candidates are now stored per type and filepath

This commit is contained in:
Strahinja Val Markovic 2012-04-29 19:51:20 -07:00
parent ced1d0ad5a
commit 903452e855
6 changed files with 138 additions and 59 deletions

View File

@ -19,18 +19,24 @@
#include "Completer.h" #include "Completer.h"
#include "Utils.h" #include "Utils.h"
using boost::python::len;
using boost::python::extract;
namespace YouCompleteMe namespace YouCompleteMe
{ {
Completer::Completer( const Pylist &candidates ) Completer::Completer( const Pylist &candidates )
{ {
AddCandidatesToDatabase( candidates, "" ); AddCandidatesToDatabase( candidates, "", "" );
} }
Completer::Completer( const Pylist &candidates, const std::string &filepath) Completer::Completer( const Pylist &candidates,
const std::string &filetype,
const std::string &filepath)
{ {
AddCandidatesToDatabase( candidates, filepath ); AddCandidatesToDatabase( candidates, filetype, filepath );
} }
@ -44,43 +50,64 @@ Completer::~Completer()
} }
void Completer::AddCandidatesToDatabase( const Pylist &candidates, void Completer::AddCandidatesToDatabase( const Pylist &new_candidates,
const std::string &filetype,
const std::string &filepath ) const std::string &filepath )
{ {
std::vector< Candidate *> &candidates =
GetCandidateVector( filetype, filepath );
int num_candidates = len( new_candidates );
candidates.clear();
candidates.reserve( num_candidates );
std::string candidate_text; std::string candidate_text;
for (int i = 0; i < boost::python::len( candidates ); ++i) for (int i = 0; i < num_candidates; ++i)
{ {
candidate_text = boost::python::extract< std::string >( candidates[ i ] ); candidate_text = extract< std::string >( new_candidates[ i ] );
Candidate *&candidate = GetValueElseInsert( candidate_repository_, Candidate *&candidate = GetValueElseInsert( candidate_repository_,
candidate_text, NULL ); candidate_text, NULL );
if ( !candidate ) if ( !candidate )
{
candidate = new Candidate( candidate_text ); candidate = new Candidate( candidate_text );
candidates_.insert( candidate );
} candidates.push_back( candidate );
} }
} }
void Completer::GetCandidatesForQuery( void Completer::CandidatesForQuery( const std::string &query,
const std::string &query, Pylist &candidates ) const Pylist &candidates ) const
{ {
CandidatesForQueryAndType( query, "", candidates );
}
void Completer::CandidatesForQueryAndType( const std::string &query,
const std::string &filetype,
Pylist &candidates ) const
{
FiletypeMap::const_iterator it = filetype_map_.find( filetype );
if ( it == filetype_map_.end() )
return;
Bitset query_bitset = LetterBitsetFromString( query ); Bitset query_bitset = LetterBitsetFromString( query );
std::vector< Result > results; std::vector< Result > results;
foreach ( Candidate* candidate, candidates_ ) foreach ( const FilepathToCandidates::value_type &path_and_candidates,
*it->second )
{ {
if ( !candidate->MatchesQueryBitset( query_bitset ) ) foreach ( Candidate* candidate, *path_and_candidates.second )
continue; {
if ( !candidate->MatchesQueryBitset( query_bitset ) )
continue;
Result result = candidate->QueryMatchResult( query ); Result result = candidate->QueryMatchResult( query );
if ( result.IsSubsequence() ) if ( result.IsSubsequence() )
results.push_back( result ); results.push_back( result );
}
} }
// Needs to be stable to preserve the lexical sort of the candidates from the std::sort( results.begin(), results.end() );
// candidates_ container
std::stable_sort( results.begin(), results.end() );
foreach ( const Result& result, results ) foreach ( const Result& result, results )
{ {
@ -89,4 +116,24 @@ void Completer::GetCandidatesForQuery(
} }
std::vector< Candidate* >& Completer::GetCandidateVector(
const std::string &filetype,
const std::string &filepath )
{
boost::shared_ptr< FilepathToCandidates > &path_to_candidates =
filetype_map_[ filetype ];
if ( !path_to_candidates )
path_to_candidates.reset( new FilepathToCandidates() );
boost::shared_ptr< std::vector< Candidate* > > &candidates =
(*path_to_candidates)[ filepath ];
if ( !candidates )
candidates.reset( new std::vector< Candidate* >() );
return *candidates;
}
} // namespace YouCompleteMe } // namespace YouCompleteMe

View File

@ -23,8 +23,8 @@
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <boost/python.hpp> #include <boost/python.hpp>
#include <boost/unordered_map.hpp> #include <boost/unordered_map.hpp>
#include <boost/shared_ptr.hpp>
#include <set>
#include <vector> #include <vector>
#include <string> #include <string>
@ -32,24 +32,49 @@ namespace YouCompleteMe
{ {
typedef boost::python::list Pylist; typedef boost::python::list Pylist;
// candidate text string -> candidate objects
typedef boost::unordered_map< std::string, Candidate* > CandidateRepository; typedef boost::unordered_map< std::string, Candidate* > CandidateRepository;
// filepath -> *( *candidate )
typedef boost::unordered_map< std::string,
boost::shared_ptr< std::vector< Candidate* > > > FilepathToCandidates;
// filetype -> *( filepath -> *( *candidate ) )
typedef boost::unordered_map< std::string,
boost::shared_ptr< FilepathToCandidates > > FiletypeMap;
// TODO: resolve problems with noncopyable
// class Completer : boost::noncopyable // class Completer : boost::noncopyable
class Completer class Completer
{ {
public: public:
Completer() {} Completer() {}
Completer( const Pylist &candidates ); Completer( const Pylist &candidates );
Completer( const Pylist &candidates, const std::string &filepath ); Completer( const Pylist &candidates,
const std::string &filetype,
const std::string &filepath );
~Completer(); ~Completer();
void AddCandidatesToDatabase( const Pylist &candidates, void AddCandidatesToDatabase( const Pylist &new_candidates,
const std::string &filetype,
const std::string &filepath ); const std::string &filepath );
void GetCandidatesForQuery( // Only provided for tests!
const std::string &query, Pylist &candidates ) const; void CandidatesForQuery( const std::string &query,
Pylist &candidates ) const;
void CandidatesForQueryAndType( const std::string &query,
const std::string &filetype,
Pylist &candidates ) const;
private: private:
std::vector< Candidate* >& GetCandidateVector(
const std::string &filetype,
const std::string &filepath );
struct CandidatePointerLess struct CandidatePointerLess
{ {
bool operator() ( const Candidate *first, const Candidate *second ) bool operator() ( const Candidate *first, const Candidate *second )
@ -58,8 +83,10 @@ private:
} }
}; };
// This data structure owns all the Candidate pointers
CandidateRepository candidate_repository_; CandidateRepository candidate_repository_;
std::set< Candidate*, CandidatePointerLess > candidates_;
FiletypeMap filetype_map_;
}; };
} // namespace YouCompleteMe } // namespace YouCompleteMe

View File

@ -27,6 +27,7 @@ namespace YouCompleteMe
bool AlmostEqual( double a, double b ); bool AlmostEqual( double a, double b );
template <class Container, class Key> template <class Container, class Key>
typename Container::mapped_type & typename Container::mapped_type &
GetValueElseInsert( Container &container, GetValueElseInsert( Container &container,
@ -37,6 +38,7 @@ GetValueElseInsert( Container &container,
.first->second; .first->second;
} }
template <class Container, class Key> template <class Container, class Key>
bool ContainsKey( Container &container, Key const& key) bool ContainsKey( Container &container, Key const& key)
{ {

View File

@ -21,10 +21,10 @@
BOOST_PYTHON_MODULE(indexer) BOOST_PYTHON_MODULE(indexer)
{ {
using namespace boost::python; using namespace boost::python;
using namespace YouCompleteMe; using namespace YouCompleteMe;
class_<Completer>( "Completer" ) class_<Completer>( "Completer" )
.def( "AddCandidatesToDatabase", &Completer::AddCandidatesToDatabase ) .def( "AddCandidatesToDatabase", &Completer::AddCandidatesToDatabase )
.def( "GetCandidatesForQuery", &Completer::GetCandidatesForQuery ); .def( "CandidatesForQueryAndType", &Completer::CandidatesForQueryAndType );
} }

View File

@ -89,7 +89,7 @@ class CompleterTest : public ::testing::Test
TEST_F( CompleterTest, OneCandidate ) TEST_F( CompleterTest, OneCandidate )
{ {
Pylist results; Pylist results;
Completer( Candidates( "foobar" ) ).GetCandidatesForQuery( "fbr", results ); Completer( Candidates( "foobar" ) ).CandidatesForQuery( "fbr", results );
EXPECT_THAT( ToStringVector( results ), ElementsAre( "foobar" ) ); EXPECT_THAT( ToStringVector( results ), ElementsAre( "foobar" ) );
} }
@ -98,9 +98,9 @@ TEST_F( CompleterTest, ManyCandidateSimple )
{ {
Pylist results; Pylist results;
Completer( Candidates( Completer( Candidates(
"foobar", "foobar",
"foobartest", "foobartest",
"Foobartest" ) ).GetCandidatesForQuery( "fbr", results ); "Foobartest" ) ).CandidatesForQuery( "fbr", results );
EXPECT_THAT( ToStringVector( results ), EXPECT_THAT( ToStringVector( results ),
WhenSorted( ElementsAre( "Foobartest", WhenSorted( ElementsAre( "Foobartest",
@ -112,8 +112,8 @@ TEST_F( CompleterTest, FirstCharSameAsQueryWins )
{ {
Pylist results; Pylist results;
Completer( Candidates( Completer( Candidates(
"foobar", "foobar",
"afoobar" ) ).GetCandidatesForQuery( "fbr", results ); "afoobar" ) ).CandidatesForQuery( "fbr", results );
EXPECT_THAT( ToStringVector( results ), EXPECT_THAT( ToStringVector( results ),
ElementsAre( "foobar", ElementsAre( "foobar",
@ -124,8 +124,8 @@ TEST_F( CompleterTest, CompleteMatchForWordBoundaryCharsWins )
{ {
Pylist results; Pylist results;
Completer( Candidates( Completer( Candidates(
"FooBarQux", "FooBarQux",
"FBaqux" ) ).GetCandidatesForQuery( "fbq", results ); "FBaqux" ) ).CandidatesForQuery( "fbq", results );
EXPECT_THAT( ToStringVector( results ), EXPECT_THAT( ToStringVector( results ),
ElementsAre( "FooBarQux", ElementsAre( "FooBarQux",
@ -133,9 +133,9 @@ TEST_F( CompleterTest, CompleteMatchForWordBoundaryCharsWins )
Pylist results2; Pylist results2;
Completer( Candidates( Completer( Candidates(
"CompleterTest", "CompleterTest",
"CompleteMatchForWordBoundaryCharsWins" "CompleteMatchForWordBoundaryCharsWins"
) ).GetCandidatesForQuery( "ct", results2 ); ) ).CandidatesForQuery( "ct", results2 );
EXPECT_THAT( ToStringVector( results2 ), EXPECT_THAT( ToStringVector( results2 ),
ElementsAre( "CompleterTest", ElementsAre( "CompleterTest",
@ -143,9 +143,8 @@ TEST_F( CompleterTest, CompleteMatchForWordBoundaryCharsWins )
Pylist results3; Pylist results3;
Completer( Candidates( Completer( Candidates(
"FooBar", "FooBar",
"FooBarRux" "FooBarRux" ) ).CandidatesForQuery( "fbr", results3 );
) ).GetCandidatesForQuery( "fbr", results3 );
EXPECT_THAT( ToStringVector( results3 ), EXPECT_THAT( ToStringVector( results3 ),
ElementsAre( "FooBarRux", ElementsAre( "FooBarRux",
@ -156,8 +155,8 @@ TEST_F( CompleterTest, RatioUtilizationTieBreak )
{ {
Pylist results; Pylist results;
Completer( Candidates( Completer( Candidates(
"FooBarQux", "FooBarQux",
"FooBarQuxZaa" ) ).GetCandidatesForQuery( "fbq", results ); "FooBarQuxZaa" ) ).CandidatesForQuery( "fbq", results );
EXPECT_THAT( ToStringVector( results ), EXPECT_THAT( ToStringVector( results ),
ElementsAre( "FooBarQux", ElementsAre( "FooBarQux",
@ -165,8 +164,8 @@ TEST_F( CompleterTest, RatioUtilizationTieBreak )
Pylist results2; Pylist results2;
Completer( Candidates( Completer( Candidates(
"FooBar", "FooBar",
"FooBarRux" ) ).GetCandidatesForQuery( "fba", results2 ); "FooBarRux" ) ).CandidatesForQuery( "fba", results2 );
EXPECT_THAT( ToStringVector( results2 ), EXPECT_THAT( ToStringVector( results2 ),
ElementsAre( "FooBar", ElementsAre( "FooBar",
@ -177,8 +176,8 @@ TEST_F( CompleterTest, QueryPrefixOfCandidateWins )
{ {
Pylist results; Pylist results;
Completer( Candidates( Completer( Candidates(
"foobar", "foobar",
"fbaroo" ) ).GetCandidatesForQuery( "foo", results ); "fbaroo" ) ).CandidatesForQuery( "foo", results );
EXPECT_THAT( ToStringVector( results ), EXPECT_THAT( ToStringVector( results ),
ElementsAre( "foobar", ElementsAre( "foobar",
@ -189,8 +188,8 @@ TEST_F( CompleterTest, ShorterCandidateWins )
{ {
Pylist results; Pylist results;
Completer( Candidates( Completer( Candidates(
"FooBarQux", "FooBarQux",
"FaBarQux" ) ).GetCandidatesForQuery( "fbq", results ); "FaBarQux" ) ).CandidatesForQuery( "fbq", results );
EXPECT_THAT( ToStringVector( results ), EXPECT_THAT( ToStringVector( results ),
ElementsAre( "FaBarQux", ElementsAre( "FaBarQux",
@ -198,8 +197,8 @@ TEST_F( CompleterTest, ShorterCandidateWins )
Pylist results2; Pylist results2;
Completer( Candidates( Completer( Candidates(
"CompleterT", "CompleterT",
"CompleterTest" ) ).GetCandidatesForQuery( "co", results2 ); "CompleterTest" ) ).CandidatesForQuery( "co", results2 );
EXPECT_THAT( ToStringVector( results2 ), EXPECT_THAT( ToStringVector( results2 ),
ElementsAre( "CompleterT", ElementsAre( "CompleterT",
@ -210,8 +209,8 @@ TEST_F( CompleterTest, SameLowercaseCandidateWins )
{ {
Pylist results; Pylist results;
Completer( Candidates( Completer( Candidates(
"foobar", "foobar",
"Foobar" ) ).GetCandidatesForQuery( "foo", results ); "Foobar" ) ).CandidatesForQuery( "foo", results );
EXPECT_THAT( ToStringVector( results ), EXPECT_THAT( ToStringVector( results ),
ElementsAre( "foobar", ElementsAre( "foobar",

View File

@ -30,7 +30,10 @@ class CompletionSystem( object ):
def CompletionCandidatesForQuery( self, query ): def CompletionCandidatesForQuery( self, query ):
candidates = [] candidates = []
self.completer.GetCandidatesForQuery( SanitizeQuery( query ), candidates ) filetype = vim.eval( "&filetype" )
self.completer.CandidatesForQueryAndType( SanitizeQuery( query ),
filetype,
candidates )
return candidates return candidates
def AddBufferIdentifiers( self ): def AddBufferIdentifiers( self ):
@ -38,8 +41,9 @@ class CompletionSystem( object ):
text = RemoveIdentFreeText( text ) text = RemoveIdentFreeText( text )
idents = re.findall( self.pattern, text ) idents = re.findall( self.pattern, text )
filetype = vim.eval( "&filetype" )
filepath = vim.eval( "expand('%:p')" ) filepath = vim.eval( "expand('%:p')" )
self.completer.AddCandidatesToDatabase( idents, filepath ) self.completer.AddCandidatesToDatabase( idents, filetype, filepath )
def CurrentColumn(): def CurrentColumn():
# vim's columns start at 1 while vim.current.line columns start at 0 # vim's columns start at 1 while vim.current.line columns start at 0