Compare commits

...
6 Commits
12 changed files with 118 additions and 69 deletions
+4 -1
View File
@@ -6,7 +6,7 @@ plugins {
}
group = "com.chylex.intellij.keyboardmaster"
version = "0.6.6"
version = "0.6.7"
repositories {
mavenCentral()
@@ -21,6 +21,9 @@ dependencies {
@Suppress("DEPRECATION")
intellijIdeaUltimate("2024.2")
bundledModule("intellij.platform.vcs.impl")
bundledModule("intellij.platform.vcs.log.impl")
bundledPlugin("com.intellij.java")
if (System.getenv("IDEAVIM") == "1") {
Binary file not shown.
+3 -1
View File
@@ -1,7 +1,9 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.0-bin.zip
networkTimeout=10000
retries=0
retryBackOffMs=500
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+6 -9
View File
@@ -1,7 +1,7 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
# gradlew start up script for POSIX generated by Gradle.
#
# Important for running:
#
@@ -29,7 +29,7 @@
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
# ksh gradlew
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
@@ -57,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -114,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -172,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -205,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
Vendored
+12 -24
View File
@@ -19,12 +19,12 @@
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem gradlew startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Set local scope for the variables, and ensure extensions are enabled
setlocal EnableExtensions
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@@ -51,7 +51,7 @@ echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
"%COMSPEC%" /c exit 1
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
@@ -65,30 +65,18 @@ echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
"%COMSPEC%" /c exit 1
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
@rem Execute gradlew
@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
@rem which allows us to clear the local environment before executing the java command
endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
:exitWithErrorLevel
@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
"%COMSPEC%" /c exit %ERRORLEVEL%
+2 -2
View File
@@ -2,7 +2,7 @@ rootProject.name = "KeyboardMaster"
pluginManagement {
plugins {
kotlin("jvm") version "1.9.24"
id("org.jetbrains.intellij.platform") version "2.9.0"
kotlin("jvm") version "1.9.24" // https://plugins.jetbrains.com/docs/intellij/using-kotlin.html#bundled-stdlib-versions
id("org.jetbrains.intellij.platform") version "2.18.1" // https://github.com/JetBrains/intellij-platform-gradle-plugin/releases
}
}
@@ -33,7 +33,7 @@ internal interface KeyStrokeNode<T> {
}
private fun isCharEvent(keyEvent: KeyEvent): Boolean {
return keyEvent.keyChar != KeyEvent.CHAR_UNDEFINED && (keyEvent.modifiersEx and KeyEvent.CTRL_DOWN_MASK) == 0
return keyEvent.keyChar != KeyEvent.CHAR_UNDEFINED && keyEvent.keyCode != KeyEvent.VK_ENTER && (keyEvent.modifiersEx and KeyEvent.CTRL_DOWN_MASK) == 0
}
private fun isCodeEvent(keyEvent: KeyEvent): Boolean {
@@ -96,32 +96,55 @@ internal open class VimNavigationDispatcher<T : JComponent>(final override val c
final override fun actionPerformed(e: AnActionEvent) {
val keyEvent = e.inputEvent as? KeyEvent ?: return
if (keyEvent.id == KeyEvent.KEY_PRESSED && keyEvent.keyCode == KeyEvent.VK_ENTER) {
handleEnterKeyPress(e, keyEvent)
return
handleEnterKeyPress(e, keyEvent) { originalEnterAction.perform(e, it) }
}
else {
handleKeyPress(e, keyEvent) {}
}
}
protected inline fun handleKeyPress(actionEvent: AnActionEvent, keyEvent: KeyEvent, fallback: () -> Unit) {
when (val nextNode = currentNode.getChild(keyEvent)) {
is KeyStrokeNode.Parent<VimNavigationDispatcher<T>> -> currentNode = nextNode
is KeyStrokeNode.ActionNode<VimNavigationDispatcher<T>> -> {
nextNode.performAction(this, e, keyEvent)
nextNode.performAction(this, actionEvent, keyEvent)
currentNode = rootNode
}
else -> {
currentNode = rootNode
fallback()
}
}
}
private fun handleEnterKeyPress(actionEvent: AnActionEvent, keyEvent: KeyEvent) {
handleEnterKeyPress(keyEvent) { originalEnterAction.perform(actionEvent, it) }
protected inline fun handleEnterKeyPress(actionEvent: AnActionEvent, keyEvent: KeyEvent, originalAction: (KeyEvent) -> Unit) {
if (stopSpeedSearchOnEnterKeyPress(keyEvent)) {
return
}
handleKeyPress(actionEvent, keyEvent) {
currentNode = rootNode
originalAction(keyEvent)
}
}
protected inline fun handleEnterKeyPress(keyEvent: KeyEvent, originalAction: (KeyEvent) -> Unit) {
if (stopSpeedSearchOnEnterKeyPress(keyEvent)) {
return
}
currentNode = rootNode
originalAction(keyEvent)
}
private fun stopSpeedSearchOnEnterKeyPress(keyEvent: KeyEvent): Boolean {
if (isSearching.compareAndSet(true, false) && !runEnterActionImmediately(keyEvent)) {
stopSpeedSearch()
return true
}
else {
currentNode = rootNode
originalAction(keyEvent)
return false
}
}
@@ -7,7 +7,6 @@ import com.chylex.intellij.keyboardmaster.feature.vimNavigation.KeyStrokeNode.Pa
import com.chylex.intellij.keyboardmaster.feature.vimNavigation.VimNavigationDispatcher
import com.chylex.intellij.keyboardmaster.feature.vimNavigation.VimNavigationDispatcher.Companion.getParentToolWindowId
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.wm.ToolWindowId
import com.intellij.openapi.wm.ex.ToolWindowManagerEx
import com.intellij.ui.ComponentUtil
import com.intellij.ui.speedSearch.SpeedSearchActivator
@@ -24,10 +23,7 @@ internal object VimCommonNavigation {
mapOf(
KeyStroke.getKeyStroke('A') to IdeaAction("MaximizeToolWindow"),
KeyStroke.getKeyStroke('f') to StartSearch(),
KeyStroke.getKeyStroke('I') to ToggleExcludedFilesInProjectView(),
KeyStroke.getKeyStroke('m') to IdeaAction("ShowPopupMenu"),
KeyStroke.getKeyStroke('r') to IdeaAction("SynchronizeCurrentFile"),
KeyStroke.getKeyStroke('R') to IdeaAction("Synchronize"),
KeyStroke.getKeyStroke('q') to CloseParentPopupOrToolWindow(),
KeyStroke.getKeyStroke('/') to StartSearch(),
)
@@ -61,17 +57,7 @@ internal object VimCommonNavigation {
val project = actionEvent.project ?: return
val toolWindowId = holder.component.getParentToolWindowId() ?: return
ToolWindowManagerEx.getInstanceEx(project).hideToolWindow(toolWindowId, true)
}
}
private class ToggleExcludedFilesInProjectView<T : JComponent> : ActionNode<VimNavigationDispatcher<T>> {
private val showExcludedFilesAction = IdeaAction<VimNavigationDispatcher<T>>("ProjectView.ShowExcludedFiles")
override fun performAction(holder: VimNavigationDispatcher<T>, actionEvent: AnActionEvent, keyEvent: KeyEvent) {
if (holder.component.getParentToolWindowId() == ToolWindowId.PROJECT_VIEW) {
showExcludedFilesAction.performAction(holder, actionEvent, keyEvent)
}
ToolWindowManagerEx.getInstanceEx(project).hideToolWindow(toolWindowId, hideSide = false)
}
}
@@ -26,7 +26,7 @@ import javax.swing.KeyStroke
internal object VimListNavigation {
private val KEY = Key.create<VimNavigationDispatcher<JList<*>>>("KeyboardMaster-VimListNavigation")
private val ROOT_NODE = VimCommonNavigation.commonRootNode<JList<*>>() + Parent(
private val BASIC_ROOT_NODE = VimCommonNavigation.commonRootNode<JList<*>>() + Parent(
mapOf(
KeyStroke.getKeyStroke('g') to IdeaAction("List-selectFirstRow"),
KeyStroke.getKeyStroke('G') to IdeaAction("List-selectLastRow"),
@@ -45,7 +45,7 @@ internal object VimListNavigation {
)
)
private val POPUP_LIST_ROOT_NODE = ROOT_NODE + Parent(
private val POPUP_LIST_ROOT_NODE = BASIC_ROOT_NODE + Parent(
mapOf(
KeyStroke.getKeyStroke('o') to IdeaAction("List-selectNextColumn"),
KeyStroke.getKeyStroke('p') to IdeaAction("List-selectPreviousColumn"),
@@ -55,7 +55,7 @@ internal object VimListNavigation {
fun install(component: JList<*>) {
if (component.getUserData(KEY) == null && component.javaClass.enclosingClass.let { it == null || !WizardPopup::class.java.isAssignableFrom(it) }) {
component.putUserData(KEY, VimNavigationDispatcher(component, ROOT_NODE))
component.putUserData(KEY, VimNavigationDispatcher(component, BASIC_ROOT_NODE))
}
}
@@ -12,6 +12,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.ui.getUserData
import com.intellij.openapi.ui.putUserData
import com.intellij.openapi.util.Key
import com.intellij.vcs.log.ui.table.VcsLogGraphTable
import java.awt.Rectangle
import java.awt.event.KeyEvent
import javax.swing.JTable
@@ -20,7 +21,7 @@ import javax.swing.KeyStroke
internal object VimTableNavigation {
private val KEY = Key.create<VimNavigationDispatcher<JTable>>("KeyboardMaster-VimTableNavigation")
private val ROOT_NODE = VimCommonNavigation.commonRootNode<JTable>() + Parent(
private val BASIC_ROOT_NODE = VimCommonNavigation.commonRootNode<JTable>() + Parent(
mapOf(
KeyStroke.getKeyStroke('g') to IdeaAction("Table-selectFirstRow"),
KeyStroke.getKeyStroke('G') to IdeaAction("Table-selectLastRow"),
@@ -39,12 +40,29 @@ internal object VimTableNavigation {
)
)
private val GIT_LOG_TABLE_ROOT_NODE = BASIC_ROOT_NODE + Parent(
mapOf(
KeyStroke.getKeyStroke('d') to IdeaAction("Git.Drop.Commits"),
KeyStroke.getKeyStroke('n') to IdeaAction("Git.Reword.Commit"),
KeyStroke.getKeyStroke('p') to IdeaAction("Vcs.CherryPick"),
KeyStroke.getKeyStroke('r') to IdeaAction("Git.Interactive.Rebase"),
KeyStroke.getKeyStroke('s') to IdeaAction("Git.Squash.Commits"),
KeyStroke.getKeyStroke('u') to IdeaAction("Git.Uncommit"),
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0) to IdeaAction("Git.CheckoutRevision"),
)
)
fun install(component: JTable) {
if (component.getUserData(KEY) == null) {
component.putUserData(KEY, VimNavigationDispatcher(component, ROOT_NODE))
component.putUserData(KEY, VimNavigationDispatcher(component, pickRootNode(component)))
}
}
private fun pickRootNode(component: JTable) = when (component) {
is VcsLogGraphTable -> GIT_LOG_TABLE_ROOT_NODE
else -> BASIC_ROOT_NODE
}
private data class ScrollVerticallyAndSelect(private val pages: Float, private val extendSelection: Boolean) : ActionNode<VimNavigationDispatcher<JTable>> {
override fun performAction(holder: VimNavigationDispatcher<JTable>, actionEvent: AnActionEvent, keyEvent: KeyEvent) {
val table = holder.component
@@ -8,13 +8,16 @@ import com.chylex.intellij.keyboardmaster.feature.vimNavigation.components.VimCo
import com.chylex.intellij.keyboardmaster.feature.vimNavigation.components.VimCommonNavigation.scrollBy
import com.chylex.intellij.keyboardmaster.feature.vimNavigation.components.VimCommonNavigation.scrollByPages
import com.chylex.intellij.keyboardmaster.feature.vimNavigation.components.VimCommonNavigation.withShiftModifier
import com.intellij.ide.projectView.impl.ProjectViewTree
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.ui.getUserData
import com.intellij.openapi.ui.putUserData
import com.intellij.openapi.util.Key
import com.intellij.openapi.vcs.changes.ui.ChangesTree
import com.intellij.ui.ClientProperty
import com.intellij.ui.tree.ui.DefaultTreeUI
import java.awt.event.KeyEvent
import javax.swing.JComponent
import javax.swing.JTree
import javax.swing.KeyStroke
import javax.swing.tree.TreeModel
@@ -23,7 +26,7 @@ import javax.swing.tree.TreePath
internal object VimTreeNavigation {
private val KEY = Key.create<VimNavigationDispatcher<JTree>>("KeyboardMaster-VimTreeNavigation")
private val ROOT_NODE = VimCommonNavigation.commonRootNode<JTree>() + Parent(
private val BASIC_ROOT_NODE = VimCommonNavigation.commonRootNode<JTree>() + Parent(
mapOf(
KeyStroke.getKeyStroke('a') to Parent(
mapOf(
@@ -62,12 +65,33 @@ internal object VimTreeNavigation {
)
)
private val PROJECT_FILE_TREE_ROOT_NODE = BASIC_ROOT_NODE + Parent(
mapOf(
KeyStroke.getKeyStroke('I') to ToggleExcludedFilesInProjectView(),
KeyStroke.getKeyStroke('r') to IdeaAction("SynchronizeCurrentFile"),
KeyStroke.getKeyStroke('R') to IdeaAction("Synchronize"),
)
)
private val GIT_CHANGES_ROOT_NODE = BASIC_ROOT_NODE + Parent(
mapOf(
KeyStroke.getKeyStroke('e') to IdeaAction("EditSource"),
KeyStroke.getKeyStroke('r') to IdeaAction("ChangesView.Revert"),
)
)
fun install(component: JTree) {
if (component.getUserData(KEY) == null) {
component.putUserData(KEY, VimNavigationDispatcher(component, ROOT_NODE))
component.putUserData(KEY, VimNavigationDispatcher(component, pickRootNode(component)))
}
}
private fun pickRootNode(component: JTree) = when (component) {
is ProjectViewTree -> PROJECT_FILE_TREE_ROOT_NODE
is ChangesTree -> GIT_CHANGES_ROOT_NODE
else -> BASIC_ROOT_NODE
}
private data class ScrollVerticallyAndSelect(private val pages: Float, private val extendSelection: Boolean) : ActionNode<VimNavigationDispatcher<JTree>> {
override fun performAction(holder: VimNavigationDispatcher<JTree>, actionEvent: AnActionEvent, keyEvent: KeyEvent) {
val tree = holder.component
@@ -357,4 +381,12 @@ internal object VimTreeNavigation {
private fun isLeaf(tree: JTree, firstChildPath: TreePath): Boolean {
return tree.model.isLeaf(firstChildPath.lastPathComponent)
}
private class ToggleExcludedFilesInProjectView<T : JComponent> : ActionNode<VimNavigationDispatcher<T>> {
private val showExcludedFilesAction = IdeaAction<VimNavigationDispatcher<T>>("ProjectView.ShowExcludedFiles")
override fun performAction(holder: VimNavigationDispatcher<T>, actionEvent: AnActionEvent, keyEvent: KeyEvent) {
showExcludedFilesAction.performAction(holder, actionEvent, keyEvent)
}
}
}