mirror of
https://github.com/NohamR/Reclass.git
synced 2026-05-10 19:59:21 +00:00
minorfixes
This commit is contained in:
@@ -222,6 +222,7 @@ void composeParent(ComposeState& state, const NodeTree& tree,
|
||||
state.baseEmitted = true;
|
||||
|
||||
// Header line (skip for array element structs and root struct)
|
||||
// Root struct header is on CommandRow2 (type + name + {)
|
||||
if (!isArrayChild && !isRootHeader) {
|
||||
// Get per-scope widths for this header's parent scope
|
||||
int typeW = state.effectiveTypeW(scopeId);
|
||||
@@ -263,8 +264,7 @@ void composeParent(ComposeState& state, const NodeTree& tree,
|
||||
return tree.nodes[a].offset < tree.nodes[b].offset;
|
||||
});
|
||||
|
||||
// Root struct children compose at same depth (no header to indent from)
|
||||
int childDepth = isRootHeader ? depth : depth + 1;
|
||||
int childDepth = depth + 1;
|
||||
|
||||
// For arrays, render children as condensed (no header/footer for struct elements)
|
||||
bool childrenAreArrayElements = (node.kind == NodeKind::Array);
|
||||
@@ -278,8 +278,8 @@ void composeParent(ComposeState& state, const NodeTree& tree,
|
||||
}
|
||||
}
|
||||
|
||||
// Footer line: skip when collapsed, for array element structs, or for root struct
|
||||
if (!isArrayChild && !isRootHeader && !node.collapsed) {
|
||||
// Footer line: skip when collapsed or for array element structs
|
||||
if (!isArrayChild && (!node.collapsed || isRootHeader)) {
|
||||
LineMeta lm;
|
||||
lm.nodeIdx = nodeIdx;
|
||||
lm.nodeId = node.id;
|
||||
@@ -501,7 +501,7 @@ ComposeResult compose(const NodeTree& tree, const Provider& prov, uint64_t viewR
|
||||
lm.markerMask = 0;
|
||||
lm.effectiveTypeW = state.typeW;
|
||||
lm.effectiveNameW = state.nameW;
|
||||
state.emitLine(QStringLiteral("struct <no class>"), lm);
|
||||
state.emitLine(QStringLiteral("struct <no class> {"), lm);
|
||||
}
|
||||
|
||||
QVector<int> roots = state.childMap.value(0);
|
||||
|
||||
@@ -1408,13 +1408,13 @@ void RcxController::updateCommandRow() {
|
||||
if (n.parentId == 0 && n.kind == NodeKind::Struct) {
|
||||
QString keyword = n.resolvedClassKeyword();
|
||||
QString className = n.structTypeName.isEmpty() ? n.name : n.structTypeName;
|
||||
row2 = QStringLiteral("%1 %2")
|
||||
row2 = QStringLiteral("%1 %2 {")
|
||||
.arg(keyword, className);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (row2.isEmpty())
|
||||
row2 = QStringLiteral("struct <no class>");
|
||||
row2 = QStringLiteral("struct <no class> {");
|
||||
|
||||
for (auto* ed : m_editors) {
|
||||
ed->setCommandRowText(row);
|
||||
|
||||
@@ -603,6 +603,7 @@ inline ColumnSpan commandRow2TypeSpan(const QString& lineText) {
|
||||
}
|
||||
|
||||
inline ColumnSpan commandRow2NameSpan(const QString& lineText) {
|
||||
// Format: "keyword name {" — extract just the name part (before " {")
|
||||
int start = 0;
|
||||
while (start < lineText.size() && lineText[start].isSpace()) start++;
|
||||
int space = lineText.indexOf(' ', start);
|
||||
@@ -610,7 +611,9 @@ inline ColumnSpan commandRow2NameSpan(const QString& lineText) {
|
||||
int nameStart = space + 1;
|
||||
while (nameStart < lineText.size() && lineText[nameStart].isSpace()) nameStart++;
|
||||
if (nameStart >= lineText.size()) return {};
|
||||
int nameEnd = lineText.size();
|
||||
// Stop before trailing " {"
|
||||
int nameEnd = lineText.indexOf(QStringLiteral(" {"), nameStart);
|
||||
if (nameEnd < 0) nameEnd = lineText.size();
|
||||
while (nameEnd > nameStart && lineText[nameEnd - 1].isSpace()) nameEnd--;
|
||||
if (nameEnd <= nameStart) return {};
|
||||
return {nameStart, nameEnd, true};
|
||||
|
||||
@@ -677,6 +677,8 @@ void RcxEditor::applyCommandRowPills() {
|
||||
// ── Shared inline-edit shutdown ──
|
||||
|
||||
RcxEditor::EndEditInfo RcxEditor::endInlineEdit() {
|
||||
// Dismiss any open user list / autocomplete popup
|
||||
m_sci->SendScintilla(QsciScintillaBase::SCI_AUTOCCANCEL);
|
||||
// Clear edit comment and error marker before deactivating
|
||||
if (m_editState.target == EditTarget::Value) {
|
||||
setEditComment({}); // Clear to spaces
|
||||
|
||||
45
src/main.cpp
45
src/main.cpp
@@ -201,9 +201,9 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) {
|
||||
m_mdiArea->setTabsMovable(true);
|
||||
setCentralWidget(m_mdiArea);
|
||||
|
||||
createWorkspaceDock();
|
||||
createMenus();
|
||||
createStatusBar();
|
||||
createWorkspaceDock();
|
||||
|
||||
connect(m_mdiArea, &QMdiArea::subWindowActivated,
|
||||
this, [this](QMdiSubWindow*) {
|
||||
@@ -279,6 +279,8 @@ void MainWindow::createMenus() {
|
||||
view->addSeparator();
|
||||
m_actViewRendered = view->addAction(makeIcon(":/vsicons/code.svg"), "&C/C++", this, [this]() { setViewMode(VM_Rendered); });
|
||||
m_actViewReclass = view->addAction(makeIcon(":/vsicons/eye.svg"), "&Reclass View", this, [this]() { setViewMode(VM_Reclass); });
|
||||
view->addSeparator();
|
||||
view->addAction(m_workspaceDock->toggleViewAction());
|
||||
|
||||
// Node
|
||||
auto* node = menuBar()->addMenu("&Node");
|
||||
@@ -395,12 +397,48 @@ void MainWindow::newFile() {
|
||||
}
|
||||
|
||||
void MainWindow::selfTest() {
|
||||
// Load demo.rcx if it exists, otherwise create a blank project
|
||||
QString demoPath = QCoreApplication::applicationDirPath() + "/demo.rcx";
|
||||
if (QFile::exists(demoPath)) {
|
||||
project_open(demoPath);
|
||||
} else {
|
||||
project_new();
|
||||
// Create default demo with a single Ball struct
|
||||
auto* doc = new RcxDocument(this);
|
||||
doc->tree.baseAddress = 0x00400000;
|
||||
|
||||
Node ball;
|
||||
ball.kind = NodeKind::Struct;
|
||||
ball.name = "aBall";
|
||||
ball.structTypeName = "Ball";
|
||||
ball.parentId = 0;
|
||||
ball.offset = 0;
|
||||
int bi = doc->tree.addNode(ball);
|
||||
uint64_t ballId = doc->tree.nodes[bi].id;
|
||||
|
||||
{ Node n; n.kind = NodeKind::Hex64; n.name = "field_00"; n.parentId = ballId; n.offset = 0; doc->tree.addNode(n); }
|
||||
{ Node n; n.kind = NodeKind::Hex64; n.name = "field_08"; n.parentId = ballId; n.offset = 8; doc->tree.addNode(n); }
|
||||
{ Node n; n.kind = NodeKind::Vec4; n.name = "position"; n.parentId = ballId; n.offset = 16; doc->tree.addNode(n); }
|
||||
{ Node n; n.kind = NodeKind::Vec3; n.name = "velocity"; n.parentId = ballId; n.offset = 32; doc->tree.addNode(n); }
|
||||
{ Node n; n.kind = NodeKind::Hex32; n.name = "field_2C"; n.parentId = ballId; n.offset = 44; doc->tree.addNode(n); }
|
||||
{ Node n; n.kind = NodeKind::Float; n.name = "speed"; n.parentId = ballId; n.offset = 48; doc->tree.addNode(n); }
|
||||
{ Node n; n.kind = NodeKind::Hex32; n.name = "field_34"; n.parentId = ballId; n.offset = 52; doc->tree.addNode(n); }
|
||||
{ Node n; n.kind = NodeKind::UInt32; n.name = "color"; n.parentId = ballId; n.offset = 56; doc->tree.addNode(n); }
|
||||
{ Node n; n.kind = NodeKind::Hex32; n.name = "field_3C"; n.parentId = ballId; n.offset = 60; doc->tree.addNode(n); }
|
||||
{ Node n; n.kind = NodeKind::Float; n.name = "radius"; n.parentId = ballId; n.offset = 64; doc->tree.addNode(n); }
|
||||
{ Node n; n.kind = NodeKind::Hex32; n.name = "field_44"; n.parentId = ballId; n.offset = 68; doc->tree.addNode(n); }
|
||||
{ Node n; n.kind = NodeKind::Double; n.name = "mass"; n.parentId = ballId; n.offset = 72; doc->tree.addNode(n); }
|
||||
{ Node n; n.kind = NodeKind::Hex64; n.name = "field_50"; n.parentId = ballId; n.offset = 80; doc->tree.addNode(n); }
|
||||
{ Node n; n.kind = NodeKind::Bool; n.name = "bouncy"; n.parentId = ballId; n.offset = 88; doc->tree.addNode(n); }
|
||||
{ Node n; n.kind = NodeKind::Hex8; n.name = "field_59"; n.parentId = ballId; n.offset = 89; doc->tree.addNode(n); }
|
||||
{ Node n; n.kind = NodeKind::Hex16; n.name = "field_5A"; n.parentId = ballId; n.offset = 90; doc->tree.addNode(n); }
|
||||
{ Node n; n.kind = NodeKind::UInt32; n.name = "bounceCount"; n.parentId = ballId; n.offset = 92; doc->tree.addNode(n); }
|
||||
{ Node n; n.kind = NodeKind::Hex32; n.name = "field_60"; n.parentId = ballId; n.offset = 96; doc->tree.addNode(n); }
|
||||
{ Node n; n.kind = NodeKind::Hex64; n.name = "field_68"; n.parentId = ballId; n.offset = 100; doc->tree.addNode(n); }
|
||||
{ Node n; n.kind = NodeKind::Hex64; n.name = "field_70"; n.parentId = ballId; n.offset = 108; doc->tree.addNode(n); }
|
||||
{ Node n; n.kind = NodeKind::Hex64; n.name = "field_78"; n.parentId = ballId; n.offset = 116; doc->tree.addNode(n); }
|
||||
|
||||
doc->save(demoPath);
|
||||
doc->load(demoPath);
|
||||
createTab(doc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -886,6 +924,7 @@ void MainWindow::createWorkspaceDock() {
|
||||
|
||||
m_workspaceDock->setWidget(m_workspaceTree);
|
||||
addDockWidget(Qt::LeftDockWidgetArea, m_workspaceDock);
|
||||
m_workspaceDock->hide();
|
||||
|
||||
connect(m_workspaceTree, &QTreeView::doubleClicked, this, [this](const QModelIndex& index) {
|
||||
// Data roles: UserRole=QMdiSubWindow*, UserRole+1=structId, UserRole+2=nodeId
|
||||
|
||||
@@ -35,8 +35,8 @@ private slots:
|
||||
NullProvider prov;
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// CommandRow + CommandRow2 + 2 fields = 4 lines (root header/footer suppressed)
|
||||
QCOMPARE(result.meta.size(), 4);
|
||||
// CommandRow + CommandRow2 + 2 fields + root footer = 5
|
||||
QCOMPARE(result.meta.size(), 5);
|
||||
|
||||
// Line 0 is CommandRow
|
||||
QCOMPARE(result.meta[0].lineKind, LineKind::CommandRow);
|
||||
@@ -44,13 +44,18 @@ private slots:
|
||||
// Line 1 is CommandRow2
|
||||
QCOMPARE(result.meta[1].lineKind, LineKind::CommandRow2);
|
||||
|
||||
// Fields at depth 0 (root struct suppressed)
|
||||
// Fields at depth 1
|
||||
QVERIFY(!result.meta[2].foldHead);
|
||||
QCOMPARE(result.meta[2].depth, 1);
|
||||
QVERIFY(!result.meta[3].foldHead);
|
||||
QCOMPARE(result.meta[3].depth, 1);
|
||||
|
||||
// Offset text
|
||||
QCOMPARE(result.meta[2].offsetText, QString("0"));
|
||||
QCOMPARE(result.meta[3].offsetText, QString("4"));
|
||||
|
||||
// Line 4 is root footer
|
||||
QCOMPARE(result.meta[4].lineKind, LineKind::Footer);
|
||||
}
|
||||
|
||||
void testVec3Continuation() {
|
||||
@@ -74,22 +79,28 @@ private slots:
|
||||
NullProvider prov;
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// CommandRow + CommandRow2 + 3 Vec3 lines = 5 lines (root header/footer suppressed)
|
||||
QCOMPARE(result.meta.size(), 5);
|
||||
// CommandRow + CommandRow2 + 3 Vec3 lines + root footer = 6
|
||||
QCOMPARE(result.meta.size(), 6);
|
||||
|
||||
// Line 2 (first Vec3 component): not continuation
|
||||
// Line 2 (first Vec3 component): not continuation, depth 1
|
||||
QVERIFY(!result.meta[2].isContinuation);
|
||||
QCOMPARE(result.meta[2].offsetText, QString("0"));
|
||||
QCOMPARE(result.meta[2].depth, 1);
|
||||
|
||||
// Lines 3-4: continuation
|
||||
// Lines 3-4: continuation, depth 1
|
||||
QVERIFY(result.meta[3].isContinuation);
|
||||
QCOMPARE(result.meta[3].offsetText, QString(" \u00B7"));
|
||||
QCOMPARE(result.meta[3].depth, 1);
|
||||
QVERIFY(result.meta[4].isContinuation);
|
||||
QCOMPARE(result.meta[4].offsetText, QString(" \u00B7"));
|
||||
QCOMPARE(result.meta[4].depth, 1);
|
||||
|
||||
// Continuation marker
|
||||
QVERIFY(result.meta[3].markerMask & (1u << M_CONT));
|
||||
QVERIFY(result.meta[4].markerMask & (1u << M_CONT));
|
||||
|
||||
// Line 5 is root footer
|
||||
QCOMPARE(result.meta[5].lineKind, LineKind::Footer);
|
||||
}
|
||||
|
||||
void testPaddingMarker() {
|
||||
@@ -113,9 +124,13 @@ private slots:
|
||||
NullProvider prov;
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// CommandRow + CommandRow2 + padding = 3 (root header/footer suppressed)
|
||||
QCOMPARE(result.meta.size(), 3);
|
||||
// CommandRow + CommandRow2 + padding + root footer = 4
|
||||
QCOMPARE(result.meta.size(), 4);
|
||||
QVERIFY(result.meta[2].markerMask & (1u << M_PAD));
|
||||
QCOMPARE(result.meta[2].depth, 1);
|
||||
|
||||
// Line 3 is root footer
|
||||
QCOMPARE(result.meta[3].lineKind, LineKind::Footer);
|
||||
}
|
||||
|
||||
void testNullPointerMarker() {
|
||||
@@ -141,10 +156,14 @@ private slots:
|
||||
BufferProvider prov(data);
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// CommandRow + CommandRow2 + ptr = 3 (root header/footer suppressed)
|
||||
QCOMPARE(result.meta.size(), 3);
|
||||
// CommandRow + CommandRow2 + ptr + root footer = 4
|
||||
QCOMPARE(result.meta.size(), 4);
|
||||
// No ambient validation markers — M_PTR0 is no longer set
|
||||
QVERIFY(!(result.meta[2].markerMask & (1u << M_PTR0)));
|
||||
QCOMPARE(result.meta[2].depth, 1);
|
||||
|
||||
// Line 3 is root footer
|
||||
QCOMPARE(result.meta[3].lineKind, LineKind::Footer);
|
||||
}
|
||||
|
||||
void testCollapsedStruct() {
|
||||
@@ -169,10 +188,12 @@ private slots:
|
||||
NullProvider prov;
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// Collapsed: CommandRow + CommandRow2 + header only (no children, no footer)
|
||||
QCOMPARE(result.meta.size(), 3);
|
||||
QVERIFY(!result.meta[2].foldHead); // root fold suppressed
|
||||
QVERIFY(!result.meta[2].foldCollapsed); // root fold suppressed
|
||||
// Collapsed root: isRootHeader overrides collapse, so children + footer still render
|
||||
// CommandRow + CommandRow2 + field + root footer = 4
|
||||
QCOMPARE(result.meta.size(), 4);
|
||||
QCOMPARE(result.meta[2].lineKind, LineKind::Field);
|
||||
QCOMPARE(result.meta[2].depth, 1);
|
||||
QCOMPARE(result.meta[3].lineKind, LineKind::Footer);
|
||||
}
|
||||
|
||||
void testUnreadablePointerNoRead() {
|
||||
@@ -199,11 +220,15 @@ private slots:
|
||||
BufferProvider prov(data);
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// CommandRow + CommandRow2 + ptr = 3 (root header/footer suppressed)
|
||||
QCOMPARE(result.meta.size(), 3);
|
||||
// CommandRow + CommandRow2 + ptr + root footer = 4
|
||||
QCOMPARE(result.meta.size(), 4);
|
||||
// No ambient validation markers
|
||||
QVERIFY(!(result.meta[2].markerMask & (1u << M_ERR)));
|
||||
QVERIFY(!(result.meta[2].markerMask & (1u << M_PTR0)));
|
||||
QCOMPARE(result.meta[2].depth, 1);
|
||||
|
||||
// Line 3 is root footer
|
||||
QCOMPARE(result.meta[3].lineKind, LineKind::Footer);
|
||||
}
|
||||
|
||||
void testFoldLevels() {
|
||||
@@ -235,14 +260,14 @@ private slots:
|
||||
NullProvider prov;
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// Child header (depth 0, fold head) — root suppressed, children at depth 0
|
||||
QCOMPARE(result.meta[2].foldLevel, 0x400 | 0x2000);
|
||||
QCOMPARE(result.meta[2].depth, 0);
|
||||
// Child header (depth 1, fold head) — root header no longer emitted
|
||||
QCOMPARE(result.meta[2].foldLevel, 0x401 | 0x2000);
|
||||
QCOMPARE(result.meta[2].depth, 1);
|
||||
QVERIFY(result.meta[2].foldHead);
|
||||
|
||||
// Leaf (depth 1, not head)
|
||||
QCOMPARE(result.meta[3].foldLevel, 0x401);
|
||||
QCOMPARE(result.meta[3].depth, 1);
|
||||
// Leaf (depth 2, not head)
|
||||
QCOMPARE(result.meta[3].foldLevel, 0x402);
|
||||
QCOMPARE(result.meta[3].depth, 2);
|
||||
}
|
||||
|
||||
void testNestedStruct() {
|
||||
@@ -289,28 +314,31 @@ private slots:
|
||||
NullProvider prov;
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// CommandRow + CommandRow2 + flags + Inner header + x + y + Inner footer = 7
|
||||
// (root header/footer suppressed, children at depth 0)
|
||||
QCOMPARE(result.meta.size(), 7);
|
||||
// CommandRow + CommandRow2 + flags + Inner header + x + y + Inner footer + root footer = 8
|
||||
QCOMPARE(result.meta.size(), 8);
|
||||
|
||||
// flags field (depth 0, root children at depth 0)
|
||||
// flags field (depth 1)
|
||||
QCOMPARE(result.meta[2].lineKind, LineKind::Field);
|
||||
QCOMPARE(result.meta[2].depth, 0);
|
||||
QCOMPARE(result.meta[2].depth, 1);
|
||||
|
||||
// Inner header (depth 0, fold head)
|
||||
// Inner header (depth 1, fold head)
|
||||
QCOMPARE(result.meta[3].lineKind, LineKind::Header);
|
||||
QCOMPARE(result.meta[3].depth, 0);
|
||||
QCOMPARE(result.meta[3].depth, 1);
|
||||
QVERIFY(result.meta[3].foldHead);
|
||||
QCOMPARE(result.meta[3].foldLevel, 0x400 | 0x2000);
|
||||
QCOMPARE(result.meta[3].foldLevel, 0x401 | 0x2000);
|
||||
|
||||
// Inner fields at depth 1
|
||||
QCOMPARE(result.meta[4].depth, 1);
|
||||
QCOMPARE(result.meta[4].foldLevel, 0x401);
|
||||
QCOMPARE(result.meta[5].depth, 1);
|
||||
// Inner fields at depth 2
|
||||
QCOMPARE(result.meta[4].depth, 2);
|
||||
QCOMPARE(result.meta[4].foldLevel, 0x402);
|
||||
QCOMPARE(result.meta[5].depth, 2);
|
||||
|
||||
// Inner footer
|
||||
QCOMPARE(result.meta[6].lineKind, LineKind::Footer);
|
||||
QCOMPARE(result.meta[6].depth, 0);
|
||||
QCOMPARE(result.meta[6].depth, 1);
|
||||
|
||||
// Root footer
|
||||
QCOMPARE(result.meta[7].lineKind, LineKind::Footer);
|
||||
QCOMPARE(result.meta[7].depth, 0);
|
||||
}
|
||||
|
||||
void testPointerDerefExpansion() {
|
||||
@@ -378,28 +406,28 @@ private slots:
|
||||
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// CommandRow + CommandRow2 + magic + ptr(merged fold header) + fn1 + fn2 + ptr footer = 7
|
||||
// CommandRow + CommandRow2 + magic + ptr(merged fold header) + fn1 + fn2 + ptr footer + Main footer = 8
|
||||
// VTable standalone: header + fn1 + fn2 + footer = 4
|
||||
// Total = 11 (root header/footer suppressed)
|
||||
QCOMPARE(result.meta.size(), 11);
|
||||
// Total = 12
|
||||
QCOMPARE(result.meta.size(), 12);
|
||||
|
||||
// magic field (depth 0, root children at depth 0)
|
||||
// magic field (depth 1)
|
||||
QCOMPARE(result.meta[2].lineKind, LineKind::Field);
|
||||
QCOMPARE(result.meta[2].depth, 0);
|
||||
QCOMPARE(result.meta[2].depth, 1);
|
||||
|
||||
// Pointer as merged fold header: "ptr64<VTable> ptr {"
|
||||
QCOMPARE(result.meta[3].lineKind, LineKind::Header);
|
||||
QCOMPARE(result.meta[3].depth, 0);
|
||||
QCOMPARE(result.meta[3].depth, 1);
|
||||
QVERIFY(result.meta[3].foldHead);
|
||||
QCOMPARE(result.meta[3].nodeKind, NodeKind::Pointer64);
|
||||
|
||||
// Expanded fields at depth 1 (struct header merged into pointer)
|
||||
QCOMPARE(result.meta[4].depth, 1);
|
||||
QCOMPARE(result.meta[5].depth, 1);
|
||||
// Expanded fields at depth 2 (struct header merged into pointer)
|
||||
QCOMPARE(result.meta[4].depth, 2);
|
||||
QCOMPARE(result.meta[5].depth, 2);
|
||||
|
||||
// Pointer fold footer
|
||||
QCOMPARE(result.meta[6].lineKind, LineKind::Footer);
|
||||
QCOMPARE(result.meta[6].depth, 0);
|
||||
QCOMPARE(result.meta[6].depth, 1);
|
||||
}
|
||||
|
||||
void testPointerDerefNull() {
|
||||
@@ -443,13 +471,14 @@ private slots:
|
||||
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// CommandRow + CommandRow2 + ptr(merged fold header) + ptr footer = 4
|
||||
// CommandRow + CommandRow2 + ptr(merged fold header) + ptr footer + Main footer = 5
|
||||
// Target standalone: header + field + footer = 3
|
||||
// Total = 7 (root header/footer suppressed)
|
||||
QCOMPARE(result.meta.size(), 7);
|
||||
// Total = 8
|
||||
QCOMPARE(result.meta.size(), 8);
|
||||
|
||||
// Pointer as merged fold header (expanded but empty — null ptr)
|
||||
QCOMPARE(result.meta[2].lineKind, LineKind::Header);
|
||||
QCOMPARE(result.meta[2].depth, 1);
|
||||
QVERIFY(result.meta[2].foldHead);
|
||||
|
||||
// Pointer fold footer (empty expansion)
|
||||
@@ -500,14 +529,14 @@ private slots:
|
||||
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// CommandRow + CommandRow2 + ptr(fold head, collapsed) = 3
|
||||
// CommandRow + CommandRow2 + ptr(fold head, collapsed) + Main footer = 4
|
||||
// Target standalone: header + field + footer = 3
|
||||
// Total = 6 (root header/footer suppressed)
|
||||
QCOMPARE(result.meta.size(), 6);
|
||||
// Total = 7
|
||||
QCOMPARE(result.meta.size(), 7);
|
||||
|
||||
// Pointer is fold head (depth 0, root children at depth 0)
|
||||
// Pointer is fold head (depth 1)
|
||||
QVERIFY(result.meta[2].foldHead);
|
||||
QCOMPARE(result.meta[2].depth, 0);
|
||||
QCOMPARE(result.meta[2].depth, 1);
|
||||
}
|
||||
|
||||
void testPointerDerefCycle() {
|
||||
@@ -570,9 +599,9 @@ private slots:
|
||||
QVERIFY(result.meta.size() > 0);
|
||||
QVERIFY(result.meta.size() < 100); // sanity: bounded output
|
||||
|
||||
// Root suppressed: CommandRow + CommandRow2 + ptr merged header + data + self merged header
|
||||
// CommandRow + CommandRow2 + ptr merged header + data + self merged header
|
||||
// Second expansion blocked by cycle guard: no children under self
|
||||
// Then: self footer + ptr footer + standalone Recursive rendering
|
||||
// Then: self footer + ptr footer + Main footer + standalone Recursive rendering
|
||||
QVERIFY(result.meta[2].foldHead); // ptr merged fold head
|
||||
QCOMPARE(result.meta[2].lineKind, LineKind::Header); // ptr merged header
|
||||
QCOMPARE(result.meta[3].lineKind, LineKind::Field); // data field (first child of Recursive)
|
||||
@@ -926,15 +955,16 @@ private slots:
|
||||
NullProvider prov;
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// CommandRow + CommandRow2 + Array header(collapsed) = 3 (root header/footer suppressed)
|
||||
QCOMPARE(result.meta.size(), 3);
|
||||
// CommandRow + CommandRow2 + Array header(collapsed) + root footer = 4
|
||||
QCOMPARE(result.meta.size(), 4);
|
||||
|
||||
// Array header is collapsed
|
||||
// Array header is collapsed (at index 2)
|
||||
int arrLine = -1;
|
||||
for (int i = 0; i < result.meta.size(); i++) {
|
||||
if (result.meta[i].isArrayHeader) { arrLine = i; break; }
|
||||
}
|
||||
QVERIFY(arrLine >= 0);
|
||||
QCOMPARE(arrLine, 2);
|
||||
QVERIFY(result.meta[arrLine].foldCollapsed);
|
||||
|
||||
// Header text should NOT contain "{"
|
||||
|
||||
@@ -1026,10 +1026,10 @@ private slots:
|
||||
m_editor->applyDocument(result);
|
||||
QApplication::processEvents();
|
||||
|
||||
// Find header line
|
||||
// Find a non-root header line (root header has no editable name/type spans)
|
||||
int headerLine = -1;
|
||||
for (int i = 0; i < result.meta.size(); i++) {
|
||||
if (result.meta[i].lineKind == LineKind::Header) {
|
||||
if (result.meta[i].lineKind == LineKind::Header && !result.meta[i].isRootHeader) {
|
||||
headerLine = i;
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user