package org.elixir_lang.code_insight.highlighting.brace_matcher;
import com.intellij.lang.BracePair;
import com.intellij.lang.PairedBraceMatcher;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.tree.IElementType;
import org.elixir_lang.psi.ElixirDoBlock;
import org.elixir_lang.psi.ElixirTypes;
import org.elixir_lang.psi.call.Call;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
class Paired implements PairedBraceMatcher {
/*
* CONSTANTS
*/
static final BracePair DO_END = new BracePair(ElixirTypes.DO, ElixirTypes.END, true);
static final BracePair FN_END = new BracePair(ElixirTypes.FN, ElixirTypes.END, true);
private final static BracePair[] BRACE_PAIRS = new BracePair[]{
DO_END,
FN_END,
new BracePair(ElixirTypes.CHAR_LIST_HEREDOC_PROMOTER, ElixirTypes.CHAR_LIST_HEREDOC_TERMINATOR, false),
new BracePair(ElixirTypes.CHAR_LIST_SIGIL_HEREDOC_PROMOTER, ElixirTypes.CHAR_LIST_SIGIL_HEREDOC_TERMINATOR, false),
new BracePair(ElixirTypes.CHAR_LIST_SIGIL_PROMOTER, ElixirTypes.CHAR_LIST_SIGIL_TERMINATOR, false),
new BracePair(ElixirTypes.CHAR_LIST_PROMOTER, ElixirTypes.CHAR_LIST_PROMOTER, false),
new BracePair(ElixirTypes.REGEX_HEREDOC_PROMOTER, ElixirTypes.REGEX_HEREDOC_TERMINATOR, false),
new BracePair(ElixirTypes.REGEX_PROMOTER, ElixirTypes.REGEX_TERMINATOR, false),
new BracePair(ElixirTypes.SIGIL_HEREDOC_PROMOTER, ElixirTypes.SIGIL_HEREDOC_TERMINATOR, false),
new BracePair(ElixirTypes.SIGIL_PROMOTER, ElixirTypes.SIGIL_TERMINATOR, false),
new BracePair(ElixirTypes.STRING_HEREDOC_PROMOTER, ElixirTypes.STRING_HEREDOC_TERMINATOR, false),
new BracePair(ElixirTypes.STRING_SIGIL_HEREDOC_PROMOTER, ElixirTypes.STRING_SIGIL_HEREDOC_TERMINATOR, false),
new BracePair(ElixirTypes.STRING_SIGIL_PROMOTER, ElixirTypes.STRING_SIGIL_TERMINATOR, false),
new BracePair(ElixirTypes.STRING_PROMOTER, ElixirTypes.STRING_TERMINATOR, false),
new BracePair(ElixirTypes.WORDS_HEREDOC_PROMOTER, ElixirTypes.WORDS_HEREDOC_TERMINATOR, false),
new BracePair(ElixirTypes.WORDS_PROMOTER, ElixirTypes.WORDS_TERMINATOR, false),
new BracePair(ElixirTypes.OPENING_BIT, ElixirTypes.CLOSING_BIT, false),
new BracePair(ElixirTypes.OPENING_BRACKET, ElixirTypes.CLOSING_BRACKET, false),
new BracePair(ElixirTypes.OPENING_CURLY, ElixirTypes.CLOSING_CURLY, false),
new BracePair(ElixirTypes.OPENING_PARENTHESIS, ElixirTypes.CLOSING_PARENTHESIS, false)
};
public final static PairedBraceMatcher INSTANCE = new Paired();
/*
* Instance Methods
*/
/**
* Returns the start offset of the code construct which owns the opening structural brace at the specified offset.
* For example, if the opening brace belongs to an 'if' statement, returns the start offset of the 'if' statement.
* This is used for the scope highlighting.
*
* @param file the file in which brace matching is performed.
* @param openingBraceOffset the offset of an opening structural brace.
* @return the offset of corresponding code construct, or the same offset if not defined.
*/
@Override
public int getCodeConstructStart(PsiFile file, int openingBraceOffset) {
int offset = openingBraceOffset;
PsiElement element = file.findElementAt(openingBraceOffset);
if (element != null) {
PsiElement parent = element.getParent();
if (parent instanceof ElixirDoBlock) {
PsiElement grandParent = parent.getParent();
if (grandParent instanceof Call) {
offset = grandParent.getTextOffset();
}
}
}
return offset;
}
/**
* Returns the array of definitions for brace pairs that need to be matched when
* editing code in the language.
*
* @return the array of brace pair definitions.
*/
@Contract(pure = true)
@Override
public BracePair[] getPairs() {
return BRACE_PAIRS;
}
/**
* Returns true if paired rbrace should be inserted after lbrace of given type when lbrace is encountered before
* contextType token. It is safe to always return true, then paired brace will be inserted anyway.
*
* @param lbraceType lbrace for which information is queried
* @param contextType token type that follows lbrace
* @return true / false as described
*/
@Override
public boolean isPairedBracesAllowedBeforeType(@NotNull IElementType lbraceType, @Nullable IElementType contextType) {
return true;
}
}