[vim/vim] Wrong C++ highlighting (#1005)

55 views
Skip to first unread message

slypiggies

unread,
Aug 25, 2016, 3:20:21 AM8/25/16
to vim/vim

The bug is not complicated, but it appears in all Vims, such as gVim and Vim (Windows/Linux).

Screenshot

vim


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub

Bram Moolenaar

unread,
Aug 25, 2016, 4:37:10 PM8/25/16
to vim/vim

Old C standards don't allow it. Does someone know what was the first when a comment before a preprocessor directive was allowed?

slypiggies

unread,
Aug 26, 2016, 7:59:29 AM8/26/16
to vim/vim

One more thing

This is also not working:
#include\
<bits/stdc++.h>

Offtopic

This editor of ideone handles preprocessors quite good.
ideone


You are receiving this because you are subscribed to this thread.

Reply to this email directly, view it on GitHub,

mattn

unread,
Aug 28, 2016, 7:51:30 PM8/28/16
to vim/vim

I'll look into it vim-jp/vim-cpp#41

dkearns

unread,
Mar 25, 2026, 1:50:45 AMMar 25
to vim/vim, Subscribed
dkearns left a comment (vim/vim#1005)

This could be fixed with a dedicated intermediate block comment but it hardly seems worth the effort. I can't easily find any examples of this in the wild.


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/1005/4123974287@github.com>

dkearns

unread,
Mar 25, 2026, 1:50:46 AMMar 25
to vim/vim, Subscribed

Closed #1005 as not planned.


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issue/1005/issue_event/23877436688@github.com>

mattn

unread,
May 29, 2026, 5:06:21 AM (3 days ago) May 29
to vim/vim, Subscribed
mattn left a comment (vim/vim#1005)

I had a look at this again. The cause is that every preprocessor anchor in the C syntax file uses ^\s*\zs\%(%:\|#\), which only allows whitespace before the #, so a block comment in front of the directive (/**/ #include) isn't recognized. Comments are folded to a space in translation phase 3 (before preprocessing), so /**/ #include is actually valid in every C/C++ standard, which answers the original question about "since which standard".

It can be done. The fix is to allow a run of leading block comments in the anchor and drop the \zs: the \zs makes the effective match start at the #, so it loses to the leftmost cComment region; starting the match at column 1 lets the (later defined) directive win, and listing cComment in contains keeps the leading comment highlighted as a comment.

diff --git a/runtime/syntax/c.vim b/runtime/syntax/c.vim
index 64bcd3e368..655486b3d3 100644
--- a/runtime/syntax/c.vim
+++ b/runtime/syntax/c.vim
@@ -458,11 +458,11 @@ endif
 " Accept %: for # (C99)
 syn cluster	cPreProcGroup	contains=cPreCondit,cIncluded,cInclude,cDefine,cErrInParen,cErrInBracket,cUserLabel,cSpecial,cOctalZero,cCppOutWrapper,cCppInWrapper,@cCppOutInGroup,cFormat,cNumber,cFloat,cOctal,cOctalError,cNumbersCom,cString,cCommentSkip,cCommentString,cComment2String,@cCommentGroup,cCommentStartError,cParen,cBracket,cMulti,cBadBlock
 if !exists("c_no_c23")
-  syn region	cPreCondit	start="^\s*\zs\%(%:\|#\)\s*\%(el\)\=\%(if\|ifdef\|ifndef\)\>" skip="\\$" end="$" keepend contains=cComment,cCommentL,cCppString,cCharacter,cCppParen,cParenError,cNumbers,cCommentError,cSpaceError
+  syn region	cPreCondit	start="^\s*\%(/\*.\{-}\*/\s*\)*\%(%:\|#\)\s*\%(el\)\=\%(if\|ifdef\|ifndef\)\>" skip="\\$" end="$" keepend contains=cComment,cCommentL,cCppString,cCharacter,cCppParen,cParenError,cNumbers,cCommentError,cSpaceError
 else
-  syn region	cPreCondit	start="^\s*\zs\%(%:\|#\)\s*\%(if\|ifdef\|ifndef\|elif\)\>"    skip="\\$" end="$" keepend contains=cComment,cCommentL,cCppString,cCharacter,cCppParen,cParenError,cNumbers,cCommentError,cSpaceError
+  syn region	cPreCondit	start="^\s*\%(/\*.\{-}\*/\s*\)*\%(%:\|#\)\s*\%(if\|ifdef\|ifndef\|elif\)\>"    skip="\\$" end="$" keepend contains=cComment,cCommentL,cCppString,cCharacter,cCppParen,cParenError,cNumbers,cCommentError,cSpaceError
 endif
-syn match	cPreConditMatch	display "^\s*\zs\%(%:\|#\)\s*\%(else\|endif\)\>"
+syn match	cPreConditMatch	display "^\s*\%(/\*.\{-}\*/\s*\)*\%(%:\|#\)\s*\%(else\|endif\)\>" contains=cComment
 if !exists("c_no_if0")
   syn cluster	cCppOutInGroup	contains=cCppInIf,cCppInElse,cCppInElse2,cCppOutIf,cCppOutIf2,cCppOutElse,cCppInSkip,cCppOutSkip
   syn region	cCppOutWrapper	start="^\s*\zs\%(%:\|#\)\s*if\s\+0\+\s*\%($\|//\|/\*\|&\)" end=".\@=\|$" contains=cCppOutIf,cCppOutElse,@NoSpell fold
@@ -510,15 +510,15 @@ if !exists("c_no_if0")
 endif
 syn region	cIncluded	display contained start=+"+ skip=+\\\\\|\\"+ end=+"+
 syn match	cIncluded	display contained "<[^>]*>"
-syn match	cInclude	display "^\s*\zs\%(%:\|#\)\s*include\>\s*["<]" contains=cIncluded
+syn match	cInclude	display "^\s*\%(/\*.\{-}\*/\s*\)*\%(%:\|#\)\s*include\>\s*["<]" contains=cIncluded,cComment
 if !exists("c_no_c23") && !s:in_cpp_family
-  syn region	cInclude	start="^\s*\zs\%(%:\|#\)\s*embed\>" skip="\\$" end="$" keepend contains=cEmbed,cComment,cCommentL,cCppString,cCharacter,cCppParen,cParenError,cNumbers,cCommentError,cSpaceError
+  syn region	cInclude	start="^\s*\%(/\*.\{-}\*/\s*\)*\%(%:\|#\)\s*embed\>" skip="\\$" end="$" keepend contains=cEmbed,cComment,cCommentL,cCppString,cCharacter,cCppParen,cParenError,cNumbers,cCommentError,cSpaceError
   syn match     cEmbed		contained "\%(%:\|#\)\s*embed\>" nextgroup=cIncluded skipwhite transparent
   syn cluster	cPreProcGroup	add=cEmbed
 endif
 "syn match cLineSkip	"\\$"
-syn region	cDefine		start="^\s*\zs\%(%:\|#\)\s*\%(define\|undef\)\>" skip="\\$" end="$" keepend contains=ALLBUT,@cPreProcGroup,@Spell
-syn region	cPreProc	start="^\s*\zs\%(%:\|#\)\s*\%(pragma\>\|line\>\|warning\>\|warn\>\|error\>\)" skip="\\$" end="$" keepend contains=ALLBUT,@cPreProcGroup,@Spell
+syn region	cDefine		start="^\s*\%(/\*.\{-}\*/\s*\)*\%(%:\|#\)\s*\%(define\|undef\)\>" skip="\\$" end="$" keepend contains=ALLBUT,@cPreProcGroup,@Spell
+syn region	cPreProc	start="^\s*\%(/\*.\{-}\*/\s*\)*\%(%:\|#\)\s*\%(pragma\>\|line\>\|warning\>\|warn\>\|error\>\)" skip="\\$" end="$" keepend contains=ALLBUT,@cPreProcGroup,@Spell
 
 " Optional embedded Autodoc parsing
 if exists("c_autodoc")

This handles /**/ #include, several stacked comments before the #, and the %: digraph form, while strings, line comments and a mid-line # are still left alone. It does not cover a comment spanning multiple lines before the directive, nor a comment placed between # and the keyword.

The trade-off worth noting is that the extra \%(/\*.\{-}\*/\s*\)* is attempted at the start of every line in every C/C++ file, so it adds a little cost to the common case for a construct that seems quite rare in practice. Posting the analysis and patch here in case it's useful.


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/1005/4572925747@github.com>

dkearns

unread,
11:03 AM (4 hours ago) 11:03 AM
to vim/vim, Subscribed
dkearns left a comment (vim/vim#1005)

It would be better to use a line-start anchored optional chain of comments using nextgroup that terminated at preprocessor directives. This would allow multiline comments to precede the directive and would prevent unwanted background highlighting artifacts.

However, from a quick inspection, it appears that preprocessor directives are the only line-start anchored syntax groups in the file. Why don't we just drop that anchoring? The # isn't valid anywhere else at top level.


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/1005/4593830336@github.com>

Reply all
Reply to author
Forward
0 new messages