Preserve raw include diagnostic provenance and derive bands from the existing shaped editor. Retain deferred tooltip paragraphs through rendering. Include source, regression, failure and native-trial evidence; corrected native acceptance remains pending.
9.5 KiB
Text diagnostic rendering contract — issue 12
Selected implementation contract for the user's request, based on the published Text workspace contribution b4b860f. This document records decisions and evaluators, not completed implementation or native acceptance. Linux remains user-paused. Live ownership and progress belong in issue 12.
Source authority
Underlines represent primary Error or Warning diagnostics for the exact active logical path and current workspace snapshot. Half-open UTF-8 byte spans identify the analyzed text; displayed line/column labels are not geometry coordinates. Reject reversed, out-of-bounds and non-character-boundary ranges without repairing or relocating them. Related locations remain explanatory context in Problems and hover, rather than independently marking an earlier declaration as erroneous.
A fresh publication generation does not establish correct provenance by itself. Disk discovery must diagnose its actual returned raw bytes, and include replies must correspond to retained draft buffers before their diagnostics can be published as current. Compiled diagnostics may only accompany the compiled bundle they describe. Currentness checks must survive workspace/file A–B–A transitions, edits, Undo/Redo, replacement publications and delayed replies.
The editor's annotation snapshot binds current publication, source snapshot, exact path and exact draft bytes. Problems visibility and drawer visit are independent: hiding Problems must not remove current editor markings. Source mutations invalidate annotations immediately; caret movement and scrolling do not invalidate diagnostic content.
Visual ranges
Use the existing editor's actual shaped buffer after its syntax highlighting has been applied in draw. Do not infer positions from monospace widths or diagnostic scalar columns, shape a second document, search for matching alias text, or move the user's selection to measure a diagnostic.
Map absolute bytes using the editor engine's actual paragraph splitting, including CRLF, LFCR and standalone CR. The language's displayed LF-based line label may differ from a rendered paragraph number. Verify each affected run against the matching exact source slice. Wrapping creates several visual runs for one logical paragraph. The engine already applies vertical scroll in run coordinates; translate by the editor's padded origin once and clip against both its inner bounds and ancestor viewport.
Any glyph cluster intersected by a nonempty diagnostic receives a visual advance band. This is explicit cluster expansion for display, not a change to the exact diagnostic source span. Keep disjoint bidirectional intervals separate; merge only touching or overlapping intervals in one visual run. A half-open end at the next paragraph's start excludes that paragraph's text.
Empty ranges and ranges covering only a line separator receive a small insertion marker at their real logical boundary. They do not borrow a neighboring token's meaning. Markers must have bounded visible and hover areas. EOF on a trailing empty paragraph is distinct from the end of the previous paragraph. A multiline span marks its visible text pieces; an included empty paragraph uses an insertion marker. Invalid or unavailable geometry suppresses that annotation safely while Problems remains available.
An omitted wrapping separator uses the preceding visual run's logical trailing edge; its marker remains offscreen if that run is offscreen. An exact following-run start belongs to that following run. Inside a multi-grapheme shaping cluster, use cosmic-text's proportional grapheme-advance caret heuristic, with RTL direction respected. Inside one indivisible grapheme this is its canonical caret affordance, not a claim of an independently rendered byte position or font-provided ligature caret.
Error and Warning use distinguishable theme-aware underline colors, with error drawn above warning where they overlap. Hover detail explicitly spells the severity and preserves the code and message, so color is not the only indication. This work does not claim screen-reader access from painted hover text.
Hover and input
Compute hover from the same current, clipped visual bands that are drawn. An editor hit test alone is insufficient because it can snap blank space to a nearby character. Overlapping bands expose all corresponding primary diagnostics in deterministic severity/publication order; any bounded display states the remaining count and directs the user to Problems.
Prefer calculating passive hover during the current draw, without retaining pointer hitboxes or delayed authority. Pointer movement and leave must request redraw even when the stock editor's focus/hover status is unchanged. Delegate normal events without capturing, publishing edit/navigation messages, changing the source interaction clock, or touching Content/cursor/selection/scroll. Keep exactly one persistent editor child and the established Find/sensor layout topology.
Hide hover while a menu, modal or pending operation owns input; cursor unavailability from ancestors is respected. Hover has no click action, does not take focus and does not consume scrolling. It stays within the editor viewport and cannot obscure a dialog or a neighboring work area. A stationary pointer sees only the diagnostic publication and geometry rendered in the current frame.
Retain shaped tooltip paragraphs through deferred renderer preparation. The pinned WGPU renderer queues weak paragraph references; draw-local ownership alone paints a background with no text. Widget state owns the current frame's body/footer paragraphs and replaces or clears them on each draw, without reusing hover authority or hitboxes. A recording test must check weak-reference survival after draw returns, rather than copying glyphs immediately; the native blank-text failure established why that distinction matters.
Architectural experiment and alternatives
Pinned Iced 0.14.2 Content keeps its renderer Editor private. The underlying graphics Editor publicly exposes its actual cosmic-text Buffer, but the stock highlighter only supports color/font. An ordinary advanced wrapper cannot access arbitrary range geometry through widget operations.
The isolated experiment privately copied the pinned dependency and added a read-only Content::with_editor callback. Its recording renderer demonstrated that the accessor observes the same buffer geometry as actual fill_editor, including its origin and clipping, without changing selection or scroll. Independent source/result review accepted that bounded evidence. The selected dependency is now the repository copy at crates/vendor/iced_widget, excluded from workspace membership and resolved by the root Cargo patch. Its only upstream Rust change is the eight-line read-only accessor. The copy retains upstream provenance, an exact source manifest, the upstream license and an explicit patch note. No global registry files are edited.
Alternatives considered: color-only highlighting does not satisfy underlines/hover; a mirror layout duplicates layout and scroll authority; a renderer decorator requires wider renderer/Content type plumbing; copying the whole editor module changes Content/Binding types across existing helpers and maintains a second event implementation. The selected narrow accessor preserves existing types and behavior but adds vendor, license and upgrade maintenance. Revisit when upstream offers supported arbitrary range geometry, or an Iced upgrade changes the callback or editor layout contract. Source capture and notices must include the actual local dependency; it must not inherit the application license or a registry checksum merely because its package name/version matches upstream.
Evaluators before integration
- Actual-widget recording: accessor and
fill_editorshare visible shaped runs and padded clip; no mutation of text, selected bytes, cursor mode behavior or scroll. Include Word/Line selection followed by insertion to detect hidden-mode loss. - Geometry: narrow/wide reflow, nonzero scroll, partially clipped first/last lines, repeated aliases, tabs, mixed line endings, combining clusters, CJK, bidirectional text, multiple wraps, multiline spans, empty/EOF and newline-only ranges. Independent expected cluster coverage and blank-space misses; do not only compare the algorithm with itself.
- Authority: real raw no-ID discovery warnings, retained edited includes, obsolete replies, changed source/path/publication, malformed ranges beside a valid diagnostic, and overlapping primary/related locations.
- Event flow: pointer movement redraw while focus status is unchanged; leave; stock click/drag/word/line selection and typing; Find Close/Escape; scrolling; menu/modal occlusion; stationary-pointer publication replacement. Existing selected-byte regressions remain required.
- Native Windows: identified built binary and exact source inputs, realistic visible warning/error fixtures, hover message legibility, wrap/scroll/resize alignment, blank-space negatives, selection/edit/Undo and modal recovery. CPU geometry evidence alone is not native acceptance.
- Cost: index source paragraphs/diagnostic candidates when their content changes and visit only visible shaped runs during drawing. Do not reparse or reshape the full document on pointer movement. Measure a long document with many offscreen diagnostics before claiming acceptable responsiveness.
The provenance repair, geometry seam, actual annotation behavior and native acceptance are separate checkpoints within issue 12. Passing one does not close the whole request.