redhat-developer / redhat-developer/lsp4ij
Support LSP quick fixes and intention actions on non-project files by implementing `DumbAware` on `LSPLazyCodeActionIntentionAction`
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 344
- Forks
- 113
- Avg merge
- 5h 22m
- Merged PRs (30d)
- 15
Description
Summary
LSP4IJ already supports diagnostics, folding, code lenses, documentation, and document links on non-project files (files outside content roots) by marking their respective passes/providers as DumbAware (LSPDiagnosticsPassFactory, LSPFoldingRangeBuilder, LSPCodeLensProvider, LSPDocumentationTargetProvider, LSPDocumentLinkPass).
However, LSP quick fixes (LSPQuickFixIntentionAction) and intention actions (LSPIntentionAction0..19) do not work on non-project files because their base class LSPLazyCodeActionIntentionAction does not implement com.intellij.openapi.project.DumbAware.
Root Cause
In IntelliJ Platform, both the intention popup (Alt+Enter via ShowIntentionsPass#addAvailableFixesForGroups and ShowIntentionsPass#getRegisteredIntentionActions) and the hover tooltip quick-fix button (DaemonTooltipActionProviderKt#extractMostPriorityFixFromHighlightInfo / DaemonTooltipAction#execute -> findIntention) filter actions using DumbService#isUsableInCurrentContext(Object thing, VirtualFile file):
fun isUsableInCurrentContext(thing: Any, file: VirtualFile?) : Boolean {
if (file == null || !file.isInLocalFileSystem) return isUsableInCurrentContext(thing)
return (!isDumb && FileIndexFacade.getInstance(project).isIndexable(file)) || isDumbAware(thing, project is LightEditCompatible)
}
For a non-project file (a file outside the project's content roots/libraries), FileIndexFacade.getInstance(project).isIndexable(file) returns false even when the IDE is in Smart Mode (!isDumb == true).
Because (!isDumb && isIndexable(file)) evaluates to false, IntelliJ requires isDumbAware(thing) to be true:
- Prior to IntelliJ 2026.2 (IJPL-254242),
extractMostPriorityFixFromHighlightInfomissed theisUsableInCurrentContextcheck, so LSP quick fixes were shown in hover tooltips on non-project files, but clicking them silently failed insideDaemonTooltipAction#execute->findIntention(which calledShowIntentionsPass#getAvailableFixes->isUsableInCurrentContext->false). - In newer IntelliJ builds where
extractMostPriorityFixFromHighlightInfoalso checksisUsableInCurrentContext, non-DumbAwarequick fixes and intentions are completely hidden on non-project files in both tooltips andAlt+Enter.
Proposed Solution
-
Implement
DumbAwareonLSPLazyCodeActionIntentionAction:
Since external language servers operate out-of-process and do not rely on IntelliJ's PSI indexes,LSPLazyCodeActionIntentionActionshould implementDumbAware.- Note: For
LSPIntentionAction0..19registered via<intentionAction>inplugin.xml, IntelliJ wraps them inIntentionActionWrapperwhich implementsIntentionActionDelegate(PossiblyDumbAware) and delegatesisDumbAware()toDumbService.isDumbAware(getDelegate()). Thus, markingLSPLazyCodeActionIntentionActionasDumbAwareautomatically makes bothLSPQuickFixIntentionActionandLSPIntentionAction0..19dumb-aware.
- Note: For
-
Guard against actual project indexing in
LSPLazyCodeActionIntentionAction#isAvailable:
LSPIntentionAction#isAvailablealready checksProjectIndexingManager.canExecuteLSPFeature(file) != ExecuteLSPFeatureStatus.NOWto avoid triggering LSP requests while the project is actually indexing (scanning || dumbIndexing || DumbService.isDumb(project)). Moving this check up toLSPLazyCodeActionIntentionAction#isAvailableensures thatLSPQuickFixIntentionActionis also guarded during actual indexing while still returningtrue(ExecuteLSPFeatureStatus.NOW) for non-project files in Smart Mode:
// In com.redhat.devtools.lsp4ij.features.codeAction.LSPLazyCodeActionIntentionAction
public class LSPLazyCodeActionIntentionAction implements IntentionAction, DumbAware {
...
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
if (ProjectIndexingManager.canExecuteLSPFeature(file) != ExecuteLSPFeatureStatus.NOW) {
return false;
}
loadCodeActionIfNeeded();
return isValidCodeAction(this.action);
}
- (Optional) Ensure write access for multi-file
WorkspaceEdits on non-project files:
For the currently activePsiFile,ShowIntentionActionsHandler#invokeIntentionautomatically callsFileModificationService.getInstance().preparePsiElementsForWrite(...)(triggering IntelliJ's standard "Non-Project Files Protection" unlock dialog beforeinvoke()runs). However, if aWorkspaceEditmodifies secondary non-project files,LSPIJUtils#applyWorkspaceEditshould callFileModificationService.getInstance().prepareVirtualFilesForWrite(project, affectedFiles)(orReadonlyStatusHandler.ensureFilesWritable(...)) before modifying documents.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in com.redhat.devtools.lsp4ij.features.codeAction.LSPLazyCodeActionIntentionAction and compare LSPIntentionAction#isAvailable with ProjectIndexingManager.canExecuteLSPFeature. Check how IntentionActionWrapper delegates DumbAware, then verify quick fixes and intention actions are available for non-project files in Smart Mode but not during indexing. Review LSPIJUtils#applyWorkspaceEdit and the mentioned FileModificationService behavior if addressing secondary-file writes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- devtools
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 74/100