3

When I place the cursor on the parenthesis of the below line, the two parenthesis get highlighted in a cyan color. When I place the cursor on the curly braces, however, no highlighting happens.

// cmake example
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
   ^                  ^               ^            ^
   |                  |               |            |
   |                  +------+--------+            |
   |                         |                     |
   |                         +--- no highlighting  |
   |                                               |
   +-------------------------+---------------------+
                             |
                             +--- expected highlighting works

Note that the set may need to be inside a sub-block to fail (i.e inside an if(SOMETHING) ... endif(SOMETHING) block for example).

Here is another example with C++ code:

// C++ example
a = "this (string) here";   // this one fails, it's inside a string
a = string("here");         // here the highlight works

As we can see the parenthesis are outside of a string and the curly braces are inside the string.

I have the same problem in comments and various other types of string-like regions.

How do I get this highlighting to work in strings and comments like it was in older versions of Vim?


Here are a couple of screenshots. The vertical bar is the cursor placed just before the parenthesis or curly braces.

enter image description here

enter image description here

Note 1: Yes. The highlighting works just fine with curly braces outside of a string, and also square brackets, <,>, etc.

Note 2: The % key works as expected, so I can find the matching character, but that's not as practical as the highlighting.


So far, this has shown up in nearly all the files formats I used (C++, Go, JavaScript, Ruby, CMakeLists.txt, etc.) However, at least the parenthesis and curly braces do work fine in a shell script (sh).

As for the matched pairs, I have:

matchpairs=(:),{:},[:],<:>

I added the <:> in my settings, but the problem occurred before I added those and whether I specify matchit or not:

set matchpairs+=<:>
packadd! matchit

Further, I tried to comment out all of my entries in my ~/.vimrc and the results are the same.


On my clean install, I see the same issues. I tried to add

matchadd! matchit
let b:match_skip = "0"

to my ~/.vimrc and that had no effect on the issue.

Just in case, here is the /usr/share/vim/vim80/debian.vim file that gets loaded through the /etc/vim/vim.vim (I removed the full line comments to make it shorter):

set runtimepath=~/.vim,/var/lib/vim/addons,/usr/share/vim/vimfiles,/usr/share/vim/vim80,/usr/share/vim/vimfiles/after,/var/lib/vim/addons/after,~/.vim/after
set nocompatible    " Use Vim defaults instead of 100% vi compatibility
set backspace=indent,eol,start  " more powerful backspacing
set history=50      " keep 50 lines of command line history
set ruler       " show the cursor position all the time
set nomodeline
set suffixes=.bak,~,.swp,.o,.info,.aux,.log,.dvi,.bbl,.blg,.brf,.cb,.ind,.idx,.ilg,.inx,.out,.toc
if &term =~ "xterm-debian" || &term =~ "xterm-xfree86"
  set t_Co=16
  set t_Sf=[3%dm
  set t_Sb=[4%dm
endif
if has("autocmd")
  if has('gui')
    function! <SID>MapExists(name, modes)
      for mode in split(a:modes, '\zs')
        if !empty(maparg(a:name, mode))
          return 1
        endif
      endfor
      return 0
    endfunction
    autocmd GUIEnter * if !<SID>MapExists("<S-Insert>", "nvso") | execute "map <S-Insert> <MiddleMouse>" | endif
    autocmd GUIEnter * if !<SID>MapExists("<S-Insert>", "ic") | execute "map! <S-Insert> <MiddleMouse>" | endif
  endif
endif
if filereadable("/etc/papersize")
  let s:papersize = matchstr(readfile('/etc/papersize', '', 1), '\p*')
  if strlen(s:papersize)
    exe "set printoptions+=paper:" . s:papersize
  endif
endif

See related question: MatchIt not matching anymore if parenthesis, brackets, etc. are between quotes or in comments?

8
  • What's the filetype? Try :set filetype?. Do you have curly braces in matchpairs? :set matchpairs? (I'm thinking you do, since % works...)
    – filbranden
    Jan 2, 2020 at 21:14
  • @filbranden I added that info, but so far it has happened in all file formats I've been working with (from what I recall) My example here is a CMake file. Jan 2, 2020 at 21:22
  • 1
    Did you try adding both packadd! matchit and let b:match_skip = "0" in your vimrc? Give me some more time on this one... This question is super interesting, but unfortunately I haven't managed to get enough time on a machine where I can mess up with Vim enough to reproduce and fix this. (Also, for some reason, my setups don't reproduce this and I want to dig into why that is...)
    – filbranden
    Jan 4, 2020 at 6:00
  • 1
    @filbranden I tried those two and it made no different, either directly or in my ~/.vimrc. Jan 4, 2020 at 6:29
  • 1
    so if I understand it correctly, it's not matchit that is not working but matchparen. Jan 4, 2020 at 8:45

1 Answer 1

4

I did a little investigation. At first I could not reproduce, but I think I have found the problem (part of it was, you did not mention what version you were using :/)

I have a local machine with an Ubuntu 18.04.03 LTS installed. In it, I could reproduce the problem when using the system vim (I usually compile my own), that is version 8.0.1453.

I traced the problem to the matchparen plugin. The matchparen plugin tries to find a matching parenthesis to the one where the cursor is while skipping special syntax groups like string or comment, if the cursor is not also in such a group. If the cursor is in such a group, it will not skip any match, by setting the special s_skip variable to 0.

Now, there was a patch 8.0.1239, that allows to use partials, funcrefs and strings as skip-expressions. At the same time, using a number as a skip expression would not work anymore and would silently return no-match. So that unfortunately regressed the default matchparen plugin, that comes with vim. (I think later on, searchpair and related functions did actually throw an error in that case.)

This problem was noticed and finally fixed by patch v8.1.0115 which makes sure, that the matchparen plugin uses a string for the skip expression.

What to do?

In your case, copy the plugin that comes from the distribution to your local runtime directory (create the ~/.vim/plugin folder if it does not exist yet):

cp /usr/share/vim/vim80/plugin/matchparen.vim ~/.vim/plugin

Now edit that file and apply this patch:

diff --git a/runtime/plugin/matchparen.vim b/runtime/plugin/matchparen.vim
index 4f68fd87b..0fa5c4d22 100644
--- a/runtime/plugin/matchparen.vim
+++ b/runtime/plugin/matchparen.vim
@@ -114,7 +114,7 @@ function! s:Highlight_Matching_Pair()
   " within those syntax types (i.e., not skip).  Otherwise, the cursor is
   " outside of the syntax types and s_skip should keep its value so we skip any
   " matching pair inside the syntax types.
-  execute 'if' s_skip '| let s_skip = 0 | endif'
+  execute 'if' s_skip '| let s_skip = "0" | endif'

   " Limit the search to lines visible in the window.
   let stoplinebottom = line('w$')

e.g. change line 117 and from ... = 0 to ... = "0" (notice the double quotes).

Then restart Vim and it should work again.

(An alternative would be to install a Vim newer than 8.1.0115, which comes with updated runtime files.

3
  • I just have to wonder... why is that execute even necessary??
    – D. Ben Knoble
    Jan 4, 2020 at 15:20
  • @D.BenKnoble you need to evaluate the skip expression, e.g. you need to know, whether to skip those special syntax groups or not. That's why you are executing it. Jan 4, 2020 at 16:38
  • Ah wait yes I see; it is a string that represents an expression. /facepalm
    – D. Ben Knoble
    Jan 4, 2020 at 16:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.