Skip to content

ADFA-4436 Add a generic editor decoration provider extension point#1448

Merged
hal-eisen-adfa merged 5 commits into
stagefrom
ADFA-4436-editor-coloring-hook
Jun 26, 2026
Merged

ADFA-4436 Add a generic editor decoration provider extension point#1448
hal-eisen-adfa merged 5 commits into
stagefrom
ADFA-4436-editor-coloring-hook

Conversation

@hal-eisen-adfa

@hal-eisen-adfa hal-eisen-adfa commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a generic, additive way for plugins to contribute foreground colors to editor text, layered on top of normal syntax highlighting — never replacing it. The IDE is feature-agnostic: it knows nothing about what a provider decorates (brackets, indent guides, markers, …); it just merges the spans a provider returns.

Motivation: the only pre-existing editor-coloring hook, EditorExtension.provideSyntaxHighlighting(), is dead code (zero call sites) and semantically unsuited — it returns a fixed semantic enum with no RGB/depth and would replace all highlighting. It is left untouched here.

API

interface EditorDecorationProvider : IPlugin {
    fun decorate(text: CharSequence, start: Int, end: Int, isDark: Boolean): List<DecorationSpan>
}
data class DecorationSpan(val start: Int, val end: Int, val argb: Int)

The provider receives the full document content and a region, and returns additive, foreground-only color spans. All feature logic lives in the plugin.

Changes

  • plugin-apiEditorDecorationProvider + DecorationSpan.
  • plugin-managergetEnabledEditorDecorationProviders() collector.
  • commonEditorDecorationRegistry holds the active providers + current theme; read by the editor pipeline, populated by the app. Keeps the editor module free of any plugin-manager dependency (common now depends on the leaf plugin-api module).
  • editor-treesitter — after building a region's base spans, LineSpansGenerator calls each provider and merges the returned spans as foreground-only overrides, preserving base styles and the strictly-ascending non-overlap invariant. ~30 generic lines; no feature concepts.
  • appEditorDecorationBridge registers enabled providers + current theme into the registry and posts ColorSchemeInvalidatedEvent to repaint; a ComponentCallbacks listener flips decorations on day/night changes live.

Dependency direction stays clean: app → plugin-manager, app → common, editor → common → plugin-api; the editor never depends on the plugin manager.

Verification

Device-verified on an emulator with a companion rainbow-brackets plugin (separate repo) that implements EditorDecorationProvider:

  • Depth-cycled bracket colors across (), [], {} in a Java file (provider scans text itself, so it's language-agnostic).
  • Nesting depth carried across lines.
  • Brackets inside strings/comments not colored.
  • Day and night palettes; live day/night toggle (no restart).
  • Disabling the plugin reverts to normal coloring (additivity).

Notes

This is the IDE-side generic API + merge. The rainbow plugin (which owns all bracket/depth/palette logic) lives in the plugin-examples repo and compiles against the refreshed plugin-api.jar.

(Reworked from an earlier rainbow-specific BracketColorExtension after review feedback that feature logic shouldn't live in the IDE.)

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

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: fcb1ccc3-c99f-45f9-8237-318d61583a62

📥 Commits

Reviewing files that changed from the base of the PR and between 7c1b683 and 84c1cd8.

📒 Files selected for processing (1)
  • common/build.gradle.kts
✅ Files skipped from review due to trivial changes (1)
  • common/build.gradle.kts

📝 Walkthrough
  • Added an additive editor decoration plugin API (EditorDecorationProvider + DecorationSpan) so plugins can contribute foreground-only color spans on top of existing syntax highlighting without replacing it.
  • Introduced a shared EditorDecorationRegistry to store the currently enabled decoration providers and the active dark/light state for the editor rendering pipeline.
  • Extended plugin-manager with getEnabledEditorDecorationProviders() to collect enabled decoration providers from loaded plugins.
  • Updated the Tree-sitter editor rendering pipeline (LineSpansGenerator) to merge provider-returned decoration spans into the final rendered spans as foreground overrides, preserving existing base styling and renderer ordering/non-overlap invariants.
  • Added EditorDecorationBridge to initialize and maintain decoration state:
    • Registers for UI day/night changes and triggers refresh on theme toggles
    • Refreshes enabled providers + theme darkness and posts ColorSchemeInvalidatedEvent to force editor repaint
    • Wires refresh into plugin loading and preference/night-mode update flows (e.g., during plugin system initialization and after plugin load operations).
  • Ensured one-time, thread-safe initialization for the theme listener via AtomicBoolean.compareAndSet, with failure paths resetting the flag to allow retry later.
  • Risk: decoration merging assumes provider output respects span validity/ordering expectations (overlapping or out-of-range spans may yield incorrect colors or rendering artifacts).
  • Risk: decoration providers execute during line span generation; slow providers may impact editor responsiveness.
  • Risk: refresh triggers (theme changes, plugin enable/disable, configuration changes) may increase redraw churn.

Walkthrough

Adds an editor-decoration plugin API and registry, bridges enabled decoration providers into the app on startup and night-mode changes, refreshes that bridge after plugin load, and applies decoration spans during tree-sitter span generation.

Changes

Editor decoration plugin flow

Layer / File(s) Summary
Decoration contract and lookup
plugin-api/src/main/kotlin/com/itsaky/androidide/plugins/extensions/EditorDecorationProvider.kt, plugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/core/PluginManager.kt, common/build.gradle.kts
EditorDecorationProvider and DecorationSpan define the decoration API, PluginManager returns enabled decoration providers, and common exposes pluginApi as an API dependency.
Decoration registry state
common/src/main/java/com/itsaky/androidide/syntax/decoration/EditorDecorationRegistry.kt
EditorDecorationRegistry stores the active provider list and shared isDark flag in process-wide volatile state.
Bridge refresh and app hooks
app/src/main/java/com/itsaky/androidide/utils/EditorDecorationBridge.kt, app/src/main/java/com/itsaky/androidide/app/CredentialProtectedApplicationLoader.kt, app/src/main/java/com/itsaky/androidide/viewmodels/PluginManagerViewModel.kt
EditorDecorationBridge initializes configuration callbacks, refreshes enabled providers into the registry, posts color-scheme invalidation, and is called after plugin load and night-mode changes.
Decoration span merging
editor-treesitter/src/main/java/io/github/rosemoe/sora/editor/ts/LineSpansGenerator.kt
Tree-sitter spans are post-processed with registry decorations by overriding foreground color and restoring base styles at decoration boundaries.

Sequence Diagram(s)

sequenceDiagram
  participant CredentialProtectedApplicationLoader
  participant PluginManagerViewModel
  participant EditorDecorationBridge
  participant PluginManager
  participant EditorDecorationRegistry
  participant EventBus

  CredentialProtectedApplicationLoader->>EditorDecorationBridge: init()
  EditorDecorationBridge->>PluginManager: getEnabledEditorDecorationProviders()
  EditorDecorationBridge->>EditorDecorationRegistry: update(providers)
  EditorDecorationBridge->>EventBus: post(ColorSchemeInvalidatedEvent)
  CredentialProtectedApplicationLoader->>EditorDecorationBridge: refresh()
  PluginManagerViewModel->>EditorDecorationBridge: refresh()
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • dara-abijo-adfa
  • jatezzz
  • itsaky-adfa

Poem

🐰 I hopped through spans of midnight blue,
and brushed the colors bright and new.
A bridge of carrots shone so true,
refresh! went the code, and bloom came through.
Hoppy tails for theme-flip cheer ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 54.17% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding a generic editor decoration provider extension point.
Description check ✅ Passed The description is directly about the same editor decoration extension point and matches the changeset.
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.
✨ 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 ADFA-4436-editor-coloring-hook

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/main/java/com/itsaky/androidide/app/CredentialProtectedApplicationLoader.kt (1)

329-337: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Register the bracket bridge even if loadPlugins() fails.

RainbowBracketBridge.init() sits between loadPlugins() and the success log inside the try. If loadPlugins() throws, init() is skipped, so the day/night theme listener is never registered and the registry is never seeded — bracket coloring won't react to theme flips for the rest of the session. init() is independent of plugin-load success (a null registry simply means "disabled"), so move it where it always runs.

🔧 Proposed fix
 			GlobalScope.launch {
 				try {
 					pluginManager?.loadPlugins()
-					com.itsaky.androidide.utils.RainbowBracketBridge.init()
 					logger.info("Plugin system initialized successfully")
 				} catch (e: Exception) {
 					logger.error("Failed to load plugins", e)
+				} finally {
+					com.itsaky.androidide.utils.RainbowBracketBridge.init()
 				}
 			}
🤖 Prompt for 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.

In
`@app/src/main/java/com/itsaky/androidide/app/CredentialProtectedApplicationLoader.kt`
around lines 329 - 337, The bracket bridge setup in GlobalScope.launch is
currently inside the same try block as pluginManager?.loadPlugins(), so
RainbowBracketBridge.init() is skipped whenever plugin loading throws. Move
RainbowBracketBridge.init() out of that failure-prone path so it always runs
regardless of loadPlugins() outcome, while keeping the existing success/error
logging around the plugin load in CredentialProtectedApplicationLoader.
🤖 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
`@editor-treesitter/src/main/java/io/github/rosemoe/sora/editor/ts/LineSpansGenerator.kt`:
- Around line 297-333: The bracket depth scan in bracketStateAtLineStart is
rescanning from the start of content on every cache miss, which makes large-file
edits and scrolling quadratic. Update the bracketStateCache used by
bracketStateAtLineStart to support finding the nearest prior cached line-start
state (for example via a floor lookup) and seed the scan from that state instead
of always starting at 0. Keep the existing depth/inBlock parsing logic, but
initialize it from the closest cached prefix so the scan only processes the
remaining suffix.

---

Outside diff comments:
In
`@app/src/main/java/com/itsaky/androidide/app/CredentialProtectedApplicationLoader.kt`:
- Around line 329-337: The bracket bridge setup in GlobalScope.launch is
currently inside the same try block as pluginManager?.loadPlugins(), so
RainbowBracketBridge.init() is skipped whenever plugin loading throws. Move
RainbowBracketBridge.init() out of that failure-prone path so it always runs
regardless of loadPlugins() outcome, while keeping the existing success/error
logging around the plugin load in CredentialProtectedApplicationLoader.
🪄 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: eb7ff7ad-5c92-4874-86ce-ce26158384d6

📥 Commits

Reviewing files that changed from the base of the PR and between 2387b73 and 84293ea.

📒 Files selected for processing (7)
  • app/src/main/java/com/itsaky/androidide/app/CredentialProtectedApplicationLoader.kt
  • app/src/main/java/com/itsaky/androidide/utils/RainbowBracketBridge.kt
  • app/src/main/java/com/itsaky/androidide/viewmodels/PluginManagerViewModel.kt
  • common/src/main/java/com/itsaky/androidide/syntax/brackets/RainbowBracketRegistry.kt
  • editor-treesitter/src/main/java/io/github/rosemoe/sora/editor/ts/LineSpansGenerator.kt
  • plugin-api/src/main/kotlin/com/itsaky/androidide/plugins/extensions/BracketColorExtension.kt
  • plugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/core/PluginManager.kt

Add an additive, feature-agnostic way for plugins to contribute foreground
colors to editor text, layered on top of the normal syntax highlighting.

- plugin-api: new EditorDecorationProvider with a single method,
  decorate(text, start, end, isDark) -> List<DecorationSpan>. The provider
  owns all of its own logic and returns colored ranges; because the only
  output is a list of spans, it can never replace or suppress highlighting.
- plugin-manager: getEnabledEditorDecorationProviders() collector.
- common: EditorDecorationRegistry holds the active providers + current theme,
  read by the editor pipeline and populated by the app. Keeps the editor
  module free of any plugin-manager dependency (common now depends on the
  leaf plugin-api module).
- editor-treesitter: after building a region's base spans, LineSpansGenerator
  calls each provider and merges the returned spans as foreground-only
  overrides, preserving base styles and the non-overlap invariant. The IDE is
  entirely feature-agnostic here.
- app: EditorDecorationBridge registers the enabled providers and current
  theme into the registry and posts ColorSchemeInvalidatedEvent to repaint; a
  ComponentCallbacks listener flips decorations on day/night changes live.

The dead EditorExtension.provideSyntaxHighlighting() hook (no call sites,
replaces highlighting, no RGB/depth) is left untouched.

A companion rainbow-brackets plugin (separate repo) implements this provider
end to end; device-verified: depth-cycled bracket colors in Java, string and
comment exclusion, day/night palettes, live theme toggle, revert on disable.
@hal-eisen-adfa hal-eisen-adfa force-pushed the ADFA-4436-editor-coloring-hook branch from 84293ea to 3d60906 Compare June 25, 2026 07:27
@hal-eisen-adfa hal-eisen-adfa changed the title ADFA-4436 Add additive rainbow-bracket editor coloring hook ADFA-4436 Add a generic editor decoration provider extension point Jun 25, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
app/src/main/java/com/itsaky/androidide/utils/EditorDecorationBridge.kt (1)

57-80: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Non-atomic registered guard contradicts the "safe to call more than once" doc.

The if (!registered) { registered = true; ... } check-then-set on a @Volatile field is not atomic, so two concurrent init() calls could both register a ComponentCallbacks. Today init() is only invoked once from the plugin-load coroutine, so this is not currently reachable, but a compareAndSet makes the guarantee in the KDoc actually hold.

♻️ Use AtomicBoolean for the one-time guard
-    `@Volatile`
-    private var registered = false
+    private val registered = java.util.concurrent.atomic.AtomicBoolean(false)
-        if (!registered) {
-            registered = true
+        if (registered.compareAndSet(false, true)) {
             try {
🤖 Prompt for 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.

In `@app/src/main/java/com/itsaky/androidide/utils/EditorDecorationBridge.kt`
around lines 57 - 80, The one-time guard in EditorDecorationBridge.init is not
atomic, so concurrent calls can register the ComponentCallbacks twice despite
the “safe to call more than once” contract. Replace the plain registered flag
with an AtomicBoolean and use a compare-and-set style check in init() to ensure
only one thread can enter the registration block. Keep the existing refresh()
behavior, and update the init()/registered logic so the guard and callback
registration remain tied to EditorDecorationBridge.
🤖 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.

Nitpick comments:
In `@app/src/main/java/com/itsaky/androidide/utils/EditorDecorationBridge.kt`:
- Around line 57-80: The one-time guard in EditorDecorationBridge.init is not
atomic, so concurrent calls can register the ComponentCallbacks twice despite
the “safe to call more than once” contract. Replace the plain registered flag
with an AtomicBoolean and use a compare-and-set style check in init() to ensure
only one thread can enter the registration block. Keep the existing refresh()
behavior, and update the init()/registered logic so the guard and callback
registration remain tied to EditorDecorationBridge.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d7ce9568-5027-40d5-8389-507007f5bbfb

📥 Commits

Reviewing files that changed from the base of the PR and between 84293ea and 3d60906.

📒 Files selected for processing (8)
  • app/src/main/java/com/itsaky/androidide/app/CredentialProtectedApplicationLoader.kt
  • app/src/main/java/com/itsaky/androidide/utils/EditorDecorationBridge.kt
  • app/src/main/java/com/itsaky/androidide/viewmodels/PluginManagerViewModel.kt
  • common/build.gradle.kts
  • common/src/main/java/com/itsaky/androidide/syntax/decoration/EditorDecorationRegistry.kt
  • editor-treesitter/src/main/java/io/github/rosemoe/sora/editor/ts/LineSpansGenerator.kt
  • plugin-api/src/main/kotlin/com/itsaky/androidide/plugins/extensions/EditorDecorationProvider.kt
  • plugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/core/PluginManager.kt

Comment thread app/src/main/java/com/itsaky/androidide/utils/EditorDecorationBridge.kt Outdated
Comment thread app/src/main/java/com/itsaky/androidide/viewmodels/PluginManagerViewModel.kt Outdated
- Replace fully-qualified EditorDecorationBridge / EditorDecorationProvider
  references with imports across the app and plugin-manager call sites.
- Invert the registration guard in EditorDecorationBridge.init() to an early
  return, dropping a level of nesting while preserving behavior.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
app/src/main/java/com/itsaky/androidide/utils/EditorDecorationBridge.kt (1)

78-79: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Avoid catching Throwable in these paths.

This also swallows unrecoverable failures (OutOfMemoryError, linkage errors, etc.) and can leave decoration state half-initialized or stale. Catch the specific exception you expect here, or at least narrow this to Exception so fatal errors still surface. Based on learnings, prefer narrow exception handling in Kotlin instead of broad catch-alls.

Also applies to: 98-99

🤖 Prompt for 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.

In `@app/src/main/java/com/itsaky/androidide/utils/EditorDecorationBridge.kt`
around lines 78 - 79, The try/catch blocks in EditorDecorationBridge’s listener
registration path are too broad because they catch Throwable and can hide fatal
JVM errors; narrow them to the expected failure type or at minimum Exception so
unrecoverable errors still propagate. Update both affected catch blocks in
EditorDecorationBridge to use specific exception handling around the editor
decoration theme listener registration logic while keeping the existing error
logging.

Source: Learnings

🤖 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/utils/EditorDecorationBridge.kt`:
- Around line 59-80: The one-time registration guard in
EditorDecorationBridge.init is being marked as registered before
registerComponentCallbacks succeeds, and the check/set is not atomic. Update the
init flow so the registered state is only set after successful callback
registration, and make the guard atomic using synchronization or a CAS-style
approach; if registration fails in the catch path, ensure the state is not left
enabled so future init calls can retry.

---

Nitpick comments:
In `@app/src/main/java/com/itsaky/androidide/utils/EditorDecorationBridge.kt`:
- Around line 78-79: The try/catch blocks in EditorDecorationBridge’s listener
registration path are too broad because they catch Throwable and can hide fatal
JVM errors; narrow them to the expected failure type or at minimum Exception so
unrecoverable errors still propagate. Update both affected catch blocks in
EditorDecorationBridge to use specific exception handling around the editor
decoration theme listener registration logic while keeping the existing error
logging.
🪄 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: 36b5c820-02dd-4e56-a733-0781fe8721dc

📥 Commits

Reviewing files that changed from the base of the PR and between 3d60906 and ce620d7.

📒 Files selected for processing (4)
  • app/src/main/java/com/itsaky/androidide/app/CredentialProtectedApplicationLoader.kt
  • app/src/main/java/com/itsaky/androidide/utils/EditorDecorationBridge.kt
  • app/src/main/java/com/itsaky/androidide/viewmodels/PluginManagerViewModel.kt
  • plugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/core/PluginManager.kt
🚧 Files skipped from review as they are similar to previous changes (2)
  • plugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/core/PluginManager.kt
  • app/src/main/java/com/itsaky/androidide/app/CredentialProtectedApplicationLoader.kt

Comment thread app/src/main/java/com/itsaky/androidide/utils/EditorDecorationBridge.kt Outdated
Claim the one-time listener registration with AtomicBoolean.compareAndSet so
concurrent init() callers can't double-register, and roll the flag back on
failure so a later init() can retry instead of being permanently stuck.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
app/src/main/java/com/itsaky/androidide/utils/EditorDecorationBridge.kt (1)

76-79: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Avoid catching Throwable in the bridge paths.

Lines 76-79 and 98-99 currently swallow fatal JVM errors as well as ordinary failures, which can leave the app limping along after conditions like OutOfMemoryError or LinkageError. Please narrow this to the concrete exception you expect here, or at least Exception, and let fatal errors fail fast. Based on learnings, similar Kotlin crash handling in this project should prefer narrow exception catches over catch-all handlers.

Also applies to: 98-99

🤖 Prompt for 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.

In `@app/src/main/java/com/itsaky/androidide/utils/EditorDecorationBridge.kt`
around lines 76 - 79, Avoid catching Throwable in EditorDecorationBridge’s
bridge paths; narrow the handler in the listener registration and cleanup code
to the specific expected exception type, or at most Exception, so fatal JVM
errors are not swallowed. Update the catch blocks around the editor decoration
theme listener registration and the related bridge cleanup path to keep the
existing log/error handling but let unrecoverable errors fail fast.

Source: Learnings

🤖 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.

Nitpick comments:
In `@app/src/main/java/com/itsaky/androidide/utils/EditorDecorationBridge.kt`:
- Around line 76-79: Avoid catching Throwable in EditorDecorationBridge’s bridge
paths; narrow the handler in the listener registration and cleanup code to the
specific expected exception type, or at most Exception, so fatal JVM errors are
not swallowed. Update the catch blocks around the editor decoration theme
listener registration and the related bridge cleanup path to keep the existing
log/error handling but let unrecoverable errors fail fast.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 52663d7c-7dbe-42fe-bacc-07799e2ada77

📥 Commits

Reviewing files that changed from the base of the PR and between ce620d7 and 7c1b683.

📒 Files selected for processing (1)
  • app/src/main/java/com/itsaky/androidide/utils/EditorDecorationBridge.kt

@hal-eisen-adfa hal-eisen-adfa requested a review from jatezzz June 26, 2026 01:38
@hal-eisen-adfa hal-eisen-adfa merged commit c14733b into stage Jun 26, 2026
2 checks passed
@hal-eisen-adfa hal-eisen-adfa deleted the ADFA-4436-editor-coloring-hook branch June 26, 2026 18:34
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.

2 participants