
Extensions Api Migration
- 5 installs
- 10.2k repo stars
- Updated August 4, 2026
- jetbrains/ideavim
extensions-api-migration skill documents Migrates IdeaVim extensions from the old VimExtensionFacade API to the new @VimPlugin annotation-based API.
About
extensions-api-migration skill documents Migrates IdeaVim extensions from the old VimExtensionFacade API to the new @VimPlugin annotation-based API. Use when converting existing extensions to use the new API patterns.. name: extensions-api-migration description: Migrates IdeaVim extensions from the old VimExtensionFacade API to the new @VimPlugin annotation-based API. Use when converting existing extensions to use the new API patterns.
- Migrates IdeaVim extensions from the old VimExtensionFacade API to the new @VimPlugin annotation-based API.
- Platform-specific setup patterns for extensions-api-migration.
- Evidence-backed steps from upstream SKILL.md.
- When-to-use criteria for extensions-api-migration versus alternatives.
Extensions Api Migration by the numbers
- 5 all-time installs (skills.sh)
- Ranked #568 of 782 Skill Development skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
extensions-api-migration capabilities & compatibility
- Capabilities
- extensions api migration quick start · extensions api migration when to use guidance · extensions api migration integration patterns
- Use cases
- documentation
- IDEs
- intellij · jetbrains
What extensions-api-migration says it does
You are an IdeaVim extensions migration specialist. Your job is to help migrate existing IdeaVim extensions from the old API (VimExtensionFacade) to the new API (@VimPlugin annotation).
**New API module**: `api/` folder - contains the new plugin API
npx skills add https://github.com/jetbrains/ideavim --skill extensions-api-migrationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 5 |
|---|---|
| repo stars | ★ 10.2k |
| Last updated | August 4, 2026 |
| Repository | jetbrains/ideavim ↗ |
How do I use extensions-api-migration correctly?
Migrates IdeaVim extensions from the old VimExtensionFacade API to the new @VimPlugin annotation-based API. Use when converting existing extensions to use the new API patterns.
Who is it for?
Teams implementing extensions-api-migration workflows from the catalog.
Skip if: Skip when requirements clearly match a different specialized stack.
When should I use this skill?
User asks about extensions-api-migration, migrates ideavim extensions from the old vimextensionfacade api to the new @vimplugin anno.
What you get
Working extensions-api-migration setup with validated configuration and next steps.
Files
Extensions API Migration
You are an IdeaVim extensions migration specialist. Your job is to help migrate existing IdeaVim extensions from the old API (VimExtensionFacade) to the new API (@VimPlugin annotation).
Key Locations
- New API module:
api/folder - contains the new plugin API - Old API:
VimExtensionFacadein vim-engine - Extensions location:
src/main/java/com/maddyhome/idea/vim/extension/
How to Use the New API
Getting Access to the API
To get access to the new API, call the api() function from com.maddyhome.idea.vim.extension.api:
val api = api()Obtain the API at the start of the init() method - this is the entry point for all further work.
Registering Text Objects
Use api.textObjects { } to register text objects:
// From VimIndentObject.kt
override fun init() {
val api = api()
api.textObjects {
register("ai") { _ -> findIndentRange(includeAbove = true, includeBelow = false) }
register("aI") { _ -> findIndentRange(includeAbove = true, includeBelow = true) }
register("ii") { _ -> findIndentRange(includeAbove = false, includeBelow = false) }
}
}Registering Mappings
Use api.mappings { } to register mappings:
// From ParagraphMotion.kt
override fun init() {
val api = api()
api.mappings {
nmapPluginAction("}", "<Plug>(ParagraphNextMotion)", keepDefaultMapping = true) {
moveParagraph(1)
}
nmapPluginAction("{", "<Plug>(ParagraphPrevMotion)", keepDefaultMapping = true) {
moveParagraph(-1)
}
xmapPluginAction("}", "<Plug>(ParagraphNextMotion)", keepDefaultMapping = true) {
moveParagraph(1)
}
// ... operator-pending mode mappings with omapPluginAction
}
}Defining Helper Functions
The lambdas in text object and mapping registrations typically call helper functions. Define these functions with VimApi as a receiver - this makes the API available inside:
// From VimIndentObject.kt
private fun VimApi.findIndentRange(includeAbove: Boolean, includeBelow: Boolean): TextObjectRange? {
val charSequence = editor { read { text } }
val caretOffset = editor { read { withPrimaryCaret { offset } } }
// ... implementation using API
}
// From ParagraphMotion.kt
internal fun VimApi.moveParagraph(direction: Int) {
val count = getVariable<Int>("v:count1") ?: 1
editor {
change {
forEachCaret {
val newOffset = getNextParagraphBoundOffset(actualCount, includeWhitespaceLines = true)
if (newOffset != null) {
updateCaret(offset = newOffset)
}
}
}
}
}API Features
<!-- Fill in additional API features here -->
How to Migrate Existing Extensions
What Stays the Same
- The extension still inherits VimExtensionFacade - this does not change
- The extension still registers in the XML file - this does not change
Migration Steps
Step 1: Ensure Test Coverage
Before starting migration, make sure tests exist for the extension:
- Tests should work and have good coverage
- If there aren't enough tests, create more tests first
- Verify tests pass on the existing version of the plugin
Step 2: Migrate in Small Steps
- Don't try to handle everything in one run
- Run tests on the plugin (just the single test class to speed up things) after making smaller changes
- This ensures consistency and makes it easier to identify issues
- Do a separate commit for each small sensible change or migration unless explicitly told not to
Step 3: Migrate Handlers One by One
If the extension has multiple handlers, migrate them one at a time rather than all at once.
Step 4: Handler Migration Process
For each handler, follow this approach:
1. Inject the API: Add val api = api() as the first line inside the execute function
2. Extract to extension function: Extract the content of the execute function into a separate function outside the ExtensionHandler class. The new function should:
- Have
VimApias a receiver - Use the api that was obtained before
- Keep the extraction as-is (no changes to logic yet)
3. Verify tests pass: Run tests to ensure the extraction didn't break anything
4. Migrate function content: Now start migrating the content of the extracted function to use the new API
5. Verify tests pass again: Run tests after each significant change
6. Update registration: Finally, change the registration of shortcuts from the existing approach to api.mappings { } where you call the newly created function
Example Migration Flow
// BEFORE: Old style handler
class MyHandler : ExtensionHandler {
override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
// ... implementation
}
}
// STEP 1: Inject API
class MyHandler : ExtensionHandler {
override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
val api = api()
// ... implementation
}
}
// STEP 2: Extract to extension function (as-is)
class MyHandler : ExtensionHandler {
override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
val api = api()
api.doMyAction(/* pass needed params */)
}
}
private fun VimApi.doMyAction(/* params */) {
// ... same implementation, moved here
}
// STEP 3-5: Migrate content to new API inside doMyAction()
// STEP 6: Update registration to use api.mappings { }
override fun init() {
val api = api()
api.mappings {
nmapPluginAction("key", "<Plug>(MyAction)") {
doMyAction()
}
}
}
// Now MyHandler class can be removedHandling Complicated Plugins
For more complicated plugins, additional steps may be required.
For example, there might be a separate large class that performs calculations. However, this class may not be usable as-is because it takes a Document - a class that is no longer directly available through the new API.
In this case, perform a pre-refactoring step: update this class to remove the Document dependency before starting the main migration. For instance, change it to accept CharSequence instead, which is available via the new API.
Final Verification: Check for Old API Usage
After migration, verify that no old API is used by checking imports for com.maddyhome.
Allowed imports (these are still required):
com.maddyhome.idea.vim.extension.VimExtensioncom.maddyhome.idea.vim.extension.api
Any other com.maddyhome imports indicate incomplete migration.
Related skills
FAQ
What does extensions-api-migration do?
extensions-api-migration skill documents Migrates IdeaVim extensions from the old VimExtensionFacade API to the new @VimPlugin annotation-based API.
When should I use extensions-api-migration?
User asks about extensions-api-migration, migrates ideavim extensions from the old vimextensionfacade api to the new @vimplugin anno.
Is this skill safe to install?
Review the Security Audits panel on this page before installing in production.