#560: GTK editor click lands 2–3 columns left of the clicked glyph — vimcode re-derives quadraui's text-layout inverse (needs quadraui hit-test API) - #562
Merged
JDonaghy merged 4 commits intoJul 6, 2026
Conversation
…aui's shared text-layout inverse quadraui#420 added Backend::editor_col_at_x / EditorLayout::col_at_x — a backend-owned inverse of the same layout draw_editor paints with. This wires vimcode's click handlers through it instead of hand-rolled math: - src/render.rs: new editor_text_layout() builds the Editor+EditorLayout pair exactly as paint does (to_q_editor + Editor::layout(editor.rect)), shared by both backends. - src/gtk/click.rs: pixel_to_click_target's TextArea arm now calls backend.editor_col_at_x(...) instead of building a second, attribute-less Pango layout and running xy_to_index by hand — the root cause of the 2-3 column left-drift on bold/italic/font_scale spans and scrolled lines. Threaded a GtkBackend reference through pixel_to_click_target/handle_mouse_click/handle_mouse_double_click/ handle_mouse_drag, dropping the now-redundant `pango_layout` param and the App::editor_pango_layout helper that built it. - src/tui_main/mouse.rs: the three TextArea click/drag/hover sites now call EditorLayout::col_at_x (the same function GTK's default falls back to) instead of duplicating the scroll_left/segment_col_offset arithmetic inline, so both backends' column math derives from one quadraui function. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…resolution The round-2 smoke test on the #560 fix (routing GTK click-column resolution through quadraui's editor_col_at_x) reported a NEW regression: clicks on markdown lines with emoji drifted one column right per preceding wide/multi-byte glyph, compounding across the line, while plain-text clicks stayed exact. Root-cause investigation (recorded in the issue's durable findings) reproduced the exact symptom shape only when GtkBackend::editor_col_at_x falls back to EditorLayout::col_at_x's naive uniform-monospace division (the fallback path used when no Pango layout is available) — the real per-glyph quadraui::gtk::editor_col_at_x (Pango xy_to_index) path was verified byte-exact for the reported repro string, both in isolation and now end-to-end through vimcode's actual render pipeline (real md_inline_spans bold-span byte offsets via build_screen_layout, then render::editor_text_layout + quadraui::gtk::editor_col_at_x). This strongly points to the smoke-tested artifact having been built against the stale/broken quadraui checkout noted in the issue's pinned environment finding (which predated the #420 merge this fix depends on), not a logic bug in the current quadraui HEAD or in vimcode's render.rs span-offset pipeline — both were re-verified correct here. Adds a regression test pinning the full pipeline against a real markdown line with base, astral-plane, and variation-selector emoji so a future reintroduction of the naive fallback (or a span byte-offset regression) fails `cargo test`, not just a manual click. Also includes a pre-existing rustfmt fixup in render.rs picked up by the mandatory `cargo fmt` pass, unrelated to this change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…l-backend fix) Iteration 2 root cause. The GTK editor-click emoji drift (click on a glyph after an emoji lands +1 column right; compounds per preceding wide glyph; plain monospace unaffected) is NOT in quadraui's per-glyph inverse — it is the dual-backend split introduced by the #540 ShellApp migration. quadraui's `gtk::run` runner creates its OWN `GtkBackend`, paints the editor with it (stashing `last_editor_pango_layout`), and passes it to `render_content` as the `&mut dyn Backend` arg. vimcode's `App` keeps a SEPARATE `self.backend` (mod.rs) used only for click hit-testing: it never paints and was never handed a Pango context. So at click time, `pixel_to_click_target -> self.backend.editor_col_at_x` found `last_editor_pango_layout = None` AND `pango_ctx = None`, and fell through to `EditorLayout::col_at_x`'s naive uniform-cell division — exact for monospace, but off by one column per preceding wide glyph (emoji/CJK). The prior fix's regression test called `quadraui::gtk::editor_col_at_x` directly with a correctly-fonted layout, so it verified the good branch while the live click took the naive one. Fix (thin wiring, mirrors what the runner does for its own backend): `render_content` now builds an editor-fonted PangoCairo context each frame and calls `self.backend.set_pango_context(...)`, so the click backend resolves columns through `quadraui::gtk::editor_col_at_x`'s exact per-glyph `xy_to_index` path instead of the naive division. Tests (src/gtk/click.rs): drive the REAL `GtkBackend::editor_col_at_x` trait method (with its fallback branch-selection), not the free function — - `live_trait_..._after_paint`: steady-state path via a stashed layout; - `editor_col_at_x_falls_back_to_editor_font_context_not_naive_division`: no paint, only `set_pango_context` (the live click state), proving the fix keeps resolution on the per-glyph path. Emoji here render 1.7-2.3x cell width, so a naive division would fail both. Note: `src/gtk/draw.rs::draw_editor` is dead since #540 (no callers); the live paint path is `render_content`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…tings Iteration-3 smoke failure root cause. The manual smoke test showed editor clicks landing LEFT of the target on plain, bold, italic AND scrolled lines, the drift GROWING the further right the click — not a constant fudge. That growth signature is a cell-width SCALE error, not the emoji-only +1-per-glyph fallback the iteration-2 fix addressed. The quadraui ShellApp runner (`quadraui::gtk::run`) paints the editor with a hardcoded "Monospace 11", ignoring `settings.font_family`/`font_size`; that painted '0' advance is what `Backend::char_width()` (== `cached_char_width`) reports and what `build_screen_layout` / `editor_text_layout` positioned glyphs with. The iteration-2 fix, however, fonted the click backend's Pango context from `settings.font_size` (default 14). So `editor_col_at_x`'s `xy_to_index` measured against glyphs ~1.27x too wide and scaled every column down — clicking column c resolved to ~c*11/14, i.e. left-drift growing with x (~1 char near line start, ~4 at the end). Emoji lines drifted too, stacked on the base scale error; horizontal scroll made it worst-magnitude. Fix: `App::render_content` now builds the click context via the new `click::build_editor_click_context(cw)`, which mirrors the runner's monospace family and tunes only the point size until a probe '0' advance equals the painted `char_width` (`cw`). Because it is the same family at the reproduced size, ALL glyph advances — plain, bold/italic (per-span attrs), emoji/CJK fallback — line up with the paint, so `xy_to_index` inverts exactly. The earlier emoji tests used ONE self-consistent font for both paint and resolve, so they never exercised the paint≠settings size split. New test `click_context_matches_painted_font_not_settings_size` reproduces it: paints at one size, resolves through the production-built context on a long plain ASCII line, asserts every column exact, and pins via `bad_drift_seen` that a size-mismatched context genuinely drifts (so the test can't pass trivially). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #560
Automated merge from the coordinator for assignment 20559e893aa2 on issue #560.
Worker branch:
issue-560-gtk-editor-click-lands-2-3-columns-left→develop.