codekingpro/portable-devtools
114k
1vim9script2# Script to fix preprocessor indentation in Vim's C source code.3#4# Usage: Vim -S <this-file>5#6# Specifications:7# - If there is no indentation on the line containing the preprocessor8# directive (`#`) following the first `#if~`, the indentation amount is9# `nesting level - 1` spaces. Otherwise, the indentation amount is `nesting10# level` spaces.11# - However, if a preprocessor directive line is detected after the12# corresponding `#endif` of the above `#if~`, the indentation amount is13# fixed at `nesting level` and the line is reprocessed from the first line.14# - If the preprocessor directive line ends with a line continuation (`\`) and15# the next line is blank, the line continuation (`\`) and the next line are16# deleted.17#18# Author: Hirohito Higashi (@h-east)19# Last Update: 2026 Apr 0220 21def Get_C_source_files(): list<string>22 var list_of_c_files: list<string> = []23 if empty(list_of_c_files)24 var fpath = '../../src'25 var list = glob(fpath .. '/*.[ch]', 0, 1) + [fpath .. '/xxd/xxd.c']26 # Some files are auto-generated, so skip those27 list_of_c_files = filter(list, (i, v) => v !~ 'dlldata.c\|if_ole.h\|iid_ole.c')28 endif29 return list_of_c_files30enddef31 32def FixPreprocessorIndent(fname: string)33 execute 'noswapfile edit! ' .. fname34 35 var nest: number = 036 var indent_offset: number = 0 # -1 if whole-file guard detected37 var first_if_seen: bool = false38 var offset_determined: bool = false39 var whole_file_guard_ended = false40 41 # First pass: remove trailing backslash + empty next line42 var lnum = 143 while lnum <= line('$')44 var line: string = getline(lnum)45 if line =~# '^\s*#.*\\$'46 var next_line: string = getline(lnum + 1)47 if next_line =~# '^\s*$'48 # Remove backslash from current line and delete next line49 setline(lnum, substitute(line, '\s*\\$', '', ''))50 deletebufline('%', lnum + 1)51 continue # Don't increment, check same line again52 endif53 endif54 lnum += 155 endwhile56 57 # Second pass: fix preprocessor indent58 while true59 var is_reprocess: bool = false60 for l in range(1, line('$'))61 var line: string = getline(l)62 63 # Skip if not a preprocessor directive64 if line !~# '^\s*#'65 continue66 endif67 68 # Extract directive and current indent69 var match_li: list<string> = matchlist(line, '^\(\s*\)#\(\s*\)\(\w\+\)')70 if empty(match_li)71 continue72 endif73 var cur_spaces: string = !empty(match_li[1]) ? match_li[1] : match_li[2]74 var directive: string = match_li[3]75 76 # If indent_offset != 0 but we encounter indented #, it's not whole-file77 # guard. Reprocess from line 1 with indent_offset=078 if whole_file_guard_ended && offset_determined && indent_offset != 079 indent_offset = 080 nest = 081 is_reprocess = true82 break83 endif84 85 # After first #if, determine offset from first nested directive86 # Only check if # is at column 1 (no leading spaces)87 if first_if_seen && !offset_determined88 offset_determined = true89 if empty(cur_spaces)90 # No indent after first `#if` --> whole-file guard style91 indent_offset = -192 endif93 endif94 95 # Determine expected indent based on directive type96 var expected_indent: number97 98 if directive ==# 'if' || directive ==# 'ifdef' || directive ==# 'ifndef'99 if !first_if_seen100 first_if_seen = true101 endif102 expected_indent = nest + indent_offset103 nest += 1104 elseif directive ==# 'elif' || directive ==# 'else'105 expected_indent = nest - 1 + indent_offset106 elseif directive ==# 'endif'107 nest -= 1108 if nest <= 0109 # Reset for next top-level block (but keep offset_determined)110 nest = 0111 whole_file_guard_ended = true112 endif113 expected_indent = nest + indent_offset114 else115 # Other directives (#define, #include, #error, #pragma, etc.)116 expected_indent = nest + indent_offset117 endif118 119 if expected_indent < 0120 expected_indent = 0121 endif122 123 # Build expected line124 var rest = substitute(line, '^\s*#\s*', '', '')125 var expected_line: string126 expected_line = '#' .. repeat(' ', expected_indent) .. rest127 128 # Update line if different129 if line !=# expected_line130 setline(l, expected_line)131 endif132 endfor133 134 if !is_reprocess135 break136 endif137 endwhile138 139 update140enddef141 142# Main143for fname in Get_C_source_files()144 FixPreprocessorIndent(fname)145endfor146 147qall!148# vim: et ts=2 sw=0149 