├── .gitignore ├── gradle.properties ├── settings.gradle.kts ├── src └── main │ ├── resources │ ├── img │ │ ├── grass.png │ │ ├── stone.png │ │ ├── water.png │ │ └── desert.png │ ├── font │ │ ├── 2_Minecraft-Italic.woff │ │ ├── 3_Minecraft-Bold.woff │ │ ├── 1_Minecraft-Regular.woff │ │ └── 4_Minecraft-BoldItalic.woff │ ├── style.css │ └── index.html │ └── kotlin │ ├── net │ └── kyori │ │ └── adventure │ │ └── text │ │ └── minimessage │ │ ├── helper │ │ ├── Key.kt │ │ ├── TextComponent.kt │ │ ├── Style.kt │ │ ├── HoverEvent.kt │ │ ├── TextColor.kt │ │ ├── TextDecoration.kt │ │ ├── ClickEvent.kt │ │ ├── Component.kt │ │ └── NamedTextColor.kt │ │ ├── markdown │ │ ├── package-info.kt │ │ ├── DiscordFlavor.kt │ │ ├── GithubFlavor.kt │ │ ├── LegacyFlavor.kt │ │ ├── MarkdownFlavor.kt │ │ └── MiniMarkdownParser.kt │ │ ├── parser │ │ ├── node │ │ │ ├── package-info.kt │ │ │ ├── RootNode.kt │ │ │ ├── TemplateNode.kt │ │ │ ├── TextNode.kt │ │ │ ├── ValueNode.kt │ │ │ ├── TagPart.kt │ │ │ ├── TagNode.kt │ │ │ └── ElementNode.kt │ │ ├── package-info.kt │ │ ├── TokenType.kt │ │ ├── Token.kt │ │ └── ParsingException.kt │ │ ├── transformation │ │ ├── package-info.kt │ │ ├── inbuild │ │ │ ├── package-info.kt │ │ │ ├── TemplateTransformation.kt │ │ │ ├── InsertionTransformation.kt │ │ │ ├── KeybindTransformation.kt │ │ │ ├── FontTransformation.kt │ │ │ ├── ClickTransformation.kt │ │ │ ├── HoverTransformation.kt │ │ │ ├── DecorationTransformation.kt │ │ │ ├── TranslatableTransformation.kt │ │ │ ├── ColorTransformation.kt │ │ │ ├── RainbowTransformation.kt │ │ │ └── GradientTransformation.kt │ │ ├── Inserting.kt │ │ ├── TransformationParser.kt │ │ ├── Modifying.kt │ │ ├── TransformationType.kt │ │ ├── Transformation.kt │ │ ├── TransformationRegistry.kt │ │ └── TransformationRegistryImpl.kt │ │ ├── package-info.kt │ │ ├── Tokens.kt │ │ ├── Template.kt │ │ ├── Context.kt │ │ ├── MiniMessageImpl.kt │ │ └── MiniMessage.kt │ └── main.kt ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .github └── workflows │ └── deploy.yml ├── README.md ├── gradlew.bat └── gradlew /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build 4 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "MiniMessageViewer" 2 | 3 | -------------------------------------------------------------------------------- /src/main/resources/img/grass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiniDigger/MiniMessageViewer/HEAD/src/main/resources/img/grass.png -------------------------------------------------------------------------------- /src/main/resources/img/stone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiniDigger/MiniMessageViewer/HEAD/src/main/resources/img/stone.png -------------------------------------------------------------------------------- /src/main/resources/img/water.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiniDigger/MiniMessageViewer/HEAD/src/main/resources/img/water.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiniDigger/MiniMessageViewer/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/resources/img/desert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiniDigger/MiniMessageViewer/HEAD/src/main/resources/img/desert.png -------------------------------------------------------------------------------- /src/main/resources/font/2_Minecraft-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiniDigger/MiniMessageViewer/HEAD/src/main/resources/font/2_Minecraft-Italic.woff -------------------------------------------------------------------------------- /src/main/resources/font/3_Minecraft-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiniDigger/MiniMessageViewer/HEAD/src/main/resources/font/3_Minecraft-Bold.woff -------------------------------------------------------------------------------- /src/main/resources/font/1_Minecraft-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiniDigger/MiniMessageViewer/HEAD/src/main/resources/font/1_Minecraft-Regular.woff -------------------------------------------------------------------------------- /src/main/resources/font/4_Minecraft-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiniDigger/MiniMessageViewer/HEAD/src/main/resources/font/4_Minecraft-BoldItalic.woff -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/helper/Key.kt: -------------------------------------------------------------------------------- 1 | package net.kyori.adventure.text.minimessage.helper 2 | 3 | class Key { 4 | 5 | companion object { 6 | fun key(fontKey: String): Key { 7 | TODO("Not yet implemented") 8 | } 9 | 10 | fun key(fontKey: String, fontKey1: String): Key { 11 | TODO("Not yet implemented") 12 | } 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/helper/TextComponent.kt: -------------------------------------------------------------------------------- 1 | package net.kyori.adventure.text.minimessage.helper 2 | 3 | class TextComponent : Component() { 4 | var content: String? = null 5 | set(value) { 6 | dom.textContent = value 7 | field = value 8 | } 9 | 10 | override fun toString(): String { 11 | return "TextComponent(content=$content) ${super.toString()}" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Build and Deploy 2 | on: 3 | push: 4 | branches: [ main ] 5 | jobs: 6 | build-and-deploy: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout 🛎️ 10 | uses: actions/checkout@v2.3.1 11 | 12 | - name: Install and Build 🔧 13 | run: ./gradlew build 14 | 15 | - name: Deploy 🚀 16 | uses: JamesIves/github-pages-deploy-action@4.1.4 17 | with: 18 | branch: gh-pages 19 | folder: build/distributions 20 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/helper/Style.kt: -------------------------------------------------------------------------------- 1 | package net.kyori.adventure.text.minimessage.helper 2 | 3 | class Style(var innerFont: Key?, var innerColor: TextColor?, var decoration: TextDecoration?) { 4 | fun font(font: Key?): Style { 5 | this.innerFont = font 6 | return this 7 | } 8 | 9 | fun color(): TextColor? { 10 | return innerColor 11 | } 12 | 13 | override fun toString(): String { 14 | return "Style(font=$innerFont, color=$innerColor, decoration=$decoration)" 15 | } 16 | 17 | companion object { 18 | fun style(): Style { 19 | return Style(null, null, null) 20 | } 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/helper/HoverEvent.kt: -------------------------------------------------------------------------------- 1 | package net.kyori.adventure.text.minimessage.helper 2 | 3 | import kotlin.random.Random 4 | import kotlinx.browser.document 5 | import kotlinx.dom.addClass 6 | import org.w3c.dom.Element 7 | 8 | open class HoverEvent(val component: Component) { 9 | fun buildOut(dom: Element) { 10 | val id = Random.nextInt(0, 100) 11 | 12 | val el = document.createElement("span") 13 | el.addClass("hover hover-$id") 14 | el.append(component.buildOutChildren()) 15 | 16 | dom.addClass("hover-source hover-source-$id") 17 | dom.append(el) 18 | } 19 | 20 | override fun toString(): String { 21 | return "HoverEvent(component=$component)" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/helper/TextColor.kt: -------------------------------------------------------------------------------- 1 | package net.kyori.adventure.text.minimessage.helper 2 | 3 | open class TextColor(val value: Int) { 4 | fun red(): Int { 5 | return this.value shr 16 and 0xff 6 | } 7 | 8 | fun green(): Int { 9 | return this.value shr 8 and 0xff 10 | } 11 | 12 | fun blue(): Int { 13 | return this.value and 0xff 14 | } 15 | 16 | fun asHexString(): String { 17 | return "#" + this.value.toString(16).padStart(6, '0') 18 | } 19 | 20 | override fun toString(): String { 21 | return "TextColor(hex=${asHexString()})" 22 | } 23 | 24 | companion object { 25 | fun fromHexString(name: String): TextColor? { 26 | return if (name.startsWith("#")) { 27 | TextColor(name.substring(1).toInt(16)) 28 | } else { 29 | null 30 | } 31 | } 32 | 33 | fun color(r: Int, g: Int, b: Int): TextColor { 34 | return TextColor(r and 0xff shl 16 or (g and 0xff shl 8) or (b and 0xff)) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/helper/TextDecoration.kt: -------------------------------------------------------------------------------- 1 | package net.kyori.adventure.text.minimessage.helper 2 | 3 | enum class TextDecoration(val myName: String) { 4 | 5 | /** 6 | * A decoration which makes text obfuscated/unreadable. 7 | * 8 | * @since 4.0.0 9 | */ 10 | OBFUSCATED("obfuscated"), 11 | /** 12 | * A decoration which makes text appear bold. 13 | * 14 | * @since 4.0.0 15 | */ 16 | BOLD("bold"), 17 | /** 18 | * A decoration which makes text have a strike through it. 19 | * 20 | * @since 4.0.0 21 | */ 22 | STRIKETHROUGH("strikethrough"), 23 | /** 24 | * A decoration which makes text have an underline. 25 | * 26 | * @since 4.0.0 27 | */ 28 | UNDERLINED("underlined"), 29 | /** 30 | * A decoration which makes text appear in italics. 31 | * 32 | * @since 4.0.0 33 | */ 34 | ITALIC("italic"); 35 | 36 | companion object { 37 | val NAMES: Map = values().associateBy { it.myName } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/markdown/package-info.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | /** 25 | * Markdown. 26 | */ 27 | package net.kyori.adventure.text.minimessage.markdown 28 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/parser/node/package-info.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | /** 25 | * Parser nodes. 26 | */ 27 | package net.kyori.adventure.text.minimessage.parser.node 28 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/transformation/package-info.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | /** 25 | * Transformations. 26 | */ 27 | package net.kyori.adventure.text.minimessage.transformation 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MiniMessage Viewer 2 | 3 | > It's cursed 4 | 5 | **in fact, its so cursed that its dead now, a much better version can be found [here](https://github.com/KyoriPowered/adventure-webui).** 6 | 7 | A hacked together web based editor/viewer for MiniMessage. 8 | 9 | --> **[Access it here](https://minidigger.github.io/MiniMessageViewer/)** <-- 10 | 11 | This was created by copy-pasting all code from MiniMessage's new parser into this project, telling IntelliJ to convert it to Kotlin, 12 | ripping out Adventure and replacing it with DOM calls, hacking till it compiles (**I don't know kotlin nor do I like it**) and throwing it on GitHub. 13 | 14 | ## Status 15 | 16 | I will most likely not spend much time on this project. You can see a list of stuff I should do here: https://github.com/MiniDigger/MiniMessageViewer/issues/1 17 | No gurantee that I will actually do that tho. 18 | Contributions are welcome tho! 19 | 20 | ## Dev Setup 21 | 22 | `` 23 | gradlew browserDevelopmentRun --continuous 24 | `` 25 | 26 | then you can just edit the kotlin code and it will auto rebuild and reload 27 | 28 | ## Licence 29 | 30 | no. this code is cursed, don't look at it, don't use it, just use the website. 31 | 32 | ## Credits 33 | 34 | Font is from here: https://fonts2u.com/minecraft-regular.font 35 | You can find the real MiniMessage project here: https://github.com/KyoriPowered/adventure-text-minimessage 36 | Blame Noxite for the idea: https://i.imgur.com/pmyoW0D.png 37 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/package-info.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | /** 25 | * MiniMessage. 26 | */ 27 | package net.kyori.adventure.text.minimessage 28 | 29 | import net.kyori.adventure.text.minimessage.MiniMessageImpl.BuilderImpl 30 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/parser/package-info.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | /** 25 | * Parser. 26 | */ 27 | package net.kyori.adventure.text.minimessage.parser 28 | 29 | import net.kyori.adventure.text.minimessage.MiniMessageImpl.BuilderImpl 30 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/parser/TokenType.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.parser 25 | 26 | /** 27 | * Represents the type of a token. 28 | * 29 | * @since 4.2.0 30 | */ 31 | enum class TokenType { 32 | TEXT, OPEN_TAG, CLOSE_TAG, TAG_VALUE 33 | } 34 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/transformation/inbuild/package-info.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | /** 25 | * Standard transformations. 26 | */ 27 | package net.kyori.adventure.text.minimessage.transformation.inbuild 28 | 29 | import net.kyori.adventure.text.minimessage.MiniMessageImpl.BuilderImpl 30 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/transformation/Inserting.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.transformation 25 | 26 | /** 27 | * Marker interface for transformations that insert text or components, but have no children. 28 | * 29 | * @since 4.2.0 30 | */ 31 | interface Inserting 32 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/parser/node/RootNode.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.parser.node 25 | 26 | /** 27 | * Represents the root node of a tree. 28 | * 29 | * @since 4.2.0 30 | */ 31 | class RootNode 32 | /** 33 | * Creates a new root node. 34 | * 35 | * @param sourceMessage the source message 36 | * @since 4.2.0 37 | */ 38 | (sourceMessage: String) : ElementNode(null, null, sourceMessage) 39 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/transformation/TransformationParser.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.transformation 25 | 26 | /** 27 | * A supplier of new transformation instances. 28 | * 29 | * @param the transformation type 30 | * @since 4.1.0 31 | */ 32 | interface TransformationParser { 33 | /** 34 | * Create a new instance of the transformation. 35 | * 36 | * @return the new instance 37 | * @since 4.1.0 38 | */ 39 | fun parse(): T 40 | } 41 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/helper/ClickEvent.kt: -------------------------------------------------------------------------------- 1 | package net.kyori.adventure.text.minimessage.helper 2 | 3 | import kotlin.random.Random 4 | import kotlinx.browser.document 5 | import kotlinx.dom.addClass 6 | import org.w3c.dom.Element 7 | import org.w3c.dom.css.CSS.Companion.escape 8 | 9 | class ClickEvent(val action: Action, val value: String) { 10 | 11 | fun buildOut(dom: Element) { 12 | val id = Random.nextInt(0, 100) 13 | 14 | val el = document.createElement("span") 15 | el.addClass("click hover hover-$id") 16 | el.innerHTML = "Action: ${action.name}, Value: ${escape(value)}" 17 | 18 | dom.addClass("click-source hover-source hover-source-$id") 19 | dom.append(el) 20 | } 21 | 22 | override fun toString(): String { 23 | return "ClickEvent(action=$action, value='$value')" 24 | } 25 | 26 | enum class Action(val myName: String, val readable: Boolean) { 27 | 28 | /** 29 | * Opens a url when clicked. 30 | * 31 | * @since 4.0.0 32 | */ 33 | OPEN_URL("open_url", true), 34 | /** 35 | * Opens a file when clicked. 36 | * 37 | *

This action is not readable, and may only be used locally on the client.

38 | * 39 | * @since 4.0.0 40 | */ 41 | OPEN_FILE("open_file", false), 42 | /** 43 | * Runs a command when clicked. 44 | * 45 | * @since 4.0.0 46 | */ 47 | RUN_COMMAND("run_command", true), 48 | /** 49 | * Suggests a command into the chat box. 50 | * 51 | * @since 4.0.0 52 | */ 53 | SUGGEST_COMMAND("suggest_command", true), 54 | /** 55 | * Changes the page of a book. 56 | * 57 | * @since 4.0.0 58 | */ 59 | CHANGE_PAGE("change_page", true), 60 | /** 61 | * Copies text to the clipboard. 62 | * 63 | * @since 4.0.0 64 | * @sinceMinecraft 1.15 65 | */ 66 | COPY_TO_CLIPBOARD("copy_to_clipboard", true); 67 | 68 | companion object { 69 | val NAMES: Map = values().associateBy { it.myName } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/parser/node/TemplateNode.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.parser.node 25 | 26 | import net.kyori.adventure.text.minimessage.parser.Token 27 | 28 | /** 29 | * Represents a template replacement in a string. 30 | * 31 | * @since 4.2.0 32 | */ 33 | class TemplateNode 34 | /** 35 | * Creates a new element node. 36 | * 37 | * @param parent the parent of this node 38 | * @param token the token that created this node 39 | * @param sourceMessage the source message 40 | * @since 4.2.0 41 | */ 42 | ( 43 | parent: ElementNode?, 44 | token: Token?, 45 | sourceMessage: String, 46 | actualValue: String 47 | ) : ValueNode(parent, token, sourceMessage, actualValue) { 48 | 49 | override fun valueName(): String { 50 | return "TemplateNode" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/parser/node/TextNode.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.parser.node 25 | 26 | import net.kyori.adventure.text.minimessage.parser.Token 27 | import net.kyori.adventure.text.minimessage.parser.TokenParser 28 | 29 | /** 30 | * Represents a string of chars. 31 | * 32 | * @since 4.2.0 33 | */ 34 | class TextNode 35 | /** 36 | * Creates a new text node. 37 | * 38 | * @param parent the parent of this node 39 | * @param token the token that created this node 40 | * @param sourceMessage the source message 41 | * @since 4.2.0 42 | */ 43 | ( 44 | parent: ElementNode?, 45 | token: Token, 46 | sourceMessage: String 47 | ) : ValueNode(parent, token, sourceMessage, TokenParser.unescape(sourceMessage, token.startIndex(), token.endIndex())) { 48 | 49 | override fun valueName(): String { 50 | return "TextNode" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/transformation/Modifying.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.transformation 25 | 26 | import net.kyori.adventure.text.minimessage.helper.Component 27 | import net.kyori.adventure.text.minimessage.parser.node.ElementNode 28 | 29 | /** 30 | * Transformations implementing this interface can transform a whole subtree of nodes. 31 | * 32 | * @since 4.2.0 33 | */ 34 | interface Modifying { 35 | /** 36 | * This method gets called once for every element in the sub tree, allowing you to do calculations beforehand. 37 | * 38 | * @param curr the current element in the sub tree 39 | * @since 4.2.0 40 | */ 41 | fun visit(curr: ElementNode?) 42 | 43 | /** 44 | * Applies this transformation for the current component. 45 | * This gets called after the component tree has been assembled, but you are free to modify it however you like. 46 | * 47 | * @param curr the current component 48 | * @param depth the depth of the tree the current component is at 49 | * @return the new parent 50 | * @since 4.2.0 51 | */ 52 | fun apply(curr: Component, depth: Int): Component? 53 | } 54 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/markdown/DiscordFlavor.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.markdown 25 | 26 | /** 27 | * The discord flavour of markdown. 28 | * 29 | * @since 4.1.0 30 | */ 31 | class DiscordFlavor private constructor() : MarkdownFlavor { 32 | 33 | override fun isBold(current: Char, next: Char): Boolean { 34 | return current == '*' && next == current 35 | } 36 | 37 | override fun isItalic(current: Char, next: Char): Boolean { 38 | return current == '*' && next != current 39 | } 40 | 41 | override fun isUnderline(current: Char, next: Char): Boolean { 42 | return current == '_' && next == current 43 | } 44 | 45 | override fun isStrikeThrough(current: Char, next: Char): Boolean { 46 | return current == '~' && next == current 47 | } 48 | 49 | override fun isObfuscate(current: Char, next: Char): Boolean { 50 | return current == '|' && next == current 51 | } 52 | 53 | companion object { 54 | private val INSTANCE = DiscordFlavor() 55 | 56 | /** 57 | * Get an instance of discord-flavoured Markdown. 58 | * 59 | * @return an instance 60 | * @since 4.1.0 61 | */ 62 | fun get(): MarkdownFlavor { 63 | return INSTANCE 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/markdown/GithubFlavor.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.markdown 25 | 26 | /** 27 | * An implementation of supported elements of *GitHub-Flavored Markdown*. 28 | * 29 | * @since 4.1.0 30 | */ 31 | class GithubFlavor private constructor() : MarkdownFlavor { 32 | 33 | override fun isBold(current: Char, next: Char): Boolean { 34 | return current == '*' && next == current || current == '_' && next == current 35 | } 36 | 37 | override fun isItalic(current: Char, next: Char): Boolean { 38 | return current == '*' && next != current || current == '_' && next != current 39 | } 40 | 41 | override fun isUnderline(current: Char, next: Char): Boolean { 42 | return false 43 | } 44 | 45 | override fun isStrikeThrough(current: Char, next: Char): Boolean { 46 | return current == '~' && next == current 47 | } 48 | 49 | override fun isObfuscate(current: Char, next: Char): Boolean { 50 | return false 51 | } 52 | 53 | companion object { 54 | private val INSTANCE = GithubFlavor() 55 | 56 | /** 57 | * Get an instance of this markdown flavour. 58 | * 59 | * @return the flavour instance 60 | * @since 4.1.0 61 | */ 62 | fun get(): MarkdownFlavor { 63 | return INSTANCE 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/parser/node/ValueNode.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.parser.node 25 | 26 | import net.kyori.adventure.text.minimessage.parser.Token 27 | 28 | /** 29 | * Represents a node in the tree which has a text value. 30 | * 31 | * @since 4.2.0 32 | */ 33 | abstract class ValueNode 34 | /** 35 | * Creates a new element node. 36 | * 37 | * @param parent the parent of this node 38 | * @param token the token that created this node 39 | * @param sourceMessage the source message 40 | * @since 4.2.0 41 | */ internal constructor(parent: ElementNode?, token: Token?, sourceMessage: String, private val value: String) : ElementNode(parent, token, sourceMessage) { 42 | abstract fun valueName(): String? 43 | 44 | /** 45 | * Returns the value of this text node. 46 | * 47 | * @return the value 48 | * @since 4.2.0 49 | */ 50 | fun value(): String { 51 | return value 52 | } 53 | 54 | override fun token(): Token { 55 | return requireNotNull(super.token()) { "token is not set" } 56 | } 57 | 58 | override fun buildToString(sb: StringBuilder, indent: Int): StringBuilder { 59 | val `in`: CharArray = this.ident(indent) 60 | sb.append(`in`).append(valueName()).append("('").append(value).append("')\n") 61 | return sb 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/markdown/LegacyFlavor.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.markdown 25 | 26 | /** 27 | * MiniMessage's original markdown flavour. 28 | * 29 | * @since 4.1.0 30 | */ 31 | @Deprecated( 32 | """The legacy flavor never made any sense, don't use 33 | """ 34 | ) 35 | class LegacyFlavor private constructor() : MarkdownFlavor { 36 | 37 | override fun isBold(current: Char, next: Char): Boolean { 38 | return current == '*' && next == current || current == '_' && next == current 39 | } 40 | 41 | override fun isItalic(current: Char, next: Char): Boolean { 42 | return current == '*' && next != current || current == '_' && next != current 43 | } 44 | 45 | override fun isUnderline(current: Char, next: Char): Boolean { 46 | return current == '~' && next == current 47 | } 48 | 49 | override fun isStrikeThrough(current: Char, next: Char): Boolean { 50 | return false 51 | } 52 | 53 | override fun isObfuscate(current: Char, next: Char): Boolean { 54 | return current == '|' && next == current 55 | } 56 | 57 | companion object { 58 | private val INSTANCE = LegacyFlavor() 59 | 60 | /** 61 | * Get an instance of the legacy markdown flavour. 62 | * 63 | * @return the flavour instance 64 | * @since 4.1.0 65 | */ 66 | fun get(): MarkdownFlavor { 67 | return INSTANCE 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/Tokens.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage 25 | 26 | import net.kyori.adventure.text.minimessage.MiniMessageImpl.BuilderImpl 27 | 28 | /** 29 | * Tokens used in the MiniMessage format. 30 | * 31 | * @since 4.0.0 32 | */ 33 | object Tokens { 34 | // vanilla components 35 | const val CLICK = "click" 36 | const val HOVER = "hover" 37 | const val KEYBIND = "key" 38 | const val TRANSLATABLE = "lang" 39 | const val TRANSLATABLE_2 = "translate" 40 | const val TRANSLATABLE_3 = "tr" 41 | const val INSERTION = "insert" 42 | const val COLOR = "color" 43 | const val COLOR_2 = "colour" 44 | const val COLOR_3 = "c" 45 | const val HEX = "#" 46 | const val FONT = "font" 47 | 48 | // vanilla decoration 49 | const val UNDERLINED = "underlined" 50 | const val UNDERLINED_2 = "u" 51 | const val STRIKETHROUGH = "strikethrough" 52 | const val STRIKETHROUGH_2 = "st" 53 | const val OBFUSCATED = "obfuscated" 54 | const val OBFUSCATED_2 = "obf" 55 | const val ITALIC = "italic" 56 | const val ITALIC_2 = "em" 57 | const val ITALIC_3 = "i" 58 | const val BOLD = "bold" 59 | const val BOLD_2 = "b" 60 | const val RESET = "reset" 61 | const val RESET_2 = "r" 62 | const val PRE = "pre" 63 | 64 | // minimessage components 65 | const val RAINBOW = "rainbow" 66 | const val GRADIENT = "gradient" 67 | 68 | // minimessage tags 69 | const val TAG_START = "<" 70 | const val TAG_END = ">" 71 | const val CLOSE_TAG = "/" 72 | const val SEPARATOR = ":" 73 | } 74 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/transformation/inbuild/TemplateTransformation.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.transformation.inbuild 25 | 26 | import net.kyori.adventure.text.minimessage.Template 27 | import net.kyori.adventure.text.minimessage.helper.Component 28 | import net.kyori.adventure.text.minimessage.transformation.Inserting 29 | import net.kyori.adventure.text.minimessage.transformation.Transformation 30 | 31 | /** 32 | * Inserts a formatted template component into the result. 33 | * 34 | * @since 4.1.0 35 | */ 36 | class TemplateTransformation(template: Template.ComponentTemplate) : Transformation(), Inserting { 37 | private val template: Template.ComponentTemplate 38 | 39 | override fun apply(): Component { 40 | return template.value() 41 | } 42 | override fun toString(): String { 43 | return "TemplateTransformation(template=$template)" 44 | } 45 | 46 | override fun equals(o: Any?): Boolean { 47 | if(this === o) return true 48 | if(o == null || this::class.js != o::class.js) return false 49 | if(!super.equals(o)) return false 50 | 51 | o as TemplateTransformation 52 | 53 | if(template != o.template) return false 54 | 55 | return true 56 | } 57 | 58 | override fun hashCode(): Int { 59 | var result = super.hashCode() 60 | result = 31 * result + template.hashCode() 61 | return result 62 | } 63 | 64 | /** 65 | * Create a new template transformation applying `template`. 66 | * 67 | * @param template the template to apply 68 | * @since 4.1.0 69 | */ 70 | init { 71 | this.template = template 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/parser/Token.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.parser 25 | 26 | /** 27 | * Represents a token for the lexer. 28 | * 29 | * @since 4.2.0 30 | */ 31 | class Token(private val startIndex: Int, private val endIndex: Int, type: TokenType) { 32 | private val type: TokenType 33 | private var childTokens: MutableList? = null 34 | 35 | /** 36 | * Returns the start index of this token. 37 | * 38 | * @return the start index 39 | * @since 4.2.0 40 | */ 41 | fun startIndex(): Int { 42 | return startIndex 43 | } 44 | 45 | /** 46 | * Returns the end index of this token. 47 | * 48 | * @return the end index 49 | * @since 4.2.0 50 | */ 51 | fun endIndex(): Int { 52 | return endIndex 53 | } 54 | 55 | /** 56 | * Returns the type of this token. 57 | * 58 | * @return the type 59 | * @since 4.2.0 60 | */ 61 | fun type(): TokenType { 62 | return type 63 | } 64 | 65 | /** 66 | * Returns the children of this token. 67 | * 68 | * @return the child tokens 69 | * @since 4.2.0 70 | */ 71 | fun childTokens(): MutableList? { 72 | return childTokens 73 | } 74 | 75 | /** 76 | * Sets the children of this token. 77 | * 78 | * @param childTokens the new children 79 | * @since 4.2.0 80 | */ 81 | fun childTokens(childTokens: MutableList?) { 82 | this.childTokens = childTokens 83 | } 84 | 85 | override fun toString(): String { 86 | return "Token(startIndex=$startIndex, endIndex=$endIndex, type=$type, childTokens=$childTokens)" 87 | } 88 | 89 | /** 90 | * Creates a new token. 91 | * 92 | * @param startIndex the start index of the token 93 | * @param endIndex the end index of the token 94 | * @param type the type of the token 95 | * @since 4.2.0 96 | */ 97 | init { 98 | this.type = type 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/markdown/MarkdownFlavor.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.markdown 25 | 26 | /** 27 | * A type of markdown. 28 | * 29 | * @since 4.1.0 30 | */ 31 | interface MarkdownFlavor { 32 | /** 33 | * Whether a pair of format characters indicate bolding. 34 | * 35 | * @param current the character being inspected 36 | * @param next the next character 37 | * @return whether the characters delimit a bold block 38 | * @since 4.1.0 39 | */ 40 | fun isBold(current: Char, next: Char): Boolean 41 | 42 | /** 43 | * Whether a pair of format characters indicate italics. 44 | * 45 | * @param current the character being inspected 46 | * @param next the next character 47 | * @return whether the characters delimit an italics block 48 | * @since 4.1.0 49 | */ 50 | fun isItalic(current: Char, next: Char): Boolean 51 | 52 | /** 53 | * Whether a pair of format characters indicate an underline. 54 | * 55 | * @param current the character being inspected 56 | * @param next the next character 57 | * @return whether the characters delimit an underlined block 58 | * @since 4.1.0 59 | */ 60 | fun isUnderline(current: Char, next: Char): Boolean 61 | 62 | /** 63 | * Whether a pair of format characters indicate a strikethrough. 64 | * 65 | * @param current the character being inspected 66 | * @param next the next character 67 | * @return whether the characters delimit a strikethrough block 68 | * @since 4.1.0 69 | */ 70 | fun isStrikeThrough(current: Char, next: Char): Boolean 71 | 72 | /** 73 | * Whether a pair of format characters indicate an obfuscated block. 74 | * 75 | * 76 | * These may also be described as spoiler blocks. 77 | * 78 | * @param current the character being inspected 79 | * @param next the next character 80 | * @return whether the characters delimit an obfuscated block 81 | * @since 4.1.0 82 | */ 83 | fun isObfuscate(current: Char, next: Char): Boolean 84 | 85 | companion object { 86 | /** 87 | * Get the default markdown flavour. 88 | * 89 | * 90 | * This is currently the [LegacyFlavor] for backwards compatibility, 91 | * but will be changed to [in the near future][DiscordFlavor]. 92 | * 93 | * @return the default flavour 94 | * @since 4.1.0 95 | */ 96 | fun defaultFlavor(): MarkdownFlavor { 97 | return LegacyFlavor.get() // TODO: change the default to DiscordFlavor in a few releases 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/transformation/inbuild/InsertionTransformation.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.transformation.inbuild 25 | 26 | import net.kyori.adventure.text.minimessage.Tokens 27 | import net.kyori.adventure.text.minimessage.helper.Component 28 | import net.kyori.adventure.text.minimessage.parser.ParsingException 29 | import net.kyori.adventure.text.minimessage.parser.node.TagPart 30 | import net.kyori.adventure.text.minimessage.transformation.Transformation 31 | import net.kyori.adventure.text.minimessage.transformation.TransformationParser 32 | 33 | /** 34 | * A transformation that applies an insertion (shift-click) event. 35 | * 36 | * @since 4.1.0 37 | */ 38 | class InsertionTransformation private constructor() : Transformation() { 39 | private var insertion: String = "" 40 | 41 | override fun load(name: String, args: List) { 42 | super.load(name, args) 43 | if(args.size == 1) { 44 | insertion = args[0].value() 45 | } else { 46 | throw ParsingException("Doesn't know how to turn token with name '$name' and arguments $args into a insertion component", *this.argTokenArray()) 47 | } 48 | } 49 | 50 | override fun apply(): Component { 51 | val component = Component.empty() 52 | component.insertion = insertion 53 | return component 54 | } 55 | 56 | override fun toString(): String { 57 | return "InsertionTransformation(insertion=$insertion)" 58 | } 59 | 60 | override fun equals(o: Any?): Boolean { 61 | if(this === o) return true 62 | if(o == null || this::class.js != o::class.js) return false 63 | 64 | o as InsertionTransformation 65 | 66 | if(insertion != o.insertion) return false 67 | 68 | return true 69 | } 70 | 71 | override fun hashCode(): Int { 72 | var result = 42 73 | result = 31 * result + insertion.hashCode() 74 | return result 75 | } 76 | 77 | /** 78 | * Factory for [InsertionTransformation] instances. 79 | * 80 | * @since 4.1.0 81 | */ 82 | class Parser : TransformationParser { 83 | 84 | override fun parse(): InsertionTransformation { 85 | return InsertionTransformation() 86 | } 87 | } 88 | 89 | companion object { 90 | /** 91 | * Get if this transformation can handle the provided tag name. 92 | * 93 | * @param name tag name to test 94 | * @return if this transformation is applicable 95 | * @since 4.1.0 96 | */ 97 | fun canParse(name: String): Boolean { 98 | return name.equals(Tokens.INSERTION, true) 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/transformation/inbuild/KeybindTransformation.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.transformation.inbuild 25 | 26 | import net.kyori.adventure.text.minimessage.Tokens 27 | import net.kyori.adventure.text.minimessage.helper.Component 28 | import net.kyori.adventure.text.minimessage.parser.ParsingException 29 | import net.kyori.adventure.text.minimessage.parser.node.TagPart 30 | import net.kyori.adventure.text.minimessage.transformation.Inserting 31 | import net.kyori.adventure.text.minimessage.transformation.Transformation 32 | import net.kyori.adventure.text.minimessage.transformation.TransformationParser 33 | 34 | /** 35 | * A transformation that inserts a key binding component. 36 | * 37 | * @since 4.1.0 38 | */ 39 | class KeybindTransformation private constructor() : Transformation(), Inserting { 40 | private var keybind: String = "" 41 | 42 | override fun load(name: String, args: List) { 43 | super.load(name, args) 44 | if(args.size == 1) { 45 | keybind = args[0].value() 46 | } else { 47 | throw ParsingException("Doesn't know how to turn token with name '$name' and arguments $args into a keybind component", *this.argTokenArray()) 48 | } 49 | } 50 | 51 | override fun apply(): Component { 52 | return Component.keybind(keybind) 53 | } 54 | 55 | override fun toString(): String { 56 | return "KeybindTransformation(keybind=$keybind)" 57 | } 58 | 59 | override fun equals(o: Any?): Boolean { 60 | if(this === o) return true 61 | if(o == null || this::class.js != o::class.js) return false 62 | if(!super.equals(o)) return false 63 | 64 | o as KeybindTransformation 65 | 66 | if(keybind != o.keybind) return false 67 | 68 | return true 69 | } 70 | 71 | override fun hashCode(): Int { 72 | var result = super.hashCode() 73 | result = 31 * result + keybind.hashCode() 74 | return result 75 | } 76 | 77 | /** 78 | * Factory for [KeybindTransformation] instances. 79 | * 80 | * @since 4.1.0 81 | */ 82 | class Parser : TransformationParser { 83 | 84 | override fun parse(): KeybindTransformation { 85 | return KeybindTransformation() 86 | } 87 | } 88 | 89 | companion object { 90 | /** 91 | * Get if this transformation can handle the provided tag name. 92 | * 93 | * @param name tag name to test 94 | * @return if this transformation is applicable 95 | * @since 4.1.0 96 | */ 97 | fun canParse(name: String): Boolean { 98 | return name.equals(Tokens.KEYBIND, true) 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/transformation/inbuild/FontTransformation.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.transformation.inbuild 25 | 26 | import net.kyori.adventure.text.minimessage.Tokens 27 | import net.kyori.adventure.text.minimessage.helper.Component 28 | import net.kyori.adventure.text.minimessage.helper.Key 29 | import net.kyori.adventure.text.minimessage.helper.Style 30 | import net.kyori.adventure.text.minimessage.parser.ParsingException 31 | import net.kyori.adventure.text.minimessage.parser.node.TagPart 32 | import net.kyori.adventure.text.minimessage.transformation.Transformation 33 | import net.kyori.adventure.text.minimessage.transformation.TransformationParser 34 | 35 | /** 36 | * A decoration that applies a font name. 37 | * 38 | * @since 4.1.0 39 | */ 40 | class FontTransformation private constructor() : Transformation() { 41 | private var font: Key? = null 42 | 43 | override fun load(name: String, args: List) { 44 | super.load(name, args) 45 | if(args.size == 1) { 46 | val fontKey: String = args[0].value() 47 | font = Key.key(fontKey) 48 | } 49 | if(args.size != 2) { 50 | throw ParsingException("Doesn't know how to turn $args into a click event", *this.argTokenArray()) 51 | } 52 | val namespaceKey: String = args[0].value() 53 | val fontKey: String = args[1].value() 54 | font = Key.key(namespaceKey, fontKey) 55 | } 56 | 57 | override fun apply(): Component { 58 | return Component.empty().style(Style.style().font(font)) 59 | } 60 | 61 | override fun toString(): String { 62 | return "FontTransformation(font=$font)" 63 | } 64 | 65 | override fun equals(o: Any?): Boolean { 66 | if(this === o) return true 67 | if(o == null || this::class.js != o::class.js) return false 68 | 69 | o as FontTransformation 70 | 71 | if(font != o.font) return false 72 | 73 | return true 74 | } 75 | 76 | override fun hashCode(): Int { 77 | var result = 42 78 | result = 31 * result + (font.hashCode() ?: 0) 79 | return result 80 | } 81 | 82 | /** 83 | * Factory for [FontTransformation] instances. 84 | * 85 | * @since 4.1.0 86 | */ 87 | class Parser : TransformationParser { 88 | 89 | override fun parse(): FontTransformation { 90 | return FontTransformation() 91 | } 92 | } 93 | 94 | companion object { 95 | /** 96 | * Get if this transformation can handle the provided tag name. 97 | * 98 | * @param name tag name to test 99 | * @return if this transformation is applicable 100 | * @since 4.1.0 101 | */ 102 | fun canParse(name: String): Boolean { 103 | return name.equals(Tokens.FONT, true) 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/parser/node/TagPart.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.parser.node 25 | 26 | import net.kyori.adventure.text.minimessage.Template 27 | import net.kyori.adventure.text.minimessage.parser.Token 28 | import net.kyori.adventure.text.minimessage.parser.TokenParser 29 | 30 | /** 31 | * Represents an inner part of a tag. 32 | * 33 | * @since 4.2.0 34 | */ 35 | class TagPart( 36 | sourceMessage: String, 37 | token: Token, 38 | templates: Map 39 | ) { 40 | private val value: String 41 | private val token: Token 42 | 43 | /** 44 | * Returns the value of this tag part. 45 | * 46 | * @return the value 47 | * @since 4.2.0 48 | */ 49 | fun value(): String { 50 | return value 51 | } 52 | 53 | /** 54 | * Returns the token that created this tag part. 55 | * 56 | * @return the token 57 | * @since 4.2.0 58 | */ 59 | fun token(): Token { 60 | return token 61 | } 62 | 63 | override fun toString(): String { 64 | return value 65 | } 66 | 67 | companion object { 68 | private fun isTag(text: String): Boolean { 69 | return text[0] == '<' || text[text.length - 1] == '>' 70 | } 71 | 72 | /** 73 | * Removes leading/trailing quotes from the given string, if necessary, and removes escaping `'\'` characters. 74 | * 75 | * @param text the input text 76 | * @param start the starting index of the substring 77 | * @param end the ending index of the substring 78 | * @return the output substring 79 | * @since 4.2.0 80 | */ 81 | fun unquoteAndEscape(text: String, start: Int, end: Int): String { 82 | if(start == end) { 83 | return "" 84 | } 85 | var startIndex = start 86 | var endIndex = end 87 | val firstChar: Char = text[startIndex] 88 | val lastChar: Char = text[endIndex - 1] 89 | if(firstChar == '\'' || firstChar == '"') { 90 | startIndex++ 91 | } 92 | if(lastChar == '\'' || lastChar == '"') { 93 | endIndex-- 94 | } 95 | return TokenParser.unescape(text, startIndex, endIndex) 96 | } 97 | } 98 | 99 | /** 100 | * Constructs a new tag part. 101 | * 102 | * @param sourceMessage the source message 103 | * @param token the token that creates this tag part 104 | * @since 4.2.0 105 | */ 106 | init { 107 | var v = unquoteAndEscape(sourceMessage, token.startIndex(), token.endIndex()) 108 | if(isTag(v)) { 109 | val text = v.substring(1, v.length - 1) 110 | val template: Template? = templates[text] 111 | if(template is Template.StringTemplate) { 112 | v = template.value() 113 | } 114 | } 115 | value = v 116 | this.token = token 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/transformation/inbuild/ClickTransformation.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.transformation.inbuild 25 | 26 | import net.kyori.adventure.text.minimessage.Tokens 27 | import net.kyori.adventure.text.minimessage.helper.ClickEvent 28 | import net.kyori.adventure.text.minimessage.helper.Component 29 | import net.kyori.adventure.text.minimessage.parser.ParsingException 30 | import net.kyori.adventure.text.minimessage.parser.node.TagPart 31 | import net.kyori.adventure.text.minimessage.transformation.Transformation 32 | import net.kyori.adventure.text.minimessage.transformation.TransformationParser 33 | 34 | /** 35 | * A transformation applying a click event. 36 | * 37 | * @since 4.1.0 38 | */ 39 | class ClickTransformation private constructor() : Transformation() { 40 | private var action: ClickEvent.Action? = null 41 | private var value: String? = null 42 | 43 | override fun load(name: String, args: List) { 44 | super.load(name, args) 45 | if(args.size == 2) { 46 | action = ClickEvent.Action.NAMES[args[0].value().lowercase()] 47 | value = args[1].value() 48 | } else { 49 | throw ParsingException("Don't know how to turn $args into a click event", *this.argTokenArray()) 50 | } 51 | } 52 | 53 | override fun apply(): Component { 54 | val comp = Component.empty() 55 | comp.clickEvent = ClickEvent(action!!, value!!) 56 | return comp 57 | } 58 | 59 | override fun toString(): String { 60 | return "ClickTransformation(action=$action, value=$value)" 61 | } 62 | 63 | override fun equals(o: Any?): Boolean { 64 | if(this === o) return true 65 | if(o == null || this::class.js != o::class.js) return false 66 | 67 | o as ClickTransformation 68 | 69 | if(action != o.action) return false 70 | if(value != o.value) return false 71 | 72 | return true 73 | } 74 | 75 | override fun hashCode(): Int { 76 | var result = 31 77 | result = 31 * result + (action.hashCode() ?: 0) 78 | result = 31 * result + (value?.hashCode() ?: 0) 79 | return result 80 | } 81 | 82 | /** 83 | * Factory for [ClickTransformation] instances. 84 | * 85 | * @since 4.1.0 86 | */ 87 | class Parser : TransformationParser { 88 | 89 | override fun parse(): ClickTransformation { 90 | return ClickTransformation() 91 | } 92 | } 93 | 94 | companion object { 95 | /** 96 | * Get if this transformation can handle the provided tag name. 97 | * 98 | * @param name tag name to test 99 | * @return if this transformation is applicable 100 | * @since 4.1.0 101 | */ 102 | fun canParse(name: String): Boolean { 103 | return name.equals(Tokens.CLICK, true) 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/helper/Component.kt: -------------------------------------------------------------------------------- 1 | package net.kyori.adventure.text.minimessage.helper 2 | 3 | import kotlin.random.Random 4 | import kotlinx.browser.document 5 | import kotlinx.dom.addClass 6 | import kotlinx.dom.removeClass 7 | import org.w3c.dom.Element 8 | import org.w3c.dom.HTMLElement 9 | import org.w3c.dom.css.CSS.Companion.escape 10 | 11 | open class Component { 12 | 13 | val dom = document.createElement("span") as HTMLElement 14 | private val childs: MutableList = mutableListOf() 15 | private val style: Style = Style.style() 16 | var hoverEvent: HoverEvent? = null 17 | var clickEvent: ClickEvent? = null 18 | var insertion: String? = null 19 | 20 | fun buildOutChildren(): Element { 21 | childs.forEach { dom.append(it.buildOutChildren()) } 22 | hoverEvent?.buildOut(dom) 23 | clickEvent?.buildOut(dom) 24 | insertion?.let { 25 | buildOutInsertion() 26 | } 27 | return dom 28 | } 29 | 30 | private fun buildOutInsertion() { 31 | val id = Random.nextInt(0, 100) 32 | 33 | val el = document.createElement("span") 34 | el.addClass("click hover hover-$id") 35 | el.innerHTML = "Insertion: ${escape(insertion ?: "")}" 36 | 37 | dom.addClass("click-source hover-source hover-source-$id") 38 | dom.append(el) 39 | } 40 | 41 | fun append(child: Component): Component { 42 | childs.add(child) 43 | return this 44 | } 45 | 46 | fun children(): List { 47 | return childs 48 | } 49 | 50 | fun children(children: List): Component { 51 | childs.clear() 52 | childs.addAll(children) 53 | return this 54 | } 55 | 56 | fun decorate(decoration: TextDecoration?): Component { 57 | style.decoration = decoration 58 | when(decoration) { 59 | TextDecoration.OBFUSCATED -> dom.addClass("obfuscated") 60 | TextDecoration.BOLD -> dom.style.fontWeight = "bold" 61 | TextDecoration.STRIKETHROUGH -> dom.style.textDecoration = "line-through" 62 | TextDecoration.UNDERLINED -> dom.style.textDecoration = "underline" 63 | TextDecoration.ITALIC -> dom.style.fontStyle = "italic" 64 | null -> { 65 | dom.removeClass("obfuscated") 66 | dom.style.fontWeight = "" 67 | dom.style.textDecoration = "" 68 | dom.style.fontStyle = "" 69 | } 70 | } 71 | return this 72 | } 73 | 74 | fun color(color: TextColor): Component { 75 | dom.style.color = color.asHexString() 76 | style.innerColor = color 77 | return this 78 | } 79 | 80 | fun style(style: Style): Component { 81 | if(style.color() != null) { 82 | color(style.color()!!) 83 | } 84 | if(style.decoration != null) { 85 | decorate(style.decoration) 86 | } 87 | return this 88 | } 89 | 90 | fun style(): Style { 91 | return style 92 | } 93 | 94 | fun mergeStyle(current: Component): Component { 95 | // TODO("Not yet implemented") 96 | println("merge style ") 97 | style(current.style()) 98 | return this 99 | } 100 | 101 | fun hasStyling(): Boolean { 102 | TODO("Not yet implemented") 103 | } 104 | 105 | override fun toString(): String { 106 | return "Component(childs=$childs, style=$style, hoverEvent=$hoverEvent, clickEvent=$clickEvent, insertion=$insertion)" 107 | } 108 | 109 | 110 | companion object { 111 | fun empty(): Component { 112 | return Component() 113 | } 114 | 115 | fun text(value: String): Component { 116 | val comp = TextComponent() 117 | comp.content = value 118 | return comp 119 | } 120 | 121 | fun text(value: String, color: TextColor): Component { 122 | val comp = text(value) 123 | comp.color(color) 124 | return comp 125 | } 126 | 127 | fun keybind(keybind: String): Component { 128 | TODO("Not yet implemented") 129 | } 130 | 131 | fun translatable(key: String): Component { 132 | TODO("Not yet implemented") 133 | } 134 | 135 | fun translatable(key: String, inners: MutableList): Component { 136 | TODO("Not yet implemented") 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/transformation/inbuild/HoverTransformation.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.transformation.inbuild 25 | 26 | import net.kyori.adventure.text.minimessage.Tokens 27 | import net.kyori.adventure.text.minimessage.helper.Component 28 | import net.kyori.adventure.text.minimessage.helper.HoverEvent 29 | import net.kyori.adventure.text.minimessage.helper.Key 30 | import net.kyori.adventure.text.minimessage.parser.ParsingException 31 | import net.kyori.adventure.text.minimessage.parser.node.TagPart 32 | import net.kyori.adventure.text.minimessage.transformation.Transformation 33 | import net.kyori.adventure.text.minimessage.transformation.TransformationParser 34 | 35 | /** 36 | * A transformation that applies a [HoverEvent]. 37 | * 38 | * @since 4.1.0 39 | */ 40 | class HoverTransformation private constructor() : Transformation() { 41 | private var value: Component? = null 42 | 43 | override fun load(name: String, args: List) { 44 | super.load(name, args) 45 | if(args.size < 2) { 46 | throw ParsingException("Doesn't know how to turn $args into a hover event", *this.argTokenArray()) 47 | } 48 | val newArgs: List = args.let { args.subList(1, it.size) } 49 | value = if(args[0].value().equals("show_text", true)) { 50 | this.context!!.parse(newArgs[0].value()) 51 | } else { 52 | throw ParsingException("Don't know how to turn '$args' into a hover event", *this.argTokenArray()) 53 | } 54 | } 55 | 56 | override fun apply(): Component { 57 | val comp = Component.empty() 58 | comp.hoverEvent = HoverEvent(value!!) 59 | return comp 60 | } 61 | 62 | override fun toString(): String { 63 | return "HoverTransformation(value=$value)" 64 | } 65 | 66 | override fun equals(o: Any?): Boolean { 67 | if(this === o) return true 68 | if(o == null || this::class.js != o::class.js) return false 69 | 70 | o as HoverTransformation 71 | 72 | if(value != o.value) return false 73 | 74 | return true 75 | } 76 | 77 | override fun hashCode(): Int { 78 | var result = 42 79 | result = 31 * result + (value?.hashCode() ?: 0) 80 | return result 81 | } 82 | 83 | /** 84 | * Factory for [HoverTransformation] instances. 85 | * 86 | * @since 4.1.0 87 | */ 88 | class Parser : TransformationParser { 89 | 90 | override fun parse(): HoverTransformation { 91 | return HoverTransformation() 92 | } 93 | } 94 | 95 | companion object { 96 | /** 97 | * Get if this transformation can handle the provided tag name. 98 | * 99 | * @param name tag name to test 100 | * @return if this transformation is applicable 101 | * @since 4.1.0 102 | */ 103 | fun canParse(name: String): Boolean { 104 | return name.equals(Tokens.HOVER, true) 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/helper/NamedTextColor.kt: -------------------------------------------------------------------------------- 1 | package net.kyori.adventure.text.minimessage.helper 2 | 3 | class NamedTextColor(val name: String, value: Int): TextColor(value) { 4 | 5 | override fun toString(): String { 6 | return "NamedTextColor(name='$name')" 7 | } 8 | 9 | companion object { 10 | 11 | private const val BLACK_VALUE = 0x000000 12 | private const val DARK_BLUE_VALUE = 0x0000aa 13 | private const val DARK_GREEN_VALUE = 0x00aa00 14 | private const val DARK_AQUA_VALUE = 0x00aaaa 15 | private const val DARK_RED_VALUE = 0xaa0000 16 | private const val DARK_PURPLE_VALUE = 0xaa00aa 17 | private const val GOLD_VALUE = 0xffaa00 18 | private const val GRAY_VALUE = 0xaaaaaa 19 | private const val DARK_GRAY_VALUE = 0x555555 20 | private const val BLUE_VALUE = 0x5555ff 21 | private const val GREEN_VALUE = 0x55ff55 22 | private const val AQUA_VALUE = 0x55ffff 23 | private const val RED_VALUE = 0xff5555 24 | private const val LIGHT_PURPLE_VALUE = 0xff55ff 25 | private const val YELLOW_VALUE = 0xffff55 26 | private const val WHITE_VALUE = 0xffffff 27 | 28 | val BLACK = NamedTextColor("black", BLACK_VALUE) 29 | 30 | /** 31 | * The standard `dark_blue` colour. 32 | * 33 | * @since 4.0.0 34 | */ 35 | val DARK_BLUE = NamedTextColor("dark_blue", DARK_BLUE_VALUE) 36 | 37 | /** 38 | * The standard `dark_green` colour. 39 | * 40 | * @since 4.0.0 41 | */ 42 | val DARK_GREEN = NamedTextColor("dark_green", DARK_GREEN_VALUE) 43 | 44 | /** 45 | * The standard `dark_aqua` colour. 46 | * 47 | * @since 4.0.0 48 | */ 49 | val DARK_AQUA = NamedTextColor("dark_aqua", DARK_AQUA_VALUE) 50 | 51 | /** 52 | * The standard `dark_red` colour. 53 | * 54 | * @since 4.0.0 55 | */ 56 | val DARK_RED = NamedTextColor("dark_red", DARK_RED_VALUE) 57 | 58 | /** 59 | * The standard `dark_purple` colour. 60 | * 61 | * @since 4.0.0 62 | */ 63 | val DARK_PURPLE = NamedTextColor("dark_purple", DARK_PURPLE_VALUE) 64 | 65 | /** 66 | * The standard `gold` colour. 67 | * 68 | * @since 4.0.0 69 | */ 70 | val GOLD = NamedTextColor("gold", GOLD_VALUE) 71 | 72 | /** 73 | * The standard `gray` colour. 74 | * 75 | * @since 4.0.0 76 | */ 77 | val GRAY = NamedTextColor("gray", GRAY_VALUE) 78 | 79 | /** 80 | * The standard `dark_gray` colour. 81 | * 82 | * @since 4.0.0 83 | */ 84 | val DARK_GRAY = NamedTextColor("dark_gray", DARK_GRAY_VALUE) 85 | 86 | /** 87 | * The standard `blue` colour. 88 | * 89 | * @since 4.0.0 90 | */ 91 | val BLUE = NamedTextColor("blue", BLUE_VALUE) 92 | 93 | /** 94 | * The standard `green` colour. 95 | * 96 | * @since 4.0.0 97 | */ 98 | val GREEN = NamedTextColor("green", GREEN_VALUE) 99 | 100 | /** 101 | * The standard `aqua` colour. 102 | * 103 | * @since 4.0.0 104 | */ 105 | val AQUA = NamedTextColor("aqua", AQUA_VALUE) 106 | 107 | /** 108 | * The standard `red` colour. 109 | * 110 | * @since 4.0.0 111 | */ 112 | val RED = NamedTextColor("red", RED_VALUE) 113 | 114 | /** 115 | * The standard `light_purple` colour. 116 | * 117 | * @since 4.0.0 118 | */ 119 | val LIGHT_PURPLE = NamedTextColor("light_purple", LIGHT_PURPLE_VALUE) 120 | 121 | /** 122 | * The standard `yellow` colour. 123 | * 124 | * @since 4.0.0 125 | */ 126 | val YELLOW = NamedTextColor("yellow", YELLOW_VALUE) 127 | 128 | /** 129 | * The standard `white` colour. 130 | * 131 | * @since 4.0.0 132 | */ 133 | val WHITE = NamedTextColor("white", WHITE_VALUE) 134 | 135 | private val VALUES: List = listOf(BLACK, DARK_BLUE, DARK_GREEN, DARK_AQUA, DARK_RED, DARK_PURPLE, GOLD, GRAY, DARK_GRAY, BLUE, GREEN, AQUA, RED, LIGHT_PURPLE, YELLOW, WHITE) 136 | 137 | /** 138 | * An index of name to color. 139 | * 140 | * @since 4.0.0 141 | */ 142 | val NAMES: Map = VALUES.associateBy { it.name } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/transformation/TransformationType.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.transformation 25 | 26 | import net.kyori.adventure.text.minimessage.transformation.inbuild.ClickTransformation 27 | import net.kyori.adventure.text.minimessage.transformation.inbuild.ColorTransformation 28 | import net.kyori.adventure.text.minimessage.transformation.inbuild.DecorationTransformation 29 | import net.kyori.adventure.text.minimessage.transformation.inbuild.FontTransformation 30 | import net.kyori.adventure.text.minimessage.transformation.inbuild.GradientTransformation 31 | import net.kyori.adventure.text.minimessage.transformation.inbuild.HoverTransformation 32 | import net.kyori.adventure.text.minimessage.transformation.inbuild.InsertionTransformation 33 | import net.kyori.adventure.text.minimessage.transformation.inbuild.KeybindTransformation 34 | import net.kyori.adventure.text.minimessage.transformation.inbuild.RainbowTransformation 35 | import net.kyori.adventure.text.minimessage.transformation.inbuild.TranslatableTransformation 36 | 37 | 38 | /** 39 | * Available types of transformation. 40 | * 41 | * @param transformation class 42 | * @since 4.1.0 43 | */ 44 | class TransformationType internal constructor(canParse: (String) -> Boolean, parser: TransformationParser) { 45 | val canParse: (String) -> Boolean 46 | val parser: TransformationParser 47 | 48 | companion object { 49 | val COLOR: TransformationType = TransformationType({ ColorTransformation.canParse(it) }, ColorTransformation.Parser()) 50 | val DECORATION: TransformationType = TransformationType({ DecorationTransformation.canParse(it) }, DecorationTransformation.Parser()) 51 | val HOVER_EVENT: TransformationType = TransformationType({ HoverTransformation .canParse(it) }, HoverTransformation.Parser()) 52 | val CLICK_EVENT: TransformationType = TransformationType({ ClickTransformation .canParse(it) }, ClickTransformation.Parser()) 53 | val KEYBIND: TransformationType = TransformationType({ KeybindTransformation .canParse(it) }, KeybindTransformation.Parser()) 54 | val TRANSLATABLE: TransformationType = TransformationType({ TranslatableTransformation .canParse(it) }, TranslatableTransformation.Parser()) 55 | val INSERTION: TransformationType = TransformationType({ InsertionTransformation .canParse(it) }, InsertionTransformation.Parser()) 56 | val FONT: TransformationType = TransformationType({ FontTransformation .canParse(it) }, FontTransformation.Parser()) 57 | val GRADIENT: TransformationType = TransformationType({ GradientTransformation .canParse(it) }, GradientTransformation.Parser()) 58 | val RAINBOW: TransformationType = TransformationType({ RainbowTransformation .canParse(it) }, RainbowTransformation.Parser()) 59 | } 60 | 61 | init { 62 | this.canParse = canParse 63 | this.parser = parser 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/resources/style.css: -------------------------------------------------------------------------------- 1 | /* font shit */ 2 | * { 3 | font-size: 20px; 4 | } 5 | .mc-font { 6 | font-family: "Minecraft", monospace; 7 | } 8 | .mono-font { 9 | font-family: monospace, monospace; 10 | } 11 | @font-face { 12 | font-family: "Minecraft"; 13 | src: url("font/1_Minecraft-Regular.woff") format("woff"); 14 | font-weight: normal; 15 | font-style: normal; 16 | } 17 | @font-face { 18 | font-family: "Minecraft"; 19 | src: url("font/2_Minecraft-Italic.woff") format("woff"); 20 | font-weight: normal; 21 | font-style: italic; 22 | } 23 | @font-face { 24 | font-family: "Minecraft"; 25 | src: url("font/3_Minecraft-Bold.woff") format("woff"); 26 | font-weight: bold; 27 | font-style: normal; 28 | } 29 | @font-face { 30 | font-family: "Minecraft"; 31 | src: url("font/4_Minecraft-BoldItalic.woff") format("woff"); 32 | font-weight: bold; 33 | font-style: italic; 34 | } 35 | /* hover */ 36 | .hover { 37 | position: absolute; 38 | background-color: white; 39 | border: black; 40 | visibility: hidden; 41 | z-index: +1; 42 | bottom: 100%; 43 | left: 50%; 44 | border-radius: 5px; 45 | box-shadow: 1px 1px 5px 0 #000000; 46 | padding: 2px; 47 | cursor: initial; 48 | color: black; 49 | } 50 | .hover-source { 51 | position: relative; 52 | cursor: pointer; 53 | } 54 | .hover-source:hover .hover { 55 | visibility: visible; 56 | } 57 | /* output pane */ 58 | #output-pane { 59 | background-image: url("img/grass.png"); 60 | background-size: cover; 61 | } 62 | #output-pane.mode-chat-open, #output-pane.mode-chat-closed { 63 | background-position: bottom left; 64 | display: flex; 65 | align-items: flex-end; 66 | } 67 | #output-pane.mode-chat-open { 68 | flex-direction: column-reverse; 69 | align-items: flex-start; 70 | } 71 | #output-pane:not(.mode-chat-open) > #chat-entry-box { 72 | display: none; 73 | } 74 | #output-pane.mode-chat-open > #chat-entry-box { 75 | background-color: rgba(0, 0, 0, 0.4); 76 | margin: 5px; 77 | height: 22px; 78 | width: calc(100% - 10px); 79 | color: white; 80 | line-height: 20px; 81 | padding-left: 5px; 82 | } 83 | #output-pane.mode-hologram { 84 | background-position: center center; 85 | align-items: center; 86 | display: flex; 87 | justify-content: center; 88 | align-content: center; 89 | } 90 | #output-pane.mode-lore { 91 | background-position: center center; 92 | align-items: center; 93 | display: flex; 94 | justify-content: center; 95 | align-content: center; 96 | } 97 | /* output pre */ 98 | #output-pre { 99 | margin-bottom: 4px; 100 | color: white; 101 | background-color: rgba(1, 1, 1, 0.4); 102 | } 103 | #output-pre.mode-chat-open, #output-pre.mode-chat-closed { 104 | padding: 0 5px; 105 | width: 55%; 106 | left: 36px; 107 | right: 36px; 108 | overflow-x: hidden; 109 | overflow-wrap: break-word; 110 | white-space: break-spaces; 111 | line-height: 19px; 112 | display: inline-flex; 113 | flex-direction: column; 114 | } 115 | #output-pre.mode-chat-open { 116 | max-height: 383px; /* 20 lines */ 117 | margin-bottom: 48px; 118 | } 119 | #output-pre.mode-chat-closed { 120 | max-height: 193px; /* 10 lines */ 121 | overflow-y: hidden; 122 | margin-bottom: 80px; 123 | } 124 | #output-pre.mode-chat-open > div:first-child, #output-pre.mode-chat-closed > div:first-child { 125 | padding-top: 3px; 126 | } 127 | #output-pre.mode-hologram { 128 | display: inline-flex; 129 | padding: 5px 10px; 130 | flex-direction: column; 131 | line-height: 25px; 132 | text-align: center; 133 | } 134 | #output-pre.mode-lore { 135 | background-color: rgba(1, 1, 1, 0.8); 136 | border: solid #1b0035; 137 | display: inline-flex; 138 | padding: 5px 0 5px 5px; 139 | flex-direction: column; 140 | line-height: 19px; 141 | border-radius: 5px; 142 | } 143 | #output-pre.mode-lore > div:first-child:not(:only-child) { 144 | padding-bottom: 7px; 145 | } 146 | /* other shit */ 147 | .is-horizontal { 148 | align-items: center; 149 | } 150 | #main-container { 151 | padding: 0 32px; 152 | width: 100%; 153 | } 154 | .gone { 155 | display: none; 156 | } 157 | body { 158 | background-color: #E6E6E6; 159 | } 160 | html { 161 | overflow-y: hidden; 162 | } 163 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/transformation/Transformation.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.transformation 25 | 26 | import net.kyori.adventure.text.minimessage.Context 27 | import net.kyori.adventure.text.minimessage.helper.Component 28 | import net.kyori.adventure.text.minimessage.helper.Style 29 | import net.kyori.adventure.text.minimessage.parser.Token 30 | import net.kyori.adventure.text.minimessage.parser.node.TagPart 31 | 32 | /** 33 | * A transformation that can be applied while parsing a message. 34 | * 35 | * 36 | * A transformation instance is created for each instance of a tag in a parsed string. 37 | * 38 | * @see TransformationRegistry to access and register available transformations 39 | * 40 | * @since 4.1.0 41 | */ 42 | abstract class Transformation protected constructor() { 43 | private var name: String? = null 44 | private var args: List? = null 45 | protected var context: Context? = null 46 | 47 | /** 48 | * Initialize this transformation with a tag name and tokens. 49 | * 50 | * @param name the alias for this transformation 51 | * @param args tokens within the tags, used to define arguments. Each 52 | * @since 4.1.0 53 | */ 54 | open fun load(name: String, args: List) { 55 | this.name = name 56 | this.args = args 57 | } 58 | 59 | /** 60 | * The tag alias used to refer to this instance. 61 | * 62 | * @return the name 63 | * @since 4.1.0 64 | */ 65 | fun name(): String? { 66 | return name 67 | } 68 | 69 | /** 70 | * The arguments making up this instance. 71 | * 72 | * @return the args 73 | * @since 4.2.0 74 | */ 75 | fun args(): List? { 76 | return args 77 | } 78 | 79 | /** 80 | * Returns the tokens which make up the arguments as an array. 81 | * 82 | * @return the arg tokens 83 | * @since 4.2.0 84 | */ 85 | fun argTokenArray(): Array { 86 | return args?.map(TagPart::token)?.toTypedArray()!! 87 | } 88 | 89 | /** 90 | * Return a transformed `component` based on the applied parameters. 91 | * 92 | * @return the transformed component 93 | * @since 4.1.0 94 | */ 95 | abstract fun apply(): Component 96 | fun context(context: Context?) { 97 | this.context = context 98 | } 99 | 100 | abstract override fun toString(): String 101 | abstract override fun equals(o: Any?): Boolean 102 | abstract override fun hashCode(): Int 103 | 104 | protected fun merge(target: Component, template: Component): Component { 105 | TODO("not implemented") 106 | // var result: Component = target.style(target.style().merge(template.style(), Style.Merge.Strategy.IF_ABSENT_ON_TARGET, Style.Merge.all())) 107 | // if(template.hoverEvent() != null) { 108 | // result = result.hoverEvent(template.hoverEvent()) 109 | // } 110 | // if(template.clickEvent() != null) { 111 | // result = result.clickEvent(template.clickEvent()) 112 | // } 113 | // if(template.insertion() != null) { 114 | // result = result.insertion(template.insertion()) 115 | // } 116 | // return result 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/transformation/inbuild/DecorationTransformation.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.transformation.inbuild 25 | 26 | import net.kyori.adventure.text.minimessage.Tokens 27 | import net.kyori.adventure.text.minimessage.helper.Component 28 | import net.kyori.adventure.text.minimessage.helper.TextDecoration 29 | import net.kyori.adventure.text.minimessage.parser.ParsingException 30 | import net.kyori.adventure.text.minimessage.parser.node.TagPart 31 | import net.kyori.adventure.text.minimessage.transformation.Transformation 32 | import net.kyori.adventure.text.minimessage.transformation.TransformationParser 33 | 34 | /** 35 | * A transformation that applies any [TextDecoration]. 36 | * 37 | * @since 4.1.0 38 | */ 39 | class DecorationTransformation private constructor() : Transformation() { 40 | private var decoration: TextDecoration? = null 41 | 42 | override fun load(name: String, args: List) { 43 | super.load(name, args) 44 | decoration = parseDecoration(name) 45 | if(decoration == null) { 46 | throw ParsingException("Don't know how to turn '$name' into a decoration", *this.argTokenArray()) 47 | } 48 | } 49 | 50 | override fun apply(): Component { 51 | return Component.empty().decorate(decoration) 52 | } 53 | 54 | override fun toString(): String { 55 | return "DecorationTransformation(decoration=$decoration)" 56 | } 57 | 58 | override fun equals(o: Any?): Boolean { 59 | if(this === o) return true 60 | if(o == null || this::class.js != o::class.js) return false 61 | 62 | o as DecorationTransformation 63 | 64 | if(decoration != o.decoration) return false 65 | 66 | return true 67 | } 68 | 69 | override fun hashCode(): Int { 70 | var result = 42 71 | result = 31 * result + (decoration.hashCode() ?: 0) 72 | return result 73 | } 74 | 75 | /** 76 | * Factory for [DecorationTransformation] instances. 77 | * 78 | * @since 4.1.0 79 | */ 80 | class Parser : TransformationParser { 81 | 82 | override fun parse(): DecorationTransformation { 83 | return DecorationTransformation() 84 | } 85 | } 86 | 87 | companion object { 88 | /** 89 | * Get if this transformation can handle the provided tag name. 90 | * 91 | * @param name tag name to test 92 | * @return if this transformation is applicable 93 | * @since 4.1.0 94 | */ 95 | fun canParse(name: String): Boolean { 96 | return parseDecoration(name) != null 97 | } 98 | 99 | private fun parseDecoration(name: String): TextDecoration? { 100 | var name = name 101 | name = name.lowercase() 102 | when(name) { 103 | Tokens.BOLD_2 -> name = Tokens.BOLD 104 | Tokens.ITALIC_2, Tokens.ITALIC_3 -> name = Tokens.ITALIC 105 | Tokens.UNDERLINED_2 -> name = Tokens.UNDERLINED 106 | Tokens.STRIKETHROUGH_2 -> name = Tokens.STRIKETHROUGH 107 | Tokens.OBFUSCATED_2 -> name = Tokens.OBFUSCATED 108 | else -> { 109 | } 110 | } 111 | return TextDecoration.NAMES[name] 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/transformation/inbuild/TranslatableTransformation.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.transformation.inbuild 25 | 26 | import net.kyori.adventure.text.minimessage.Tokens 27 | import net.kyori.adventure.text.minimessage.helper.Component 28 | import net.kyori.adventure.text.minimessage.parser.ParsingException 29 | import net.kyori.adventure.text.minimessage.parser.node.TagPart 30 | import net.kyori.adventure.text.minimessage.transformation.Inserting 31 | import net.kyori.adventure.text.minimessage.transformation.Transformation 32 | import net.kyori.adventure.text.minimessage.transformation.TransformationParser 33 | 34 | /** 35 | * Insert a translation component into the result. 36 | * 37 | * @since 4.1.0 38 | */ 39 | class TranslatableTransformation : Transformation(), Inserting { 40 | private var key: String = "" 41 | private val inners: MutableList = ArrayList() 42 | 43 | override fun load(name: String, args: List) { 44 | super.load(name, args) 45 | if(args.isEmpty()) { 46 | throw ParsingException("Doesn't know how to turn $args into a translatable component", *this.argTokenArray()) 47 | } 48 | key = args[0].value() 49 | if(args.size > 1) { 50 | for(`in` in args.subList(1, args.size)) { 51 | inners.add(this.context!!.parse(`in`.value())) 52 | } 53 | } 54 | } 55 | 56 | override fun apply(): Component { 57 | return if(inners.isEmpty()) { 58 | Component.translatable(key) 59 | } else { 60 | Component.translatable(key, inners) 61 | } 62 | } 63 | 64 | override fun toString(): String { 65 | return "TranslatableTransformation(key=$key, inners=$inners)" 66 | } 67 | 68 | override fun equals(o: Any?): Boolean { 69 | if(this === o) return true 70 | if(o == null || this::class.js != o::class.js) return false 71 | if(!super.equals(o)) return false 72 | 73 | o as TranslatableTransformation 74 | 75 | if(key != o.key) return false 76 | if(inners != o.inners) return false 77 | 78 | return true 79 | } 80 | 81 | override fun hashCode(): Int { 82 | var result = super.hashCode() 83 | result = 31 * result + key.hashCode() 84 | result = 31 * result + inners.hashCode() 85 | return result 86 | } 87 | 88 | /** 89 | * Factory for [TranslatableTransformation] instances. 90 | * 91 | * @since 4.1.0 92 | */ 93 | class Parser : TransformationParser { 94 | 95 | override fun parse(): TranslatableTransformation { 96 | return TranslatableTransformation() 97 | } 98 | } 99 | 100 | companion object { 101 | private val DUM_SPLIT_PATTERN: Regex = Regex("['\"]:['\"]") 102 | 103 | /** 104 | * Get if this transformation can handle the provided tag name. 105 | * 106 | * @param name tag name to test 107 | * @return if this transformation is applicable 108 | * @since 4.1.0 109 | */ 110 | fun canParse(name: String): Boolean { 111 | return (name.equals(Tokens.TRANSLATABLE, true) 112 | || name.equals(Tokens.TRANSLATABLE_2, true) 113 | || name.equals(Tokens.TRANSLATABLE_3, true)) 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/transformation/TransformationRegistry.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.transformation 25 | 26 | import net.kyori.adventure.text.minimessage.Context 27 | import net.kyori.adventure.text.minimessage.Template 28 | import net.kyori.adventure.text.minimessage.helper.Component 29 | import net.kyori.adventure.text.minimessage.parser.node.TagPart 30 | 31 | /** 32 | * A registry of transformation types understood by the MiniMessage parser. 33 | * 34 | * @since 4.1.0 35 | */ 36 | interface TransformationRegistry { 37 | /** 38 | * Get a transformation from this registry based on the current state. 39 | * 40 | * @param name tag name 41 | * @param inners tokens that make up the tag arguments 42 | * @param templates available templates 43 | * @param placeholderResolver function to resolve other component types 44 | * @param context the debug context 45 | * @return a possible transformation 46 | * @since 4.1.0 47 | */ 48 | operator fun get(name: String, inners: List, templates: Map, placeholderResolver: (String) -> Component?, context: Context): Transformation? 49 | 50 | /** 51 | * Test if any registered transformation type matches the provided key. 52 | * 53 | * @param name tag name 54 | * @param placeholderResolver function to resolve other component types 55 | * @return whether any transformation exists 56 | * @since 4.1.0 57 | */ 58 | fun exists(name: String, placeholderResolver: (String) -> Component?): Boolean 59 | 60 | /** 61 | * A builder for [TransformationRegistry]. 62 | * 63 | * @since 4.2.0 64 | */ 65 | interface Builder { 66 | /** 67 | * Clears all currently set transformations. 68 | * 69 | * @return this builder 70 | * @since 4.2.0 71 | */ 72 | fun clear(): Builder? 73 | 74 | /** 75 | * Adds a supplied transformation to the registry. 76 | * 77 | * @return this builder 78 | * @since 4.2.0 79 | */ 80 | fun add(transformation: TransformationType): Builder? 81 | 82 | /** 83 | * Adds the supplied transformations to the registry. 84 | * 85 | * @return this builder 86 | * @since 4.2.0 87 | */ 88 | fun add(vararg transformations: TransformationType): Builder? 89 | fun build(): TransformationRegistry 90 | } 91 | 92 | companion object { 93 | /** 94 | * Creates a new [Builder]. 95 | * 96 | * @return a builder 97 | * @since 4.2.0 98 | */ 99 | fun builder(): Builder { 100 | return TransformationRegistryImpl.BuilderImpl() 101 | } 102 | 103 | /** 104 | * Gets an instance of the transformation registry without any transformations. 105 | * 106 | * @return a empty transformation registry 107 | * @since 4.2.0 108 | */ 109 | fun empty(): TransformationRegistry { 110 | return TransformationRegistryImpl.EMPTY 111 | } 112 | 113 | /** 114 | * Gets an instance of the transformation registry with only the standard transformations. 115 | * 116 | * @return a standard transformation registry 117 | * @since 4.2.0 118 | */ 119 | fun standard(): TransformationRegistry { 120 | return TransformationRegistryImpl.STANDARD 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/parser/node/TagNode.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.parser.node 25 | 26 | import net.kyori.adventure.text.minimessage.Template 27 | import net.kyori.adventure.text.minimessage.parser.ParsingException 28 | import net.kyori.adventure.text.minimessage.parser.Token 29 | import net.kyori.adventure.text.minimessage.transformation.Transformation 30 | 31 | /** 32 | * Node that represents a tag. 33 | * 34 | * @since 4.2.0 35 | */ 36 | class TagNode( 37 | parent: ElementNode?, 38 | token: Token, 39 | sourceMessage: String, 40 | templates: Map 41 | ) : ElementNode(parent, token, sourceMessage) { 42 | private val parts: List 43 | 44 | private var transformation: Transformation? = null 45 | 46 | /** 47 | * Returns the parts of this tag. 48 | * 49 | * @return the parts 50 | * @since 4.2.0 51 | */ 52 | fun parts(): List { 53 | return parts 54 | } 55 | 56 | /** 57 | * Returns the name of this tag. 58 | * 59 | * @return the name 60 | * @since 4.2.0 61 | */ 62 | fun name(): String { 63 | if(parts.isEmpty()) { 64 | throw ParsingException("Tag has no parts? $this", this.sourceMessage(), token()) 65 | } 66 | return parts[0].value() 67 | } 68 | 69 | override fun token(): Token { 70 | return requireNotNull(super.token()) { "token is not set" } 71 | } 72 | 73 | /** 74 | * Gets the transformation attached to this tag node. 75 | * 76 | * @return the transformation for this tag node 77 | * @since 4.2.0 78 | */ 79 | fun transformation(): Transformation { 80 | return requireNotNull(transformation) { "no transformation set" } 81 | } 82 | 83 | /** 84 | * Sets the transformation that is represented by this tag. 85 | * 86 | * @param transformation the transformation 87 | * @since 4.2.0 88 | */ 89 | fun transformation(transformation: Transformation?) { 90 | this.transformation = transformation 91 | } 92 | 93 | override fun buildToString(sb: StringBuilder, indent: Int): StringBuilder { 94 | val `in`: CharArray = this.ident(indent) 95 | sb.append(`in`).append("TagNode(") 96 | val size: Int = parts.size 97 | for(i in 0 until size) { 98 | val part: TagPart = parts[i] 99 | sb.append('\'').append(part.value()).append('\'') 100 | if(i != size - 1) { 101 | sb.append(", ") 102 | } 103 | } 104 | sb.append(") {\n") 105 | for(child in this.children()) { 106 | child.buildToString(sb, indent + 1) 107 | } 108 | sb.append(`in`).append("}\n") 109 | return sb 110 | } 111 | 112 | companion object { 113 | private fun genParts( 114 | token: Token, 115 | sourceMessage: String, 116 | templates: Map 117 | ): List { 118 | val parts: ArrayList = ArrayList() 119 | if(token.childTokens() != null) { 120 | for(childToken in token.childTokens()!!) { 121 | parts.add(TagPart(sourceMessage, childToken, templates)) 122 | } 123 | } 124 | return parts 125 | } 126 | } 127 | 128 | /** 129 | * Creates a new element node. 130 | * 131 | * @param parent the parent of this node 132 | * @param token the token that created this node 133 | * @param sourceMessage the source message 134 | * @since 4.2.0 135 | */ 136 | init { 137 | parts = genParts(token, sourceMessage, templates) 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/transformation/inbuild/ColorTransformation.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.transformation.inbuild 25 | 26 | import net.kyori.adventure.text.minimessage.Tokens 27 | import net.kyori.adventure.text.minimessage.helper.Component 28 | import net.kyori.adventure.text.minimessage.helper.NamedTextColor 29 | import net.kyori.adventure.text.minimessage.helper.TextColor 30 | import net.kyori.adventure.text.minimessage.parser.ParsingException 31 | import net.kyori.adventure.text.minimessage.parser.node.TagPart 32 | import net.kyori.adventure.text.minimessage.transformation.Transformation 33 | import net.kyori.adventure.text.minimessage.transformation.TransformationParser 34 | 35 | /** 36 | * A transformation applying a single text color. 37 | * 38 | * @since 4.1.0 39 | */ 40 | class ColorTransformation private constructor() : Transformation() { 41 | companion object { 42 | private val colorAliases: MutableMap = HashMap() 43 | 44 | /** 45 | * Get if this transformation can handle the provided tag name. 46 | * 47 | * @param name tag name to test 48 | * @return if this transformation is applicable 49 | * @since 4.1.0 50 | */ 51 | fun canParse(name: String): Boolean { 52 | return (name.equals(Tokens.COLOR, true) 53 | || name.equals(Tokens.COLOR_2, true) 54 | || name.equals(Tokens.COLOR_3, true) 55 | || TextColor.fromHexString(name) != null || NamedTextColor.NAMES[name.lowercase()] != null || colorAliases.containsKey(name)) 56 | } 57 | 58 | init { 59 | colorAliases["dark_grey"] = "dark_gray" 60 | colorAliases["grey"] = "gray" 61 | } 62 | } 63 | 64 | private var color: TextColor? = null 65 | 66 | override fun load(name: String, args: List) { 67 | var name = name 68 | super.load(name, args) 69 | if(name.equals(Tokens.COLOR, true)) { 70 | name = if(args.size == 1) { 71 | args[0].value() 72 | } else { 73 | throw ParsingException("Expected to find a color parameter, but found $args", *this.argTokenArray()) 74 | } 75 | } 76 | if(colorAliases.containsKey(name)) { 77 | name = colorAliases[name]!! 78 | } 79 | color = if(name[0] == '#') { 80 | TextColor.fromHexString(name) 81 | } else { 82 | NamedTextColor.NAMES[name.lowercase()] 83 | } 84 | if(color == null) { 85 | throw ParsingException("Don't know how to turn '$name' into a color", *this.argTokenArray()) 86 | } 87 | } 88 | 89 | override fun apply(): Component { 90 | return Component.empty().color(color!!) 91 | } 92 | 93 | override fun toString(): String { 94 | return "ColorTransformation(color=$color)" 95 | } 96 | 97 | override fun equals(o: Any?): Boolean { 98 | if(this === o) return true 99 | if(o == null || this::class.js != o::class.js) return false 100 | 101 | o as ColorTransformation 102 | 103 | if(color != o.color) return false 104 | 105 | return true 106 | } 107 | 108 | override fun hashCode(): Int { 109 | var result = 42 110 | result = 31 * result + (color.hashCode() ?: 0) 111 | return result 112 | } 113 | 114 | /** 115 | * Factory for [ColorTransformation] instances. 116 | * 117 | * @since 4.1.0 118 | */ 119 | class Parser : TransformationParser { 120 | 121 | override fun parse(): ColorTransformation { 122 | return ColorTransformation() 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/parser/node/ElementNode.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.parser.node 25 | 26 | import net.kyori.adventure.text.minimessage.parser.Token 27 | import net.kyori.adventure.text.minimessage.parser.TokenType 28 | 29 | /** 30 | * Represents a node in the tree. 31 | * 32 | * @since 4.2.0 33 | */ 34 | open class ElementNode internal constructor(private val parent: ElementNode?, token: Token?, sourceMessage: String) { 35 | 36 | private val token: Token? 37 | private val sourceMessage: String 38 | private val children: MutableList = ArrayList() 39 | 40 | /** 41 | * Returns the parent of this node, if present. 42 | * 43 | * @return the parent or null 44 | * @since 4.2.0 45 | */ 46 | fun parent(): ElementNode? { 47 | return parent 48 | } 49 | 50 | /** 51 | * Returns the token that lead to the creation of this token. 52 | * 53 | * @return the token 54 | * @since 4.2.0 55 | */ 56 | open fun token(): Token? { 57 | return token 58 | } 59 | 60 | /** 61 | * Returns the source message of this node. 62 | * 63 | * @return the source message 64 | * @since 4.2.0 65 | */ 66 | fun sourceMessage(): String { 67 | return sourceMessage 68 | } 69 | 70 | /** 71 | * Returns the children of this node. 72 | * 73 | * @return the children of this node 74 | * @since 4.2.0 75 | */ 76 | fun children(): List { 77 | return children 78 | } 79 | 80 | /** 81 | * Adds a child to this node. 82 | * 83 | * 84 | * This method will attempt to join text tokens together if possible. 85 | * 86 | * @param childNode the child node to add. 87 | * @since 4.2.0 88 | */ 89 | fun addChild(childNode: ElementNode) { 90 | val last: Int = children.size - 1 91 | if(childNode !is TextNode || children.isEmpty() || children[last] !is TextNode) { 92 | children.add(childNode) 93 | } else { 94 | val lastNode: TextNode = children.removeAt(last) as TextNode 95 | if(lastNode.token().endIndex() == childNode.token().startIndex()) { 96 | val replace = Token(lastNode.token().startIndex(), childNode.token().endIndex(), TokenType.TEXT) 97 | children.add(TextNode(this, replace, lastNode.sourceMessage())) 98 | } else { 99 | // These nodes aren't adjacent in the string, so put the last one back 100 | children.add(lastNode) 101 | children.add(childNode) 102 | } 103 | } 104 | } 105 | 106 | /** 107 | * Serializes this node to a string. 108 | * 109 | * @param sb the string builder to serialize into 110 | * @param indent the current indent level 111 | * @return the passed string builder, for chaining 112 | * @since 4.2.0 113 | */ 114 | open fun buildToString(sb: StringBuilder, indent: Int): StringBuilder { 115 | val `in` = ident(indent) 116 | sb.append(`in`).append("Node {\n") 117 | for(child in children) { 118 | child.buildToString(sb, indent + 1) 119 | } 120 | sb.append(`in`).append("}\n") 121 | return sb 122 | } 123 | 124 | fun ident(indent: Int): CharArray { 125 | val c = CharArray(indent * 2) 126 | c.fill(' ') 127 | return c 128 | } 129 | 130 | override fun toString(): String { 131 | return buildToString(StringBuilder(), 0).toString() 132 | } 133 | 134 | /** 135 | * Creates a new element node. 136 | * 137 | * @param parent the parent of this node 138 | * @param token the token that created this node 139 | * @param sourceMessage the source message 140 | * @since 4.2.0 141 | */ 142 | init { 143 | this.token = token 144 | this.sourceMessage = sourceMessage 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/Template.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage 25 | 26 | import net.kyori.adventure.text.minimessage.helper.Component 27 | import net.kyori.adventure.text.minimessage.transformation.TransformationRegistry.Companion.empty 28 | 29 | /** 30 | * A placeholder in a message, which can replace a tag with a component. 31 | * 32 | * @since 4.0.0 33 | */ 34 | interface Template { 35 | /** 36 | * Get the key for this template. 37 | * 38 | * @return the key 39 | * @since 4.2.0 40 | */ 41 | fun key(): String 42 | 43 | /** 44 | * Get the value for this template. 45 | * 46 | * @return the value 47 | * @since 4.2.0 48 | */ 49 | fun value(): Any 50 | 51 | /** 52 | * A template with a value that will be parsed as a MiniMessage string. 53 | * 54 | * @since 4.0.0 55 | */ 56 | class StringTemplate internal constructor(private val key: String, private val value: String) : Template { 57 | 58 | override fun key(): String { 59 | return key 60 | } 61 | 62 | override fun value(): String { 63 | return value 64 | } 65 | 66 | override fun toString(): String { 67 | return "StringTemplate(key='$key', value='$value')" 68 | } 69 | } 70 | 71 | /** 72 | * A template with a [Component] value that will be inserted directly. 73 | * 74 | * @since 4.0.0 75 | */ 76 | open class ComponentTemplate(private val key: String, value: Component) : Template { 77 | 78 | private val value: Component 79 | 80 | override fun key(): String { 81 | return key 82 | } 83 | 84 | override fun value(): Component { 85 | return value 86 | } 87 | 88 | override fun toString(): String { 89 | return "ComponentTemplate(key='$key', value=$value)" 90 | } 91 | 92 | init { 93 | this.value = value 94 | } 95 | } 96 | 97 | /** 98 | * A template with a lazily provided [Component] value that will be inserted directly. 99 | * 100 | * @since 4.2.0 101 | */ 102 | class LazyComponentTemplate(key: String, value: () -> Component) : ComponentTemplate(key, Component.empty()) { 103 | 104 | private val value: () -> Component 105 | 106 | override fun value(): Component { 107 | return value.invoke() 108 | } 109 | 110 | override fun toString(): String { 111 | return "LazyComponentTemplate(value=$value)" 112 | } 113 | 114 | init { 115 | this.value = value 116 | } 117 | } 118 | 119 | companion object { 120 | /** 121 | * Constructs a template that gets replaced with a string. 122 | * 123 | * @param key the placeholder 124 | * @param value the value to replace the key with 125 | * @return the constructed template 126 | * @since 4.0.0 127 | */ 128 | fun of(key: String, value: String): Template { 129 | return StringTemplate(key, value) 130 | } 131 | 132 | /** 133 | * Constructs a template that gets replaced with a component. 134 | * 135 | * @param key the placeholder 136 | * @param value the component to replace the key with 137 | * @return the constructed template 138 | * @since 4.0.0 139 | */ 140 | fun of(key: String, value: Component): Template { 141 | return ComponentTemplate(key, value) 142 | } 143 | 144 | /** 145 | * Constructs a template that gets replaced with a component lazily. 146 | * 147 | * @param key the placeholder 148 | * @param value the supplier that supplies the component to replace the key with 149 | * @return the constructed template 150 | * @since 4.2.0 151 | */ 152 | fun of(key: String, value: () -> Component): Template { 153 | return LazyComponentTemplate(key, value) 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/parser/ParsingException.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.parser 25 | 26 | /** 27 | * An exception that happens while parsing. 28 | * 29 | * @since 4.1.0 30 | */ 31 | class ParsingException : RuntimeException { 32 | 33 | private var originalText: String? 34 | private var tokens: Array 35 | 36 | /** 37 | * Create a new parsing exception. 38 | * 39 | * @param message the detail message 40 | * @param originalText the origina text which was parsed 41 | * @param tokens the token which caused the error 42 | * @since 4.1.0 43 | */ 44 | constructor( 45 | message: String, 46 | originalText: String, 47 | vararg tokens: Token 48 | ) : super(message) { 49 | this.tokens = tokens 50 | this.originalText = originalText 51 | } 52 | 53 | /** 54 | * Create a new parsing exception. 55 | * 56 | * @param message the detail message 57 | * @param originalText the origina text which was parsed 58 | * @param cause the cause 59 | * @param tokens the token which caused the error 60 | * @since 4.1.0 61 | */ 62 | constructor( 63 | message: String, 64 | originalText: String?, 65 | cause: Throwable?, 66 | vararg tokens: Token 67 | ) : super(message, cause) { 68 | this.tokens = tokens 69 | this.originalText = originalText 70 | } 71 | 72 | /** 73 | * Create a new parsing exception. 74 | * 75 | * @param message the detail message 76 | * @param tokens the token which caused the error 77 | * @since 4.1.0 78 | */ 79 | constructor(message: String, vararg tokens: Token) : this(message, null, null, *tokens) {} 80 | 81 | /** 82 | * Create a new parsing exception. 83 | * 84 | * @param message the detail message 85 | * @param cause the cause 86 | * @param tokens the token which caused the error 87 | * @since 4.1.0 88 | */ 89 | constructor( 90 | message: String, 91 | cause: Throwable?, 92 | vararg tokens: Token 93 | ) : this(message, null, cause, *tokens) { 94 | } 95 | 96 | override val message: String 97 | get() { 98 | val arrowInfo = if(this.tokens().size != 0) """ 99 | ${arrow()}""" else "" 100 | val messageInfo = if(this.originalText() != null) """ 101 | ${this.originalText()}$arrowInfo""" else "" 102 | return super.message + messageInfo 103 | } 104 | 105 | /** 106 | * Get the message which caused this exception. 107 | * 108 | * @return the original message 109 | * @since 4.2.0 110 | */ 111 | fun originalText(): String? { 112 | return originalText 113 | } 114 | 115 | /** 116 | * Set the message which caused this exception. 117 | * 118 | * @param originalText the original message 119 | * @since 4.2.0 120 | */ 121 | fun originalText(originalText: String) { 122 | this.originalText = originalText 123 | } 124 | 125 | /** 126 | * Gets the tokens associated with this parsing error. 127 | * 128 | * @return the tokens for this error 129 | * @since 4.1.0 130 | */ 131 | fun tokens(): Array { 132 | return tokens 133 | } 134 | 135 | /** 136 | * Sets the tokens associated with this parsing error. 137 | * 138 | * @param tokens the tokens for this error 139 | * @since 4.2.0 140 | */ 141 | fun tokens(tokens: Array) { 142 | this.tokens = tokens 143 | } 144 | 145 | private fun arrow(): String { 146 | val ts: Array = this.tokens 147 | val chars = CharArray(ts[ts.size - 1].endIndex()) 148 | var i = 0 149 | for(t in ts) { 150 | chars.fill(' ', i, t.startIndex()) 151 | chars[t.startIndex()] = '^' 152 | chars.fill( '~', t.startIndex() + 1, t.endIndex() - 1) 153 | chars[t.endIndex() - 1] = '^' 154 | i = t.endIndex() 155 | } 156 | return chars.concatToString() 157 | } 158 | 159 | companion object { 160 | private const val serialVersionUID = 2507190809441787201L 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/transformation/TransformationRegistryImpl.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.transformation 25 | 26 | import net.kyori.adventure.text.minimessage.Context 27 | import net.kyori.adventure.text.minimessage.Template 28 | import net.kyori.adventure.text.minimessage.helper.Component 29 | import net.kyori.adventure.text.minimessage.parser.ParsingException 30 | import net.kyori.adventure.text.minimessage.parser.node.TagPart 31 | import net.kyori.adventure.text.minimessage.transformation.TransformationRegistry.Builder 32 | import net.kyori.adventure.text.minimessage.transformation.inbuild.TemplateTransformation 33 | 34 | internal class TransformationRegistryImpl(types: List>) : TransformationRegistry { 35 | companion object { 36 | private val DEFAULT_TRANSFORMATIONS: MutableList> = ArrayList() 37 | var EMPTY: TransformationRegistry 38 | var STANDARD: TransformationRegistry 39 | 40 | init { 41 | DEFAULT_TRANSFORMATIONS.add(TransformationType.COLOR) 42 | DEFAULT_TRANSFORMATIONS.add(TransformationType.DECORATION) 43 | DEFAULT_TRANSFORMATIONS.add(TransformationType.HOVER_EVENT) 44 | DEFAULT_TRANSFORMATIONS.add(TransformationType.CLICK_EVENT) 45 | DEFAULT_TRANSFORMATIONS.add(TransformationType.KEYBIND) 46 | DEFAULT_TRANSFORMATIONS.add(TransformationType.TRANSLATABLE) 47 | DEFAULT_TRANSFORMATIONS.add(TransformationType.INSERTION) 48 | DEFAULT_TRANSFORMATIONS.add(TransformationType.FONT) 49 | DEFAULT_TRANSFORMATIONS.add(TransformationType.GRADIENT) 50 | DEFAULT_TRANSFORMATIONS.add(TransformationType.RAINBOW) 51 | EMPTY = TransformationRegistryImpl(listOf()) 52 | STANDARD = TransformationRegistry.builder().build() 53 | } 54 | } 55 | 56 | private val types: List> 57 | private fun tryLoad(transformation: Transformation, name: String, inners: List, context: Context): Transformation? { 58 | return try { 59 | transformation.context(context) 60 | transformation.load(name, inners.subList(1, inners.size)) 61 | transformation 62 | } catch(exception: ParsingException) { 63 | exception.originalText(context.ogMessage()) 64 | throw exception 65 | } 66 | } 67 | 68 | override operator fun get(name: String, inners: List, templates: Map, placeholderResolver: (String) -> Component?, context: Context): Transformation? { 69 | // first try if we have a custom placeholder resolver 70 | val potentialTemplate: Component? = placeholderResolver.invoke(name) 71 | if(potentialTemplate != null) { 72 | return tryLoad(TemplateTransformation(Template.ComponentTemplate(name, potentialTemplate)), name, inners, context) 73 | } 74 | // then check our registry 75 | for(type in types) { 76 | if(type.canParse.invoke(name)) { 77 | return tryLoad(type.parser.parse(), name, inners, context) 78 | } else if(templates.containsKey(name)) { 79 | val template: Template? = templates[name] 80 | // The parser handles StringTemplates 81 | if(template is Template.ComponentTemplate) { 82 | return tryLoad(TemplateTransformation(template), name, inners, context) 83 | } 84 | } 85 | } 86 | return null 87 | } 88 | 89 | override fun exists(name: String, placeholderResolver: (String) -> Component?): Boolean { 90 | // first check the placeholder resolver 91 | if(placeholderResolver.invoke(name) != null) { 92 | return true 93 | } 94 | // then check registry 95 | for(type in types) { 96 | if(type.canParse.invoke(name)) { 97 | return true 98 | } 99 | } 100 | return false 101 | } 102 | 103 | internal class BuilderImpl : Builder { 104 | private val types: MutableList> = ArrayList(DEFAULT_TRANSFORMATIONS) 105 | 106 | override fun clear(): Builder { 107 | types.clear() 108 | return this 109 | } 110 | 111 | override fun add(transformation: TransformationType): Builder { 112 | types.add(transformation) 113 | return this 114 | } 115 | 116 | override fun add(vararg transformations: TransformationType): Builder { 117 | types.addAll(transformations) 118 | return this 119 | } 120 | 121 | override fun build(): TransformationRegistry { 122 | return TransformationRegistryImpl(types) 123 | } 124 | } 125 | 126 | /** 127 | * Create a transformation registry with the specified transformation types. 128 | * 129 | * @param types known transformation types 130 | * @since 4.1.0 131 | */ 132 | init { 133 | this.types = types 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/main/resources/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MiniMessageViewer 6 | 7 | 9 | 10 | 12 | 13 | 14 | 61 | 62 |
63 |
64 |
65 | 66 |
67 | 68 | 69 |
70 |
71 | 72 |
73 | 74 |
75 | 76 |
77 |
_
78 |

 79 |             
80 |
81 |
82 |
83 | 84 |
85 |
86 | © 2021. Made by MiniDigger, under the influence of Beer™. 87 |
88 |
89 |
90 | 91 | 92 | 121 | 122 | 123 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/Context.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage 25 | 26 | import net.kyori.adventure.text.minimessage.helper.Component 27 | import net.kyori.adventure.text.minimessage.parser.node.ElementNode 28 | 29 | /** 30 | * Carries needed context for minimessage around, ranging from debug info to the configured minimessage instance. 31 | * 32 | * @since 4.1.0 33 | */ 34 | class Context internal constructor(private val strict: Boolean, private val debugOutput: Appendable?, root: ElementNode?, ogMessage: String, replacedMessage: String?, miniMessage: MiniMessageImpl, templates: Array) { 35 | private var root: ElementNode? 36 | private val ogMessage: String 37 | private var replacedMessage: String? 38 | private val miniMessage: MiniMessageImpl 39 | 40 | private val templates: Array 41 | 42 | /** 43 | * Sets the root element. 44 | * 45 | * @param root the root element. 46 | * @since 4.1.0 47 | */ 48 | fun root(root: ElementNode?) { 49 | this.root = root 50 | } 51 | 52 | /** 53 | * sets the replaced message. 54 | * 55 | * @param replacedMessage the replaced message 56 | * @since 4.1.0 57 | */ 58 | fun replacedMessage(replacedMessage: String?) { 59 | this.replacedMessage = replacedMessage 60 | } 61 | 62 | /** 63 | * Returns strict mode. 64 | * 65 | * @return if strict mode is enabled 66 | * @since 4.1.0 67 | */ 68 | fun strict(): Boolean { 69 | return strict 70 | } 71 | 72 | /** 73 | * Returns the appendable to print debug output to. 74 | * 75 | * @return the debug output to print to 76 | * @since 4.2.0 77 | */ 78 | fun debugOutput(): Appendable? { 79 | return debugOutput 80 | } 81 | 82 | /** 83 | * Returns the root element. 84 | * 85 | * @return root 86 | * @since 4.1.0 87 | */ 88 | fun tokens(): ElementNode? { 89 | return root 90 | } 91 | 92 | /** 93 | * Returns og message. 94 | * 95 | * @return ogMessage 96 | * @since 4.1.0 97 | */ 98 | fun ogMessage(): String { 99 | return ogMessage 100 | } 101 | 102 | /** 103 | * Returns replaced message. 104 | * 105 | * @return replacedMessage 106 | * @since 4.1.0 107 | */ 108 | fun replacedMessage(): String? { 109 | return replacedMessage 110 | } 111 | 112 | /** 113 | * Returns minimessage. 114 | * 115 | * @return minimessage 116 | * @since 4.1.0 117 | */ 118 | fun miniMessage(): MiniMessageImpl { 119 | return miniMessage 120 | } 121 | 122 | /** 123 | * Parses a MiniMessage using all the settings of this context, including templates. 124 | * 125 | * @param message the message to parse 126 | * @return the parsed message 127 | * @since 4.1.0 128 | */ 129 | fun parse(message: String): Component { 130 | return if(templates != null && templates.isNotEmpty()) { 131 | miniMessage.parse(message, templates) 132 | } else { 133 | miniMessage.parse(message) 134 | } 135 | } 136 | 137 | companion object { 138 | /** 139 | * Init. 140 | * 141 | * @param strict if strict mode is enabled 142 | * @param input the input message 143 | * @param miniMessage the minimessage instance 144 | * @return the debug context 145 | * @since 4.1.0 146 | */ 147 | fun of(strict: Boolean, input: String, miniMessage: MiniMessageImpl): Context { 148 | return Context(strict, null, null, input, null, miniMessage, arrayOf()) 149 | } 150 | 151 | /** 152 | * Init. 153 | * 154 | * @param strict if strict mode is enabled 155 | * @param debugOutput where to print debug output 156 | * @param input the input message 157 | * @param miniMessage the minimessage instance 158 | * @return the debug context 159 | * @since 4.1.0 160 | */ 161 | fun of(strict: Boolean, debugOutput: Appendable?, input: String, miniMessage: MiniMessageImpl): Context { 162 | return Context(strict, debugOutput, null, input, null, miniMessage, arrayOf()) 163 | } 164 | 165 | /** 166 | * Init. 167 | * 168 | * @param strict if strict mode is enabled 169 | * @param input the input message 170 | * @param miniMessage the minimessage instance 171 | * @param templates the templates passed to minimessage 172 | * @return the debug context 173 | * @since 4.1.0 174 | */ 175 | fun of(strict: Boolean, input: String, miniMessage: MiniMessageImpl, templates: Array): Context { 176 | return Context(strict, null, null, input, null, miniMessage, templates) 177 | } 178 | 179 | /** 180 | * Init. 181 | * 182 | * @param strict if strict mode is enabled 183 | * @param debugOutput where to print debug output 184 | * @param input the input message 185 | * @param miniMessage the minimessage instance 186 | * @param templates the templates passed to minimessage 187 | * @return the debug context 188 | * @since 4.2.0 189 | */ 190 | fun of(strict: Boolean, debugOutput: Appendable?, input: String, miniMessage: MiniMessageImpl, templates: Array): Context { 191 | return Context(strict, debugOutput, null, input, null, miniMessage, templates) 192 | } 193 | } 194 | 195 | init { 196 | this.root = root 197 | this.ogMessage = ogMessage 198 | this.replacedMessage = replacedMessage 199 | this.miniMessage = miniMessage 200 | this.templates = templates 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/markdown/MiniMarkdownParser.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.markdown 25 | 26 | import net.kyori.adventure.text.minimessage.Tokens 27 | 28 | /** 29 | * Internal class for markdown handling. 30 | * 31 | * @since 4.0.0 32 | */ 33 | object MiniMarkdownParser { 34 | /** 35 | * Strip any markdown formatting that would be interpreted by `markdownFlavor`. 36 | * 37 | * @param input the input string 38 | * @param markdownFlavor markdown flavor to test against 39 | * @return the stripped input 40 | * @since 4.1.0 41 | */ 42 | fun stripMarkdown(input: String, markdownFlavor: MarkdownFlavor): String { 43 | return handle(input, true, markdownFlavor) 44 | } 45 | 46 | /** 47 | * Parse the markdown input and return it as a MiniMessage string. 48 | * 49 | * @param input the input string 50 | * @param markdownFlavor the flavour of markdown to recognize 51 | * @return a modified string 52 | * @since 4.1.0 53 | */ 54 | fun parse(input: String, markdownFlavor: MarkdownFlavor): String { 55 | return handle(input, false, markdownFlavor) 56 | } 57 | 58 | private fun handle(input: String, strip: Boolean, markdownFlavor: MarkdownFlavor): String { 59 | val sb = StringBuilder() 60 | var bold = -1 61 | var boldSkip: Insert? = null 62 | var italic = -1 63 | var italicSkip: Insert? = null 64 | var underline = -1 65 | var underlineSkip: Insert? = null 66 | var strikeThrough = -1 67 | var strikeThroughSkip: Insert? = null 68 | var obfuscate = -1 69 | var obfuscateSkip: Insert? = null 70 | val inserts: MutableList = ArrayList() 71 | var skip = 0 72 | var i = 0 73 | while(i + skip < input.length) { 74 | val currIndex = i + skip 75 | val c: Char = input[currIndex] 76 | val n = next(currIndex, input) 77 | var shouldSkip = false 78 | if(markdownFlavor.isBold(c, n)) { 79 | if(bold == -1) { 80 | bold = sb.length 81 | boldSkip = Insert(sb.length, c.toString() + "") 82 | } else { 83 | inserts.add(Insert(bold, "<" + Tokens.BOLD + ">")) 84 | inserts.add(Insert(sb.length, "")) 85 | bold = -1 86 | } 87 | skip += if(c == n) 1 else 0 88 | shouldSkip = true 89 | } else if(markdownFlavor.isItalic(c, n)) { 90 | if(italic == -1) { 91 | italic = sb.length 92 | italicSkip = Insert(sb.length, c.toString() + "") 93 | } else { 94 | inserts.add(Insert(italic, "<" + Tokens.ITALIC + ">")) 95 | inserts.add(Insert(sb.length, "")) 96 | italic = -1 97 | } 98 | skip += if(c == n) 1 else 0 99 | shouldSkip = true 100 | } else if(markdownFlavor.isUnderline(c, n)) { 101 | if(underline == -1) { 102 | underline = sb.length 103 | underlineSkip = Insert(sb.length, c.toString() + "") 104 | } else { 105 | inserts.add(Insert(underline, "<" + Tokens.UNDERLINED + ">")) 106 | inserts.add(Insert(sb.length, "")) 107 | underline = -1 108 | } 109 | skip += if(c == n) 1 else 0 110 | shouldSkip = true 111 | } else if(markdownFlavor.isStrikeThrough(c, n)) { 112 | if(strikeThrough == -1) { 113 | strikeThrough = sb.length 114 | strikeThroughSkip = Insert(sb.length, c.toString() + "") 115 | } else { 116 | inserts.add(Insert(strikeThrough, "<" + Tokens.STRIKETHROUGH + ">")) 117 | inserts.add(Insert(sb.length, "")) 118 | strikeThrough = -1 119 | } 120 | skip += if(c == n) 1 else 0 121 | shouldSkip = true 122 | } else if(markdownFlavor.isObfuscate(c, n)) { 123 | if(obfuscate == -1) { 124 | obfuscate = sb.length 125 | obfuscateSkip = Insert(sb.length, c.toString() + "") 126 | } else { 127 | inserts.add(Insert(obfuscate, "<" + Tokens.OBFUSCATED + ">")) 128 | inserts.add(Insert(sb.length, "")) 129 | obfuscate = -1 130 | } 131 | skip += if(c == n) 1 else 0 132 | shouldSkip = true 133 | } 134 | if(!shouldSkip) { 135 | sb.append(c) 136 | } 137 | i++ 138 | } 139 | if(strip) { 140 | inserts.clear() 141 | } else { 142 | inserts.sortedWith(compareBy { obj: Insert -> obj.pos() }.thenByDescending { obj: Insert -> obj.value() }) 143 | } 144 | if(underline != -1) { 145 | inserts.add(underlineSkip!!) 146 | } 147 | if(bold != -1) { 148 | inserts.add(boldSkip!!) 149 | } 150 | if(italic != -1) { 151 | inserts.add(italicSkip!!) 152 | } 153 | if(strikeThrough != -1) { 154 | inserts.add(strikeThroughSkip!!) 155 | } 156 | if(obfuscate != -1) { 157 | inserts.add(obfuscateSkip!!) 158 | } 159 | for(el in inserts) { 160 | sb.insert(el.pos(), el.value()) 161 | } 162 | return sb.toString() 163 | } 164 | 165 | private fun next(index: Int, input: String): Char { 166 | return if(index < input.length - 1) { 167 | input[index + 1] 168 | } else { 169 | ' ' 170 | } 171 | } 172 | 173 | internal class Insert(private val pos: Int, private val value: String) { 174 | fun pos(): Int { 175 | return pos 176 | } 177 | 178 | fun value(): String { 179 | return value 180 | } 181 | 182 | override fun toString(): String { 183 | return "Insert(pos=$pos, value='$value')" 184 | } 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/transformation/inbuild/RainbowTransformation.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage.transformation.inbuild 25 | 26 | import kotlin.math.PI 27 | import kotlin.math.sin 28 | import net.kyori.adventure.text.minimessage.Tokens 29 | import net.kyori.adventure.text.minimessage.helper.Component 30 | import net.kyori.adventure.text.minimessage.helper.TextColor 31 | import net.kyori.adventure.text.minimessage.helper.TextComponent 32 | import net.kyori.adventure.text.minimessage.parser.ParsingException 33 | import net.kyori.adventure.text.minimessage.parser.node.ElementNode 34 | import net.kyori.adventure.text.minimessage.parser.node.TagPart 35 | import net.kyori.adventure.text.minimessage.parser.node.ValueNode 36 | import net.kyori.adventure.text.minimessage.transformation.Modifying 37 | import net.kyori.adventure.text.minimessage.transformation.Transformation 38 | import net.kyori.adventure.text.minimessage.transformation.TransformationParser 39 | 40 | /** 41 | * Applies rainbow color to a component. 42 | * 43 | * @since 4.1.0 44 | */ 45 | class RainbowTransformation private constructor() : Transformation(), Modifying { 46 | private var size = 0 47 | private var disableApplyingColorDepth = -1 48 | private var colorIndex = 0 49 | private var center = 128f 50 | private var width = 127f 51 | private var frequency = 1.0 52 | private var phase = 0 53 | 54 | override fun load(name: String, args: List) { 55 | super.load(name, args) 56 | if(args.size == 1) { 57 | try { 58 | phase = args[0].value().toInt() 59 | } catch(ex: NumberFormatException) { 60 | throw ParsingException("Expected phase, got " + args[0], *this.argTokenArray()) 61 | } 62 | } 63 | } 64 | 65 | override fun visit(curr: ElementNode?) { 66 | if(curr is ValueNode) { 67 | val value: String = curr.value() 68 | size += value.length 69 | } 70 | } 71 | 72 | override fun apply(): Component { 73 | // init 74 | center = 128f 75 | width = 127f 76 | frequency = PI * 2 / size 77 | return Component.empty() 78 | } 79 | 80 | override fun apply(current: Component, depth: Int): Component { 81 | if(disableApplyingColorDepth != -1 && depth >= disableApplyingColorDepth || current.style().color() != null) { 82 | if(disableApplyingColorDepth == -1) { 83 | disableApplyingColorDepth = depth 84 | } 85 | // This component has it's own color applied, which overrides ours 86 | // We still want to keep track of where we are though if this is text 87 | if(current is TextComponent && current.content != null && current.content!!.isNotBlank()) { 88 | val content: String = current.content!! 89 | val len: Int = content.length 90 | for(i in 0 until len) { 91 | // increment our color index 92 | color(phase.toFloat()) 93 | } 94 | } 95 | return current 96 | } 97 | disableApplyingColorDepth = -1 98 | if(current is TextComponent && current.content != null && current.content!!.isNotBlank()) { 99 | val textComponent: TextComponent = current 100 | val content: String = textComponent.content!! 101 | var parent: Component = Component.empty() 102 | 103 | // apply 104 | val holder = CharArray(1) 105 | val it = content.toCharArray().iterator() 106 | while(it.hasNext()) { 107 | holder[0] = it.nextChar() 108 | val comp: Component = Component.text(holder.concatToString(0, 1), color(phase.toFloat())) 109 | parent = parent.append(comp) 110 | } 111 | return parent 112 | } 113 | return Component.empty().mergeStyle(current) 114 | } 115 | 116 | private fun color(phase: Float): TextColor { 117 | val index = colorIndex++ 118 | val red = (sin(frequency * index + 2 + phase) * width + center).toInt() 119 | val green = (sin(frequency * index + 0 + phase) * width + center).toInt() 120 | val blue = (sin(frequency * index + 4 + phase) * width + center).toInt() 121 | return TextColor.color(red, green, blue) 122 | } 123 | 124 | override fun toString(): String { 125 | return "RainbowTransformation(size=$size, disableApplyingColorDepth=$disableApplyingColorDepth, colorIndex=$colorIndex, center=$center, width=$width, frequency=$frequency, phase=$phase)" 126 | } 127 | 128 | override fun equals(o: Any?): Boolean { 129 | if(this === o) return true 130 | if(o == null || this::class.js != o::class.js) return false 131 | if(!super.equals(o)) return false 132 | 133 | o as RainbowTransformation 134 | 135 | if(size != o.size) return false 136 | if(disableApplyingColorDepth != o.disableApplyingColorDepth) return false 137 | if(colorIndex != o.colorIndex) return false 138 | if(center != o.center) return false 139 | if(width != o.width) return false 140 | if(frequency != o.frequency) return false 141 | if(phase != o.phase) return false 142 | 143 | return true 144 | } 145 | 146 | override fun hashCode(): Int { 147 | var result = super.hashCode() 148 | result = 31 * result + size 149 | result = 31 * result + disableApplyingColorDepth 150 | result = 31 * result + colorIndex 151 | result = 31 * result + center.hashCode() 152 | result = 31 * result + width.hashCode() 153 | result = 31 * result + frequency.hashCode() 154 | result = 31 * result + phase 155 | return result 156 | } 157 | 158 | /** 159 | * Factory for [RainbowTransformation] instances. 160 | * 161 | * @since 4.1.0 162 | */ 163 | class Parser : TransformationParser { 164 | 165 | override fun parse(): RainbowTransformation { 166 | return RainbowTransformation() 167 | } 168 | } 169 | 170 | companion object { 171 | /** 172 | * Get if this transformation can handle the provided tag name. 173 | * 174 | * @param name tag name to test 175 | * @return if this transformation is applicable 176 | * @since 4.1.0 177 | */ 178 | fun canParse(name: String): Boolean { 179 | return name.equals(Tokens.RAINBOW, true) 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /src/main/kotlin/main.kt: -------------------------------------------------------------------------------- 1 | 2 | import kotlinext.js.asJsObject 3 | import kotlinx.browser.document 4 | import kotlinx.browser.window 5 | import kotlinx.dom.hasClass 6 | import net.kyori.adventure.text.minimessage.MiniMessage 7 | import org.w3c.dom.Element 8 | import org.w3c.dom.HTMLAnchorElement 9 | import org.w3c.dom.HTMLDivElement 10 | import org.w3c.dom.HTMLElement 11 | import org.w3c.dom.HTMLPreElement 12 | import org.w3c.dom.HTMLSelectElement 13 | import org.w3c.dom.HTMLTextAreaElement 14 | import org.w3c.dom.asList 15 | import org.w3c.dom.get 16 | import org.w3c.dom.url.URLSearchParams 17 | 18 | enum class Mode { 19 | CHAT_OPEN, CHAT_CLOSED, LORE, HOLOGRAM, BOOK; 20 | 21 | val className = "mode-${name.lowercase().replace('_', '-')}" 22 | val paramName = name.lowercase() 23 | 24 | companion object { 25 | val default = CHAT_CLOSED 26 | val modes = values().asList() 27 | val index = modes.associateBy { it.name } 28 | 29 | /** Gets a mode from [string], returning [CHAT_CLOSED] as a default. */ 30 | fun fromString(string: String?): Mode = index[string?.uppercase()] ?: default 31 | } 32 | } 33 | 34 | val homeUrl by lazy { window.location.href.split('?')[0] } 35 | lateinit var currentMode: Mode 36 | 37 | // thanks kotlin you rock 38 | external fun decodeURIComponent(encodedURI: String): String 39 | external fun encodeURIComponent(string: String): String 40 | 41 | const val PARAM_INPUT = "input" 42 | const val PARAM_MODE = "mode" 43 | 44 | fun main() { 45 | document.addEventListener("DOMContentLoaded", { 46 | // CORRECT HOME LINK 47 | document.getElementById("home-link")!!.asJsObject().unsafeCast().href = homeUrl 48 | 49 | // SHARING 50 | val inputBox = document.getElementById("input")!!.asJsObject().unsafeCast() 51 | val urlParams = URLSearchParams(window.location.search) 52 | val outputPre = document.getElementById("output-pre")!!.asJsObject().unsafeCast() 53 | val outputPane = document.getElementById("output-pane")!!.asJsObject().unsafeCast() 54 | 55 | currentMode = Mode.fromString(urlParams.get(PARAM_MODE)) 56 | outputPre.classList.add(currentMode.className) 57 | outputPane.classList.add(currentMode.className) 58 | 59 | urlParams.get(PARAM_INPUT)?.also { inputString -> 60 | val text = decodeURIComponent(inputString) 61 | inputBox.innerText = text 62 | println("SHARED: $text") 63 | parse(text) 64 | } 65 | 66 | // INPUT 67 | val input = document.getElementById("input")!!.asJsObject().unsafeCast() 68 | input.addEventListener("keyup", { 69 | parse(input.value) 70 | }) 71 | input.addEventListener("change", { 72 | parse(input.value) 73 | }) 74 | 75 | // OBFUSCATION 76 | window.setInterval( { obfuscateAll() }, 10) 77 | 78 | // CARET 79 | val chatBox = document.getElementById("chat-entry-box")!!.asJsObject().unsafeCast() 80 | window.setInterval({ 81 | chatBox.innerHTML = if (chatBox.innerHTML == "_") " " else "_" 82 | }, 380) 83 | 84 | // BUTTONS 85 | val settingsBox = document.getElementById("settings-box") 86 | document.getElementsByClassName("settings-button").asList().forEach { element -> 87 | element.addEventListener("click", { 88 | settingsBox!!.classList.toggle("is-active") 89 | }) 90 | } 91 | 92 | val modeButtons = document.getElementsByClassName("mc-mode").asList().unsafeCast>() 93 | modeButtons.forEach { element -> 94 | // set is-active on the current mode first 95 | val mode = Mode.valueOf(element.dataset["mode"]!!) 96 | if (currentMode == mode) { 97 | element.classList.add("is-active") 98 | } 99 | 100 | // then add event listeners for the rest 101 | element.addEventListener("click", { event -> 102 | // remove active 103 | modeButtons.forEach { button -> 104 | button.classList.remove("is-active") 105 | } 106 | 107 | // now add it again lmao 10/10 code 108 | val button = event.target!!.asJsObject().unsafeCast() 109 | button.classList.add("is-active") 110 | currentMode = mode 111 | 112 | // swap the class for the pane 113 | Mode.modes.forEach { mode -> 114 | if (currentMode == mode) { 115 | outputPre.classList.add(mode.className) 116 | outputPane.classList.add(mode.className) 117 | } else { 118 | outputPre.classList.remove(mode.className) 119 | outputPane.classList.remove(mode.className) 120 | } 121 | } 122 | }) 123 | } 124 | 125 | // CLIPBOARD 126 | val shareButton = document.getElementById("share-button")!!.asJsObject().unsafeCast() 127 | val shareBox = document.getElementById("share-box")!!.asJsObject().unsafeCast() 128 | shareButton.addEventListener("click", { 129 | window.navigator.clipboard.writeText("$homeUrl?$PARAM_MODE=${currentMode.paramName}&$PARAM_INPUT=${encodeURIComponent(input.value)}").then { 130 | shareBox.classList.add("is-active") 131 | } 132 | }) 133 | document.getElementsByClassName("close-share-box").asList().unsafeCast>().forEach { element -> 134 | element.addEventListener("click", { 135 | shareBox.classList.remove("is-active") 136 | }) 137 | } 138 | 139 | // BURGER MENU 140 | val burgerMenu = document.getElementById("burger-menu")!! 141 | val navbarMenu = document.getElementById("navbar-menu")!! 142 | burgerMenu.addEventListener("click", { 143 | burgerMenu.classList.toggle("is-active") 144 | navbarMenu.classList.toggle("is-active") 145 | }) 146 | 147 | // SETTINGS 148 | val settingBackground = document.getElementById("setting-background")!!.asJsObject().unsafeCast() 149 | settingBackground.addEventListener("change", { 150 | outputPane.style.backgroundImage = "url(\"img/${settingBackground.value}.png\")" 151 | }) 152 | }) 153 | } 154 | 155 | fun obfuscateAll() { 156 | document.getElementsByClassName("obfuscated").asList().forEach { 157 | obfuscate(it) 158 | } 159 | } 160 | 161 | fun obfuscate(input: Element) { 162 | if (input.hasClass("hover")) return 163 | if (input.childElementCount > 0) { 164 | input.children.asList().forEach { 165 | obfuscate(it) 166 | } 167 | } else if (input.textContent != null){ 168 | input.textContent = obfuscate(input.textContent!!) 169 | } 170 | } 171 | 172 | fun CharArray.map(transform: (Char) -> Char): CharArray { 173 | for (i in this.indices) { 174 | this[i] = transform(this[i]) 175 | } 176 | return this 177 | } 178 | 179 | fun obfuscate(input: String): String { 180 | val allowedChars = ('A'..'Z') + ('a'..'z') + ('0'..'9') 181 | 182 | return input.toCharArray() 183 | .map { if (it != ' ') allowedChars.random() else it } 184 | .concatToString() 185 | } 186 | 187 | fun parse(input: String) { 188 | val output = document.getElementById("output-pre")!! 189 | output.textContent = "" 190 | val miniMessage = MiniMessage.builder().debug(object : Appendable { 191 | override fun append(value: Char): Appendable { 192 | print(value) 193 | return this 194 | } 195 | 196 | override fun append(value: CharSequence?): Appendable { 197 | print(value) 198 | return this 199 | } 200 | 201 | override fun append(value: CharSequence?, startIndex: Int, endIndex: Int): Appendable { 202 | TODO("Not yet implemented") 203 | } 204 | 205 | }).parsingErrorMessageConsumer { }.build() 206 | val lines = input.split("\n") 207 | 208 | lines.map { line -> 209 | // we don't want to lose empty lines, so replace them with zero-width space 210 | if (line == "") "\u200B" else line 211 | }.forEach { line -> 212 | println("BEGING PARSING \"$line\"") 213 | val div = document.createElement("div") 214 | div.append(miniMessage.parse(line).buildOutChildren()) 215 | output.append(div) 216 | println("DONE") 217 | } 218 | 219 | // reset scroll to bottom (like how chat works) 220 | if (currentMode == Mode.CHAT_OPEN || currentMode == Mode.CHAT_CLOSED) { 221 | output.scrollTop = output.scrollHeight.toDouble() 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /src/main/kotlin/net/kyori/adventure/text/minimessage/MiniMessageImpl.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of adventure-text-minimessage, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 KyoriPowered 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package net.kyori.adventure.text.minimessage 25 | 26 | import net.kyori.adventure.text.minimessage.MiniMessage.Builder 27 | import net.kyori.adventure.text.minimessage.helper.Component 28 | import net.kyori.adventure.text.minimessage.markdown.MarkdownFlavor 29 | import net.kyori.adventure.text.minimessage.markdown.MiniMarkdownParser 30 | import net.kyori.adventure.text.minimessage.transformation.TransformationRegistry 31 | 32 | /** 33 | * not public api. 34 | * 35 | * @since 4.0.0 36 | */ 37 | class MiniMessageImpl internal constructor(private val markdown: Boolean, markdownFlavor: MarkdownFlavor, registry: TransformationRegistry, placeholderResolver: (String) -> Component?, strict: Boolean, debugOutput: Appendable?, parsingErrorMessageConsumer: (List) -> Unit) : MiniMessage { 38 | private val markdownFlavor: MarkdownFlavor 39 | private val parser: MiniMessageParser 40 | private val strict: Boolean 41 | private val debugOutput: Appendable? 42 | private val parsingErrorMessageConsumer: (List) -> Unit 43 | 44 | override fun deserialize(input: String): Component { 45 | var input = input 46 | if(markdown) { 47 | input = MiniMarkdownParser.parse(input, markdownFlavor) 48 | } 49 | return parser.parseFormat(input, Context.of(strict, debugOutput, input, this)) 50 | } 51 | 52 | override fun parse(input: String, vararg placeholders: String): Component { 53 | var input = input 54 | if(markdown) { 55 | input = MiniMarkdownParser.parse(input, markdownFlavor) 56 | } 57 | return parser.parseFormat(input, Context.of(strict, debugOutput, input, this), *placeholders) 58 | } 59 | 60 | override fun parse(input: String, placeholders: Map): Component { 61 | var input = input 62 | if(markdown) { 63 | input = MiniMarkdownParser.parse(input, markdownFlavor) 64 | } 65 | return parser.parseFormat(input, placeholders, Context.of(strict, debugOutput, input, this)) 66 | } 67 | 68 | override fun parse(input: String, vararg placeholders: Any): Component { 69 | val templates: MutableList