# Copyright (C) 2016, Davit Samvelyan # # 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 . from ycm import vimsupport from ycm.client.event_notification import EventNotification from ycm.diagnostic_interface import DiagnosticInterface DIAGNOSTIC_UI_FILETYPES = { 'cpp', 'cs', 'c', 'objc', 'objcpp', 'cuda', 'javascript', 'typescript', 'typescriptreact' } # Emulates Vim buffer # Used to store buffer related information like diagnostics, latest parse # request. Stores buffer change tick at the parse request moment, allowing # to effectively determine whether reparse is needed for the buffer. class Buffer: def __init__( self, bufnr, user_options, filetypes ): self._number = bufnr self._parse_tick = 0 self._handled_tick = 0 self._parse_request = None self._should_resend = False self._diag_interface = DiagnosticInterface( bufnr, user_options ) self.UpdateFromFileTypes( filetypes ) def FileParseRequestReady( self, block = False ): return bool( self._parse_request and ( block or self._parse_request.Done() ) ) def SendParseRequest( self, extra_data ): # Don't send a parse request if one is in progress if self._parse_request is not None and not self._parse_request.Done(): self._should_resend = True return self._should_resend = False self._parse_request = EventNotification( 'FileReadyToParse', extra_data = extra_data ) self._parse_request.Start() # Decrement handled tick to ensure correct handling when we are forcing # reparse on buffer visit and changed tick remains the same. self._handled_tick -= 1 self._parse_tick = self._ChangedTick() def NeedsReparse( self ): return self._parse_tick != self._ChangedTick() def ShouldResendParseRequest( self ): return ( self._should_resend or ( bool( self._parse_request ) and self._parse_request.ShouldResend() ) ) def UpdateDiagnostics( self, force = False ): if force or not self._async_diags: self.UpdateWithNewDiagnostics( self._parse_request.Response() ) else: # We need to call the response method, because it might throw an exception # or require extra config confirmation, even if we don't actually use the # diagnostics. self._parse_request.Response() def UpdateWithNewDiagnostics( self, diagnostics ): self._diag_interface.UpdateWithNewDiagnostics( diagnostics ) def UpdateMatches( self ): self._diag_interface.UpdateMatches() def PopulateLocationList( self ): return self._diag_interface.PopulateLocationList() def GetResponse( self ): return self._parse_request.Response() def IsResponseHandled( self ): return self._handled_tick == self._parse_tick def MarkResponseHandled( self ): self._handled_tick = self._parse_tick def OnCursorMoved( self ): self._diag_interface.OnCursorMoved() def GetErrorCount( self ): return self._diag_interface.GetErrorCount() def GetWarningCount( self ): return self._diag_interface.GetWarningCount() def UpdateFromFileTypes( self, filetypes ): self._filetypes = filetypes self._async_diags = not any( x in DIAGNOSTIC_UI_FILETYPES for x in filetypes ) def _ChangedTick( self ): return vimsupport.GetBufferChangedTick( self._number ) class BufferDict( dict ): def __init__( self, user_options ): self._user_options = user_options def __missing__( self, key ): # Python does not allow to return assignment operation result directly new_value = self[ key ] = Buffer( key, self._user_options, vimsupport.GetBufferFiletypes( key ) ) return new_value