Skip to content

style: Convert continuation lines to tabs in Generals#2571

Open
bobtista wants to merge 10 commits intoTheSuperHackers:mainfrom
bobtista:bobtista/feat/continuation-indent-generals
Open

style: Convert continuation lines to tabs in Generals#2571
bobtista wants to merge 10 commits intoTheSuperHackers:mainfrom
bobtista:bobtista/feat/continuation-indent-generals

Conversation

@bobtista
Copy link
Copy Markdown

@bobtista bobtista commented Apr 9, 2026

Summary

  • Convert continuation lines (multi-line function args, initializer lists, etc.) to tabs
  • Continuation lines get parent statement depth + 1 tab
  • Closing delimiters on their own line go at parent depth
  • All changes are whitespace-only (git diff -w is empty)

Note on diff size

This PR currently shows a large diff because it includes Phase 1-3 changes
(#2561-#2564) in its branch history. After those PRs merge and this is
rebased onto main, the diff will shrink to just the continuation line delta.

Both parts

Script

The formatting script is included for reference. See scripts/cpp/convert_leading_spaces_to_tabs.py.

@bobtista
Copy link
Copy Markdown
Author

bobtista commented Apr 9, 2026

These should be rebased after 2561-2564 get merged, as they contain those changes. I couldn't set the base branch in github here because those branches only exist on my fork.

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Apr 12, 2026

Greptile Summary

This PR converts continuation lines (multi-line function arguments, initializer lists, constructor initializers, etc.) from leading spaces to tabs across ~481 C++ files in Generals/. All C++ changes are whitespace-only (git diff -w is empty), and the new scripts/cpp/convert_leading_spaces_to_tabs.py tool used to generate them is included for reference. The two script bugs previously flagged in earlier threads remain unaddressed in this version.

Confidence Score: 5/5

Safe to merge — all C++ changes are pure whitespace (git diff -w is empty) and the script is included for reference only.

All 480 C++ file changes are whitespace-only reformatting confirmed by diff inspection. The only new file is the Python formatting script, which has known bugs already flagged in prior review threads; those bugs affect future script runs but do not affect the correctness of the changes already committed to this PR. The sole remaining P2 finding is a missing license header on the script.

scripts/cpp/convert_leading_spaces_to_tabs.py — two previously-flagged script bugs remain unresolved, and the file lacks a GPL/copyright header.

Important Files Changed

Filename Overview
scripts/cpp/convert_leading_spaces_to_tabs.py New tool driving the reformatting; two previously-flagged bugs (is_closing_delimiter_line misses compound delimiters like });, and mid-line /* inside // comments triggers false block-comment state) remain unaddressed. No GPL header.
Generals/Code/GameEngine/Source/Common/GlobalData.cpp Whitespace-only: converts 2-space continuation lines to single tabs inside initializer lists and constructors.
Generals/Code/GameEngine/Include/Common/GlobalData.h Whitespace-only: aligns member declarations inside preprocessor-guarded blocks to tabs.
Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp Whitespace-only: cleans mixed space/tab indentation in several method bodies to pure tabs.
Generals/Code/GameEngine/Source/GameLogic/ScriptEngine/ScriptActions.cpp Whitespace-only reformatting of continuation lines.
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp Whitespace-only reformatting of continuation lines in W3D rendering code.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Read file as cp1252] --> B[Parse with tree-sitter C++ parser]
    B --> C{Too many parse errors?}
    C -- Yes --> D[Skip file]
    C -- No --> E[Iterate lines]
    E --> F{In block comment?}
    F -- Yes --> G[Pass through unchanged]
    F -- No --> H{In macro continuation?}
    H -- Yes --> G
    H -- No --> I{In asm block?}
    I -- Yes --> G
    I -- No --> J{Preprocessor directive?}
    J -- Yes --> K[Pass through, update pp_depth]
    J -- No --> L{Leading spaces only?}
    L -- No --> G
    L -- Yes --> M[Query AST node at col]
    M --> N{Continuation line?}
    N -- Yes --> O[depth = parent_depth + 1 or parent_depth if closing delimiter]
    N -- No --> P[depth = get_indent_depth node]
    O --> Q{Sanity check depth == 0?}
    P --> Q
    Q -- Fail --> G
    Q -- Pass --> R[Write tabs x depth + content]
    R --> S[Check for mid-line /* opening]
    S --> E
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: scripts/cpp/convert_leading_spaces_to_tabs.py
Line: 1

Comment:
**Missing GPL license header**

This is a newly created community file and has no license header in its prologue. Per the project's convention, newly created files should carry a copyright notice and, if applicable, the project's GPL header.

```suggestion
# Copyright 2026 TheSuperHackers
#
# This file is part of the Command & Conquer Generals open-source project.
# ... (GPL header) ...
"""
```

**Rule Used:** Only flag missing GPL license headers in file prol... ([source](https://app.greptile.com/review/custom-context?memory=1cd6ffcb-aeb0-457d-899f-184a39b97b1e))

How can I resolve this? If you propose a fix, please make it concise.

Reviews (2): Last reviewed commit: "style: Preserve indentation inside prepr..." | Re-trigger Greptile

Comment on lines +176 to +182
lines = content.split('\n')
# Preserve original line endings
if content.endswith('\n'):
lines = lines[:-1] # split adds an empty string after trailing \n

code_bytes = content.encode('utf-8')
parse_bytes = preprocess_for_parsing(code_bytes)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 /* inside // comments falsely opens block-comment state

stripped.rfind('/*') runs on the already-lstripped line content without first checking whether the /* appears after a //. A line like code(); // relies on /* old trick */ would set in_block_comment = True (since the */ is in the after_open slice but not correctly attributed), or if the */ were absent it would definitely set the flag — causing the immediately following line to be left un-converted. Consider skipping the mid-line /* check when a // precedes it:

# Track mid-line block comment opens (e.g. /**< trailing doc comments)
line_comment_pos = stripped.find('//')
last_open = stripped.rfind('/*')
if last_open >= 0 and (line_comment_pos < 0 or last_open < line_comment_pos):
    after_open = stripped[last_open + 2:]
    if '*/' not in after_open:
        in_block_comment = True
Prompt To Fix With AI
This is a comment left during a code review.
Path: scripts/cpp/convert_leading_spaces_to_tabs.py
Line: 176-182

Comment:
**`/*` inside `//` comments falsely opens block-comment state**

`stripped.rfind('/*')` runs on the already-lstripped line content without first checking whether the `/*` appears after a `//`. A line like `code(); // relies on /* old trick */` would set `in_block_comment = True` (since the `*/` is in the `after_open` slice but not correctly attributed), or if the `*/` were absent it would definitely set the flag — causing the immediately following line to be left un-converted. Consider skipping the mid-line `/*` check when a `//` precedes it:

```python
# Track mid-line block comment opens (e.g. /**< trailing doc comments)
line_comment_pos = stripped.find('//')
last_open = stripped.rfind('/*')
if last_open >= 0 and (line_comment_pos < 0 or last_open < line_comment_pos):
    after_open = stripped[last_open + 2:]
    if '*/' not in after_open:
        in_block_comment = True
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +147 to +153


def is_closing_delimiter_line(stripped):
"""Check if a line is just a closing delimiter, possibly with trailing punctuation.

Matches lines like ')', ');', ') {', ']);', etc.
These should be at the parent statement's depth, not +1.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 is_closing_delimiter_line misses compound closing delimiters

stripped.rstrip(';,{ ') strips trailing punctuation but stops before ). So }); produces remainder }), which is not in the recognized set (')', ']', '}'). Any line that closes both a brace and a parenthesis (e.g. closing a lambda-style init block or a chained call) would be treated as a continuation body line (depth+1) instead of a closing delimiter (depth+0), leaving it one tab too deeply indented.

def is_closing_delimiter_line(stripped):
    s = stripped.rstrip(';,{ ')
    # strip any number of interleaved closing delimiters, e.g. '})' or '])'
    s = s.rstrip(')]}')
    return s == '' or s in (')', ']', '}')
Prompt To Fix With AI
This is a comment left during a code review.
Path: scripts/cpp/convert_leading_spaces_to_tabs.py
Line: 147-153

Comment:
**`is_closing_delimiter_line` misses compound closing delimiters**

`stripped.rstrip(';,{ ')` strips trailing punctuation but stops before `)`. So `});` produces remainder `})`, which is not in the recognized set `(')', ']', '}')`. Any line that closes both a brace and a parenthesis (e.g. closing a lambda-style init block or a chained call) would be treated as a continuation body line (depth+1) instead of a closing delimiter (depth+0), leaving it one tab too deeply indented.

```python
def is_closing_delimiter_line(stripped):
    s = stripped.rstrip(';,{ ')
    # strip any number of interleaved closing delimiters, e.g. '})' or '])'
    s = s.rstrip(')]}')
    return s == '' or s in (')', ']', '}')
```

How can I resolve this? If you propose a fix, please make it concise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant