uttrflow / uttrflow/uttrflow-swift
The AI suggestion ghost is placed for left-to-right text only: in Arabic or Hebrew it is anchored on the wrong side of the caret and drawn over what was typed
- Dominant language
- Swift
- Stars
- 4
- Forks
- 17
- Avg merge
- 3h 32m
- Merged PRs (30d)
- 277
Description
## What happens
Every step from caret to panel assumes the text runs left to right.
1. **The caret is taken from the wrong edge of the previous character.** `FocusedFieldReader.caret` (`Sources/UttrflowContext/FocusedFieldReader+System.swift:205-211`) places the caret at the previous character's right edge:
```swift
// The caret sits at the trailing edge of the glyph before it…
return CGRect(x: before.maxX, y: before.minY, width: 0, height: before.height)
```
For a right-to-left run, the logically previous character sits to the **right** of the caret, so its trailing edge is `minX`. The fallback at `:213-214` (`at.minX` of the next character) has the same assumption mirrored.
2. **The ghost is drawn to the right of that point.** `SuggestionGeometry.anchor` (`Sources/UttrflowContext/SuggestionGeometry.swift:35-40`) uses `x: caret.maxX`. `availableWidth` (`:44-49`) measures room from the caret to the field's or screen's **right** edge.
3. **Nothing asks which way the line runs.** Neither the reader nor the geometry reads direction:
```
$ git grep -n -i "rightToLeft\|writingDirection\|bidi" -- Sources/UttrflowContext Sources/UttrflowPredict Sources/Uttrflow/Suggestion
(no output)
```
`SuggestionView` lays out its text left to right as well.
For a user typing Arabic, Hebrew, Persian or Urdu, the ghost starts one character to the right of the real caret and extends rightwards, which is back over the words already typed. Its right-edge clamp is measured on the wrong side, so a caret near the field's left edge (where RTL lines end) still gets a full-width ghost. Mixed lines, such as an RTL sentence containing a Latin product code, have both problems at the run boundary.
No gate stops suggestions for these scripts: `Quieting` (`Sources/UttrflowPredict/Quieting.swift:31-63`) has no script or direction reason.
## Why it matters
Ghost text drawn over what someone just typed makes the field unreadable, and Tab would then accept a continuation the user could not read. Non-English users are the ones who get it.
## How to reproduce
Needs a real RTL field, so `help wanted`:
1. Add an Arabic or Hebrew input source and type a sentence in a plain multi-line text editor window. Pause at the end of the line.
2. With AI suggestions on, note where the ghost is drawn relative to the caret.
3. Run `uttrflow-dev probe surface` in the same field and report the caret rectangle it reads, alongside a screenshot description of where the real caret is.
## Acceptance criteria
- The reader reports a direction for the run at the caret, from `kAXAttributedStringForRangeParameterizedAttribute`'s paragraph style or by comparing the bounds of the previous and next characters, and takes the caret from the leading edge that direction implies.
- `SuggestionGeometry` anchors the ghost on the side the text grows towards, measures room towards that field or screen edge, and has tests for an RTL caret near either edge.
- `SuggestionView` lays out RTL text right to left. Where direction cannot be determined, the turn is quiet with a named reason rather than drawn on a guess.
Contributor guide
Research direction
Start by reading FocusedFieldReader+System.swift at lines 205-214, then trace SuggestionGeometry.swift lines 35-49 and the SuggestionView layout. Reproduce an RTL case with an Arabic or Hebrew input source and run `uttrflow-dev probe surface` to compare the reported caret with the real caret. Done means RTL and mixed-direction suggestions anchor and clamp correctly, have geometry coverage near both edges, and remain quiet when direction is unavailable.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- macos, swift
- Domain
- accessibility, desktop
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100