mirror of
https://github.com/NohamR/Reclass.git
synced 2026-05-10 19:59:21 +00:00
Move alignas alignment to context menu, fix hover state across refreshes
Replace inline alignas() editing with a proper "Align Members" submenu in the right-click context menu. Remove alignas display from command row and all related span/hit-test/edit machinery. Preserve hover highlight state across document refreshes.
This commit is contained in:
@@ -495,7 +495,7 @@ ComposeResult compose(const NodeTree& tree, const Provider& prov) {
|
|||||||
lm.markerMask = 0;
|
lm.markerMask = 0;
|
||||||
lm.effectiveTypeW = state.typeW;
|
lm.effectiveTypeW = state.typeW;
|
||||||
lm.effectiveNameW = state.nameW;
|
lm.effectiveNameW = state.nameW;
|
||||||
state.emitLine(QStringLiteral("struct <no class> alignas(1)"), lm);
|
state.emitLine(QStringLiteral("struct <no class>"), lm);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<int> roots = state.childMap.value(0);
|
QVector<int> roots = state.childMap.value(0);
|
||||||
|
|||||||
@@ -177,8 +177,7 @@ void RcxController::connectEditor(RcxEditor* editor) {
|
|||||||
this, [this](int nodeIdx, int subLine, EditTarget target, const QString& text) {
|
this, [this](int nodeIdx, int subLine, EditTarget target, const QString& text) {
|
||||||
// CommandRow BaseAddress/Source edit has nodeIdx=-1; CommandRow2 edits too
|
// CommandRow BaseAddress/Source edit has nodeIdx=-1; CommandRow2 edits too
|
||||||
if (nodeIdx < 0 && target != EditTarget::BaseAddress && target != EditTarget::Source
|
if (nodeIdx < 0 && target != EditTarget::BaseAddress && target != EditTarget::Source
|
||||||
&& target != EditTarget::RootClassType && target != EditTarget::RootClassName
|
&& target != EditTarget::RootClassType && target != EditTarget::RootClassName) { refresh(); return; }
|
||||||
&& target != EditTarget::Alignas) { refresh(); return; }
|
|
||||||
switch (target) {
|
switch (target) {
|
||||||
case EditTarget::Name: {
|
case EditTarget::Name: {
|
||||||
if (text.isEmpty()) break;
|
if (text.isEmpty()) break;
|
||||||
@@ -462,22 +461,6 @@ void RcxController::connectEditor(RcxEditor* editor) {
|
|||||||
case EditTarget::ArrayCount:
|
case EditTarget::ArrayCount:
|
||||||
// Array navigation removed - these cases are unreachable
|
// Array navigation removed - these cases are unreachable
|
||||||
break;
|
break;
|
||||||
case EditTarget::Alignas: {
|
|
||||||
// Parse "alignas(N)" → N
|
|
||||||
int paren = text.indexOf('(');
|
|
||||||
int close = text.indexOf(')');
|
|
||||||
if (paren < 0 || close < 0) break;
|
|
||||||
int newAlign = text.mid(paren + 1, close - paren - 1).toInt();
|
|
||||||
if (newAlign <= 0) break;
|
|
||||||
for (int i = 0; i < m_doc->tree.nodes.size(); i++) {
|
|
||||||
const auto& n = m_doc->tree.nodes[i];
|
|
||||||
if (n.parentId == 0 && n.kind == NodeKind::Struct) {
|
|
||||||
performRealignment(n.id, newAlign);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Always refresh to restore canonical text (handles parse failures, no-ops, etc.)
|
// Always refresh to restore canonical text (handles parse failures, no-ops, etc.)
|
||||||
refresh();
|
refresh();
|
||||||
@@ -1000,6 +983,23 @@ void RcxController::showContextMenu(RcxEditor* editor, int line, int nodeIdx,
|
|||||||
if (ni >= 0) toggleCollapse(ni);
|
if (ni >= 0) toggleCollapse(ni);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Align Members submenu
|
||||||
|
if (node.kind == NodeKind::Struct) {
|
||||||
|
int curAlign = m_doc->tree.computeStructAlignment(nodeId);
|
||||||
|
auto* alignMenu = menu.addMenu(icon("symbol-ruler.svg"), "Align &Members");
|
||||||
|
static const int alignValues[] = {1, 2, 4, 8, 16, 32, 64, 128};
|
||||||
|
for (int av : alignValues) {
|
||||||
|
QString label = (av == 1)
|
||||||
|
? QStringLiteral("1 (packed)")
|
||||||
|
: QString::number(av);
|
||||||
|
auto* act = alignMenu->addAction(label, [this, nodeId, av]() {
|
||||||
|
performRealignment(nodeId, av);
|
||||||
|
});
|
||||||
|
act->setCheckable(true);
|
||||||
|
act->setChecked(av == curAlign);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.addAction(icon("files.svg"), "D&uplicate\tCtrl+D", [this, nodeId]() {
|
menu.addAction(icon("files.svg"), "D&uplicate\tCtrl+D", [this, nodeId]() {
|
||||||
@@ -1034,6 +1034,33 @@ void RcxController::showContextMenu(RcxEditor* editor, int line, int nodeIdx,
|
|||||||
|
|
||||||
// ── Always-available actions ──
|
// ── Always-available actions ──
|
||||||
|
|
||||||
|
// Root struct alignment (always available if a root struct exists)
|
||||||
|
{
|
||||||
|
uint64_t rootStructId = 0;
|
||||||
|
for (const auto& n : m_doc->tree.nodes) {
|
||||||
|
if (n.parentId == 0 && n.kind == NodeKind::Struct) {
|
||||||
|
rootStructId = n.id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rootStructId != 0) {
|
||||||
|
int curAlign = m_doc->tree.computeStructAlignment(rootStructId);
|
||||||
|
auto* alignMenu = menu.addMenu(icon("symbol-ruler.svg"), "Align &Members");
|
||||||
|
static const int alignValues[] = {1, 2, 4, 8, 16, 32, 64, 128};
|
||||||
|
for (int av : alignValues) {
|
||||||
|
QString label = (av == 1)
|
||||||
|
? QStringLiteral("1 (packed)")
|
||||||
|
: QString::number(av);
|
||||||
|
auto* act = alignMenu->addAction(label, [this, rootStructId, av]() {
|
||||||
|
performRealignment(rootStructId, av);
|
||||||
|
});
|
||||||
|
act->setCheckable(true);
|
||||||
|
act->setChecked(av == curAlign);
|
||||||
|
}
|
||||||
|
menu.addSeparator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
menu.addAction(icon("add.svg"), "Add Hex64 at Root", [this]() {
|
menu.addAction(icon("add.svg"), "Add Hex64 at Root", [this]() {
|
||||||
insertNode(0, -1, NodeKind::Hex64, "newField");
|
insertNode(0, -1, NodeKind::Hex64, "newField");
|
||||||
});
|
});
|
||||||
@@ -1324,21 +1351,20 @@ void RcxController::updateCommandRow() {
|
|||||||
.arg(elide(src, 40), elide(addr, 24), elide(sym, 40));
|
.arg(elide(src, 40), elide(addr, 24), elide(sym, 40));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build row 2: root class type + name + alignment
|
// Build row 2: root class type + name
|
||||||
QString row2;
|
QString row2;
|
||||||
for (int i = 0; i < m_doc->tree.nodes.size(); i++) {
|
for (int i = 0; i < m_doc->tree.nodes.size(); i++) {
|
||||||
const auto& n = m_doc->tree.nodes[i];
|
const auto& n = m_doc->tree.nodes[i];
|
||||||
if (n.parentId == 0 && n.kind == NodeKind::Struct) {
|
if (n.parentId == 0 && n.kind == NodeKind::Struct) {
|
||||||
QString keyword = n.resolvedClassKeyword();
|
QString keyword = n.resolvedClassKeyword();
|
||||||
QString className = n.structTypeName.isEmpty() ? n.name : n.structTypeName;
|
QString className = n.structTypeName.isEmpty() ? n.name : n.structTypeName;
|
||||||
int alignment = m_doc->tree.computeStructAlignment(n.id);
|
row2 = QStringLiteral("%1 %2")
|
||||||
row2 = QStringLiteral("%1 %2 alignas(%3)")
|
.arg(keyword, className);
|
||||||
.arg(keyword, className).arg(alignment);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (row2.isEmpty())
|
if (row2.isEmpty())
|
||||||
row2 = QStringLiteral("struct <no class> alignas(1)");
|
row2 = QStringLiteral("struct <no class>");
|
||||||
|
|
||||||
for (auto* ed : m_editors) {
|
for (auto* ed : m_editors) {
|
||||||
ed->setCommandRowText(row);
|
ed->setCommandRowText(row);
|
||||||
|
|||||||
16
src/core.h
16
src/core.h
@@ -484,7 +484,7 @@ struct ColumnSpan {
|
|||||||
|
|
||||||
enum class EditTarget { Name, Type, Value, BaseAddress, Source, ArrayIndex, ArrayCount,
|
enum class EditTarget { Name, Type, Value, BaseAddress, Source, ArrayIndex, ArrayCount,
|
||||||
ArrayElementType, ArrayElementCount, PointerTarget,
|
ArrayElementType, ArrayElementCount, PointerTarget,
|
||||||
RootClassType, RootClassName, Alignas };
|
RootClassType, RootClassName };
|
||||||
|
|
||||||
// Column layout constants (shared with format.cpp span computation)
|
// Column layout constants (shared with format.cpp span computation)
|
||||||
inline constexpr int kFoldCol = 3; // 3-char fold indicator prefix per line
|
inline constexpr int kFoldCol = 3; // 3-char fold indicator prefix per line
|
||||||
@@ -587,7 +587,7 @@ inline ColumnSpan commandRowAddrSpan(const QString& lineText) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── CommandRow2 spans ──
|
// ── CommandRow2 spans ──
|
||||||
// Line format: "struct ClassName alignas(8)"
|
// Line format: "struct ClassName"
|
||||||
|
|
||||||
inline ColumnSpan commandRow2TypeSpan(const QString& lineText) {
|
inline ColumnSpan commandRow2TypeSpan(const QString& lineText) {
|
||||||
int start = 0;
|
int start = 0;
|
||||||
@@ -606,22 +606,12 @@ inline ColumnSpan commandRow2NameSpan(const QString& lineText) {
|
|||||||
int nameStart = space + 1;
|
int nameStart = space + 1;
|
||||||
while (nameStart < lineText.size() && lineText[nameStart].isSpace()) nameStart++;
|
while (nameStart < lineText.size() && lineText[nameStart].isSpace()) nameStart++;
|
||||||
if (nameStart >= lineText.size()) return {};
|
if (nameStart >= lineText.size()) return {};
|
||||||
// Name ends before "alignas(" if present, otherwise at line end
|
int nameEnd = lineText.size();
|
||||||
int nameEnd = lineText.indexOf(QStringLiteral(" alignas("), nameStart);
|
|
||||||
if (nameEnd < 0) nameEnd = lineText.size();
|
|
||||||
while (nameEnd > nameStart && lineText[nameEnd - 1].isSpace()) nameEnd--;
|
while (nameEnd > nameStart && lineText[nameEnd - 1].isSpace()) nameEnd--;
|
||||||
if (nameEnd <= nameStart) return {};
|
if (nameEnd <= nameStart) return {};
|
||||||
return {nameStart, nameEnd, true};
|
return {nameStart, nameEnd, true};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ColumnSpan commandRow2AlignasSpan(const QString& lineText) {
|
|
||||||
int idx = lineText.indexOf(QStringLiteral("alignas("));
|
|
||||||
if (idx < 0) return {};
|
|
||||||
int end = lineText.indexOf(')', idx);
|
|
||||||
if (end < 0) return {};
|
|
||||||
return {idx, end + 1, true};
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Array element type/count spans (within type column of array headers) ──
|
// ── Array element type/count spans (within type column of array headers) ──
|
||||||
// Line format: " int32_t[10] name {"
|
// Line format: " int32_t[10] name {"
|
||||||
// arrayElemTypeSpan covers "int32_t", arrayElemCountSpan covers "10"
|
// arrayElemTypeSpan covers "int32_t", arrayElemCountSpan covers "10"
|
||||||
|
|||||||
@@ -81,8 +81,7 @@ RcxEditor::RcxEditor(QWidget* parent) : QWidget(parent) {
|
|||||||
if (id == 1 && (m_editState.target == EditTarget::Type
|
if (id == 1 && (m_editState.target == EditTarget::Type
|
||||||
|| m_editState.target == EditTarget::ArrayElementType
|
|| m_editState.target == EditTarget::ArrayElementType
|
||||||
|| m_editState.target == EditTarget::PointerTarget
|
|| m_editState.target == EditTarget::PointerTarget
|
||||||
|| m_editState.target == EditTarget::RootClassType
|
|| m_editState.target == EditTarget::RootClassType)) {
|
||||||
|| m_editState.target == EditTarget::Alignas)) {
|
|
||||||
auto info = endInlineEdit();
|
auto info = endInlineEdit();
|
||||||
emit inlineEditCommitted(info.nodeIdx, info.subLine, info.target, text);
|
emit inlineEditCommitted(info.nodeIdx, info.subLine, info.target, text);
|
||||||
}
|
}
|
||||||
@@ -314,6 +313,11 @@ void RcxEditor::applyDocument(const ComposeResult& result) {
|
|||||||
if (m_editState.active)
|
if (m_editState.active)
|
||||||
endInlineEdit();
|
endInlineEdit();
|
||||||
|
|
||||||
|
// Save hover state — setText() triggers viewport Leave events that would clear it
|
||||||
|
uint64_t savedHoverId = m_hoveredNodeId;
|
||||||
|
int savedHoverLine = m_hoveredLine;
|
||||||
|
bool savedHoverInside = m_hoverInside;
|
||||||
|
|
||||||
m_meta = result.meta;
|
m_meta = result.meta;
|
||||||
m_layout = result.layout;
|
m_layout = result.layout;
|
||||||
|
|
||||||
@@ -333,6 +337,11 @@ void RcxEditor::applyDocument(const ComposeResult& result) {
|
|||||||
|
|
||||||
// Reset hint line - applySelectionOverlay will repaint indicators
|
// Reset hint line - applySelectionOverlay will repaint indicators
|
||||||
m_hintLine = -1;
|
m_hintLine = -1;
|
||||||
|
|
||||||
|
// Restore hover state
|
||||||
|
m_hoveredNodeId = savedHoverId;
|
||||||
|
m_hoveredLine = savedHoverLine;
|
||||||
|
m_hoverInside = savedHoverInside;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RcxEditor::applyMarginText(const QVector<LineMeta>& meta) {
|
void RcxEditor::applyMarginText(const QVector<LineMeta>& meta) {
|
||||||
@@ -448,6 +457,7 @@ void RcxEditor::applySelectionOverlay(const QSet<uint64_t>& selIds) {
|
|||||||
m_hintLine = -1;
|
m_hintLine = -1;
|
||||||
|
|
||||||
applyHoverHighlight();
|
applyHoverHighlight();
|
||||||
|
applyHoverCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RcxEditor::applyHoverHighlight() {
|
void RcxEditor::applyHoverHighlight() {
|
||||||
@@ -651,10 +661,6 @@ void RcxEditor::applyCommandRowPills() {
|
|||||||
ColumnSpan nameSpan = commandRow2NameSpan(t2);
|
ColumnSpan nameSpan = commandRow2NameSpan(t2);
|
||||||
fillPadded2(nameSpan);
|
fillPadded2(nameSpan);
|
||||||
|
|
||||||
ColumnSpan alignasSpan = commandRow2AlignasSpan(t2);
|
|
||||||
fillPadded2(alignasSpan);
|
|
||||||
if (alignasSpan.valid)
|
|
||||||
fillIndicatorCols(IND_HEX_DIM, line2, alignasSpan.start, alignasSpan.end);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -811,15 +817,13 @@ bool RcxEditor::resolvedSpanFor(int line, EditTarget t,
|
|||||||
return out.valid;
|
return out.valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommandRow2: root class type, name, and alignas
|
// CommandRow2: root class type and name
|
||||||
if (lm->lineKind == LineKind::CommandRow2) {
|
if (lm->lineKind == LineKind::CommandRow2) {
|
||||||
if (t != EditTarget::RootClassType && t != EditTarget::RootClassName
|
if (t != EditTarget::RootClassType && t != EditTarget::RootClassName) return false;
|
||||||
&& t != EditTarget::Alignas) return false;
|
|
||||||
QString lineText = getLineText(m_sci, line);
|
QString lineText = getLineText(m_sci, line);
|
||||||
ColumnSpan s;
|
ColumnSpan s;
|
||||||
if (t == EditTarget::RootClassType) s = commandRow2TypeSpan(lineText);
|
if (t == EditTarget::RootClassType) s = commandRow2TypeSpan(lineText);
|
||||||
else if (t == EditTarget::RootClassName) s = commandRow2NameSpan(lineText);
|
else s = commandRow2NameSpan(lineText);
|
||||||
else s = commandRow2AlignasSpan(lineText);
|
|
||||||
out = normalizeSpan(s, lineText, t, false);
|
out = normalizeSpan(s, lineText, t, false);
|
||||||
if (lineTextOut) *lineTextOut = lineText;
|
if (lineTextOut) *lineTextOut = lineText;
|
||||||
return out.valid;
|
return out.valid;
|
||||||
@@ -943,14 +947,12 @@ static bool hitTestTarget(QsciScintilla* sci,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommandRow2: root class type, name, and alignas
|
// CommandRow2: root class type and name
|
||||||
if (lm.lineKind == LineKind::CommandRow2) {
|
if (lm.lineKind == LineKind::CommandRow2) {
|
||||||
ColumnSpan ts = commandRow2TypeSpan(lineText);
|
ColumnSpan ts = commandRow2TypeSpan(lineText);
|
||||||
if (inSpan(ts)) { outTarget = EditTarget::RootClassType; outLine = line; return true; }
|
if (inSpan(ts)) { outTarget = EditTarget::RootClassType; outLine = line; return true; }
|
||||||
ColumnSpan ns = commandRow2NameSpan(lineText);
|
ColumnSpan ns = commandRow2NameSpan(lineText);
|
||||||
if (inSpan(ns)) { outTarget = EditTarget::RootClassName; outLine = line; return true; }
|
if (inSpan(ns)) { outTarget = EditTarget::RootClassName; outLine = line; return true; }
|
||||||
ColumnSpan as = commandRow2AlignasSpan(lineText);
|
|
||||||
if (inSpan(as)) { outTarget = EditTarget::Alignas; outLine = line; return true; }
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1369,8 +1371,7 @@ bool RcxEditor::beginInlineEdit(EditTarget target, int line) {
|
|||||||
if (lm->nodeIdx < 0 && !(lm->lineKind == LineKind::CommandRow &&
|
if (lm->nodeIdx < 0 && !(lm->lineKind == LineKind::CommandRow &&
|
||||||
(target == EditTarget::BaseAddress || target == EditTarget::Source))
|
(target == EditTarget::BaseAddress || target == EditTarget::Source))
|
||||||
&& !(lm->lineKind == LineKind::CommandRow2 &&
|
&& !(lm->lineKind == LineKind::CommandRow2 &&
|
||||||
(target == EditTarget::RootClassType || target == EditTarget::RootClassName
|
(target == EditTarget::RootClassType || target == EditTarget::RootClassName)))
|
||||||
|| target == EditTarget::Alignas)))
|
|
||||||
return false;
|
return false;
|
||||||
// Padding: reject value editing (display-only hex bytes)
|
// Padding: reject value editing (display-only hex bytes)
|
||||||
if (target == EditTarget::Value && lm->nodeKind == NodeKind::Padding)
|
if (target == EditTarget::Value && lm->nodeKind == NodeKind::Padding)
|
||||||
@@ -1462,24 +1463,6 @@ bool RcxEditor::beginInlineEdit(EditTarget target, int line) {
|
|||||||
m_sci->viewport()->setCursor(Qt::ArrowCursor);
|
m_sci->viewport()->setCursor(Qt::ArrowCursor);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (target == EditTarget::Alignas) {
|
|
||||||
QTimer::singleShot(0, this, [this]() {
|
|
||||||
if (!m_editState.active || m_editState.target != EditTarget::Alignas) return;
|
|
||||||
int len = m_editState.original.size();
|
|
||||||
QString spaces(len, ' ');
|
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_SETSEL,
|
|
||||||
m_editState.posStart, m_editState.posEnd);
|
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_REPLACESEL,
|
|
||||||
(uintptr_t)0, spaces.toUtf8().constData());
|
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_GOTOPOS, m_editState.posStart);
|
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_AUTOCSETSEPARATOR, (long)'\n');
|
|
||||||
m_sci->SendScintilla(QsciScintillaBase::SCI_USERLISTSHOW,
|
|
||||||
(uintptr_t)1,
|
|
||||||
"alignas(1)\nalignas(4)\nalignas(8)\nalignas(16)");
|
|
||||||
m_sci->viewport()->setCursor(Qt::ArrowCursor);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1747,15 +1730,13 @@ void RcxEditor::paintEditableSpans(int line) {
|
|||||||
fillIndicatorCols(IND_EDITABLE, line, norm.start, norm.end);
|
fillIndicatorCols(IND_EDITABLE, line, norm.start, norm.end);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// CommandRow2: paint RootClassType, RootClassName, and Alignas spans
|
// CommandRow2: paint RootClassType and RootClassName spans
|
||||||
if (lm->lineKind == LineKind::CommandRow2) {
|
if (lm->lineKind == LineKind::CommandRow2) {
|
||||||
NormalizedSpan norm;
|
NormalizedSpan norm;
|
||||||
if (resolvedSpanFor(line, EditTarget::RootClassType, norm))
|
if (resolvedSpanFor(line, EditTarget::RootClassType, norm))
|
||||||
fillIndicatorCols(IND_EDITABLE, line, norm.start, norm.end);
|
fillIndicatorCols(IND_EDITABLE, line, norm.start, norm.end);
|
||||||
if (resolvedSpanFor(line, EditTarget::RootClassName, norm))
|
if (resolvedSpanFor(line, EditTarget::RootClassName, norm))
|
||||||
fillIndicatorCols(IND_EDITABLE, line, norm.start, norm.end);
|
fillIndicatorCols(IND_EDITABLE, line, norm.start, norm.end);
|
||||||
if (resolvedSpanFor(line, EditTarget::Alignas, norm))
|
|
||||||
fillIndicatorCols(IND_EDITABLE, line, norm.start, norm.end);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isSyntheticLine(*lm)) return;
|
if (isSyntheticLine(*lm)) return;
|
||||||
@@ -1890,7 +1871,6 @@ void RcxEditor::applyHoverCursor() {
|
|||||||
case EditTarget::ArrayElementType:
|
case EditTarget::ArrayElementType:
|
||||||
case EditTarget::PointerTarget:
|
case EditTarget::PointerTarget:
|
||||||
case EditTarget::RootClassType:
|
case EditTarget::RootClassType:
|
||||||
case EditTarget::Alignas:
|
|
||||||
desired = Qt::PointingHandCursor;
|
desired = Qt::PointingHandCursor;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -40,5 +40,7 @@
|
|||||||
<file alias="rename.svg">vsicons/rename.svg</file>
|
<file alias="rename.svg">vsicons/rename.svg</file>
|
||||||
<file alias="whole-word.svg">vsicons/whole-word.svg</file>
|
<file alias="whole-word.svg">vsicons/whole-word.svg</file>
|
||||||
<file alias="selection.svg">vsicons/list-selection.svg</file>
|
<file alias="selection.svg">vsicons/list-selection.svg</file>
|
||||||
|
<file alias="symbol-numeric.svg">vsicons/symbol-numeric.svg</file>
|
||||||
|
<file alias="symbol-ruler.svg">vsicons/symbol-ruler.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
@@ -1799,34 +1799,13 @@ private slots:
|
|||||||
QCOMPARE(tree.computeStructAlignment(rootId), 1);
|
QCOMPARE(tree.computeStructAlignment(rootId), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void testCommandRow2AlignasSpan() {
|
void testCommandRow2NameSpan() {
|
||||||
// Test span detection for alignas(N) in CommandRow2 text
|
// Name span should cover the class name
|
||||||
QString text = "struct MyClass alignas(8)";
|
|
||||||
ColumnSpan span = commandRow2AlignasSpan(text);
|
|
||||||
QVERIFY(span.valid);
|
|
||||||
QVERIFY(span.start >= 0);
|
|
||||||
QVERIFY(span.end > span.start);
|
|
||||||
|
|
||||||
QString spanText = text.mid(span.start, span.end - span.start);
|
|
||||||
QCOMPARE(spanText, QString("alignas(8)"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void testCommandRow2AlignasSpanNoMatch() {
|
|
||||||
// Text without alignas should return invalid span
|
|
||||||
QString text = "struct MyClass";
|
QString text = "struct MyClass";
|
||||||
ColumnSpan span = commandRow2AlignasSpan(text);
|
|
||||||
QVERIFY(!span.valid);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testCommandRow2NameSpanStopsBeforeAlignas() {
|
|
||||||
// Name span should NOT include the alignas part
|
|
||||||
QString text = "struct MyClass alignas(4)";
|
|
||||||
ColumnSpan nameSpan = commandRow2NameSpan(text);
|
ColumnSpan nameSpan = commandRow2NameSpan(text);
|
||||||
QVERIFY(nameSpan.valid);
|
QVERIFY(nameSpan.valid);
|
||||||
|
|
||||||
QString nameText = text.mid(nameSpan.start, nameSpan.end - nameSpan.start);
|
QString nameText = text.mid(nameSpan.start, nameSpan.end - nameSpan.start);
|
||||||
QVERIFY2(!nameText.contains("alignas"),
|
|
||||||
qPrintable("Name span should not include alignas: " + nameText));
|
|
||||||
QVERIFY2(nameText.trimmed() == "MyClass",
|
QVERIFY2(nameText.trimmed() == "MyClass",
|
||||||
qPrintable("Name span should be 'MyClass', got: '" + nameText.trimmed() + "'"));
|
qPrintable("Name span should be 'MyClass', got: '" + nameText.trimmed() + "'"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1058,20 +1058,20 @@ private slots:
|
|||||||
m_editor->cancelInlineEdit();
|
m_editor->cancelInlineEdit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Test: alignas span detection on CommandRow2 ──
|
// ── Test: CommandRow2 has class type and name but no alignas ──
|
||||||
void testAlignasSpanOnCommandRow2() {
|
void testCommandRow2NoAlignas() {
|
||||||
m_editor->applyDocument(m_result);
|
m_editor->applyDocument(m_result);
|
||||||
|
|
||||||
// Set CommandRow2 with alignas
|
// Set CommandRow2 without alignas
|
||||||
m_editor->setCommandRow2Text(QStringLiteral("struct _PEB64 alignas(8)"));
|
m_editor->setCommandRow2Text(QStringLiteral("struct _PEB64"));
|
||||||
|
|
||||||
// Line 1 is CommandRow2
|
// Line 1 is CommandRow2
|
||||||
const LineMeta* lm = m_editor->metaForLine(1);
|
const LineMeta* lm = m_editor->metaForLine(1);
|
||||||
QVERIFY(lm);
|
QVERIFY(lm);
|
||||||
QCOMPARE(lm->lineKind, LineKind::CommandRow2);
|
QCOMPARE(lm->lineKind, LineKind::CommandRow2);
|
||||||
|
|
||||||
// Alignas IS allowed as inline edit (picker-based)
|
// RootClassName should work
|
||||||
QVERIFY(m_editor->beginInlineEdit(EditTarget::Alignas, 1));
|
QVERIFY(m_editor->beginInlineEdit(EditTarget::RootClassName, 1));
|
||||||
QVERIFY(m_editor->isEditing());
|
QVERIFY(m_editor->isEditing());
|
||||||
m_editor->cancelInlineEdit();
|
m_editor->cancelInlineEdit();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user