override fun getChildAttributes()

in src/main/kotlin/org/arend/formatting/block/SimpleArendBlock.kt [173:301]


    override fun getChildAttributes(newChildIndex: Int): ChildAttributes {
        printChildAttributesContext(newChildIndex)

        val nodePsi = node.psi

        if (node.elementType == STAT || nodePsi is ArendFile) return ChildAttributes.DELEGATE_TO_PREV_CHILD

        if (node.elementType == TUPLE && subBlocks.size > 1 && newChildIndex == 1)
            return ChildAttributes(Indent.getNormalIndent(), null)

        val prev2Child = if (newChildIndex > 1) subBlocks[newChildIndex - 2] else null
        val prevChild = if (newChildIndex > 0) subBlocks[newChildIndex - 1] else null
        val nextChild = if (newChildIndex < subBlocks.size) subBlocks[newChildIndex] else null

        if (prevChild is AbstractArendBlock) {
            val prevET = prevChild.node.elementType
            val prev2ET = if (prev2Child is AbstractArendBlock) prev2Child.node.elementType else null

            if (nodePsi is ArendWhere) {
                if (prevET == STAT) return ChildAttributes.DELEGATE_TO_PREV_CHILD
                if (prevET == WHERE_KW || prevET == LBRACE || prevET == ERROR_ELEMENT) return ChildAttributes(Indent.getNormalIndent(), null)
            }

            // Definitions
            if ((nodePsi is ArendDefinition<*> || nodePsi is ArendClassField ||
                            nodePsi is ArendPiExpr || nodePsi is ArendLamExpr || nodePsi is ArendSigmaExpr)
                    && newChildIndex <= subBlocks.size) {
                when (if (prevET == ERROR_ELEMENT) prev2ET else prevET) {
                    TYPE_TELE, NAME_TELE, FIELD_TELE -> {
                        val isLast = if (nextChild is AbstractArendBlock) when (nextChild.node.elementType) {
                            TYPE_TELE, NAME_TELE, FIELD_TELE -> false
                            else -> true
                        } else true
                        val align = (if (prevET == ERROR_ELEMENT) prev2Child else prevChild).let {
                            if (!isLast || it != null && hasLfBefore(it)) it?.alignment else null
                        }
                        return ChildAttributes(prevChild.indent, align)
                    }
                }
            }

            if ((nodePsi is ArendDefinition<*> || nodePsi is ArendDefModule) && prevET == WHERE)
                return ChildAttributes.DELEGATE_TO_PREV_CHILD

            if (nodePsi is ArendDefClass) when (prevET) {
                SUPER_CLASS, LONG_NAME -> return ChildAttributes(Indent.getNormalIndent(), null)
                CLASS_STAT -> return ChildAttributes.DELEGATE_TO_PREV_CHILD
            }

            if (nodePsi is ArendClassStat) return ChildAttributes.DELEGATE_TO_PREV_CHILD

            if (nodePsi is ArendDefData) when (prevET) {
                DEF_IDENTIFIER, UNIVERSE_EXPR, DATA_BODY, TYPE_TELE -> return ChildAttributes(Indent.getNormalIndent(), null)
            }

            if (nodePsi is ArendDefFunction) when (prevET) {
                FUNCTION_BODY -> return ChildAttributes.DELEGATE_TO_PREV_CHILD
            }

            if (nodePsi is ArendDefInstance) {
                when (prevChild.node.psi) {
                    is ArendReturnExpr -> return ChildAttributes(Indent.getNormalIndent(), null)
                    is ArendFunctionBody -> return ChildAttributes.DELEGATE_TO_PREV_CHILD
                    is ArendWhere -> return ChildAttributes(Indent.getNoneIndent(), null)
                }
            }

            // Data and function bodies
            if (nodePsi is ArendDataBody && prevChild.node.psi is ArendElim)
                return ChildAttributes(Indent.getNormalIndent(), null)

            if (nodePsi is ArendFunctionBody) {
                val indent = if (prevChild.node.psi is ArendExpr || prevChild is GroupBlock ) return ChildAttributes.DELEGATE_TO_PREV_CHILD else
                    when (prevET) {
                        FUNCTION_CLAUSES, CO_CLAUSE -> return ChildAttributes.DELEGATE_TO_PREV_CHILD
                        else -> Indent.getNormalIndent()
                    }
                return ChildAttributes(indent, null)
            }

            if (nodePsi is ArendFunctionClauses) {
                val clauseAttributes = getChildAttributesInfo(prevChild, prevChild.subBlocks.size)
                if (!(clauseAttributes.childIndent?.type == Indent.Type.NONE && clauseAttributes.alignment == null)) return clauseAttributes
            }
            if (nodePsi is ArendClause || nodePsi is ArendLocalCoClause) return ChildAttributes.DELEGATE_TO_PREV_CHILD

            //Expressions
            when (node.elementType) {
                PI_EXPR, LAM_EXPR -> when (prevET) {
                    ERROR_ELEMENT -> if (newChildIndex > 1) {
                        val sB = subBlocks[newChildIndex - 2]
                        if (sB is AbstractBlock && sB.node.elementType == TYPE_TELE) return ChildAttributes(sB.indent, sB.alignment)
                    }
                    ARROW, FAT_ARROW, PI_KW, LAM_KW, TYPE_TELE, NAME_TELE -> {
                    }
                    else -> return ChildAttributes.DELEGATE_TO_PREV_CHILD
                }
                ARR_EXPR -> return ChildAttributes.DELEGATE_TO_PREV_CHILD
                TUPLE, IMPLICIT_ARGUMENT -> when (prevET) {
                    RPAREN, RBRACE -> {
                    }
                    COMMA -> subBlocks.mapFirstNotNull { it.alignment }?.let {
                        return ChildAttributes(Indent.getNormalIndent(), it)
                    }
                    else -> return ChildAttributes.DELEGATE_TO_PREV_CHILD
                }
                NEW_EXPR -> when (prevET) {
                    LBRACE -> {
                    }
                    else -> return ChildAttributes.DELEGATE_TO_PREV_CHILD
                }
                TUPLE_EXPR -> return ChildAttributes.DELEGATE_TO_PREV_CHILD
                LET_CLAUSE -> if (prevET == FAT_ARROW || prevET == ERROR_ELEMENT && prev2ET == FAT_ARROW) return ChildAttributes(Indent.getNormalIndent(false), null)
            }

            //General case

            val indent = when (prevET) {
                LBRACE -> Indent.getNormalIndent()
                ERROR_ELEMENT -> if (prev2ET == LBRACE) Indent.getNormalIndent() else prevChild.indent
                else -> prevChild.indent
            }

            return ChildAttributes(indent, prevChild.alignment)
        } else if (nodePsi is PsiErrorElement)
            return ChildAttributes(Indent.getNormalIndent(), null)

        return super.getChildAttributes(newChildIndex)
    }