1
0
mirror of https://github.com/chylex/IntelliJ-Keyboard-Master.git synced 2025-05-07 17:34:07 +02:00

Make amount of code completion shortcuts customizable

This commit is contained in:
chylex 2021-08-26 22:01:06 +02:00
parent 28c3d80c6e
commit 2f3780bdfc
Signed by: chylex
GPG Key ID: 4DE42C8F19A80548
4 changed files with 67 additions and 97 deletions
src/main/kotlin/com/chylex/intellij/keyboardmaster

View File

@ -2,32 +2,27 @@ package com.chylex.intellij.keyboardmaster.configuration
import com.intellij.openapi.options.Configurable
import com.intellij.ui.components.JBTextField
import com.intellij.util.ui.FormBuilder
import com.intellij.ui.layout.panel
import javax.swing.JComponent
import javax.swing.JPanel
class PluginConfigurable : Configurable {
private lateinit var component: JComponent
private val charFields = Array(10) {
JBTextField(5)
}
private val codeCompletionItemShortcuts = JBTextField(20)
private val codeCompletionNextPageShortcut = JBTextField(2)
override fun getDisplayName(): String {
return "Keyboard Master"
}
override fun createComponent(): JComponent {
var builder = FormBuilder.createFormBuilder()
for (index in 1..9) {
builder = builder.addLabeledComponent("Code completion char $index: ", charFields[index])
component = panel {
titledRow("Code Completion") {
row("Item shortcuts:") { component(codeCompletionItemShortcuts) }
row("Next page shortcut:") { component(codeCompletionNextPageShortcut) }
}
}
builder = builder.addLabeledComponent("Code completion next page char: ", charFields[0])
builder = builder.addComponentFillVertically(JPanel(), 0)
component = builder.panel
return component
}
@ -36,40 +31,16 @@ class PluginConfigurable : Configurable {
}
override fun apply() {
fun getChar(index: Int): Int {
return charFields[index].text.firstOrNull()?.code ?: 0
PluginConfiguration.modify {
it.codeCompletionItemShortcuts = codeCompletionItemShortcuts.text
it.codeCompletionNextPageShortcut = codeCompletionNextPageShortcut.text.firstOrNull()?.code ?: 0
}
val instance = PluginConfiguration.instance
instance.charOption1 = getChar(1)
instance.charOption2 = getChar(2)
instance.charOption3 = getChar(3)
instance.charOption4 = getChar(4)
instance.charOption5 = getChar(5)
instance.charOption6 = getChar(6)
instance.charOption7 = getChar(7)
instance.charOption8 = getChar(8)
instance.charOption9 = getChar(9)
instance.charNextPage = getChar(0)
PluginConfiguration.update()
}
override fun reset() {
fun setChar(index: Int, char: Int) {
charFields[index].text = if (char == 0) "" else char.toChar().toString()
PluginConfiguration.read {
codeCompletionItemShortcuts.text = it.codeCompletionItemShortcuts
codeCompletionNextPageShortcut.text = it.codeCompletionNextPageShortcut.let { code -> if (code == 0) "" else code.toChar().toString() }
}
val instance = PluginConfiguration.instance
setChar(1, instance.charOption1)
setChar(2, instance.charOption2)
setChar(3, instance.charOption3)
setChar(4, instance.charOption4)
setChar(5, instance.charOption5)
setChar(6, instance.charOption6)
setChar(7, instance.charOption7)
setChar(8, instance.charOption8)
setChar(9, instance.charOption9)
setChar(0, instance.charNextPage)
}
}

View File

@ -1,61 +1,38 @@
package com.chylex.intellij.keyboardmaster.configuration
import com.chylex.intellij.keyboardmaster.lookup.ProjectLookupListener
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.PersistentStateComponent
import com.intellij.openapi.components.State
import com.intellij.openapi.components.Storage
import com.intellij.util.containers.IntIntHashMap
import com.intellij.util.xmlb.XmlSerializerUtil
import it.unimi.dsi.fastutil.ints.Int2IntMap
@State(
name = "com.chylex.intellij.keyboardmaster.configuration.PluginConfiguration",
storages = [Storage("KeyboardMaster.xml")]
)
class PluginConfiguration : PersistentStateComponent<PluginConfiguration> {
var charOption1: Int = '1'.code
var charOption2: Int = '2'.code
var charOption3: Int = '3'.code
var charOption4: Int = '4'.code
var charOption5: Int = '5'.code
var charOption6: Int = '6'.code
var charOption7: Int = '7'.code
var charOption8: Int = '8'.code
var charOption9: Int = '9'.code
var charNextPage: Int = '0'.code
var codeCompletionItemShortcuts = "123456789"
var codeCompletionNextPageShortcut: Int = '0'.code
companion object {
val instance: PluginConfiguration
private val instance: PluginConfiguration
get() = ApplicationManager.getApplication().getService(PluginConfiguration::class.java)
val charToIndexMap: Int2IntMap = IntIntHashMap(10, -1)
val hintText = Array(10) { "" }
init {
instance
update()
instance.apply(this::update)
}
fun update() {
val instance = instance
charToIndexMap.clear()
charToIndexMap[instance.charOption1] = 1
charToIndexMap[instance.charOption2] = 2
charToIndexMap[instance.charOption3] = 3
charToIndexMap[instance.charOption4] = 4
charToIndexMap[instance.charOption5] = 5
charToIndexMap[instance.charOption6] = 6
charToIndexMap[instance.charOption7] = 7
charToIndexMap[instance.charOption8] = 8
charToIndexMap[instance.charOption9] = 9
charToIndexMap[instance.charNextPage] = 0
for (entry in charToIndexMap.int2IntEntrySet()) {
val hintIndex = if (entry.intValue == 0) 9 else entry.intValue - 1
val charText = if (entry.intKey == 0) "" else " [${entry.intKey.toChar()}]"
hintText[hintIndex] = charText
}
fun read(callback: (PluginConfiguration) -> Unit) {
instance.apply(callback)
}
fun modify(callback: (PluginConfiguration) -> Unit) {
instance.apply(callback).apply(this::update)
}
private fun update(instance: PluginConfiguration) {
ProjectLookupListener.updateShortcuts(instance)
}
}

View File

@ -1,6 +1,5 @@
package com.chylex.intellij.keyboardmaster.lookup
import com.chylex.intellij.keyboardmaster.configuration.PluginConfiguration
import com.intellij.codeInsight.lookup.LookupManager
import com.intellij.codeInsight.lookup.impl.LookupImpl
import com.intellij.codeInsight.template.impl.editorActions.TypedActionHandlerBase
@ -21,8 +20,8 @@ class LookupTypedActionHandler(originalHandler: TypedActionHandler?) : TypedActi
}
private fun executeImpl(editor: Editor, charTyped: Char): Boolean {
val mappedIndex = PluginConfiguration.charToIndexMap[charTyped.code]
if (mappedIndex == -1) {
val shortcutItem = ProjectLookupListener.getShortcut(charTyped)
if (shortcutItem == -1) {
return false
}
@ -33,19 +32,21 @@ class LookupTypedActionHandler(originalHandler: TypedActionHandler?) : TypedActi
val offset = ProjectLookupListener.getLookupOffset(lookup)
if (mappedIndex == 0) {
if (shortcutItem == 0) {
val list = lookup.list
val itemCount = list.model.size
val topIndex = (offset + 9).let { if (it >= itemCount) 0 else it }
val shortcutCount = ProjectLookupListener.itemShortcutCount
val topIndex = (offset + shortcutCount).let { if (it >= itemCount) 0 else it }
ProjectLookupListener.setLookupOffset(lookup, topIndex)
lookup.selectedIndex = topIndex
ScrollingUtil.ensureRangeIsVisible(list, topIndex, topIndex + 8)
ScrollingUtil.ensureRangeIsVisible(list, topIndex, topIndex + shortcutCount - 1)
lookup.markSelectionTouched()
lookup.refreshUi(false, true)
}
else {
lookup.selectedIndex = offset + mappedIndex - 1
lookup.selectedIndex = offset + shortcutItem - 1
}
return true

View File

@ -6,6 +6,7 @@ import com.intellij.codeInsight.lookup.LookupElementPresentation
import com.intellij.codeInsight.lookup.LookupManagerListener
import com.intellij.codeInsight.lookup.impl.LookupImpl
import com.intellij.openapi.util.Key
import com.intellij.util.containers.IntIntHashMap
/**
* Adds hints to code completion items with the digit that selects it.
@ -15,6 +16,29 @@ class ProjectLookupListener : LookupManagerListener {
private val OFFSET_KEY = Key.create<Int>("chylexKeyboardMasterOffset")
private val IS_MODIFIED_KEY = Key.create<Boolean>("chylexKeyboardMasterModified")
private var hintTexts = mutableListOf<String>()
private val charToShortcutMap = IntIntHashMap(16, -1)
val itemShortcutCount
get() = hintTexts.size
fun updateShortcuts(configuration: PluginConfiguration) {
hintTexts.clear()
for (char in configuration.codeCompletionItemShortcuts) {
hintTexts.add(" [$char]")
}
charToShortcutMap.clear()
configuration.codeCompletionNextPageShortcut.takeUnless { it == 0 }?.let { charToShortcutMap[it] = 0 }
for ((index, char) in configuration.codeCompletionItemShortcuts.withIndex()) {
charToShortcutMap[char.code] = index + 1
}
}
fun getShortcut(char: Char): Int {
return charToShortcutMap[char.code]
}
fun getLookupOffset(lookup: LookupImpl): Int {
val offset = lookup.getUserData(OFFSET_KEY)
if (offset == null || offset >= lookup.list.model.size) {
@ -31,7 +55,7 @@ class ProjectLookupListener : LookupManagerListener {
}
override fun activeLookupChanged(oldLookup: Lookup?, newLookup: Lookup?) {
if (newLookup !is LookupImpl || newLookup.getUserData(IS_MODIFIED_KEY) == true) {
if (newLookup !is LookupImpl || newLookup.getUserData(IS_MODIFIED_KEY) == true || itemShortcutCount == 0) {
return
}
@ -43,20 +67,17 @@ class ProjectLookupListener : LookupManagerListener {
val itemCount = itemList.size
val offset = getLookupOffset(newLookup)
for (index in 0 until 9) {
for (index in hintTexts.indices) {
val itemIndex = offset + index
if (itemIndex >= itemCount) {
break
}
if (item === itemList.getElementAt(itemIndex)) {
val hint = PluginConfiguration.hintText[index]
if (hint != "") {
val customized = LookupElementPresentation()
customized.copyFrom(presentation)
customized.appendTailTextItalic(hint, true)
return@addPresentationCustomizer customized
}
val customized = LookupElementPresentation()
customized.copyFrom(presentation)
customized.appendTailTextItalic(hintTexts[index], true)
return@addPresentationCustomizer customized
}
}