Search in sources :

Example 1 with PerlHeredocElementImpl

use of com.perl5.lang.perl.psi.impl.PerlHeredocElementImpl in project Perl5-IDEA by Camelcade.

the class PerlDocumentBasedFormattingModel method shiftIndentInsideDocumentRange.

@Override
public TextRange shiftIndentInsideDocumentRange(Document document, ASTNode node, TextRange range, int indent) {
    if (!HEREDOC_BODIES_TOKENSET.contains(PsiUtilCore.getElementType(node))) {
        return null;
    }
    PsiElement psi = node.getPsi();
    assert psi instanceof PerlHeredocElementImpl : "Got " + psi + " instead of heredoc from " + PsiUtilCore.getElementType(node);
    if (!((PerlHeredocElementImpl) psi).isIndentable()) {
        return null;
    }
    final int newLength = shiftIndentInside(range, indent);
    return new TextRange(range.getStartOffset(), range.getStartOffset() + newLength);
}
Also used : TextRange(com.intellij.openapi.util.TextRange) PsiElement(com.intellij.psi.PsiElement) PerlHeredocElementImpl(com.perl5.lang.perl.psi.impl.PerlHeredocElementImpl)

Example 2 with PerlHeredocElementImpl

use of com.perl5.lang.perl.psi.impl.PerlHeredocElementImpl in project Perl5-IDEA by Camelcade.

the class PerlIndentProcessor method getNodeIndent.

@NotNull
public Indent getNodeIndent(@NotNull ASTNode node) {
    IElementType nodeType = node.getElementType();
    ASTNode parent = node.getTreeParent();
    ASTNode grandParent = parent != null ? parent.getTreeParent() : null;
    IElementType parentNodeType = parent != null ? parent.getElementType() : null;
    IElementType grandParentNodeType = grandParent != null ? grandParent.getElementType() : null;
    ASTNode prevSibling = FormatterUtil.getPreviousNonWhitespaceSibling(node);
    IElementType prevSiblingElementType = prevSibling != null ? prevSibling.getElementType() : null;
    ASTNode nextSibling = FormatterUtil.getNextNonWhitespaceSibling(node);
    IElementType nextSiblingElementType = nextSibling != null ? nextSibling.getElementType() : null;
    boolean isFirst = prevSibling == null;
    boolean isLast = nextSibling == null;
    if (parentNodeType == ATTRIBUTES) {
        return Indent.getContinuationIndent();
    }
    if (isFirst && BLOCK_OPENERS.contains(nodeType) || isLast && BLOCK_CLOSERS.contains(nodeType)) {
        return Indent.getNoneIndent();
    }
    if (VARIABLE_DECLARATIONS.contains(parentNodeType) && (nodeType == LEFT_PAREN || nodeType == RIGHT_PAREN)) {
        return Indent.getNoneIndent();
    }
    boolean forceFirstIndent = false;
    if (HEREDOC_BODIES_TOKENSET.contains(nodeType)) {
        PsiElement psi = node.getPsi();
        assert psi instanceof PerlHeredocElementImpl;
        if (!((PerlHeredocElementImpl) psi).isIndentable()) {
            return Indent.getAbsoluteNoneIndent();
        }
        forceFirstIndent = true;
    }
    if (getAbsoluteUnindentableTokens().contains(nodeType)) {
        return Indent.getAbsoluteNoneIndent();
    }
    if (nodeType == BLOCK && MULTI_PARAM_BLOCK_CONTAINERS.contains(parentNodeType)) {
        return Indent.getNoneIndent();
    }
    if (parent == null || grandParent == null && nodeType != HEREDOC_END_INDENTABLE && !HEREDOC_BODIES_TOKENSET.contains(nodeType)) {
        return Indent.getNoneIndent();
    }
    if (getUnindentableTokens().contains(nodeType) || (nodeType instanceof PerlPolyNamedElementType && !(node.getPsi() instanceof PerlPolyNamedNestedCallElementBase))) {
        return Indent.getNoneIndent();
    }
    if (parentNodeType == STRING_LIST && (nodeType == QUOTE_SINGLE_OPEN || nodeType == QUOTE_SINGLE_CLOSE)) {
        return Indent.getNoneIndent();
    }
    if (nodeType == STRING_CONTENT && (parentNodeType == STRING_LIST || parentNodeType == LP_STRING_QW)) {
        return Indent.getContinuationIndent();
    }
    // defined by parent
    if (getUnindentableContainers().contains(parentNodeType)) {
        // a little magic for sub attributes
        if (parentNodeType == SUB_DEFINITION) {
            if (nodeType == COLON && nextSiblingElementType == ATTRIBUTE || nodeType == ATTRIBUTE && prevSiblingElementType != COLON) {
                return Indent.getContinuationIndent();
            }
        }
        return Indent.getNoneIndent();
    }
    if (PerlFormattingContext.COMMA_LIKE_SEQUENCES.contains(parentNodeType)) {
        return grandParentNodeType == STATEMENT ? Indent.getContinuationWithoutFirstIndent() : Indent.getContinuationIndent();
    }
    if (parentNodeType == CALL_ARGUMENTS) {
        return Indent.getContinuationIndent();
    }
    if (getBlockLikeContainers().contains(parentNodeType)) {
        return Indent.getNormalIndent();
    }
    return forceFirstIndent ? Indent.getContinuationIndent() : Indent.getContinuationWithoutFirstIndent();
}
Also used : IElementType(com.intellij.psi.tree.IElementType) PerlPolyNamedElementType(com.perl5.lang.perl.psi.stubs.PerlPolyNamedElementType) ASTNode(com.intellij.lang.ASTNode) PsiElement(com.intellij.psi.PsiElement) PerlHeredocElementImpl(com.perl5.lang.perl.psi.impl.PerlHeredocElementImpl) PerlPolyNamedNestedCallElementBase(com.perl5.lang.perl.psi.impl.PerlPolyNamedNestedCallElementBase) NotNull(org.jetbrains.annotations.NotNull)

Example 3 with PerlHeredocElementImpl

use of com.perl5.lang.perl.psi.impl.PerlHeredocElementImpl in project Perl5-IDEA by Camelcade.

the class PerlEnterHeredocClosingHandler method postProcessEnter.

@Override
public Result postProcessEnter(@NotNull PsiFile file, @NotNull Editor editor, @NotNull DataContext dataContext) {
    if (!file.getLanguage().is(PerlLanguage.INSTANCE)) {
        return Result.Continue;
    }
    final CaretModel caretModel = editor.getCaretModel();
    int offset = caretModel.getOffset();
    PsiElement currentElement = file.findElementAt(offset);
    if (currentElement != null && (!(currentElement.getParent() instanceof PerlHeredocElementImpl) || !Perl5CodeInsightSettings.getInstance().HEREDOC_AUTO_INSERTION)) {
        return Result.Continue;
    }
    LogicalPosition currentPosition = caretModel.getLogicalPosition();
    final int enterLine = currentPosition.line - 1;
    final int currentOffset = caretModel.getOffset();
    if (enterLine <= -1 || currentOffset <= 0) {
        return Result.Continue;
    }
    final Document document = editor.getDocument();
    final PsiDocumentManager manager = PsiDocumentManager.getInstance(file.getProject());
    manager.commitDocument(document);
    final int lineStartOffset = document.getLineStartOffset(enterLine);
    PsiElement firstLineElement = file.findElementAt(lineStartOffset);
    if (firstLineElement == null) {
        return Result.Continue;
    }
    HeredocCollector collector = new HeredocCollector(currentOffset - 1);
    PerlPsiUtil.iteratePsiElementsRight(firstLineElement, collector);
    SmartPsiElementPointer<PerlHeredocOpener> lastOpenerPointer = null;
    for (SmartPsiElementPointer<PerlHeredocOpener> currentOpenerPointer : collector.getResult()) {
        PerlHeredocOpener currentOpener = currentOpenerPointer.getElement();
        if (currentOpener == null) {
            // System.err.println("Opener invalidated on reparse");
            return Result.Continue;
        }
        String openerName = currentOpener.getName();
        boolean emptyOpener = StringUtil.isEmpty(openerName);
        PsiReference inboundReference = ReferencesSearch.search(currentOpener).findFirst();
        if (inboundReference != null) {
            boolean falseAlarm = false;
            PsiElement run = inboundReference.getElement().getPrevSibling();
            while (run instanceof PsiWhiteSpace) {
                run = run.getPrevSibling();
            }
            if (run instanceof PerlHeredocElementImpl) {
                Pattern openerPattern = EMPTY_OPENER_PATTERN;
                if (!emptyOpener) {
                    openerPattern = Pattern.compile("<<~?(\\s*)(?:" + "\"" + openerName + "\"" + "|" + "`" + openerName + "`" + "|" + "'" + openerName + "'" + "|" + "\\\\" + openerName + "|" + openerName + ")");
                }
                falseAlarm = openerPattern.matcher(run.getNode().getChars()).find();
            }
            if (// looks like overlapping heredocs
            falseAlarm) {
                inboundReference = null;
            } else {
                lastOpenerPointer = currentOpenerPointer;
            }
        }
        if (// disclosed marker
        inboundReference == null) {
            int addOffset;
            String closeMarker = "\n" + openerName + "\n";
            if (// first one
            lastOpenerPointer == null) {
                addOffset = currentOffset;
            } else // sequentional
            {
                PerlHeredocOpener lastOpener = lastOpenerPointer.getElement();
                if (lastOpener == null) {
                    return Result.Continue;
                }
                PsiReference lastOpenerReference = ReferencesSearch.search(lastOpener).findFirst();
                if (lastOpenerReference != null) {
                    PsiElement element = lastOpenerReference.getElement();
                    addOffset = element.getTextRange().getEndOffset();
                    if (!emptyOpener) {
                        closeMarker = "\n" + closeMarker;
                    }
                } else {
                    return Result.Continue;
                }
            }
            document.insertString(addOffset, closeMarker);
            manager.commitDocument(document);
            CodeStyleManager.getInstance(file.getProject()).reformatRange(file, addOffset, addOffset + closeMarker.length());
            currentOpener = currentOpenerPointer.getElement();
            if (currentOpener == null) {
                return Result.Continue;
            }
            inboundReference = ReferencesSearch.search(currentOpener).findFirst();
            if (inboundReference != null) {
                lastOpenerPointer = currentOpenerPointer;
            } else {
                return Result.Continue;
            }
        }
    }
    return Result.Continue;
}
Also used : LogicalPosition(com.intellij.openapi.editor.LogicalPosition) Pattern(java.util.regex.Pattern) CaretModel(com.intellij.openapi.editor.CaretModel) PerlHeredocOpener(com.perl5.lang.perl.psi.PerlHeredocOpener) Document(com.intellij.openapi.editor.Document) PerlHeredocElementImpl(com.perl5.lang.perl.psi.impl.PerlHeredocElementImpl)

Example 4 with PerlHeredocElementImpl

use of com.perl5.lang.perl.psi.impl.PerlHeredocElementImpl in project Perl5-IDEA by Camelcade.

the class PerlHeredocFormattingBlock method getTextRange.

@NotNull
@Override
public TextRange getTextRange() {
    TextRange originalRange = super.getTextRange();
    if (originalRange.isEmpty()) {
        return originalRange;
    }
    TextRange trimmedRange = TextRange.create(originalRange.getStartOffset(), originalRange.getEndOffset() - 1);
    PerlHeredocElementImpl heredocElement = getPsi();
    if (!heredocElement.isIndentable()) {
        return trimmedRange;
    }
    PerlHeredocTerminatorElement terminatorElement = heredocElement.getTerminatorElement();
    if (terminatorElement == null) {
        return trimmedRange;
    }
    // perlop: Tabs and spaces can be mixed, but are matched exactly. One tab will not be equal to 8 spaces!
    int spacesBeforeTerminator = terminatorElement.getTextRange().getStartOffset() - trimmedRange.getEndOffset() - 1;
    if (spacesBeforeTerminator == 0) {
        return trimmedRange;
    }
    CharSequence nodeChars = trimmedRange.shiftRight(-myNode.getStartOffset()).subSequence(myNode.getChars());
    int effectiveCharsLength = nodeChars.length();
    int realSpaces;
    int offset = 0;
    OUTER: while (offset < effectiveCharsLength) {
        for (realSpaces = 0; realSpaces <= spacesBeforeTerminator && offset < effectiveCharsLength; realSpaces++) {
            if (realSpaces == spacesBeforeTerminator) {
                break OUTER;
            }
            char currentChar = nodeChars.charAt(offset);
            if (currentChar == '\n') {
                offset++;
                break;
            } else if (!Character.isWhitespace(currentChar)) {
                break OUTER;
            } else {
                offset++;
            }
        }
    }
    return TextRange.create(trimmedRange.getStartOffset() + offset, trimmedRange.getEndOffset());
}
Also used : PerlHeredocTerminatorElement(com.perl5.lang.perl.psi.PerlHeredocTerminatorElement) TextRange(com.intellij.openapi.util.TextRange) PerlHeredocElementImpl(com.perl5.lang.perl.psi.impl.PerlHeredocElementImpl) NotNull(org.jetbrains.annotations.NotNull)

Example 5 with PerlHeredocElementImpl

use of com.perl5.lang.perl.psi.impl.PerlHeredocElementImpl in project Perl5-IDEA by Camelcade.

the class PerlDocUtil method getPerlOpDoc.

@Nullable
public static PsiElement getPerlOpDoc(@NotNull PsiElement element) {
    final Project project = element.getProject();
    String text = element.getText();
    String redirect = myOperatorsRedirections.get(text);
    if (redirect != null) {
        return resolveDocLink(redirect, element);
    }
    // fixme use map?
    PodDocumentPattern pattern = PodDocumentPattern.indexPattern(text);
    if (element instanceof PerlHeredocOpener || element instanceof PerlHeredocTerminatorElement || element instanceof PerlHeredocElementImpl) {
        // searches with X<>
        pattern.setIndexKey("heredoc");
    } else if (text.matches("-[rwxoRWXOeszfdlpSbctugkTBMAC]")) {
        pattern.setIndexKey("-X");
    } else if ("?".equals(text) || ":".equals(text)) {
        pattern.setIndexKey("?:");
    }
    return searchPodElementInFile(project, PodSearchHelper.PERL_OP_FILE_NAME, pattern);
}
Also used : PerlHeredocTerminatorElement(com.perl5.lang.perl.psi.PerlHeredocTerminatorElement) Project(com.intellij.openapi.project.Project) PerlHeredocOpener(com.perl5.lang.perl.psi.PerlHeredocOpener) PerlHeredocElementImpl(com.perl5.lang.perl.psi.impl.PerlHeredocElementImpl) Nullable(org.jetbrains.annotations.Nullable)

Aggregations

PerlHeredocElementImpl (com.perl5.lang.perl.psi.impl.PerlHeredocElementImpl)9 NotNull (org.jetbrains.annotations.NotNull)4 Language (com.intellij.lang.Language)3 TextRange (com.intellij.openapi.util.TextRange)3 PerlHeredocTerminatorElement (com.perl5.lang.perl.psi.PerlHeredocTerminatorElement)3 Project (com.intellij.openapi.project.Project)2 PsiElement (com.intellij.psi.PsiElement)2 IElementType (com.intellij.psi.tree.IElementType)2 PerlHeredocOpener (com.perl5.lang.perl.psi.PerlHeredocOpener)2 Nullable (org.jetbrains.annotations.Nullable)2 ASTNode (com.intellij.lang.ASTNode)1 MultiHostRegistrar (com.intellij.lang.injection.MultiHostRegistrar)1 CaretModel (com.intellij.openapi.editor.CaretModel)1 Document (com.intellij.openapi.editor.Document)1 LogicalPosition (com.intellij.openapi.editor.LogicalPosition)1 PsiLanguageInjectionHost (com.intellij.psi.PsiLanguageInjectionHost)1 PerlHeredocLanguageInjector (com.perl5.lang.perl.idea.intellilang.PerlHeredocLanguageInjector)1 PerlFileImpl (com.perl5.lang.perl.psi.impl.PerlFileImpl)1 PerlPolyNamedNestedCallElementBase (com.perl5.lang.perl.psi.impl.PerlPolyNamedNestedCallElementBase)1 PerlPolyNamedElementType (com.perl5.lang.perl.psi.stubs.PerlPolyNamedElementType)1