All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.piacenti.dslmaker.dsl.Highlighter.kt Maven / Gradle / Ivy

Go to download

Kotlin multiplatform library to facilitate creation of DSLs with ANTLR or a simple built in parser

There is a newer version: 1.1.55
Show newest version
package piacenti.dslmaker.dsl

import piacenti.dslmaker.GenericParser
import piacenti.dslmaker.GenericParser2
import piacenti.dslmaker.abstraction.ProductionStep
import piacenti.dslmaker.combine
import piacenti.dslmaker.dsl.TextModifier.Companion.applyModificationsMap
import piacenti.dslmaker.interfaces.GrammarInventory
import piacenti.dslmaker.interfaces.Parser
import piacenti.dslmaker.structures.ASTNode
import piacenti.dslmaker.structures.Grammar

//"'&<>
private val htmlCharTempMap = mutableMapOf(
        "\"" to "\u00CB",
        "'" to "\u00CC",
        "&" to "\u00CD",
        "<" to "\u00CE",
        ">" to "\u00CF"
)
private val htmlTempToEncodeMap = mutableMapOf(
        "\u00CB" to """,
        "\u00CC" to "'",
        "\u00CD" to "&",
        "\u00CE" to "<",
        "\u00CF" to ">"
)


interface Highlighter : TextModifier {
    fun highlight(text: String, encodeExistingHtml: Boolean = false): String {
        val map = computeHighlighting(text)
        var text2 = text
        if (encodeExistingHtml) {
            //replace html characters with unique new mapped characters before adding styling xml so that they can be
            // replaced afterwards
            htmlCharTempMap.forEach {
                text2 = text2.replace(it.key, it.value)
            }
        }
        var result = applyModificationsMap(text2, map)
        if (encodeExistingHtml) {
            htmlTempToEncodeMap.forEach {
                result = result.replace(it.key, it.value)
            }
        }
        return result
    }

    fun computeHighlighting(text: String, providedAST: ASTNode? = null, providedParser: GenericParser2<*>? = null): MutableMap>
}

data class StyleParse(val style: String, val start: Int, val end: Int, val customAttributes: List> = emptyList())
abstract class HTMLHighlighterBase : Highlighter {
    companion object {
        fun processStyles(styles: MutableList, text: String, errorClass: String): MutableMap> {
            val result: MutableMap> = mutableMapOf()
            var lastIndex = 0
            for (p in styles) {
                var attributesText = p.customAttributes.joinToString(separator = " ") { it.first + "=" + it.second }
                attributesText = if (attributesText.isNotBlank()) " $attributesText" else ""
                result.getOrPut(p.start) { mutableListOf() }.add(TextModification("", Order.BEFORE, InsertionType.STYLE))
                result.getOrPut(p.end) { mutableListOf() }.add(TextModification("", Order.AFTER, InsertionType.STYLE))
                if (p.end > lastIndex)
                    lastIndex = p.end
            }
            if (lastIndex < text.length - 1) {
                result.getOrPut(lastIndex + 1) { mutableListOf() }.add(TextModification("", Order.BEFORE, InsertionType.STYLE))
                result.getOrPut(text.length) { mutableListOf() }.add(TextModification("", Order.AFTER, InsertionType.STYLE))
            }
            return result
        }
    }
}

abstract class GrammarBasedHighlighter(val grammar: Grammar,
                                                             val styleProduction: ProductionStep,
                                                             val fullParseProduction: ProductionStep,
                                                             val parser: Parser = GenericParser(grammar)
) : HTMLHighlighterBase() {
    protected abstract fun setGrammarActions(styles: MutableList)

    override fun computeHighlighting(text: String, providedAST: ASTNode?, providedParser: GenericParser2<*>?): MutableMap> {
        val properStyles = mutableListOf()
        val partialStyles = mutableListOf()
        try {
            handleStyleProduction(partialStyles, text, providedAST)
        } catch (e: Throwable) {

        }
        try {
            handleStartProduction(properStyles, text, providedAST)
        } catch (e: Throwable) {
            //ignore errors while typing
        }
        if ((providedParser?.highestIndexParsed ?: parser.highestIndexParsed) < text.length) {
            return (processStyles(partialStyles, text, "error").combine(processStyles(properStyles, text, "error-line"))).toMutableMap()
        }
        return (processStyles(properStyles, text, "error-line")).toMutableMap()
    }

    protected open fun handleStartProduction(properStyles: MutableList, text: String, providedAST: ASTNode? = null) {
        setGrammarActions(properStyles)
        grammar.startProduction = fullParseProduction
        parser.parse(text, false)
    }

    protected open fun handleStyleProduction(partialStyles: MutableList, text: String, providedAST: ASTNode? = null) {
        setGrammarActions(partialStyles)
        grammar.startProduction = styleProduction
        parser.parse(text, false)
    }

}

//uses version 2 of the parser
abstract class GrammarBasedHighlighter2(grammar: Grammar,
                                                              styleProduction: ProductionStep,
                                                              fullParseProduction: ProductionStep,
                                                              parser: GenericParser2 = GenericParser2(grammar)
) : GrammarBasedHighlighter(grammar, styleProduction, fullParseProduction, parser) {
    private var currentASTNode: ASTNode? = null
    protected abstract fun setGrammarActions(styles: MutableList, ast: ASTNode)
    override fun setGrammarActions(styles: MutableList) {
        val astNode = currentASTNode
        if (astNode != null)
            setGrammarActions(styles, astNode)
    }

    override fun handleStartProduction(properStyles: MutableList, text: String, providedAST: ASTNode?) {
        grammar.startProduction = fullParseProduction
        val ast = providedAST ?: parser.parse(text, false)
        if (ast is ASTNode)
            setGrammarActions(properStyles, ast)
    }

    override fun handleStyleProduction(partialStyles: MutableList, text: String, providedAST: ASTNode?) {
        grammar.startProduction = styleProduction
        val ast = providedAST ?: parser.parse(text, false)
        if (ast is ASTNode)
            setGrammarActions(partialStyles, ast)
    }

}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy