1
0
mirror of https://github.com/chylex/IntelliJ-Rainbow-Brackets.git synced 2025-05-14 12:34:03 +02:00

Initial commit for remove Nashorn Engine

This commit is contained in:
张志豪 2021-07-11 13:24:28 +08:00
parent 715fca803f
commit 5777d7bace
7 changed files with 327 additions and 15 deletions

View File

@ -1,5 +1,6 @@
package com.github.izhangzhihao.rainbow.brackets
import com.github.izhangzhihao.rainbow.brackets.fromRGBstr
import com.github.izhangzhihao.rainbow.brackets.settings.RainbowSettings
import com.github.izhangzhihao.rainbow.brackets.util.memoize
import com.intellij.codeInsight.daemon.impl.HighlightInfo
@ -132,7 +133,7 @@ object RainbowHighlighter {
}
private fun genByOption(option: String) =
TextAttributes(Color.decode(RandomColorGenerator.randomColor(option)), null, null, null, 0)
TextAttributes(fromRGBstr(randomColor(option)), null, null, null, 0)
val memGetRainbowColorByLevel = { isDark: Boolean, rainbowName: String, level: Int -> generateColor(isDark, rainbowName, level) }.memoize()

View File

@ -1,20 +1,27 @@
package com.github.izhangzhihao.rainbow.brackets
import jdk.nashorn.api.scripting.JSObject
import jdk.nashorn.api.scripting.NashornScriptEngineFactory
import javax.script.Invocable
import javax.script.ScriptEngine
import com.github.izhangzhihao.rainbow.brackets.color.Luminosity
import com.github.izhangzhihao.rainbow.brackets.color.fromString
import org.json.JSONObject
import java.awt.Color
object RandomColorGenerator {
private val engine: ScriptEngine by lazy { NashornScriptEngineFactory().getScriptEngine() }
private val invocable: Invocable by lazy {
engine.eval(javaClass.classLoader.getResource("randomColor.js").readText())
engine as Invocable
}
fun randomColor(options: String): String {
val options = JSONObject(options)
return com.github.izhangzhihao.rainbow.brackets.color.randomColor(
fromString(options.getStringOrDefault("hue", "random")),
Luminosity.valueOf(options.getStringOrDefault("luminosity", "random"))
)
}
fun randomColor(options: String): String {
engine.put("paras", options)
val obj = engine.eval("JSON.parse(paras)") as JSObject
return invocable.invokeFunction("randomColor", obj).toString()
fun org.json.JSONObject.getStringOrDefault(key: String, default: String): String {
return try {
this.getString(key)
} catch (e: Exception) {
default
}
}
fun fromRGBstr(str: String): Color {
val split = str.trimStart('(').trimEnd(')').split(", ")
return Color(split[0].toInt(), split[1].toInt(), split[2].toInt())
}

View File

@ -0,0 +1,108 @@
package com.github.izhangzhihao.rainbow.brackets.color
import kotlin.math.floor
enum class Color(val hueRange: Pair<Int, Int>, val lowerBounds: List<Pair<Int, Int>>) {
monochrome(
Pair(-1, -1),
listOf(Pair(0, 0), Pair(100, 0))
),
red(
Pair(-26, 18),
listOf(
Pair(20, 100),
Pair(30, 92),
Pair(40, 89),
Pair(50, 85),
Pair(60, 78),
Pair(70, 70),
Pair(80, 60),
Pair(90, 55),
Pair(100, 50)
)
),
orange(
Pair(18, 46),
listOf(Pair(20, 100), Pair(30, 93), Pair(40, 88), Pair(50, 86), Pair(60, 85), Pair(70, 70), Pair(100, 70))
),
yellow(
Pair(46, 62),
listOf(
Pair(25, 100),
Pair(40, 94),
Pair(50, 89),
Pair(60, 86),
Pair(70, 84),
Pair(80, 82),
Pair(90, 80),
Pair(100, 75)
)
),
green(
Pair(62, 178),
listOf(
Pair(30, 100),
Pair(40, 90),
Pair(50, 85),
Pair(60, 81),
Pair(70, 74),
Pair(80, 64),
Pair(90, 50),
Pair(100, 40)
)
),
blue(
Pair(178, 257),
listOf(
Pair(20, 100),
Pair(30, 86),
Pair(40, 80),
Pair(50, 74),
Pair(60, 60),
Pair(70, 52),
Pair(80, 44),
Pair(90, 39),
Pair(100, 35)
)
),
purple(
Pair(257, 282),
listOf(
Pair(20, 100),
Pair(30, 87),
Pair(40, 79),
Pair(50, 70),
Pair(60, 65),
Pair(70, 59),
Pair(80, 52),
Pair(90, 45),
Pair(100, 42)
)
),
pink(
Pair(282, 334),
listOf(Pair(20, 100), Pair(30, 90), Pair(40, 86), Pair(60, 84), Pair(80, 80), Pair(90, 75), Pair(100, 73))
)
}
fun Color.saturationRange(): Pair<Int, Int> {
return Pair(lowerBounds.first().first, lowerBounds.last().first)
}
fun Color.brightnessRange(saturation: Int): Pair<Int, Int> {
for (i in 0 until lowerBounds.size - 1) {
val s1 = lowerBounds[i].first.toFloat()
val v1 = lowerBounds[i].second.toFloat()
val s2 = lowerBounds[i + 1].first.toFloat()
val v2 = lowerBounds[i + 1].second.toFloat()
if (saturation.toFloat() in s1..s2) {
val m = (v2 - v1) / (s2 - s1)
val b = v1 - m * s1
val minBrightness = m * saturation + b
return Pair(floor(minBrightness).toInt(), 100)
}
}
return Pair(0, 100)
}

View File

@ -0,0 +1,7 @@
package com.github.izhangzhihao.rainbow.brackets.color
enum class Format {
HSL,
RGB,
HEX
}

View File

@ -0,0 +1,23 @@
package com.github.izhangzhihao.rainbow.brackets.color
sealed class Hue
object RandomHue : Hue()
data class NumberHue(val value: Int) : Hue()
data class ColorHue(val color: Color) : Hue()
fun Hue.getHueRange(): Pair<Int, Int> {
return when (this) {
is ColorHue -> color.hueRange
is NumberHue -> if (value in 1..359) Pair(value, value) else Pair(0, 360)
RandomHue -> Pair(0, 360)
}
}
fun fromString(str: String): Hue {
return when (str) {
"random" -> RandomHue
is String -> ColorHue(Color.valueOf(str))
else -> TODO()
}
}

View File

@ -0,0 +1,8 @@
package com.github.izhangzhihao.rainbow.brackets.color
enum class Luminosity {
random,
bright,
light,
dark
}

View File

@ -0,0 +1,158 @@
package com.github.izhangzhihao.rainbow.brackets.color
import kotlin.math.floor
import kotlin.random.Random
/**
* Generate a single random color with specified (or random) hue and luminosity.
*/
fun randomColor(
hue: Hue = RandomHue,
luminosity: Luminosity = Luminosity.random,
format: Format = Format.RGB
): String {
// First we pick a hue (H)
val hueValue = pickHue(hue)
// Then use H to determine saturation (S)
val saturation = pickSaturation(hueValue, hue, luminosity)
// Then use S and H to determine brightness (B)
val brightness = pickBrightness(hueValue, hue, saturation, luminosity)
// Then we return the HSB color in the desired format
return setFormat(hueValue, saturation, brightness, format)
}
private fun pickHue(hue: Hue): Int {
val hueRange = hue.getHueRange()
var hueValue = randomWithin(hueRange)
// Instead of storing red as two separate ranges,
// we group them, using negative numbers
if (hueValue < 0) {
hueValue += 360
}
return hueValue
}
private fun pickSaturation(hueValue: Int, hue: Hue, luminosity: Luminosity): Int {
if (hue == ColorHue(Color.monochrome)) {
return 0
}
val color: Color = matchColor(hueValue, hue)
val sMin = color.saturationRange().first
val sMax = color.saturationRange().second
return when (luminosity) {
Luminosity.random -> randomWithin(Pair(0, 100))
Luminosity.bright -> randomWithin(Pair(55, sMax))
Luminosity.light -> randomWithin(Pair(sMin, 55))
Luminosity.dark -> randomWithin(Pair(sMax - 10, sMax))
}
}
private fun pickBrightness(hueValue: Int, hue: Hue, saturation: Int, luminosity: Luminosity): Int {
val color: Color = matchColor(hueValue, hue)
val bMin = color.brightnessRange(saturation).first
val bMax = color.brightnessRange(saturation).second
return when (luminosity) {
Luminosity.random -> randomWithin(Pair(50, 100)) // I set this to 50 arbitrarily, they look more attractive
Luminosity.bright -> randomWithin(Pair(bMin, bMax))
Luminosity.light -> randomWithin(Pair((bMax + bMin) / 2, bMax))
Luminosity.dark -> randomWithin(Pair(bMin, bMin + 20))
}
}
private fun setFormat(hueValue: Int, saturation: Int, brightness: Int, format: Format): String {
return when (format) {
Format.HSL -> TODO()
Format.RGB -> HSVtoRGB(hueValue, saturation, brightness).toString()
Format.HEX -> TODO()
}
}
private fun HSVtoRGB(hueValue: Int, saturation: Int, brightness: Int): Triple<Int, Int, Int> {
// This doesn't work for the values of 0 and 360
// Here's the hacky fix
// Rebase the h,s,v values
val h: Float = hueValue.coerceIn(1, 359) / 360f
val s = saturation / 100f
val v = brightness / 100f
val hI = floor(h * 6f).toInt()
val f = h * 6f - hI
val p = v * (1f - s)
val q = v * (1f - f * s)
val t = v * (1f - (1f - f) * s)
var r = 256f
var g = 256f
var b = 256f
when (hI) {
0 -> {
r = v; g = t; b = p
}
1 -> {
r = q; g = v; b = p
}
2 -> {
r = p; g = v; b = t
}
3 -> {
r = p; g = q; b = v
}
4 -> {
r = t; g = p; b = v
}
5 -> {
r = v; g = p; b = q
}
}
return Triple(floor(r * 255f).toInt(), floor(g * 255f).toInt(), floor(b * 255f).toInt())
}
/**
* Turns hue into a color if it isn't already one.
* First we check if hue was passed in as a color, and just return that if it is.
* If not, we iterate through every color to see which one the given hueValue fits in.
* For some reason if a matching hue is not found, just return Monochrome.
*/
private fun matchColor(hueValue: Int, hue: Hue): Color {
return when (hue) {
is ColorHue -> hue.color
else -> {
// Maps red colors to make picking hue easier
var hueVal = hueValue
if (hueVal in 334..360) {
hueVal -= 360
}
for (color in Color.values()) {
if (hueVal in color.hueRange.first..color.hueRange.second) {
return color
}
}
// Returning Monochrome if we can't find a value, but this should never happen
return Color.monochrome
}
}
}
private fun randomWithin(range: Pair<Int, Int>): Int {
// Generate random evenly distinct number from:
// https://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/
val goldenRatio = 0.618033988749895
var r = Random.nextDouble()
r += goldenRatio
r %= 1
return floor(range.first + r * (range.second + 1 - range.first)).toInt()
}