Summary
Manage IntelliJ's native guide rendering when it can appear beside a multiline
active vertical guide from Bracket Pair Guides.
This issue now also covers the two-line report in
#27.
The report is not caused by Current scope alone:
- IntelliJ's regular indent guide is the physical native line in the New UI.
- Matched-brace and Current scope markers can emphasize that existing line.
- At a brace boundary, matched-brace highlighting can emphasize the line even
when Current scope is disabled.
Provide one IntelliJ-integration gate, one native-highlight mode, and one
independent indent-guide option. The default should reduce competing native
highlighting while preserving useful regular indent guides:
manageNativeVisuals = true
nativeHighlightMode = SUPPRESS_MATCHED_BRACE_AND_CURRENT_SCOPE
hideNativeIndentGuides = false
This default can still show a dim IntelliJ indent guide beside the plugin's
active guide. Users who require exactly one vertical line can opt into hiding
IntelliJ indent guides.
Preference-schema migration from earlier plugin versions is not required for
this design. Runtime ownership and restoration of native values are still
required.
Native rendering model
The relevant IntelliJ values are:
| Symbol |
IntelliJ value |
Effect |
B |
CodeInsightSettings.HIGHLIGHT_BRACES |
Enables native matched-brace processing and gates the standard Current scope path |
S |
CodeInsightSettings.HIGHLIGHT_SCOPE |
Enables Current scope while B is enabled |
I |
affectedEditor.settings.isIndentGuidesShown |
Controls effective regular indent-guide visibility for that editor |
The global suppression target for I is
EditorSettingsExternalizable.isIndentGuidesShown. Detection must use the
affected editor's effective value because an editor may override the global
default.
Marker creation
For a standard monolithic editor, the relevant marker conditions are:
matchedBraceMarker =
B && caretTouchesMatchedBrace && multilinePair
currentScopeMarker =
B && S && scopeFallbackResolvesEnclosingPair && multilinePair
marker = matchedBraceMarker || currentScopeMarker
HIGHLIGHT_SCOPE does not control the direct matched-brace marker at a brace
boundary. IntelliJ processes direct brace highlighting before evaluating
HIGHLIGHT_SCOPE, and both paths can install the same line marker for a
multiline range.
Relevant platform paths:
New UI visibility
In the New UI, the marker does not directly paint the code-area line.
IndentGuideRenderer
uses it to choose the color of an existing indent guide.
Conceptually:
ordinaryNativeLine = I && indentDescriptorExists
highlightedNativeLine =
ordinaryNativeLine && marker && matchingStartLine
Consequences:
- Disabling Show indent guides removes the native code-area line.
- Disabling matched-brace highlighting removes its emphasis but leaves a dim
regular indent guide when I remains enabled.
- Disabling Current scope does not remove direct matched-brace emphasis at a
brace boundary.
- In the New UI, matched-brace and Current scope highlighting are not separate
physical code-area lines; they can recolor the existing indent guide.
Classic UI visibility
In the Classic UI, DefaultLineMarkerRenderer can paint a gutter-side marker
directly. That marker can remain visible independently of Show indent
guides. Detection and tests must not assume the New UI rendering path for
every supported IDE configuration.
Reproduction from #27
The verified New UI states are:
| State at a multiline brace boundary |
Result |
B=On, S=On, I=On |
Emphasized native indent guide + plugin guide |
B=On, S=Off, I=On |
Same result; the direct matched-brace marker remains |
B=Off, I=On |
Dim regular indent guide + plugin guide |
I=Off |
Plugin guide only in the code area |
Settings model
Use a parent gate, a mode for the dependent native highlight settings, and a
separate indent-guide Boolean:
enum class NativeHighlightMode {
SUPPRESS_MATCHED_BRACE_AND_CURRENT_SCOPE,
SUPPRESS_CURRENT_SCOPE_ONLY,
LEAVE_INTELLIJ_HIGHLIGHTING_UNCHANGED,
}
data class IntelliJIntegrationPreferences(
val manageNativeVisuals: Boolean = true,
val nativeHighlightMode: NativeHighlightMode =
NativeHighlightMode.SUPPRESS_MATCHED_BRACE_AND_CURRENT_SCOPE,
val hideNativeIndentGuides: Boolean = false,
)
The parent is an operational gate, not a persisted mirror of whether every
child is selected:
- Parent off: release every owned native value and leave IntelliJ rendering
unchanged while retaining the selected child configuration.
- Parent on: apply the selected highlight mode and indent-guide option.
- Bracket Pair Guides' existing global Enabled option remains the outer
lifecycle gate. Disabling the plugin also releases every native value.
Highlight-mode mapping
The UI describes rendered effects, while ownership must change only the native
value required for that mode:
| Mode |
HIGHLIGHT_BRACES ownership |
HIGHLIGHT_SCOPE ownership |
| Suppress matched-brace and Current scope |
Own as false |
Do not own or rewrite; Current scope is suppressed by the B gate |
| Suppress Current scope only |
Do not own or rewrite |
Own as false |
| Leave IntelliJ highlighting unchanged |
Do not own; restore if necessary |
Do not own; restore if necessary |
Do not silently set HIGHLIGHT_SCOPE=false when suppressing matched-brace
highlighting. The rendered Current scope effect is dependent, but the native
settings and restore values remain independently owned.
Only the selected highlight slot may remain owned in steady state. When
switching modes, acquire the new suppressing slot before releasing the old one
inside one coordinator transaction so the intermediate state does not briefly
re-enable both native effects.
hideNativeIndentGuides=true independently owns the global
EditorSettingsExternalizable.isIndentGuidesShown value as false.
The complete "plugin guide only" configuration is:
manageNativeVisuals = true
nativeHighlightMode = SUPPRESS_MATCHED_BRACE_AND_CURRENT_SCOPE
hideNativeIndentGuides = true
Settings UI
Use one shared explanation rather than explanatory text under every control:
IntelliJ integration
[x] Adjust IntelliJ guide rendering while Bracket Pair Guides is enabled
Native guide highlighting:
[ Hide matched-brace and Current scope highlighting v ]
[ ] Hide regular IntelliJ indent guides
IntelliJ visuals left enabled may appear beside the active bracket guide.
Keeping indent guides can result in two adjacent vertical lines.
Highlight-mode choices:
- Hide matched-brace and Current scope highlighting — default
- Hide Current scope highlighting only
- Leave IntelliJ highlighting unchanged
When the parent is off, disable the child controls without clearing their
values.
Show the shared informational text only when all of the following are true:
pluginVerticalGuideCanAppear =
pluginEnabled && activeGuideEnabled && verticalGuideEnabled
potentialNativeVisualRemains =
!manageNativeVisuals ||
!hideNativeIndentGuides ||
nativeHighlightMode != SUPPRESS_MATCHED_BRACE_AND_CURRENT_SCOPE
showSharedInfo =
pluginVerticalGuideCanAppear && potentialNativeVisualRemains
This is neutral informational text, not a warning: retaining IntelliJ indent
guides is useful and is the default. Always show one separate common restoration
note for the group:
Original IntelliJ settings are restored when this integration or Bracket Pair
Guides is disabled.
Runtime conflict detection
The Settings-page information describes the possible coexistence of regular
indent guides. The runtime notification has a narrower purpose: alert the user
only when native matched-brace or Current scope highlighting can visibly
emphasize another line beside a multiline plugin guide.
Regular IntelliJ indent guides being enabled is intentional under the default
configuration and is not sufficient to trigger a notification.
Before notifying, require all of the following:
- Bracket Pair Guides is enabled for the current editor and language.
- Active guide and Vertical are enabled.
- A multiline active vertical guide has actually been displayed.
- Native matched-brace or Current scope highlighting remains effective after
the selected management settings have been applied.
- A supported editor path confirms that the native highlighted marker can be
visible beside the plugin guide.
The native highlight sources must be distinguished:
directMatchedBraceCapability =
HIGHLIGHT_BRACES && caretTouchesMatchedBrace && multilinePair
currentScopeCapability =
HIGHLIGHT_BRACES && HIGHLIGHT_SCOPE &&
scopeFallbackResolvesEnclosingPair
Do not report a Current scope conflict from HIGHLIGHT_SCOPE=true alone, and do
not assume disabling Current scope resolves the direct brace-boundary case.
Classify visibility by UI path:
- New UI: require an effective indent guide and a matching indent
descriptor beside the plugin geometry. A native marker without that carrier
is not a visible code-area conflict.
- Classic UI: evaluate direct matched-brace and scope-fallback gutter-marker
capability separately from indent guides because the marker can paint
directly.
Use supported editor APIs and the plugin's computed guide geometry. Do not
inspect private renderer internals. If the UI path, marker source, or relevant
geometry cannot be classified safely, skip the notification.
Initial compatibility scope
The initial implementation covers standard monolithic editors only.
Do not enable conflict notifications or native-setting ownership in Remote
Development, Code With Me, or local-editor-support paths until their settings
context is handled explicitly. CodeInsightSettings and
EditorSettingsExternalizable can be client-specific, and a shared restore
value can restore the wrong client's setting.
Notification behavior
Use one IntelliJ notification balloon with informational severity. Do not use
an editor banner: this is guidance about an IDE-wide setting combination, not a
file-specific error requiring persistent editor space.
Suggested copy:
IntelliJ guide highlighting may overlap
IntelliJ highlighting may draw another line beside Bracket Pair Guides.
Review the integration settings if this is unintended.
Provide one action:
- Review settings: open the IntelliJ integration settings group.
The notification is advisory. Publishing, closing, or opening it must not
change IntelliJ settings or plugin preferences.
Show it only once, with persisted application-level state. Do not show it again
on every IDE process or project after it has been published. Mark the state when
the notification is successfully published, not when detection first starts.
If the plugin exposes a notification reset, keep that reset in the IntelliJ
integration settings and use the same persisted state as the single source of
truth.
The ordinary indent-guide coexistence described in the Settings page must not
publish this notification. It is intended only for the prominent native
highlighting case that a user may have enabled unintentionally.
Suppression lifetime
Suppression is preference-based, not toggled per caret position or active pair.
Once requested, hold the corresponding native value while both Bracket Pair
Guides and the IntelliJ-integration gate are enabled. Per-guide mutation would
cause global-setting churn and visible flicker across editors.
Disabling the integration gate, disabling Bracket Pair Guides, changing to a
mode that no longer owns a value, dynamic plugin unload, or application exit
releases the relevant ownership.
For indent-guide changes, use the public
EditorSettingsExternalizable.setIndentGuidesShown(...) setter and refresh open
editors on the EDT. Re-evaluate the affected editor afterward because an
explicit per-editor override can remain effective.
HIGHLIGHT_BRACES and HIGHLIGHT_SCOPE expose no change-notifying setter, and
IntelliJ exposes no public API dedicated to removing an already installed scope
marker. Do not call internal brace or indent renderers. Request supported
editor/daemon recomputation where available; the change must be visible by the
next native brace-highlighting update and must not require an IDE restart.
Ownership and restoration
Use one application-level lifecycle coordinator with three independent
Boolean ownership slots:
HIGHLIGHT_BRACES
HIGHLIGHT_SCOPE
EditorSettingsExternalizable.isIndentGuidesShown
Each slot must:
- Persist the exact original Boolean before first enforcing
false.
- Distinguish original
false from no ownership, for example with Boolean?.
- Change only its assigned native value.
- Restore only when the current value is still the plugin-owned
false.
- Release on parent disable, plugin disable, mode/option change, dynamic unload,
and application exit.
- Treat an external change to
true as the newer user choice: preserve it,
release that slot, and update only the corresponding plugin configuration.
- Persist once after releasing all applicable slots during shutdown/unload.
Mode updates after an external override:
- External
HIGHLIGHT_BRACES=true while the first mode owns it: switch the
highlight mode to Leave IntelliJ highlighting unchanged.
- External
HIGHLIGHT_SCOPE=true while Current-scope-only mode owns it: switch
the highlight mode to Leave IntelliJ highlighting unchanged.
- External indent guides
true while owned: set
hideNativeIndentGuides=false.
- Keep
manageNativeVisuals=true; release only the overridden child target.
These preference updates must be compare-and-set operations against the mode
that still owns the overridden target. Delayed cleanup for a previous mode must
not replace a newer mode selected by the user.
Native writes and restores performed by the coordinator must not be observed as
external overrides. Use a scoped reentrancy/write guard, including around the
indent-guide setter and any change event it produces.
An external write of false while the plugin already owns false is
observationally indistinguishable from the plugin-owned value. Document this as
a limitation of Boolean value-based ownership.
Non-goals
- Treating the three native values as independent rendered effects
- Mutating
HIGHLIGHT_SCOPE merely because HIGHLIGHT_BRACES is suppressed
- Hiding regular IntelliJ indent guides by default
- Repositioning the plugin guide to mask a native indicator
- Depending on private renderer implementation details solely for detection
- Acquiring and releasing application-wide settings on every caret movement
- Supporting Remote Development settings ownership in the initial version
Acceptance criteria
Summary
Manage IntelliJ's native guide rendering when it can appear beside a multiline
active vertical guide from Bracket Pair Guides.
This issue now also covers the two-line report in
#27.
The report is not caused by Current scope alone:
when Current scope is disabled.
Provide one IntelliJ-integration gate, one native-highlight mode, and one
independent indent-guide option. The default should reduce competing native
highlighting while preserving useful regular indent guides:
This default can still show a dim IntelliJ indent guide beside the plugin's
active guide. Users who require exactly one vertical line can opt into hiding
IntelliJ indent guides.
Preference-schema migration from earlier plugin versions is not required for
this design. Runtime ownership and restoration of native values are still
required.
Native rendering model
The relevant IntelliJ values are:
BCodeInsightSettings.HIGHLIGHT_BRACESSCodeInsightSettings.HIGHLIGHT_SCOPEBis enabledIaffectedEditor.settings.isIndentGuidesShownThe global suppression target for
IisEditorSettingsExternalizable.isIndentGuidesShown. Detection must use theaffected editor's effective value because an editor may override the global
default.
Marker creation
For a standard monolithic editor, the relevant marker conditions are:
HIGHLIGHT_SCOPEdoes not control the direct matched-brace marker at a braceboundary. IntelliJ processes direct brace highlighting before evaluating
HIGHLIGHT_SCOPE, and both paths can install the same line marker for amultiline range.
Relevant platform paths:
BackgroundHighlightingUtil.needMatching()rejects the standard matching update when
HIGHLIGHT_BRACESis disabled.BraceHighlightingHandlerhandles a direct brace first and evaluates
HIGHLIGHT_SCOPEafterward.DefaultLineMarkerRenderer.New UI visibility
In the New UI, the marker does not directly paint the code-area line.
IndentGuideRendereruses it to choose the color of an existing indent guide.
Conceptually:
Consequences:
regular indent guide when
Iremains enabled.brace boundary.
physical code-area lines; they can recolor the existing indent guide.
Classic UI visibility
In the Classic UI,
DefaultLineMarkerRenderercan paint a gutter-side markerdirectly. That marker can remain visible independently of Show indent
guides. Detection and tests must not assume the New UI rendering path for
every supported IDE configuration.
Reproduction from #27
The verified New UI states are:
B=On,S=On,I=OnB=On,S=Off,I=OnB=Off,I=OnI=OffSettings model
Use a parent gate, a mode for the dependent native highlight settings, and a
separate indent-guide Boolean:
The parent is an operational gate, not a persisted mirror of whether every
child is selected:
unchanged while retaining the selected child configuration.
lifecycle gate. Disabling the plugin also releases every native value.
Highlight-mode mapping
The UI describes rendered effects, while ownership must change only the native
value required for that mode:
HIGHLIGHT_BRACESownershipHIGHLIGHT_SCOPEownershipfalseBgatefalseDo not silently set
HIGHLIGHT_SCOPE=falsewhen suppressing matched-bracehighlighting. The rendered Current scope effect is dependent, but the native
settings and restore values remain independently owned.
Only the selected highlight slot may remain owned in steady state. When
switching modes, acquire the new suppressing slot before releasing the old one
inside one coordinator transaction so the intermediate state does not briefly
re-enable both native effects.
hideNativeIndentGuides=trueindependently owns the globalEditorSettingsExternalizable.isIndentGuidesShownvalue asfalse.The complete "plugin guide only" configuration is:
Settings UI
Use one shared explanation rather than explanatory text under every control:
Highlight-mode choices:
When the parent is off, disable the child controls without clearing their
values.
Show the shared informational text only when all of the following are true:
This is neutral informational text, not a warning: retaining IntelliJ indent
guides is useful and is the default. Always show one separate common restoration
note for the group:
Runtime conflict detection
The Settings-page information describes the possible coexistence of regular
indent guides. The runtime notification has a narrower purpose: alert the user
only when native matched-brace or Current scope highlighting can visibly
emphasize another line beside a multiline plugin guide.
Regular IntelliJ indent guides being enabled is intentional under the default
configuration and is not sufficient to trigger a notification.
Before notifying, require all of the following:
the selected management settings have been applied.
visible beside the plugin guide.
The native highlight sources must be distinguished:
Do not report a Current scope conflict from
HIGHLIGHT_SCOPE=truealone, and donot assume disabling Current scope resolves the direct brace-boundary case.
Classify visibility by UI path:
descriptor beside the plugin geometry. A native marker without that carrier
is not a visible code-area conflict.
capability separately from indent guides because the marker can paint
directly.
Use supported editor APIs and the plugin's computed guide geometry. Do not
inspect private renderer internals. If the UI path, marker source, or relevant
geometry cannot be classified safely, skip the notification.
Initial compatibility scope
The initial implementation covers standard monolithic editors only.
Do not enable conflict notifications or native-setting ownership in Remote
Development, Code With Me, or local-editor-support paths until their settings
context is handled explicitly.
CodeInsightSettingsandEditorSettingsExternalizablecan be client-specific, and a shared restorevalue can restore the wrong client's setting.
Notification behavior
Use one IntelliJ notification balloon with informational severity. Do not use
an editor banner: this is guidance about an IDE-wide setting combination, not a
file-specific error requiring persistent editor space.
Suggested copy:
Provide one action:
The notification is advisory. Publishing, closing, or opening it must not
change IntelliJ settings or plugin preferences.
Show it only once, with persisted application-level state. Do not show it again
on every IDE process or project after it has been published. Mark the state when
the notification is successfully published, not when detection first starts.
If the plugin exposes a notification reset, keep that reset in the IntelliJ
integration settings and use the same persisted state as the single source of
truth.
The ordinary indent-guide coexistence described in the Settings page must not
publish this notification. It is intended only for the prominent native
highlighting case that a user may have enabled unintentionally.
Suppression lifetime
Suppression is preference-based, not toggled per caret position or active pair.
Once requested, hold the corresponding native value while both Bracket Pair
Guides and the IntelliJ-integration gate are enabled. Per-guide mutation would
cause global-setting churn and visible flicker across editors.
Disabling the integration gate, disabling Bracket Pair Guides, changing to a
mode that no longer owns a value, dynamic plugin unload, or application exit
releases the relevant ownership.
For indent-guide changes, use the public
EditorSettingsExternalizable.setIndentGuidesShown(...)setter and refresh openeditors on the EDT. Re-evaluate the affected editor afterward because an
explicit per-editor override can remain effective.
HIGHLIGHT_BRACESandHIGHLIGHT_SCOPEexpose no change-notifying setter, andIntelliJ exposes no public API dedicated to removing an already installed scope
marker. Do not call internal brace or indent renderers. Request supported
editor/daemon recomputation where available; the change must be visible by the
next native brace-highlighting update and must not require an IDE restart.
Ownership and restoration
Use one application-level lifecycle coordinator with three independent
Boolean ownership slots:
HIGHLIGHT_BRACESHIGHLIGHT_SCOPEEditorSettingsExternalizable.isIndentGuidesShownEach slot must:
false.falsefrom no ownership, for example withBoolean?.false.and application exit.
trueas the newer user choice: preserve it,release that slot, and update only the corresponding plugin configuration.
Mode updates after an external override:
HIGHLIGHT_BRACES=truewhile the first mode owns it: switch thehighlight mode to Leave IntelliJ highlighting unchanged.
HIGHLIGHT_SCOPE=truewhile Current-scope-only mode owns it: switchthe highlight mode to Leave IntelliJ highlighting unchanged.
truewhile owned: sethideNativeIndentGuides=false.manageNativeVisuals=true; release only the overridden child target.These preference updates must be compare-and-set operations against the mode
that still owns the overridden target. Delayed cleanup for a previous mode must
not replace a newer mode selected by the user.
Native writes and restores performed by the coordinator must not be observed as
external overrides. Use a scoped reentrancy/write guard, including around the
indent-guide setter and any change event it produces.
An external write of
falsewhile the plugin already ownsfalseisobservationally indistinguishable from the plugin-owned value. Document this as
a limitation of Boolean value-based ownership.
Non-goals
HIGHLIGHT_SCOPEmerely becauseHIGHLIGHT_BRACESis suppressedAcceptance criteria
manageNativeVisualsdefaults totrue.scope rendering by owning only
HIGHLIGHT_BRACES=false.mode or indent-guide option.
HIGHLIGHT_SCOPE=falseand does notmodify or own
HIGHLIGHT_BRACES.briefly re-enable both native effects while switching.
guide can appear and a potentially overlapping native visual remains.
can still be reproduced.
a dim native indent guide rather than the emphasized guide.
plugin guide.
guide and effective native matched-brace or Current scope highlighting.
descriptor, not only the global indent-guide flag or an internal marker.
gutter marker independently of the indent-guide setting.
not an editor banner.
projects unless its persisted state is explicitly reset.
IntelliJ setting or plugin preference.
trueandfalserestore correctly forall three slots.
native value.
and leaves the parent enabled.
selected mode or indent-guide option.
per-editor override remains detectable and is not silently overwritten.
platform versions.
notification nor native-setting mutation.
emphasis and removing the physical native indent guide.