commonMain.piacenti.dslmaker.dsl.Highlighter.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dsl-maker-js Show documentation
Show all versions of dsl-maker-js Show documentation
Kotlin multiplatform library to facilitate creation of DSLs with ANTLR or a simple built in parser
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