Skip to content

Commit 5153b8a

Browse files
committed
VIM-4134 Extract frontend-only dependencies from VimPlugin
1 parent 765cf27 commit 5153b8a

File tree

9 files changed

+205
-162
lines changed

9 files changed

+205
-162
lines changed
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
/*
2+
* Copyright 2003-2026 The IdeaVim authors
3+
*
4+
* Use of this source code is governed by an MIT-style
5+
* license that can be found in the LICENSE.txt file or at
6+
* https://opensource.org/licenses/MIT.
7+
*/
8+
9+
package com.maddyhome.idea.vim
10+
11+
import com.intellij.openapi.application.ApplicationManager
12+
import com.intellij.openapi.components.Service
13+
import com.intellij.openapi.diagnostic.Logger
14+
import com.intellij.openapi.keymap.Keymap
15+
import com.intellij.openapi.keymap.ex.KeymapManagerEx
16+
import com.intellij.openapi.keymap.impl.DefaultKeymap
17+
import com.intellij.openapi.ui.Messages
18+
import com.intellij.openapi.util.SystemInfo
19+
import com.intellij.util.SlowOperations
20+
import com.maddyhome.idea.vim.api.VimPluginActivator
21+
import com.maddyhome.idea.vim.api.injector
22+
import com.maddyhome.idea.vim.extension.VimExtensionRegistrar
23+
import com.maddyhome.idea.vim.helper.MacKeyRepeat
24+
import com.maddyhome.idea.vim.listener.VimListenerManager
25+
import com.maddyhome.idea.vim.newapi.IjVimSearchGroup
26+
import com.maddyhome.idea.vim.ui.StatusBarIconFactory
27+
import com.maddyhome.idea.vim.vimscript.services.VimRcService.executeIdeaVimRc
28+
29+
/**
30+
* Handles the frontend-facing plugin activation/deactivation lifecycle.
31+
*
32+
* This class contains the logic that was previously in VimPlugin.turnOnPlugin/turnOffPlugin.
33+
* It's separated to decouple VimPlugin.java from frontend-only classes like VimListenerManager,
34+
* RegisterActions, StatusBarIconFactory, etc.
35+
*
36+
* This class (and its dependencies) can be moved to the frontend module once the split is complete.
37+
*/
38+
@Service
39+
internal class IjVimPluginActivator : VimPluginActivator {
40+
41+
private val log = Logger.getInstance(IjVimPluginActivator::class.java)
42+
private var stateUpdated = false
43+
44+
/**
45+
* IdeaVim plugin activation.
46+
* This is an important operation and some commands ordering should be preserved.
47+
* Please make sure that the documentation of this function is in sync with the code.
48+
*
49+
* 1. Update state - schedules a state update (shows dialogs to the user)
50+
* 2. Command registration - BEFORE ~/.ideavimrc execution
51+
* 2.1 Register vim actions in command mode
52+
* 2.2 Register extensions
53+
* 2.3 Register functions
54+
* 3. Options initialisation
55+
* 4. ~/.ideavimrc execution
56+
* 5. Components initialization - AFTER ideavimrc execution
57+
* (VimListenerManager accesses `number` option and guicaret)
58+
*/
59+
override fun activate() {
60+
// 1) Update state
61+
ApplicationManager.getApplication().invokeLater(this::updateState)
62+
63+
// 2) Command registration
64+
// 2.1) Register vim actions in command mode
65+
RegisterActions.registerActions()
66+
67+
// 2.2) Register extensions
68+
VimExtensionRegistrar.registerExtensions()
69+
70+
// 2.3) Register functions
71+
injector.functionService.registerHandlers()
72+
73+
// 3) Option initialisation
74+
injector.optionGroup.initialiseOptions()
75+
76+
// 4) ~/.ideavimrc execution
77+
// Evaluate in the context of the fallback window, to capture local option state, to copy to the first editor window
78+
try {
79+
SlowOperations.knownIssue("VIM-3661").use {
80+
registerIdeavimrc()
81+
}
82+
} catch (e: Exception) {
83+
log.error("Failed to register ideavimrc", e)
84+
}
85+
86+
// 5) Turning on should be performed after all commands registration
87+
VimPlugin.getSearch().turnOn()
88+
VimListenerManager.turnOn()
89+
}
90+
91+
override fun deactivate(unsubscribe: Boolean) {
92+
val searchGroup: IjVimSearchGroup? = VimPlugin.getSearchIfCreated()
93+
searchGroup?.turnOff()
94+
95+
if (unsubscribe) {
96+
VimListenerManager.turnOff()
97+
}
98+
99+
// Use getServiceIfCreated to avoid creating the service during the dispose (this is prohibited by the platform)
100+
ApplicationManager.getApplication()
101+
.getServiceIfCreated(com.maddyhome.idea.vim.api.VimCommandLineService::class.java)
102+
?.fullReset()
103+
104+
// Unregister vim actions in command mode
105+
RegisterActions.unregisterActions()
106+
}
107+
108+
override fun updateStatusBarIcon() {
109+
StatusBarIconFactory.Util.updateIcon()
110+
}
111+
112+
private var ideavimrcRegistered = false
113+
114+
private fun registerIdeavimrc() {
115+
if (ideavimrcRegistered) return
116+
ideavimrcRegistered = true
117+
118+
if (!ApplicationManager.getApplication().isUnitTestMode) {
119+
try {
120+
injector.optionGroup.startInitVimRc()
121+
executeIdeaVimRc(injector.fallbackWindow)
122+
} finally {
123+
injector.optionGroup.endInitVimRc()
124+
}
125+
}
126+
}
127+
128+
private fun updateState() {
129+
if (stateUpdated) return
130+
if (VimPlugin.isEnabled() && !ApplicationManager.getApplication().isUnitTestMode) {
131+
stateUpdated = true
132+
if (SystemInfo.isMac) {
133+
val enabled = MacKeyRepeat.isEnabled
134+
val isKeyRepeat = VimPlugin.getEditor().isKeyRepeat()
135+
if ((enabled == null || !enabled) && (isKeyRepeat == null || isKeyRepeat)) {
136+
// This system property is used in IJ ui robot to hide the startup tips
137+
val showNotification =
138+
System.getProperty("ide.show.tips.on.startup.default.value", "true").toBoolean()
139+
log.info("Do not show mac repeat notification because ide.show.tips.on.startup.default.value=false")
140+
if (showNotification) {
141+
if (VimPlugin.getNotifications(null).enableRepeatingMode() == Messages.YES) {
142+
VimPlugin.getEditor().setKeyRepeat(true)
143+
MacKeyRepeat.isEnabled = true
144+
} else {
145+
VimPlugin.getEditor().setKeyRepeat(false)
146+
}
147+
}
148+
}
149+
}
150+
151+
val previousStateVersion = VimPlugin.getInstance().previousStateVersion
152+
val previousKeyMap = VimPlugin.getInstance().previousKeyMap
153+
154+
if (previousStateVersion > 0 && previousStateVersion < 3) {
155+
val manager = KeymapManagerEx.getInstanceEx()
156+
var keymap: Keymap? = null
157+
if (previousKeyMap != null) {
158+
keymap = manager.getKeymap(previousKeyMap)
159+
}
160+
if (keymap == null) {
161+
keymap = manager.getKeymap(DefaultKeymap.getInstance().defaultKeymapName)
162+
}
163+
assert(keymap != null) { "Default keymap not found" }
164+
manager.activeKeymap = keymap!!
165+
}
166+
if (previousStateVersion > 0 && previousStateVersion < 4) {
167+
VimPlugin.getNotifications(null).noVimrcAsDefault()
168+
}
169+
}
170+
}
171+
}

0 commit comments

Comments
 (0)