본문 바로가기
Linux/vim

[vim] C언어 #ifdef

by 暻煥 2024. 2. 3.

컴파일되지 않는 Code Block을 비활성화하는 방법을 소개한다.


사용 가능한 명령어

:Define xxx  #ifdef xxx 영역을 활성화
:Undefine xxx #idef xxx 영역을 비활성화

 


현재경로의 .defined 파일에 아래와 같이 미리 추가하는 것도 가능하다

 

undefined=xxx
defined=yyy
defined=zzz

나는 ~/.vimrc 파일에 단축키를 추가해서 사용중이다.

  • 활성화 : " \ + e + d "
  • 비활성화 : " \ + u + d "
nmap <leader>ed :Define <C-R>=expand("<cword>")<CR><CR>
nmap <leader>ud :Undefine <C-R>=expand("<cword>")<CR><CR>

설치 방법

 

아래의 vim script를 ~/.vim/after/syntax/c.vim 위치에 복사 붙여 넣기 한다.

(만약 해당 파일이 없으면 만든다.)

 

" Description: C Preprocessor Highlighting
" Language: Preprocessor on top of c, cpp, idl syntax
" Author: Michael Geddes <vimmer@frog.wheelycreek.net>
" Modified: July 2011
" Version: 3.2
"
" Copyright 2002-2011 Michael Geddes
" Please feel free to use, modify & distribute all or part of this script,
" providing this copyright message remains.
" I would appreciate being acknowledged in any derived scripts, and would
" appreciate and welcome any updates, modifications or suggestions.

" Usage:
" Use as a syntax plugin (source ifdef.vim from ~/vimfiles/after/syntax/cpp.vim -
" also c.vim and idl.vim )
"
" #ifdef defintions are considered to be in 1 of 3 states, defined, not-defined
" or don't know (the default).
"
" To specify which defines are valid/invalid, the scripts searches two places.
"   * Firstly, the current directory, and all higher directories are search for
"     the file specified in g:ifdef_filename - which defaults to '.defines'
"     (first one found gets used)
"   * Secondly, modelines prefixed by 'vim_ifdef:' are searched for within the
"     current file being loaded.  You can either use the vim default settings
"     for modeline/modelines, or these can be overridden by using
"     ifdef_modeline and ifdef_modelines.
" The defines/undefines are addeded in order.  Lines must be prefixed with
" 'defined=' or 'undefined=' and contain a ';' or ',' separated list of keywords.
" Keywords may be regular expressions, though use of '\k' rather than '.' is
" highly recommended.
"
" Specifying '*' by itself equates to '\k\+' and allows
" setting of the default to be defined/undefined.
" Caveat:
" Don't expect an #else/#endif inside an open bracket '(' to match the #ifdef
" correctly.  This is almost impossible to do without messing up the error-in
" bracket code.
" Currently #else/#endif that are inside brackets where the #ifdef is outside
" will be highlighted as 'Special', you may wish to hilight it as an error. >
"   hi link ifdefElseEndifInBracketError Error
"
" NB: On 16bit and win32s windows builds, the default for ifdef_filename is
" '_defines'.  I've assumed that win32 apps can handle '.defines'.
"
" Examples:
" ----.defines-------
" undefined=*
" defined=WIN32;__MT
" ----.defines----------
" undefined=DEBUG,DBG
" ----(modelines) samples.cpp-------
" /* vim_ifdef: defined=WIN32 */
" // vim_ifdef: undefine=DBG
"
" Settings:
" g:ifdef_modeline overrides &modeline for whether to use the ifdef modelines.
" g:ifdef_modelines overrides &modelines for how many lines to look at.
"
" Hilighting:
" ifdefIfZero (default Comment)                     - Inside #if 0 highlighting
" ifdefUndefined (default Debug)                    - The #ifdef/#else/#endif/#elseif
" ifdefNeutralDefine (default PreCondit)            - Other defines where the defines are valid
" ifdefInBadPreCondit (default PreCondit)           - The #ifdef/#else/#endif/#elseif in an invalid section.
" ifdefInUndefinedComment (default ifdefUndefined)  - A C/C++ comment inside a an invalid section
" ifdefPreCondit1 (defualt PreCondit)               - The #ifdef/#else/#endif/#elseif in a valid section
" ifdefElseEndifInBracketError (default Special)    - Usupported #else/#endif inside a bracket '('.
" ------------------------------
" Alternate (old) usage.
" Call CIfDef() after sourcing the c/cpp syntax file.
" Use :Define <keyword> or function Define(keyword) to mark a preprocessor symbol as being defined.
" Use  :Undefine <keyword> or function Undefine(keyword) to mark a preprocessor symbol as not being defined.
" call Undefine('\k\+') will mark all words that aren't explicitly 'defined' as undefined.
"
" History:
" 3.2
"  - Fix by Dr. Chip for C comment at endof ifdef continuing over line.
" 3.1
"  - Wu Hong fixed bug in Undefine()
"  - Stop errors in script due to undefined hl being cleared.
"  - Added :Define, :Undefine with completion
" 3.0
"   - Renamed everything to be more clear, and reversed some of the include
"   groups from exclude groups - make use of ALL in groups. This seems to have
"   fixed most bugs, but may have reintroduced some as well, however doing it
"   this way round should prevent most interaction with other scripts.
"   KNOWN issues: Comments at the end of #ifndef, #else don't always highlight.
"   - Actually clear the cPreCondit highlight group as we are taking it over.
"     Ditto cCppOut (#if 0) handling
" 2.4
"   - Prevent interaction with c brackets (Picked up by Dany St-Amant)
" 2.3
"   - Clean up some of the comments
"   - Ignore whitespace in .defines files. (TODO: Credit person who suggested this!)
"   - Add comments for highlighting groups.
" 2.2
"   - Add support for idl files.
"   - Suggestions from
"     - Check for 'shell' type and 'shellslash'
"     - Don't use has("windows"), which is different.
" 2.1
"   - Fixes from Erik Remmelzwaal
"     - Need to use %:p:h instead of %:h to get directory
"     - Documentation fixes/updates
"     - Added ability to parse ',' or ';' separated lists instead of fixing
"       the documentation ;)
" 2.0:
"   - Added loading of ifdefs
"     - via ifdef modelines
"     - via .defines files
"   - Added missing highlight link.. relinked ifdefed out comments to special
"   - Conditional loading of functions
" 1.3:
"   - Fix some group names
" 1.2:
"   - Fix some errors in the tidy-up with group names
"   - Make it a propper syntax file - to be added onto c.vim / cpp.vim
"   - Use standard highlight groups - PreProc, Comment and Debug
"   - Use 'default' highlight syntax.
" 1.1:
"   - Tidy-up
"   - Make sure CIfDef gets called.
"   - Turn of #if 0 properly - this script handles it!
"   - prefix 'ifdef' to all groups
"   - Use some c 'clusters' to get rid of some inhouse code
"
"   TODO: (Feel free to contact me with suggestions)
"     - Allow defined= and undefined= on the same line in modelines.
"

"
if exists('b:current_syntax') && b:current_syntax =~ 'ifdef'
  finish
endif

if !exists('b:current_syntax')
  let b:current_syntax = "ifdef"
else
  let b:current_syntax = b:current_syntax.'+ifdef'
endif


" Settings for the c.vim highlighting .. disable the default preprocessor handling.
let c_no_if0=1
if hlexists('cPreCondit')
  syn clear cPreCondit
endif
if hlexists('cCppOut')
  syn clear cCppOut
endif

if hlexists('cCppOut2')
  syn clear cCppOut2
endif
if hlexists('cCppSkip')
  syn clear cCppSkip
endif

" Reload protection
if !exists('ifdef_loaded') || exists('ifdef_debug')
  let ifdef_loaded=1
else
  call s:CIfDef(1)
  call IfdefLoad()
  finish
endif

if !exists('ifdef_filename')
  if has('dos16') || has('gui_win32s') || has('win16')
    let ifdef_filename='_defines'
  else
    let ifdef_filename='.defines'
  endif
endif

" Reload CIfDef - backwards compatible
function! CIfDef()
  call s:CIfDef(0)
endfun

" Load the C ifdef highlighting.
function! s:CIfDef(force)
  if ! a:force &&  exists('b:ifdef_syntax')
      return
  endif
  let b:ifdef_syntax=1

  " Some useful groups.
  syn cluster ifdefClusterCommon contains=TOP,cPreCondit
  syn cluster ifdefClusterNeutral contains=@ifdefClusterCommon,ifdefDefined,ifdefUndefined,ifdefNeutral.*,ifdefInNeutralIf
  syn cluster ifdefClusterDefined contains=@ifdefClusterCommon,ifdefDefined,ifdefUndefined,ifdefNeutral.*,ifdefInNeutralIf
  syn cluster ifdefClusterUndefined contains=ifdefInUndefinedComment,ifdefInUndefinedIf

  syn region ifdefCommentAtEnd contained start=+//+ end='$' skip='\\$' contains=cSpaceError
  syn region ifdefCommentAtEnd contained extend start=+/\*+ end='\*/' contains=cSpaceError nextgroup=ifdefCommentAtEnd


  " #if .. #endif  nesting
  syn region ifdefOutsideNeutral matchgroup=ifdefPreCondit1 start="^\s*#\s*\(if\>\|ifdef\>\|ifndef\>\)\(/[/*]\@!\|[^/]\)*" matchgroup=ifdefPreCondit1 end="^\s*#\s*endif\>.*$" contains=@ifdefClusterNeutral,ifdefElseInDefinedNeutral,cComment,cCommentL
  " #if .. #endif  nesting
  syn region ifdefInNeutralIf matchgroup=ifdefPreCondit1 start="^\s*#\s*\(if\>\|ifdef\>\|ifndef\>\).*$" matchgroup=ifdefPreCondit1 end="^\s*#\s*endif\>.*$" contained contains=@ifdefClusterNeutral,ifdefElseInDefinedNeutral,cComment,cCommentL
  syn region ifdefInUndefinedIf matchgroup=ifdefPreConditBad start="^\s*#\s*\(if\>\|ifdef\>\|ifndef\>\).*$" matchgroup=ifdefPreConditBad end="^\s*#\s*endif\>" contained contains=@ifdefClusterUndefined,ifdefElseInUndefinedNeutral,cCommentL,cComment skipwhite nextgroup=ifdefCommentAtEnd

  " #else highlighting for nesting
  syn match ifdefElseInDefinedNeutral "^\s*#\s*\(elif\>\|else\>\)" contained skipwhite
  syn match ifdefElseInUndefinedNeutral "^\s*#\s*\(elif\>\|else\>\)" contained skipwhite nextgroup=ifdefCommentAtEnd

  " #if 0 matching
  syn region ifdefUndefined  matchgroup=ifdefPreCondit4 start="^\s*#\s*if\s\+0\>" matchgroup=ifdefPreCondit4 end="^\s*#\s*endif" contains=@ifdefClusterUndefined,ifdefElseInUndefinedToDefined

  " #else handling .. switching to out group
  syn region ifdefElseInDefinedToUndefined matchgroup=ifdefPreCondit3 start="^\s*#\s*else\>" end="^\s*#\s*endif\>"me=s-1 contained contains=@ifdefClusterUndefined
  " #else handling .. switching to in group
  syn region ifdefElseInUndefinedToDefined matchgroup=ifdefPreCondit6 start="^\s*#\s*else\>" end="^\s*#\s*endif\>"me=s-1 contained contains=@ifdefClusterDefined

  " Handle #else, #endif inside a bracket. Not really an error, but impossible
  " to work out.
  syn match ifdefElseEndifInBracketError "^\s*#\s*\(elif\>\|else\>\|endif\>\)" contained containedin=cParen

  " comment highlighting
  syntax region ifdefInUndefinedComment start="/\*" end="\*/" contained contains=cCharacter,cNumber,cFloat,cSpaceError
  syntax match  ifdefInUndefinedComment "//.*" contained contains=cCharacter,cNumber,cSpaceError

  " Now add to all the c/rc/idl clusters
  syn cluster cParenGroup add=ifdefInUndefined.*,ifdefElse.*,ifdefInNeutralIf
  syn cluster cPreProcGroup add=ifdefInUndefined.*,ifdefElse.*,ifdefInNeutralIf
  syn cluster cMultiGroup add=ifdefInUndefined.*,ifdefElse.*,ifdefInNeutralIf
  syn cluster rcParenGroup add=ifdefInUndefined.*,ifdefElse.*,ifdefInNeutralIf
  syn cluster rcGroup add=ifdefInUndefined.*,ifdefElse.*,ifdefInNeutralIf

  " Include group - so reverse
  syn cluster idlCommentable add=ifdefUndefined,ifdefDefined

  " Start sync from scratch
  syn sync fromstart

endfunction

" Mark a (regexp) definition as defined.
" Note that the regular expression is use with \< \> arround it.
fun! Define(define)
  call CIfDef()
  exe 'syn region ifdefUndefined  matchgroup=ifdefPreCondit4 start="^\s*#\s*ifndef\s\+'.a:define.'\>" matchgroup=ifdefPreCondit4 end="^\s*#\s*endif" contains=@ifdefClusterUndefined,ifdefElseInUndefinedToDefined'
  exe 'syn region ifdefDefined matchgroup=ifdefPreCondit5 start="^\s*#\s*ifdef\s\+'.a:define.'\>" matchgroup=ifdefPreCondit5 end="^\s*#\s*endif" contains=@ifdefClusterDefined,ifdefElseInDefinedToUndefined'
endfun

" Mark a (regexp) definition as not defined.
" Note that the regular expression is use with \< \> arround it.
fun! Undefine(define)
  call CIfDef()
  exe 'syn region ifdefUndefined  matchgroup=ifdefPreCondit4 start="^\s*#\s*ifdef\s\+'.a:define.'\>" matchgroup=ifdefPreCondit4 end="^\s*#\s*endif" contains=@ifdefClusterUndefined,ifdefElseInUndefinedToDefined'
  exe 'syn region ifdefDefined matchgroup=ifdefPreCondit5 start="^\s*#\s*ifndef\s\+'.a:define.'\>" matchgroup=ifdefPreCondit5 end="^\s*#\s*endif" contains=@ifdefClusterDefined,ifdefElseInDefinedToUndefined'

endfun

" Find the modelines for vim_ifdef between l1 and l2.
fun! s:GetModelines( l1, l2)
  if a:l1==0 | return ''| endif
  let c=a:l1
  let lines=''
  let reA='\<vim_ifdef:'
  let reB='\<vim_ifdef:\s*\zs\(.\{-}\)\ze\s*\(\*/\s*\)\=$'
  while c <= a:l2
    let l=getline(c)
    if l =~reA
      let lines=lines.matchstr(l,reB)."\n"
    endif
    let c=c+1
  endwhile
  return lines
endfun

" Return the modelines based on the settings.
fun! s:ReadDefineModeline()
  " Check for modeline=enable/disable
  if (exists('g:ifdef_modeline') ? (g:ifdef_modeline==0):(!&modeline)) | return | endif
  let defmodelines= (exists('g:ifdef_modelines')?(g:ifdef_modelines):(&modelines))
  if ((2*defmodelines)>=line('$'))
    " Check whole file
    return s:GetModelines( 1,line('$'))
  else
    " Check top & bottom
    return s:GetModelines( 1,defmodelines).s:GetModelines(line('$')-defmodelines,line('$'))
  endif
endfun

" Check a directory for the specified file
function! s:CheckDirForFile(directory,file)
  let aborted=0
  let cur=a:directory
  let slsh= ((cur=~'[/\\]$') ? '' : '/')
  while !filereadable(cur.slsh.a:file)
    let nxt=fnamemodify(cur,':h')
    let aborted=(nxt==cur)
    if aborted!=0 | break |endif
    let cur=nxt
    let slsh=((cur=~'[/\\]$') ? '' : '/')
  endwhile
  " Check the two cases we haven't tried
  if aborted | let aborted=!filereadable(cur.slsh.a:file) | endif

  return ((aborted==0) ? cur.slsh : '')
endfun

" Read a .defines file in the specified (or higher) directory
fun! s:ReadFile( dir, filename)
  let realdir= s:CheckDirForFile( a:dir, a:filename )
  if realdir=='' | return '' | endif
  " if has('dos16') || has('gui_win32s') || has('win16') || ha
  if !has('unix') && !&shellslash && &shell !~ 'sh[a-z.]*$'
    return system('type "'.fnamemodify(realdir,':gs?/?\\?.').a:filename.'"')
  else
    return system( 'cat "'.escape(realdir.a:filename,'\$*').'"' )
  endif
endfun

" Define/undefine a ';' or ',' separated list
fun! s:DoDefines( define, defines)
  let reBreak='[^;,]*'
  let here=0
  let back=strlen(a:defines)
  while here<back
    let idx=matchend(a:defines,reBreak,here)+1
    if idx<0 | let idx=back|endif
    let part=strpart(a:defines,here,(idx-here)-1)
    let part=substitute(substitute(part,'^\s*','',''),'\s*$','','')
    if part != ''
      if part=='*' | let part='\k\+' | endif
      if a:define
        call Define(part)
      else
        call Undefine(part)
      endif
    endif
    let here=idx
  endwhile
endfun

" Load ifdefs for a file
fun! IfdefLoad()
  let txt=s:ReadFile(expand('%:p:h'),g:ifdef_filename)
  if txt!='' && txt !~"[\r\n]$" | let txt=txt."\n" | endif
  let txt=txt.s:ReadDefineModeline()
  let reCr="[^\n\r]*[\r\n]*"
  let reDef='^\s*\(un\)\=defined\=\s*=\s*'
  let back=strlen(txt)
  let here=0
  while here < back
    let idx=matchend(txt,reCr,here)
    if idx < 0 | let idx=back|endif
    let part=strpart(txt,here,(idx-here))
    if part=~reDef
      let un=(part[0]=='u')
      let rest=substitute(strpart(part,matchend(part,reDef)),"[\r\n]*$",'','')
      call s:DoDefines(!un , rest)
    endif
    let here=idx
  endwhile
endfun

"  hi default ifdefIfZero term=bold ctermfg=1 gui=italic guifg=DarkSeaGreen
hi default link ifdefIfZero Comment
hi default link ifdefCommentAtEnd Comment
hi default link ifdefUndefined Debug
hi default link ifdefInUndefinedIf ifdefUndefined
hi default link ifdefElseInDefinedToUndefined ifdefUndefined
hi default link ifdefNeutralDefine PreCondit
hi default link ifdefNeutralPreProc PreProc
hi default link ifdefElseInDefinedNeutral PreCondit
hi default link ifdefElseInUndefinedNeutral PreCondit
hi default link ifdefInBadPreCondit PreCondit
hi default link ifdefInUndefinedComment ifdefUndefined
hi default link ifdefOutPreCondit ifdefInBadPreCondit
hi default link ifdefPreCondit1 PreCondit
hi default link ifdefPreConditBad ifdefInBadPreCondit
hi default link ifdefPreCondit3 ifdefPreCondit1
hi default link ifdefPreCondit4 ifdefPreCondit1
hi default link ifdefPreCondit5 ifdefPreCondit1
hi default link ifdefPreCondit6 ifdefPreCondit1
hi default link ifdefElseEndifInBracketError Special

call s:CIfDef(1)
call IfdefLoad()

fun! Find_defines(A, L, P)
  " Use dictionary to fix uniqueness
  let l:ret={}
  let cur=1
  while cur <= line('$')
    let line=getline(cur)
    if line =~ '^\s*#\s*ifn\=def\>\s\+'.a:A
      let l:find=matchstr(line,'^\s*#\s*ifn\=def\s*\zs\k\+')
      let ret[l:find]=1
    endif
    let cur+=1
  endwhile
  " Return the sorted keys of the dictionary
  return sort(keys(ret))
endfun

com! -complete=customlist,Find_defines -nargs=1 Define call Define(<q-args>)
com! -complete=customlist,Find_defines -nargs=1 Undefine call Undefine(<q-args>)

" vim:ts=2 sw=2 et

(출처 : https://www.vim.org/scripts/script.php?script_id=7)

'Linux > vim' 카테고리의 다른 글

[vim] 임의 위치의 tags & cscope 추가  (0) 2024.09.21
[vim][c] syntax highlight  (0) 2024.02.03
[vim] mark 설치 (형광펜 기능)  (0) 2024.02.03
vim-highlighter 설치  (0) 2024.02.03
NERDTree, TagList, SourceExplorer 설치  (0) 2024.02.03