Pyrola.nvim
Nvim Read–Eval–Print Loop (REPL) plugin for data science workflow
Install / Use
/learn @matarina/Pyrola.nvimREADME
Pyrola
If you are seeking an alternative to Jupyter, Spyder, or RStudio in Neovim, Pyrola is the solution.
Pyrola delivers a multi-language REPL (Read-Eval-Print Loop) experience inside Neovim. It is designed for interactive programming, especially for data scientists, and supports:
- Real-time code execution
- Variable inspection
- Image visualization
Since Pyrola is built on Jupyter kernels, any language with a Jupyter kernel can be integrated.
Demo
<div align="center"> <a href="https://www.youtube.com/watch?v=S3arFOPnD40"> <img src="https://img.youtube.com/vi/S3arFOPnD40/0.jpg" alt="Watch the video" style="width:100%;"> </a> </div>Features
-
Multi-language support: Any language with a Jupyter kernel works in Pyrola (Python, R, C++, Julia, etc.).
-
Real-time REPL: Execute code dynamically within Neovim with immediate feedback.
-
Multiple code-sending methods: Send code via Tree-sitter semantic blocks, visual selection, or entire buffer.
-
Variable inspector: Inspect variables (class, type, shape, content) directly from the REPL (Python and R).
-
Global variable browser: View all user globals in a floating window. Press
<CR>on any variable to inspect it. -
Image viewer: Preview image outputs in a floating window via Kitty or iTerm2 terminal protocols.
-
Image history: Browse previously plotted images in a floating window.
-
Reliable interrupts: Interrupt long-running cells and recover cleanly.
-
One-command setup:
:Pyrola setupinstalls dependencies and prepares a managedpyrola_<language>kernel automatically. -
Auto kernel registration: Pyrola auto-manages
pyrola_python,pyrola_r,pyrola_cpp, andpyrola_juliaunless you explicitly override the kernel name.
Installation
1. Plugin setup
Add Pyrola to your plugin manager. Example using lazy.nvim:
{
"matarina/pyrola.nvim",
dependencies = { "nvim-treesitter/nvim-treesitter" },
config = function()
local pyrola = require("pyrola")
pyrola.setup({
-- Optional: point to a specific Python (conda/venv).
-- If omitted, Pyrola uses the active python3 from PATH.
-- python_path = "~/miniconda3/envs/ds/bin/python",
-- Optional overrides. When omitted, Pyrola auto-creates and uses
-- managed kernels named pyrola_<language>.
kernel_map = {
-- python = "custom-python-kernel",
-- r = "custom-r-kernel",
},
split_horizontal = false,
split_ratio = 0.65,
image = {
cell_width = 10,
cell_height = 20,
max_width_ratio = 0.5,
max_height_ratio = 0.5,
offset_row = 0,
offset_col = 0,
protocol = "auto", -- auto | kitty | iterm2 | none
},
})
-- Keybindings
vim.keymap.set("n", "<CR>", pyrola.send_statement_definition, { noremap = true })
vim.keymap.set("v", "<leader>vs", pyrola.send_visual_to_repl, { noremap = true })
vim.keymap.set("n", "<leader>vb", pyrola.send_buffer_to_repl, { noremap = true })
vim.keymap.set("n", "<leader>is", pyrola.inspect, { noremap = true })
vim.keymap.set("n", "<leader>ig", pyrola.show_globals, { noremap = true })
vim.keymap.set("n", "<leader>ik", pyrola.interrupt_kernel, { noremap = true })
vim.keymap.set("n", "<leader>im", pyrola.open_history_manager, { noremap = true })
end,
},
-- Tree-sitter is required. Install parsers for languages in kernel_map.
{
"nvim-treesitter/nvim-treesitter",
build = ":TSUpdate",
config = function()
local ts = require("nvim-treesitter")
ts.setup({ install_dir = vim.fn.stdpath("data") .. "/site" })
ts.install({ "python", "r", "lua" })
end,
}
2. Python environment setup
Pyrola needs a few Python packages. There are three ways to set them up:
Option A: One-command setup (recommended)
Open a file and run:
:Pyrola setup
This installs all dependencies via pip and prepares the managed kernel for the current filetype. By default the managed name is pyrola_<language>. When finished, run :Pyrola init to start.
Option B: Manual install
pip install -r /path/to/pyrola.nvim/rplugin/python3/requirements.txt
pip install ipykernel
python3 -m ipykernel install --user --name py3
If you manually set kernel_map.python = "py3", the kernel name must match that explicit config.
Option C: Auto-prompted install
When you run :Pyrola init with missing packages, Pyrola prompts you to install them. If the kernel is missing for a Python file, it offers to install and register it.
3. Conda / venv users
Usually you do not need extra config. Pyrola follows the active environment that launched Neovim and creates managed kernels named pyrola_<language>.
Set python_path only if you want to override the active Python interpreter:
pyrola.setup({
python_path = "~/miniconda3/envs/ds/bin/python",
})
This takes precedence over the active python3 on PATH.
4. Non-Python kernels
Pyrola auto-creates pyrola_r, pyrola_cpp, and pyrola_julia by reusing the language kernel available in the current environment. If the underlying language kernel is missing, install it first:
| Language | Underlying kernel requirement | Managed name |
|----------|------------------------------|--------------|
| R | IRkernel installed in the active R environment | pyrola_r |
| C++ | xeus-cling installed | pyrola_cpp |
| Julia | IJulia installed | pyrola_julia |
5. Image preview (optional)
Pyrola renders images in floating windows via Kitty or iTerm2 terminal protocols (image.protocol = "auto" detects automatically).
For embedded pixel images in the REPL console output, install timg:
# Debian/Ubuntu
apt install timg
# macOS
brew install timg
tmux users: Add to ~/.tmux.conf:
set -g focus-events on
set -g allow-passthrough all
Usage
Commands
| Command | Description |
|---------|-------------|
| :Pyrola setup | Install dependencies + prepare the managed kernel for the current filetype |
| :Pyrola init | Start kernel and open REPL terminal |
Both commands support tab completion.
Sending code
| Function | Description |
|----------|-------------|
| pyrola.send_statement_definition() | Send the Tree-sitter semantic block under cursor. When REPL is not running, falls back to normal <CR>. |
| pyrola.send_visual_to_repl() | Send visual selection to REPL. Exits visual mode and moves cursor to next code line. |
| pyrola.send_buffer_to_repl() | Send the entire buffer to REPL. |
Inspecting variables
| Function | Description |
|----------|-------------|
| pyrola.inspect() | Inspect the symbol under cursor in a floating window. Uses Tree-sitter to identify the symbol, falls back to <cword>. Shows type, shape, content, methods, etc. Supports Python and R. |
| pyrola.show_globals() | Show all user variables in a floating window. Press <CR> on any entry to inspect it. Press q or <Esc> to close. |
Kernel control
| Function | Description |
|----------|-------------|
| pyrola.interrupt_kernel() | Send SIGINT to interrupt the running kernel execution. |
Image history
| Function | Description |
|----------|-------------|
| pyrola.open_history_manager() | Open image history browser. Use h/l to navigate, q to close. |
| pyrola.show_last_image() | Show the most recent image in a floating window. |
| pyrola.show_previous_image() | Navigate to the previous image in history. |
| pyrola.show_next_image() | Navigate to the next image in history. |
Configuration reference
pyrola.setup({
-- Python interpreter path. Supports ~ expansion.
-- Priority: python_path > exepath("python3") > g:python3_host_prog > "python3"
python_path = nil,
-- Optional explicit overrides. If a filetype is omitted, Pyrola uses
-- its managed kernel name: pyrola_<language>.
kernel_map = {
-- python = "python3",
-- r = "ir",
-- cpp = "xcpp17",
},
-- REPL terminal split direction and size.
split_horizontal = false, -- false = vertical split (right), true = horizontal (bottom)
split_ratio = 0.65, -- fraction of editor width/height for the split
-- Image display settings.
image = {
cell_width = 10, -- terminal cell width in pixels (for size calculations)
cell_height = 20, -- terminal cell height in pixels
max_width_ratio = 0.5, -- max image width as fraction of editor columns
max_height_ratio = 0.5, -- max image height as fraction of editor lines
offset_row = 0, -- adjust image row position (cells)
offset_col = 0, -- adjust image col position (cells)
protocol = "auto", -- "auto" | "kitty" | "iterm2" | "none"
},
})
Highlight groups
Floating windows use theme-aware defaults (linked to FloatBorder, FloatTitle, NormalFloat). Highlight groups are automatically refreshed when you change colorscheme. Override them for custom colors:
-- Inspector window
vim.api.nvim_set_hl(0, "PyrolaInspectorBorder", { link = "FloatBorder" })
vim.api.nvim_set_hl(0, "PyrolaInspectorTitle", { link = "FloatTitle" })
vim.api.nvim_set_hl(0, "PyrolaInspectorNormal", { link =
