1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2024-11-25 07:42:59 +01:00

Compare commits

..

15 Commits

Author SHA1 Message Date
30de641513
Set plugin version to chylex-33 2024-04-28 08:41:36 +02:00
d1b58c9d39
Revert "Factor disposable objects on editor opening"
This reverts commit 1fa78935
2024-04-28 08:41:21 +02:00
45ed79d865
Apply NERDTree to all tree views 2024-04-27 06:18:47 +02:00
527eb4cbb3
Fix(VIM-3364): Exception with mapped Generate action 2024-04-27 06:18:47 +02:00
e32ac125b2
Disable speed search in Project tool window when NERDTree is enabled 2024-04-27 06:18:47 +02:00
4d1d3b697c
Apply scrolloff after executing native IDEA actions 2024-04-27 06:18:47 +02:00
3246832528
Stay on same line after reindenting 2024-04-27 06:18:47 +02:00
6505bfc9aa
Update search register when using f/t 2024-04-27 06:17:20 +02:00
0c63890e9d
Automatically add unambiguous imports after running a macro 2024-04-27 06:17:20 +02:00
259958e702
Fix(VIM-3179): Respect virtual space below editor (imperfectly) 2024-04-27 06:17:20 +02:00
4916545b53
Fix(VIM-3178): Workaround to support "Jump to Source" action mapping 2024-04-27 06:17:19 +02:00
b8a9bddfa9
Fix(VIM-3166): Workaround to fix broken filtering of visual lines 2024-04-27 06:17:19 +02:00
95688b33c8
Add support for count for visual and line motion surround 2024-04-27 06:17:17 +02:00
07f44f1c93
Fix vim-surround not working with multiple cursors
Fixes multiple cursors with vim-surround commands `cs, ds, S` (but not `ys`).
2024-04-27 06:17:05 +02:00
2ce6239ad6
Fix(VIM-696) Restore visual mode after undo/redo, and disable incompatible actions 2024-04-26 19:58:12 +02:00
6 changed files with 126 additions and 113 deletions

View File

@ -14,7 +14,7 @@ ideaVersion=2024.1
ideaType=IC
downloadIdeaSources=true
instrumentPluginCode=true
version=chylex-34
version=chylex-33
javaVersion=17
remoteRobotVersion=0.11.22
antlrVersion=4.10.1

View File

@ -8,25 +8,21 @@
package com.maddyhome.idea.vim.extension.nerdtree
import com.intellij.ide.projectView.ProjectView
import com.intellij.ide.projectView.impl.AbstractProjectViewPane
import com.intellij.ide.projectView.impl.ProjectViewImpl
import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.PlatformCoreDataKeys
import com.intellij.openapi.actionSystem.PlatformDataKeys
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
import com.intellij.openapi.project.DumbAwareAction
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ProjectManager
import com.intellij.openapi.startup.ProjectActivity
import com.intellij.openapi.wm.ToolWindow
import com.intellij.openapi.ui.getUserData
import com.intellij.openapi.ui.putUserData
import com.intellij.openapi.util.Key
import com.intellij.openapi.wm.ToolWindowId
import com.intellij.openapi.wm.ex.ToolWindowManagerEx
import com.intellij.openapi.wm.ex.ToolWindowManagerListener
import com.intellij.ui.KeyStrokeAdapter
import com.intellij.ui.TreeExpandCollapse
import com.intellij.ui.speedSearch.SpeedSearchSupply
@ -53,6 +49,8 @@ import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString
import java.awt.event.KeyEvent
import javax.swing.JComponent
import javax.swing.JTree
import javax.swing.KeyStroke
import javax.swing.SwingConstants
@ -132,7 +130,6 @@ internal class NerdTree : VimExtension {
synchronized(Util.monitor) {
Util.commandsRegistered = true
ProjectManager.getInstance().openProjects.forEach { project -> installDispatcher(project) }
}
}
@ -164,39 +161,8 @@ internal class NerdTree : VimExtension {
}
}
class ProjectViewListener(private val project: Project) : ToolWindowManagerListener {
override fun toolWindowShown(toolWindow: ToolWindow) {
if (ToolWindowId.PROJECT_VIEW != toolWindow.id) return
val dispatcher = NerdDispatcher.getInstance(project)
if (dispatcher.speedSearchListenerInstalled) return
// I specify nullability explicitly as we've got a lot of exceptions saying this property is null
val currentProjectViewPane: AbstractProjectViewPane? = ProjectView.getInstance(project).currentProjectViewPane
val tree = currentProjectViewPane?.tree ?: return
val supply = SpeedSearchSupply.getSupply(tree, true) ?: return
// NB: Here might be some issues with concurrency, but it's not really bad, I think
dispatcher.speedSearchListenerInstalled = true
supply.addChangeListener {
dispatcher.waitForSearch = false
}
}
}
// TODO I'm not sure is this activity runs at all? Should we use [RunOnceUtil] instead?
class NerdStartupActivity : ProjectActivity {
override suspend fun execute(project: Project) {
synchronized(Util.monitor) {
if (!Util.commandsRegistered) return
installDispatcher(project)
}
}
}
class NerdDispatcher : DumbAwareAction() {
internal var waitForSearch = false
internal var speedSearchListenerInstalled = false
override fun actionPerformed(e: AnActionEvent) {
var keyStroke = getKeyStroke(e) ?: return
@ -244,10 +210,6 @@ internal class NerdTree : VimExtension {
}
companion object {
fun getInstance(project: Project): NerdDispatcher {
return project.getService(NerdDispatcher::class.java)
}
private const val ESCAPE_KEY_CODE = 27
}
@ -283,19 +245,14 @@ internal class NerdTree : VimExtension {
registerCommand(
"NERDTreeMapActivateNode",
"o",
NerdAction.Code { project, dataContext, _ ->
val tree = ProjectView.getInstance(project).currentProjectViewPane.tree
NerdAction.Code { _, dataContext, e ->
val tree = getTree(e) ?: return@Code
val array = CommonDataKeys.NAVIGATABLE_ARRAY.getData(dataContext)?.filter { it.canNavigateToSource() }
if (array.isNullOrEmpty()) {
val row = tree.selectionRows?.getOrNull(0) ?: return@Code
if (tree.isExpanded(row)) {
tree.collapseRow(row)
} else {
tree.expandRow(row)
}
val row = tree.selectionRows?.getOrNull(0) ?: return@Code
if (tree.isExpanded(row)) {
tree.collapseRow(row)
} else {
array.forEach { it.navigate(true) }
tree.expandRow(row)
}
},
)
@ -374,8 +331,8 @@ internal class NerdTree : VimExtension {
registerCommand(
"NERDTreeMapOpenRecursively",
"O",
NerdAction.Code { project, _, _ ->
val tree = ProjectView.getInstance(project).currentProjectViewPane.tree
NerdAction.Code { _, _, e ->
val tree = getTree(e) ?: return@Code
TreeExpandCollapse.expandAll(tree)
tree.selectionPath?.let {
TreeUtil.scrollToVisible(tree, it, false)
@ -385,8 +342,8 @@ internal class NerdTree : VimExtension {
registerCommand(
"NERDTreeMapCloseChildren",
"X",
NerdAction.Code { project, _, _ ->
val tree = ProjectView.getInstance(project).currentProjectViewPane.tree
NerdAction.Code { _, _, e ->
val tree = getTree(e) ?: return@Code
TreeExpandCollapse.collapse(tree)
tree.selectionPath?.let {
TreeUtil.scrollToVisible(tree, it, false)
@ -396,8 +353,8 @@ internal class NerdTree : VimExtension {
registerCommand(
"NERDTreeMapCloseDir",
"x",
NerdAction.Code { project, _, _ ->
val tree = ProjectView.getInstance(project).currentProjectViewPane.tree
NerdAction.Code { _, _, e ->
val tree = getTree(e) ?: return@Code
val currentPath = tree.selectionPath ?: return@Code
if (tree.isExpanded(currentPath)) {
tree.collapsePath(currentPath)
@ -415,8 +372,8 @@ internal class NerdTree : VimExtension {
registerCommand(
"NERDTreeMapJumpParent",
"p",
NerdAction.Code { project, _, _ ->
val tree = ProjectView.getInstance(project).currentProjectViewPane.tree
NerdAction.Code { _, _, e ->
val tree = getTree(e) ?: return@Code
val currentPath = tree.selectionPath ?: return@Code
val parentPath = currentPath.parentPath ?: return@Code
if (parentPath.parentPath != null) {
@ -429,8 +386,8 @@ internal class NerdTree : VimExtension {
registerCommand(
"NERDTreeMapJumpFirstChild",
"K",
NerdAction.Code { project, _, _ ->
val tree = ProjectView.getInstance(project).currentProjectViewPane.tree
NerdAction.Code { _, _, e ->
val tree = getTree(e) ?: return@Code
val currentPath = tree.selectionPath ?: return@Code
val parent = currentPath.parentPath ?: return@Code
val row = tree.getRowForPath(parent)
@ -442,8 +399,8 @@ internal class NerdTree : VimExtension {
registerCommand(
"NERDTreeMapJumpLastChild",
"J",
NerdAction.Code { project, _, _ ->
val tree = ProjectView.getInstance(project).currentProjectViewPane.tree
NerdAction.Code { _, _, e ->
val tree = getTree(e) ?: return@Code
val currentPath = tree.selectionPath ?: return@Code
val currentPathCount = currentPath.pathCount
@ -464,12 +421,12 @@ internal class NerdTree : VimExtension {
)
registerCommand(
"NERDTreeMapJumpNextSibling",
"<C-J>",
"<A-J>",
NerdAction.ToIj("Tree-selectNextSibling"),
)
registerCommand(
"NERDTreeMapJumpPrevSibling",
"<C-K>",
"<A-K>",
NerdAction.ToIj("Tree-selectPreviousSibling"),
)
registerCommand(
@ -488,20 +445,26 @@ internal class NerdTree : VimExtension {
registerCommand(
"/",
NerdAction.Code { project, _, _ ->
NerdDispatcher.getInstance(project).waitForSearch = true
NerdAction.Code { _, _, e ->
val tree = getTree(e) ?: return@Code
tree.getUserData(KEY)?.waitForSearch = true
},
)
registerCommand(
"<ESC>",
NerdAction.Code { project, _, _ ->
val instance = NerdDispatcher.getInstance(project)
if (instance.waitForSearch) {
instance.waitForSearch = false
}
NerdAction.Code { _, _, e ->
val tree = getTree(e) ?: return@Code
tree.getUserData(KEY)?.waitForSearch = false
},
)
for (c in ('a'..'z') + ('A'..'Z')) {
val ks = KeyStroke.getKeyStroke(c)
if (ks !in actionsRoot) {
registerCommand(c.toString(), NerdAction.Code { _, _, _ -> })
}
}
}
object Util {
@ -526,6 +489,21 @@ internal class NerdTree : VimExtension {
companion object {
const val pluginName = "NERDTree"
private val LOG = logger<NerdTree>()
private val KEY = Key.create<NerdDispatcher>("IdeaVim-NerdTree-Dispatcher")
fun installDispatcher(component: JComponent) {
if (component.getUserData(KEY) != null) return
val dispatcher = NerdDispatcher()
component.putUserData(KEY, dispatcher)
val shortcuts = collectShortcuts(actionsRoot).map { RequiredShortcut(it, MappingOwner.Plugin.get(pluginName)) }
dispatcher.registerCustomShortcutSet(KeyGroup.toShortcutSet(shortcuts), component)
SpeedSearchSupply.getSupply(component, true)?.addChangeListener {
dispatcher.waitForSearch = false
}
}
}
}
@ -560,12 +538,6 @@ private fun collectShortcuts(node: Node<NerdAction>): Set<KeyStroke> {
}
}
private fun installDispatcher(project: Project) {
val dispatcher = NerdTree.NerdDispatcher.getInstance(project)
val shortcuts =
collectShortcuts(actionsRoot).map { RequiredShortcut(it, MappingOwner.Plugin.get(NerdTree.pluginName)) }
dispatcher.registerCustomShortcutSet(
KeyGroup.toShortcutSet(shortcuts),
(ProjectView.getInstance(project) as ProjectViewImpl).component,
)
private fun getTree(e: AnActionEvent): JTree? {
return e.dataContext.getData(PlatformCoreDataKeys.CONTEXT_COMPONENT) as? JTree
}

View File

@ -0,0 +1,25 @@
package com.maddyhome.idea.vim.extension.nerdtree
import com.intellij.ide.ApplicationInitializedListener
import com.intellij.openapi.application.ApplicationManager
import com.intellij.util.ui.StartupUiUtil
import kotlinx.coroutines.CoroutineScope
import java.awt.AWTEvent
import java.awt.event.FocusEvent
import javax.swing.JTree
@Suppress("UnstableApiUsage")
internal class NerdTreeApplicationListener : ApplicationInitializedListener {
override suspend fun execute(asyncScope: CoroutineScope) {
StartupUiUtil.addAwtListener(::handleEvent, AWTEvent.FOCUS_EVENT_MASK, ApplicationManager.getApplication().getService(NerdTreeDisposableService::class.java))
}
private fun handleEvent(event: AWTEvent) {
if (event is FocusEvent && event.id == FocusEvent.FOCUS_GAINED) {
val source = event.source
if (source is JTree) {
NerdTree.installDispatcher(source)
}
}
}
}

View File

@ -0,0 +1,9 @@
package com.maddyhome.idea.vim.extension.nerdtree
import com.intellij.openapi.Disposable
import com.intellij.openapi.components.Service
@Service
internal class NerdTreeDisposableService : Disposable {
override fun dispose() {}
}

View File

@ -61,15 +61,18 @@ internal class UndoRedoHelper : UndoRedoBase() {
undoManager: UndoManager,
fileEditor: TextEditor,
editor: VimEditor,
) {
if (injector.globalIjOptions().oldundo) {
SelectionVimListenerSuppressor.lock().use { undoManager.undo(fileEditor) }
restoreVisualMode(editor)
} else {
// TODO refactor me after VIM-308 when restoring selection and caret movement will be ignored by undo
editor.runWithChangeTracking {
undoManager.undo(fileEditor)
) {if (injector.globalIjOptions().oldundo) {
SelectionVimListenerSuppressor.lock().use { undoManager.undo(fileEditor) }
restoreVisualMode(editor)
} else {
// TODO refactor me after VIM-308 when restoring selection and caret movement will be ignored by undo
editor.runWithChangeTracking {
undoManager.undo(fileEditor)
// We execute undo one more time if the previous one just restored selection
if (!hasChanges && hasSelection(editor) && undoManager.isUndoAvailable(fileEditor)) {
undoManager.undo(fileEditor)
}
}
CommandProcessor.getInstance().runUndoTransparentAction {
@ -88,7 +91,15 @@ internal class UndoRedoHelper : UndoRedoBase() {
// TODO refactor me after VIM-308 when restoring selection and caret movement will be ignored by undo
editor.runWithChangeTracking {
undoManager.undo(fileEditor)
restoreVisualMode(editor)
// We execute undo one more time if the previous one just restored selection
if (!hasChanges && hasSelection(editor) && undoManager.isUndoAvailable(fileEditor)) {
undoManager.undo(fileEditor)
}
}
CommandProcessor.getInstance().runUndoTransparentAction {
removeSelections(editor)
}
} else {
runWithBooleanRegistryOption("ide.undo.transparent.caret.movement", true) {
@ -127,17 +138,17 @@ internal class UndoRedoHelper : UndoRedoBase() {
undoManager: UndoManager,
fileEditor: TextEditor,
editor: VimEditor,
) {
if (injector.globalIjOptions().oldundo) {
SelectionVimListenerSuppressor.lock().use { undoManager.redo(fileEditor) }
} else {
undoManager.redo(fileEditor)
CommandProcessor.getInstance().runUndoTransparentAction {
editor.carets().forEach { it.ij.removeSelection() }
}
// TODO refactor me after VIM-308 when restoring selection and caret movement will be ignored by undo
editor.runWithChangeTracking {
) {if (injector.globalIjOptions().oldundo) {
SelectionVimListenerSuppressor.lock().use { undoManager.redo(fileEditor) }
restoreVisualMode(editor)
} else {
undoManager.redo(fileEditor)
CommandProcessor.getInstance().runUndoTransparentAction {
editor.carets().forEach { it.ij.removeSelection() }
}
// TODO refactor me after VIM-308 when restoring selection and caret movement will be ignored by undo
editor.runWithChangeTracking {
undoManager.redo(fileEditor)
// We execute undo one more time if the previous one just restored selection
if (!hasChanges && hasSelection(editor) && undoManager.isRedoAvailable(fileEditor)) {

View File

@ -136,11 +136,7 @@
<!-- IdeaVim extensions-->
<extensions defaultExtensionNs="com.intellij">
<projectService serviceImplementation="com.maddyhome.idea.vim.extension.nerdtree.NerdTree$NerdDispatcher"/>
<postStartupActivity implementation="com.maddyhome.idea.vim.extension.nerdtree.NerdTree$NerdStartupActivity"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.extension.nerdtree.NerdTree$NerdDispatcher"/>
<applicationInitializedListener implementation="com.maddyhome.idea.vim.extension.nerdtree.NerdTreeApplicationListener"/>
</extensions>
<projectListeners>
<listener class="com.maddyhome.idea.vim.extension.nerdtree.NerdTree$ProjectViewListener"
topic="com.intellij.openapi.wm.ex.ToolWindowManagerListener"/>
</projectListeners>
</idea-plugin>