diff --git a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/InstanceofExpressionPostfixTemplate.java b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/InstanceofExpressionPostfixTemplate.java index 3da411a8be36..a27e33449cfa 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/InstanceofExpressionPostfixTemplate.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/InstanceofExpressionPostfixTemplate.java @@ -82,10 +82,9 @@ public class InstanceofExpressionPostfixTemplate extends PostfixTemplate impleme public PostfixModExpander createModExpander() { return (ActionContext actionContext, PostfixTemplateProvider provider, TextRange keyRange) -> { TextRange selection = actionContext.selection(); - return ModCommand.psiUpdate(actionContext.withSelection(new TextRange(keyRange.getStartOffset(), keyRange.getStartOffset())) - .withOffset(keyRange.getStartOffset()), - document -> document.deleteString(selection.getStartOffset(), selection.getEndOffset()), + return ModCommand.psiUpdate(actionContext, true, updater -> { + updater.select(TextRange.from(keyRange.getStartOffset(), 0)); updater.getDocument().deleteString(PostfixLiveTemplate.positiveOffset(keyRange.getStartOffset()), selection.getStartOffset()); PsiDocumentManager.getInstance(updater.getProject()).commitDocument(updater.getDocument()); PsiElement context = diff --git a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/IntroduceFieldPostfixTemplate.java b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/IntroduceFieldPostfixTemplate.java index 751d9406ed27..890582e5c15d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/IntroduceFieldPostfixTemplate.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/IntroduceFieldPostfixTemplate.java @@ -137,13 +137,11 @@ public class IntroduceFieldPostfixTemplate extends PostfixTemplateWithExpression @NotNull PsiExpression virtualExpr, @NotNull JavaIntroduceFieldService.InitializationPlace place, @NotNull PostfixTemplateProvider provider) { - TextRange newSelection = new TextRange(keyRange.getStartOffset(), keyRange.getStartOffset()); - ActionContext updatedContext = ctx.withSelection(newSelection).withOffset(keyRange.getStartOffset()); JavaIntroduceFieldService introduceFieldService = JavaIntroduceFieldService.getInstance(); if (introduceFieldService == null) return ModCommand.error(JavaRefactoringBundle.message("selected.expression.cannot.be.extracted")); - return ModCommand.psiUpdate(updatedContext, - document -> document.deleteString(ctx.selection().getStartOffset(), ctx.selection().getEndOffset()), + return ModCommand.psiUpdate(ctx, true, updater -> { + updater.select(TextRange.from(keyRange.getStartOffset(), 0)); updater.getDocument() .deleteString(PostfixLiveTemplate.positiveOffset(keyRange.getStartOffset()), ctx.selection().getStartOffset()); diff --git a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/IntroduceVariablePostfixTemplate.java b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/IntroduceVariablePostfixTemplate.java index 84710701d119..14d5792d1070 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/IntroduceVariablePostfixTemplate.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/IntroduceVariablePostfixTemplate.java @@ -130,13 +130,10 @@ public class IntroduceVariablePostfixTemplate extends PostfixTemplateWithExpress @NotNull PsiElement virtualExpr, boolean replaceAll, @NotNull PostfixTemplateProvider provider) { - TextRange newSelection = new TextRange(keyRange.getStartOffset(), keyRange.getStartOffset()); - ActionContext updatedContext = ctx.withSelection(newSelection).withOffset(keyRange.getStartOffset()); - ModCommand command = ModCommand.psiUpdate(updatedContext, - document -> { - document.deleteString(ctx.selection().getStartOffset(), ctx.selection().getEndOffset()); - }, + ModCommand command = ModCommand.psiUpdate(ctx, + true, updater -> { + updater.select(TextRange.from(keyRange.getStartOffset(), 0)); updater.getDocument() .deleteString(PostfixLiveTemplate.positiveOffset(keyRange.getStartOffset()), ctx.selection().getStartOffset()); PsiDocumentManager.getInstance(ctx.project()).commitDocument(updater.getDocument()); diff --git a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/TryStatementPostfixTemplate.java b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/TryStatementPostfixTemplate.java index faabbc0286cd..d8a519b0cb22 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/TryStatementPostfixTemplate.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/TryStatementPostfixTemplate.java @@ -55,9 +55,7 @@ public class TryStatementPostfixTemplate extends PostfixTemplate implements Dumb @Override public PostfixModExpander createModExpander() { return (ActionContext actionContext, PostfixTemplateProvider provider, TextRange keyRange) -> - ModCommand.psiUpdate(actionContext.withSelection(new TextRange(keyRange.getStartOffset(), keyRange.getStartOffset())) - .withOffset(keyRange.getStartOffset()), - document -> document.deleteString(actionContext.selection().getStartOffset(), actionContext.selection().getEndOffset()), + ModCommand.psiUpdate(actionContext, true, updater -> expandModImpl(actionContext, provider, keyRange, updater)); } diff --git a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/TryWithResourcesPostfixTemplate.java b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/TryWithResourcesPostfixTemplate.java index 7c8338171dda..d0834854625e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/TryWithResourcesPostfixTemplate.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/TryWithResourcesPostfixTemplate.java @@ -74,10 +74,9 @@ public class TryWithResourcesPostfixTemplate extends PostfixTemplate implements @Override public PostfixModExpander createModExpander() { return (ActionContext actionContext, PostfixTemplateProvider provider, TextRange keyRange) -> - ModCommand.psiUpdate(actionContext.withSelection(new TextRange(keyRange.getStartOffset(), keyRange.getStartOffset())) - .withOffset(keyRange.getStartOffset()), - document -> document.deleteString(actionContext.selection().getStartOffset(), actionContext.selection().getEndOffset()), + ModCommand.psiUpdate(actionContext, true, updater -> { + updater.select(TextRange.from(keyRange.getStartOffset(), 0)); updater.getDocument().deleteString(PostfixLiveTemplate.positiveOffset(keyRange.getStartOffset()), actionContext.selection().getStartOffset()); PsiDocumentManager.getInstance(actionContext.project()).commitDocument(updater.getDocument()); PsiFile file = updater.getPsiFile(); diff --git a/java/java-tests/testData/codeInsight/completion/keywords/inInjection.java b/java/java-tests/testData/codeInsight/completion/keywords/inInjection.java new file mode 100644 index 000000000000..6ec0f3547d20 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/keywords/inInjection.java @@ -0,0 +1,9 @@ +import org.intellij.lang.annotations.Language; + +class Hello { + void test() { + @Language("JAVA") String string = """ + publ + """; + } +} diff --git a/java/java-tests/testData/codeInsight/completion/keywords/inInjection_after.java b/java/java-tests/testData/codeInsight/completion/keywords/inInjection_after.java new file mode 100644 index 000000000000..3072a383a819 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/keywords/inInjection_after.java @@ -0,0 +1,9 @@ +import org.intellij.lang.annotations.Language; + +class Hello { + void test() { + @Language("JAVA") String string = """ + public + """; + } +} diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/KeywordCompletionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/KeywordCompletionTest.java index 2510284f4767..a38310bacd97 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/KeywordCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/KeywordCompletionTest.java @@ -413,6 +413,11 @@ public class KeywordCompletionTest extends LightCompletionTestCase { public void testNoPrimitivesAfterExpressions3() { doTest(); } public void testNoPrimitivesAfterExpressions4() { doTest(); } + + @NeedsIndex.SmartMode(reason = "Smart is necessary for injection") + public void testInInjection() { + doTest(); + } private void doTest() { configureByTestName(); diff --git a/platform/analysis-api/api-dump.txt b/platform/analysis-api/api-dump.txt index 4c818a8aa767..c7eee198f7f2 100644 --- a/platform/analysis-api/api-dump.txt +++ b/platform/analysis-api/api-dump.txt @@ -1490,7 +1490,7 @@ com.intellij.modcommand.ModCommandService - a:chooseFileAndPerform(com.intellij.psi.PsiFile,com.intellij.openapi.editor.Editor,com.intellij.modcommand.ModCommandAction,I):com.intellij.modcommand.ModCommandWithContext - s:getInstance():com.intellij.modcommand.ModCommandService - a:insertText(com.intellij.modcommand.ActionContext,java.lang.String,Z):com.intellij.modcommand.ModCommand -- a:psiUpdate(com.intellij.modcommand.ActionContext,java.util.function.Consumer,java.util.function.Consumer):com.intellij.modcommand.ModCommand +- a:psiUpdate(com.intellij.modcommand.ActionContext,Z,java.util.function.Consumer):com.intellij.modcommand.ModCommand - a:unwrap(com.intellij.codeInspection.LocalQuickFix):com.intellij.modcommand.ModCommandAction - a:updateOption(com.intellij.psi.PsiElement,com.intellij.codeInspection.InspectionProfileEntry,java.util.function.Consumer):com.intellij.modcommand.ModCommand - a:wrap(com.intellij.modcommand.ModCommandAction):com.intellij.codeInsight.intention.IntentionAction diff --git a/platform/analysis-api/src/com/intellij/modcommand/ModCommand.java b/platform/analysis-api/src/com/intellij/modcommand/ModCommand.java index b84b0b278e8f..d47e8dd53d71 100644 --- a/platform/analysis-api/src/com/intellij/modcommand/ModCommand.java +++ b/platform/analysis-api/src/com/intellij/modcommand/ModCommand.java @@ -241,23 +241,21 @@ public sealed interface ModCommand */ static @NotNull ModCommand psiUpdate(@NotNull ActionContext context, @NotNull Consumer<@NotNull ModPsiUpdater> updater) { - return ModCommandService.getInstance().psiUpdate(context, doc -> {}, updater); + return ModCommandService.getInstance().psiUpdate(context, false, updater); } /** - * @param context a context of the original action - * @param copyCleaner a function that updates the document to ignore intermittent changes in the original. - * This could be useful for completion when the prefix is already inserted to the original document, - * but the final command should be applied to the document without the prefix. - * @param updater a function that accepts an updater, so it can query writable copies from it and perform modifications; - * also additional editor operation like caret positioning could be performed + * @param context a context of the original action + * @param deleteSelection if true, a text selected in the action context will be deleted prior to execution + * @param updater a function that accepts an updater, so it can query writable copies from it and perform modifications; + * also additional editor operation like caret positioning could be performed * @return a command that will perform the corresponding update to the original elements and the editor */ @ApiStatus.Internal static @NotNull ModCommand psiUpdate(@NotNull ActionContext context, - @NotNull Consumer<@NotNull Document> copyCleaner, + boolean deleteSelection, @NotNull Consumer<@NotNull ModPsiUpdater> updater) { - return ModCommandService.getInstance().psiUpdate(context, copyCleaner, updater); + return ModCommandService.getInstance().psiUpdate(context, deleteSelection, updater); } /** @@ -267,7 +265,7 @@ public sealed interface ModCommand * @return a command that will perform the corresponding update to the original element */ static @NotNull ModCommand psiUpdate(@NotNull E orig, @NotNull Consumer<@NotNull E> updater) { - return psiUpdate(orig, (e, ctx) -> updater.accept(e)); + return psiUpdate(orig, (e, _) -> updater.accept(e)); } /** @@ -310,7 +308,7 @@ public sealed interface ModCommand final @NotNull @IntentionName String title, @NotNull Function<@NotNull T, @NotNull ModCommand> function, @NotNull Function<@NotNull T, @NotNull TextRange> range) { - return new PsiBasedModCommandAction(element) { + return new PsiBasedModCommandAction<>(element) { @Override protected @NotNull ModCommand perform(@NotNull ActionContext context, @NotNull T element) { return function.apply(element); @@ -343,7 +341,7 @@ public sealed interface ModCommand final @NotNull @IntentionName String title, @NotNull BiConsumer<@NotNull T, @NotNull ModPsiUpdater> action, @NotNull Function<@NotNull T, @NotNull TextRange> range) { - return new PsiUpdateModCommandAction(element) { + return new PsiUpdateModCommandAction<>(element) { @Override protected void invoke(@NotNull ActionContext context, @NotNull T element, @NotNull ModPsiUpdater updater) { action.accept(element, updater); @@ -387,7 +385,7 @@ public sealed interface ModCommand * @param file a file where we want to navigate * @param offset an offset in the file before the command is executed * @param leanRight if true, lean to the right side when the text was inserted right at the caret position - * @return an updated command which tries to navigate inside the specified file, taking into account the modifications inside that file + * @return an updated command that tries to navigate inside the specified file, taking into account the modifications inside that file */ @ApiStatus.Experimental static @NotNull ModCommand moveCaretAfter(@NotNull ModCommand command, @NotNull PsiFile file, int offset, boolean leanRight) { diff --git a/platform/analysis-api/src/com/intellij/modcommand/ModCommandService.java b/platform/analysis-api/src/com/intellij/modcommand/ModCommandService.java index 36a73fd95288..bfbaaf731266 100644 --- a/platform/analysis-api/src/com/intellij/modcommand/ModCommandService.java +++ b/platform/analysis-api/src/com/intellij/modcommand/ModCommandService.java @@ -6,7 +6,6 @@ import com.intellij.codeInspection.InspectionProfileEntry; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; @@ -57,7 +56,7 @@ public interface ModCommandService { * Implementation of ModCommand.psiUpdate; should not be used directly. */ @NotNull ModCommand psiUpdate(@NotNull ActionContext context, - @NotNull Consumer<@NotNull Document> copyCleaner, + boolean deleteSelection, @NotNull Consumer<@NotNull ModPsiUpdater> updater); /** diff --git a/platform/analysis-api/src/com/intellij/modcompletion/PsiUpdateCompletionItem.java b/platform/analysis-api/src/com/intellij/modcompletion/PsiUpdateCompletionItem.java index 37e3fc5310dc..495382aea94e 100644 --- a/platform/analysis-api/src/com/intellij/modcompletion/PsiUpdateCompletionItem.java +++ b/platform/analysis-api/src/com/intellij/modcompletion/PsiUpdateCompletionItem.java @@ -37,23 +37,16 @@ public abstract class PsiUpdateCompletionItem implements ModCompletionItem { @Override public ModCommand perform(ActionContext actionContext, InsertionContext insertionContext) { - String lookupString = mainLookupString(); - int completionStart = actionContext.selection().getStartOffset(); - int prefixEnd = actionContext.selection().getEndOffset(); - int updatedCaretPos = completionStart + lookupString.length(); - ActionContext finalActionContext = actionContext - .withSelection(TextRange.create(updatedCaretPos, updatedCaretPos)) - .withOffset(updatedCaretPos); - return ModCommand.psiUpdate(finalActionContext, doc -> { - doc.deleteString(completionStart, prefixEnd); - }, updater -> { + return ModCommand.psiUpdate(actionContext, true, updater -> { Document document = updater.getDocument(); - document.replaceString(completionStart, + String lookupString = mainLookupString(); + TextRange range = TextRange.create(updater.getCaretOffset(), updater.getCaretOffset() + lookupString.length()); + document.replaceString(range.getStartOffset(), insertionContext.mode() == InsertionMode.OVERWRITE ? - calculateEndOffsetForOverwrite(document, completionStart) : completionStart, lookupString); - updater.moveCaretTo(updatedCaretPos); - update(actionContext.withOffset(updatedCaretPos) - .withSelection(TextRange.create(completionStart, updatedCaretPos)), insertionContext, updater); + calculateEndOffsetForOverwrite(document, range.getStartOffset()) : range.getStartOffset(), lookupString); + updater.moveCaretTo(range.getEndOffset()); + update(actionContext.withOffset(range.getEndOffset()) + .withSelection(range), insertionContext, updater); addCompletionChar(updater, insertionContext); }); } diff --git a/platform/analysis-impl/src/com/intellij/lang/impl/modcommand/ModCommandServiceImpl.java b/platform/analysis-impl/src/com/intellij/lang/impl/modcommand/ModCommandServiceImpl.java index 422b5e367e0a..91dbfff30b5f 100644 --- a/platform/analysis-impl/src/com/intellij/lang/impl/modcommand/ModCommandServiceImpl.java +++ b/platform/analysis-impl/src/com/intellij/lang/impl/modcommand/ModCommandServiceImpl.java @@ -72,9 +72,9 @@ public final class ModCommandServiceImpl implements ModCommandService { @Override public @NotNull ModCommand psiUpdate(@NotNull ActionContext context, - @NotNull Consumer<@NotNull Document> copyCleaner, + boolean deleteSelection, @NotNull Consumer<@NotNull ModPsiUpdater> updater) { - return PsiUpdateImpl.psiUpdate(context, copyCleaner, updater); + return PsiUpdateImpl.psiUpdate(context, deleteSelection, updater); } @Override diff --git a/platform/analysis-impl/src/com/intellij/lang/impl/modcommand/PsiUpdateImpl.java b/platform/analysis-impl/src/com/intellij/lang/impl/modcommand/PsiUpdateImpl.java index 2eb4b0ede8b2..ecb717694492 100644 --- a/platform/analysis-impl/src/com/intellij/lang/impl/modcommand/PsiUpdateImpl.java +++ b/platform/analysis-impl/src/com/intellij/lang/impl/modcommand/PsiUpdateImpl.java @@ -82,14 +82,14 @@ final class PsiUpdateImpl { private static final Key ORIGINAL_FILE_FOR_INJECTION = Key.create("ORIGINAL_FILE_FOR_INJECTION"); static @NotNull ModCommand psiUpdate(@NotNull ActionContext context, - @NotNull Consumer<@NotNull Document> copyCleaner, + boolean deleteSelection, @NotNull Consumer<@NotNull ModPsiUpdater> updater) { var runnable = new Runnable() { private ModPsiUpdaterImpl myUpdater; @Override public void run() { - myUpdater = new ModPsiUpdaterImpl(context, copyCleaner); + myUpdater = new ModPsiUpdaterImpl(context, deleteSelection); updater.accept(myUpdater); } @@ -121,15 +121,13 @@ final class PsiUpdateImpl { private boolean myDeleted; private boolean myGuardModification; - FileTracker(@NotNull PsiFile origFile, @NotNull Map changedFiles, @NotNull Consumer<@NotNull Document> copyCleaner) { + FileTracker(@NotNull PsiFile origFile, @NotNull Map changedFiles, @Nullable TextRange selectionToDelete) { Project project = origFile.getProject(); myCopyFile = copyFile(project, origFile); - PsiFileImplUtil.setNonPhysicalFileDeleteHandler(myCopyFile, f -> myDeleted = true); + PsiFileImplUtil.setNonPhysicalFileDeleteHandler(myCopyFile, _ -> myDeleted = true); assert !myCopyFile.getViewProvider().isEventSystemEnabled() : "Event system for " + myCopyFile.getName(); myManager = PsiDocumentManager.getInstance(project); myDocument = myCopyFile.getFileDocument(); - copyCleaner.accept(myDocument); - myManager.commitDocument(myDocument); InjectedLanguageManager injectionManager = InjectedLanguageManager.getInstance(project); boolean injected = injectionManager.isInjectedFragment(origFile); if (injected) { @@ -151,6 +149,16 @@ final class PsiUpdateImpl { } }, this); Disposer.register(this, disposable); + if (selectionToDelete != null) { + // The supplied selection is in host-document coordinates (completion uses the top-level editor); + // map it into the injected copy's coordinate space, as myDocument is the copy of the injected file here. + Document injectedDocument = origFile.getFileDocument(); + if (injectedDocument instanceof DocumentWindow window) { + int start = injectionManager.mapInjectedOffsetToUnescaped(origFile, window.hostToInjected(selectionToDelete.getStartOffset())); + int end = injectionManager.mapInjectedOffsetToUnescaped(origFile, window.hostToInjected(selectionToDelete.getEndOffset())); + selectionToDelete = TextRange.create(start, end); + } + } myTargetFile = hostFileCopy; origFile = hostFile; myPositionDocument = hostFileCopy.getViewProvider().getDocument(); @@ -160,6 +168,10 @@ final class PsiUpdateImpl { myTargetFile = myCopyFile; myPositionDocument = myDocument; } + if (selectionToDelete != null) { + myDocument.deleteString(selectionToDelete.getStartOffset(), selectionToDelete.getEndOffset()); + myManager.commitDocument(myDocument); + } myPositionDocument.addDocumentListener(this, this); myOrigText = myTargetFile.getText(); myOrigFile = origFile; @@ -308,12 +320,12 @@ final class PsiUpdateImpl { private int myCaretVirtualEnd; private @NotNull TextRange mySelection; private final @NotNull List<@NotNull ModRegisterTabOut> myTabOutCommands = new ArrayList<>(); - private final Consumer<@NotNull Document> myCopyCleaner; + private final boolean myDeleteSelection; private final List myHighlightInfos = new ArrayList<>(); private final List myTemplateFields = new ArrayList<>(); private final Map myTemplateValues = new HashMap<>(); private final List myLaunchEditorActions = new ArrayList<>(); - private @NotNull Function myTemplateFinishFunction = f -> nop(); + private @NotNull Function myTemplateFinishFunction = _ -> nop(); private @Nullable ModStartRename myRenameSymbol; private final List myTrackedDeclarations = new ArrayList<>(); private boolean myPositionUpdated = false; @@ -356,11 +368,11 @@ final class PsiUpdateImpl { } } - private ModPsiUpdaterImpl(@NotNull ActionContext actionContext, @NotNull Consumer<@NotNull Document> copyCleaner) { + private ModPsiUpdaterImpl(@NotNull ActionContext actionContext, boolean deleteSelection) { myActionContext = actionContext; myCaretOffset = myCaretVirtualEnd = actionContext.offset(); mySelection = actionContext.selection(); - myCopyCleaner = copyCleaner; + myDeleteSelection = deleteSelection; } private @NotNull FileTracker tracker() { @@ -391,7 +403,15 @@ final class PsiUpdateImpl { private @NotNull FileTracker tracker(@NotNull PsiFile file) { FileTracker result = myChangedFiles.computeIfAbsent(file, origFile -> { - var tracker = new FileTracker(origFile, myChangedFiles, myActionContext.file() == file ? myCopyCleaner : doc -> {}); + FileTracker tracker; + if (myDeleteSelection && myActionContext.file() == file && mySelection.getLength() > 0) { + tracker = new FileTracker(origFile, myChangedFiles, mySelection); + myCaretOffset = mySelection.getStartOffset(); + mySelection = TextRange.from(myCaretOffset, 0); + } + else { + tracker = new FileTracker(origFile, myChangedFiles, null); + } Disposer.register(this, tracker); return tracker; }); @@ -417,7 +437,7 @@ final class PsiUpdateImpl { if (element instanceof PsiDirectory dir) { VirtualFile file = dir.getVirtualFile(); if (file instanceof ChangedVirtualDirectory) return element; - ChangedDirectoryInfo directory = myChangedDirectories.computeIfAbsent(file, f -> ChangedDirectoryInfo.create(dir)); + ChangedDirectoryInfo directory = myChangedDirectories.computeIfAbsent(file, _ -> ChangedDirectoryInfo.create(dir)); @SuppressWarnings("unchecked") E result = (E)directory.psiDirectory; return result; } @@ -557,7 +577,7 @@ final class PsiUpdateImpl { TemplateImpl.DummyContext context = new TemplateImpl.DummyContext(range, element, getPsiFile()); Result result = varName == null ? expression.calculateResult(context) - : myTemplateValues.computeIfAbsent(varName, v -> expression.calculateResult(context)); + : myTemplateValues.computeIfAbsent(varName, _ -> expression.calculateResult(context)); if (result != null) { FileTracker tracker = requireNonNull(myTracker); // guarded by getRange call diff --git a/platform/code-style-api/src/com/intellij/application/options/CodeStyle.java b/platform/code-style-api/src/com/intellij/application/options/CodeStyle.java index 92b5734e9d71..d418f9a8f396 100644 --- a/platform/code-style-api/src/com/intellij/application/options/CodeStyle.java +++ b/platform/code-style-api/src/com/intellij/application/options/CodeStyle.java @@ -5,6 +5,7 @@ import com.intellij.application.options.codeStyle.cache.CodeStyleCachingService; import com.intellij.lang.Language; import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; @@ -114,7 +115,8 @@ public final class CodeStyle { } return localOrTempSettings; } - PsiFile topLevel = InjectedLanguageManager.getInstance(project).getTopLevelFile(file); + InjectedLanguageManager manager = InjectedLanguageManager.getInstance(project); + PsiFile topLevel = ReadAction.computeBlocking(() -> manager.getTopLevelFile(file)); PsiFile settingsFile = getSettingsPsi(topLevel != null ? topLevel : file); if (settingsFile == null) { return getSettings(project); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java index fa849fac8334..0eab064473e2 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java @@ -41,6 +41,7 @@ import com.intellij.ide.PowerSaveMode; import com.intellij.internal.statistic.service.fus.collectors.UIEventLogger; import com.intellij.lang.LangBundle; import com.intellij.lang.Language; +import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.modcommand.ActionContext; import com.intellij.modcommand.ModCommand; import com.intellij.modcompletion.ModCompletionItem; @@ -749,6 +750,8 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable, ModCompletionItem.InsertionContext insertionContext = new ModCompletionItem.InsertionContext( completionChar == REPLACE_SELECT_CHAR ? ModCompletionItem.InsertionMode.OVERWRITE : ModCompletionItem.InsertionMode.INSERT, completionChar); + PsiFile topLevelFile = InjectedLanguageManager.getInstance(psiFile.getProject()).getTopLevelFile(psiFile); + psiFile = topLevelFile == null ? psiFile : topLevelFile; ActionContext actionContext = ActionContext.from(editor, psiFile); ActionContext finalActionContext = actionContext .withOffset(start) @@ -1302,6 +1305,8 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable, // templates whose matcher prefix is "" right after the dot). At that moment the // "prefix length" is logically meaningless if (prefixLength < 0) return; + PsiFile topLevelFile = InjectedLanguageManager.getInstance(getProject()).getTopLevelFile(file); + file = topLevelFile == null ? file : topLevelFile; ActionContext actionContext = ActionContext.from(editor, file); int start = actionContext.offset() - prefixLength; // it can happen when an external change diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/ExpressionSelectorModExpander.java b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/ExpressionSelectorModExpander.java index 3b6a10d6b77a..cb649a515f28 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/ExpressionSelectorModExpander.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/ExpressionSelectorModExpander.java @@ -117,16 +117,15 @@ public class ExpressionSelectorModExpander implements PostfixModExpander { @NotNull TextRange key, @NotNull PsiElement virtualExpression, @NotNull PostfixTemplateProvider provider) { - TextRange selection = new TextRange(key.getStartOffset(), key.getStartOffset()); - ActionContext updatedContext = ctx.withSelection(selection).withOffset(key.getStartOffset()); - return ModCommand.psiUpdate(updatedContext, - document -> document.deleteString(ctx.selection().getStartOffset(), ctx.selection().getEndOffset()), + return ModCommand.psiUpdate(ctx, + true, updater -> { + updater.select(TextRange.from(key.getStartOffset(), 0)); updater.getDocument().deleteString(PostfixLiveTemplate.positiveOffset(key.getStartOffset()), ctx.selection().getStartOffset()); PsiDocumentManager.getInstance(ctx.project()).commitDocument(updater.getDocument()); provider.prepareCopyForModCommand(updater.getPsiFile(), PostfixLiveTemplate.positiveOffset(key.getStartOffset())); PsiElement elementInCopy = PsiTreeUtil.findSameElementInCopy(virtualExpression, updater.getPsiFile()); - myExpandAction.expand(updatedContext, updater, elementInCopy); + myExpandAction.expand(ctx, updater, elementInCopy); }); } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/editable/EditableTemplateModExpander.java b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/editable/EditableTemplateModExpander.java index 27250f3e1d4d..e5a30f96bf6e 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/editable/EditableTemplateModExpander.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/editable/EditableTemplateModExpander.java @@ -109,9 +109,9 @@ public class EditableTemplateModExpander implements PostfixModExpander { private @NotNull ModCommand createModCommand(@NotNull ActionContext ctx, @NotNull TextRange key, @NotNull PsiElement virtualExpression, @NotNull PostfixTemplateProvider provider) { - return ModCommand.psiUpdate(ctx.withSelection(new TextRange(key.getStartOffset(), key.getStartOffset())).withOffset(key.getStartOffset()), - document -> document.deleteString(ctx.selection().getStartOffset(), ctx.selection().getEndOffset()), + return ModCommand.psiUpdate(ctx, true, updater -> { + updater.select(TextRange.from(key.getStartOffset(), 0)); updater.getDocument().deleteString(PostfixLiveTemplate.positiveOffset(key.getStartOffset()), ctx.selection().getStartOffset()); PsiDocumentManager.getInstance(ctx.project()).commitDocument(updater.getDocument()); provider.prepareCopyForModCommand(updater.getPsiFile(), PostfixLiveTemplate.positiveOffset(key.getStartOffset()));