Skip to content

Commit b201f8b

Browse files
committed
VIM-4134 Extract frontend-only dependencies from common module
1 parent 5153b8a commit b201f8b

File tree

136 files changed

+762
-531
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

136 files changed

+762
-531
lines changed

build.gradle.kts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,9 @@ dependencies {
8787
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")
8888
compileOnly("org.jetbrains:annotations:26.0.2-1")
8989

90-
// Test fixtures need access to the plugin classes (now in ideavim-common)
90+
// Test fixtures need access to the plugin classes (now in ideavim-common and ideavim-frontend)
9191
testFixturesApi(project(":modules:ideavim-common"))
92+
testFixturesApi(project(":modules:ideavim-frontend"))
9293

9394
intellijPlatform {
9495
// Snapshots don't use installers
@@ -374,22 +375,29 @@ afterEvaluate {
374375
tasks.named("kspTestKotlin").configure { enabled = false }
375376
}
376377

377-
// Allow test and testFixtures sources to access `internal` members from :modules:ideavim-common.
378-
// This is needed because all plugin source code was moved to the common module during the plugin split,
379-
// but tests remain in the root project. Kotlin's -Xfriend-paths compiler flag grants internal visibility
380-
// across module boundaries for testing purposes.
378+
// Allow test and testFixtures sources to access `internal` members from :modules:ideavim-common
379+
// and :modules:ideavim-frontend.
380+
// This is needed because plugin source code was split across common and frontend modules during the
381+
// plugin split, but tests remain in the root project. Kotlin's -Xfriend-paths compiler flag grants
382+
// internal visibility across module boundaries for testing purposes.
381383
// We add both the class directory and the JAR because the IntelliJ Platform Gradle plugin may resolve
382384
// classes from the composed/instrumented JAR rather than raw class files.
383385
val commonProject = project(":modules:ideavim-common")
384386
val commonClassesDir = commonProject.layout.buildDirectory.dir("classes/kotlin/main").get().asFile
385387
val commonLibsDir = commonProject.layout.buildDirectory.dir("libs").get().asFile
388+
val frontendProject = project(":modules:ideavim-frontend")
389+
val frontendClassesDir = frontendProject.layout.buildDirectory.dir("classes/kotlin/main").get().asFile
386390
tasks.named<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>("compileTestKotlin") {
387391
friendPaths.from(commonClassesDir)
388392
friendPaths.from(commonProject.layout.buildDirectory.dir("libs"))
393+
friendPaths.from(frontendClassesDir)
394+
friendPaths.from(frontendProject.layout.buildDirectory.dir("libs"))
389395
}
390396
tasks.named<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>("compileTestFixturesKotlin") {
391397
friendPaths.from(commonClassesDir)
392398
friendPaths.from(commonProject.layout.buildDirectory.dir("libs"))
399+
friendPaths.from(frontendClassesDir)
400+
friendPaths.from(frontendProject.layout.buildDirectory.dir("libs"))
393401
}
394402

395403

modules/ideavim-backend/src/main/resources/IdeaVIM.ideavim-backend.xml

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -62,37 +62,4 @@
6262
<!-- NERDTree startup (ProjectView integration) -->
6363
<postStartupActivity implementation="com.maddyhome.idea.vim.extension.nerdtree.NerdTree$NerdStartupActivity"/>
6464
</extensions>
65-
66-
<!-- PSI/file-dependent vim extensions -->
67-
<extensions defaultExtensionNs="IdeaVIM">
68-
<vimExtension implementation="com.maddyhome.idea.vim.extension.nerdtree.NerdTree" name="NERDTree">
69-
<aliases>
70-
<alias name="https://github.com/preservim/nerdtree"/>
71-
<alias name="preservim/nerdtree"/>
72-
<alias name="https://github.com/scrooloose/nerdtree"/>
73-
<alias name="scrooloose/nerdtree"/>
74-
<alias name="nerdtree"/>
75-
</aliases>
76-
</vimExtension>
77-
78-
<vimExtension implementation="com.maddyhome.idea.vim.extension.commentary.CommentaryExtension" name="commentary">
79-
<aliases>
80-
<alias name="https://github.com/tpope/vim-commentary"/>
81-
<alias name="tpope/vim-commentary"/>
82-
<alias name="vim-commentary"/>
83-
<alias name="https://www.vim.org/scripts/script.php?script_id=3695"/>
84-
<alias name="https://github.com/tomtom/tcomment_vim"/>
85-
<alias name="tomtom/tcomment_vim"/>
86-
<alias name="tcomment_vim"/>
87-
<alias name="https://www.vim.org/scripts/script.php?script_id=1173"/>
88-
</aliases>
89-
</vimExtension>
90-
91-
<vimExtension implementation="com.maddyhome.idea.vim.extension.matchit.Matchit" name="matchit">
92-
<aliases>
93-
<alias name="vim-matchit"/>
94-
<alias name="chrisbra/matchit"/>
95-
</aliases>
96-
</vimExtension>
97-
</extensions>
9865
</idea-plugin>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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.fileEditor.ex.FileEditorManagerEx
12+
import com.intellij.openapi.project.Project
13+
import com.intellij.openapi.project.ProjectManagerListener
14+
import com.maddyhome.idea.vim.api.injector
15+
import com.maddyhome.idea.vim.helper.EditorHelper
16+
import com.maddyhome.idea.vim.newapi.IjVimEditor
17+
import com.maddyhome.idea.vim.newapi.globalIjOptions
18+
import com.maddyhome.idea.vim.newapi.initInjector
19+
20+
// This is a temporal workaround for VIM-2487
21+
internal class PyNotebooksCloseWorkaround : ProjectManagerListener {
22+
override fun projectClosingBeforeSave(project: Project) {
23+
initInjector()
24+
// TODO: Confirm context in CWM scenario
25+
if (injector.globalIjOptions().closenotebooks) {
26+
injector.editorGroup.getEditors().forEach { vimEditor ->
27+
val editor = (vimEditor as IjVimEditor).editor
28+
val virtualFile = EditorHelper.getVirtualFile(editor)
29+
if (virtualFile?.extension == "ipynb") {
30+
val fileEditorManager = FileEditorManagerEx.getInstanceEx(project)
31+
fileEditorManager.closeFile(virtualFile)
32+
}
33+
}
34+
}
35+
}
36+
}

modules/ideavim-common/src/main/java/com/maddyhome/idea/vim/RegisterActions.kt

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
/*
2-
* Copyright 2003-2023 The IdeaVim authors
2+
* Copyright 2003-2026 The IdeaVim authors
33
*
44
* Use of this source code is governed by an MIT-style
55
* license that can be found in the LICENSE.txt file or at
66
* https://opensource.org/licenses/MIT.
77
*/
88
package com.maddyhome.idea.vim
99

10+
import com.maddyhome.idea.vim.RegisterActions.registerActions
11+
import com.maddyhome.idea.vim.action.CommandProvider
1012
import com.maddyhome.idea.vim.action.EngineCommandProvider
1113
import com.maddyhome.idea.vim.action.IntellijCommandProvider
1214
import com.maddyhome.idea.vim.handler.EditorActionHandlerBase
@@ -15,6 +17,20 @@ import java.awt.event.KeyEvent
1517
import javax.swing.KeyStroke
1618

1719
object RegisterActions {
20+
21+
private val additionalCommandProviders = mutableListOf<CommandProvider>()
22+
23+
/**
24+
* Registers an additional [CommandProvider] whose commands will be included
25+
* during action registration. Call this before [registerActions].
26+
*
27+
* This allows modules like ideavim-frontend to contribute their own
28+
* KSP-generated commands without a compile-time dependency from common.
29+
*/
30+
fun registerCommandProvider(provider: CommandProvider) {
31+
additionalCommandProviders.add(provider)
32+
}
33+
1834
/**
1935
* Register all the key/action mappings for the plugin.
2036
*/
@@ -25,8 +41,8 @@ object RegisterActions {
2541
}
2642

2743
fun findAction(id: String): EditorActionHandlerBase? {
28-
val commandBean = IntellijCommandProvider.getCommands().firstOrNull { it.actionId == id }
29-
?: EngineCommandProvider.getCommands().firstOrNull { it.actionId == id } ?: return null
44+
val allProviders = listOf(IntellijCommandProvider, EngineCommandProvider) + additionalCommandProviders
45+
val commandBean = allProviders.flatMap { it.getCommands() }.firstOrNull { it.actionId == id } ?: return null
3046
return commandBean.instance
3147
}
3248

@@ -44,6 +60,7 @@ object RegisterActions {
4460
val parser = VimPlugin.getKey()
4561
IntellijCommandProvider.getCommands().forEach { parser.registerCommandAction(it) }
4662
EngineCommandProvider.getCommands().forEach { parser.registerCommandAction(it) }
63+
additionalCommandProviders.flatMap { it.getCommands() }.forEach { parser.registerCommandAction(it) }
4764
}
4865

4966
private fun registerShortcutsWithoutActions() {

modules/ideavim-common/src/main/java/com/maddyhome/idea/vim/VimPlugin.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
5454

5555
private final @NotNull VimState state = new VimState();
5656
public Disposable onOffDisposable;
57-
// Package-private for IjVimPluginActivator access
58-
int previousStateVersion = 0;
59-
String previousKeyMap = "";
57+
// Public for cross-module access from IjVimPluginActivator (frontend module)
58+
public int previousStateVersion = 0;
59+
public String previousKeyMap = "";
6060
// It is enabled by default to avoid any special configuration after plugin installation
6161
private boolean enabled = true;
6262

@@ -65,14 +65,14 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
6565
}
6666

6767
/**
68-
* @return NotificationService as applicationService if project is null and projectService otherwise
68+
* @return VimNotifications as applicationService if project is null and projectService otherwise
6969
*/
70-
public static @NotNull NotificationService getNotifications(@Nullable Project project) {
70+
public static @NotNull VimNotifications getNotifications(@Nullable Project project) {
7171
if (project == null) {
72-
return ApplicationManager.getApplication().getService(NotificationService.class);
72+
return ApplicationManager.getApplication().getService(VimNotifications.class);
7373
}
7474
else {
75-
return project.getService(NotificationService.class);
75+
return project.getService(VimNotifications.class);
7676
}
7777
}
7878

@@ -169,7 +169,7 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
169169
return VimInjectorKt.getInjector().getOptionGroup();
170170
}
171171

172-
private static @NotNull NotificationService getNotifications() {
172+
private static @NotNull VimNotifications getNotifications() {
173173
return getNotifications(null);
174174
}
175175

modules/ideavim-common/src/main/java/com/maddyhome/idea/vim/config/VimState.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2003-2023 The IdeaVim authors
2+
* Copyright 2003-2026 The IdeaVim authors
33
*
44
* Use of this source code is governed by an MIT-style
55
* license that can be found in the LICENSE.txt file or at
@@ -15,7 +15,7 @@ import kotlin.reflect.KProperty
1515
/**
1616
* @author Alex Plate
1717
*/
18-
internal class VimState {
18+
class VimState {
1919
var isIdeaJoinNotified by StateProperty("idea-join")
2020
var isIdeaPutNotified by StateProperty("idea-put")
2121
var wasSubscribedToEAPAutomatically by StateProperty("was-automatically-subscribed-to-eap")

modules/ideavim-common/src/main/java/com/maddyhome/idea/vim/extension/VimApi.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2003-2025 The IdeaVim authors
2+
* Copyright 2003-2026 The IdeaVim authors
33
*
44
* Use of this source code is governed by an MIT-style
55
* license that can be found in the LICENSE.txt file or at
@@ -13,7 +13,7 @@ import com.maddyhome.idea.vim.common.ListenerOwner
1313
import com.maddyhome.idea.vim.key.MappingOwner
1414
import com.maddyhome.idea.vim.thinapi.VimApiImpl
1515

16-
internal fun VimExtension.api(): VimApi = VimApiImpl(
16+
fun VimExtension.api(): VimApi = VimApiImpl(
1717
ListenerOwner.Plugin.get(this.name),
1818
MappingOwner.Plugin.get(this.name),
1919
)

modules/ideavim-common/src/main/java/com/maddyhome/idea/vim/extension/VimExtensionFacade.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ import com.maddyhome.idea.vim.key.MappingOwner
3030
import com.maddyhome.idea.vim.key.OperatorFunction
3131
import com.maddyhome.idea.vim.newapi.vim
3232
import com.maddyhome.idea.vim.state.mode.SelectionType
33-
import com.maddyhome.idea.vim.ui.ModalEntry
3433
import com.maddyhome.idea.vim.vimscript.model.Executable
3534
import com.maddyhome.idea.vim.vimscript.model.ExecutionResult
3635
import com.maddyhome.idea.vim.vimscript.model.VimLContext
@@ -168,7 +167,7 @@ object VimExtensionFacade {
168167
} else {
169168
LOG.trace("Getting char from the modal entry...")
170169
var ref: KeyStroke? = null
171-
ModalEntry.activate(editor.vim) { stroke: KeyStroke? ->
170+
injector.modalInput.activate(editor.vim) { stroke: KeyStroke ->
172171
ref = stroke
173172
false
174173
}

modules/ideavim-common/src/main/java/com/maddyhome/idea/vim/extension/VimExtensionRegistrar.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ import com.maddyhome.idea.vim.key.MappingOwner.Plugin.Companion.remove
1818
import com.maddyhome.idea.vim.options.OptionAccessScope
1919
import com.maddyhome.idea.vim.options.OptionDeclaredScope
2020
import com.maddyhome.idea.vim.options.ToggleOption
21-
import com.maddyhome.idea.vim.statistic.PluginState
21+
import com.maddyhome.idea.vim.statistic.ExtensionTracking
2222

23-
internal object VimExtensionRegistrar : VimExtensionRegistrator {
23+
object VimExtensionRegistrar : VimExtensionRegistrator {
2424
internal val registeredExtensions: MutableSet<String> = HashSet()
2525
internal val extensionAliases = HashMap<String, String>()
2626
private var extensionRegistered = false
@@ -67,7 +67,7 @@ internal object VimExtensionRegistrar : VimExtensionRegistrator {
6767
VimPlugin.getOptionGroup().addGlobalOptionChangeListener(option) {
6868
if (injector.optionGroup.getOptionValue(option, OptionAccessScope.GLOBAL(null)).booleanValue) {
6969
initExtension(extensionBean, name)
70-
PluginState.Util.enabledExtensions.add(name)
70+
ExtensionTracking.enabledExtensions.add(name)
7171
} else {
7272
extensionBean.instance.dispose()
7373
}

modules/ideavim-common/src/main/java/com/maddyhome/idea/vim/group/MacroGroup.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2003-2023 The IdeaVim authors
2+
* Copyright 2003-2026 The IdeaVim authors
33
*
44
* Use of this source code is governed by an MIT-style
55
* license that can be found in the LICENSE.txt file or at
@@ -26,7 +26,7 @@ import com.maddyhome.idea.vim.newapi.IjVimEditor
2626
* Used to handle playback of macros
2727
*/
2828
@Service
29-
internal class MacroGroup : VimMacroBase() {
29+
class MacroGroup : VimMacroBase() {
3030

3131
// If it's null, this is the top macro (as in most cases). If it's not null, this macro is executed from top macro
3232
private var potemkinProgress: PotemkinProgress? = null

0 commit comments

Comments
 (0)