mirror of
				https://github.com/chylex/IntelliJ-IdeaVim.git
				synced 2025-11-04 01:40:12 +01:00 
			
		
		
		
	Compare commits
	
		
			15 Commits
		
	
	
		
			12575c3cb9
			...
			30de641513
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						
						
							
						
						30de641513
	
				 | 
					
					
						|||
| 
						
						
							
						
						d1b58c9d39
	
				 | 
					
					
						|||
| 
						
						
							
						
						45ed79d865
	
				 | 
					
					
						|||
| 
						
						
							
						
						527eb4cbb3
	
				 | 
					
					
						|||
| 
						
						
							
						
						e32ac125b2
	
				 | 
					
					
						|||
| 
						
						
							
						
						4d1d3b697c
	
				 | 
					
					
						|||
| 
						
						
							
						
						3246832528
	
				 | 
					
					
						|||
| 
						
						
							
						
						6505bfc9aa
	
				 | 
					
					
						|||
| 
						
						
							
						
						0c63890e9d
	
				 | 
					
					
						|||
| 
						
						
							
						
						259958e702
	
				 | 
					
					
						|||
| 
						
						
							
						
						4916545b53
	
				 | 
					
					
						|||
| 
						
						
							
						
						b8a9bddfa9
	
				 | 
					
					
						|||
| 
						
						
							
						
						95688b33c8
	
				 | 
					
					
						|||
| 
						
						
							
						
						07f44f1c93
	
				 | 
					
					
						|||
| 
						
						
							
						
						2ce6239ad6
	
				 | 
					
					
						
@@ -14,7 +14,7 @@ ideaVersion=2024.1
 | 
				
			|||||||
ideaType=IC
 | 
					ideaType=IC
 | 
				
			||||||
downloadIdeaSources=true
 | 
					downloadIdeaSources=true
 | 
				
			||||||
instrumentPluginCode=true
 | 
					instrumentPluginCode=true
 | 
				
			||||||
version=chylex-34
 | 
					version=chylex-33
 | 
				
			||||||
javaVersion=17
 | 
					javaVersion=17
 | 
				
			||||||
remoteRobotVersion=0.11.22
 | 
					remoteRobotVersion=0.11.22
 | 
				
			||||||
antlrVersion=4.10.1
 | 
					antlrVersion=4.10.1
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,25 +8,21 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package com.maddyhome.idea.vim.extension.nerdtree
 | 
					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.ActionManager
 | 
				
			||||||
import com.intellij.openapi.actionSystem.ActionUpdateThread
 | 
					import com.intellij.openapi.actionSystem.ActionUpdateThread
 | 
				
			||||||
import com.intellij.openapi.actionSystem.AnActionEvent
 | 
					import com.intellij.openapi.actionSystem.AnActionEvent
 | 
				
			||||||
import com.intellij.openapi.actionSystem.CommonDataKeys
 | 
					import com.intellij.openapi.actionSystem.CommonDataKeys
 | 
				
			||||||
 | 
					import com.intellij.openapi.actionSystem.PlatformCoreDataKeys
 | 
				
			||||||
import com.intellij.openapi.actionSystem.PlatformDataKeys
 | 
					import com.intellij.openapi.actionSystem.PlatformDataKeys
 | 
				
			||||||
import com.intellij.openapi.application.ApplicationManager
 | 
					import com.intellij.openapi.application.ApplicationManager
 | 
				
			||||||
import com.intellij.openapi.diagnostic.logger
 | 
					import com.intellij.openapi.diagnostic.logger
 | 
				
			||||||
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
 | 
					import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
 | 
				
			||||||
import com.intellij.openapi.project.DumbAwareAction
 | 
					import com.intellij.openapi.project.DumbAwareAction
 | 
				
			||||||
import com.intellij.openapi.project.Project
 | 
					import com.intellij.openapi.ui.getUserData
 | 
				
			||||||
import com.intellij.openapi.project.ProjectManager
 | 
					import com.intellij.openapi.ui.putUserData
 | 
				
			||||||
import com.intellij.openapi.startup.ProjectActivity
 | 
					import com.intellij.openapi.util.Key
 | 
				
			||||||
import com.intellij.openapi.wm.ToolWindow
 | 
					 | 
				
			||||||
import com.intellij.openapi.wm.ToolWindowId
 | 
					import com.intellij.openapi.wm.ToolWindowId
 | 
				
			||||||
import com.intellij.openapi.wm.ex.ToolWindowManagerEx
 | 
					import com.intellij.openapi.wm.ex.ToolWindowManagerEx
 | 
				
			||||||
import com.intellij.openapi.wm.ex.ToolWindowManagerListener
 | 
					 | 
				
			||||||
import com.intellij.ui.KeyStrokeAdapter
 | 
					import com.intellij.ui.KeyStrokeAdapter
 | 
				
			||||||
import com.intellij.ui.TreeExpandCollapse
 | 
					import com.intellij.ui.TreeExpandCollapse
 | 
				
			||||||
import com.intellij.ui.speedSearch.SpeedSearchSupply
 | 
					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.newapi.vim
 | 
				
			||||||
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString
 | 
					import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString
 | 
				
			||||||
import java.awt.event.KeyEvent
 | 
					import java.awt.event.KeyEvent
 | 
				
			||||||
 | 
					import javax.swing.JComponent
 | 
				
			||||||
 | 
					import javax.swing.JTree
 | 
				
			||||||
import javax.swing.KeyStroke
 | 
					import javax.swing.KeyStroke
 | 
				
			||||||
import javax.swing.SwingConstants
 | 
					import javax.swing.SwingConstants
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -132,7 +130,6 @@ internal class NerdTree : VimExtension {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    synchronized(Util.monitor) {
 | 
					    synchronized(Util.monitor) {
 | 
				
			||||||
      Util.commandsRegistered = true
 | 
					      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() {
 | 
					  class NerdDispatcher : DumbAwareAction() {
 | 
				
			||||||
    internal var waitForSearch = false
 | 
					    internal var waitForSearch = false
 | 
				
			||||||
    internal var speedSearchListenerInstalled = false
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun actionPerformed(e: AnActionEvent) {
 | 
					    override fun actionPerformed(e: AnActionEvent) {
 | 
				
			||||||
      var keyStroke = getKeyStroke(e) ?: return
 | 
					      var keyStroke = getKeyStroke(e) ?: return
 | 
				
			||||||
@@ -244,10 +210,6 @@ internal class NerdTree : VimExtension {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    companion object {
 | 
					    companion object {
 | 
				
			||||||
      fun getInstance(project: Project): NerdDispatcher {
 | 
					 | 
				
			||||||
        return project.getService(NerdDispatcher::class.java)
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      private const val ESCAPE_KEY_CODE = 27
 | 
					      private const val ESCAPE_KEY_CODE = 27
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -283,19 +245,14 @@ internal class NerdTree : VimExtension {
 | 
				
			|||||||
    registerCommand(
 | 
					    registerCommand(
 | 
				
			||||||
      "NERDTreeMapActivateNode",
 | 
					      "NERDTreeMapActivateNode",
 | 
				
			||||||
      "o",
 | 
					      "o",
 | 
				
			||||||
      NerdAction.Code { project, dataContext, _ ->
 | 
					      NerdAction.Code { _, dataContext, e ->
 | 
				
			||||||
        val tree = ProjectView.getInstance(project).currentProjectViewPane.tree
 | 
					        val tree = getTree(e) ?: return@Code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val array = CommonDataKeys.NAVIGATABLE_ARRAY.getData(dataContext)?.filter { it.canNavigateToSource() }
 | 
					        val row = tree.selectionRows?.getOrNull(0) ?: return@Code
 | 
				
			||||||
        if (array.isNullOrEmpty()) {
 | 
					        if (tree.isExpanded(row)) {
 | 
				
			||||||
          val row = tree.selectionRows?.getOrNull(0) ?: return@Code
 | 
					          tree.collapseRow(row)
 | 
				
			||||||
          if (tree.isExpanded(row)) {
 | 
					 | 
				
			||||||
            tree.collapseRow(row)
 | 
					 | 
				
			||||||
          } else {
 | 
					 | 
				
			||||||
            tree.expandRow(row)
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          array.forEach { it.navigate(true) }
 | 
					          tree.expandRow(row)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
@@ -374,8 +331,8 @@ internal class NerdTree : VimExtension {
 | 
				
			|||||||
    registerCommand(
 | 
					    registerCommand(
 | 
				
			||||||
      "NERDTreeMapOpenRecursively",
 | 
					      "NERDTreeMapOpenRecursively",
 | 
				
			||||||
      "O",
 | 
					      "O",
 | 
				
			||||||
      NerdAction.Code { project, _, _ ->
 | 
					      NerdAction.Code { _, _, e ->
 | 
				
			||||||
        val tree = ProjectView.getInstance(project).currentProjectViewPane.tree
 | 
					        val tree = getTree(e) ?: return@Code
 | 
				
			||||||
        TreeExpandCollapse.expandAll(tree)
 | 
					        TreeExpandCollapse.expandAll(tree)
 | 
				
			||||||
        tree.selectionPath?.let {
 | 
					        tree.selectionPath?.let {
 | 
				
			||||||
          TreeUtil.scrollToVisible(tree, it, false)
 | 
					          TreeUtil.scrollToVisible(tree, it, false)
 | 
				
			||||||
@@ -385,8 +342,8 @@ internal class NerdTree : VimExtension {
 | 
				
			|||||||
    registerCommand(
 | 
					    registerCommand(
 | 
				
			||||||
      "NERDTreeMapCloseChildren",
 | 
					      "NERDTreeMapCloseChildren",
 | 
				
			||||||
      "X",
 | 
					      "X",
 | 
				
			||||||
      NerdAction.Code { project, _, _ ->
 | 
					      NerdAction.Code { _, _, e ->
 | 
				
			||||||
        val tree = ProjectView.getInstance(project).currentProjectViewPane.tree
 | 
					        val tree = getTree(e) ?: return@Code
 | 
				
			||||||
        TreeExpandCollapse.collapse(tree)
 | 
					        TreeExpandCollapse.collapse(tree)
 | 
				
			||||||
        tree.selectionPath?.let {
 | 
					        tree.selectionPath?.let {
 | 
				
			||||||
          TreeUtil.scrollToVisible(tree, it, false)
 | 
					          TreeUtil.scrollToVisible(tree, it, false)
 | 
				
			||||||
@@ -396,8 +353,8 @@ internal class NerdTree : VimExtension {
 | 
				
			|||||||
    registerCommand(
 | 
					    registerCommand(
 | 
				
			||||||
      "NERDTreeMapCloseDir",
 | 
					      "NERDTreeMapCloseDir",
 | 
				
			||||||
      "x",
 | 
					      "x",
 | 
				
			||||||
      NerdAction.Code { project, _, _ ->
 | 
					      NerdAction.Code { _, _, e ->
 | 
				
			||||||
        val tree = ProjectView.getInstance(project).currentProjectViewPane.tree
 | 
					        val tree = getTree(e) ?: return@Code
 | 
				
			||||||
        val currentPath = tree.selectionPath ?: return@Code
 | 
					        val currentPath = tree.selectionPath ?: return@Code
 | 
				
			||||||
        if (tree.isExpanded(currentPath)) {
 | 
					        if (tree.isExpanded(currentPath)) {
 | 
				
			||||||
          tree.collapsePath(currentPath)
 | 
					          tree.collapsePath(currentPath)
 | 
				
			||||||
@@ -415,8 +372,8 @@ internal class NerdTree : VimExtension {
 | 
				
			|||||||
    registerCommand(
 | 
					    registerCommand(
 | 
				
			||||||
      "NERDTreeMapJumpParent",
 | 
					      "NERDTreeMapJumpParent",
 | 
				
			||||||
      "p",
 | 
					      "p",
 | 
				
			||||||
      NerdAction.Code { project, _, _ ->
 | 
					      NerdAction.Code { _, _, e ->
 | 
				
			||||||
        val tree = ProjectView.getInstance(project).currentProjectViewPane.tree
 | 
					        val tree = getTree(e) ?: return@Code
 | 
				
			||||||
        val currentPath = tree.selectionPath ?: return@Code
 | 
					        val currentPath = tree.selectionPath ?: return@Code
 | 
				
			||||||
        val parentPath = currentPath.parentPath ?: return@Code
 | 
					        val parentPath = currentPath.parentPath ?: return@Code
 | 
				
			||||||
        if (parentPath.parentPath != null) {
 | 
					        if (parentPath.parentPath != null) {
 | 
				
			||||||
@@ -429,8 +386,8 @@ internal class NerdTree : VimExtension {
 | 
				
			|||||||
    registerCommand(
 | 
					    registerCommand(
 | 
				
			||||||
      "NERDTreeMapJumpFirstChild",
 | 
					      "NERDTreeMapJumpFirstChild",
 | 
				
			||||||
      "K",
 | 
					      "K",
 | 
				
			||||||
      NerdAction.Code { project, _, _ ->
 | 
					      NerdAction.Code { _, _, e ->
 | 
				
			||||||
        val tree = ProjectView.getInstance(project).currentProjectViewPane.tree
 | 
					        val tree = getTree(e) ?: return@Code
 | 
				
			||||||
        val currentPath = tree.selectionPath ?: return@Code
 | 
					        val currentPath = tree.selectionPath ?: return@Code
 | 
				
			||||||
        val parent = currentPath.parentPath ?: return@Code
 | 
					        val parent = currentPath.parentPath ?: return@Code
 | 
				
			||||||
        val row = tree.getRowForPath(parent)
 | 
					        val row = tree.getRowForPath(parent)
 | 
				
			||||||
@@ -442,8 +399,8 @@ internal class NerdTree : VimExtension {
 | 
				
			|||||||
    registerCommand(
 | 
					    registerCommand(
 | 
				
			||||||
      "NERDTreeMapJumpLastChild",
 | 
					      "NERDTreeMapJumpLastChild",
 | 
				
			||||||
      "J",
 | 
					      "J",
 | 
				
			||||||
      NerdAction.Code { project, _, _ ->
 | 
					      NerdAction.Code { _, _, e ->
 | 
				
			||||||
        val tree = ProjectView.getInstance(project).currentProjectViewPane.tree
 | 
					        val tree = getTree(e) ?: return@Code
 | 
				
			||||||
        val currentPath = tree.selectionPath ?: return@Code
 | 
					        val currentPath = tree.selectionPath ?: return@Code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val currentPathCount = currentPath.pathCount
 | 
					        val currentPathCount = currentPath.pathCount
 | 
				
			||||||
@@ -464,12 +421,12 @@ internal class NerdTree : VimExtension {
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
    registerCommand(
 | 
					    registerCommand(
 | 
				
			||||||
      "NERDTreeMapJumpNextSibling",
 | 
					      "NERDTreeMapJumpNextSibling",
 | 
				
			||||||
      "<C-J>",
 | 
					      "<A-J>",
 | 
				
			||||||
      NerdAction.ToIj("Tree-selectNextSibling"),
 | 
					      NerdAction.ToIj("Tree-selectNextSibling"),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    registerCommand(
 | 
					    registerCommand(
 | 
				
			||||||
      "NERDTreeMapJumpPrevSibling",
 | 
					      "NERDTreeMapJumpPrevSibling",
 | 
				
			||||||
      "<C-K>",
 | 
					      "<A-K>",
 | 
				
			||||||
      NerdAction.ToIj("Tree-selectPreviousSibling"),
 | 
					      NerdAction.ToIj("Tree-selectPreviousSibling"),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    registerCommand(
 | 
					    registerCommand(
 | 
				
			||||||
@@ -488,20 +445,26 @@ internal class NerdTree : VimExtension {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    registerCommand(
 | 
					    registerCommand(
 | 
				
			||||||
      "/",
 | 
					      "/",
 | 
				
			||||||
      NerdAction.Code { project, _, _ ->
 | 
					      NerdAction.Code { _, _, e ->
 | 
				
			||||||
        NerdDispatcher.getInstance(project).waitForSearch = true
 | 
					        val tree = getTree(e) ?: return@Code
 | 
				
			||||||
 | 
					        tree.getUserData(KEY)?.waitForSearch = true
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    registerCommand(
 | 
					    registerCommand(
 | 
				
			||||||
      "<ESC>",
 | 
					      "<ESC>",
 | 
				
			||||||
      NerdAction.Code { project, _, _ ->
 | 
					      NerdAction.Code { _, _, e ->
 | 
				
			||||||
        val instance = NerdDispatcher.getInstance(project)
 | 
					        val tree = getTree(e) ?: return@Code
 | 
				
			||||||
        if (instance.waitForSearch) {
 | 
					        tree.getUserData(KEY)?.waitForSearch = false
 | 
				
			||||||
          instance.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 {
 | 
					  object Util {
 | 
				
			||||||
@@ -526,6 +489,21 @@ internal class NerdTree : VimExtension {
 | 
				
			|||||||
  companion object {
 | 
					  companion object {
 | 
				
			||||||
    const val pluginName = "NERDTree"
 | 
					    const val pluginName = "NERDTree"
 | 
				
			||||||
    private val LOG = logger<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) {
 | 
					private fun getTree(e: AnActionEvent): JTree? {
 | 
				
			||||||
  val dispatcher = NerdTree.NerdDispatcher.getInstance(project)
 | 
					  return e.dataContext.getData(PlatformCoreDataKeys.CONTEXT_COMPONENT) as? JTree
 | 
				
			||||||
  val shortcuts =
 | 
					 | 
				
			||||||
    collectShortcuts(actionsRoot).map { RequiredShortcut(it, MappingOwner.Plugin.get(NerdTree.pluginName)) }
 | 
					 | 
				
			||||||
  dispatcher.registerCustomShortcutSet(
 | 
					 | 
				
			||||||
    KeyGroup.toShortcutSet(shortcuts),
 | 
					 | 
				
			||||||
    (ProjectView.getInstance(project) as ProjectViewImpl).component,
 | 
					 | 
				
			||||||
  )
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -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() {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -61,15 +61,18 @@ internal class UndoRedoHelper : UndoRedoBase() {
 | 
				
			|||||||
    undoManager: UndoManager,
 | 
					    undoManager: UndoManager,
 | 
				
			||||||
    fileEditor: TextEditor,
 | 
					    fileEditor: TextEditor,
 | 
				
			||||||
    editor: VimEditor,
 | 
					    editor: VimEditor,
 | 
				
			||||||
  ) {
 | 
					  ) {if (injector.globalIjOptions().oldundo) {
 | 
				
			||||||
    if (injector.globalIjOptions().oldundo) {
 | 
					        SelectionVimListenerSuppressor.lock().use { undoManager.undo(fileEditor) }
 | 
				
			||||||
      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)
 | 
					 | 
				
			||||||
        restoreVisualMode(editor)
 | 
					        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 {
 | 
					      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
 | 
					      // TODO refactor me after VIM-308 when restoring selection and caret movement will be ignored by undo
 | 
				
			||||||
      editor.runWithChangeTracking {
 | 
					      editor.runWithChangeTracking {
 | 
				
			||||||
        undoManager.undo(fileEditor)
 | 
					        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 {
 | 
					    } else {
 | 
				
			||||||
      runWithBooleanRegistryOption("ide.undo.transparent.caret.movement", true) {
 | 
					      runWithBooleanRegistryOption("ide.undo.transparent.caret.movement", true) {
 | 
				
			||||||
@@ -104,7 +115,7 @@ internal class UndoRedoHelper : UndoRedoBase() {
 | 
				
			|||||||
  private fun hasSelection(editor: VimEditor): Boolean {
 | 
					  private fun hasSelection(editor: VimEditor): Boolean {
 | 
				
			||||||
    return editor.primaryCaret().ij.hasSelection()
 | 
					    return editor.primaryCaret().ij.hasSelection()
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
  override fun redo(editor: VimEditor, context: ExecutionContext): Boolean {
 | 
					  override fun redo(editor: VimEditor, context: ExecutionContext): Boolean {
 | 
				
			||||||
    val ijContext = context.context as DataContext
 | 
					    val ijContext = context.context as DataContext
 | 
				
			||||||
    val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false
 | 
					    val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false
 | 
				
			||||||
@@ -127,17 +138,17 @@ internal class UndoRedoHelper : UndoRedoBase() {
 | 
				
			|||||||
    undoManager: UndoManager,
 | 
					    undoManager: UndoManager,
 | 
				
			||||||
    fileEditor: TextEditor,
 | 
					    fileEditor: TextEditor,
 | 
				
			||||||
    editor: VimEditor,
 | 
					    editor: VimEditor,
 | 
				
			||||||
  ) {
 | 
					  ) {if (injector.globalIjOptions().oldundo) {
 | 
				
			||||||
    if (injector.globalIjOptions().oldundo) {
 | 
					        SelectionVimListenerSuppressor.lock().use { undoManager.redo(fileEditor) }
 | 
				
			||||||
      SelectionVimListenerSuppressor.lock().use { undoManager.redo(fileEditor) }
 | 
					        restoreVisualMode(editor)
 | 
				
			||||||
    } else {
 | 
					      } 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)
 | 
					        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
 | 
					        // We execute undo one more time if the previous one just restored selection
 | 
				
			||||||
        if (!hasChanges && hasSelection(editor) && undoManager.isRedoAvailable(fileEditor)) {
 | 
					        if (!hasChanges && hasSelection(editor) && undoManager.isRedoAvailable(fileEditor)) {
 | 
				
			||||||
@@ -233,7 +244,7 @@ internal class UndoRedoHelper : UndoRedoBase() {
 | 
				
			|||||||
  private fun restoreVisualMode(editor: VimEditor) {
 | 
					  private fun restoreVisualMode(editor: VimEditor) {
 | 
				
			||||||
    if (!editor.inVisualMode && editor.getSelectionModel().hasSelection()) {
 | 
					    if (!editor.inVisualMode && editor.getSelectionModel().hasSelection()) {
 | 
				
			||||||
      val detectedMode = VimPlugin.getVisualMotion().autodetectVisualSubmode(editor)
 | 
					      val detectedMode = VimPlugin.getVisualMotion().autodetectVisualSubmode(editor)
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
      // Visual block selection is restored into multiple carets, so multi-carets that form a block are always
 | 
					      // Visual block selection is restored into multiple carets, so multi-carets that form a block are always
 | 
				
			||||||
      // identified as visual block mode, leading to false positives.
 | 
					      // identified as visual block mode, leading to false positives.
 | 
				
			||||||
      // Since I use visual block mode much less often than multi-carets, this is a judgment call to never restore
 | 
					      // Since I use visual block mode much less often than multi-carets, this is a judgment call to never restore
 | 
				
			||||||
@@ -242,7 +253,7 @@ internal class UndoRedoHelper : UndoRedoBase() {
 | 
				
			|||||||
        SelectionType.CHARACTER_WISE
 | 
					        SelectionType.CHARACTER_WISE
 | 
				
			||||||
      else
 | 
					      else
 | 
				
			||||||
        detectedMode
 | 
					        detectedMode
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
      VimPlugin.getVisualMotion().enterVisualMode(editor, wantedMode)
 | 
					      VimPlugin.getVisualMotion().enterVisualMode(editor, wantedMode)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -136,11 +136,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  <!--  IdeaVim extensions-->
 | 
					  <!--  IdeaVim extensions-->
 | 
				
			||||||
  <extensions defaultExtensionNs="com.intellij">
 | 
					  <extensions defaultExtensionNs="com.intellij">
 | 
				
			||||||
    <projectService serviceImplementation="com.maddyhome.idea.vim.extension.nerdtree.NerdTree$NerdDispatcher"/>
 | 
					    <applicationService serviceImplementation="com.maddyhome.idea.vim.extension.nerdtree.NerdTree$NerdDispatcher"/>
 | 
				
			||||||
    <postStartupActivity implementation="com.maddyhome.idea.vim.extension.nerdtree.NerdTree$NerdStartupActivity"/>
 | 
					    <applicationInitializedListener implementation="com.maddyhome.idea.vim.extension.nerdtree.NerdTreeApplicationListener"/>
 | 
				
			||||||
  </extensions>
 | 
					  </extensions>
 | 
				
			||||||
  <projectListeners>
 | 
					 | 
				
			||||||
    <listener class="com.maddyhome.idea.vim.extension.nerdtree.NerdTree$ProjectViewListener"
 | 
					 | 
				
			||||||
              topic="com.intellij.openapi.wm.ex.ToolWindowManagerListener"/>
 | 
					 | 
				
			||||||
  </projectListeners>
 | 
					 | 
				
			||||||
</idea-plugin>
 | 
					</idea-plugin>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user