diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/actions/FlipCommaIntention.java b/platform/lang-impl/src/com/intellij/openapi/editor/actions/FlipCommaIntention.java new file mode 100644 index 000000000000..52da2855c718 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/openapi/editor/actions/FlipCommaIntention.java @@ -0,0 +1,123 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.editor.actions; + +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.openapi.application.Result; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiWhiteSpace; +import com.intellij.psi.impl.source.PostprocessReformattingAspect; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.ObjectUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class FlipCommaIntention implements IntentionAction { + @NotNull + @Override + public String getText() { + return getFamilyName(); + } + + @NotNull + @Override + public String getFamilyName() { + return "Flip ','"; + } + + @Override + public boolean isAvailable(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) { + PsiElement comma = currentCommaElement(editor, file); + return comma != null && smartAdvanceAsExpr(comma, true) != null && smartAdvance(comma, false) != null; + } + + @Override + public void invoke(@NotNull Project project, @NotNull final Editor editor, @NotNull PsiFile file) throws IncorrectOperationException { + final PsiElement element = currentCommaElement(editor, file); + if (element != null) { + new WriteCommandAction(project, file) { + protected void run(@NotNull Result result) throws Throwable { + PostprocessReformattingAspect.getInstance(getProject()).disablePostprocessFormattingInside(new Runnable() { + @Override + public void run() { + swapAtComma(editor, element); + } + }); + } + }.execute(); + } + } + + @Override + public boolean startInWriteAction() { + return true; + } + + private static void swapAtComma(@NotNull Editor editor, @NotNull PsiElement comma) { + PsiElement prev = smartAdvanceAsExpr(comma, false); + PsiElement next = smartAdvanceAsExpr(comma, true); + if (prev != null && next != null) { + boolean caretBeforeComma = editor.getCaretModel().getOffset() <= comma.getTextRange().getStartOffset(); + PsiElement nextAnchor = next.getPrevSibling(); + PsiElement prevAnchor = prev.getNextSibling(); + comma.getParent().addBefore(next, prevAnchor); + comma.getParent().addAfter(prev, nextAnchor); + next.delete(); + prev.delete(); + editor.getCaretModel().moveToOffset(caretBeforeComma ? comma.getTextRange().getStartOffset() : comma.getTextRange().getEndOffset()); + } + } + + private static PsiElement currentCommaElement(@NotNull Editor editor, @NotNull PsiFile file) { + PsiElement element; + if (!isComma(element = leftElement(editor, file)) && !isComma(element = rightElement(editor, file))) { + return null; + } + return element; + } + + @Nullable + private static PsiElement leftElement(@NotNull Editor editor, @NotNull PsiFile file) { + return file.findElementAt(editor.getCaretModel().getOffset() - 1); + } + + @Nullable + private static PsiElement rightElement(@NotNull Editor editor, @NotNull PsiFile file) { + return file.findElementAt(editor.getCaretModel().getOffset()); + } + + private static boolean isComma(@Nullable PsiElement element) { + return element != null && element.getText().equals(","); + } + + @Nullable + private static PsiElement smartAdvance(PsiElement element, boolean fwd) { + Class[] skipTypes = {PsiWhiteSpace.class, PsiComment.class}; + return fwd ? PsiTreeUtil.skipSiblingsForward(element, skipTypes) + : PsiTreeUtil.skipSiblingsBackward(element, skipTypes); + } + + @Nullable + static private PsiElement smartAdvanceAsExpr(PsiElement element, boolean fwd) { + return ObjectUtils.tryCast(smartAdvance(element, fwd), PsiElement.class); + } +} diff --git a/platform/platform-resources-en/src/intentionDescriptions/FlipCommaIntention/after.sql.template b/platform/platform-resources-en/src/intentionDescriptions/FlipCommaIntention/after.sql.template new file mode 100644 index 000000000000..efc990bab465 --- /dev/null +++ b/platform/platform-resources-en/src/intentionDescriptions/FlipCommaIntention/after.sql.template @@ -0,0 +1 @@ +foo(b, a) \ No newline at end of file diff --git a/platform/platform-resources-en/src/intentionDescriptions/FlipCommaIntention/before.sql.template b/platform/platform-resources-en/src/intentionDescriptions/FlipCommaIntention/before.sql.template new file mode 100644 index 000000000000..21ad4c6a8559 --- /dev/null +++ b/platform/platform-resources-en/src/intentionDescriptions/FlipCommaIntention/before.sql.template @@ -0,0 +1 @@ +foo(a, b); \ No newline at end of file diff --git a/platform/platform-resources-en/src/intentionDescriptions/FlipCommaIntention/description.html b/platform/platform-resources-en/src/intentionDescriptions/FlipCommaIntention/description.html new file mode 100644 index 000000000000..f787f577eeac --- /dev/null +++ b/platform/platform-resources-en/src/intentionDescriptions/FlipCommaIntention/description.html @@ -0,0 +1,5 @@ + + +Flips two elements separated by comma. + + \ No newline at end of file diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index fa2ec98db08a..a4da5e913e82 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -411,5 +411,10 @@ + + + com.intellij.openapi.editor.actions.FlipCommaIntention + +