/* * Copyright 2013-2016 Sergey Ignatov, Alexander Zolotov, Florin Patan * * 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.goide.editor.smart; import com.goide.inspections.GoDeferGoInspection; import com.goide.psi.*; import com.goide.psi.impl.GoElementFactory; import com.intellij.lang.SmartEnterProcessorWithFixers; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; public class GoSmartEnterProcessor extends SmartEnterProcessorWithFixers { public GoSmartEnterProcessor() { addFixers(new IfFixer(), new ForFixer(), new FuncFixer(), new GoDeferExpressionFixer()); addEnterProcessors(new PlainEnterProcessor()); } private static void addBlockIfNeeded(@NotNull GoStatement element) { if (element.getBlock() == null) element.add(GoElementFactory.createBlock(element.getProject())); } @Override public boolean doNotStepInto(PsiElement element) { return element instanceof GoBlock; } @Override protected void collectAdditionalElements(@NotNull PsiElement element, @NotNull List<PsiElement> result) { element = PsiTreeUtil.getParentOfType(element, GoStatement.class, GoFunctionOrMethodDeclaration.class, GoFunctionLit.class); if (element != null) { result.add(element); PsiElement parent = element.getParent(); if (parent instanceof GoStatement) { result.add(parent); } } } private static class GoDeferExpressionFixer extends Fixer<SmartEnterProcessorWithFixers> { @Override public void apply(@NotNull Editor editor, @NotNull SmartEnterProcessorWithFixers processor, @NotNull PsiElement element) throws IncorrectOperationException { Project project = element.getProject(); if (element instanceof GoGoStatement) { PsiElement expr = GoDeferGoInspection.GoAddParensQuickFix.addParensIfNeeded(project, ((GoGoStatement)element).getExpression()); if (expr != null) { element.replace(GoElementFactory.createGoStatement(project, expr.getText())); } } else if (element instanceof GoDeferStatement) { PsiElement expr = GoDeferGoInspection.GoAddParensQuickFix.addParensIfNeeded(project, ((GoDeferStatement)element).getExpression()); if (expr != null) { element.replace(GoElementFactory.createDeferStatement(project, expr.getText())); } } } } private static class FuncFixer extends Fixer<SmartEnterProcessorWithFixers> { @Override public void apply(@NotNull Editor editor, @NotNull SmartEnterProcessorWithFixers processor, @NotNull PsiElement element) throws IncorrectOperationException { if (element instanceof GoFunctionOrMethodDeclaration && ((GoFunctionOrMethodDeclaration)element).getBlock() == null) { element.add(GoElementFactory.createBlock(element.getProject())); } if (element instanceof GoFunctionLit && ((GoFunctionLit)element).getBlock() == null) { element.add(GoElementFactory.createBlock(element.getProject())); } } } private static class IfFixer extends Fixer<SmartEnterProcessorWithFixers> { @Override public void apply(@NotNull Editor editor, @NotNull SmartEnterProcessorWithFixers processor, @NotNull PsiElement element) throws IncorrectOperationException { if (element instanceof GoIfStatement) addBlockIfNeeded((GoIfStatement)element); } } private static class ForFixer extends Fixer<SmartEnterProcessorWithFixers> { @Override public void apply(@NotNull Editor editor, @NotNull SmartEnterProcessorWithFixers processor, @NotNull PsiElement element) throws IncorrectOperationException { if (element instanceof GoForStatement) addBlockIfNeeded((GoStatement)element); } } public static class PlainEnterProcessor extends FixEnterProcessor { @Nullable private static GoBlock findBlock(@Nullable PsiElement element) { element = PsiTreeUtil.getNonStrictParentOfType(element, GoStatement.class, GoBlock.class, GoFunctionOrMethodDeclaration.class, GoFunctionLit.class); if (element instanceof GoSimpleStatement && element.getParent() instanceof GoStatement) { element = element.getParent(); } if (element instanceof GoIfStatement) return ((GoIfStatement)element).getBlock(); if (element instanceof GoForStatement) return ((GoForStatement)element).getBlock(); if (element instanceof GoBlock) return (GoBlock)element; if (element instanceof GoFunctionOrMethodDeclaration) return ((GoFunctionOrMethodDeclaration)element).getBlock(); if (element instanceof GoFunctionLit) return ((GoFunctionLit)element).getBlock(); return null; } @Override public boolean doEnter(PsiElement psiElement, PsiFile file, @NotNull Editor editor, boolean modified) { GoBlock block = findBlock(psiElement); if (block != null) { editor.getCaretModel().moveToOffset(block.getLbrace().getTextRange().getEndOffset()); } plainEnter(editor); return true; } } }