From 8230f9806dc658b349d2749a47403bb54a804c4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Przemys=C5=82aw=20Pluta?= Date: Mon, 15 Mar 2021 22:24:55 +0100 Subject: [PATCH] [Editor] Implement XML base syntax highlighting --- .../code/highlighting/XmlSyntaxHighlighter.kt | 79 +++++++++++++++++++ .../XmlSyntaxHighlightingStylesheet.kt | 53 +++++++++++++ .../editor/code/view/editor/CodeEditorView.kt | 4 +- 3 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/highlighting/XmlSyntaxHighlighter.kt create mode 100644 editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/stylesheet/XmlSyntaxHighlightingStylesheet.kt diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/highlighting/XmlSyntaxHighlighter.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/highlighting/XmlSyntaxHighlighter.kt new file mode 100644 index 00000000..975b3477 --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/highlighting/XmlSyntaxHighlighter.kt @@ -0,0 +1,79 @@ +package com.bartlomiejpluta.base.editor.code.highlighting + +import com.bartlomiejpluta.base.editor.code.stylesheet.XmlSyntaxHighlightingStylesheet +import org.fxmisc.richtext.model.StyleSpansBuilder +import org.springframework.stereotype.Component + + +@Component +class XmlSyntaxHighlighter : SyntaxHighlighter { + private val XML_TAG = + """(?(?[\w:]+)(?[^<>]*)(?\h*/?>))|(?)|(?<\?[^<>?]+?\?>)""".toRegex() + + private val ATTRIBUTES = """(?[\w:]+\h*)(?=)(?\h*"[^"]+")""".toRegex() + + override fun highlight(code: String) = StyleSpansBuilder>().let { + var lastKwEnd = 0; + + XML_TAG.findAll(code).forEach { matcher -> + it.add(emptyList(), matcher.start - lastKwEnd); + + when { + matcher.groups["PROLOG"] != null -> { + it.add(listOf("prolog"), matcher.end - matcher.start) + } + + matcher.groups["COMMENT"] != null -> { + it.add(listOf("comment"), matcher.end - matcher.start) + } + + matcher.groups["ELEMENT"] != null -> { + it.add(listOf("tagmark"), matcher.end("OPEN") - matcher.start("OPEN")) + it.add(listOf("anytag"), matcher.end("ELEM") - matcher.end("OPEN")) + + val attributesString = matcher.groups["ATTRS"]?.let(MatchGroup::value)?.takeIf(String::isNotEmpty) + val attributesStringLength = attributesString?.length ?: 0 + + if (attributesString?.isNotEmpty() == true) { + lastKwEnd = 0 + ATTRIBUTES.findAll(attributesString).forEach { attr -> + it.add(emptyList(), attr.range.first - lastKwEnd) + it.add(listOf("attribute"), attr.end("ATTR") - attr.start("ATTR")) + it.add(listOf("tagmark"), attr.end("EQ") - attr.end("ATTR")) + it.add(listOf("avalue"), attr.end("VALUE") - attr.end("EQ")) + lastKwEnd = attr.end + } + + if (attributesStringLength > lastKwEnd) { + it.add(emptyList(), attributesStringLength - lastKwEnd) + } + } + + lastKwEnd = matcher.end("ATTRS") + it.add(listOf("tagmark"), matcher.end("CLOSE") - lastKwEnd) + } + } + + lastKwEnd = matcher.end + } + + it.add(emptyList(), code.length - lastKwEnd) + + it.create() + } + + private val MatchResult.start: Int + get() = this.range.first + + private val MatchResult.end: Int + get() = this.range.last + 1 + + private fun MatchResult.start(group: Int) = this.groups[group]?.range?.first ?: 0 + private fun MatchResult.start(group: String) = this.groups[group]?.range?.first ?: 0 + + private fun MatchResult.end(group: Int) = (this.groups[group]?.range?.last ?: 0) + 1 + private fun MatchResult.end(group: String) = (this.groups[group]?.range?.last ?: 0) + 1 + + override val stylesheet = XmlSyntaxHighlightingStylesheet() +} + diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/stylesheet/XmlSyntaxHighlightingStylesheet.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/stylesheet/XmlSyntaxHighlightingStylesheet.kt new file mode 100644 index 00000000..73a9c786 --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/stylesheet/XmlSyntaxHighlightingStylesheet.kt @@ -0,0 +1,53 @@ +package com.bartlomiejpluta.base.editor.code.stylesheet + +import javafx.scene.paint.Color +import javafx.scene.text.FontPosture +import javafx.scene.text.FontWeight +import tornadofx.Stylesheet +import tornadofx.c +import tornadofx.cssclass + + +class XmlSyntaxHighlightingStylesheet : Stylesheet() { + companion object { + val prolog by cssclass() + val tagmark by cssclass() + val anytag by cssclass() + val paren by cssclass() + val attribute by cssclass() + val avalue by cssclass() + val comment by cssclass() + } + + init { + prolog { + fill = c("#BBB529") + fontStyle = FontPosture.ITALIC + } + + tagmark { + fill = Color.GRAY + } + + anytag { + fill = Color.CRIMSON + } + + paren { + fill = Color.FIREBRICK + fontWeight = FontWeight.BOLD + } + + attribute { + fill = Color.DARKVIOLET + } + + avalue { + fill = Color.BLACK + } + + comment { + fill = Color.TEAL + } + } +} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/view/editor/CodeEditorView.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/view/editor/CodeEditorView.kt index ab1dbb3a..d5c7db41 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/view/editor/CodeEditorView.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/view/editor/CodeEditorView.kt @@ -2,6 +2,7 @@ package com.bartlomiejpluta.base.editor.code.view.editor import com.bartlomiejpluta.base.editor.code.component.CodeEditor import com.bartlomiejpluta.base.editor.code.highlighting.JavaSyntaxHighlighter +import com.bartlomiejpluta.base.editor.code.highlighting.XmlSyntaxHighlighter import com.bartlomiejpluta.base.editor.code.model.CodeScope import com.bartlomiejpluta.base.editor.code.model.CodeType import com.bartlomiejpluta.base.editor.code.viewmodel.CodeVM @@ -18,13 +19,14 @@ class CodeEditorView : View() { private val projectContext: ProjectContext by di() private val javaSyntaxHighlighter: JavaSyntaxHighlighter by di() + private val xmlSyntaxHighlighter: XmlSyntaxHighlighter by di() private val codeVM = find() private val highlighter = Bindings.createObjectBinding({ when (codeVM.type!!) { CodeType.JAVA -> javaSyntaxHighlighter - CodeType.XML -> javaSyntaxHighlighter + CodeType.XML -> xmlSyntaxHighlighter } }, codeVM.typeProperty)