1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2025-04-16 19:15:46 +02:00
IntelliJ-IdeaVim/src/main/java/com/maddyhome/idea/vim/handler/ActionBeanClass.kt
2022-11-01 20:00:07 +02:00

100 lines
3.2 KiB
Kotlin

/*
* Copyright 2022 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.handler
import com.intellij.serviceContainer.BaseKeyedLazyInstance
import com.intellij.util.SmartList
import com.intellij.util.xmlb.annotations.Attribute
import com.maddyhome.idea.vim.command.MappingMode
import javax.swing.KeyStroke
/**
* Action holder for IdeaVim actions.
*
* [implementation] should be subclass of [EditorActionHandlerBase]
*
* [modes] ("mappingModes") defines the action modes. E.g. "NO" - action works in normal and op-pending modes.
* Warning: V - Visual and Select mode. X - Visual mode. (like vmap and xmap).
* Use "ALL" to enable action for all modes.
*
* [keys] comma-separated list of keys for the action. E.g. `gt,gT` - action gets executed on `gt` or `gT`
* Since xml doesn't allow using raw `<` character, use « and » symbols for mappings with modifiers.
* E.g. `«C-U»` - CTRL-U (<C-U> in vim notation)
* If you want to use exactly `<` character, replace it with `&lt;`. E.g. `i&lt;` - i<
* If you want to use comma in mapping, use `«COMMA»`
* Do not place a whitespace around the comma!
*
*
* !! IMPORTANT !!
* You may wonder why the extension points are used instead of any other approach to register actions.
* The reason is startup performance. Using the extension points you don't even have to load classes of actions.
* So, all actions are loaded on demand, including classes in classloader.
*/
class ActionBeanClass : BaseKeyedLazyInstance<EditorActionHandlerBase>() {
@Attribute("implementation")
var implementation: String? = null
@Attribute("mappingModes")
var modes: String? = null
@Attribute("keys")
var keys: String? = null
val actionId: String get() = implementation?.let { EditorActionHandlerBase.getActionId(it) } ?: ""
fun getParsedKeys(): Set<List<KeyStroke>>? {
val myKeys = keys ?: return null
val escapedKeys = myKeys.splitByComma()
return EditorActionHandlerBase.parseKeysSet(escapedKeys)
}
override fun getImplementationClassName(): String? = implementation
fun getParsedModes(): Set<MappingMode>? {
val myModes = modes ?: return null
if ("ALL" == myModes) return MappingMode.ALL
val res = mutableListOf<MappingMode>()
for (c in myModes) {
when (c) {
'N' -> res += MappingMode.NORMAL
'X' -> res += MappingMode.VISUAL
'V' -> {
res += MappingMode.VISUAL
res += MappingMode.SELECT
}
'S' -> res += MappingMode.SELECT
'O' -> res += MappingMode.OP_PENDING
'I' -> res += MappingMode.INSERT
'C' -> res += MappingMode.CMD_LINE
else -> error("Wrong mapping mode: $c")
}
}
return res.toSet()
}
private fun String.splitByComma(): List<String> {
if (this.isEmpty()) return ArrayList()
val res = SmartList<String>()
var start = 0
var current = 0
while (current < this.length) {
if (this[current] == ',') {
res += this.substring(start, current)
current++
start = current
}
current++
}
res += this.substring(start, current)
return res
}
}