Skip to content

Commit

Permalink
generify keyboard layout, start implementing #172
Browse files Browse the repository at this point in the history
  • Loading branch information
breandan committed Oct 31, 2018
1 parent 868b7ba commit 8e5d676
Show file tree
Hide file tree
Showing 10 changed files with 59 additions and 50 deletions.
5 changes: 2 additions & 3 deletions src/main/kotlin/org/acejump/config/AceConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import com.intellij.openapi.components.State
import com.intellij.openapi.components.Storage
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.options.Configurable
import org.acejump.label.Pattern
import javax.swing.JComponent

/* Persists the state of the AceJump IDE settings across IDE restarts.
Expand Down Expand Up @@ -40,12 +39,12 @@ object AceConfig : Configurable, PersistentStateComponent<AceSettings> {
panel.tagBackgroundColor != settings.tagBackgroundColor

private fun String.distinctAlphanumerics() = toList().distinct().run {
if (isEmpty()) Pattern.defaultChars else filter { it.isLetterOrDigit() }
if (isEmpty()) settings.keyLayout.chars else filter { it.isLetterOrDigit() }
}.joinToString("")

override fun apply() {
settings.allowedChars = panel.allowedChars.distinctAlphanumerics()
settings.keyboardChars = panel.keyboardChars.distinctAlphanumerics()
settings.keyboardChars = panel.keyboardChars
panel.jumpModeColor?.let { settings.jumpModeRGB = it.rgb }
panel.targetModeColor?.let { settings.targetModeRGB = it.rgb }
panel.textHighlightColor?.let { settings.textHighlightRGB = it.rgb }
Expand Down
7 changes: 4 additions & 3 deletions src/main/kotlin/org/acejump/config/AceSettings.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package org.acejump.config

import org.acejump.label.Pattern
import org.acejump.label.Pattern.Companion.KeyLayout
import java.awt.Color
import java.awt.Color.*
import kotlin.reflect.KProperty

data class AceSettings(var allowedChars: String = Pattern.defaultChars.joinToString(""),
var keyboardChars: String = Pattern.keyboardKeys,
data class AceSettings(var keyLayout: KeyLayout = KeyLayout.QWERTY,
var allowedChars: String = keyLayout.toString(),
var keyboardChars: String = keyLayout.keyboard(),
// These must be primitives in order to be serializable
internal var jumpModeRGB: Int = BLUE.rgb,
internal var targetModeRGB: Int = RED.rgb,
Expand Down
28 changes: 17 additions & 11 deletions src/main/kotlin/org/acejump/config/AceSettingsPanel.kt
Original file line number Diff line number Diff line change
@@ -1,36 +1,42 @@
package org.acejump.config

import com.intellij.ui.ColorPanel
import com.intellij.ui.SeparatorComponent
import com.intellij.ui.layout.Cell
import com.intellij.ui.layout.GrowPolicy.MEDIUM_TEXT
import com.intellij.ui.layout.GrowPolicy.SHORT_TEXT
import com.intellij.ui.layout.panel
import org.acejump.search.aceString
import java.awt.Color
import java.awt.Font
import javax.swing.JComponent
import javax.swing.JPanel
import javax.swing.JTextArea
import javax.swing.JTextField
import kotlin.reflect.KProperty

class AceSettingsPanel {
private var tagCharactersField = JTextField()
private var jumpModeColorWheel = ColorPanel()
private var targetModeColorWheel = ColorPanel()
private var textHighlightColorWheel = ColorPanel()
private var tagForegroundColorWheel = ColorPanel()
private var tagBackgroundColorWheel = ColorPanel()
private var keyboardCharsLayout = JTextArea()
private val tagCharactersField =
JTextField().apply { font = Font("monospaced", font.style, font.size) }
private val jumpModeColorWheel = ColorPanel()
private val targetModeColorWheel = ColorPanel()
private val textHighlightColorWheel = ColorPanel()
private val tagForegroundColorWheel = ColorPanel()
private val tagBackgroundColorWheel = ColorPanel()
private val keyboardCharsLayout = JTextArea()
.apply {
font = Font("monospaced", font.style, font.size)
isEditable = false
}

internal val rootPanel: JPanel = panel {
fun Cell.short(component: JComponent) = component(growPolicy = SHORT_TEXT)
fun Cell.medium(component: JComponent) = component(growPolicy = MEDIUM_TEXT)

noteRow(aceString("tagCharsToBeUsedHeading"))
noteRow(aceString("tagCharsToBeUsedHeading")) { SeparatorComponent() }
row(aceString("tagCharsToBeUsedLabel")) { medium(tagCharactersField) }
noteRow("Alphanumeric Keyboard Characters from top to bottom")
row("Keyboard keys") { medium(keyboardCharsLayout) }
noteRow(aceString("colorsToBeUsedHeading"))
row("Keyboard layout") { medium(keyboardCharsLayout) }
noteRow(aceString("colorsToBeUsedHeading")) { SeparatorComponent() }
row(aceString("jumpModeColorLabel")) { short(jumpModeColorWheel) }
row(aceString("tagBackgroundColorLabel")) { short(tagBackgroundColorWheel) }
row(aceString("tagForegroundColorLabel")) { short(tagForegroundColorWheel) }
Expand Down
44 changes: 20 additions & 24 deletions src/main/kotlin/org/acejump/label/Pattern.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.acejump.label

import org.acejump.config.AceConfig
import org.acejump.search.mapIndices

/**
* Patterns related to key priority, separation, and regexps for line mode.
Expand All @@ -18,8 +19,6 @@ enum class Pattern(val string: String) {
companion object {
private fun distance(fromKey: Char, toKey: Char) = nearby[fromKey]!![toKey]

fun priority(char: Char) = priority[char]

private var allBigrams = emptyList<String>()
get() = AceConfig.settings.allowedChars
.run { flatMap { e -> map { c -> "$e$c" } } }
Expand All @@ -31,21 +30,12 @@ enum class Pattern(val string: String) {
var NUM_CHARS: Int = 36
get() = AceConfig.settings.allowedChars.length

private val priority: Map<Char, Int> =
"fjghdkslavncmbxzrutyeiwoqp5849673210".mapIndices()

val defaultChars = ('a'..'z').plus('0'..'9').sortedBy { priority[it] }
val keyboardKeys = """
12345890
qwertyuiop
asdfghjkl
zxcvbnm
""".trimIndent()

val defaultOrder: Comparator<String> = compareBy(
val defaultTagOrder: Comparator<String> = compareBy(
{ it[0].isDigit() || it[1].isDigit() },
{ Pattern.distance(it[0], it.last()) },
{ Pattern.priority(it[0]) })
AceConfig.settings.keyLayout.priority { it[0] })

fun filterTags(query: String) = allBigrams.filter { !query.endsWith(it[0]) }

/**
* Sorts available tags by key distance. Tags which are ergonomically easier
Expand All @@ -54,14 +44,22 @@ enum class Pattern(val string: String) {
* keys (ex. 12, 21) to keys that are located further apart on the keyboard.
*/

fun filterTags(query: String) = allBigrams.filter { !query.endsWith(it[0]) }
enum class KeyLayout(val text: Array<String>) {
COLEMAK(arrayOf("1234567890", "qwfpgjluy", "arstdhneio", "zxcvbkm")),
DVORAK(arrayOf("1234567890", "pyfgcrl", "aoeuidhtns", "qjkxbmwvz")),
QWERTY(arrayOf("1234567890", "qwertyuiop", "asdfghjkl", "zxcvbnm")),
WORKMAN(arrayOf("1234567890", "qdrwbjfup", "ashtgyneoi", "zxmcvkl"));

// TODO: Currently specialized to QWERTY, need to make this more generic
private val priority = "fjghdkslavncmbxzrutyeiwoqp5849673210".mapIndices()
val chars = text.flatMap { it.toList() }.sortedBy { priority[it] }

private val defaultKeyboardLayout = arrayOf(
"1234567890",
"qwertyuiop",
"asdfghjkl",
"zxcvbnm"
)
fun priority(tagToChar: (String) -> Char): (String) -> Int? =
{ priority[tagToChar(it)] }

fun keyboard() = text.joinToString("\n")
override fun toString() = chars.joinToString("")
}

private val nearby: Map<Char, Map<Char, Int>> = mapOf(
// Values are QWERTY keys sorted by physical proximity to the map key
Expand Down Expand Up @@ -102,7 +100,5 @@ enum class Pattern(val string: String) {
'9' to "9807654321ioujklpyhnmtgbrfvedcwsxqaz",
'0' to "0987654321opiklujmyhntgbrfvedcwsxqaz")
.mapValues { it.value.mapIndices() }

private fun String.mapIndices() = mapIndexed { i, c -> Pair(c, i) }.toMap()
}
}
7 changes: 4 additions & 3 deletions src/main/kotlin/org/acejump/label/Solver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import com.google.common.collect.Multimaps
import com.google.common.collect.Ordering
import com.google.common.collect.TreeMultimap
import com.intellij.openapi.diagnostic.Logger
import org.acejump.label.Pattern.Companion.defaultOrder
import org.acejump.config.AceConfig
import org.acejump.label.Pattern.Companion.defaultTagOrder
import org.acejump.search.wordBoundsPlus
import org.acejump.view.Model.editorText
import org.acejump.view.Model.viewBounds
Expand Down Expand Up @@ -69,9 +70,9 @@ object Solver {
return true
}

private val tagOrder = defaultOrder
private val tagOrder = defaultTagOrder
.thenBy { eligibleSitesByTag[it].size }
.thenBy { Pattern.priority(it.last()) }
.thenBy(AceConfig.settings.keyLayout.priority { it.last() })

/**
* Sorts jump targets to determine which positions get first choice for tags,
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/org/acejump/label/Tagger.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.acejump.label

import com.intellij.openapi.diagnostic.Logger
import org.acejump.label.Pattern.Companion.defaultOrder
import org.acejump.label.Pattern.Companion.defaultTagOrder
import org.acejump.label.Pattern.Companion.filterTags
import org.acejump.search.*
import org.acejump.search.Jumper.hasJumped
Expand Down Expand Up @@ -236,7 +236,7 @@ object Tagger : Resettable {
}

private fun solveRegex(vacantResults: List<Int>, availableTags: Set<String>) =
availableTags.sortedWith(defaultOrder).zip(vacantResults).toMap()
availableTags.sortedWith(defaultTagOrder).zip(vacantResults).toMap()

/**
* Adds pre-existing tags where search string and tag overlap. For example,
Expand Down
2 changes: 2 additions & 0 deletions src/main/kotlin/org/acejump/search/AceUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ interface Resettable {

fun aceString(s: String) = ResourceBundle.getBundle("AceResources").getString(s)

fun String.mapIndices() = mapIndexed { i, c -> Pair(c, i) }.toMap()

fun <P> applyTo(vararg ps: P, fx: P.() -> Unit) = ps.forEach { it.fx() }

operator fun Point.component1() = x
Expand Down
2 changes: 2 additions & 0 deletions src/main/kotlin/org/acejump/view/Model.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import java.awt.Font.PLAIN

/**
* Data holder for all settings and IDE components needed by AceJump.
*
* TODO: Integrate this class with AceSettings.
*/

object Model {
Expand Down
4 changes: 2 additions & 2 deletions src/main/resources/AceResources.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
tagCharsToBeUsedHeading=Characters to be used when tagging (only alphanumeric characters, sorted from highest to lowest priority):
tagCharsToBeUsedLabel=Characters to be use:
tagCharsToBeUsedHeading=Characters to be used when tagging
tagCharsToBeUsedLabel=Priority (highest to lowest):
colorsToBeUsedHeading=Colors to be used when tagging
jumpModeColorLabel=Jump mode color:
tagBackgroundColorLabel=Tag background color:
Expand Down
6 changes: 4 additions & 2 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ Bug fix: AceJump settings should now properly persist after restarting the IDE.
</application-components>

<extensions defaultExtensionNs="com.intellij">
<applicationService serviceInterface="org.acejump.config.AceConfig" serviceImplementation="org.acejump.config.AceConfig" overrides="true"/>
<applicationConfigurable groupId="tools" displayName="AceJump" id="preferences.AceConfigurable" instance="org.acejump.config.AceConfig"/>
<applicationService serviceImplementation="org.acejump.config.AceConfig"/>
<applicationConfigurable groupId="tools" displayName="AceJump"
id="preferences.AceConfigurable"
instance="org.acejump.config.AceConfig"/>
</extensions>

<actions>
Expand Down

0 comments on commit 8e5d676

Please sign in to comment.