1
0
mirror of https://github.com/chylex/IntelliJ-AceJump.git synced 2025-09-17 10:24:48 +02:00

3 Commits

5 changed files with 86 additions and 53 deletions

View File

@@ -8,7 +8,7 @@ plugins {
} }
group = "org.acejump" group = "org.acejump"
version = "chylex-21" version = "chylex-22"
repositories { repositories {
mavenCentral() mavenCentral()

View File

@@ -14,25 +14,20 @@ enum class KeyLayout(
COLEMK(arrayOf("1234567890", "qwfpgjluy", "arstdhneio", "zxcvbkm"), priority = "tndhseriaovkcmbxzgjplfuwyq5849673210"), COLEMK(arrayOf("1234567890", "qwfpgjluy", "arstdhneio", "zxcvbkm"), priority = "tndhseriaovkcmbxzgjplfuwyq5849673210"),
WORKMN(arrayOf("1234567890", "qdrwbjfup", "ashtgyneoi", "zxmcvkl"), priority = "tnhegysoaiclvkmxzwfrubjdpq5849673210"), WORKMN(arrayOf("1234567890", "qdrwbjfup", "ashtgyneoi", "zxmcvkl"), priority = "tnhegysoaiclvkmxzwfrubjdpq5849673210"),
DVORAK(arrayOf("1234567890", "pyfgcrl", "aoeuidhtns", "qjkxbmwvz"), priority = "uhetidonasxkbjmqwvzgfycprl5849673210"), DVORAK(arrayOf("1234567890", "pyfgcrl", "aoeuidhtns", "qjkxbmwvz"), priority = "uhetidonasxkbjmqwvzgfycprl5849673210"),
QWERTY(arrayOf("1234567890", "qwertyuiop", "asdfghjkl", "zxcvbnm"), priority = "fjghdkslavncmbxzrutyeiwoqp5849673210"), QWERTY(arrayOf("1234567890", "qwertyuiop", "asdfghjkl", "zxcvbnm"), priority = "fjghdkslavncmbxzrutyeiwoqp5849673210", characterSides = sides(listOf("123456", "qwert", "asdfg", "zxcvb"), listOf("7890", "yuiop", "hjkl", "nm"))),
QWERTZ(arrayOf("1234567890", "qwertzuiop", "asdfghjkl", "yxcvbnm"), priority = "fjghdkslavncmbxyrutzeiwoqp5849673210"), QWERTZ(arrayOf("1234567890", "qwertzuiop", "asdfghjkl", "yxcvbnm"), priority = "fjghdkslavncmbxyrutzeiwoqp5849673210", characterSides = sides(listOf("123456", "qwert", "asdfg", "yxcvb"), listOf("7890", "zuiop", "hjkl", "nm"))),
QWERTZ_CZ( QWERTZ_CZ(arrayOf("1234567890", "qwertzuiop", "asdfghjkl", "yxcvbnm"), priority = "fjghdkslavncmbxyrutzeiwoqp5849673210", characterSides = sides(listOf("123456", "qwert", "asdfg", "yxcvb"), listOf("7890", "zuiop", "hjkl", "nm")), characterRemapping = mapOf(
arrayOf("1234567890", "qwertzuiop", "asdfghjkl", "yxcvbnm"), '+' to '1',
priority = "fjghdkslavncmbxyrutzeiwoqp5849673210", 'ě' to '2',
characterSides = sides("", ""), 'š' to '3',
characterRemapping = mapOf( 'č' to '4',
'+' to '1', 'ř' to '5',
'ě' to '2', 'ž' to '6',
'š' to '3', 'ý' to '7',
'č' to '4', 'á' to '8',
'ř' to '5', 'í' to '9',
'ž' to '6', 'é' to '0'
'ý' to '7', )),
'á' to '8',
'í' to '9',
'é' to '0'
)
),
QGMLWY(arrayOf("1234567890", "qgmlwyfub", "dstnriaeoh", "zxcvjkp"), priority = "naterisodhvkcpjxzlfmuwygbq5849673210"), QGMLWY(arrayOf("1234567890", "qgmlwyfub", "dstnriaeoh", "zxcvjkp"), priority = "naterisodhvkcpjxzlfmuwygbq5849673210"),
QGMLWB(arrayOf("1234567890", "qgmlwbyuv", "dstnriaeoh", "zxcfjkp"), priority = "naterisodhfkcpjxzlymuwbgvq5849673210"), QGMLWB(arrayOf("1234567890", "qgmlwbyuv", "dstnriaeoh", "zxcfjkp"), priority = "naterisodhfkcpjxzlymuwbgvq5849673210"),
NORMAN(arrayOf("1234567890", "qwdfkjurl", "asetgynioh", "zxcvbpm"), priority = "tneigysoahbvpcmxzjkufrdlwq5849673210"); NORMAN(arrayOf("1234567890", "qwdfkjurl", "asetgynioh", "zxcvbpm"), priority = "tneigysoahbvpcmxzjkufrdlwq5849673210");
@@ -40,11 +35,18 @@ enum class KeyLayout(
internal val allChars = rows.joinToString("").toCharArray().apply(CharArray::sort).joinToString("") internal val allChars = rows.joinToString("").toCharArray().apply(CharArray::sort).joinToString("")
private val allPriorities = priority.mapIndexed { index, char -> char to index }.toMap() private val allPriorities = priority.mapIndexed { index, char -> char to index }.toMap()
internal fun priority(): (Char) -> Int { fun priority(char: Char): Int {
return { allPriorities.getOrDefault(it, Int.MAX_VALUE) } return allPriorities[char] ?: allChars.length
}
fun areOnSameSide(c1: Char, c2: Char): Boolean {
return (c1 in characterSides.first && c2 in characterSides.first) || (c1 in characterSides.second && c2 in characterSides.second)
} }
} }
private fun sides(left: String, right: String): Pair<Set<Char>, Set<Char>> { private fun sides(left: List<String>, right: List<String>): Pair<Set<Char>, Set<Char>> {
return Pair(left.toCharArray().toSet(), right.toCharArray().toSet()) return Pair(
left.flatMapTo(mutableSetOf()) { it.toCharArray().toSet() },
right.flatMapTo(mutableSetOf()) { it.toCharArray().toSet() }
)
} }

View File

@@ -1,20 +1,22 @@
package org.acejump.input package org.acejump.input
import org.acejump.config.AceSettings import org.acejump.config.AceSettings
import kotlin.math.pow
import kotlin.math.roundToInt
/** /**
* Stores data specific to the selected keyboard layout. We want to assign tags with easily reachable keys first, and ideally have tags * Stores data specific to the selected keyboard layout. We want to assign tags with easily reachable keys first, and ideally have tags
* with repeated keys (ex. FF, JJ) or adjacent keys (ex. GH, UJ). * with repeated keys (ex. FF, JJ) or adjacent keys (ex. GH, UJ).
*/ */
internal object KeyLayoutCache { internal object KeyLayoutCache {
lateinit var allowedCharsSorted: List<Char> lateinit var allowedTagsSorted: List<String>
private set private set
/** /**
* Called before any lazily initialized properties are used, to ensure that they are initialized even if the settings are missing. * Called before any lazily initialized properties are used, to ensure that they are initialized even if the settings are missing.
*/ */
fun ensureInitialized(settings: AceSettings) { fun ensureInitialized(settings: AceSettings) {
if (!::allowedCharsSorted.isInitialized) { if (!::allowedTagsSorted.isInitialized) {
reset(settings) reset(settings)
} }
} }
@@ -23,17 +25,38 @@ internal object KeyLayoutCache {
* Re-initializes cached data according to updated settings. * Re-initializes cached data according to updated settings.
*/ */
fun reset(settings: AceSettings) { fun reset(settings: AceSettings) {
val allowedCharList = processCharList(settings.allowedChars) val allowedChars = processCharList(settings.allowedChars).ifEmpty { processCharList(settings.layout.allChars) }
val allowedTags = mutableSetOf<String>()
allowedCharsSorted = if (allowedCharList.isEmpty()) { for (c1 in allowedChars) {
processCharList(settings.layout.allChars) allowedTags.add("$c1")
}
else { for (c2 in allowedChars) {
allowedCharList.sortedWith(compareBy(settings.layout.priority())) if (c1 != c2) {
allowedTags.add("$c1$c2")
}
}
} }
allowedTagsSorted = allowedTags.sortedBy { rankPriority(settings.layout, it) }
} }
private fun processCharList(charList: String): List<Char> { private fun processCharList(charList: String): List<Char> {
return charList.toCharArray().map(Char::lowercaseChar).distinct() return charList.toCharArray().map(Char::lowercaseChar).distinct()
} }
private fun rankPriority(layout: KeyLayout, tag: String): Int {
val c1 = tag.first()
val p1 = (1.0 + layout.priority(c1)).pow(3)
if (tag.length == 1) {
return p1.roundToInt()
}
val c2 = tag.last()
val p2 = (1.0 + layout.priority(c2)).pow(3)
val multiplier = if (layout.areOnSameSide(c1, c2)) 2 else 1
return (((p1 * 50) + p2 + 1000) * multiplier).roundToInt()
}
} }

View File

@@ -62,28 +62,33 @@ class Tagger(private val editors: List<Editor>, results: Map<Editor, IntList>) {
private companion object { private companion object {
private fun generateTags(tagSites: List<Tag>): List<String> { private fun generateTags(tagSites: List<Tag>): List<String> {
val allowedChars = KeyLayoutCache.allowedCharsSorted
val tags = mutableListOf<String>() val tags = mutableListOf<String>()
var remainingTagCount = tagSites.size
outer@ for (i in allowedChars.indices) { val containedSingleCharTags = mutableSetOf<Char>()
val c1 = allowedChars[i] val blockedSingleCharTags = mutableSetOf<Char>()
if (remainingTagCount <= allowedChars.size - i) { for (tag in KeyLayoutCache.allowedTagsSorted) {
tags.add(c1.toString()) val firstChar = tag.first()
if (--remainingTagCount <= 0) {
break@outer if (tag.length == 1) {
if (firstChar in blockedSingleCharTags) {
continue
} }
containedSingleCharTags.add(firstChar)
} }
else { else {
for (c2 in allowedChars) { if (containedSingleCharTags.remove(firstChar)) {
tags.add("$c1$c2") tags.remove(firstChar.toString())
if (--remainingTagCount <= 0) {
break@outer
}
} }
blockedSingleCharTags.add(firstChar)
}
tags.add(tag)
if (tags.size >= tagSites.size) {
return tags
} }
} }

View File

@@ -12,10 +12,13 @@ import java.awt.Rectangle
* Describes a 1 or 2 character shortcut that points to a specific character in the editor. * Describes a 1 or 2 character shortcut that points to a specific character in the editor.
*/ */
internal class TagMarker( internal class TagMarker(
private val tag: CharArray, private val firstChar: String,
private val secondChar: String,
val offset: Int val offset: Int
) { ) {
private val length = tag.size private constructor(tag: String, offset: Int) : this(tag.first().toString(), tag.drop(1), offset)
private val length = firstChar.length + secondChar.length
companion object { companion object {
/** /**
@@ -28,7 +31,7 @@ internal class TagMarker(
* character ([typedTag]) matches the first [tag] character, only the second [tag] character is displayed. * character ([typedTag]) matches the first [tag] character, only the second [tag] character is displayed.
*/ */
fun create(tag: String, offset: Int, typedTag: String): TagMarker { fun create(tag: String, offset: Int, typedTag: String): TagMarker {
return TagMarker(tag.drop(typedTag.length).toCharArray(), offset) return TagMarker(tag.drop(typedTag.length), offset)
} }
} }
@@ -65,11 +68,11 @@ internal class TagMarker(
g.font = font.tagFont g.font = font.tagFont
g.color = font.foregroundColor1 g.color = font.foregroundColor1
g.drawChars(tag, 0, 1, x, y) g.drawString(firstChar, x, y)
if (tag.size > 1) { if (secondChar.isNotEmpty()) {
g.color = font.foregroundColor2 g.color = font.foregroundColor2
g.drawChars(tag, 1, length - 1, x + font.tagCharWidth, y) g.drawString(secondChar, x + font.tagCharWidth, y)
} }
} }