diff --git a/.github/workflows/whitespace_checks.yml b/.github/workflows/whitespace_checks.yml index cc16e7b22..7f6f615cc 100644 --- a/.github/workflows/whitespace_checks.yml +++ b/.github/workflows/whitespace_checks.yml @@ -14,6 +14,7 @@ on: - '**.sh' - '**.cmake' - '**.glsl' + - '**.lua' pull_request: paths: - '**.txt' @@ -24,6 +25,7 @@ on: - '**.sh' - '**.cmake' - '**.glsl' + - '**.lua' jobs: trailing_whitespaces: @@ -34,6 +36,32 @@ jobs: - name: Check trailing whitespaces run: if git ls-files | grep -E '\.txt$|\.md$|\.[ch]$|\.cpp$|\.hpp$|\.sh$|\.cmake$|\.glsl$' | xargs grep -n '\s$'; then echo -e "\033[0;31mFound trailing whitespace"; (exit 1); else (exit 0); fi + indent_spaces: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + # Line endings are already ensured by .gitattributes + # Multiple multline comments in one line is not supported by this check + # and there is no reason to use them + # So lines like: "/* */ /*" or "*/ a = 5; /*" will result in error + - name: Check for unsupported multiline comments + run: | + if git ls-files | grep -E '^src/.*\.cpp$|^src/.*\.[ch]$' | xargs grep -n '\*/.*/\*'; then echo -e "\033[0;31mUnsupported combination of multiline comments. New multiline comment should begin on new line."; (exit 1); else (exit 0); fi + if git ls-files | grep -E '\.lua$' | xargs grep -n -e '\]\].*--\[\['; then echo -e "\033[0;31mUnsupported combination of multiline comments. New multiline comment should begin on new line."; (exit 1); else (exit 0); fi + # This prepare files for final check + # See python script ./util/ci/indent_tab_preprocess.py for details. + - name: Preprocess files + run: | + git ls-files | grep -E '^src/.*\.cpp$|^src/.*\.[ch]$' | xargs -L 1 -P $(($(nproc) + 1)) python3 ./util/ci/indent_tab_preprocess.py "/*" "*/" + git ls-files | grep -E '\.lua$' | xargs -L 1 -P $(($(nproc) + 1)) python3 ./util/ci/indent_tab_preprocess.py "--[[" "]]" + # Check for bad indent. + # This runs over preprocessed files. + # If there is any remaining space on line beginning or after tab, + # error is generated + - name: Check indent spaces + run: | + if git ls-files | grep -E '^src/.*\.cpp$|^src/.*\.[ch]$|\.lua' | xargs grep -n -P '^\t*[ ]'; then echo -e "\033[0;31mFound incorrect indent whitespaces"; (exit 1); else (exit 0); fi + tabs_lua_api_files: runs-on: ubuntu-latest steps: diff --git a/util/ci/indent_tab_preprocess.py b/util/ci/indent_tab_preprocess.py new file mode 100644 index 000000000..50d7f7686 --- /dev/null +++ b/util/ci/indent_tab_preprocess.py @@ -0,0 +1,152 @@ +#!/usr/bin/python3 + +import sys +import re + +# preprocess files for indent check + +# Code processing: +# +# Tabs are kept. +# Spaces after tabs are removed if indent is not smaller than in previous line. +# +# Example: +# +# a = 6; +# b = 5; +# if ( +# ) { +# c = 7; +# } +# +# Result: +# +# a = 6; +# b = 5; +# if ( +# ) { +# c = 7; +# } + +# Multiline comments processing: +# +# It is expected that tabs indent from comment begining is +# used as indent on begining of every commented line. +# +# Example: +# +# /* +# A +# B +# C +# D +# */ +# /* +# R +# */ +# +# Result: +# +# /* +# A +# B +# C +# D +# */ +# /* +# *R +# */ + + +def main(): + if len(sys.argv) != 4: + #print("Bad arguments") + #print(sys.argv) + exit() + # multiline comment begining and end from command line + mlc_begin = sys.argv[1] + mlc_end = sys.argv[2] + file_name = sys.argv[3] + + mlc_end_len = len(mlc_end) + re_begin = re.escape(mlc_begin) + re_end = re.escape(mlc_end) + + re_mlc_begin = "^.*{}".format(re_begin) + re_mlc_begin_end = "^.*{}.*{}".format(re_begin, re_end) + re_mlc_end = "^.*{}".format(re_end) + + file = open(file_name, "r") + + lines = [] + + #print(re_mlc_begin) + #print(re_mlc_begin_end) + #print(re_mlc_end) + #print(file) + + # -1 means not in the multiline comment + # other values mean multiline comment indent in the number of tabs + limit = -1 + # this value stores the previous line indent in code mode (not in multiline comment) + prev = 80 + for line in file: + if limit == -1: + find = re.search(re_mlc_begin, line) + if find: + if not re.search(re_mlc_begin_end, line): + # enter in block comment mode + find = re.search("^\\s*", line) + limit = find.end() + find = re.search("^\\t*", line) + end = find.end() + if end < prev: + lines.append(line) + else: + # in this case, there can be allowed extra trailing whitespaces + # up to 3 trailing whitespaces are allowed + #find = re.search("^\\t+[ ]{0,3}", line) + # unlimited number of trailng whitespaces are allowed + find = re.search("^\\t+[ ]*", line) + fend = find.end() if find else 0 + if fend >= end: + find = re.search("^\\t*", line) + lines.append(line[0:find.end()] + line[fend:]) + else: + lines.append(line) + prev = end + else: + # in block comment mode + find = re.search(re_mlc_end, line) + if find: + # erase whitechars enabled for ignore, end in block comment mode + begin = find.end() - mlc_end_len + if begin > limit: + lines.append(line[0:limit] + line[begin:]) + else: + lines.append(line) + limit = -1 + else: + # erase whitechars enabled for ignore + find = re.search("^$", line) + if find: + lines.append(line) + else: + find = re.search("^\\s*", line) + if find: + end = find.end() + if end > limit: + lines.append(line[0:limit] + line[end:]) + else: + lines.append(line) + else: + lines.append(line) + + file.close() + file = open(file_name, "w") + for line in lines: + file.write(line) + file.close() + +if __name__ == "__main__": + main()