Package org.intellij.jflex.editor

Source Code of org.intellij.jflex.editor.JFlexCompletionContributor

/*
* Copyright 2011-2014 Gregory Shrago
*
* 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.intellij.jflex.editor;

import com.intellij.codeInsight.TailType;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.codeInsight.lookup.TailTypeDecorator;
import com.intellij.lang.Language;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.patterns.StandardPatterns;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileFactory;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.impl.source.tree.LeafPsiElement;
import com.intellij.psi.impl.source.tree.TreeUtil;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ProcessingContext;
import org.intellij.grammar.parser.GeneratedParserUtilBase;
import org.intellij.jflex.parser.JFlexFileType;
import org.intellij.jflex.psi.JFlexDeclarationsSection;
import org.intellij.jflex.psi.JFlexExpression;
import org.intellij.jflex.psi.JFlexUserCodeSection;
import org.intellij.jflex.psi.impl.JFlexFileImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Collection;
import java.util.Collections;

import static com.intellij.patterns.PlatformPatterns.psiElement;
import static org.intellij.jflex.psi.JFlexTypes.*;

/**
* @author gregsh
*/
public class JFlexCompletionContributor extends CompletionContributor {

  public JFlexCompletionContributor() {
    extend(CompletionType.BASIC, psiElement().inFile(StandardPatterns.instanceOf(JFlexFileImpl.class)), new CompletionProvider<CompletionParameters>() {
      @Override
      protected void addCompletions(@NotNull CompletionParameters parameters,
                                    ProcessingContext context,
                                    @NotNull CompletionResultSet result) {
        for (String keyword : suggestKeywords(parameters.getPosition())) {
          result.addElement(createKeywordLookupItem(keyword));
        }
      }
    });
  }

  @Override
  public void beforeCompletion(@NotNull CompletionInitializationContext context) {
    context.setDummyIdentifier(CompletionUtil.DUMMY_IDENTIFIER_TRIMMED);
  }

  private static Collection<String> suggestKeywords(PsiElement position) {
    if (position instanceof LeafPsiElement && ((LeafPsiElement)position).getElementType() == FLEX_STRING) return Collections.emptySet();
    if (PsiTreeUtil.getParentOfType(position, JFlexUserCodeSection.class) != null) return Collections.emptySet();
    boolean inDeclare = PsiTreeUtil.getParentOfType(position, JFlexDeclarationsSection.class) != null;
    PsiFile flexFile = position.getContainingFile();
    Language language = flexFile.getLanguage();
    String flexFileText = flexFile.getText();
    int positionOffset = position.getTextRange().getEndOffset();

    JFlexExpression expr = PsiTreeUtil.getParentOfType(position, JFlexExpression.class);
    final boolean inMacro =
      expr != null && expr.getText().substring(0, positionOffset - expr.getTextRange().getStartOffset()).indexOf('\n') == -1;

    String fragment = (inDeclare ? "%%\n" : "%%\n%%\n") + flexFileText.substring(flexFileText.lastIndexOf("%%", positionOffset-1) + 2, positionOffset);
    boolean empty = StringUtil.isEmptyOrSpaces(fragment);
    final String text = empty ? CompletionInitializationContext.DUMMY_IDENTIFIER : fragment;
    int completionOffset = empty ? 0 : fragment.length();
    PsiFile file = PsiFileFactory.getInstance(flexFile.getProject()).createFileFromText("a.flex", language, text, true, false);
    GeneratedParserUtilBase.CompletionState state = new GeneratedParserUtilBase.CompletionState(completionOffset) {
      @Nullable
      @Override
      public String convertItem(Object o) {
        if (o == null) return null;
        if (o instanceof IElementType[]) return super.convertItem(o);
        if (o == FLEX_ID || o == FLEX_CHAR || o == FLEX_ESCAPED_CHAR || o == FLEX_STRING || o == FLEX_NUMBER || o == FLEX_JAVA) return null;
        String text = o.toString();
        return text.length() == 1 || inMacro && text.startsWith("%") || !inMacro && text.startsWith("[")? null : text;
      }
    };
    file.putUserData(GeneratedParserUtilBase.COMPLETION_STATE_KEY, state);
    TreeUtil.ensureParsed(file.getNode());
    return state.items;
  }

  private static LookupElement createKeywordLookupItem(String keyword) {
    LookupElementBuilder builder = LookupElementBuilder.create(keyword.toLowerCase()).withCaseSensitivity(false).bold();
    boolean braces = keyword.endsWith("{") || keyword.endsWith("}");
    if (!braces) {
      return keyword.startsWith("%") ? TailTypeDecorator.withTail(builder, TailType.SPACE) : builder;
    }
    else {
      final String closing = keyword.endsWith("{") ? keyword.substring(0, keyword.length()-1) + "}" : null;
      return PrioritizedLookupElement.withPriority(builder.withInsertHandler(new InsertHandler<LookupElement>() {
        @Override
        public void handleInsert(InsertionContext context, LookupElement item) {
          int caret = context.getTailOffset();
          Document document = context.getDocument();
          StringBuilder sb = new StringBuilder("\n");
          caret += sb.length();
          if (closing != null) {
            int indentSize = CodeStyleSettingsManager.getInstance(context.getProject()).
              getCurrentSettings().getIndentSize(JFlexFileType.INSTANCE);
            sb.append(StringUtil.repeat(" ", indentSize));
            caret += indentSize;
            sb.append("\n").append(closing).append("\n");
          }
          document.insertString(context.getTailOffset(), sb);
          context.getEditor().getCaretModel().moveToOffset(caret);
        }
      }), 1.d / keyword.length());
    }
  }
}
TOP

Related Classes of org.intellij.jflex.editor.JFlexCompletionContributor

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.