Package com.dci.intellij.dbn.code.common.completion

Source Code of com.dci.intellij.dbn.code.common.completion.CodeCompletionProvider

package com.dci.intellij.dbn.code.common.completion;

import com.dci.intellij.dbn.code.common.completion.options.filter.CodeCompletionFilterSettings;
import com.dci.intellij.dbn.code.common.lookup.AliasLookupItemFactory;
import com.dci.intellij.dbn.code.common.lookup.LookupItemFactory;
import com.dci.intellij.dbn.code.common.lookup.VariableLookupItemFactory;
import com.dci.intellij.dbn.common.content.DatabaseLoadMonitor;
import com.dci.intellij.dbn.common.lookup.ConsumerStoppedException;
import com.dci.intellij.dbn.common.lookup.LookupConsumer;
import com.dci.intellij.dbn.common.util.NamingUtil;
import com.dci.intellij.dbn.connection.ConnectionHandler;
import com.dci.intellij.dbn.language.common.DBLanguage;
import com.dci.intellij.dbn.language.common.DBLanguageFile;
import com.dci.intellij.dbn.language.common.element.ElementType;
import com.dci.intellij.dbn.language.common.element.ElementTypeBundle;
import com.dci.intellij.dbn.language.common.element.IdentifierElementType;
import com.dci.intellij.dbn.language.common.element.LeafElementType;
import com.dci.intellij.dbn.language.common.element.TokenElementType;
import com.dci.intellij.dbn.language.common.element.impl.QualifiedIdentifierVariant;
import com.dci.intellij.dbn.language.common.element.path.ASTPathNode;
import com.dci.intellij.dbn.language.common.element.path.PathNode;
import com.dci.intellij.dbn.language.common.psi.BasePsiElement;
import com.dci.intellij.dbn.language.common.psi.IdentifierPsiElement;
import com.dci.intellij.dbn.language.common.psi.LeafPsiElement;
import com.dci.intellij.dbn.language.common.psi.PsiUtil;
import com.dci.intellij.dbn.language.common.psi.QualifiedIdentifierPsiElement;
import com.dci.intellij.dbn.language.common.psi.lookup.AliasDefinitionLookupAdapter;
import com.dci.intellij.dbn.language.common.psi.lookup.ObjectDefinitionLookupAdapter;
import com.dci.intellij.dbn.language.common.psi.lookup.PsiLookupAdapter;
import com.dci.intellij.dbn.language.common.psi.lookup.VariableDefinitionLookupAdapter;
import com.dci.intellij.dbn.object.DBSchema;
import com.dci.intellij.dbn.object.common.DBObject;
import com.dci.intellij.dbn.object.common.DBObjectBundle;
import com.dci.intellij.dbn.object.common.DBObjectType;
import com.dci.intellij.dbn.object.common.ObjectTypeFilter;
import com.intellij.codeInsight.completion.CompletionParameters;
import com.intellij.codeInsight.completion.CompletionProvider;
import com.intellij.codeInsight.completion.CompletionResultSet;
import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.ProcessingContext;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;

import java.util.Map;
import java.util.Set;

public class CodeCompletionProvider extends CompletionProvider<CompletionParameters> {
    public static final CodeCompletionProvider INSTANCE = new CodeCompletionProvider();


    public CodeCompletionProvider() {
        super();
    }

    @Override
    protected void addCompletions(
            @NotNull CompletionParameters parameters,
            ProcessingContext processingContext,
            @NotNull CompletionResultSet result) {
        try {
            DatabaseLoadMonitor.setEnsureDataLoaded(false);
            doAddCompletions(parameters, result);
        } finally {
            DatabaseLoadMonitor.setEnsureDataLoaded(true);
        }

    }

    private void doAddCompletions(CompletionParameters parameters, CompletionResultSet result) {
        PsiFile originalFile = parameters.getOriginalFile();
        if (originalFile instanceof DBLanguageFile) {
            DBLanguageFile file = (DBLanguageFile) originalFile;

            CodeCompletionContext context = new CodeCompletionContext(file, parameters, result);
            CodeCompletionLookupConsumer consumer = new CodeCompletionLookupConsumer(context);
            DBLanguage language = context.getLanguage();


            int caretOffset = parameters.getOffset();
            if (file.findElementAt(caretOffset) instanceof PsiComment) return;

            LeafPsiElement leafBeforeCaret = PsiUtil.lookupLeafBeforeOffset(file, caretOffset);


            int invocationCount = parameters.getInvocationCount();
            if (invocationCount > 1) context.setExtended(true);

            if (leafBeforeCaret == null) {
                ElementTypeBundle elementTypeBundle = file.getElementTypeBundle();
                Set<LeafElementType> firstPossibleLeafs = elementTypeBundle.getRootElementType().getLookupCache().getFirstPossibleLeafs();
                for (LeafElementType firstPossibleLeaf : firstPossibleLeafs) {
                    if (firstPossibleLeaf instanceof TokenElementType) {
                        TokenElementType tokenElementType = (TokenElementType) firstPossibleLeaf;
                        if (context.getCodeCompletionFilterSettings().acceptReservedWord(tokenElementType.getTokenTypeCategory())) {
                            LookupItemFactory lookupItemFactory = tokenElementType.getLookupItemFactory(language);
                            lookupItemFactory.createLookupItem(tokenElementType, consumer);
                        }
                    }
                }
            } else {
                leafBeforeCaret = (LeafPsiElement) leafBeforeCaret.getOriginalElement();
                try {
                    buildElementRelativeVariants(leafBeforeCaret, consumer);
                } catch (ConsumerStoppedException e) {

                }
            }
        }
    }

    private String getLeafUniqueKey(LeafElementType leaf) {
        if (leaf instanceof TokenElementType) {
            TokenElementType tokenElementType = (TokenElementType) leaf;
            return tokenElementType.getTokenType().getId();
        } else if (leaf instanceof IdentifierElementType){
            IdentifierElementType identifierElementType = (IdentifierElementType) leaf;
            return identifierElementType.getQualifiedObjectTypeName();
        }
        return null;
    }

    private void buildElementRelativeVariants(LeafPsiElement element, CodeCompletionLookupConsumer consumer) throws ConsumerStoppedException {

        CodeCompletionContext context = consumer.getContext();
        ConnectionHandler connectionHandler = context.getConnectionHandler();

        CodeCompletionFilterSettings filterSettings = context.getCodeCompletionFilterSettings();
        Map<String, LeafElementType> nextPossibleLeafs = new THashMap<String, LeafElementType>();
        DBObject parentObject = null;
        if (element.getParent() instanceof QualifiedIdentifierPsiElement) {
            QualifiedIdentifierPsiElement qualifiedIdentifier = (QualifiedIdentifierPsiElement) element.getParent();
            ElementType separator = qualifiedIdentifier.getElementType().getSeparatorToken();

            if (element.getElementType() == separator){
                BasePsiElement parentPsiElement = element.getPrevElement();
                if (parentPsiElement != null && parentPsiElement instanceof IdentifierPsiElement) {
                    IdentifierPsiElement identifierPsiElement = (IdentifierPsiElement) parentPsiElement;
                    parentObject = identifierPsiElement.resolveUnderlyingObject();

                    if (parentObject != null) {
                        for (QualifiedIdentifierVariant parseVariant : qualifiedIdentifier.getParseVariants()){
                            boolean match = parseVariant.matchesPsiElement(qualifiedIdentifier);
                            if (match) {
                                int index = qualifiedIdentifier.getIndexOf(identifierPsiElement);
                                LeafElementType leafElementType = parseVariant.getLeaf(index + 1);
                                if (leafElementType != null) {
                                    nextPossibleLeafs.put(getLeafUniqueKey(leafElementType), leafElementType);
                                }
                            }
                        }
                    }
                }
            }
        }

        if (nextPossibleLeafs.size() == 0) {
            LeafElementType elementType = (LeafElementType) element.getElementType();
            PathNode pathNode = new ASTPathNode(element.getNode());
            for (LeafElementType leafElementType : elementType.getNextPossibleLeafs(pathNode, filterSettings)) {
                String leafUniqueKey = getLeafUniqueKey(leafElementType);
                if (leafUniqueKey != null) {
                    nextPossibleLeafs.put(leafUniqueKey, leafElementType);   
                }
            }
        }

        for (LeafElementType nextPossibleLeaf : nextPossibleLeafs.values()) {
            consumer.check();
            //boolean addParenthesis =
            //        nextPossibleLeaf.getLookupCache().getNextRequiredTokens().contains(
            //                element.getLanguage().getSharedTokenTypes().getLeftParenthesis());
            //consumer.setAddParenthesis(addParenthesis);

            if (nextPossibleLeaf instanceof TokenElementType) {
                TokenElementType tokenElementType = (TokenElementType) nextPossibleLeaf;
                //consumer.setAddParenthesis(addParenthesis && tokenType.isFunction());
                if (filterSettings.acceptReservedWord(tokenElementType.getTokenTypeCategory())) {
                    consumer.consume(tokenElementType);
                }
            }
            else if (nextPossibleLeaf instanceof IdentifierElementType) {
                IdentifierElementType identifierElementType = (IdentifierElementType) nextPossibleLeaf;
                if (identifierElementType.isReference()) {
                    DBObjectType objectType = identifierElementType.getObjectType();
                    if (identifierElementType.isObject()) {
                        PsiLookupAdapter lookupAdapter = new ObjectDefinitionLookupAdapter(null, objectType,  null);
                        Set<BasePsiElement> objectDefinitions = lookupAdapter.collectInParentScopeOf(element);
                        if (objectDefinitions != null) {
                            for (BasePsiElement psiElement : objectDefinitions) {
                                if (psiElement instanceof IdentifierPsiElement) {
                                    IdentifierPsiElement identifierPsiElement = (IdentifierPsiElement) psiElement;
                                    PsiElement referencedPsiElement = identifierPsiElement.resolve();
                                    if (referencedPsiElement instanceof DBObject) {
                                        DBObject object = (DBObject) referencedPsiElement;
                                        LookupItemFactory lookupItemFactory = object.getLookupItemFactory(identifierElementType.getLanguage());
                                        lookupItemFactory.createLookupItem(object, consumer);
                                    }
                                }
                            }
                        }
                       
                        if (connectionHandler != null && !connectionHandler.isVirtual()) {
                            if (parentObject == null) {
                                BasePsiElement scope = element.getEnclosingScopePsiElement();
                                collectObjectMatchingScope(consumer, identifierElementType, filterSettings, scope, context);
                            } else {
                                for (DBObject object : parentObject.getChildObjects(identifierElementType.getObjectType())) {
                                    consumer.check();
                                    consumer.consume(object);
                                }
                            }
                        }

                    } else if (identifierElementType.isAlias()) {
                        PsiLookupAdapter lookupAdapter = new AliasDefinitionLookupAdapter(null, objectType,  null);
                        Set<BasePsiElement> aliasDefinitions = lookupAdapter.collectInParentScopeOf(element);
                        if (aliasDefinitions != null) {
                            for (PsiElement psiElement : aliasDefinitions) {
                                IdentifierPsiElement identifierPsiElement = (IdentifierPsiElement) psiElement;
                                AliasLookupItemFactory lookupItemFactory = new AliasLookupItemFactory(identifierPsiElement.getChars(), true);
                                lookupItemFactory.createLookupItem(identifierPsiElement, consumer);
                            }
                        }
                    } else if (identifierElementType.isVariable()) {
                        PsiLookupAdapter lookupAdapter = new VariableDefinitionLookupAdapter(null, objectType, null);
                        Set<BasePsiElement> aliasDefinitions = lookupAdapter.collectInParentScopeOf(element);
                        if (aliasDefinitions != null) {
                            for (BasePsiElement psiElement : aliasDefinitions) {
                                IdentifierPsiElement identifierPsiElement = (IdentifierPsiElement) psiElement;
                                VariableLookupItemFactory lookupItemFactory = new VariableLookupItemFactory(identifierPsiElement.getChars(), true);
                                lookupItemFactory.createLookupItem(identifierPsiElement, consumer);
                            }
                        }
                    }
                } else if (identifierElementType.isDefinition()) {
                    if (identifierElementType.isAlias()) {
                        String[] aliasNames = buildAliasDefinitionNames(element);
                        for (String aliasName : aliasNames) {
                            AliasLookupItemFactory lookupItemFactory = new AliasLookupItemFactory(aliasName, true);
                            lookupItemFactory.createLookupItem(aliasName, consumer);
                        }
                    }
                }
            }
        }
    }

    public String[] buildAliasDefinitionNames(BasePsiElement aliasElement) {
        IdentifierPsiElement aliasedObject = PsiUtil.lookupObjectPriorTo(aliasElement, DBObjectType.ANY);
        if (aliasedObject != null && aliasedObject.isObject()) {
            String[] aliasNames = NamingUtil.createAliasNames(aliasedObject.getUnquotedText());

            BasePsiElement scope = aliasElement.getEnclosingScopePsiElement();

            for (int i = 0; i< aliasNames.length; i++) {
                while (true) {
                    PsiLookupAdapter lookupAdapter = new AliasDefinitionLookupAdapter(null, DBObjectType.ANY, aliasNames[i]);
                    boolean isExisting = lookupAdapter.findInScope(scope) != null;
                    boolean isKeyword = aliasElement.getLanguageDialect().isReservedWord(aliasNames[i]);
                    if (isKeyword || isExisting) {
                        aliasNames[i] = NamingUtil.getNextNumberedName(aliasNames[i], false);
                    } else {
                        break;
                    }
                }
            }
            return aliasNames;
        }
        return new String[0];
    }

    private void collectObjectMatchingScope(
            LookupConsumer consumer,
            IdentifierElementType identifierElementType,
            ObjectTypeFilter filter,
            BasePsiElement sourceScope,
            CodeCompletionContext context) throws ConsumerStoppedException {
        DBObjectType objectType = identifierElementType.getObjectType();
        PsiElement sourceElement = context.getElementAtCaret();
        ConnectionHandler connectionHandler = context.getConnectionHandler();

        if (connectionHandler != null ) {
            DBObjectBundle objectBundle = connectionHandler.getObjectBundle();
            if (sourceElement.getParent() instanceof QualifiedIdentifierPsiElement && sourceElement.getParent().getFirstChild() != sourceElement) {
                QualifiedIdentifierPsiElement qualifiedIdentifierPsiElement = (QualifiedIdentifierPsiElement) sourceElement.getOriginalElement().getParent();
                DBObject parentObject = qualifiedIdentifierPsiElement.lookupParentObjectFor(identifierElementType);
                if (parentObject != null) {
                    DBSchema currentSchema = PsiUtil.getCurrentSchema(sourceScope);
                    objectBundle.lookupChildObjectsOfType(
                            consumer,
                            parentObject,
                            objectType,
                            filter,
                            currentSchema);

                }
            } else if (!identifierElementType.isLocalReference()){
                Set<DBObject> parentObjects = LeafPsiElement.identifyPotentialParentObjects(objectType, filter, sourceScope, null);
                if (parentObjects != null && parentObjects.size() > 0) {
                    for (DBObject parentObject : parentObjects) {
                        DBSchema currentSchema = PsiUtil.getCurrentSchema(sourceScope);
                        objectBundle.lookupChildObjectsOfType(
                                consumer,
                                parentObject.getUndisposedElement(),
                                objectType,
                                filter,
                                currentSchema);
                    }
                } else {
                    if (filter.acceptsRootObject(objectType)) {
                        objectBundle.lookupObjectsOfType(
                                consumer,
                                objectType);
                    }
                }
            }
        }
    }
}
TOP

Related Classes of com.dci.intellij.dbn.code.common.completion.CodeCompletionProvider

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.