Complete knowledge base for porting JetBrains or VSCode plugins to Neovim.
📋 EXECUTIVE_SUMMARY.md - Start here! TL;DR and decision rationale
📚 PROJECT_KNOWLEDGE.md - Deep dive: architecture, pain points, APIs
🔄 API_MAPPING.md - VSCode/JetBrains → Neovim API translations
✅ PORTING_CHECKLIST.md - Step-by-step tracking tool
Port from the VSCode extension (TypeScript).
- Cost: ~40-70K tokens
- Difficulty: 1.0x (baseline)
- Why: Better language/API alignment, more LLM training data, less boilerplate
vs.
JetBrains (Kotlin):
- Cost: ~80-120K tokens (2x more expensive!)
- Difficulty: 2.0x (heavy OOP, complex APIs)
Perfect for getting oriented quickly. Answers:
- Which plugin should I port from?
- What's the cost difference?
- What are the main challenges?
- How do I get started?
Read this first if you're new to the project.
The comprehensive knowledge base. Contains:
- Architecture overview and design decisions
- Neovim-specific pain points and gotchas
- Detailed API reference with code examples
- Development guidelines for humans and LLMs
- Resource links and community info
Read this when you're ready to start coding.
Translation guide between platforms. Includes:
- Side-by-side API comparisons
- VSCode → Neovim mappings (commands, config, events, etc.)
- JetBrains → Neovim mappings (actions, PSI, notifications, etc.)
- Common pitfalls (indexing, async patterns, error handling)
- Code examples for every pattern
Keep this open while porting for quick lookups.
Practical tracking tool. Includes:
- Pre-port analysis worksheet
- Feature inventory template
- Phase-by-phase checklist (Foundation → Core → Features → Polish → Release)
- Metrics tracking
- Lessons learned section
Copy this file and fill it out for your specific project.
# 1. Read the executive summary
cat EXECUTIVE_SUMMARY.md
# 2. Analyze your source plugin
# For VSCode:
cat package.json # Commands, config
cat src/extension.ts # Entry point
# 3. Set up your Neovim plugin structure
mkdir -p lua/your-plugin
cd lua/your-plugin
# 4. Create initial files
cat > init.lua << 'EOF'
local M = {}
M.config = {}
function M.setup(opts)
M.config = vim.tbl_deep_extend('force', M.config, opts or {})
end
return M
EOF
# 5. Link to your Neovim config for testing
ln -s $(pwd) ~/.config/nvim/lua/your-plugin
# 6. Test it loads
nvim -c "lua require('your-plugin').setup()"When starting a porting task:
- Read PROJECT_KNOWLEDGE.md first - Get full context
- Check API_MAPPING.md - Find equivalent APIs
- Reference PORTING_CHECKLIST.md - Track progress
- Use targeted edits - Prefer
str_replaceover full file rewrites - Build incrementally - One command at a time, test frequently
Remember:
- Lua is 1-indexed for tables (but 0-indexed for buffers/lines!)
- No async/await (use callbacks or plenary.async)
- All requires are cached (clear package.loaded for hot reload)
- Use
vim.schedule()for deferred execution
your-neovim-plugin/
├── lua/
│ └── your-plugin/
│ ├── init.lua # Entry point, setup()
│ ├── config.lua # Configuration defaults
│ ├── commands.lua # User command definitions
│ ├── autocmds.lua # Autocommand setup
│ ├── mappings.lua # Keybinding definitions
│ └── utils.lua # Helper functions
├── plugin/
│ └── your-plugin.vim # Legacy Vimscript shim (optional)
├── doc/
│ └── your-plugin.txt # Vim help documentation
├── tests/
│ └── your-plugin_spec.lua # Plenary tests
├── README.md # User-facing documentation
├── CHANGELOG.md # Version history
└── LICENSE # License file
" In Neovim, while developing:
:lua package.loaded['your-plugin'] = nil
:lua require('your-plugin').setup()
" Or create a command:
:command! Reload lua package.loaded['your-plugin'] = nil; require('your-plugin').setup()-- Print debugging
print(vim.inspect(some_table))
-- Visual notification
vim.notify('Debug: ' .. tostring(value), vim.log.levels.DEBUG)
-- Log to file
local log = io.open('/tmp/plugin.log', 'a')
log:write(vim.inspect(data) .. '\n')
log:close()# Using plenary.nvim
nvim --headless -c "PlenaryBustedDirectory tests/ {minimal_init = 'tests/minimal_init.lua'}"local M = {}
-- Private state
local internal = {}
-- Public API
function M.setup(opts)
-- configuration
end
function M.public_function()
-- implementation
end
return Mvim.api.nvim_create_user_command('CommandName', function(opts)
-- Implementation
end, {
desc = 'Description for :Telescope commands',
nargs = '*',
bang = true,
})local augroup = vim.api.nvim_create_augroup('PluginName', { clear = true })
vim.api.nvim_create_autocmd('BufEnter', {
group = augroup,
pattern = '*.lua',
callback = function(args)
-- Implementation
end,
})- Comment.nvim - Simple, clean structure
- gitsigns.nvim - Advanced async patterns
- telescope.nvim - Complex UI
- plenary.nvim - Lua utilities, async lib
- nui.nvim - UI components
Found something missing or incorrect? This documentation should evolve as you learn:
- Update the relevant .md file
- Document new patterns in API_MAPPING.md
- Add pain points to PROJECT_KNOWLEDGE.md
- Share lessons learned in PORTING_CHECKLIST.md
This documentation is provided as-is for your porting project. Use, modify, and share freely.
Ready to start? → Read the Executive Summary
Need API translations? → Check the API Mapping
Ready to code? → Dive into Project Knowledge
Want to track progress? → Use the Checklist