mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IJPL-245860 [mod-completion] IOOBE: DocumentImpl.deleteString via PsiUpdateCompletionItem in injection
Support ModCompletion in injection (cherry picked from commit 41985f580fe3f4e6155b3ebac160a840de8632b3) Review ID: IJ-CR-209545 GitOrigin-RevId: 1bd7ea7c17324f78ebf8dd3254f29c952382a3a4
This commit is contained in:
committed by
intellij-monorepo-bot
parent
0089a1fc18
commit
49f18225c5
+2
-3
@@ -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 =
|
||||
|
||||
+2
-4
@@ -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());
|
||||
|
||||
+3
-6
@@ -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());
|
||||
|
||||
+1
-3
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
+2
-3
@@ -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();
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import org.intellij.lang.annotations.Language;
|
||||
|
||||
class Hello {
|
||||
void test() {
|
||||
@Language("JAVA") String string = """
|
||||
publ<caret>
|
||||
""";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import org.intellij.lang.annotations.Language;
|
||||
|
||||
class Hello {
|
||||
void test() {
|
||||
@Language("JAVA") String string = """
|
||||
public <caret>
|
||||
""";
|
||||
}
|
||||
}
|
||||
+5
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <E extends PsiElement> @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<T>(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<T>(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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,23 +37,16 @@ public abstract class PsiUpdateCompletionItem<T> 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);
|
||||
});
|
||||
}
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
@@ -82,14 +82,14 @@ final class PsiUpdateImpl {
|
||||
private static final Key<PsiFile> 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<PsiFile, FileTracker> changedFiles, @NotNull Consumer<@NotNull Document> copyCleaner) {
|
||||
FileTracker(@NotNull PsiFile origFile, @NotNull Map<PsiFile, FileTracker> 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<ModHighlight.HighlightInfo> myHighlightInfos = new ArrayList<>();
|
||||
private final List<ModStartTemplate.TemplateField> myTemplateFields = new ArrayList<>();
|
||||
private final Map<String, Result> myTemplateValues = new HashMap<>();
|
||||
private final List<ModLaunchEditorAction> myLaunchEditorActions = new ArrayList<>();
|
||||
private @NotNull Function<? super @NotNull PsiFile, ? extends @NotNull ModCommand> myTemplateFinishFunction = f -> nop();
|
||||
private @NotNull Function<? super @NotNull PsiFile, ? extends @NotNull ModCommand> myTemplateFinishFunction = _ -> nop();
|
||||
private @Nullable ModStartRename myRenameSymbol;
|
||||
private final List<ModUpdateReferences> 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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
+4
-5
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -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()));
|
||||
|
||||
Reference in New Issue
Block a user