diff --git a/autoload/youcompleteme.vim b/autoload/youcompleteme.vim index cf676cb8..e44f3ac0 100644 --- a/autoload/youcompleteme.vim +++ b/autoload/youcompleteme.vim @@ -61,6 +61,7 @@ function! youcompleteme#Enable() " that happens *after" BufRead/BufEnter has already triggered for the " initial file. autocmd BufRead,BufEnter * call s:OnBufferVisit() + autocmd BufDelete * call s:OnBufferDelete( expand( ':p' ) ) autocmd CursorHold,CursorHoldI * call s:OnCursorHold() autocmd InsertLeave * call s:OnInsertLeave() autocmd InsertEnter * call s:OnInsertEnter() @@ -183,6 +184,15 @@ function! s:OnBufferVisit() endfunction +function! s:OnBufferDelete( deleted_buffer_file ) + if !s:AllowedToCompleteInCurrentFile() || empty( a:deleted_buffer_file ) + return + endif + + py ycm_state.OnBufferDelete( vim.eval( 'a:deleted_buffer_file' ) ) +endfunction + + function! s:OnCursorHold() if !s:AllowedToCompleteInCurrentFile() return diff --git a/cpp/ycm/ClangCompleter/ClangCompleter.cpp b/cpp/ycm/ClangCompleter/ClangCompleter.cpp index 86dc21d9..ac4d3c11 100644 --- a/cpp/ycm/ClangCompleter/ClangCompleter.cpp +++ b/cpp/ycm/ClangCompleter/ClangCompleter.cpp @@ -262,6 +262,16 @@ ClangCompleter::CandidatesForQueryAndLocationInFileAsync( } +void ClangCompleter::DeleteCachesForFile( const std::string &filename ) { + // If the clang thread is currently parsing the file when the user deletes the + // buffer and thus we try to delete the caches, Vim's GUI thread would block + // until the clang thread releases the mutex. Move this operation to the clang + // thread. + lock_guard< mutex > lock( filename_to_translation_unit_mutex_ ); + filename_to_translation_unit_.erase( filename ); +} + + bool ClangCompleter::ShouldSkipClangResultCache( const std::string &query, int line, int column ) { diff --git a/cpp/ycm/ClangCompleter/ClangCompleter.h b/cpp/ycm/ClangCompleter/ClangCompleter.h index fd546a8e..1b0c092b 100644 --- a/cpp/ycm/ClangCompleter/ClangCompleter.h +++ b/cpp/ycm/ClangCompleter/ClangCompleter.h @@ -93,6 +93,8 @@ public: const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags ); + void DeleteCachesForFile( const std::string &filename ); + private: // This is basically a union. Only one of the two tasks is set to something diff --git a/cpp/ycm/ClangCompleter/TranslationUnit.cpp b/cpp/ycm/ClangCompleter/TranslationUnit.cpp index 257cdb3f..8b7aca00 100644 --- a/cpp/ycm/ClangCompleter/TranslationUnit.cpp +++ b/cpp/ycm/ClangCompleter/TranslationUnit.cpp @@ -81,6 +81,8 @@ TranslationUnit::~TranslationUnit() { } void TranslationUnit::Destroy() { + unique_lock< mutex > lock( clang_access_mutex_ ); + if ( clang_translation_unit_ ) { clang_disposeTranslationUnit( clang_translation_unit_ ); clang_translation_unit_ = NULL; diff --git a/cpp/ycm/ycm_core.cpp b/cpp/ycm/ycm_core.cpp index 4ee8bdd8..7a05e87d 100644 --- a/cpp/ycm/ycm_core.cpp +++ b/cpp/ycm/ycm_core.cpp @@ -115,6 +115,7 @@ BOOST_PYTHON_MODULE(ycm_core) class_< ClangCompleter, boost::noncopyable >( "ClangCompleter" ) .def( "EnableThreading", &ClangCompleter::EnableThreading ) .def( "DiagnosticsForFile", &ClangCompleter::DiagnosticsForFile ) + .def( "DeleteCachesForFile", &ClangCompleter::DeleteCachesForFile ) .def( "UpdatingTranslationUnit", &ClangCompleter::UpdatingTranslationUnit ) .def( "UpdateTranslationUnitAsync", &ClangCompleter::UpdateTranslationUnitAsync ) diff --git a/python/completers/completer.py b/python/completers/completer.py index f96aed49..e87299af 100644 --- a/python/completers/completer.py +++ b/python/completers/completer.py @@ -235,6 +235,10 @@ class Completer( object ): pass + def OnBufferDelete( self, deleted_buffer_file ): + pass + + def OnCursorHold( self ): pass diff --git a/python/completers/cpp/clang_completer.py b/python/completers/cpp/clang_completer.py index a934f339..7d1647e2 100644 --- a/python/completers/cpp/clang_completer.py +++ b/python/completers/cpp/clang_completer.py @@ -147,6 +147,10 @@ class ClangCompleter( Completer ): flags ) + def OnBufferDelete( self, deleted_buffer_file ): + self.completer.DeleteCachesForFile( deleted_buffer_file ) + + def DiagnosticsForCurrentFileReady( self ): if not self.parse_future: return False diff --git a/python/ycm.py b/python/ycm.py index e027a86c..d31fccb8 100644 --- a/python/ycm.py +++ b/python/ycm.py @@ -139,6 +139,13 @@ class YouCompleteMe( object ): self.GetFiletypeCompleter().OnFileReadyToParse() + def OnBufferDelete( self, deleted_buffer_file ): + self.identcomp.OnBufferDelete( deleted_buffer_file ) + + if self.FiletypeCompletionUsable(): + self.GetFiletypeCompleter().OnBufferDelete( deleted_buffer_file ) + + def OnInsertLeave( self ): self.identcomp.OnInsertLeave()