mirror of
https://github.com/vim/vim.git
synced 2026-02-16 20:26:59 +02:00
CI: Add C preproc indentation check to CI
closes: #19165 Signed-off-by: Hirohito Higashi <h.east.727@gmail.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
9fd2cae482
commit
1d4fe89054
1
.github/MAINTAINERS
vendored
1
.github/MAINTAINERS
vendored
@@ -699,6 +699,7 @@ runtime/syntax/xs.vim @petdance
|
||||
runtime/syntax/xslt.vim @Boobies
|
||||
runtime/syntax/zserio.vim @dpelle
|
||||
runtime/syntax/zsh.vim @chrisbra
|
||||
runtime/tools/preproc_indent.vim @h-east
|
||||
runtime/tutor/tutor1.eo @dpelle
|
||||
runtime/tutor/tutor1.fr @dpelle
|
||||
runtime/tutor/tutor1.ru @RestorerZ
|
||||
|
||||
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
@@ -84,7 +84,7 @@ jobs:
|
||||
architecture: arm64
|
||||
- features: normal
|
||||
compiler: gcc
|
||||
extra: [vimtags, proto]
|
||||
extra: [vimtags, proto, preproc_indent]
|
||||
- features: huge
|
||||
compiler: gcc
|
||||
extra: [no_x11_wl]
|
||||
@@ -363,6 +363,16 @@ jobs:
|
||||
true
|
||||
)
|
||||
|
||||
- name: Check preprocessor indent
|
||||
if: contains(matrix.extra, 'preproc_indent')
|
||||
run: |
|
||||
# This will exit with an error code if the files differ from source
|
||||
(
|
||||
"${SRCDIR}"/vim -u NONE --not-a-term -esNX +"cd runtime/tools" -S preproc_indent.vim
|
||||
git diff --exit-code -- src/*.[ch] src/xxd/xxd.c
|
||||
true
|
||||
)
|
||||
|
||||
- name: Generate gcov files
|
||||
if: matrix.coverage
|
||||
run: |
|
||||
|
||||
@@ -16,6 +16,9 @@ pltags.pl: Perl script to create a tags file from Perl scripts.
|
||||
|
||||
ref: Shell script for the K command.
|
||||
|
||||
preproc_indent.vim:
|
||||
Fix preprocessor indentation in Vim's C source code.
|
||||
|
||||
shtags.*: Perl script to create a tags file from a shell script.
|
||||
|
||||
vim132: Shell script to edit in 132 column mode on vt100 compatible
|
||||
|
||||
148
runtime/tools/preproc_indent.vim
Normal file
148
runtime/tools/preproc_indent.vim
Normal file
@@ -0,0 +1,148 @@
|
||||
vim9script
|
||||
# Script to fix preprocessor indentation in Vim's C source code.
|
||||
#
|
||||
# Usage: Vim -S <this-file>
|
||||
#
|
||||
# Specifications:
|
||||
# - If there is no indentation on the line containing the preprocessor
|
||||
# directive (`#`) following the first `#if~`, the indentation amount is
|
||||
# `nesting level - 1` spaces. Otherwise, the indentation amount is `nesting
|
||||
# level` spaces.
|
||||
# - However, if a preprocessor directive line is detected after the
|
||||
# corresponding `#endif` of the above `#if~`, the indentation amount is
|
||||
# fixed at `nesting level` and the line is reprocessed from the first line.
|
||||
# - If the preprocessor directive line ends with a line continuation (`\`) and
|
||||
# the next line is blank, the line continuation (`\`) and the next line are
|
||||
# deleted.
|
||||
#
|
||||
# Author: Hirohito Higashi (@h-east)
|
||||
# Last Update: 2026 Jan 12
|
||||
|
||||
def Get_C_source_files(): list<string>
|
||||
var list_of_c_files: list<string> = []
|
||||
if empty(list_of_c_files)
|
||||
var fpath = '../../src'
|
||||
var list = glob(fpath .. '/*.[ch]', 0, 1) + [fpath .. '/xxd/xxd.c']
|
||||
# Some files are auto-generated, so skip those
|
||||
list_of_c_files = filter(list, (i, v) => v !~ 'dlldata.c\|if_ole.h\|iid_ole.c')
|
||||
endif
|
||||
return list_of_c_files
|
||||
enddef
|
||||
|
||||
def FixPreprocessorIndent(fname: string)
|
||||
execute 'edit! ' .. fname
|
||||
|
||||
var nest: number = 0
|
||||
var indent_offset: number = 0 # -1 if whole-file guard detected
|
||||
var first_if_seen: bool = false
|
||||
var offset_determined: bool = false
|
||||
var whole_file_guard_ended = false
|
||||
|
||||
# First pass: remove trailing backslash + empty next line
|
||||
var lnum = 1
|
||||
while lnum <= line('$')
|
||||
var line: string = getline(lnum)
|
||||
if line =~# '^\s*#.*\\$'
|
||||
var next_line: string = getline(lnum + 1)
|
||||
if next_line =~# '^\s*$'
|
||||
# Remove backslash from current line and delete next line
|
||||
setline(lnum, substitute(line, '\s*\\$', '', ''))
|
||||
deletebufline('%', lnum + 1)
|
||||
continue # Don't increment, check same line again
|
||||
endif
|
||||
endif
|
||||
lnum += 1
|
||||
endwhile
|
||||
|
||||
# Second pass: fix preprocessor indent
|
||||
while true
|
||||
var is_reprocess: bool = false
|
||||
for l in range(1, line('$'))
|
||||
var line: string = getline(l)
|
||||
|
||||
# Skip if not a preprocessor directive
|
||||
if line !~# '^\s*#'
|
||||
continue
|
||||
endif
|
||||
|
||||
# Extract directive and current indent
|
||||
var match_li: list<string> = matchlist(line, '^\(\s*\)#\(\s*\)\(\w\+\)')
|
||||
if empty(match_li)
|
||||
continue
|
||||
endif
|
||||
var cur_spaces: string = !empty(match_li[1]) ? match_li[1] : match_li[2]
|
||||
var directive: string = match_li[3]
|
||||
|
||||
# If indent_offset != 0 but we encounter indented #, it's not whole-file
|
||||
# guard. Reprocess from line 1 with indent_offset=0
|
||||
if whole_file_guard_ended && offset_determined && indent_offset != 0
|
||||
indent_offset = 0
|
||||
nest = 0
|
||||
is_reprocess = true
|
||||
break
|
||||
endif
|
||||
|
||||
# After first #if, determine offset from first nested directive
|
||||
# Only check if # is at column 1 (no leading spaces)
|
||||
if first_if_seen && !offset_determined
|
||||
offset_determined = true
|
||||
if empty(cur_spaces)
|
||||
# No indent after first `#if` --> whole-file guard style
|
||||
indent_offset = -1
|
||||
endif
|
||||
endif
|
||||
|
||||
# Determine expected indent based on directive type
|
||||
var expected_indent: number
|
||||
|
||||
if directive ==# 'if' || directive ==# 'ifdef' || directive ==# 'ifndef'
|
||||
if !first_if_seen
|
||||
first_if_seen = true
|
||||
endif
|
||||
expected_indent = nest + indent_offset
|
||||
nest += 1
|
||||
elseif directive ==# 'elif' || directive ==# 'else'
|
||||
expected_indent = nest - 1 + indent_offset
|
||||
elseif directive ==# 'endif'
|
||||
nest -= 1
|
||||
if nest <= 0
|
||||
# Reset for next top-level block (but keep offset_determined)
|
||||
nest = 0
|
||||
whole_file_guard_ended = true
|
||||
endif
|
||||
expected_indent = nest + indent_offset
|
||||
else
|
||||
# Other directives (#define, #include, #error, #pragma, etc.)
|
||||
expected_indent = nest + indent_offset
|
||||
endif
|
||||
|
||||
if expected_indent < 0
|
||||
expected_indent = 0
|
||||
endif
|
||||
|
||||
# Build expected line
|
||||
var rest = substitute(line, '^\s*#\s*', '', '')
|
||||
var expected_line: string
|
||||
expected_line = '#' .. repeat(' ', expected_indent) .. rest
|
||||
|
||||
# Update line if different
|
||||
if line !=# expected_line
|
||||
setline(l, expected_line)
|
||||
endif
|
||||
endfor
|
||||
|
||||
if !is_reprocess
|
||||
break
|
||||
endif
|
||||
endwhile
|
||||
|
||||
update
|
||||
enddef
|
||||
|
||||
# Main
|
||||
for fname in Get_C_source_files()
|
||||
FixPreprocessorIndent(fname)
|
||||
endfor
|
||||
|
||||
qall!
|
||||
# vim: et ts=2 sw=0
|
||||
Reference in New Issue
Block a user