Addded Romeo that generates some doc. WIP.

This commit is contained in:
2026-07-18 18:58:29 -04:00
parent 446670bd29
commit 0c583b58da
120 changed files with 6167 additions and 18 deletions
+300
View File
@@ -0,0 +1,300 @@
#include "Database.h"
#include <Core/HAL/Filesystem/Filesystem.h>
#include <Core/Memory/MemoryArena.h>
#include <Windows.h>
namespace Romeo
{
void DB_Init(Database& db, Juliet::Arena* arena)
{
printf("Entering DB_Init...\n");
db.DbArena = arena;
db.Entries.Create(arena JULIET_DEBUG_ONLY(, "RomeoDB"));
printf("Exiting DB_Init...\n");
}
struct ScanContext
{
Database* Db;
Juliet::Arena* TempArena;
};
static void ProcessFile(ScanContext& ctx, const Juliet::String& path, const WIN32_FIND_DATAW& findData)
{
// Simple filter: only .h and .cpp
const char* pPath = CStr(path);
size_t len = StringLength(path);
if (len < 3)
{
return;
}
bool isHeader = false;
bool isCpp = false;
if (pPath[len - 2] == '.' && pPath[len - 1] == 'h')
{
isHeader = true;
}
else if (len >= 4 && pPath[len - 4] == '.' && pPath[len - 3] == 'c' && pPath[len - 2] == 'p' && pPath[len - 1] == 'p')
{
isCpp = true;
}
if (!isHeader && !isCpp)
{
return;
}
uint64_t lastModified = (static_cast<uint64_t>(findData.ftLastWriteTime.dwHighDateTime) << 32) | findData.ftLastWriteTime.dwLowDateTime;
// Try to find if we already have it in the DB (ignoring \include\ or \src\ offset)
const char* relStart = pPath;
if (const char* p1 = strstr(pPath, "\\include\\"))
{
relStart = p1 + 9;
}
else if (const char* p2 = strstr(pPath, "\\src\\"))
{
relStart = p2 + 5;
}
size_t baseLen = len - static_cast<size_t>(relStart - pPath);
baseLen -= (isHeader ? 2 : 4);
FileEntry* entry = nullptr;
for (FileEntry& e : ctx.Db->Entries)
{
Juliet::String dbPath = e.HeaderPath.Size > 0 ? e.HeaderPath : e.CppPath;
if (dbPath.Size > 0)
{
const char* pDbPath = CStr(dbPath);
const char* dbRelStart = pDbPath;
if (const char* p1 = strstr(pDbPath, "\\include\\"))
{
dbRelStart = p1 + 9;
}
else if (const char* p2 = strstr(pDbPath, "\\src\\"))
{
dbRelStart = p2 + 5;
}
bool dbIsHeader = (pDbPath[dbPath.Size - 1] == 'h');
size_t dbBaseLen = dbPath.Size - static_cast<size_t>(dbRelStart - pDbPath);
dbBaseLen -= (dbIsHeader ? 2 : 4);
if (baseLen == dbBaseLen && strncmp(relStart, dbRelStart, baseLen) == 0)
{
entry = &e;
break;
}
}
}
if (!entry)
{
FileEntry newEntry = {};
ctx.Db->Entries.PushBack(newEntry);
entry = ctx.Db->Entries.Back();
}
if (isHeader)
{
if (entry->HeaderPath.Size == 0)
{
entry->HeaderPath = Juliet::StringCopy(ctx.Db->DbArena, path);
}
entry->LastModifiedHeader = lastModified;
}
else
{
if (entry->CppPath.Size == 0)
{
entry->CppPath = Juliet::StringCopy(ctx.Db->DbArena, path);
}
entry->LastModifiedCpp = lastModified;
}
}
static void ScanDirectoryRecursive(ScanContext& ctx, const Juliet::String& currentDir)
{
size_t searchPathLen = currentDir.Size + 3; // "\*" + null
char* searchPathBuf = ArenaPushArray<char>(ctx.TempArena, searchPathLen JULIET_DEBUG_PARAM("RomeoDbSearchPathBuf"));
snprintf(searchPathBuf, searchPathLen, "%s\\*", CStr(currentDir));
Juliet::String searchPath = {searchPathBuf, searchPathLen - 1};
// Convert to wide string for Win32
int wLen = MultiByteToWideChar(CP_UTF8, 0, CStr(searchPath), -1, nullptr, 0);
if (wLen <= 0)
{
return;
}
wchar_t* wSearchPath = ArenaPushArray<wchar_t>(ctx.TempArena, static_cast<size_t>(wLen) JULIET_DEBUG_PARAM("RomeoDbWSearch"));
MultiByteToWideChar(CP_UTF8, 0, CStr(searchPath), -1, wSearchPath, wLen);
WIN32_FIND_DATAW findData;
HANDLE hFind = FindFirstFileExW(wSearchPath, FindExInfoBasic, &findData, FindExSearchNameMatch, nullptr, 0);
if (hFind == INVALID_HANDLE_VALUE)
{
return;
}
do
{
if (wcscmp(findData.cFileName, L".") == 0 || wcscmp(findData.cFileName, L"..") == 0)
{
continue;
}
// Convert filename back to UTF8
int uLen = WideCharToMultiByte(CP_UTF8, 0, findData.cFileName, -1, nullptr, 0, nullptr, nullptr);
char* uFileName = ArenaPushArray<char>(ctx.TempArena, static_cast<size_t>(uLen) JULIET_DEBUG_PARAM("RomeoDbUFileName"));
WideCharToMultiByte(CP_UTF8, 0, findData.cFileName, -1, uFileName, uLen, nullptr, nullptr);
size_t fullPathLen = currentDir.Size + 1 + static_cast<size_t>(uLen); // "\" + null
char* fullPathBuf = ArenaPushArray<char>(ctx.TempArena, fullPathLen JULIET_DEBUG_PARAM("RomeoDbFullPathBuf"));
snprintf(fullPathBuf, fullPathLen, "%s\\%s", CStr(currentDir), uFileName);
Juliet::String fullPath = {fullPathBuf, fullPathLen - 1};
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
// Skip external/build dirs
if (strcmp(uFileName, "External") != 0 && strcmp(uFileName, "Intermediate") != 0 && strcmp(uFileName, "bin") != 0 && strcmp(uFileName, ".git") != 0)
{
ScanDirectoryRecursive(ctx, fullPath);
}
}
else
{
ProcessFile(ctx, fullPath, findData);
}
} while (FindNextFileW(hFind, &findData) != 0);
FindClose(hFind);
}
void DB_ScanWorkspace(Database& db, Juliet::Arena* tempArena, const Juliet::String& rootDir)
{
Assert(tempArena != nullptr);
ScanContext ctx;
ctx.Db = &db;
ctx.TempArena = tempArena;
// Scan the src and include directories specifically to avoid trash
size_t srcDirLen = rootDir.Size + 12; // "\Juliet\src" + null
char* srcDirBuf = ArenaPushArray<char>(tempArena, srcDirLen JULIET_DEBUG_PARAM("RomeoDbSrcDirBuf"));
snprintf(srcDirBuf, srcDirLen, "%s\\Juliet\\src", CStr(rootDir));
Juliet::String srcDir = {srcDirBuf, srcDirLen - 1};
size_t incDirLen = rootDir.Size + 16; // "\Juliet\include" + null
char* incDirBuf = ArenaPushArray<char>(tempArena, incDirLen JULIET_DEBUG_PARAM("RomeoDbIncDirBuf"));
snprintf(incDirBuf, incDirLen, "%s\\Juliet\\include", CStr(rootDir));
Juliet::String incDir = {incDirBuf, incDirLen - 1};
ScanDirectoryRecursive(ctx, srcDir);
ScanDirectoryRecursive(ctx, incDir);
}
bool DB_Save(const Database& db, const Juliet::String& filePath)
{
FILE* file = nullptr;
if (fopen_s(&file, CStr(filePath), "wb") != 0 || !file)
{
return false;
}
uint64_t entryCount = db.Entries.Size();
fwrite(&entryCount, sizeof(uint64_t), 1, file);
for (const FileEntry& entry : db.Entries)
{
uint64_t hLen = entry.HeaderPath.Size;
fwrite(&hLen, sizeof(uint64_t), 1, file);
if (hLen > 0) fwrite(entry.HeaderPath.Data, 1, static_cast<size_t>(hLen), file);
uint64_t cLen = entry.CppPath.Size;
fwrite(&cLen, sizeof(uint64_t), 1, file);
if (cLen > 0) fwrite(entry.CppPath.Data, 1, static_cast<size_t>(cLen), file);
fwrite(&entry.LastModifiedHeader, sizeof(uint64_t), 1, file);
fwrite(&entry.LastModifiedCpp, sizeof(uint64_t), 1, file);
fwrite(&entry.LastMarkdownCreatedTime, sizeof(uint64_t), 1, file);
fwrite(&entry.LastAIGeneratedTime, sizeof(uint64_t), 1, file);
uint64_t dLen = entry.Description.Size;
fwrite(&dLen, sizeof(uint64_t), 1, file);
if (dLen > 0) fwrite(entry.Description.Data, 1, static_cast<size_t>(dLen), file);
}
fclose(file);
return true;
}
bool DB_Load(Database& db, const Juliet::String& filePath)
{
FILE* file = nullptr;
if (fopen_s(&file, CStr(filePath), "rb") != 0 || !file)
{
return false;
}
db.Entries.Clear();
uint64_t entryCount = 0;
if (fread(&entryCount, sizeof(uint64_t), 1, file) != 1)
{
fclose(file);
return false;
}
for (uint64_t i = 0; i < entryCount; ++i)
{
FileEntry entry = {};
uint64_t hLen = 0;
if (fread(&hLen, sizeof(uint64_t), 1, file) != 1) break;
if (hLen > 0)
{
entry.HeaderPath.Data = ArenaPushArray<char>(db.DbArena, static_cast<size_t>(hLen + 1) JULIET_DEBUG_PARAM("DbLoadHeader"));
entry.HeaderPath.Size = static_cast<size_t>(hLen);
fread(entry.HeaderPath.Data, 1, static_cast<size_t>(hLen), file);
entry.HeaderPath.Data[hLen] = '\0';
}
uint64_t cLen = 0;
if (fread(&cLen, sizeof(uint64_t), 1, file) != 1) break;
if (cLen > 0)
{
entry.CppPath.Data = ArenaPushArray<char>(db.DbArena, static_cast<size_t>(cLen + 1) JULIET_DEBUG_PARAM("DbLoadCpp"));
entry.CppPath.Size = static_cast<size_t>(cLen);
fread(entry.CppPath.Data, 1, static_cast<size_t>(cLen), file);
entry.CppPath.Data[cLen] = '\0';
}
fread(&entry.LastModifiedHeader, sizeof(uint64_t), 1, file);
fread(&entry.LastModifiedCpp, sizeof(uint64_t), 1, file);
fread(&entry.LastMarkdownCreatedTime, sizeof(uint64_t), 1, file);
fread(&entry.LastAIGeneratedTime, sizeof(uint64_t), 1, file);
uint64_t dLen = 0;
if (fread(&dLen, sizeof(uint64_t), 1, file) != 1) break;
if (dLen > 0)
{
entry.Description.Data = ArenaPushArray<char>(db.DbArena, static_cast<size_t>(dLen + 1) JULIET_DEBUG_PARAM("DbLoadDesc"));
entry.Description.Size = static_cast<size_t>(dLen);
fread(entry.Description.Data, 1, static_cast<size_t>(dLen), file);
entry.Description.Data[dLen] = '\0';
}
db.Entries.PushBack(entry);
}
fclose(file);
return true;
}
} // namespace Romeo