uttrflow / uttrflow/uttrflow-swift

No AI suggestion is drawn for a caret under the Dock or menu bar band, where full-screen windows put their composer and address bar

Open
#618 0 comments 0 reactions 0 assignees View on GitHub
area:ai-suggestions bug help wanted P2
Dominant language
Swift
Stars
4
Forks
17
Avg merge
3h 32m
Merged PRs (30d)
277

Description

## What happens

`SuggestionPanelController` picks the screen holding the caret by its full `frame` (`Sources/Uttrflow/Suggestion/SuggestionPanelController.swift:166-169`). It then hands that screen's **`visibleFrame`** to the geometry:

```swift
// :171-174
(screenHoldingCaret ?? panel.screen ?? NSScreen.main ?? NSScreen.screens.first)?.visibleFrame
```

`SuggestionGeometry.anchor` refuses any caret whose point is not inside that rectangle (`Sources/UttrflowContext/SuggestionGeometry.swift:30`, `:66-73`):

```swift
if rect.isEmpty {
return screen.contains(CGPoint(x: rect.minX, y: rect.midY)) ? rect : nil
}
```

`visibleFrame` leaves out the menu bar and the Dock's band. AppKit keeps reporting it that way while a full-screen app has hidden both, so windows that do cover those bands still have their carets measured against the smaller rectangle:

- a full-screen window: chat composers sit at the very bottom, and a browser's address bar at the very top;
- a window the user has dragged or zoomed behind a Dock that is always shown;
- on a display with a notch, the taller menu bar band.

A thin caret (zero width, the usual case) in those bands fails `usable`, `anchor` returns nil, and `reposition()` orders the panel out. `Quieting` answers `nowhereToDraw` only from `context.canDraw` (`Sources/UttrflowPredict/Quieting.swift:18`), which is decided from the field reading, not from this geometry, so the two can disagree.

## Why it matters

A composer at the bottom of a full-screen chat window, and the address bar of a full-screen browser, are both prime places for a completion. On a 13-inch laptop, which most people keep in full screen, the bottom band is where they type.

## How to reproduce

A unit test shows the geometry half:

```swift
let frame = CGRect(x: 0, y: 0, width: 1440, height: 900)
let visible = CGRect(x: 0, y: 70, width: 1440, height: 797) // Dock and menu bar removed
let caret = CGRect(x: 400, y: 40, width: 0, height: 18) // composer in the Dock band
#expect(SuggestionGeometry.anchor(for: .inlineGhost, caret: caret, window: nil, screen: visible, size: CGSize(width: 200, height: 20)) == nil)
```

To confirm on a real Mac (`help wanted`): make a chat or browser window full screen, type into the bottom composer or the address bar, and report whether a ghost appears there when it does appear in the same app windowed.

## Acceptance criteria

- The caret is accepted if it lies anywhere on the screen's `frame`. `visibleFrame` is used only to keep the drawn panel from being clipped where that does not move it off the line.
- A ghost for a caret in the bottom or top band is placed on the caret's line, with tests for a caret in the Dock band and in the menu bar band.
- Whatever the geometry refuses, `canDraw` refuses too, so a caret that truly cannot be drawn for is quiet with `nowhereToDraw` before a candidate is generated.

Contributor guide

Open the contributing guide

Research direction

Start with Sources/Uttrflow/Suggestion/SuggestionPanelController.swift:166-174 and Sources/UttrflowContext/SuggestionGeometry.swift:30,66-73 to trace how screen.frame and visibleFrame reach anchor. Then inspect Sources/UttrflowPredict/Quieting.swift:18 and run or extend the geometry unit test with Dock-band and menu-bar-band carets. Done means those carets are accepted and positioned on their lines, while geometry failures consistently produce nowhereToDraw before candidate generation.

Written by the indexing model from the issue text.

Assessment

Tech stack
swift
Domain
accessibility, desktop-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.