" Vim syntax file " Language: C " Maintainer: Bram Moolenaar " Last Change: 2023 Mar 08 " Quit when a (custom) syntax file was already loaded if exists("b:current_syntax") finish endif let s:cpo_save = &cpo set cpo&vim let s:ft = matchstr(&ft, '^\%([^.]\)\+') " check if this was included from cpp.vim let s:in_cpp_family = exists("b:filetype_in_cpp_family") " Optional embedded Autodoc parsing " To enable it add: let g:c_autodoc = 1 " to your .vimrc if exists("c_autodoc") syn include @cAutodoc :p:h/autodoc.vim unlet b:current_syntax endif " A bunch of useful C keywords syn keyword cStatement goto break return continue asm syn keyword cLabel case default syn keyword cConditional if else switch syn keyword cRepeat while for do syn keyword cTodo contained TODO FIXME XXX " It's easy to accidentally add a space after a backslash that was intended " for line continuation. Some compilers allow it, which makes it " unpredictable and should be avoided. syn match cBadContinuation contained "\\\s\+$" " cCommentGroup allows adding matches for special things in comments syn cluster cCommentGroup contains=cTodo,cBadContinuation " String and Character constants " Highlight special characters (those which have a backslash) differently syn match cSpecial display contained "\\\%(x\x\+\|\o\{1,3}\|.\|$\)" if !exists("c_no_utf") syn match cSpecial display contained "\\\%(u\x\{4}\|U\x\{8}\)" endif if !exists("c_no_cformat") " Highlight % items in strings. if !exists("c_no_c99") " ISO C99 syn match cFormat display "%\%(\d\+\$\)\=[-+' #0*]*\%(\d*\|\*\|\*\d\+\$\)\%(\.\%(\d*\|\*\|\*\d\+\$\)\)\=\%([hlLjzt]\|ll\|hh\)\=\%([aAbdiuoxXDOUfFeEgGcCsSpn]\|\[\^\=.[^]]*\]\)" contained else syn match cFormat display "%\%(\d\+\$\)\=[-+' #0*]*\%(\d*\|\*\|\*\d\+\$\)\%(\.\%(\d*\|\*\|\*\d\+\$\)\)\=\%([hlL]\|ll\)\=\%([bdiuoxXDOUfeEgGcCsSpn]\|\[\^\=.[^]]*\]\)" contained endif syn match cFormat display "%%" contained endif " cCppString: same as cString, but ends at end of line if s:in_cpp_family && !exists("cpp_no_cpp11") && !exists("c_no_cformat") " ISO C++11 syn region cString start=+\%(L\|u\|u8\|U\|R\|LR\|u8R\|uR\|UR\)\="+ skip=+\\\\\|\\"+ end=+"+ contains=cSpecial,cFormat,@Spell extend syn region cCppString start=+\%(L\|u\|u8\|U\|R\|LR\|u8R\|uR\|UR\)\="+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end='$' contains=cSpecial,cFormat,@Spell elseif s:ft ==# "c" && !exists("c_no_c11") && !exists("c_no_cformat") " ISO C99 syn region cString start=+\%(L\|U\|u8\)\="+ skip=+\\\\\|\\"+ end=+"+ contains=cSpecial,cFormat,@Spell extend syn region cCppString start=+\%(L\|U\|u8\)\="+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end='$' contains=cSpecial,cFormat,@Spell else " older C or C++ syn match cFormat display "%%" contained syn region cString start=+L\="+ skip=+\\\\\|\\"+ end=+"+ contains=cSpecial,cFormat,@Spell extend syn region cCppString start=+L\="+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end='$' contains=cSpecial,cFormat,@Spell endif syn region cCppSkip contained start="^\s*\%(%:\|#\)\s*\%(if\>\|ifdef\>\|ifndef\>\)" skip="\\$" end="^\s*\%(%:\|#\)\s*endif\>" contains=cSpaceError,cCppSkip syn cluster cStringGroup contains=cCppString,cCppSkip syn match cCharacter "L\='[^\\]'" syn match cCharacter "L'[^']*'" contains=cSpecial if exists("c_gnu") syn match cSpecialError "L\='\\[^'\"?\\abefnrtv]'" syn match cSpecialCharacter "L\='\\['\"?\\abefnrtv]'" else syn match cSpecialError "L\='\\[^'\"?\\abfnrtv]'" syn match cSpecialCharacter "L\='\\['\"?\\abfnrtv]'" endif syn match cSpecialCharacter display "L\='\\\o\{1,3}'" syn match cSpecialCharacter display "'\\x\x\{1,2}'" syn match cSpecialCharacter display "L'\\x\x\+'" if (s:ft ==# "c" && !exists("c_no_c11")) || (s:in_cpp_family && !exists("cpp_no_cpp11")) " ISO C11 or ISO C++ 11 if exists("c_no_cformat") syn region cString start=+\%(U\|u8\=\)"+ skip=+\\\\\|\\"+ end=+"+ contains=cSpecial,@Spell extend else syn region cString start=+\%(U\|u8\=\)"+ skip=+\\\\\|\\"+ end=+"+ contains=cSpecial,cFormat,@Spell extend endif syn match cCharacter "[Uu]'[^\\]'" syn match cCharacter "[Uu]'[^']*'" contains=cSpecial if exists("c_gnu") syn match cSpecialError "[Uu]'\\[^'\"?\\abefnrtv]'" syn match cSpecialCharacter "[Uu]'\\['\"?\\abefnrtv]'" else syn match cSpecialError "[Uu]'\\[^'\"?\\abfnrtv]'" syn match cSpecialCharacter "[Uu]'\\['\"?\\abfnrtv]'" endif syn match cSpecialCharacter display "[Uu]'\\\o\{1,3}'" syn match cSpecialCharacter display "[Uu]'\\x\x\+'" endif "when wanted, highlight trailing white space if exists("c_space_errors") if !exists("c_no_trail_space_error") syn match cSpaceError display excludenl "\s\+$" endif if !exists("c_no_tab_space_error") syn match cSpaceError display " \+\t"me=e-1 endif endif " This should be before cErrInParen to avoid problems with #define ({ xxx }) if exists("c_curly_error") syn match cCurlyError "}" syn region cBlock start="{" end="}" contains=ALLBUT,cBadBlock,cCurlyError,@cParenGroup,cErrInParen,cCppParen,cErrInBracket,cCppBracket,@cStringGroup,@Spell fold else syn region cBlock start="{" end="}" transparent fold endif " Catch errors caused by wrong parenthesis and brackets. " Also accept <% for {, %> for }, <: for [ and :> for ] (C99) " But avoid matching <::. syn cluster cParenGroup contains=cParenError,cIncluded,cSpecial,cCommentSkip,cCommentString,cComment2String,@cCommentGroup,cCommentStartError,cUserLabel,cBitField,cOctalZero,@cCppOutInGroup,cFormat,cNumber,cFloat,cOctal,cOctalError,cNumbersCom if exists("c_no_curly_error") if s:in_cpp_family && !exists("cpp_no_cpp11") syn region cParen transparent start='(' end=')' contains=ALLBUT,@cParenGroup,cCppParen,@cStringGroup,@Spell " cCppParen: same as cParen but ends at end-of-line; used in cDefine syn region cCppParen transparent start='(' skip='\\$' excludenl end=')' end='$' contained contains=ALLBUT,@cParenGroup,cParen,cString,@Spell syn match cParenError display ")" syn match cErrInParen display contained "^^<%\|^%>" else syn region cParen transparent start='(' end=')' contains=ALLBUT,cBlock,@cParenGroup,cCppParen,@cStringGroup,@Spell " cCppParen: same as cParen but ends at end-of-line; used in cDefine syn region cCppParen transparent start='(' skip='\\$' excludenl end=')' end='$' contained contains=ALLBUT,@cParenGroup,cParen,cString,@Spell syn match cParenError display ")" syn match cErrInParen display contained "^[{}]\|^<%\|^%>" endif elseif exists("c_no_bracket_error") if s:in_cpp_family && !exists("cpp_no_cpp11") syn region cParen transparent start='(' end=')' contains=ALLBUT,@cParenGroup,cCppParen,@cStringGroup,@Spell " cCppParen: same as cParen but ends at end-of-line; used in cDefine syn region cCppParen transparent start='(' skip='\\$' excludenl end=')' end='$' contained contains=ALLBUT,@cParenGroup,cParen,cString,@Spell syn match cParenError display ")" syn match cErrInParen display contained "<%\|%>" else syn region cParen transparent start='(' end=')' end='}'me=s-1 contains=ALLBUT,cBlock,@cParenGroup,cCppParen,@cStringGroup,@Spell " cCppParen: same as cParen but ends at end-of-line; used in cDefine syn region cCppParen transparent start='(' skip='\\$' excludenl end=')' end='$' contained contains=ALLBUT,@cParenGroup,cParen,cString,@Spell syn match cParenError display ")" syn match cErrInParen display contained "[{}]\|<%\|%>" endif else if s:in_cpp_family && !exists("cpp_no_cpp11") syn region cParen transparent start='(' end=')' contains=ALLBUT,@cParenGroup,cCppParen,cErrInBracket,cCppBracket,@cStringGroup,@Spell " cCppParen: same as cParen but ends at end-of-line; used in cDefine syn region cCppParen transparent start='(' skip='\\$' excludenl end=')' end='$' contained contains=ALLBUT,@cParenGroup,cErrInBracket,cParen,cBracket,cString,@Spell syn match cParenError display "[\])]" syn match cErrInParen display contained "<%\|%>" syn region cBracket transparent start='\[\|<::\@!' end=']\|:>' contains=ALLBUT,@cParenGroup,cErrInParen,cCppParen,cCppBracket,@cStringGroup,@Spell else syn region cParen transparent start='(' end=')' end='}'me=s-1 contains=ALLBUT,cBlock,@cParenGroup,cCppParen,cErrInBracket,cCppBracket,@cStringGroup,@Spell " cCppParen: same as cParen but ends at end-of-line; used in cDefine syn region cCppParen transparent start='(' skip='\\$' excludenl end=')' end='$' contained contains=ALLBUT,@cParenGroup,cErrInBracket,cParen,cBracket,cString,@Spell syn match cParenError display "[\])]" syn match cErrInParen display contained "[\]{}]\|<%\|%>" syn region cBracket transparent start='\[\|<::\@!' end=']\|:>' end='}'me=s-1 contains=ALLBUT,cBlock,@cParenGroup,cErrInParen,cCppParen,cCppBracket,@cStringGroup,@Spell endif " cCppBracket: same as cParen but ends at end-of-line; used in cDefine syn region cCppBracket transparent start='\[\|<::\@!' skip='\\$' excludenl end=']\|:>' end='$' contained contains=ALLBUT,@cParenGroup,cErrInParen,cParen,cBracket,cString,@Spell syn match cErrInBracket display contained "[);{}]\|<%\|%>" endif if s:ft ==# 'c' || exists("cpp_no_cpp11") syn region cBadBlock keepend start="{" end="}" contained containedin=cParen,cBracket,cBadBlock transparent fold endif "integer number, or floating point number without a dot and with "f". syn case ignore syn match cNumbers display transparent "\<\d\|\.\d" contains=cNumber,cFloat,cOctalError,cOctal " Same, but without octal error (for comments) syn match cNumbersCom display contained transparent "\<\d\|\.\d" contains=cNumber,cFloat,cOctal syn match cNumber display contained "\d\+\%(u\=l\{0,2}\|ll\=u\)\>" "hex number syn match cNumber display contained "0x\x\+\%(u\=l\{0,2}\|ll\=u\)\>" " Flag the first zero of an octal number as something special syn match cOctal display contained "0\o\+\%(u\=l\{0,2}\|ll\=u\)\>" contains=cOctalZero syn match cOctalZero display contained "\<0" "floating point number, with dot, optional exponent syn match cFloat display contained "\d\+\.\d*\%(e[-+]\=\d\+\)\=[fl]\=" "floating point number, starting with a dot, optional exponent syn match cFloat display contained "\.\d\+\%(e[-+]\=\d\+\)\=[fl]\=\>" "floating point number, without dot, with exponent syn match cFloat display contained "\d\+e[-+]\=\d\+[fl]\=\>" if !exists("c_no_c99") "hexadecimal floating point number, optional leading digits, with dot, with exponent syn match cFloat display contained "0x\x*\.\x\+p[-+]\=\d\+[fl]\=\>" "hexadecimal floating point number, with leading digits, optional dot, with exponent syn match cFloat display contained "0x\x\+\.\=p[-+]\=\d\+[fl]\=\>" endif " flag an octal number with wrong digits syn match cOctalError display contained "0\o*[89]\d*" syn case match if exists("c_comment_strings") " A comment can contain cString, cCharacter and cNumber. " But a "*/" inside a cString in a cComment DOES end the comment! So we " need to use a special type of cString: cCommentString, which also ends on " "*/", and sees a "*" at the start of the line as comment again. " Unfortunately this doesn't very well work for // type of comments :-( syn match cCommentSkip contained "^\s*\*\%($\|\s\+\)" syn region cCommentString contained start=+L\=\\\@" skip="\\$" end="$" keepend contains=cComment,cCommentL,cCppString,cCharacter,cCppParen,cParenError,cNumbers,cCommentError,cSpaceError syn match cPreConditMatch display "^\s*\zs\%(%:\|#\)\s*\%(else\|endif\)\>" 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 syn region cCppOutIf contained start="0\+" matchgroup=cCppOutWrapper end="^\s*\%(%:\|#\)\s*endif\>" contains=cCppOutIf2,cCppOutElse if !exists("c_no_if0_fold") syn region cCppOutIf2 contained matchgroup=cCppOutWrapper start="0\+" end="^\s*\%(%:\|#\)\s*\%(else\>\|elif\s\+\%(0\+\s*\%($\|//\|/\*\|&\)\)\@!\|endif\>\)"me=s-1 contains=cSpaceError,cCppOutSkip,@Spell fold else syn region cCppOutIf2 contained matchgroup=cCppOutWrapper start="0\+" end="^\s*\%(%:\|#\)\s*\%(else\>\|elif\s\+\%(0\+\s*\%($\|//\|/\*\|&\)\)\@!\|endif\>\)"me=s-1 contains=cSpaceError,cCppOutSkip,@Spell endif syn region cCppOutElse contained matchgroup=cCppOutWrapper start="^\s*\%(%:\|#\)\s*\%(else\|elif\)" end="^\s*\%(%:\|#\)\s*endif\>"me=s-1 contains=TOP,cPreCondit syn region cCppInWrapper start="^\s*\zs\%(%:\|#\)\s*if\s\+0*[1-9]\d*\s*\%($\|//\|/\*\||\)" end=".\@=\|$" contains=cCppInIf,cCppInElse fold syn region cCppInIf contained matchgroup=cCppInWrapper start="\d\+" end="^\s*\%(%:\|#\)\s*endif\>" contains=TOP,cPreCondit if !exists("c_no_if0_fold") syn region cCppInElse contained start="^\s*\%(%:\|#\)\s*\%(else\>\|elif\s\+\%(0*[1-9]\d*\s*\%($\|//\|/\*\||\)\)\@!\)" end=".\@=\|$" containedin=cCppInIf contains=cCppInElse2 fold else syn region cCppInElse contained start="^\s*\%(%:\|#\)\s*\%(else\>\|elif\s\+\%(0*[1-9]\d*\s*\%($\|//\|/\*\||\)\)\@!\)" end=".\@=\|$" containedin=cCppInIf contains=cCppInElse2 endif syn region cCppInElse2 contained matchgroup=cCppInWrapper start="^\s*\%(%:\|#\)\s*\%(else\|elif\)\%([^/]\|/[^/*]\)*" end="^\s*\%(%:\|#\)\s*endif\>"me=s-1 contains=cSpaceError,cCppOutSkip,@Spell syn region cCppOutSkip contained start="^\s*\%(%:\|#\)\s*\%(if\>\|ifdef\>\|ifndef\>\)" skip="\\$" end="^\s*\%(%:\|#\)\s*endif\>" contains=cSpaceError,cCppOutSkip syn region cCppInSkip contained matchgroup=cCppInWrapper start="^\s*\%(%:\|#\)\s*\%(if\s\+\%(\d\+\s*\%($\|//\|/\*\||\|&\)\)\@!\|ifdef\>\|ifndef\>\)" skip="\\$" end="^\s*\%(%:\|#\)\s*endif\>" containedin=cCppOutElse,cCppInIf,cCppInSkip contains=TOP,cPreProc 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 cLineSkip "\\$" 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 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 " Optional embedded Autodoc parsing if exists("c_autodoc") syn match cAutodocReal display contained "\%(//\|[/ \t\v]\*\|^\*\)\@2<=!.*" contains=@cAutodoc containedin=cComment,cCommentL syn cluster cCommentGroup add=cAutodocReal syn cluster cPreProcGroup add=cAutodocReal endif " be able to fold #pragma regions syn region cPragma start="^\s*#pragma\s\+region\>" end="^\s*#pragma\s\+endregion\>" transparent keepend extend fold " Highlight User Labels syn cluster cMultiGroup contains=cIncluded,cSpecial,cCommentSkip,cCommentString,cComment2String,@cCommentGroup,cCommentStartError,cUserCont,cUserLabel,cBitField,cOctalZero,cCppOutWrapper,cCppInWrapper,@cCppOutInGroup,cFormat,cNumber,cFloat,cOctal,cOctalError,cNumbersCom,cCppParen,cCppBracket,cCppString if s:ft ==# 'c' || exists("cpp_no_cpp11") syn region cMulti transparent start='?' skip='::' end=':' contains=ALLBUT,@cMultiGroup,@Spell,@cStringGroup endif " Avoid matching foo::bar() in C++ by requiring that the next char is not ':' syn cluster cLabelGroup contains=cUserLabel syn match cUserCont display "^\s*\zs\I\i*\s*:$" contains=@cLabelGroup syn match cUserCont display ";\s*\zs\I\i*\s*:$" contains=@cLabelGroup if s:in_cpp_family syn match cUserCont display "^\s*\zs\%(class\|struct\|enum\)\@!\I\i*\s*:[^:]"me=e-1 contains=@cLabelGroup syn match cUserCont display ";\s*\zs\%(class\|struct\|enum\)\@!\I\i*\s*:[^:]"me=e-1 contains=@cLabelGroup else syn match cUserCont display "^\s*\zs\I\i*\s*:[^:]"me=e-1 contains=@cLabelGroup syn match cUserCont display ";\s*\zs\I\i*\s*:[^:]"me=e-1 contains=@cLabelGroup endif syn match cUserLabel display "\I\i*" contained " Avoid recognizing most bitfields as labels syn match cBitField display "^\s*\zs\I\i*\s*:\s*[1-9]"me=e-1 contains=cType syn match cBitField display ";\s*\zs\I\i*\s*:\s*[1-9]"me=e-1 contains=cType if exists("c_minlines") let b:c_minlines = c_minlines else if !exists("c_no_if0") let b:c_minlines = 50 " #if 0 constructs can be long else let b:c_minlines = 15 " mostly for () constructs endif endif if exists("c_curly_error") syn sync fromstart else exec "syn sync ccomment cComment minlines=" . b:c_minlines endif " Define the default highlighting. " Only used when an item doesn't have highlighting yet hi def link cFormat cSpecial hi def link cCppString cString hi def link cCommentL cComment hi def link cCommentStart cComment hi def link cLabel Label hi def link cUserLabel Label hi def link cConditional Conditional hi def link cRepeat Repeat hi def link cCharacter Character hi def link cSpecialCharacter cSpecial hi def link cNumber Number hi def link cOctal Number hi def link cOctalZero PreProc " link this to Error if you want hi def link cFloat Float hi def link cOctalError cError hi def link cParenError cError hi def link cErrInParen cError hi def link cErrInBracket cError hi def link cCommentError cError hi def link cCommentStartError cError hi def link cSpaceError cError hi def link cWrongComTail cError hi def link cSpecialError cError hi def link cCurlyError cError hi def link cOperator Operator hi def link cStructure Structure hi def link cTypedef Structure hi def link cStorageClass StorageClass hi def link cInclude Include hi def link cPreProc PreProc hi def link cDefine Macro hi def link cIncluded cString hi def link cError Error hi def link cStatement Statement hi def link cCppInWrapper cCppOutWrapper hi def link cCppOutWrapper cPreCondit hi def link cPreConditMatch cPreCondit hi def link cPreCondit PreCondit hi def link cType Type hi def link cConstant Constant hi def link cCommentString cString hi def link cComment2String cString hi def link cCommentSkip cComment hi def link cString String hi def link cComment Comment hi def link cSpecial SpecialChar hi def link cTodo Todo hi def link cBadContinuation Error hi def link cCppOutSkip cCppOutIf2 hi def link cCppInElse2 cCppOutIf2 hi def link cCppOutIf2 cCppOut hi def link cCppOut Comment let b:current_syntax = "c" unlet s:ft let &cpo = s:cpo_save unlet s:cpo_save " vim: ts=8