aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-10 09:30:37 +0200
committerDanilo M. <danix@danix.xyz>2026-08-10 09:30:37 +0200
commite1dba2987a9a1e87b92801959df9c9d4f1375d2f (patch)
tree25718fd36e87eac721f41b02cca46b6fb07e94d9
parent93e6a533f4b0cc1a75000b2f8c77181dfc56e199 (diff)
downloadqtmaildir-e1dba2987a9a1e87b92801959df9c9d4f1375d2f.tar.gz
qtmaildir-e1dba2987a9a1e87b92801959df9c9d4f1375d2f.zip
fix(view): indent a flat thread's replies like any other
A reply in a thread with no usable In-Reply-To carries depth 0, because that is how notmuch reports every message of such a thread. CardLayout read depth 0 as "not nested", so those replies drew flush against their own thread with no spine, while a nested thread's replies indented normally: the list showed two different shapes for the same relationship, side by side. A MESSAGE row is nested at least one level whatever depth it reports. Being a child row IS the nesting; the depth only says how much further to go. This is the third fault from the same root. The depth numbering was trusted to mean structure when it only ever meant "how notmuch happened to thread this": first it hid a flat thread's replies entirely, then it left the first message unreachable, and now it drew the survivors without their indent.
-rw-r--r--src/cardlayout.cpp12
-rw-r--r--tests/test_cardlayout.cpp36
2 files changed, 47 insertions, 1 deletions
diff --git a/src/cardlayout.cpp b/src/cardlayout.cpp
index 0e118ab..f542df0 100644
--- a/src/cardlayout.cpp
+++ b/src/cardlayout.cpp
@@ -103,7 +103,17 @@ CardLayout CardLayout::compute(const Input &input, const QRect &rect,
// Indent, capped. qMin rather than a branch so depth 5 and depth 50 land
// in exactly the same place.
- const int depth = qMin(input.depth, kMaxDepth);
+ //
+ // A MESSAGE row is nested at least one level whatever depth it reports.
+ // notmuch numbers every message of a thread with no usable In-Reply-To as
+ // depth 0, so a flat thread's replies arrived here claiming no nesting and
+ // drew flush against their own thread with no spine, while a nested
+ // thread's replies indented normally: two different shapes on screen for
+ // the same relationship. Being a child row IS the nesting; the depth only
+ // says how much further to go.
+ const int effectiveDepth =
+ input.isMessage ? qMax(1, input.depth) : input.depth;
+ const int depth = qMin(effectiveDepth, kMaxDepth);
const int indent = depth * kIndentStep;
out.contentLeft = textLeft + kPaddingX + indent;
diff --git a/tests/test_cardlayout.cpp b/tests/test_cardlayout.cpp
index 48bba25..fdc18bf 100644
--- a/tests/test_cardlayout.cpp
+++ b/tests/test_cardlayout.cpp
@@ -30,6 +30,7 @@ private slots:
void everyCardIsTheSameHeight();
void threeLinesStackWithoutOverlapping();
void replyIndentsByDepth();
+ void aDepthZeroReplyStillIndents();
void indentStopsAtTheCap();
void expanderSitsOnTheSecondLine();
void expanderIsEmptyWithoutReplies();
@@ -139,6 +140,41 @@ void TestCardLayout::replyIndentsByDepth()
}
}
+void TestCardLayout::aDepthZeroReplyStillIndents()
+{
+ // A reply in a FLAT thread carries depth 0, because notmuch reports every
+ // message of a thread with no usable In-Reply-To as a top-level message.
+ // It is still a reply: it is a child row under the root card, and it has
+ // to read as one.
+ //
+ // Treating depth 0 as "no nesting" left those replies flush against their
+ // thread with no spine, while a nested thread's replies indented normally,
+ // so the list showed two different shapes for the same relationship.
+ const QFont font;
+ const int h = CardLayout::heightFor(font);
+ const QRect rect(0, 0, 400, h);
+
+ CardLayout::Input flatReply;
+ flatReply.isMessage = true;
+ flatReply.depth = 0;
+
+ const CardLayout root = CardLayout::compute(threadInput(), rect, font);
+ const CardLayout reply = CardLayout::compute(flatReply, rect, font);
+
+ QVERIFY2(reply.contentLeft > root.contentLeft,
+ "a depth-0 reply sits flush with its thread, so a flat thread's "
+ "replies look like more threads");
+ QVERIFY2(!reply.spines.isEmpty(),
+ "a depth-0 reply has no spine, so nothing joins it to the thread "
+ "above it");
+
+ // And it lands at the same place a depth-1 reply does: the two are the
+ // same relationship and notmuch's numbering is the only difference.
+ const CardLayout nested = CardLayout::compute(replyInput(1), rect, font);
+ QCOMPARE(reply.contentLeft, nested.contentLeft);
+ QCOMPARE(reply.spines.size(), nested.spines.size());
+}
+
void TestCardLayout::indentStopsAtTheCap()
{
const QFont font;