Browse Source

Auto merge of #3279 - micbou:fix-signs, r=puremourning

[READY] Update sign place regex pattern for newer versions

Among other things, [Vim 8.1.0614](https://github.com/vim/vim/commit/162b71479bd4dcdb3a2ef9198a1444f6f99e6843) changed the output of the `sign place` command by adding the `priority` field:
```
--- Signs ---
Signs for test.cpp:
    line=4  id=100000000  name=YcmError priority=10
    line=5  id=100000001  name=YcmError priority=10
```
This breaks [the `GetSignsForBuffer` function](https://github.com/Valloric/YouCompleteMe/blob/7997fc5536e8220ed2798c5522a1eb4421577fa2/python/ycm/vimsupport.py#L204-L215) which extract the signs from the output of that command. We need to update the regex pattern used to match the lines of `sign place` for Vim 8.1.0614 or later.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/valloric/youcompleteme/3279)
<!-- Reviewable:end -->
zzbot 6 years ago
parent
commit
c209cdbbfc
3 changed files with 52 additions and 20 deletions
  1. 13 11
      python/ycm/tests/test_utils.py
  2. 25 5
      python/ycm/tests/youcompleteme_test.py
  3. 14 4
      python/ycm/vimsupport.py

+ 13 - 11
python/ycm/tests/test_utils.py

@@ -84,14 +84,17 @@ VIM_OPTIONS = {
   '&expandtab': 1
 }
 
-# This variable must be patched with a Version object for tests depending on the
-# Vim version. Example:
+Version = namedtuple( 'Version', [ 'major', 'minor', 'patch' ] )
+
+# This variable must be patched with a Version object for tests depending on a
+# recent Vim version. Example:
 #
-#   @patch( 'ycm.tests.test_utils.VIM_VERSION', Version( 7, 4, 1578 ) )
+#   @patch( 'ycm.tests.test_utils.VIM_VERSION', Version( 8, 1, 614 ) )
 #   def ThisTestDependsOnTheVimVersion_test():
 #     ...
 #
-VIM_VERSION = None
+# Default is the oldest supported version.
+VIM_VERSION = Version( 7, 4, 1578 )
 
 REDIR = {
   'status': False,
@@ -100,9 +103,6 @@ REDIR = {
 }
 
 
-Version = namedtuple( 'Version', [ 'major', 'minor', 'patch' ] )
-
-
 @contextlib.contextmanager
 def CurrentWorkingDirectory( path ):
   old_cwd = GetCurrentDirectory()
@@ -312,10 +312,12 @@ def _MockSignCommand( command ):
                           'Signs for foo:\n' )
     for sign in VIM_SIGNS:
       if sign.bufnr == bufnr:
-        REDIR[ 'output' ] += (
-          '    line={0}  id={1}  name={2}'.format( sign.line,
-                                                   sign.id,
-                                                   sign.name ) )
+        if VIM_VERSION >= Version( 8, 1, 614 ):
+          # 10 is the default priority.
+          line_output = '    line={}  id={}  name={} priority=10'
+        else:
+          line_output = '    line={}  id={}  name={}'
+        REDIR[ 'output' ] += line_output.format( sign.line, sign.id, sign.name )
     return True
 
   match = SIGN_PLACE_REGEX.search( command )

+ 25 - 5
python/ycm/tests/youcompleteme_test.py

@@ -22,8 +22,13 @@ from __future__ import absolute_import
 # Not installing aliases from python-future; it's unreliable and slow.
 from builtins import *  # noqa
 
-from ycm.tests.test_utils import ( ExtendedMock, MockVimBuffers, MockVimModule,
-                                   VimBuffer, VimMatch, VimSign )
+from ycm.tests.test_utils import ( ExtendedMock,
+                                   MockVimBuffers,
+                                   MockVimModule,
+                                   Version,
+                                   VimBuffer,
+                                   VimMatch,
+                                   VimSign )
 MockVimModule()
 
 import os
@@ -32,9 +37,14 @@ from hamcrest import ( assert_that, contains, empty, equal_to, has_entries,
                        is_in, is_not, matches_regexp )
 from mock import call, MagicMock, patch
 
+from ycm import vimsupport
 from ycm.paths import _PathToPythonUsedDuringBuild
-from ycm.vimsupport import SetVariableValue, SIGN_BUFFER_ID_INITIAL_VALUE
-from ycm.tests import ( StopServer, test_utils, UserOptions, WaitUntilReady,
+from ycm.vimsupport import ( SetVariableValue,
+                             SIGN_BUFFER_ID_INITIAL_VALUE )
+from ycm.tests import ( StopServer,
+                        test_utils,
+                        UserOptions,
+                        WaitUntilReady,
                         YouCompleteMeInstance )
 from ycm.client.base_request import _LoadExtraConfFile
 from ycm.youcompleteme import YouCompleteMe
@@ -537,7 +547,7 @@ def YouCompleteMe_ShowDiagnostics_DiagnosticsFound_OpenLocationList_test(
 @patch( 'ycm.youcompleteme.YouCompleteMe.FiletypeCompleterExistsForFiletype',
         return_value = True )
 @patch( 'ycm.vimsupport.PostVimMessage', new_callable = ExtendedMock )
-def YouCompleteMe_UpdateDiagnosticInterface_PrioritizeErrorsOverWarnings_test(
+def YouCompleteMe_UpdateDiagnosticInterface(
   ycm, post_vim_message, *args ):
 
   contents = """int main() {
@@ -611,6 +621,7 @@ def YouCompleteMe_UpdateDiagnosticInterface_PrioritizeErrorsOverWarnings_test(
 
   test_utils.VIM_MATCHES_FOR_WINDOW.clear()
   test_utils.VIM_SIGNS = []
+  vimsupport.SIGN_ID_FOR_BUFFER.clear()
 
   with MockVimBuffers( [ current_buffer ], [ current_buffer ], ( 3, 1 ) ):
     with patch( 'ycm.client.event_notification.EventNotification.Response',
@@ -686,6 +697,15 @@ def YouCompleteMe_UpdateDiagnosticInterface_PrioritizeErrorsOverWarnings_test(
     )
 
 
+def YouCompleteMe_UpdateDiagnosticInterface_OldVim_test():
+  YouCompleteMe_UpdateDiagnosticInterface()
+
+
+@patch( 'ycm.tests.test_utils.VIM_VERSION', Version( 8, 1, 614 ) )
+def YouCompleteMe_UpdateDiagnosticInterface_NewVim_test():
+  YouCompleteMe_UpdateDiagnosticInterface()
+
+
 @YouCompleteMeInstance( { 'g:ycm_enable_diagnostic_highlighting': 1 } )
 def YouCompleteMe_UpdateMatches_ClearDiagnosticMatchesInNewBuffer_test( ycm ):
   current_buffer = VimBuffer( 'buffer',

+ 14 - 4
python/ycm/vimsupport.py

@@ -54,8 +54,18 @@ SIGN_BUFFER_ID_INITIAL_VALUE = 100000000
 # This holds the next sign's id to assign for each buffer.
 SIGN_ID_FOR_BUFFER = defaultdict( lambda: SIGN_BUFFER_ID_INITIAL_VALUE )
 
+# The ":sign place" command ouputs each sign on one line in the format
+#
+#    line=<line> id=<id> name=<name> priority=<priority>
+#
+# where the words "line", "id", "name", and "priority" are localized. On
+# versions older than Vim 8.1.0614, the "priority" property doesn't exist and
+# the output is
+#
+#    line=<line> id=<id> name=<name>
+#
 SIGN_PLACE_REGEX = re.compile(
-  r"^.*=(?P<line>\d+).*=(?P<id>\d+).*=(?P<name>Ycm\w+)$" )
+  r"^.*=(?P<line>\d+).*=(?P<id>\d+).*=(?P<name>Ycm\w+)" )
 
 NO_COMPLETIONS = {
   'line': -1,
@@ -222,12 +232,12 @@ def CreateSign( line, name, buffer_number ):
 
 
 def UnplaceSign( sign ):
-  vim.command( 'sign unplace {0} buffer={1}'.format( sign.id,
-                                                     sign.buffer_number ) )
+  vim.command( 'sign unplace {} buffer={}'.format( sign.id,
+                                                   sign.buffer_number ) )
 
 
 def PlaceSign( sign ):
-  vim.command( 'sign place {0} name={1} line={2} buffer={3}'.format(
+  vim.command( 'sign place {} name={} line={} buffer={}'.format(
     sign.id, sign.name, sign.line, sign.buffer_number ) )