ADFA-4419: Remote peer editor decoration API#1459
Conversation
Add IdeEditorService.addRemotePeerMarker/removeRemotePeerMarker/clearRemotePeerMarkers as default-implemented (backward-compatible) methods so a plugin can draw a remote collaborator's caret/badge inside the editor. Backed by a new EditorDecorationManager + RemotePeerMarkerWindow (an EditorPopupWindow overlay that tracks scroll via FEATURE_SCROLL_AS_CONTENT) in the app module; EditorProviderImpl resolves the live editor via EditorHandlerActivity.getEditorForFile and marshals onto the main thread, clearing markers on dispose. IdeEditorServiceImpl exposes read-gated overrides and the parallel EditorProvider contract methods. The new interface methods are default-implemented so this is an additive, non-breaking change for the generated plugin-api lib and existing implementers. Consumed by the Pair pair-programming plugin.
…e-peer-editor-decoration
…e-peer-editor-decoration
…orations Rename EditorDecorationManager -> PeerPresenceOverlayManager and extract a focused PeerPresenceProvider interface out of the broad EditorProvider, so the pair-programming peer-cursor overlay (floating named badges) reads as a distinct concern from the generic EditorDecorationProvider (additive color spans) added in #1448 (ADFA-4436). Host-internal only: no plugin-api contract changed and the merged rainbow- brackets plugin is unaffected. Verified with :app:compileV8DebugKotlin.
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.
Tip: disable this comment in your organization's Code Review settings.
|
@claude review |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
💤 Files with no reviewable changes (1)
🚧 Files skipped from review as they are similar to previous changes (4)
📝 Walkthrough
WalkthroughAdds peer-cursor presence rendering, an openProject plugin API and implementation, and plugin load-failure tracking with install-time verification. ChangesPeer Cursor Overlay Feature
openProject Plugin API Implementation
Plugin Load Error Tracking
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@app/src/main/java/com/itsaky/androidide/activities/editor/PeerPresenceOverlayManager.kt`:
- Around line 122-125: The clamping logic in PeerPresenceOverlayManager’s
position calculation does not handle the exact-fit case because when maxX is 0
it falls back to rawX, allowing the overlay to render off-screen; update the x
computation so the clamp applies whenever the editor width is known, including
when label.measuredWidth equals boundEditor.width, and keep the existing
rawX.coerceIn(0, maxX) behavior for all non-negative maxX values.
In
`@app/src/main/java/com/itsaky/androidide/repositories/PluginRepositoryImpl.kt`:
- Around line 147-154: The failure path in installPluginFromFile() leaves a
broken upgraded plugin on disk after the old version has already been removed,
so adjust the replace flow to avoid half-installed upgrades. Use the existing
load check around manager.loadPlugins()/manager.getPlugin(pluginId) to either
delay uninstalling the current plugin until the new package is proven loadable,
or restore the previous package on failure. In the failure branch that throws
IllegalStateException, also delete the copied finalFile so future
PluginRepositoryImpl loads do not keep retrying the bad artifact.
In
`@plugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/core/PluginManager.kt`:
- Around line 279-284: The load path in PluginManager.loadPlugins is swallowing
coroutine cancellation by catching all Exception around loadPlugin, so a
cancelled job is treated like a plugin failure instead of stopping execution.
Narrow the catch in the loadPlugin/result block to let CancellationException
pass through unchanged, and only wrap genuine plugin load errors in
Result.failure before calling recordLoadFailure.
In
`@plugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/services/IdeEditorServiceImpl.kt`:
- Around line 283-292: `hidePeerCursor` and `clearPeerCursors` in
`IdeEditorServiceImpl` are unnecessarily gated by `ensureFileAccessible(file)`,
which blocks overlay cleanup when the file/tab is no longer open. Remove the
accessibility check from these cleanup-only paths while keeping `requireRead()`
and the downstream `editorProvider.hidePeerCursor(...)` /
`editorProvider.clearPeerCursors(...)` calls so peer overlays can still be
dismissed by file key.
In
`@plugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/services/IdeProjectServiceImpl.kt`:
- Around line 97-105: Use the validated canonical project path in
IdeProjectServiceImpl.openProject and apply the existing PathValidator before
switching projects. The current flow checks containment with
isUnderProjectsDir(projectDir) but later persists the original path, so update
the openProject logic to reuse the validated canonical target and run it through
PathValidator like getProjectByPath does before calling the project
switch/selection code.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: e0348b09-b91a-4370-9cb1-9c72e245fff6
📒 Files selected for processing (7)
app/src/main/java/com/itsaky/androidide/activities/editor/PeerPresenceOverlayManager.ktapp/src/main/java/com/itsaky/androidide/app/EditorProviderImpl.ktapp/src/main/java/com/itsaky/androidide/repositories/PluginRepositoryImpl.ktplugin-api/src/main/kotlin/com/itsaky/androidide/plugins/services/IdeServices.ktplugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/core/PluginManager.ktplugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/services/IdeEditorServiceImpl.ktplugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/services/IdeProjectServiceImpl.kt
- PeerPresenceOverlayManager: clamp peer badge on exact-fit width (maxX >= 0) - PluginManager.loadPlugins: rethrow CancellationException instead of recording cancellation as a plugin load failure - IdeEditorServiceImpl: don't gate hidePeerCursor/clearPeerCursors on file accessibility, so overlay cleanup still works after a tab closes - IdeProjectServiceImpl.openProject: use the validated canonical path and run it through PathValidator before switching projects - PluginRepositoryImpl: delete the broken artifact when an upgraded plugin fails to load, so loadPlugins() doesn't keep retrying it - Drop PairTrace / [HOST] dev-trace Log.d (kept warn/error diagnostics)
Summary
Host-side support for the pair-programming plugin (ADFA-4419): lets the external
.cgppair plugin render remote collaborators in the editor and drive shared editing entirely throughplugin-api. The pair plugin itself ships separately; this PR adds only the host contract + bridge it talks to.