From ef49f3e052bbf2d30ad4462b7458dabfc35312f9 Mon Sep 17 00:00:00 2001 From: micbou Date: Tue, 16 Aug 2016 16:08:11 +0200 Subject: [PATCH] Fix diagnostic highlighting at line ending When columns are clamped to not be past the contents of the line for highlighting diagnostics, we need to account for the column end not being included in the diagnostic range. --- python/ycm/tests/vimsupport_test.py | 30 +++++++++++++++++++++++++++-- python/ycm/vimsupport.py | 27 ++++++++++++++------------ 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/python/ycm/tests/vimsupport_test.py b/python/ycm/tests/vimsupport_test.py index bcc39709..19dae398 100644 --- a/python/ycm/tests/vimsupport_test.py +++ b/python/ycm/tests/vimsupport_test.py @@ -681,7 +681,7 @@ def _BuildLocations( start_line, start_column, end_line, end_column ): def ReplaceChunksInBuffer_SortedChunks_test(): chunks = [ - _BuildChunk( 1, 4, 1, 4, '('), + _BuildChunk( 1, 4, 1, 4, '(' ), _BuildChunk( 1, 11, 1, 11, ')' ) ] @@ -694,7 +694,7 @@ def ReplaceChunksInBuffer_SortedChunks_test(): def ReplaceChunksInBuffer_UnsortedChunks_test(): chunks = [ - _BuildChunk( 1, 11, 1, 11, ')'), + _BuildChunk( 1, 11, 1, 11, ')' ), _BuildChunk( 1, 4, 1, 4, '(' ) ] @@ -1220,6 +1220,32 @@ def _BuildChunk( start_line, } +@patch( 'vim.eval', new_callable = ExtendedMock ) +def AddDiagnosticSyntaxMatch_ErrorInMiddleOfLine_test( vim_eval ): + current_buffer = MockBuffer( [ + 'Highlight this error please' + ], 'some_file', 1 ) + + with patch( 'vim.current.buffer', current_buffer ): + vimsupport.AddDiagnosticSyntaxMatch( 1, 16, 1, 21 ) + + vim_eval.assert_called_once_with( + r"matchadd('YcmErrorSection', '\%1l\%16c\_.\{-}\%1l\%21c')" ) + + +@patch( 'vim.eval', new_callable = ExtendedMock ) +def AddDiagnosticSyntaxMatch_WarningAtEndOfLine_test( vim_eval ): + current_buffer = MockBuffer( [ + 'Highlight this warning' + ], 'some_file', 1 ) + + with patch( 'vim.current.buffer', current_buffer ): + vimsupport.AddDiagnosticSyntaxMatch( 1, 16, 1, 23, is_error = False ) + + vim_eval.assert_called_once_with( + r"matchadd('YcmWarningSection', '\%1l\%16c\_.\{-}\%1l\%23c')" ) + + @patch( 'vim.command', new_callable=ExtendedMock ) @patch( 'vim.current', new_callable=ExtendedMock) def WriteToPreviewWindow_test( vim_current, vim_command ): diff --git a/python/ycm/vimsupport.py b/python/ycm/vimsupport.py index 17f32e68..e1d750d7 100644 --- a/python/ycm/vimsupport.py +++ b/python/ycm/vimsupport.py @@ -208,29 +208,32 @@ def ClearYcmSyntaxMatches(): vim.eval( 'matchdelete({0})'.format( match[ 'id' ] ) ) -# Returns the ID of the newly added match -# Both line and column numbers are 1-based def AddDiagnosticSyntaxMatch( line_num, column_num, line_end_num = None, column_end_num = None, is_error = True ): + """Highlight a range in the current window starting from + (|line_num|, |column_num|) included to (|line_end_num|, |column_end_num|) + excluded. If |line_end_num| or |column_end_num| are not given, highlight the + character at (|line_num|, |column_num|). Both line and column numbers are + 1-based. Return the ID of the newly added match.""" group = 'YcmErrorSection' if is_error else 'YcmWarningSection' - if not line_end_num: - line_end_num = line_num - line_num, column_num = LineAndColumnNumbersClamped( line_num, column_num ) - line_end_num, column_end_num = LineAndColumnNumbersClamped( line_end_num, - column_end_num ) - if not column_end_num: + if not line_end_num or not column_end_num: return GetIntValue( "matchadd('{0}', '\%{1}l\%{2}c')".format( group, line_num, column_num ) ) - else: - return GetIntValue( - "matchadd('{0}', '\%{1}l\%{2}c\_.\\{{-}}\%{3}l\%{4}c')".format( - group, line_num, column_num, line_end_num, column_end_num ) ) + + # -1 and then +1 to account for column end not included in the range. + line_end_num, column_end_num = LineAndColumnNumbersClamped( + line_end_num, column_end_num - 1 ) + column_end_num += 1 + + return GetIntValue( + "matchadd('{0}', '\%{1}l\%{2}c\_.\\{{-}}\%{3}l\%{4}c')".format( + group, line_num, column_num, line_end_num, column_end_num ) ) # Clamps the line and column numbers so that they are not past the contents of