Support for showing extra info for diagstics
This was intended to show the full clang output for a given diagnostic, including notes. But it appears that libclang does not provide this functionality...
This commit is contained in:
parent
a4d344aa36
commit
daef17feb4
@ -74,6 +74,9 @@ function! youcompleteme#Enable()
|
|||||||
inoremap <unique> <C-Space> <C-X><C-O><C-P>
|
inoremap <unique> <C-Space> <C-X><C-O><C-P>
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
" TODO: make this a nicer, customizable map
|
||||||
|
nnoremap <unique> <leader>d :call <sid>ShowDetailedDiagnostic()<cr>
|
||||||
|
|
||||||
" Calling this once solves the problem of BufRead/BufEnter not triggering for
|
" Calling this once solves the problem of BufRead/BufEnter not triggering for
|
||||||
" the first loaded file. This should be the last command executed in this
|
" the first loaded file. This should be the last command executed in this
|
||||||
" function!
|
" function!
|
||||||
@ -350,6 +353,11 @@ function! youcompleteme#OmniComplete( findstart, base )
|
|||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
function! s:ShowDetailedDiagnostic()
|
||||||
|
py ycm_state.ShowDetailedDiagnostic()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
" This is what Syntastic calls indirectly when it decides an auto-check is
|
" This is what Syntastic calls indirectly when it decides an auto-check is
|
||||||
" required (currently that's on buffer save) OR when the SyntasticCheck command
|
" required (currently that's on buffer save) OR when the SyntasticCheck command
|
||||||
" is invoked
|
" is invoked
|
||||||
@ -357,6 +365,7 @@ function! youcompleteme#CurrentFileDiagnostics()
|
|||||||
return pyeval( 'ycm_state.GetDiagnosticsForCurrentFile()' )
|
return pyeval( 'ycm_state.GetDiagnosticsForCurrentFile()' )
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
" This is basic vim plugin boilerplate
|
" This is basic vim plugin boilerplate
|
||||||
let &cpo = s:save_cpo
|
let &cpo = s:save_cpo
|
||||||
unlet s:save_cpo
|
unlet s:save_cpo
|
||||||
|
@ -123,6 +123,38 @@ std::vector< CompletionData > ToCompletionDataVector(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// NOTE: The passed in pointer should never be NULL!
|
||||||
|
// TODO: move all functions that are not external into an unnamed namespace
|
||||||
|
std::string FullDiagnosticText( CXDiagnostic cxdiagnostic )
|
||||||
|
{
|
||||||
|
std::string full_text = CXStringToString( clang_formatDiagnostic(
|
||||||
|
cxdiagnostic,
|
||||||
|
clang_defaultDiagnosticDisplayOptions() ) );
|
||||||
|
|
||||||
|
// Note: clang docs say that a CXDiagnosticSet retrieved with
|
||||||
|
// clang_getChildDiagnostics do NOT need to be released with
|
||||||
|
// clang_diposeDiagnosticSet
|
||||||
|
CXDiagnosticSet diag_set = clang_getChildDiagnostics( cxdiagnostic );
|
||||||
|
if ( !diag_set )
|
||||||
|
return full_text;
|
||||||
|
|
||||||
|
uint num_child_diagnostics = clang_getNumDiagnosticsInSet( diag_set );
|
||||||
|
if ( !num_child_diagnostics )
|
||||||
|
return full_text;
|
||||||
|
|
||||||
|
for ( uint i = 0; i < num_child_diagnostics; ++i )
|
||||||
|
{
|
||||||
|
CXDiagnostic diagnostic = clang_getDiagnosticInSet( diag_set, i );
|
||||||
|
if ( !diagnostic )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
full_text.append( FullDiagnosticText( diagnostic ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return full_text;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Diagnostic CXDiagnosticToDiagnostic( CXDiagnostic cxdiagnostic )
|
Diagnostic CXDiagnosticToDiagnostic( CXDiagnostic cxdiagnostic )
|
||||||
{
|
{
|
||||||
Diagnostic diagnostic;
|
Diagnostic diagnostic;
|
||||||
@ -145,9 +177,11 @@ Diagnostic CXDiagnosticToDiagnostic( CXDiagnostic cxdiagnostic )
|
|||||||
&diagnostic.line_number_,
|
&diagnostic.line_number_,
|
||||||
&diagnostic.column_number_,
|
&diagnostic.column_number_,
|
||||||
&unused_offset );
|
&unused_offset );
|
||||||
|
|
||||||
diagnostic.filename_ = CXStringToString( clang_getFileName( file ) );
|
diagnostic.filename_ = CXStringToString( clang_getFileName( file ) );
|
||||||
diagnostic.text_ = CXStringToString(
|
diagnostic.text_ = CXStringToString(
|
||||||
clang_getDiagnosticSpelling( cxdiagnostic ) );
|
clang_getDiagnosticSpelling( cxdiagnostic ) );
|
||||||
|
diagnostic.long_formatted_text_ = FullDiagnosticText( cxdiagnostic );
|
||||||
|
|
||||||
clang_disposeDiagnostic( cxdiagnostic );
|
clang_disposeDiagnostic( cxdiagnostic );
|
||||||
return diagnostic;
|
return diagnostic;
|
||||||
|
@ -47,6 +47,8 @@ struct Diagnostic
|
|||||||
std::string filename_;
|
std::string filename_;
|
||||||
|
|
||||||
std::string text_;
|
std::string text_;
|
||||||
|
|
||||||
|
std::string long_formatted_text_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace YouCompleteMe
|
} // namespace YouCompleteMe
|
||||||
|
@ -54,7 +54,8 @@ BOOST_PYTHON_MODULE(ycm_core)
|
|||||||
.def_readonly( "column_number_", &Diagnostic::column_number_ )
|
.def_readonly( "column_number_", &Diagnostic::column_number_ )
|
||||||
.def_readonly( "kind_", &Diagnostic::kind_ )
|
.def_readonly( "kind_", &Diagnostic::kind_ )
|
||||||
.def_readonly( "filename_", &Diagnostic::filename_ )
|
.def_readonly( "filename_", &Diagnostic::filename_ )
|
||||||
.def_readonly( "text_", &Diagnostic::text_ );
|
.def_readonly( "text_", &Diagnostic::text_ )
|
||||||
|
.def_readonly( "long_formatted_text_", &Diagnostic::long_formatted_text_ );
|
||||||
|
|
||||||
class_< std::vector< Diagnostic > >( "DiagnosticVec" )
|
class_< std::vector< Diagnostic > >( "DiagnosticVec" )
|
||||||
.def( vector_indexing_suite< std::vector< Diagnostic > >() );
|
.def( vector_indexing_suite< std::vector< Diagnostic > >() );
|
||||||
|
@ -78,6 +78,10 @@ class Completer( object ):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def ShowDetailedDiagnostic( self ):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def SupportedFiletypes( self ):
|
def SupportedFiletypes( self ):
|
||||||
pass
|
pass
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
|
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from completers.completer import Completer
|
from completers.completer import Completer
|
||||||
|
from collections import defaultdict
|
||||||
import vim
|
import vim
|
||||||
import vimsupport
|
import vimsupport
|
||||||
import ycm_core
|
import ycm_core
|
||||||
@ -32,7 +33,7 @@ class ClangCompleter( Completer ):
|
|||||||
self.completer.EnableThreading()
|
self.completer.EnableThreading()
|
||||||
self.contents_holder = []
|
self.contents_holder = []
|
||||||
self.filename_holder = []
|
self.filename_holder = []
|
||||||
self.last_diagnostics = []
|
self.last_prepared_diagnostics = []
|
||||||
self.parse_future = None
|
self.parse_future = None
|
||||||
self.flags = Flags()
|
self.flags = Flags()
|
||||||
|
|
||||||
@ -127,11 +128,38 @@ class ClangCompleter( Completer ):
|
|||||||
|
|
||||||
def GetDiagnosticsForCurrentFile( self ):
|
def GetDiagnosticsForCurrentFile( self ):
|
||||||
if self.DiagnosticsForCurrentFileReady():
|
if self.DiagnosticsForCurrentFileReady():
|
||||||
self.last_diagnostics = [ DiagnosticToDict( x ) for x in
|
diagnostics = self.completer.DiagnosticsForFile( vim.current.buffer.name )
|
||||||
self.completer.DiagnosticsForFile(
|
self.diagnostic_store = DiagnosticsToDiagStructure( diagnostics )
|
||||||
vim.current.buffer.name ) ]
|
self.last_prepared_diagnostics = [ DiagnosticToDict( x ) for x in
|
||||||
|
diagnostics ]
|
||||||
self.parse_future = None
|
self.parse_future = None
|
||||||
return self.last_diagnostics
|
return self.last_prepared_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
def ShowDetailedDiagnostic( self ):
|
||||||
|
current_line, current_column = vimsupport.CurrentLineAndColumn()
|
||||||
|
|
||||||
|
# CurrentLineAndColumn() numbers are 0-based, clang numbers are 1-based
|
||||||
|
current_line += 1
|
||||||
|
current_column += 1
|
||||||
|
|
||||||
|
current_file = vim.current.buffer.name
|
||||||
|
diagnostics = self.diagnostic_store[ current_file ][ current_line ]
|
||||||
|
|
||||||
|
if not diagnostics:
|
||||||
|
vimsupport.PostVimMessage( "No diagnostic for current line!" )
|
||||||
|
return
|
||||||
|
|
||||||
|
closest_diagnostic = None
|
||||||
|
distance_to_closest_diagnostic = 999
|
||||||
|
|
||||||
|
for diagnostic in diagnostics:
|
||||||
|
distance = abs( current_column - diagnostic.column_number_ )
|
||||||
|
if distance < distance_to_closest_diagnostic:
|
||||||
|
distance_to_closest_diagnostic = distance
|
||||||
|
closest_diagnostic = diagnostic
|
||||||
|
|
||||||
|
vimsupport.EchoText( closest_diagnostic.long_formatted_text_ )
|
||||||
|
|
||||||
|
|
||||||
def ShouldUseNow( self, start_column ):
|
def ShouldUseNow( self, start_column ):
|
||||||
@ -165,6 +193,14 @@ def DiagnosticToDict( diagnostic ):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def DiagnosticsToDiagStructure( diagnostics ):
|
||||||
|
structure = defaultdict(lambda : defaultdict(list))
|
||||||
|
for diagnostic in diagnostics:
|
||||||
|
structure[ diagnostic.filename_ ][ diagnostic.line_number_ ].append(
|
||||||
|
diagnostic )
|
||||||
|
return structure
|
||||||
|
|
||||||
|
|
||||||
def ClangAvailableForBuffer( buffer_object ):
|
def ClangAvailableForBuffer( buffer_object ):
|
||||||
filetype = vim.eval( 'getbufvar({0}, "&ft")'.format( buffer_object.number ) )
|
filetype = vim.eval( 'getbufvar({0}, "&ft")'.format( buffer_object.number ) )
|
||||||
return filetype in CLANG_FILETYPES
|
return filetype in CLANG_FILETYPES
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
import vim
|
import vim
|
||||||
|
|
||||||
def CurrentLineAndColumn():
|
def CurrentLineAndColumn():
|
||||||
|
"""Returns the 0-based current line."""
|
||||||
# See the comment in CurrentColumn about the calculation for the line and
|
# See the comment in CurrentColumn about the calculation for the line and
|
||||||
# column number
|
# column number
|
||||||
line, column = vim.current.window.cursor
|
line, column = vim.current.window.cursor
|
||||||
@ -28,8 +29,9 @@ def CurrentLineAndColumn():
|
|||||||
|
|
||||||
|
|
||||||
def CurrentColumn():
|
def CurrentColumn():
|
||||||
"""Do NOT access the CurrentColumn in vim.current.line. It doesn't exist yet.
|
"""Returns the 0-based current column. Do NOT access the CurrentColumn in
|
||||||
Only the chars before the current column exist in vim.current.line."""
|
vim.current.line. It doesn't exist yet. Only the chars before the current
|
||||||
|
column exist in vim.current.line."""
|
||||||
|
|
||||||
# vim's columns are 1-based while vim.current.line columns are 0-based
|
# vim's columns are 1-based while vim.current.line columns are 0-based
|
||||||
# ... but vim.current.window.cursor (which returns a (line, column) tuple)
|
# ... but vim.current.window.cursor (which returns a (line, column) tuple)
|
||||||
@ -58,6 +60,10 @@ def PostVimMessage( message ):
|
|||||||
.format( message ) )
|
.format( message ) )
|
||||||
|
|
||||||
|
|
||||||
|
def EchoText( text ):
|
||||||
|
vim.command( "echom '{0}'".format( text.replace( "'", r"''") ) )
|
||||||
|
|
||||||
|
|
||||||
def EscapeForVim( text ):
|
def EscapeForVim( text ):
|
||||||
return text.replace( "'", "''" )
|
return text.replace( "'", "''" )
|
||||||
|
|
||||||
|
@ -106,6 +106,11 @@ class YouCompleteMe( object ):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def ShowDetailedDiagnostic( self ):
|
||||||
|
if self.FiletypeCompletionEnabledForCurrentFile():
|
||||||
|
return self.GetFiletypeCompleterForCurrentFile().ShowDetailedDiagnostic()
|
||||||
|
|
||||||
|
|
||||||
def OnCurrentIdentifierFinished( self ):
|
def OnCurrentIdentifierFinished( self ):
|
||||||
self.identcomp.OnCurrentIdentifierFinished()
|
self.identcomp.OnCurrentIdentifierFinished()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user