org.mustbe.consulo.csharp.ide.completion.CSharpAccessorCompletionContributor.java Source code

Java tutorial

Introduction

Here is the source code for org.mustbe.consulo.csharp.ide.completion.CSharpAccessorCompletionContributor.java

Source

/*
 * Copyright 2013-2014 must-be.org
 *
 * 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 org.mustbe.consulo.csharp.ide.completion;

import static com.intellij.patterns.StandardPatterns.psiElement;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.mustbe.consulo.RequiredReadAction;
import org.mustbe.consulo.RequiredWriteAction;
import org.mustbe.consulo.codeInsight.completion.CompletionProvider;
import org.mustbe.consulo.csharp.lang.psi.CSharpEventDeclaration;
import org.mustbe.consulo.csharp.lang.psi.CSharpSoftTokens;
import org.mustbe.consulo.csharp.lang.psi.CSharpXXXAccessorOwner;
import org.mustbe.consulo.dotnet.psi.DotNetModifier;
import org.mustbe.consulo.dotnet.psi.DotNetXXXAccessor;
import com.intellij.codeInsight.completion.CompletionContributor;
import com.intellij.codeInsight.completion.CompletionParameters;
import com.intellij.codeInsight.completion.CompletionResultSet;
import com.intellij.codeInsight.completion.CompletionType;
import com.intellij.codeInsight.completion.InsertHandler;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.editor.CaretModel;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.actionSystem.EditorActionManager;
import com.intellij.openapi.editor.actionSystem.EditorWriteActionHandler;
import com.intellij.psi.PsiElement;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ProcessingContext;

/**
 * @author VISTALL
 * @since 24.12.14
 */
public class CSharpAccessorCompletionContributor extends CompletionContributor {
    public CSharpAccessorCompletionContributor() {
        extend(CompletionType.BASIC, psiElement().andNot(psiElement().inside(DotNetXXXAccessor.class)),
                new CompletionProvider() {
                    @RequiredReadAction
                    @Override
                    protected void addCompletions(@NotNull CompletionParameters completionParameters,
                            ProcessingContext processingContext, @NotNull CompletionResultSet resultSet) {
                        PsiElement position = completionParameters.getPosition();
                        final CSharpXXXAccessorOwner accessorOwner = PsiTreeUtil.getParentOfType(position,
                                CSharpXXXAccessorOwner.class);
                        if (accessorOwner == null) {
                            return;
                        }
                        PsiElement leftBrace = accessorOwner.getLeftBrace();
                        if (leftBrace == null) {
                            return;
                        }

                        int textOffset = position.getTextOffset();
                        PsiElement rightBrace = accessorOwner.getRightBrace();
                        int rightTextRange = rightBrace == null ? -1 : rightBrace.getTextOffset();

                        if ((rightTextRange == -1 || textOffset < rightTextRange)
                                && textOffset > leftBrace.getTextOffset()) {
                            if (accessorOwner.hasModifier(DotNetModifier.ABSTRACT)) {
                                buildAccessorKeywordsCompletion(resultSet, accessorOwner, null);
                            } else {
                                buildAccessorKeywordsCompletion(resultSet, accessorOwner,
                                        new InsertHandler<LookupElement>() {
                                            @Override
                                            @RequiredWriteAction
                                            public void handleInsert(InsertionContext context, LookupElement item) {
                                                if (context.getCompletionChar() == '{') {
                                                    context.setAddCompletionChar(false);

                                                    Editor editor = context.getEditor();

                                                    CaretModel caretModel = editor.getCaretModel();
                                                    int offset = caretModel.getOffset();

                                                    context.getDocument().insertString(offset, "{\n}");
                                                    caretModel.moveToOffset(offset + 1);

                                                    PsiElement elementAt = context.getFile()
                                                            .findElementAt(offset - 1);

                                                    context.commitDocument();

                                                    DotNetXXXAccessor accessor = PsiTreeUtil
                                                            .getParentOfType(elementAt, DotNetXXXAccessor.class);
                                                    if (accessor != null) {
                                                        CodeStyleManager.getInstance(context.getProject())
                                                                .reformat(accessor);
                                                    }

                                                    EditorWriteActionHandler actionHandler = (EditorWriteActionHandler) EditorActionManager
                                                            .getInstance()
                                                            .getActionHandler(IdeActions.ACTION_EDITOR_ENTER);
                                                    actionHandler.executeWriteAction(editor,
                                                            DataManager.getInstance()
                                                                    .getDataContext(editor.getContentComponent()));
                                                }
                                            }
                                        });
                            }
                        }
                    }
                });
    }

    private void buildAccessorKeywordsCompletion(CompletionResultSet resultSet,
            final CSharpXXXAccessorOwner accessorOwner, @Nullable InsertHandler<LookupElement> insertHandler) {
        TokenSet tokenSet = accessorOwner instanceof CSharpEventDeclaration
                ? TokenSet.create(CSharpSoftTokens.ADD_KEYWORD, CSharpSoftTokens.REMOVE_KEYWORD)
                : TokenSet.create(CSharpSoftTokens.GET_KEYWORD, CSharpSoftTokens.SET_KEYWORD);

        for (IElementType elementType : tokenSet.getTypes()) {
            if (!isCanShowAccessorKeyword(elementType, accessorOwner)) {
                continue;
            }
            LookupElementBuilder builder = LookupElementBuilder
                    .create(CSharpCompletionUtil.textOfKeyword(elementType));
            builder = builder.bold();

            if (insertHandler != null) {
                builder = builder.withInsertHandler(insertHandler);
            }

            builder.putUserData(CSharpCompletionUtil.KEYWORD_ELEMENT_TYPE, elementType);

            resultSet.addElement(builder);
        }
    }

    private static boolean isCanShowAccessorKeyword(IElementType elementType,
            CSharpXXXAccessorOwner accessorOwner) {
        DotNetXXXAccessor[] accessors = accessorOwner.getAccessors();
        for (DotNetXXXAccessor accessor : accessors) {
            DotNetXXXAccessor.Kind accessorKind = accessor.getAccessorKind();
            if (accessorKind == null) {
                continue;
            }
            IElementType expectedElementType;
            switch (accessorKind) {
            case GET:
                expectedElementType = CSharpSoftTokens.GET_KEYWORD;
                break;
            case SET:
                expectedElementType = CSharpSoftTokens.SET_KEYWORD;
                break;
            case ADD:
                expectedElementType = CSharpSoftTokens.ADD_KEYWORD;
                break;
            case REMOVE:
                expectedElementType = CSharpSoftTokens.REMOVE_KEYWORD;
                break;
            default:
                continue;
            }
            if (expectedElementType == elementType) {
                return false;
            }
        }
        return true;
    }
}