mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[mod-command] PsiUpdateContext#moveToPrevious; AddFinallyFix -> ModCommandAction
GitOrigin-RevId: 56625a1739da460bcc71712ae4ad682f2ce200c7
This commit is contained in:
committed by
intellij-monorepo-bot
parent
498d3de463
commit
d75b5e726f
+2
-2
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.daemon.impl.analysis;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
|
||||
@@ -31,7 +31,7 @@ public class JavaErrorQuickFixProvider implements ErrorQuickFixProvider {
|
||||
}
|
||||
if (parent instanceof PsiTryStatement && description.equals(JavaPsiBundle.message("expected.catch.or.finally"))) {
|
||||
registrar.add(new AddExceptionToCatchFix(false));
|
||||
registrar.add(new AddFinallyFix((PsiTryStatement)parent));
|
||||
registrar.add(new AddFinallyFix((PsiTryStatement)parent).asIntention());
|
||||
}
|
||||
if (parent instanceof PsiSwitchLabeledRuleStatement && description.equals(JavaPsiBundle.message("expected.switch.rule"))) {
|
||||
IntentionAction action =
|
||||
|
||||
+33
-39
@@ -1,26 +1,47 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.daemon.impl.quickfix;
|
||||
|
||||
import com.intellij.codeInsight.daemon.QuickFixBundle;
|
||||
import com.intellij.codeInsight.generation.surroundWith.JavaWithTryFinallySurrounder;
|
||||
import com.intellij.codeInsight.intention.FileModifier;
|
||||
import com.intellij.codeInsight.intention.impl.BaseIntentionAction;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.codeInspection.ModCommands;
|
||||
import com.intellij.codeInspection.PsiUpdateContext;
|
||||
import com.intellij.modcommand.ModCommand;
|
||||
import com.intellij.modcommand.PsiBasedModCommandAction;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class AddFinallyFix extends BaseIntentionAction {
|
||||
private final PsiTryStatement myTryStatement;
|
||||
|
||||
public class AddFinallyFix extends PsiBasedModCommandAction<PsiTryStatement> {
|
||||
public AddFinallyFix(PsiTryStatement statement) {
|
||||
myTryStatement = statement;
|
||||
super(statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull ModCommand perform(@NotNull ActionContext context, @NotNull PsiTryStatement element) {
|
||||
return ModCommands.psiUpdate(element, (tryStatement, updater) -> {
|
||||
PsiStatement replacement =
|
||||
JavaPsiFacade.getElementFactory(context.project())
|
||||
.createStatementFromText(tryStatement.getText() + "finally {\n\n}", tryStatement);
|
||||
PsiTryStatement result = (PsiTryStatement)tryStatement.replace(replacement);
|
||||
moveCaretToFinallyBlock(updater, Objects.requireNonNull(result.getFinallyBlock()));
|
||||
});
|
||||
}
|
||||
|
||||
private static void moveCaretToFinallyBlock(@NotNull PsiUpdateContext updater, @NotNull PsiCodeBlock block) {
|
||||
PsiFile file = block.getContainingFile();
|
||||
Document document = file.getViewProvider().getDocument();
|
||||
Project project = file.getProject();
|
||||
updater.moveTo(Objects.requireNonNull(block.getRBrace()));
|
||||
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(document);
|
||||
TextRange finallyBlockRange = block.getTextRange();
|
||||
int newLineOffset = finallyBlockRange.getStartOffset() + 2;
|
||||
CodeStyleManager.getInstance(project).adjustLineIndent(document, newLineOffset);
|
||||
updater.moveToPrevious('\n');
|
||||
}
|
||||
|
||||
@Nls(capitalization = Nls.Capitalization.Sentence)
|
||||
@@ -29,31 +50,4 @@ public class AddFinallyFix extends BaseIntentionAction {
|
||||
public String getFamilyName() {
|
||||
return QuickFixBundle.message("add.finally.block.family");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getText() {
|
||||
return getFamilyName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
|
||||
if (!(file instanceof PsiJavaFile)) return false;
|
||||
if (!myTryStatement.isValid()) return false;
|
||||
if (myTryStatement.getFinallyBlock() != null) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
|
||||
PsiStatement replacement =
|
||||
JavaPsiFacade.getElementFactory(project).createStatementFromText(myTryStatement.getText() + "finally {\n\n}", myTryStatement);
|
||||
PsiTryStatement result = (PsiTryStatement)myTryStatement.replace(replacement);
|
||||
JavaWithTryFinallySurrounder.moveCaretToFinallyBlock(project, editor, Objects.requireNonNull(result.getFinallyBlock()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable FileModifier getFileModifierForPreview(@NotNull PsiFile target) {
|
||||
return new AddFinallyFix(PsiTreeUtil.findSameElementInCopy(myTryStatement, target));
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ class Test {
|
||||
void foo() {
|
||||
try {
|
||||
} finally {
|
||||
|
||||
<caret>
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,6 @@ import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.LocalTimeCounter;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -108,48 +107,7 @@ public final class ModCommands {
|
||||
positionDocument = document;
|
||||
}
|
||||
String oldText = targetFile.getText();
|
||||
var context = new PsiUpdateContext() {
|
||||
@Nullable RangeMarker mySelectionRange = actionContext.selection().getStartOffset() == -1 ? null :
|
||||
positionDocument.createRangeMarker(actionContext.selection().getStartOffset(),
|
||||
actionContext.selection().getEndOffset(), true);
|
||||
@Nullable RangeMarker myCaretRange = actionContext.offset() == -1 ? null :
|
||||
positionDocument.createRangeMarker(actionContext.offset(), actionContext.offset(), true);
|
||||
|
||||
@Override
|
||||
public void select(@NotNull PsiElement element) {
|
||||
validate(element);
|
||||
manager.doPostponedOperationsAndUnblockDocument(document);
|
||||
if (mySelectionRange != null) {
|
||||
mySelectionRange.dispose();
|
||||
}
|
||||
if (myCaretRange != null) {
|
||||
myCaretRange.dispose();
|
||||
}
|
||||
if (injected) {
|
||||
element = PsiTreeUtil.findSameElementInCopy(element, targetFile);
|
||||
}
|
||||
mySelectionRange = positionDocument.createRangeMarker(element.getTextRange());
|
||||
myCaretRange = positionDocument.createRangeMarker(element.getTextRange().getStartOffset(), element.getTextRange().getStartOffset());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveTo(@NotNull PsiElement element) {
|
||||
validate(element);
|
||||
manager.doPostponedOperationsAndUnblockDocument(document);
|
||||
if (myCaretRange != null) {
|
||||
myCaretRange.dispose();
|
||||
}
|
||||
if (injected) {
|
||||
element = PsiTreeUtil.findSameElementInCopy(element, targetFile);
|
||||
}
|
||||
myCaretRange = positionDocument.createRangeMarker(element.getTextRange().getStartOffset(), element.getTextRange().getStartOffset());
|
||||
}
|
||||
|
||||
private void validate(@NotNull PsiElement element) {
|
||||
if (!element.isValid()) throw new IllegalArgumentException();
|
||||
if (!PsiTreeUtil.isAncestor(copyFile, element, false)) throw new IllegalArgumentException();
|
||||
}
|
||||
};
|
||||
var context = new PsiUpdateContextImpl(actionContext, positionDocument, manager, document, injected, targetFile, copyFile);
|
||||
aspect.postponeFormattingInside(
|
||||
() -> aspect.forcePostprocessFormatInside(copyFile, () -> updater.accept(copy, context)));
|
||||
manager.commitDocument(document);
|
||||
@@ -159,23 +117,19 @@ public final class ModCommands {
|
||||
VirtualFile origVirtualFile = origFile.getOriginalFile().getVirtualFile();
|
||||
if (origVirtualFile != null) {
|
||||
int start = -1, end = -1, caret = -1;
|
||||
if (context.mySelectionRange != null && context.mySelectionRange.getEndOffset() <= newText.length()) {
|
||||
if (context.mySelectionRange.getEndOffset() <= newText.length()) {
|
||||
start = context.mySelectionRange.getStartOffset();
|
||||
end = context.mySelectionRange.getEndOffset();
|
||||
}
|
||||
if (context.myCaretRange != null && context.myCaretRange.getStartOffset() <= newText.length()) {
|
||||
if (context.myCaretRange.getStartOffset() <= newText.length()) {
|
||||
caret = context.myCaretRange.getStartOffset();
|
||||
}
|
||||
if (start != -1 || end != -1 || caret != -1) {
|
||||
command = command.andThen(new ModNavigate(origVirtualFile, start, end, caret));
|
||||
}
|
||||
}
|
||||
if (context.mySelectionRange != null) {
|
||||
context.mySelectionRange.dispose();
|
||||
}
|
||||
if (context.myCaretRange != null) {
|
||||
context.myCaretRange.dispose();
|
||||
}
|
||||
context.mySelectionRange.dispose();
|
||||
context.myCaretRange.dispose();
|
||||
if (disposable != null) {
|
||||
Disposer.dispose(disposable);
|
||||
}
|
||||
@@ -227,4 +181,76 @@ public final class ModCommands {
|
||||
}
|
||||
return new ModCommandAction.ActionContext(project, copyFile, offset, TextRange.create(start, end));
|
||||
}
|
||||
|
||||
private static class PsiUpdateContextImpl implements PsiUpdateContext {
|
||||
private final @NotNull Document myPositionDocument;
|
||||
private final @NotNull PsiDocumentManager myManager;
|
||||
private final @NotNull Document myDocument;
|
||||
private final boolean myInjected;
|
||||
private final @NotNull PsiFile myTargetFile;
|
||||
private final @NotNull PsiFile myCopyFile;
|
||||
@NotNull RangeMarker mySelectionRange;
|
||||
@NotNull RangeMarker myCaretRange;
|
||||
|
||||
private PsiUpdateContextImpl(@NotNull ModCommandAction.ActionContext actionContext,
|
||||
@NotNull Document positionDocument,
|
||||
@NotNull PsiDocumentManager manager,
|
||||
@NotNull Document document,
|
||||
boolean injected,
|
||||
@NotNull PsiFile targetFile,
|
||||
@NotNull PsiFile copyFile) {
|
||||
myPositionDocument = positionDocument;
|
||||
myManager = manager;
|
||||
myDocument = document;
|
||||
myInjected = injected;
|
||||
myTargetFile = targetFile;
|
||||
myCopyFile = copyFile;
|
||||
mySelectionRange = myPositionDocument.createRangeMarker(actionContext.selection().getStartOffset(),
|
||||
actionContext.selection().getEndOffset(), true);
|
||||
myCaretRange = myPositionDocument.createRangeMarker(actionContext.offset(), actionContext.offset(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void select(@NotNull PsiElement element) {
|
||||
validate(element);
|
||||
myManager.doPostponedOperationsAndUnblockDocument(myDocument);
|
||||
mySelectionRange.dispose();
|
||||
myCaretRange.dispose();
|
||||
if (myInjected) {
|
||||
element = PsiTreeUtil.findSameElementInCopy(element, myTargetFile);
|
||||
}
|
||||
mySelectionRange = myPositionDocument.createRangeMarker(element.getTextRange());
|
||||
myCaretRange = myPositionDocument.createRangeMarker(element.getTextRange().getStartOffset(), element.getTextRange().getStartOffset());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveTo(@NotNull PsiElement element) {
|
||||
validate(element);
|
||||
myManager.doPostponedOperationsAndUnblockDocument(myDocument);
|
||||
if (myInjected) {
|
||||
element = PsiTreeUtil.findSameElementInCopy(element, myTargetFile);
|
||||
}
|
||||
int offset = element.getTextRange().getStartOffset();
|
||||
moveToOffset(offset);
|
||||
}
|
||||
|
||||
private void moveToOffset(int offset) {
|
||||
myCaretRange.dispose();
|
||||
myCaretRange = myPositionDocument.createRangeMarker(offset, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveToPrevious(char ch) {
|
||||
myManager.doPostponedOperationsAndUnblockDocument(myDocument);
|
||||
String text = myPositionDocument.getText();
|
||||
int idx = text.lastIndexOf(ch, myCaretRange.getStartOffset());
|
||||
if (idx == -1) return;
|
||||
moveToOffset(idx);
|
||||
}
|
||||
|
||||
private void validate(@NotNull PsiElement element) {
|
||||
if (!element.isValid()) throw new IllegalArgumentException();
|
||||
if (!PsiTreeUtil.isAncestor(myCopyFile, element, false)) throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,4 +25,10 @@ public interface PsiUpdateContext {
|
||||
* @param element element to navigate to
|
||||
*/
|
||||
void moveTo(@NotNull PsiElement element);
|
||||
|
||||
/**
|
||||
* Moves caret to a previous occurrence of character ch. Do nothing if no such occurrence is found
|
||||
* @param ch character to find
|
||||
*/
|
||||
void moveToPrevious(char ch);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user