Ghidra development plugin for Neovim. The GhidraDev experience, but for Neovim -- with real LSP.
Write Ghidra scripts in Java and Python with full autocomplete, go-to-definition, hover docs, and diagnostics -- powered by JDTLS and Pyright, automatically configured with Ghidra's API.
ghidra.nvim does what Eclipse's GhidraDev plugin does under the hood: it points your existing language servers at Ghidra's JARs and Python libraries. No custom LSP server required.
┌──────────────┐
Neovim │ JDTLS │──── Ghidra/Framework/*/lib/*.jar
├─ ghidra.nvim ────►│ (Java LSP) │──── Ghidra/Features/*/lib/*.jar
│ configures └──────────────┘
│ classpath
│ ┌──────────────┐
└─ ghidra.nvim ────►│ Pyright │──── Ghidra/Features/Python/
configures │ (Python LSP) │──── ~/ghidra_scripts/
extraPaths └──────────────┘
Java scripts get full GhidraScript, FlatProgramAPI, Program, Listing, Function, etc. completion via JDTLS reading the generated .classpath.
Python scripts get Ghidra's Jython/PyGhidra API completion via Pyright's extraPaths and a generated pyrightconfig.json.
- Neovim >= 0.10
- A Ghidra installation
- For Java scripts: JDTLS (via nvim-jdtls or nvim-lspconfig)
- For Python scripts: pyright, basedpyright, or pylsp
{
"jdearmas/ghidra.nvim",
config = function()
require("ghidra").setup({
-- Path to your Ghidra installation (or set $GHIDRA_INSTALL_DIR)
ghidra_install = "/opt/ghidra_11.2",
})
end,
}use {
"jdearmas/ghidra.nvim",
config = function()
require("ghidra").setup({
ghidra_install = "/opt/ghidra_11.2",
})
end,
}Clone into your Neovim packages directory:
git clone https://github.com/jdearmas/ghidra.nvim \
~/.local/share/nvim/site/pack/plugins/start/ghidra.nvimIf you already have the repo cloned somewhere (e.g. you're hacking on the plugin itself), pick one of these:
-- In your lazy.nvim plugin spec:
{
dir = "/absolute/path/to/ghidra.nvim",
config = function()
require("ghidra").setup({
ghidra_install = "/opt/ghidra_11.2",
})
end,
}# One command — done. Neovim picks it up on next launch.
ln -s /absolute/path/to/ghidra.nvim \
~/.local/share/nvim/site/pack/plugins/start/ghidra.nvimThen add to your Neovim config (init.lua):
require("ghidra").setup({
ghidra_install = "/opt/ghidra_11.2",
})-- Add to the very top of your init.lua:
vim.opt.rtp:prepend("/absolute/path/to/ghidra.nvim")
require("ghidra").setup({
ghidra_install = "/opt/ghidra_11.2",
})Tip: After any of these, run
:checkhealth ghidrato verify everything is wired up.
All options with their defaults:
require("ghidra").setup({
-- Path to Ghidra installation. If nil, auto-detects from
-- $GHIDRA_INSTALL_DIR or common locations (/opt/ghidra*, ~/ghidra*, etc.)
ghidra_install = nil,
java = {
enabled = true,
-- Auto-generate .classpath and .project files for JDTLS
generate_classpath = true,
},
python = {
enabled = true,
-- "jython" (Ghidra's bundled Jython) or "pyghidra" (Python 3 via PyGhidra)
interpreter = "jython",
},
-- Default directory for new scripts (Ghidra auto-discovers ~/ghidra_scripts)
scripts_dir = "~/ghidra_scripts",
})| Command | Description |
|---|---|
:GhidraSetup [path] |
Link a Ghidra installation. Auto-detects if no path given. |
:GhidraNewScript java|python <name> |
Create a new script from template with Ghidra boilerplate. |
:GhidraRunScript [file] [flags] |
Run a script headlessly via analyzeHeadless. Defaults to current buffer. --all runs every script in dir. |
:GhidraInfo |
Show linked installation, JAR count, paths, and config in a floating window. |
:GhidraRefresh |
Re-scan Ghidra JARs and push updated settings to running LSP servers. |
" Run the current buffer headlessly
:GhidraRunScript
" Run a specific script against a binary
:GhidraRunScript ~/ghidra_scripts/MyScript.java --import /path/to/binary.exe
" Skip auto-analysis for faster execution
:GhidraRunScript --noanalysis
" Run as a pre-analysis script instead of post-analysis
:GhidraRunScript --pre
" Open output in a vertical split or new tab
:GhidraRunScript --vertical
:GhidraRunScript --tab
" Run ALL scripts in the current script's directory
:GhidraRunScript --all
:GhidraMake --all:checkhealth ghidraReports:
- Ghidra installation validity and version
- Number of discovered API JARs
analyzeHeadlessavailability- Python library paths
- JDTLS / Pyright availability
- Scripts directory status
When you open a .java file inside a Ghidra project directory (detected by .ghidra_project marker, Module.manifest, ghidra_scripts/ directory name, or your configured scripts_dir), the plugin:
- Discovers all
.jarfiles underGhidra/Framework/*/lib/,Ghidra/Features/*/lib/,Ghidra/Processors/*/lib/, andGhidra/Extensions/*/lib/ - Generates a
.classpathfile (Eclipse format) that JDTLS reads natively - Generates a
.projectfile so JDTLS treats the directory as a Java project - Pushes
referencedLibrariesto any running JDTLS client
This gives you autocomplete, go-to-definition, hover, and diagnostics for the entire Ghidra API -- GhidraScript, FlatProgramAPI, Program, Listing, Function, Address, DataType, and everything else.
When you open a .py file in a Ghidra project context, the plugin:
- Discovers Jython/PyGhidra library paths from the Ghidra installation
- Generates a
pyrightconfig.jsonwith those paths inextraPaths - Pushes
python.analysis.extraPathsto any running Pyright/basedpyright/pylsp client
:GhidraRunScript invokes Ghidra's analyzeHeadless (found at <GhidraInstall>/support/analyzeHeadless) in a Neovim terminal split. It automatically:
- Uses a temporary project in
~/.cache/nvim/ghidra_projects/ - Sets
-scriptPathto include your script's directory and configuredscripts_dir - Supports importing binaries for analysis with
--import
The plugin identifies Ghidra project roots by looking for any of:
.ghidra_projectmarker file (create this in your project root)Module.manifest(Ghidra extension module marker).classpathfile containing "ghidra" or "Ghidra"- Directory named
ghidra_scripts - Files inside your configured
scripts_dir
# 1. Set up your scripts directory
mkdir -p ~/ghidra_scripts-- 2. In your Neovim config
require("ghidra").setup({
ghidra_install = "/opt/ghidra_11.2",
})" 3. Create a new script
:GhidraNewScript java MyAnalyzer
" 4. Write your script with full autocomplete (JDTLS kicks in automatically)
" - Type 'currentProgram.' and get completions
" - Hover over GhidraScript methods for docs
" - Go-to-definition on any Ghidra API class
" 5. Run it headlessly against a binary
:GhidraRunScript --import /path/to/firmware.binMIT