diff --git a/cpp/ycm/ClangCompleter.cpp b/cpp/ycm/ClangCompleter.cpp index 95cf644b..ec94a6cd 100644 --- a/cpp/ycm/ClangCompleter.cpp +++ b/cpp/ycm/ClangCompleter.cpp @@ -21,10 +21,13 @@ #include "standard.h" #include "CandidateRepository.h" #include "ConcurrentLatestValue.h" +#include "Utils.h" +#include "ClangUtils.h" #include #include +namespace fs = boost::filesystem; using boost::packaged_task; using boost::bind; using boost::unique_future; @@ -258,7 +261,8 @@ void ClangCompleter::SetFileCompileFlags( const std::string &filename, const std::vector< std::string > &flags ) { - flags_for_file_[ filename ] = flags; + flags_for_file_[ filename ] = + make_shared< std::vector< std::string > >( flags ); } @@ -393,7 +397,14 @@ CXTranslationUnit ClangCompleter::CreateTranslationUnit( const std::string &filename, const std::vector< UnsavedFile > &unsaved_files ) { - std::vector< const char* > flags = ClangFlagsForFilename( filename ); + std::vector< const char* > flags = FlagsForFilename( filename ); + flags.reserve( flags.size() + global_flags_.size() ); + + foreach ( const std::string &flag, global_flags_ ) + { + flags.push_back( flag.c_str() ); + } + std::vector< CXUnsavedFile > cxunsaved_files = ToCXUnsavedFiles( unsaved_files ); @@ -408,20 +419,30 @@ CXTranslationUnit ClangCompleter::CreateTranslationUnit( } -std::vector< const char* > ClangCompleter::ClangFlagsForFilename( - const std::string &filename ) +// The implementation of this function is somewhat non-obvious because we need +// to make sure that the data pointed to by the const char* pointers returned +// outlives this function. We want to make sure that we are calling c_str on the +// string objects that are actually stored in flags_for_file_ +std::vector< const char* > ClangCompleter::FlagsForFilename( + const std::string &filename) { - std::vector< const char* > flags; + FlagsForFile::iterator it = + flags_for_file_.find( filename ); - std::vector< std::string > file_flags = flags_for_file_[ filename ]; - flags.reserve( file_flags.size() + global_flags_.size() ); - - foreach ( const std::string &flag, global_flags_ ) + if ( it == flags_for_file_.end() ) { - flags.push_back( flag.c_str() ); + flags_for_file_[ filename ] = make_shared< std::vector< std::string > >( + SanitizeClangFlags( + SplitFlags( + GetNearestClangOptions( filename ) ) ) ); + + it = flags_for_file_.find( filename ); } - foreach ( const std::string &flag, file_flags ) + // TODO: assert it != end + + std::vector< const char* > flags; + foreach ( const std::string &flag, *it->second ) { flags.push_back( flag.c_str() ); } diff --git a/cpp/ycm/ClangCompleter.h b/cpp/ycm/ClangCompleter.h index 7d943be5..6a6986d5 100644 --- a/cpp/ycm/ClangCompleter.h +++ b/cpp/ycm/ClangCompleter.h @@ -38,13 +38,15 @@ struct CompletionData; typedef boost::shared_ptr< std::vector< CompletionData > > AsyncCompletions; -typedef boost::unordered_map< std::string, std::vector< std::string > > - FlagsForFile; +typedef boost::unordered_map< std::string, + boost::shared_ptr< + std::vector< std::string > > > FlagsForFile; typedef boost::unordered_map< std::string, CXTranslationUnit > TranslationUnitForFilename; +// TODO: document that all filename parameters must be absolute paths class ClangCompleter : boost::noncopyable { public: @@ -84,8 +86,7 @@ private: const std::string &filename, const std::vector< UnsavedFile > &unsaved_files ); - std::vector< const char* > ClangFlagsForFilename( - const std::string &filename ); + std::vector< const char* > FlagsForFilename( const std::string &filename ); CXTranslationUnit GetTranslationUnitForFile( const std::string &filename, diff --git a/cpp/ycm/ClangUtils.cpp b/cpp/ycm/ClangUtils.cpp new file mode 100644 index 00000000..38dd3315 --- /dev/null +++ b/cpp/ycm/ClangUtils.cpp @@ -0,0 +1,118 @@ +// Copyright (C) 2011, 2012 Strahinja Val Markovic +// +// This file is part of YouCompleteMe. +// +// YouCompleteMe is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// YouCompleteMe is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with YouCompleteMe. If not, see . + +#include "ClangUtils.h" +#include "Utils.h" + +#include +#include + + +namespace YouCompleteMe +{ + +const char *CLANG_OPTIONS_FILENAME = ".ycm_clang_options"; + +std::vector< std::string > SanitizeClangFlags( + const std::vector< std::string > &flags ) +{ + std::vector< std::string > sanitized_flags = flags; + std::vector< std::string >::iterator it = sanitized_flags.begin(); + + while ( it != sanitized_flags.end() ) + { + if ( *it == "-arch" ) + { + if ( it + 1 != sanitized_flags.end() ) + sanitized_flags.erase( it, it + 2 ); + else + sanitized_flags.erase( it, it + 1 ); + } + + else + { + ++it; + } + } + + return sanitized_flags; +} + + +std::vector< std::string > SplitFlags( const std::string &flags_string ) +{ + std::vector< std::string > flags; + + bool in_quotes = false; + uint flag_start = 0; + uint flag_length = 0; + for ( uint i = 0; i < flags_string.size(); ++i ) + { + char current_char = flags_string[ i ]; + if ( isspace( current_char ) and !in_quotes ) + { + if ( flag_length != 0 ) + { + flags.push_back( flags_string.substr( flag_start, flag_length ) ); + flag_length = 0; + } + + flag_start = i + 1; + continue; + } + + if ( current_char == '\'' || current_char == '\"' ) + { + in_quotes = !in_quotes; + } + + ++flag_length; + } + + if ( flag_length != 0 ) + flags.push_back( flags_string.substr( flag_start, flag_length ) ); + + return flags; +} + + +std::string GetNearestClangOptions( const std::string &filename ) +{ + fs::path parent_folder = fs::path( filename ).parent_path(); + fs::path clang_options_filename( CLANG_OPTIONS_FILENAME ); + + std::string options_file_contents; + fs::path old_parent_folder = parent_folder; + + do + { + fs::path current_file = parent_folder / clang_options_filename; + if ( fs::exists( current_file ) ) + { + options_file_contents = ReadUtf8File( current_file ); + break; + } + + old_parent_folder = parent_folder; + parent_folder = parent_folder.parent_path(); + } + while ( old_parent_folder != parent_folder ); + + return options_file_contents; +} + +} // namespace YouCompleteMe diff --git a/cpp/ycm/ClangUtils.h b/cpp/ycm/ClangUtils.h new file mode 100644 index 00000000..1ec442d1 --- /dev/null +++ b/cpp/ycm/ClangUtils.h @@ -0,0 +1,40 @@ +// Copyright (C) 2011, 2012 Strahinja Val Markovic +// +// This file is part of YouCompleteMe. +// +// YouCompleteMe is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// YouCompleteMe is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with YouCompleteMe. If not, see . + +#ifndef CLANGUTILS_H_9MVHQLJS +#define CLANGUTILS_H_9MVHQLJS + +#include +#include + +namespace YouCompleteMe +{ + +// TODO: move most of the anon funcs in ClangCompleter.cpp to here + +// Removes flags that are either unnecessary or cause clang to crash +std::vector< std::string > SanitizeClangFlags( + const std::vector< std::string > &flags ); + +std::vector< std::string > SplitFlags( const std::string &flags_string ); + +std::string GetNearestClangOptions( const std::string &filename ); + +} // namespace YouCompleteMe + +#endif /* end of include guard: CLANGUTILS_H_9MVHQLJS */ + diff --git a/cpp/ycm/Utils.cpp b/cpp/ycm/Utils.cpp index a8c32a71..fd418dd6 100644 --- a/cpp/ycm/Utils.cpp +++ b/cpp/ycm/Utils.cpp @@ -18,6 +18,10 @@ #include "Utils.h" #include #include +#include +#include + +namespace fs = boost::filesystem; namespace YouCompleteMe { @@ -29,4 +33,26 @@ bool AlmostEqual( double a, double b ) std::max( std::abs( a ), std::abs( b ) ) ); } + +std::string ReadUtf8File( const fs::path &filepath ) +{ + fs::ifstream file( filepath, std::ios::in | std::ios::binary ); + std::vector< char > contents( (std::istreambuf_iterator< char >( file )), + std::istreambuf_iterator< char >() ); + + if ( contents.size() == 0 ) + return std::string(); + + return std::string( contents.begin(), contents.end() ); +} + + +void WriteUtf8File( const fs::path &filepath, const std::string &contents ) +{ + fs::ofstream file; + file.open( filepath ); + file << contents; + file.close(); +} + } // namespace YouCompleteMe diff --git a/cpp/ycm/Utils.h b/cpp/ycm/Utils.h index e5c8c71f..2c135336 100644 --- a/cpp/ycm/Utils.h +++ b/cpp/ycm/Utils.h @@ -18,15 +18,23 @@ #ifndef UTILS_H_KEPMRPBH #define UTILS_H_KEPMRPBH - #include #include +#include +namespace fs = boost::filesystem; namespace YouCompleteMe { bool AlmostEqual( double a, double b ); +// Reads the entire contents of the specified file. If the file does not exist, +// an exception is thrown. +std::string ReadUtf8File( const fs::path &filepath ); + +// Writes the entire contents of the specified file. If the file does not exist, +// an exception is thrown. +void WriteUtf8File( const fs::path &filepath, const std::string &contents ); template typename Container::mapped_type & diff --git a/cpp/ycm/tests/ClangUtils_test.cpp b/cpp/ycm/tests/ClangUtils_test.cpp new file mode 100644 index 00000000..bec55840 --- /dev/null +++ b/cpp/ycm/tests/ClangUtils_test.cpp @@ -0,0 +1,104 @@ +// Copyright (C) 2011, 2012 Strahinja Val Markovic +// +// This file is part of YouCompleteMe. +// +// YouCompleteMe is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// YouCompleteMe is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with YouCompleteMe. If not, see . + +#include "ClangUtils.h" +#include "Utils.h" +#include "TestUtils.h" +#include +#include + +using ::testing::ElementsAre; +using ::testing::WhenSorted; + +namespace YouCompleteMe +{ + +extern const char *CLANG_OPTIONS_FILENAME; + +TEST( ClangUtilsTest, SanitizeClangFlagsWorks ) +{ + EXPECT_THAT( SanitizeClangFlags( StringVector( + "foo", + "-arch", + "die", + "-arch", + "die2", + "bar" ) ), + ElementsAre( "foo", + "bar" ) ); + + EXPECT_THAT( SanitizeClangFlags( StringVector( + "foo", + "-arch", + "die" ) ), + ElementsAre( "foo" ) ); + + EXPECT_THAT( SanitizeClangFlags( StringVector( + "-arch", + "die" ) ), + ElementsAre() ); + + EXPECT_THAT( SanitizeClangFlags( StringVector( + "-arch" ) ), + ElementsAre() ); +} + + +TEST( ClangUtilsTest, SplitFlagsWorks ) +{ + EXPECT_THAT( SplitFlags( "-f --bar=qux" ), + ElementsAre( "-f", + "--bar=qux" ) ); + + EXPECT_THAT( SplitFlags( "foo" ), + ElementsAre( "foo" ) ); + + EXPECT_THAT( SplitFlags( "foo \n\n\t\v bar" ), + ElementsAre( "foo", + "bar" ) ); + + EXPECT_THAT( SplitFlags( " a ' a b c ' q " ), + ElementsAre( "a", + "' a b c '", + "q" ) ); + + EXPECT_THAT( SplitFlags( "-I../a/b/c -I\"foo/b/c\" -I\"a c\" -I'a/b/c'" ), + ElementsAre( "-I../a/b/c", + "-I\"foo/b/c\"", + "-I\"a c\"", + "-I'a/b/c'" ) ); +} + + +TEST( ClangUtilsTest, GetNearestClangOptionsWorks ) +{ + fs::path temp_root = fs::temp_directory_path() / fs::unique_path(); + fs::create_directories( temp_root ); + + std::string contents = "foo bar"; + WriteUtf8File( temp_root / fs::path( CLANG_OPTIONS_FILENAME ), contents ); + + fs::path parent = temp_root / fs::unique_path(); + fs::create_directories( parent ); + + EXPECT_STREQ( contents.c_str(), + GetNearestClangOptions( + ( parent / fs::unique_path() ).string() ).c_str() ); +} + +} // namespace YouCompleteMe + diff --git a/cpp/ycm/tests/IdentifierCompleter_test.cpp b/cpp/ycm/tests/IdentifierCompleter_test.cpp index b972673a..23e33663 100644 --- a/cpp/ycm/tests/IdentifierCompleter_test.cpp +++ b/cpp/ycm/tests/IdentifierCompleter_test.cpp @@ -19,6 +19,7 @@ #include #include "IdentifierCompleter.h" #include "Utils.h" +#include "TestUtils.h" using ::testing::ElementsAre; using ::testing::WhenSorted; @@ -26,56 +27,19 @@ using ::testing::WhenSorted; namespace YouCompleteMe { -namespace -{ - -std::vector< std::string > Candidates( const std::string &a, - const std::string &b = std::string(), - const std::string &c = std::string(), - const std::string &d = std::string(), - const std::string &e = std::string(), - const std::string &f = std::string(), - const std::string &g = std::string(), - const std::string &h = std::string(), - const std::string &i = std::string() ) -{ - std::vector< std::string > candidates; - candidates.push_back( a ); - if ( !b.empty() ) - candidates.push_back( b ); - if ( !c.empty() ) - candidates.push_back( c ); - if ( !d.empty() ) - candidates.push_back( d ); - if ( !e.empty() ) - candidates.push_back( e ); - if ( !f.empty() ) - candidates.push_back( f ); - if ( !g.empty() ) - candidates.push_back( g ); - if ( !h.empty() ) - candidates.push_back( h ); - if ( !i.empty() ) - candidates.push_back( i ); - - return candidates; -} - -} // unnamed namespace - // This differs from what we expect from the ClangCompleter. That one should // return results for an empty query. TEST( IdentifierCompleterTest, EmptyQueryNoResults ) { - EXPECT_THAT( IdentifierCompleter( Candidates( + EXPECT_THAT( IdentifierCompleter( StringVector( "foobar" ) ).CandidatesForQuery( "" ), ElementsAre() ); } TEST( IdentifierCompleterTest, NoDuplicatesReturned ) { - EXPECT_THAT( IdentifierCompleter( Candidates( + EXPECT_THAT( IdentifierCompleter( StringVector( "foobar", "foobar", "foobar" ) ).CandidatesForQuery( "foo" ), @@ -85,14 +49,14 @@ TEST( IdentifierCompleterTest, NoDuplicatesReturned ) TEST( IdentifierCompleterTest, OneCandidate ) { - EXPECT_THAT( IdentifierCompleter( Candidates( + EXPECT_THAT( IdentifierCompleter( StringVector( "foobar" ) ).CandidatesForQuery( "fbr" ), ElementsAre( "foobar" ) ); } TEST( IdentifierCompleterTest, ManyCandidateSimple ) { - EXPECT_THAT( IdentifierCompleter( Candidates( + EXPECT_THAT( IdentifierCompleter( StringVector( "foobar", "foobartest", "Foobartest" ) ).CandidatesForQuery( "fbr" ), @@ -103,7 +67,7 @@ TEST( IdentifierCompleterTest, ManyCandidateSimple ) TEST( IdentifierCompleterTest, FirstCharSameAsQueryWins ) { - EXPECT_THAT( IdentifierCompleter( Candidates( + EXPECT_THAT( IdentifierCompleter( StringVector( "foobar", "afoobar" ) ).CandidatesForQuery( "fbr" ), ElementsAre( "foobar", @@ -112,20 +76,20 @@ TEST( IdentifierCompleterTest, FirstCharSameAsQueryWins ) TEST( IdentifierCompleterTest, CompleteMatchForWordBoundaryCharsWins ) { - EXPECT_THAT( IdentifierCompleter( Candidates( + EXPECT_THAT( IdentifierCompleter( StringVector( "FooBarQux", "FBaqux" ) ).CandidatesForQuery( "fbq" ), ElementsAre( "FooBarQux", "FBaqux" ) ); - EXPECT_THAT( IdentifierCompleter( Candidates( + EXPECT_THAT( IdentifierCompleter( StringVector( "CompleterTest", "CompleteMatchForWordBoundaryCharsWins" ) ) .CandidatesForQuery( "ct" ), ElementsAre( "CompleterTest", "CompleteMatchForWordBoundaryCharsWins" ) ); - EXPECT_THAT( IdentifierCompleter( Candidates( + EXPECT_THAT( IdentifierCompleter( StringVector( "FooBar", "FooBarRux" ) ).CandidatesForQuery( "fbr" ), ElementsAre( "FooBarRux", @@ -134,37 +98,37 @@ TEST( IdentifierCompleterTest, CompleteMatchForWordBoundaryCharsWins ) TEST( IdentifierCompleterTest, RatioUtilizationTieBreak ) { - EXPECT_THAT( IdentifierCompleter( Candidates( + EXPECT_THAT( IdentifierCompleter( StringVector( "aGaaFooBarQux", "aBaafbq" ) ).CandidatesForQuery( "fbq" ), ElementsAre( "aGaaFooBarQux", "aBaafbq" ) ); - EXPECT_THAT( IdentifierCompleter( Candidates( + EXPECT_THAT( IdentifierCompleter( StringVector( "aFooBarQux", "afbq" ) ).CandidatesForQuery( "fbq" ), ElementsAre( "aFooBarQux", "afbq" ) ); - EXPECT_THAT( IdentifierCompleter( Candidates( + EXPECT_THAT( IdentifierCompleter( StringVector( "acaaCaaFooGxx", "aCaafoog" ) ).CandidatesForQuery( "caafoo" ), ElementsAre( "acaaCaaFooGxx", "aCaafoog" ) ); - EXPECT_THAT( IdentifierCompleter( Candidates( + EXPECT_THAT( IdentifierCompleter( StringVector( "acaaCaaFooGxx", "aCaafoog" ) ).CandidatesForQuery( "caaFoo" ), ElementsAre( "acaaCaaFooGxx", "aCaafoog" ) ); - EXPECT_THAT( IdentifierCompleter( Candidates( + EXPECT_THAT( IdentifierCompleter( StringVector( "FooBarQux", "FooBarQuxZaa" ) ).CandidatesForQuery( "fbq" ), ElementsAre( "FooBarQux", "FooBarQuxZaa" ) ); - EXPECT_THAT( IdentifierCompleter( Candidates( + EXPECT_THAT( IdentifierCompleter( StringVector( "FooBar", "FooBarRux" ) ).CandidatesForQuery( "fba" ), ElementsAre( "FooBar", @@ -173,7 +137,7 @@ TEST( IdentifierCompleterTest, RatioUtilizationTieBreak ) TEST( IdentifierCompleterTest, QueryPrefixOfCandidateWins ) { - EXPECT_THAT( IdentifierCompleter( Candidates( + EXPECT_THAT( IdentifierCompleter( StringVector( "foobar", "fbaroo" ) ).CandidatesForQuery( "foo" ), ElementsAre( "foobar", @@ -182,26 +146,26 @@ TEST( IdentifierCompleterTest, QueryPrefixOfCandidateWins ) TEST( IdentifierCompleterTest, LowerMatchCharIndexSumWins ) { - EXPECT_THAT( IdentifierCompleter( Candidates( + EXPECT_THAT( IdentifierCompleter( StringVector( "ratio_of_word_boundary_chars_in_query_", "first_char_same_in_query_and_text_") ) .CandidatesForQuery( "charinq" ), ElementsAre( "first_char_same_in_query_and_text_", "ratio_of_word_boundary_chars_in_query_") ); - EXPECT_THAT( IdentifierCompleter( Candidates( + EXPECT_THAT( IdentifierCompleter( StringVector( "barfooq", "barquxfoo" ) ).CandidatesForQuery( "foo" ), ElementsAre( "barfooq", "barquxfoo") ); - EXPECT_THAT( IdentifierCompleter( Candidates( + EXPECT_THAT( IdentifierCompleter( StringVector( "xxxxxxabc", "xxabcxxxx" ) ).CandidatesForQuery( "abc" ), ElementsAre( "xxabcxxxx", "xxxxxxabc") ); - EXPECT_THAT( IdentifierCompleter( Candidates( + EXPECT_THAT( IdentifierCompleter( StringVector( "FooBarQux", "FaBarQux" ) ).CandidatesForQuery( "fbq" ), ElementsAre( "FaBarQux", @@ -210,13 +174,13 @@ TEST( IdentifierCompleterTest, LowerMatchCharIndexSumWins ) TEST( IdentifierCompleterTest, ShorterCandidateWins ) { - EXPECT_THAT( IdentifierCompleter( Candidates( + EXPECT_THAT( IdentifierCompleter( StringVector( "CompleterT", "CompleterTest" ) ).CandidatesForQuery( "co" ), ElementsAre( "CompleterT", "CompleterTest" ) ); - EXPECT_THAT( IdentifierCompleter( Candidates( + EXPECT_THAT( IdentifierCompleter( StringVector( "CompleterT", "CompleterTest" ) ).CandidatesForQuery( "plet" ), ElementsAre( "CompleterT", @@ -225,7 +189,7 @@ TEST( IdentifierCompleterTest, ShorterCandidateWins ) TEST( IdentifierCompleterTest, SameLowercaseCandidateWins ) { - EXPECT_THAT( IdentifierCompleter( Candidates( + EXPECT_THAT( IdentifierCompleter( StringVector( "foobar", "Foobar" ) ).CandidatesForQuery( "foo" ), ElementsAre( "foobar", diff --git a/cpp/ycm/tests/TestUtils.cpp b/cpp/ycm/tests/TestUtils.cpp new file mode 100644 index 00000000..ded977f2 --- /dev/null +++ b/cpp/ycm/tests/TestUtils.cpp @@ -0,0 +1,56 @@ +// Copyright (C) 2011, 2012 Strahinja Val Markovic +// +// This file is part of YouCompleteMe. +// +// YouCompleteMe is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// YouCompleteMe is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with YouCompleteMe. If not, see . + +#include "TestUtils.h" + +namespace YouCompleteMe +{ + +std::vector< std::string > StringVector( const std::string &a, + const std::string &b, + const std::string &c, + const std::string &d, + const std::string &e, + const std::string &f, + const std::string &g, + const std::string &h, + const std::string &i ) +{ + std::vector< std::string > string_vector; + string_vector.push_back( a ); + if ( !b.empty() ) + string_vector.push_back( b ); + if ( !c.empty() ) + string_vector.push_back( c ); + if ( !d.empty() ) + string_vector.push_back( d ); + if ( !e.empty() ) + string_vector.push_back( e ); + if ( !f.empty() ) + string_vector.push_back( f ); + if ( !g.empty() ) + string_vector.push_back( g ); + if ( !h.empty() ) + string_vector.push_back( h ); + if ( !i.empty() ) + string_vector.push_back( i ); + + return string_vector; +} + +} // namespace YouCompleteMe + diff --git a/cpp/ycm/tests/TestUtils.h b/cpp/ycm/tests/TestUtils.h new file mode 100644 index 00000000..a6ba19dd --- /dev/null +++ b/cpp/ycm/tests/TestUtils.h @@ -0,0 +1,40 @@ +// Copyright (C) 2011, 2012 Strahinja Val Markovic +// +// This file is part of YouCompleteMe. +// +// YouCompleteMe is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// YouCompleteMe is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with YouCompleteMe. If not, see . + +#ifndef TESTUTILS_H_G4RKMGUD +#define TESTUTILS_H_G4RKMGUD + +#include +#include + +namespace YouCompleteMe +{ + +std::vector< std::string > StringVector( const std::string &a, + const std::string &b = std::string(), + const std::string &c = std::string(), + const std::string &d = std::string(), + const std::string &e = std::string(), + const std::string &f = std::string(), + const std::string &g = std::string(), + const std::string &h = std::string(), + const std::string &i = std::string() ); + +} // namespace YouCompleteMe + +#endif /* end of include guard: TESTUTILS_H_G4RKMGUD */ + diff --git a/python/ycm.py b/python/ycm.py index e8a567f3..23a6a56e 100644 --- a/python/ycm.py +++ b/python/ycm.py @@ -121,6 +121,7 @@ class ClangCompleter( Completer ): self.contents_holder = [] self.filename_holder = [] + def CandidatesForQueryAsync( self, query ): # TODO: sanitize query files = indexer.UnsavedFileVec() @@ -164,6 +165,11 @@ class ClangCompleter( Completer ): return [ CompletionDataToDict( x ) for x in self.future.GetResults() ] + def OnFileEnter( self ): + pass + + + def GetUnsavedBuffers(): def BufferModified( buffer_number ): to_eval = 'getbufvar({0}, "&mod")'.format( buffer_number )