Skip to content

Add mouse cursor shape, visibility, and link hover URL support#32

Merged
trydis merged 2 commits intomainfrom
mouse-cursor-shape
Mar 17, 2026
Merged

Add mouse cursor shape, visibility, and link hover URL support#32
trydis merged 2 commits intomainfrom
mouse-cursor-shape

Conversation

@trydis
Copy link
Owner

@trydis trydis commented Mar 17, 2026

Handle GHOSTTY_ACTION_MOUSE_SHAPE, MOUSE_VISIBILITY, and MOUSE_OVER_LINK actions from libghostty. Cursor shape changes via resetCursorRects/NSCursor mapping (15 shapes with macOS 15+ columnResize/rowResize fallbacks), cursor hide/show via setHiddenUntilMouseMoves, and hovered link URLs surfaced as a dual-pill tooltip overlay in PaneLeafView that toggles sides to avoid the cursor.

Summary by CodeRabbit

  • New Features
    • URL hover tooltips appear when hovering links with Cmd, pinning left or right to avoid obscuring content and allowing side flipping.
    • Hover state now propagates from the terminal to the surrounding pane so tooltips update reliably.
    • Cursor behavior is enhanced: shape and visibility update dynamically based on terminal mouse interactions.

Handle GHOSTTY_ACTION_MOUSE_SHAPE, MOUSE_VISIBILITY, and MOUSE_OVER_LINK
actions from libghostty. Cursor shape changes via resetCursorRects/NSCursor
mapping (15 shapes with macOS 15+ columnResize/rowResize fallbacks), cursor
hide/show via setHiddenUntilMouseMoves, and hovered link URLs surfaced as a
dual-pill tooltip overlay in PaneLeafView that toggles sides to avoid the cursor.
@coderabbitai
Copy link

coderabbitai bot commented Mar 17, 2026

📝 Walkthrough

Walkthrough

Adds hover-URL propagation and tooltip rendering plus cursor-shape support: a new onHoverUrlChange callback is threaded through GhosttyRuntime → GhosttyTerminalView, PaneLeafView consumes it to show a tooltip, and LibghosttySurfaceView maps mouse actions to cursor updates and hover events.

Changes

Cohort / File(s) Summary
Runtime: surface callbacks
Sources/Shellraiser/Infrastructure/Ghostty/GhosttyRuntime.swift
Added SurfaceCallbacks.onHoverUrlChange: (String?) -> Void; extended registerSurfaceCallbacks and acquireHostView signatures to accept/store onHoverUrlChange; handle MOUSE_OVER_LINK, MOUSE_SHAPE, MOUSE_VISIBILITY.
Terminal view wiring
Sources/Shellraiser/Features/Terminal/GhosttyTerminalView.swift
Added let onHoverUrlChange: (String?) -> Void to GhosttyTerminalView and passed it into host acquisition/updating (makeNSView/updateNSViewacquireHostView).
Pane UI / tooltip
Sources/Shellraiser/Features/WorkspaceDetail/PaneLeafView.swift
Added hoverUrl: String? and isHoveringURLLeft: Bool state; bound terminal's onHoverUrlChange to update state; render conditional left/right tooltip overlay with hit-test semantics.
Surface view cursor handling
Sources/Shellraiser/Infrastructure/Ghostty/LibghosttySurfaceView.swift
Introduced currentCursor, resetCursorRects(), setCursorShape(_:), and nsCursor(for:) to map Ghostty cursor shapes to NSCursor and apply cursor rects.

Sequence Diagram

sequenceDiagram
    participant User
    participant Ghostty as Ghostty Surface
    participant Runtime as GhosttyRuntime
    participant Terminal as GhosttyTerminalView
    participant Pane as PaneLeafView
    participant UI as Tooltip

    User->>Ghostty: Hover mouse over link
    Ghostty->>Runtime: Emit MOUSE_OVER_LINK (with URL) / MOUSE_SHAPE / MOUSE_VISIBILITY
    Runtime->>Runtime: Map action -> invoke onHoverUrlChange / setCursorShape / toggle visibility
    Runtime->>Terminal: onHoverUrlChange(url)
    Terminal->>Pane: Deliver onHoverUrlChange(url)
    Pane->>Pane: Set hoverUrl / isHoveringURLLeft state
    Pane->>UI: Render tooltip overlay
    UI->>User: Display hovered URL tooltip
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main changes: adding mouse cursor shape support, cursor visibility toggling, and hover URL link detection.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch mouse-cursor-shape
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Sources/Shellraiser/Features/WorkspaceDetail/PaneLeafView.swift`:
- Around line 310-351: The hit-testing disablement on the ZStack is causing the
tooltip to get stuck because when isHoveringURLLeft == true the entire ZStack
ignores pointer events so the right-side Text's onHover can't get the exit
event; remove or change the .allowsHitTesting(!isHoveringURLLeft) usage in
PaneLeafView (the ZStack that contains hoverUrl and the two HStacks) so hit
testing remains enabled (e.g., remove the modifier or set
allowsHitTesting(true)), or instead apply hit-testing control only to the
non-interactive background layer rather than the whole ZStack; if the sticky
behavior is intentional, add a short doc comment next to isHoveringURLLeft
explaining this design.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dc8df599-1fa6-475e-a121-215d3975b679

📥 Commits

Reviewing files that changed from the base of the PR and between a05792d and 0772280.

📒 Files selected for processing (4)
  • Sources/Shellraiser/Features/Terminal/GhosttyTerminalView.swift
  • Sources/Shellraiser/Features/WorkspaceDetail/PaneLeafView.swift
  • Sources/Shellraiser/Infrastructure/Ghostty/GhosttyRuntime.swift
  • Sources/Shellraiser/Infrastructure/Ghostty/LibghosttySurfaceView.swift

Move .allowsHitTesting(false) from ZStack to the right-side HStack only,
so the left-side HStack's onHover can still receive exit events when the
cursor moves away.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
Sources/Shellraiser/Features/WorkspaceDetail/PaneLeafView.swift (1)

311-351: Refactor duplicated tooltip UI into a small helper view.

The left/right tooltip branches duplicate most modifiers. Extracting a focused helper will keep panelBody easier to read and maintain.

As per coding guidelines, "Prefer small, composable methods and keep methods focused and readable".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/Shellraiser/Features/WorkspaceDetail/PaneLeafView.swift` around lines
311 - 351, The tooltip branches in PaneLeafView's panelBody duplicate the same
Text + padding + background + modifiers for left/right; extract a small reusable
View (e.g., TooltipBubble or HoverURLView) that takes hoverUrl: String,
cornerRadii: CornerRadii/Bool (or isLeft: Bool), and an optional onHover
handler, move the shared Text(...) modifiers and UnevenRoundedRectangle
background into that helper, then replace the two HStack/VStack blocks with
instances of the new HoverURLView wired to isHoveringURLLeft and .onHover to
preserve existing behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@Sources/Shellraiser/Features/WorkspaceDetail/PaneLeafView.swift`:
- Around line 311-351: The tooltip branches in PaneLeafView's panelBody
duplicate the same Text + padding + background + modifiers for left/right;
extract a small reusable View (e.g., TooltipBubble or HoverURLView) that takes
hoverUrl: String, cornerRadii: CornerRadii/Bool (or isLeft: Bool), and an
optional onHover handler, move the shared Text(...) modifiers and
UnevenRoundedRectangle background into that helper, then replace the two
HStack/VStack blocks with instances of the new HoverURLView wired to
isHoveringURLLeft and .onHover to preserve existing behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: eeb75e5e-24de-4330-b5a8-11a5feb7fa3b

📥 Commits

Reviewing files that changed from the base of the PR and between 0772280 and e713e9b.

📒 Files selected for processing (1)
  • Sources/Shellraiser/Features/WorkspaceDetail/PaneLeafView.swift

@trydis trydis merged commit 05e1cc2 into main Mar 17, 2026
2 checks passed
@trydis trydis deleted the mouse-cursor-shape branch March 17, 2026 22:16
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