Skip to content

refactor(cursor-overlay): extract rotate_toward into shared util crate - #1662

Merged
f-trycua merged 1 commit into
mainfrom
refactor/cursor-overlay-rotate-toward-util
May 23, 2026
Merged

refactor(cursor-overlay): extract rotate_toward into shared util crate#1662
f-trycua merged 1 commit into
mainfrom
refactor/cursor-overlay-rotate-toward-util

Conversation

@f-trycua

@f-trycua f-trycua commented May 23, 2026

Copy link
Copy Markdown
Collaborator

Summary

Pure refactor — no behavior change. Extracts the `rotate_toward` function (~10 LOC) from `platform-linux/src/overlay.rs` and `platform-windows/src/overlay.rs` into the shared `cursor-overlay` crate at `src/util.rs`, plus 4 unit tests covering the wraparound + clamp logic.

`rotate_toward` rotates a current angle toward a desired angle by at most `max_step` radians, picking the short way around. It was identically copy-pasted in both per-OS overlays; consolidating removes the duplication and unit-tests the modular-arithmetic edges.

Diff

  • `crates/cursor-overlay/src/util.rs` — new module with 4 unit tests
  • `crates/cursor-overlay/src/lib.rs` — add `pub mod util;`
  • `crates/platform-linux/src/overlay.rs` — use `cursor_overlay::util::rotate_toward`
  • `crates/platform-windows/src/overlay.rs` — same

Tests

`cargo test -p cursor-overlay --lib util::tests` → 4/4 passing (verified locally + on Windows VM).

The 4 cases:

  • `no_motion_when_aligned` — current == desired returns current
  • `clamps_to_max_step` — large differences clamp to ±max_step
  • `picks_short_way_around` — desired on the "other side" of π wraps the short way
  • `negative_direction_when_shorter` — negative-direction wrap when shorter

Test plan

  • cargo test passing locally + on Windows VM
  • Both per-OS overlays compile and link
  • CI green
  • No behavior regression on the cursor-overlay smoke test (animation should look identical)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Refactor
    • Extracted cursor heading rotation logic into a shared utility module within the overlay component, now used across platform implementations. The shared rotation utility provides incremental angle adjustment with intelligent wrap-around handling. This consolidation eliminates duplicate code between Windows and Linux overlays while preserving the existing rotation behavior and animation smoothness for all cursor heading changes.

Review Change Stack

`rotate_toward` (angle-easing primitive used by per-OS overlay render loops)
was duplicated verbatim — 6 lines, identical — between
platform-windows/src/overlay.rs and platform-linux/src/overlay.rs.

Pulled it into a new `cursor-overlay/src/util.rs` module so both per-OS
backends (and any future ones — Wayland-native, etc.) share the same
math. Added 4 unit tests covering:

- no-motion-when-aligned (current == desired)
- clamping to max_step
- short-way wrap (current=0.95π, desired=-0.95π) takes the +0.1π path
  not the -1.9π path
- negative wrap (current=-0.95π, desired=0.95π) takes the -0.1π path

This is the first pass at the "abstract visual components between OSes"
work surfaced in the 2026-05-23 overnight journal. Render-loop functions
(`render_frame`, `draw_default_arrow`) are LARGER and per-OS state shapes
differ (Win: virt_w/h, Linux: scr_w/h) — those need a follow-up that
unifies the state-name surface before they can be shared.

Local-only; not pushed yet.
@vercel

vercel Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Ignored Ignored Preview May 23, 2026 12:21pm

Request Review

@coderabbitai

coderabbitai Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 38fc73fd-18b0-4bd0-a555-8ae7ed1f9aa1

📥 Commits

Reviewing files that changed from the base of the PR and between e37687c and 91c953c.

📒 Files selected for processing (4)
  • libs/cua-driver-rs/crates/cursor-overlay/src/lib.rs
  • libs/cua-driver-rs/crates/cursor-overlay/src/util.rs
  • libs/cua-driver-rs/crates/platform-linux/src/overlay.rs
  • libs/cua-driver-rs/crates/platform-windows/src/overlay.rs

📝 Walkthrough

Walkthrough

The PR extracts the rotate_toward angle interpolation function from Linux and Windows platform overlays into a shared utility module within the cursor-overlay crate. Both platforms previously implemented identical logic locally; this change centralizes it into a single tested implementation that both can depend on.

Changes

Shared rotation utility extraction

Layer / File(s) Summary
Shared rotate_toward utility
libs/cua-driver-rs/crates/cursor-overlay/src/lib.rs, libs/cua-driver-rs/crates/cursor-overlay/src/util.rs
A new util module exports rotate_toward(current, desired, max_step) for incrementally rotating an angle toward a target with wrap-around normalization to (-π, π] and step clamping. Unit tests validate alignment detection, step limits, shortest-path wrap direction, and rotation sign for both positive and negative wrap cases.
Platform overlay integration
libs/cua-driver-rs/crates/platform-linux/src/overlay.rs, libs/cua-driver-rs/crates/platform-windows/src/overlay.rs
Both Linux and Windows overlay implementations replace their local rotate_toward definitions with imports from the shared cursor_overlay::util module for heading interpolation.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A rabbit hops 'cross code domains,
Where angles spun cause motion pains,
One function shared, both paths align,
No duplication on the line!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: extracting the rotate_toward function into a shared util module within the cursor-overlay crate for code reuse across platforms.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 refactor/cursor-overlay-rotate-toward-util

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@f-trycua
f-trycua merged commit 6978a09 into main May 23, 2026
5 checks passed
@f-trycua
f-trycua deleted the refactor/cursor-overlay-rotate-toward-util branch May 23, 2026 14:39
f-trycua added a commit that referenced this pull request May 23, 2026
…arnings cleanup (#1665)

* fix(cua-driver-rs)(uninstall): converge uninstall.{ps1,sh} + UAC self-elevation

Three changes that together let -AutoStart installs roll back cleanly:

1. uninstall.ps1 self-elevates via UAC when it detects an -AutoStart
   install. The cua-driver-serve task is registered at RunLevel=Highest
   (autostart.rs:127, since 2026-05-21 for UWP/AppContainer support), so
   the daemon spawned by it runs at High IL and a non-elevated process
   — even the same user who installed it — could neither terminate the
   daemon nor delete the task. Detection: schtasks /Query OR a running
   cua-driver.exe. Re-exec via Start-Process -Verb RunAs; supports both
   `-File` invocation and `irm | iex` (materialises body to tempfile).

2. uninstall.sh inlines what _uninstall-rust.sh used to do — single
   canonical script per shell, mirrors uninstall.ps1's shape. Same
   --experimental-rust / --backend=rust / --backend=swift flag set,
   same non-macOS Rust auto-select. _uninstall-rust.sh deleted.

3. cd-rust-cua-driver.yml drops the cp _uninstall-rust.sh release-upload
   line + updated comment. installation.mdx docs page reflects the new
   one-file-per-shell shape and the .ps1 self-elevation behaviour.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(cua-driver-rs)(install-local.ps1): UTF-8 read for post-install-hints

The `Next steps:` block rendered with mojibake (`•` for `•`, `â€"`
for `—`) because PowerShell 5.1's `Get-Content -Raw` defaults to
Windows-1252 when the source file has no BOM. The .txt is UTF-8.

Replaced `Get-Content -Raw` with `[System.IO.File]::ReadAllText(...,
UTF8)`. Surgical fix at the one Windows reader; the other 3 installers
(install.ps1 via Invoke-WebRequest HTTP-charset, _install-rust.sh /
install-local.sh via sed on bytes) were never affected, so the .txt
stays BOM-free.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* chore(cua-driver-rs): clean up 30 build warnings in -p cua-driver path

`cargo build --release -p cua-driver` previously emitted 28 warnings
on platform-windows + 3 on cua-driver. After this commit: zero.

Mechanical groups:

1. Dead code (delete):
   - overlay.rs: unused `Duration` import; 2 stray `use Win32::*` lines
     (PR #1662 fallout from rotate_toward extraction); 2 unused `mut`;
     uia/mod.rs lines 173-174 dead writes to `counter`/`total` that
     are never read after the fallback block.
   - cli.rs: deleted unused `run_dump_docs` wrapper — `main.rs` only
     calls `run_dump_docs_with_type`, the wrapper had zero callers.
2. #[allow(dead_code)] on bundle.rs non-macOS/non-unix stubs — they
   exist for cross-platform API symmetry per the module header.
3. `let _ = ` on 10 Win32 teardown calls (ShowWindow, TranslateMessage,
   DeleteDC, UpdateLayeredWindow, DeleteObject) that return BOOL /
   Result. These are fire-and-forget at end-of-scope; the lint wants
   explicit ignore.
4. Module-scope #![allow(non_upper_case_globals)] in uia/windows_enum.rs
   — pattern-matches against `UIA_*ControlTypeId` constants from the
   `windows` crate (we can't rename external symbols). Mirrors the
   existing `#![allow(...)]` at overlay.rs:12.

Cargo.lock picks up the 0.2.7 → 0.2.18 workspace-version-bump that
shipped earlier this session.

The `TypeTextCharsTool { state: _state }` rename + per-tool description
thickening on platform-windows/tools/impl_.rs land in a follow-up
commit alongside the agent-guidance refactor.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(cua-driver-rs): agent-guidance refactor — Skills/MCP-instructions/per-tool

Three changes informed by a survey of how OSS computer-use tools push
usage guidance to LLM agents (Playwright MCP, browser-use, Goose,
Open Interpreter, Anthropic computer-use cookbook) cross-checked
against the MCP spec + Claude Skills convention.

Findings driving the changes:

- Anthropic's documented Skills tip is "Keep SKILL.md under 500 lines;
  move detailed reference material to separate files"
  (code.claude.com/docs/en/skills). Our SKILL.md was 911 lines.
- The MCP `instructions` field is spec'd as a hint that "MAY be added
  to the system prompt" — eager, every-turn cost. Community ceiling
  ~200 words. Goose templates its `instructions` per-OS (AX vs UIA
  vs AT-SPI) so the agent only sees the path that applies.
- AGENT_INSTRUCTIONS reaches every MCP client uniformly (Hermes,
  Cursor, Copilot CLI, plus Claude-Skills-aware agents over MCP).
  SKILL.md reaches only the 4 agents with a Skills loader. So both
  surfaces should cross-reference each other rather than duplicate.

Changes:

1. **SKILL.md split**: 911 lines → 493-line cross-platform entrypoint
   (snapshot invariant, CLI/MCP defaults, behavior matrix, canonical
   loop, pixel-click contract, common errors) + new MACOS.md (475
   lines) carrying the no-foreground contract, AppleScript / `open`
   prohibitions, AXMenuBar navigation, SkyLight click dispatch, and
   the Apple-Events JS bridge. Existing WINDOWS.md (686), LINUX.md
   (87), WEB_APPS.md (477), RECORDING.md (120) untouched — they were
   already separated. (Sibling Swift driver skill at
   libs/cua-driver/Skills/cua-driver/SKILL.md is 887 lines — also
   over budget but out of scope for this Rust-port PR.)

2. **AGENT_INSTRUCTIONS in crates/mcp-server/src/protocol.rs**:
   - Converted from `const &str` to `fn() -> String` so it can be
     templated at compile time per host (`cfg!(target_os = ...)`).
     macOS clients see "AX (Accessibility)", Windows see "UIA (UI
     Automation)", Linux see "AT-SPI" — same pattern as Goose's
     ComputerController + Open Interpreter's `platform.system()`.
   - Added a closing line pointing skill-aware harnesses at SKILL.md
     + the relevant per-OS companion (e.g. MACOS.md on macOS). MCP
     clients without a skills loader (Hermes, Cursor) ignore the
     pointer; clients with one get a free description-match hint.
   - Tightened the workflow: 5 steps including re-snapshot, dropped
     the redundant list_apps step in favor of launch_app's `windows`
     array. Still under 200 words.

3. **Thicker per-tool descriptions** on click + screenshot (all 3
   platforms): pushed "prefer element_index over pixel coords"
   guidance onto click (per Playwright's "this is better than
   screenshot" editorial pattern), and a pointer to get_window_state
   + max_image_dimension=1568 default onto screenshot. Per-call
   gating rather than per-session — Anthropic computer-use cookbook
   shape.

Also includes the `TypeTextCharsTool { state: _state }` rename on
platform-windows/tools/impl_.rs (the warnings-cleanup change that
overlapped this file — the only field rename, struct still
intentionally unregistered per the comment at impl_.rs:3991).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(cua-driver-rs): address CodeRabbit review on #1665

Six findings, all valid:

1. SKILL.md:114 — added `bash` language identifier to the canonical-
   workflow fenced code block (MD040 lint + syntax highlighting).
2. MACOS.md:373 — added `bash` identifier to the osascript activate
   fallback fence.
3. MACOS.md:414 — added `bash` identifier to the
   get_window_state-with-javascript example fence.
4. uninstall.sh:78-80 — `--backend=swift` was silently overridden by
   the auto-Rust-on-non-Darwin branch (the doc calls it an "explicit
   no-op default" but the code ignored the explicit signal). Added a
   BACKEND_EXPLICIT flag set by every `--backend=*`/`--experimental-rust`
   arm; the auto-Rust dispatch checks it and skips when the user
   pinned a backend.
5. uninstall.sh — `/Applications/CuaDriver.app` is shared between
   Swift and Rust on macOS (same bundle id `com.trycua.driver` since
   cua-driver-rs ≥ 0.2.4), so the prior Rust-branch logic could
   delete a Swift-only Mac's bundle, symlink, and Claude MCP
   registrations on a stray `uninstall.sh --experimental-rust`.
   Added a $RUST_INSTALL_PRESENT marker computed up-front from
   unambiguous Rust artifacts (HOME_DIR, legacy CuaDriverRs.app,
   LaunchAgent plist, systemd unit) and gated every shared-path
   removal on it:
     - CLI symlink case branch (split into "unambiguous Rust paths"
       and "shared path; require marker")
     - .app bundle removal (legacy unconditionally; canonical only
       when marker present)
     - Claude MCP scrub (the Python heredoc now reads
       RUST_INSTALL_PRESENT from env and gates the
       `/Applications/CuaDriver.app` match on it; unambiguous Rust
       anchors still match unconditionally)
6. protocol.rs:188-209 — converted AGENT_INSTRUCTIONS format! string
   to a raw string literal (r#"..."#). Drops the backslash line
   continuations + escaped backticks; identical runtime output, much
   easier to read.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
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