Skip to content

style: Convert leading spaces to tabs in Core and Dependencies#2561

Open
bobtista wants to merge 10 commits intoTheSuperHackers:mainfrom
bobtista:bobtista/feat/access-spec-indent-core
Open

style: Convert leading spaces to tabs in Core and Dependencies#2561
bobtista wants to merge 10 commits intoTheSuperHackers:mainfrom
bobtista:bobtista/feat/access-spec-indent-core

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 1 of 4 — Core/ and Dependencies/ (499 files).
See also: #2562, #2563, #2564.

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Apr 9, 2026

Greptile Summary

This PR performs a whitespace-only conversion of leading spaces to tabs across 452 C++ files in Core/ and Dependencies/, using a tree-sitter-based Python script for accurate AST-guided reformatting. git diff -w is confirmed empty, meaning no logic was changed.

  • The main() function in the committed script still lists Dependencies/Utility in top_dirs, but the HEAD commit (a9cbcc22) explicitly reverted those 7 files because the script "cannot reliably handle" them. Re-running the script as shipped would re-apply incorrect indentation to those excluded headers.

Confidence Score: 4/5

Safe to merge for the C++ files; the script has one correctness issue that should be fixed before re-use.

All 452 C++ file changes are confirmed whitespace-only (git diff -w is empty). The single P1 finding is in the committed script: top_dirs still targets Dependencies/Utility even though the HEAD commit explicitly reverted those files as incompatible — re-running the script would re-corrupt them.

scripts/cpp/convert_leading_spaces_to_tabs.py — top_dirs needs Dependencies/Utility removed

Important Files Changed

Filename Overview
scripts/cpp/convert_leading_spaces_to_tabs.py New script documenting how whitespace was converted; top_dirs still includes Dependencies/Utility even though the HEAD commit reverted those files as incompatible with the script
Core/GameEngine/Source/GameNetwork/GameInfo.cpp Whitespace-only: leading spaces converted to tabs; no logic changes
Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp Whitespace-only: leading spaces converted to tabs, including previously mixed tab+space lines; no logic changes
Core/GameEngine/Source/Common/System/GameMemory.cpp Whitespace-only: corrects mixed space+tab indentation to pure tabs; no logic changes
Core/Libraries/Source/WWVegas/WWLib/cpudetect.cpp Whitespace-only: GNU __asm__ call-style lines correctly converted; inline asm brace blocks preserved as-is
Core/GameEngine/Include/Common/INI.h Whitespace-only: private member declarations and one public method corrected from spaces to tabs

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Read C++ file\ncp1252 encoding] --> B[Preprocess: expand\nconfusing macros]
    B --> C[tree-sitter parse\nC++ AST]
    C --> D{Too many\nparse errors?}
    D -->|Yes| E[Skip file]
    D -->|No| F[Process each line]
    F --> G{In block comment\nor ASM block?}
    G -->|Yes| H[Preserve as-is]
    G -->|No| I{Preprocessor\ndirective?}
    I -->|Yes| J[Preserve, track pp_depth]
    I -->|No| K{Already tabs /\ncontinuation line?}
    K -->|Yes| H
    K -->|No| L[Query AST node\nat line start col]
    L --> M[get_indent_depth:\ncount scope ancestors]
    M --> N{depth==0 and\nspaces>=4 or pp_depth>0?}
    N -->|Yes - sanity skip| H
    N -->|No| O[Replace leading\nwhitespace with N tabs]
    O --> P[Write converted\nfile back]
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: 443-454

Comment:
**`top_dirs` still includes `Dependencies/Utility`**

The HEAD commit (`a9cbcc22`) explicitly reverted the seven `Dependencies/Utility/Utility/*.h` files because the script "cannot reliably handle the interaction between preprocessor nesting and C++ nesting in these files." However, `top_dirs` still lists that directory, so re-running the script as committed would re-process — and likely corrupt — those same files.

```suggestion
        top_dirs = [
            os.path.join(root_dir, 'Core'),
            os.path.join(root_dir, 'Generals'),
            os.path.join(root_dir, 'GeneralsMD'),
        ]
```

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

Reviews (5): Last reviewed commit: "style: Exclude Dependencies/Utility comp..." | Re-trigger Greptile

Copy link
Copy Markdown

@xezon xezon left a comment

Choose a reason for hiding this comment

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

By what rules are these whitespaces edited? How can it be reviewed?

//using the IMC_SETCOMPOSITIONWINDOW message.
//
//I'm not sure what to do here.
m_result = 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.

This does not look right.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Still look wrong

@bobtista
Copy link
Copy Markdown
Author

By what rules are these whitespaces edited? How can it be reviewed?

Leading whitespace is regenerated from the C++ AST, not counted from spaces. For more details on how it's done, check scripts/cpp/convert_leading_spaces_to_tabs.py it will:

  • Parse the file with tree-sitter-cpp
  • For any line whose leading whitespace contains a space, locate the AST node at the first non-whitespace column.
  • Walk up the AST counting "scope-creating" ancestors: compound_statement, field_declaration_list, declaration_list (namespace body), enumerator_list, initializer_list, case_statement. Add one level for the braceless body/consequence/alternative of if/while/for/do/else. A compound_statement directly under a case_statement does not add a level (the case already provides it).
  • Replace the leading whitespace with exactly that many tab characters.

It skips a bunch of things eg block comments, and things that are addressed in later PRs to make review easier. To review it, I'd make sure you like the approach in the script, then spot check the results.

Copy link
Copy Markdown

@xezon xezon left a comment

Choose a reason for hiding this comment

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

There are still some indentation errors.


const Coord3D *pos = obj->getPosition();
Real angle = obj->getOrientation();
Real angle = obj->getOrientation();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 indent too much

Int cy = REAL_TO_INT_FLOOR((y + 0.5f)/PATHFIND_CELL_SIZE_F);
if (cx >= 0 && cy >= 0 && cx < m_extent.hi.x && cy < m_extent.hi.y)
{
for (Int iy = 0; iy < numStepsY; ++iy, tl_x += ydx, tl_y += ydy)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 indent too much

Many times

}
}

return ;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Side note: I thought we had all the superfluous returns already removed.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

looks like the space between return and semicolon was never considered.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This return is at the end of the function and can be removed. We already had such a change previously, but perhaps it missed W3DView.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I'm aware of that. I was merely making a note that the space between return and the semicolon, which the original script/regexp may not have considered.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The original script is only focused on leading spaces. Removing the space between the return and semicolon would be a separate PR, as would removing the return

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ah I see it was started but never finished: #1811

I can pick that up.

@@ -525,8 +525,8 @@ BoneMgrDialogClass::Remove_Object_From_Bone
{
// Loop through all the children of this bone
for (HTREEITEM hchild_item = m_BoneTree.GetChildItem (bone_item);
(hchild_item != nullptr);
hchild_item = m_BoneTree.GetNextSiblingItem (hchild_item)) {
(hchild_item != 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.

Can we put one more indent after for, while, if, else if?

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.

Sampled a few files. Comments are recurring throughout the PR.

Bool m_use3DSoundRangeVolumeFade; // TheSuperHackers @feature Enables 3D sound range volume fade as originally intended
Real m_3DSoundRangeVolumeFadeExponent; // TheSuperHackers @feature Sets 3D sound range volume fade exponent for non-linear fade.
// The higher the exponent, the sharper the decline at the max range.
// The higher the exponent, the sharper the decline at the max range.
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, now it looks like this comment belongs to the next line, rather than the previous

mov esi,[buf]
mov ecx,[len]
dec ecx
mov edi,[crcPtr]
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. Multiple times. This function is now a mess

* memory pointed at by buffer. Returns the number of bytes read.
* Returns -1 if an error occurred.
*/
* memory pointed at by buffer. Returns the number of bytes read.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Documentation block comment should be placed before function - multiple times in this is file

Int winActivate(); ///< pop window to top of list and activate
Int winBringToTop(); ///< bring this window to the top of the win list
Int winEnable( Bool enable ); /**< enable/disable a window, a disbled
window can be seen but accepts no input */
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Place documentation comment before function

public:

virtual VideoStreamInterface* next() override; ///< Returns next open stream
virtual VideoStreamInterface* next() override; ///< Returns next open stream
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

Improve conversion script to handle:
- Inline assembly blocks (skip entirely)
- Tabs-then-spaces alignment (preserve as-is)
- Mixed space-before-tab indentation (use tab count)
- Mid-line block comment opens (track for next line)

Manually fix tree-sitter depth errors in AIPathfind.cpp and
TerrainVisual.cpp caused by heavy preprocessor conditionals.
@DevGeniusCode DevGeniusCode self-requested a review April 12, 2026 17:29
Copy link
Copy Markdown

@DevGeniusCode DevGeniusCode left a comment

Choose a reason for hiding this comment

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

I manually reviewed some of the files (started from the bottom of the list and worked my way up). I left comments on the main indentation issues I noticed.

Comment on lines 111 to 117
#if __has_builtin(__builtin_return_address)
static inline uintptr_t _ReturnAddress()
{
return reinterpret_cast<uintptr_t>(__builtin_return_address(0));
return reinterpret_cast<uintptr_t>(__builtin_return_address(0));
}
#else
#error "No implementation for _ReturnAddress"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The script seems to have flattened the indentation within this preprocessor block. The function body should be indented further than the function signature.

Comment on lines +88 to +99
}

return wsOut;
}

inline char* WINAPI ConvertBSTRToString(BSTR pSrc)
{
DWORD cb, cwch;
char *szOut = nullptr;

if (!pSrc)
return nullptr;

// Retrieve the size of the BSTR with the null terminator
cwch = SysStringLen(pSrc) + 1;

// Compute the needed size with the null terminator
cb = WideCharToMultiByte(CP_ACP, 0, pSrc, cwch, nullptr, 0, nullptr, nullptr);
if (cb == 0)
{
cwch = GetLastError();
_com_issue_error(!IS_ERROR(cwch) ? HRESULT_FROM_WIN32(cwch) : cwch);
return nullptr;
}

// Allocate the string
szOut = (char*)::operator new(cb * sizeof(char));
if (!szOut)
{
_com_issue_error(HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY));
return nullptr;
}

// Convert the string and null-terminate
szOut[cb - 1] = '\0';
if (WideCharToMultiByte(CP_ACP, 0, pSrc, cwch, szOut, cb, nullptr, nullptr) == 0)
{
// We failed, clean everything up
cwch = GetLastError();

::operator delete(szOut);
szOut = nullptr;

_com_issue_error(!IS_ERROR(cwch) ? HRESULT_FROM_WIN32(cwch) : cwch);
}

return szOut;
DWORD cb, cwch;
char *szOut = nullptr;

if (!pSrc)
return 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.

The script seems to be adding unnecessary padding here. The function body is misaligned, and the indentation level is no longer consistent with the rest of the code.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

reverted

Comment on lines 650 to 653
inline void Matrix3::Get_Z_Vector(Vector3 * set) const
{
set->Set(Row[0][2], Row[1][2], Row[2][2]);
set->Set(Row[0][2], Row[1][2], Row[2][2]);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

While the script works correctly in simple cases like this one, it remains inconsistent overall, leading to the broken indentation seen in more complex blocks (like preprocessor directives).

(m_stringBackgroundBMP.CompareNoCase (pszBackgroundBMP) != 0))
{
{
// Create a new instance of the BMP object to use
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Excess tab

if (m_pCBackgroundBMP)
{
// Remove the background BMP from the scene
// and release its pointer
m_pCBackgroundBMP->Remove ();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Excess tab

{
ASSERT (m_pC2DScene);
if (m_pC2DScene)
{
// Remove the old background BMP if there was one.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Excess tab

Comment on lines +994 to 999
if ((use_global_reset_flag && m_bAutoCameraReset) ||
((use_global_reset_flag == false) && allow_reset) ||
m_bOneTimeReset) {
pCGraphicView->Reset_Camera_To_Display_Object (*m_pCRenderObj);
m_bOneTimeReset = false;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Excess tab

// Update the animation frame
if (m_pCRenderObj)
{
// Update the animation frame
for (int i = 0; i < m_pCAnimCombo->Get_Num_Anims(); i++)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Excess tab

These files use space-based indentation inside #if blocks for
platform-specific code. The script cannot reliably handle the
interaction between preprocessor nesting and C++ nesting in
these files, so they are excluded from conversion.
Comment on lines +443 to +454
top_dirs = [
os.path.join(root_dir, 'Core'),
os.path.join(root_dir, 'Generals'),
os.path.join(root_dir, 'GeneralsMD'),
os.path.join(root_dir, 'Dependencies', 'Utility'),
]
file_list = []
for ext in ['*.cpp', '*.h', '*.inl']:
for top_dir in top_dirs:
file_list.extend(
glob.glob(os.path.join(top_dir, '**', ext), recursive=True)
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 top_dirs still includes Dependencies/Utility

The HEAD commit (a9cbcc22) explicitly reverted the seven Dependencies/Utility/Utility/*.h files because the script "cannot reliably handle the interaction between preprocessor nesting and C++ nesting in these files." However, top_dirs still lists that directory, so re-running the script as committed would re-process — and likely corrupt — those same files.

Suggested change
top_dirs = [
os.path.join(root_dir, 'Core'),
os.path.join(root_dir, 'Generals'),
os.path.join(root_dir, 'GeneralsMD'),
os.path.join(root_dir, 'Dependencies', 'Utility'),
]
file_list = []
for ext in ['*.cpp', '*.h', '*.inl']:
for top_dir in top_dirs:
file_list.extend(
glob.glob(os.path.join(top_dir, '**', ext), recursive=True)
)
top_dirs = [
os.path.join(root_dir, 'Core'),
os.path.join(root_dir, 'Generals'),
os.path.join(root_dir, 'GeneralsMD'),
]
Prompt To Fix With AI
This is a comment left during a code review.
Path: scripts/cpp/convert_leading_spaces_to_tabs.py
Line: 443-454

Comment:
**`top_dirs` still includes `Dependencies/Utility`**

The HEAD commit (`a9cbcc22`) explicitly reverted the seven `Dependencies/Utility/Utility/*.h` files because the script "cannot reliably handle the interaction between preprocessor nesting and C++ nesting in these files." However, `top_dirs` still lists that directory, so re-running the script as committed would re-process — and likely corrupt — those same files.

```suggestion
        top_dirs = [
            os.path.join(root_dir, 'Core'),
            os.path.join(root_dir, 'Generals'),
            os.path.join(root_dir, 'GeneralsMD'),
        ]
```

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.

4 participants