Skip to content

fix: Claude multiline suggestion placement#761

Open
akramj13 wants to merge 5 commits into
FuJacob:mainfrom
akramj13:codex/fix-claude-compat
Open

fix: Claude multiline suggestion placement#761
akramj13 wants to merge 5 commits into
FuJacob:mainfrom
akramj13:codex/fix-claude-compat

Conversation

@akramj13

@akramj13 akramj13 commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Correct Claude Desktop multiline ghost-text placement by detecting AXStaticText frames that span multiple visual lines.
  • Prefer exact previous-character AX bounds for wrapped runs, with TextKit layout estimation as a fallback.
  • Preserve the fast path for true single-line runs and avoid redundant descendant searches.
  • Restore fade-in settings initialization required for Cotabby Dev builds and add the project-local build/run action.

Root cause

Claude's Electron accessibility tree exposes a wrapped prompt as one AXStaticText frame. Cotabby treated that union rectangle as a single line and placed the caret proportionally inside it. Near the right edge, the overlay wrapped to the next line's left edge and covered existing text.

Validation

  • Cotabby Dev Debug build completed with code signing disabled and launched with -cotabby-debug.
  • Focused Xcode tests passed for caret run placement, focus selection, layout repair, text-layout estimation, AX geometry, throttle caching, and settings initialization.
  • Live Claude verification resolved wrapped runs through exact character bounds or the layout fallback instead of the single-line aligned-run path.
  • git diff --check passed.

Linked issues

solves #754

Risk / rollout notes

  • The additional AX bounds query runs only for ambiguous wrapped runs carrying the active selection.
  • Ordinary per-line static text runs remain on the existing measured fast path.

Greptile Summary

This PR fixes misplaced Claude Desktop ghost-text by detecting AXStaticText nodes whose frame is the union of multiple soft-wrapped lines rather than a single rendered line, then recovering the true caret position from either exact previous-character AX bounds or a TextKit layout estimate as a fallback.

  • Introduces canUseProportionalCaretPlacement to classify wrapped-union frames; adds allowsProportionalCaretPlacement and caretCharacterFrame to the TextRun cache so the expensive AppKit measurement and the per-character AX query happen only once per throttle window instead of on every caret poll.
  • Adds resolveWrappedRunCaret to handle the ambiguous-frame path separately, and threads allowsDeepSearch: false through CaretGeometryResultAXFocusCandidateCaretGeometrySelector.shouldSearchDeep to prevent the deep BFS from redundantly re-discovering the same union rect on every poll tick.
  • Restores two missing fadeIn* field assignments in SuggestionSettingsModel.applyData, adds the build_and_run.sh helper with a retry-polling launch-verify function, and expands test coverage with captured real-world Claude frames.

Confidence Score: 5/5

Safe to merge — all changed paths are well-guarded, the new wrapped-run detection is conservative by design, and the fix is covered by real captured-frame regression tests.

The classification heuristic intentionally favors false negatives over false positives, so the worst outcome of a misclassification is an extra IPC round-trip rather than misplaced ghost text. The allowsDeepSearch: false guard is threaded end-to-end without any gap. No existing behavior is removed — the single-line proportional path is preserved as the fast default.

No files require special attention.

Important Files Changed

Filename Overview
Cotabby/Services/Focus/AXTextGeometryResolver.swift Core change: adds wrapped-run detection via canUseProportionalCaretPlacement, early-exits to resolveWrappedRunCaret when the selected run is ambiguous, and refactors metrics to use only single-line runs. The selectedRun.frame direct access avoids the index-mismatch that would have occurred had cocoaRunFrames[placement.runIndex] been kept after filtering to measurableRuns.
Cotabby/Services/Focus/StaticTextRunWalkThrottle.swift Promotes TextRun from a named tuple to a proper struct, adding caretCharacterFrame and allowsProportionalCaretPlacement fields. The init with a nil default for the optional character frame preserves backward compatibility.
Cotabby/Support/CaretGeometrySelector.swift Adds primaryAllowsDeepSearch guard as the first check in shouldSearchDeep, short-circuiting to false before any quality evaluation. Default true preserves behavior for all existing callers.
Cotabby/Services/Focus/FocusSnapshotResolver.swift Threads caretAllowsDeepSearch from CaretGeometryResult through AXFocusCandidate to shouldSearchDeep. The ?? true default for nil results correctly preserves the "try deep search when no primary result exists" path.
Cotabby/Models/SuggestionSettingsModel.swift Adds two previously missing fadeInSuggestions and fadeInDurationSeconds assignments in applyData; a straightforward omission fix.
CotabbyTests/CaretRunPlacementTests.swift Adds six new tests covering proportional-placement classification using real captured Claude Desktop frames, increasing regression value significantly.
CotabbyTests/StaticTextRunWalkThrottleTests.swift Updates existing tests to use the new struct-based TextRun init; adds a test verifying that caretCharacterFrame and allowsProportionalCaretPlacement survive the throttle cache window together.
script/build_and_run.sh New helper script for Cotabby Dev builds with a proper polling loop replacing the prior sleep 1 race condition.
.codex/environments/environment.toml Registers the new build_and_run.sh as a Codex "Run" action. Autogenerated file, no logic concerns.

Reviews (3): Last reviewed commit: "fix: poll for dev app launch" | Re-trigger Greptile

@akramj13 akramj13 changed the title [codex] fix Claude multiline suggestion placement fix: Claude multiline suggestion placement Jun 28, 2026
@akramj13

Copy link
Copy Markdown
Contributor Author

@greptileai

@akramj13 akramj13 marked this pull request as ready for review June 28, 2026 22:13
Comment thread Cotabby/Services/Focus/AXTextGeometryResolver.swift Outdated
Comment thread Cotabby/Services/Focus/AXTextGeometryResolver.swift Outdated
Comment thread Cotabby/Services/Focus/AXTextGeometryResolver.swift
Comment thread Cotabby/Services/Focus/AXTextGeometryResolver.swift
Comment thread script/build_and_run.sh Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant