{"id":47865297,"url":"https://github.com/ansh-info/ipynb.nvim","last_synced_at":"2026-05-01T19:00:57.679Z","repository":{"id":347988506,"uuid":"1194625133","full_name":"ansh-info/ipynb.nvim","owner":"ansh-info","description":"Neovim plugin for editing Jupyter notebooks (.ipynb) natively - Colab style cell rendering, kernel execution, inline output, and image rendering","archived":false,"fork":false,"pushed_at":"2026-04-25T15:27:50.000Z","size":528,"stargazers_count":3,"open_issues_count":55,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-25T17:35:44.448Z","etag":null,"topics":["ipynb","jupyter","jupyter-notebook","lua","neovim","neovim-plugin","nvim","python"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ansh-info.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-28T15:55:55.000Z","updated_at":"2026-04-25T15:27:54.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ansh-info/ipynb.nvim","commit_stats":null,"previous_names":["ansh-info/ipynb.nvim"],"tags_count":76,"template":false,"template_full_name":null,"purl":"pkg:github/ansh-info/ipynb.nvim","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ansh-info%2Fipynb.nvim","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ansh-info%2Fipynb.nvim/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ansh-info%2Fipynb.nvim/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ansh-info%2Fipynb.nvim/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ansh-info","download_url":"https://codeload.github.com/ansh-info/ipynb.nvim/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ansh-info%2Fipynb.nvim/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32508912,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"online","status_checked_at":"2026-05-01T02:00:05.856Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ipynb","jupyter","jupyter-notebook","lua","neovim","neovim-plugin","nvim","python"],"created_at":"2026-04-04T00:08:32.303Z","updated_at":"2026-05-01T19:00:57.626Z","avatar_url":"https://github.com/ansh-info.png","language":"Lua","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ipynb\n\n[![CI](https://github.com/ansh-info/ipynb.nvim/actions/workflows/ci.yml/badge.svg)](https://github.com/ansh-info/ipynb.nvim/actions/workflows/ci.yml)\n\nNeovim plugin for editing Jupyter notebooks (`.ipynb`) natively - Colab-style cell\nrendering, full Vim modal editing, live kernel execution, and inline output.\n\n```\n╭── [ python · [3] ────────────────────────────────────────╮\n  import numpy as np\n  x = np.linspace(0, 10, 100)\n  print(x.mean())\n╰── ✓ 0.12s ───────────────────────────────────────────────╯\n  5.0\n```\n\n## Table of Contents\n\n- [Requirements](#requirements)\n- [Installation](#installation)\n- [Setup](#setup)\n- [Usage](#usage)\n  - [Using packages from a project venv](#using-packages-from-a-project-venv-numpy-matplotlib-etc)\n- [Keymaps](#keymaps)\n- [Commands](#commands)\n- [Configuration](#configuration)\n- [Statusline](#statusline)\n- [Contributing](#contributing)\n\n## Requirements\n\n- Neovim \u003e= 0.9\n- Python \u003e= 3.12\n- [uv](https://github.com/astral-sh/uv) (recommended) or python3 (built-in venv fallback)\n\n**Required for image rendering** (matplotlib plots, inline PNG/JPEG/SVG)\n\n- [folke/snacks.nvim](https://github.com/folke/snacks.nvim) with `image` module enabled\n- A terminal with Kitty graphics protocol **unicode placeholder** support:\n\n| Terminal | Supported |\n|---|---|\n| [kitty](https://sw.kovidgoyal.net/kitty/) \u003e= 0.28 | yes |\n| [Ghostty](https://ghostty.org/) | yes |\n| [WezTerm](https://wezfurlong.org/wezterm/) | yes |\n| tmux (wrapping any of the above) | yes - see note below |\n| alacritty, iTerm2, others | no |\n\n- **tmux users:** add to `~/.tmux.conf` and restart tmux:\n  ```\n  set -gq allow-passthrough on\n  set -g visual-activity off\n  set-option -g focus-events on\n  ```\n\n**Optional - completion**\n\n- [nvim-cmp](https://github.com/hrsh7th/nvim-cmp)\n\n**Optional - language icons in cell borders**\n\n- [nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons)\n\n## Installation\n\n### lazy.nvim\n\n```lua\nreturn {\n  {\n    \"ansh-info/ipynb.nvim\",\n    lazy = false,\n    build = \"uv sync --project python/ || (python3 -m venv python/.venv \u0026\u0026 python/.venv/bin/pip install ./python/)\",\n    opts = {},\n  },\n}\n```\n\n\u003e `lazy = false` is required - the plugin must load before any buffer is opened\n\u003e so it can intercept `.ipynb` files via `BufReadCmd`.\n\n\u003e The `build` hook installs the Python kernel bridge dependencies\n\u003e (`jupyter_client`, `ipykernel`, `nbformat`) into an isolated venv at\n\u003e `python/.venv/`. It tries `uv` first; if `uv` is not installed it falls back\n\u003e to the standard `python3 -m venv`. Run `:Lazy build ipynb` to re-run it\n\u003e manually after updates.\n\n**With optional dependencies:**\n\n```lua\nreturn {\n  {\n    \"ansh-info/ipynb.nvim\",\n    lazy = false,\n    build = \"uv sync --project python/ || (python3 -m venv python/.venv \u0026\u0026 python/.venv/bin/pip install ./python/)\",\n    dependencies = {\n      {\n        \"folke/snacks.nvim\",\n        opts = {\n          image = { enabled = true },\n        },\n      },\n      { \"hrsh7th/nvim-cmp\" },\n      { \"nvim-tree/nvim-web-devicons\" },\n    },\n    opts = {},\n  },\n}\n```\n\n### packer.nvim\n\n```lua\nuse({\n  \"ansh-info/ipynb.nvim\",\n  run = \"uv sync --project python/ || (python3 -m venv python/.venv \u0026\u0026 python/.venv/bin/pip install ./python/)\",\n  config = function()\n    require(\"ipynb\").setup({})\n  end,\n})\n```\n\n## Setup\n\nSetup is called automatically when you pass `opts = {}` to lazy.nvim. If you\nmanage setup yourself:\n\n```lua\nrequire(\"ipynb\").setup({})\n```\n\n## Usage\n\nOpen any `.ipynb` file - the plugin renders it automatically:\n\n```\nnvim my_notebook.ipynb\n```\n\nThe kernel starts automatically when you run your first cell. No manual\n`:IpynbKernelStart` needed unless `auto_start` is disabled.\n\n```\n\u003cleader\u003err     run the cell under the cursor\n]c / [c        jump to next / previous cell\n\u003cleader\u003eji     open variable inspector\n```\n\n### Using packages from a project venv (numpy, matplotlib, etc.)\n\nBy default the kernel runs on the plugin's own Python, which only has the\nbridge dependencies (`jupyter_client`, `ipykernel`, `nbformat`). To use\nyour own packages, activate your project venv **before** launching Neovim:\n\n```bash\n# One-time setup per venv - ipykernel is required for the kernel to launch\nuv pip install ipykernel numpy matplotlib   # or: pip install ...\n\n# Then just activate and open Neovim as normal\nsource .venv/bin/activate\nnvim my_notebook.ipynb\n```\n\nThe plugin auto-detects `$VIRTUAL_ENV` (uv/venv) and `$CONDA_PREFIX`\n(conda) and uses that Python as the kernel. No config change needed.\n\n\u003e **Why ipykernel?** The kernel is a separate process launched as\n\u003e `python -m ipykernel_launcher`. That process must be able to import\n\u003e `ipykernel`, so it needs to be installed in your venv alongside your\n\u003e packages. If it is missing you will see an error in `:messages` with\n\u003e install instructions.\n\n## Keymaps\n\nAll keymaps are buffer-local and only active inside `.ipynb` buffers.\nPress `\u003cleader\u003ejh` to show the help overlay at any time.\n\n| Key | Action |\n|---|---|\n| `\u003cleader\u003err` | Run current cell |\n| `\u003cleader\u003ern` | Run cell and advance to next (Shift+Enter) |\n| `\u003cleader\u003era` | Run all cells above cursor |\n| `\u003cleader\u003erb` | Run all cells from cursor downwards |\n| `\u003cleader\u003eri` | Interrupt kernel |\n| `]c` | Next cell |\n| `[c` | Previous cell |\n| `\u003cleader\u003eco` | Add code cell below |\n| `\u003cleader\u003ecO` | Add code cell above |\n| `\u003cleader\u003emo` | Add markdown cell below |\n| `\u003cleader\u003emO` | Add markdown cell above |\n| `\u003cleader\u003ecd` | Delete current cell |\n| `\u003cleader\u003eck` | Move current cell up |\n| `\u003cleader\u003ecj` | Move current cell down |\n| `\u003cleader\u003ecc` | Duplicate current cell |\n| `\u003cleader\u003ecy` | Yank cell into cell register |\n| `\u003cleader\u003ecv` | Paste yanked cell below |\n| `\u003cleader\u003ect` | Toggle cell type (code/markdown) |\n| `\u003cleader\u003ecs` | Split cell at cursor line |\n| `\u003cleader\u003ecm` | Merge cell with the cell below |\n| `\u003cleader\u003ecx` | Clear current cell output |\n| `\u003cleader\u003ecX` | Clear all cell outputs |\n| `u` | Smart undo (text edits or structural cell ops) |\n| `\u003cC-r\u003e` | Smart redo (text edits or structural cell ops) |\n| `\u003cleader\u003ew` | Save notebook |\n| `\u003cleader\u003eji` | Variable inspector |\n| `\u003cleader\u003ejh` | Keymap help overlay |\n| `\u003cC-x\u003e\u003cC-o\u003e` | Kernel completions (insert mode) |\n\n## Commands\n\n| Command | Description |\n|---|---|\n| `:IpynbOpen [path]` | Open a notebook |\n| `:IpynbSave` | Save the current notebook |\n| `:IpynbKernelStart [name]` | Start a kernel (`python3` default) |\n| `:IpynbKernelStop` | Stop the kernel |\n| `:IpynbKernelRestart` | Restart kernel and clear all output |\n| `:IpynbKernelInterrupt` | Send interrupt (Ctrl-C) |\n| `:IpynbKernelInfo` | Show kernel status window |\n| `:IpynbKernelAttach [file]` | Attach to an existing kernel via connection file |\n| `:IpynbRun` | Run current cell |\n| `:IpynbRunAdvance` | Run cell and advance to next |\n| `:IpynbRunAll` | Run all cells |\n| `:IpynbRunAbove` | Run all cells above cursor |\n| `:IpynbRunBelow` | Run all cells from cursor downwards |\n| `:IpynbCellAdd` | Add code cell below |\n| `:IpynbCellDelete` | Delete current cell |\n| `:IpynbCellAddMarkdown` | Add markdown cell below |\n| `:IpynbCellAddMarkdownAbove` | Add markdown cell above |\n| `:IpynbCellMoveUp` | Move current cell up |\n| `:IpynbCellMoveDown` | Move current cell down |\n| `:IpynbCellDuplicate` | Duplicate current cell below |\n| `:IpynbCellYank` | Yank cell into cell register |\n| `:IpynbCellPaste` | Paste yanked cell below |\n| `:IpynbCellToggleType` | Toggle cell type (code/markdown) |\n| `:IpynbCellSplit` | Split cell at cursor line |\n| `:IpynbCellMerge` | Merge cell with the cell below |\n| `:IpynbClearOutput` | Clear output for cell under cursor |\n| `:IpynbClearAllOutput` | Clear output for every cell |\n| `:IpynbInspect` | Open variable inspector |\n| `:IpynbHelp` | Show keymap reference |\n\n## Configuration\n\nThe following is the default configuration. Pass any subset of these to `opts`\nor `setup()` to override.\n\n```lua\nrequire(\"ipynb\").setup({\n  kernel = {\n    default_kernel   = \"python3\",\n    auto_start       = true,       -- start kernel automatically on first run\n    python_path      = \"python3\",  -- fallback if uv venv is not found\n    restart_on_crash = false,      -- auto-restart kernel after unexpected crash\n  },\n  ui = {\n    show_execution_count = true,\n    show_elapsed_time    = true,\n    output_max_lines     = 50,   -- max output lines per cell; 0 = unlimited\n  },\n  image = {\n    enabled    = true,           -- requires snacks.nvim + unicode placeholder terminal\n    max_width  = 80,\n    max_height = 20,\n  },\n  keymaps = {\n    enabled          = true,\n    run_cell              = \"\u003cleader\u003err\",\n    run_cell_and_advance  = \"\u003cleader\u003ern\",\n    run_all_above         = \"\u003cleader\u003era\",\n    run_all_below    = \"\u003cleader\u003erb\",\n    next_cell        = \"]c\",\n    prev_cell        = \"[c\",\n    add_cell_below   = \"\u003cleader\u003eco\",\n    add_cell_above   = \"\u003cleader\u003ecO\",\n    delete_cell      = \"\u003cleader\u003ecd\",\n    interrupt_kernel = \"\u003cleader\u003eri\",\n    clear_output        = \"\u003cleader\u003ecx\",\n    clear_all_output    = \"\u003cleader\u003ecX\",\n    add_markdown_below  = \"\u003cleader\u003emo\",\n    add_markdown_above  = \"\u003cleader\u003emO\",\n    move_cell_up        = \"\u003cleader\u003eck\",\n    move_cell_down      = \"\u003cleader\u003ecj\",\n    duplicate_cell      = \"\u003cleader\u003ecc\",\n    yank_cell           = \"\u003cleader\u003ecy\",\n    paste_cell          = \"\u003cleader\u003ecv\",\n    toggle_cell_type    = \"\u003cleader\u003ect\",\n    split_cell          = \"\u003cleader\u003ecs\",\n    merge_cell          = \"\u003cleader\u003ecm\",\n  },\n  notebook = {\n    auto_save = false,\n  },\n})\n```\n\n## Statusline\n\n`require(\"ipynb\").statusline()` returns a formatted string showing the kernel\nname and status for the current buffer. Returns an empty string for non-notebook\nbuffers so the component disappears outside `.ipynb` files.\n\n```\n⬤ python3 [idle]       -- kernel ready\n⬤ python3 [busy]       -- cell executing\n⬤ python3 [starting]   -- kernel booting\n⬤ python3 [stopped]    -- kernel dead or not started\n```\n\n`require(\"ipynb\").statusline_hl()` returns a highlight group name matching the\nstatus (`DiagnosticOk`, `DiagnosticWarn`, `DiagnosticInfo`, `DiagnosticError`).\n\n### lualine\n\n```lua\nrequire(\"lualine\").setup({\n  sections = {\n    lualine_x = {\n      {\n        function() return require(\"ipynb\").statusline() end,\n        cond = function() return require(\"ipynb\").statusline() ~= \"\" end,\n        color = function()\n          return { fg = vim.fn.synIDattr(vim.fn.hlID(require(\"ipynb\").statusline_hl()), \"fg#\") }\n        end,\n      },\n    },\n  },\n})\n```\n\n### heirline\n\n```lua\nlocal IpynbStatus = {\n  condition = function() return require(\"ipynb\").statusline() ~= \"\" end,\n  provider = function() return \" \" .. require(\"ipynb\").statusline() .. \" \" end,\n  hl = function() return require(\"ipynb\").statusline_hl() end,\n}\n```\n\n## Contributing\n\nIssues and pull requests are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for\ndevelopment setup, test instructions, and the contribution workflow.\n\n## License\n\nMIT - see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fansh-info%2Fipynb.nvim","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fansh-info%2Fipynb.nvim","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fansh-info%2Fipynb.nvim/lists"}