Skip to content

style: Convert leading spaces to tabs in GeneralsMD GameEngine#2563

Open
bobtista wants to merge 2 commits intoTheSuperHackers:mainfrom
bobtista:bobtista/feat/access-spec-indent-generalsmd-engine
Open

style: Convert leading spaces to tabs in GeneralsMD GameEngine#2563
bobtista wants to merge 2 commits intoTheSuperHackers:mainfrom
bobtista:bobtista/feat/access-spec-indent-generalsmd-engine

Conversation

@bobtista
Copy link
Copy Markdown

@bobtista bobtista commented Apr 9, 2026

Summary

  • Convert leading spaces/mixed whitespace to tabs, including access specifier indentation
  • All changes are whitespace-only (git diff -w is empty)
  • Uses tree-sitter-cpp for accurate C++ parsing with macro preprocessing

Access specifiers (public:/private:/protected:) are placed at the class
brace level, matching the existing codebase convention.

Script

The formatting script is included in the PR for reference but is not intended
to be merged — it shows how the changes were generated.

See scripts/cpp/convert_leading_spaces_to_tabs.py for details.

Part 3 of 4 — GeneralsMD/Code/GameEngine/ (356 files).
See also: #2561, #2562, #2564.

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Apr 9, 2026

Greptile Summary

Whitespace-only reformatting (Part 3 of 4) converting leading spaces to tabs across 356 C++ files in GeneralsMD/Code/GameEngine/. Verified clean: git diff -w produces no output. The conversion script (scripts/cpp/convert_leading_spaces_to_tabs.py) uses tree-sitter for accurate C++ AST-guided depth calculation and handles edge cases such as block comments, inline assembly, macro continuations, preprocessor nesting, and access specifier alignment correctly.

Confidence Score: 5/5

Safe to merge — all 445 C++ file changes are confirmed whitespace-only.

git diff -w is empty, meaning zero functional changes across all source files. The only non-trivial change is the new Python script, which has one minor edge-case bug (P2) with no impact on the already-committed output.

scripts/cpp/convert_leading_spaces_to_tabs.py — minor //+/* edge case in block-comment detection (P2, no current impact).

Important Files Changed

Filename Overview
scripts/cpp/convert_leading_spaces_to_tabs.py New tree-sitter-based Python script for converting leading spaces to tabs; well-structured with good edge-case handling, but has a minor bug in the mid-line /* detection that doesn't account for // line comments containing /*.
GeneralsMD/Code/GameEngine/Include/Common/BitFlags.h Whitespace-only: leading spaces converted to tabs; confirmed by git diff -w producing no output.
GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp Whitespace-only reformatting; all functional content unchanged.
GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h Whitespace-only: leading spaces converted to tabs; access specifiers placed at class-brace level per codebase convention.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Read file as cp1252] --> B[Encode to UTF-8 bytes]
    B --> C[Apply MACRO_EXPANSIONS for tree-sitter parsing]
    C --> D[Parse with tree-sitter C++]
    D --> E{Top-level parse errors > 10?}
    E -- Yes --> F[Skip entire file]
    E -- No --> G[Process lines]
    G --> H{Inside block comment?}
    H -- Yes --> I[Append unchanged / check for closing]
    H -- No --> J{Starts with /*?}
    J -- Yes --> K[Append unchanged / update in_block_comment]
    J -- No --> L{ASM / macro continuation / blank / preprocessor?}
    L -- Yes --> M[Append unchanged]
    L -- No --> N{Leading whitespace already tabs only?}
    N -- Yes --> O[Append unchanged]
    N -- No --> P{Tabs-then-spaces alignment?}
    P -- Yes --> Q[Append unchanged / skipped++]
    P -- No --> R[Query tree-sitter AST for node at first non-WS char]
    R --> S{Node in ERROR or continuation line?}
    S -- Yes --> T[Append unchanged / skipped++]
    S -- No --> U[get_indent_depth with special-case braces/case/access-specifiers]
    U --> V{depth==0 but significant spaces?}
    V -- Yes --> W[Append unchanged / skipped++]
    V -- No --> X[Replace leading WS with depth tabs]
    X --> Y[Track mid-line /* opens]
    Y --> Z[Write file if changed]
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: 419-424

Comment:
**`//` line comments containing `/*` trigger false block-comment mode**

`stripped.rfind('/*')` doesn't first strip the `//`-comment portion, so a line like `doFoo(); // see /* example` finds the `/*` inside the line comment, sees no closing `*/`, and sets `in_block_comment = True`. The following line is then left untouched (treated as block-comment content).

Since this script has already produced the committed output the practical impact is zero today, but if it is ever re-run the affected lines will be silently skipped. A guard against this would be to truncate `stripped` at the first `//` before doing the `rfind`:

```python
# Track mid-line block comment opens (e.g. /**< trailing doc comments)
code_part = stripped
double_slash = stripped.find('//')
if double_slash >= 0:
    code_part = stripped[:double_slash]
last_open = code_part.rfind('/*')
if last_open >= 0:
    after_open = code_part[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.

Reviews (6): Last reviewed commit: "style: Convert leading spaces to tabs in..." | Re-trigger Greptile

Copy link
Copy Markdown

@Skyaero42 Skyaero42 left a comment

Choose a reason for hiding this comment

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

Quick sample,

I've skipped the issue about documentation block comments - see other PR's for that.

const AudioEventRTS *getSoundFalling() const { return getAudio(TTAUDIO_soundFalling); }

Bool hasSoundAmbient() const { return hasAudio(TTAUDIO_soundAmbient); }
Bool hasSoundAmbient() const { return hasAudio(TTAUDIO_soundAmbient); }
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

incorrect indentation

Bool hasSoundAmbient() const { return hasAudio(TTAUDIO_soundAmbient); }

const AudioEventRTS *getPerUnitSound(const AsciiString& soundName) const;
const AudioEventRTS *getPerUnitSound(const AsciiString& soundName) const;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

incorrect indentation

UnsignedInt getThreatValue() const { return m_threatValue; }

//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

incorrect indentation

//-------------------------------------------------------------------------------------------------
NameKeyType getMaxSimultaneousLinkKey() const { return m_maxSimultaneousLinkKey; }
UnsignedInt getMaxSimultaneousOfType() const;
//-------------------------------------------------------------------------------------------------
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Incorrect indentation x 3

void validateAudio();
const AudioEventRTS* getAudio(ThingTemplateAudioType t) const { return m_audioarray.m_audio[t] ? &m_audioarray.m_audio[t]->m_event : &s_audioEventNoSound; }
Bool hasAudio(ThingTemplateAudioType t) const { return m_audioarray.m_audio[t] != nullptr; }
Bool hasAudio(ThingTemplateAudioType t) const { return m_audioarray.m_audio[t] != nullptr; }
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Incorrect indentation

static void parseReplaceModule(INI *ini, void *instance, void *store, const void *userData);
static void parseInheritableModule(INI *ini, void *instance, void *store, const void *userData);
static void OverrideableByLikeKind(INI *ini, void *instance, void *store, const void *userData);
static void OverrideableByLikeKind(INI *ini, void *instance, void *store, const void *userData);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Incorrect indentation

@bobtista bobtista force-pushed the bobtista/feat/access-spec-indent-generalsmd-engine branch from f148578 to bcfa380 Compare April 15, 2026 16:48
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.

2 participants