From a7de9cc8c53a97b86e1cb805257d515e36bbe5e8 Mon Sep 17 00:00:00 2001 From: Pascal Garber Date: Wed, 11 Nov 2026 13:04:57 +0100 Subject: [PATCH] fix(ui): wire copy button of lone code blocks A deferred section that is just a code block is the SourceView itself; wireSubtree only walked descendants, so its copy event reached nobody (seen on Android, where the tutorial defers sections). --- packages/ui/src/mdx/mdx-view.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/ui/src/mdx/mdx-view.ts b/packages/ui/src/mdx/mdx-view.ts index 76731a1b..f47e3a6e 100644 --- a/packages/ui/src/mdx/mdx-view.ts +++ b/packages/ui/src/mdx/mdx-view.ts @@ -205,25 +205,34 @@ export class MdxView extends Adw.Bin { } /** - * Wires everything under `root`, and returns whether there was anything. Re-runnable: the RTL + * Wires `root` and everything under it, and returns whether there was anything. Re-runnable: the RTL * pass is idempotent and a code block is connected once however often it is walked. * * Needed past {@link wire}'s one walk because {@link revealDeferred} attaches sections AFTER - * it: those were never under the walk, so their copy buttons reached nobody. + * it: those were never under the walk, so their copy buttons reached nobody. `root` itself is + * walked too: a deferred section that is just a code block IS the `SourceView`, with nothing + * above it for {@link descendants} to yield. */ private wireSubtree(root: Gtk.Widget): boolean { const rtl = this.get_direction() === Gtk.TextDirection.RTL; let found = false; - for (const child of descendants(root)) { - found = true; + const walk = (child: Gtk.Widget): void => { if (child instanceof SourceView) { - if (this.wiredBlocks.has(child)) continue; + if (this.wiredBlocks.has(child)) return; this.wiredBlocks.add(child); // TODO: Disconnect the signal when the source view is destroyed child.events.on("copy", (event: SourceViewCopyEvent) => this.emit("copy", event.code)); } else if (rtl && child instanceof Gtk.Label && child.label) { child.label = applyRtlBaseDirection(child.label); } + }; + if (root instanceof SourceView) { + walk(root); + return true; + } + for (const child of descendants(root)) { + found = true; + walk(child); } return found; }