Skip to content

Releases

jupynvim v0.5.0-beta.1

Pre-release

Choose a tag to compare

@github-actions github-actions released this 03 Nov 19:49

jupynvim v0.5.0-beta.1

This is a pre-release, the first beta of v0.5.0. It brings the first 10 of the 45 pieces v0.5.0 is made of, the five contributor pull requests among them. Please try it and tell me what breaks. More betas follow as the rest lands.

About v0.5.0

v0.5.0 is the biggest jupynvim release yet. The heavy work moves into a Rust library that runs inside Neovim on its own threads, so Lua only paints, and the rendering is rebuilt on top of it.

Markdown renders the way GitHub shows a .md file and the way VS Code shows a notebook's markdown cells, with math that gets the dollar signs right, \newcommand and numbered equations. DataFrames and other rich outputs are drawn the way VS Code draws them, in one table style, and you can scroll a table, yank from it and page through a whole frame. ipywidgets work: every control of @jupyter-widgets/controls drawn natively and usable from the keyboard, and third-party widgets such as ipympl and plotly in an offscreen web engine.

Everything takes its colors from your colorscheme. Cell boxes never break and get room to breathe. A notebook is on screen at once with its kernel ready in about half a second, images go through a pipeline in Rust, and SSH, tmux and mosh all work, with a text mode where the terminal has no graphics.

A backend that dies no longer strands the notebook (#43), and outputs keep their terminal colors (#42). Releases are signed, kernel connection files stay in a private directory, and CI runs the whole test suite. Cell mode becomes optional and its Esc remappable (#27, #28), scripts get a kernel API and a documented backend protocol (#40), language servers see a notebook's cells in order, Julia and R included, any output opens in the browser (#23), kernels can keep running after you quit (#10), markdown images can be hidden (#13), and WezTerm gets images once it supports Kitty placeholders (#22).

In this beta

This is the first beta, so everything below is new since v0.4.6.

Images no longer garble the screen

On Neovim 0.12, inline images no longer garble the screen, print a stray 66:97m or break cell borders. Every graphics write goes through nvim_ui_send, in order with the screen.

A GIF out of view sends nothing, also while its cell's last line is still on the window's last rows and none of the GIF shows, and picks up where its clock is when it comes back. GIFs keep their own speed: each frame shows for its own delay, so a late frame never slows an animation down. Frames wait for a slow terminal instead of piling up, several GIFs in view share it fairly, and typing next to a plot writes no graphics. Nothing is written while Neovim is suspended or detached, and quitting, suspending or detaching with a GIF playing leaves no terminal answers in your shell.

On Neovim 0.11 far fewer image bytes are written, but a write can still cut the screen (see Known issues). Image data in a notebook that is not valid base64 is no longer passed to the terminal. Images wider or taller than 116 cells draw every row and column in place. New commands: :JupynvimPauseAnimations and :JupynvimRenderStats.

Every notebook talks to its own backend

A local notebook always runs, saves and completes on the local backend, also while a remote session is active, and a remote notebook on its remote. Before, opening a remote notebook pointed everything at the remote, so a local notebook opened after it came up empty and its saves, runs and restarts went to the remote.

:JupynvimUseLocal points the explorer, terminal and picker keys back at this machine without stopping any backend. A remote file is one buffer whichever name you open it by: ~/work/train.ipynb, a relative name and the absolute path the explorer shows are the same notebook. :JupynvimOpenRemote resolves ~ on the remote, :e! and :JupynvimReset reopen a remote notebook from its remote, and a request the backend refuses, such as an interrupt, now says so.

Jupyter widgets talk to the kernel

Widgets from ipywidgets 8 now run against the kernel. tqdm.notebook and tqdm.auto progress bars update live until they reach 100%. An Output widget captures the prints and displays made inside it, plots included. The widget state is saved in the notebook, so a saved notebook shows its widgets without a kernel. Widgets draw as text in this beta; the real controls come in a later one (#3). Widgets need pip install "ipywidgets>=8,<9" in the kernel's environment.

Colors from your colorscheme

jupynvim derives 35 color tokens from whatever colorscheme you use: its highlight groups, the colors of its VS Code port when it is a known one, then VS Code's own defaults. It keeps them readable on the real background, the terminal's own with a transparent colorscheme. Set any of them with palette = { ... }, and :JupynvimPalette lists them and where each came from. Widget progress bars take their colors from it. The palette needs the in-process library below.

The in-process library

libjupynvim, a Rust library Neovim loads through LuaJIT's FFI, comes with the same install as the backend, prebuilt for macOS arm64 and x86_64 and Linux x86_64 and arm64. It runs heavy work on worker threads, never on the UI thread. It is optional: without it, or on a Neovim built without LuaJIT, everything works as before. A missing or outdated library is fetched in the background while you keep working, checked against the release's SHA256SUMS and loaded in a separate Neovim first. native = { ... } in setup() and JUPYNVIM_NATIVE turn it off or point at a library you built, and :checkhealth jupynvim shows whether it loaded.

Kernel connection files

Kernel connection files are kept in a private per-user runtime directory and removed when kernels stop or jupynvim exits, also after a crash or a closed terminal. ipykernel binds its own ports and other kernels get ports reserved for them. Starting a kernel is faster, about 0.2 s instead of 1.5 s. The README's Runtime files section has the details, and JUPYNVIM_RUNTIME_DIR picks another place.

From contributors

  • A second notebook opened while the first was still attaching no longer starts a second backend, which was one cause of the "no session" error (#44, by @nyxar77).
  • A pandas Styler shows its table as aligned text instead of <pandas.io.formats.style.Styler at 0x...> (#45, by @Matthew-Eucaristo).
  • The comment above image_rows and image_cols names the real default, 16x48 (#46, by @Matthew-Eucaristo).
  • A project's Pixi environment is found automatically, for local and remote notebooks and the kernel picker, when ipykernel is installed in it (#47, by @jdefowler).
  • Run all, run above and run below mark every submitted cell [*] the JupyterLab way, with a gray dot on the cells waiting behind the running one. A cell run again before its earlier run finished stays queued until its last run, and Stop, Restart, a kernel that dies and a backend that exits release the waiting cells (#48, by @ClaytonMcCray).

Also

  • :checkhealth jupynvim starts with the plugin's version, also when the backend is missing.
  • JUPYNVIM_LOG_DIR writes core.log to another directory, and JUPYNVIM_RELEASE_BASE points every download at a mirror laid out like the GitHub releases.
  • Neovim 0.12 is now the recommended version.
  • For contributors: the test suite runs in an isolated environment of its own, never touches your own Neovim state, and two runs can go at once. A headless harness checks what the terminal shows, Kitty graphics included, with no GUI terminal.

Trying it

lazy.nvim users who follow main, as the README's spec does, get the beta with the next :Lazy update, whose build step also downloads the matching backend and library. To pin it, use tag = "v0.5.0-beta.1"; to stay on the stable release, tag = "v0.4.6".

With vim.pack, version = vim.version.range("*") picks the beta up, since it is the newest tag. To stay on the stable release, use version = "v0.4.6".

With mini.deps, set checkout = "v0.5.0-beta.1". The README's example keeps pointing at v0.4.6 during the betas.

For remote notebooks, the Linux backend is cross-built and uploaded again on the next :JupynvimConnect, as with every new version.

Known issues

  • On Neovim 0.11 an image write can still land inside a screen update and leave garbled text or a broken border. :JupynvimPauseAnimations and then :mode clear it. Neovim 0.12 does not have this.
  • Widgets draw as text, and no key or click changes a widget yet.
  • A backend that crashes or is killed still leaves its open notebooks with a "no session" error. Restart recovery comes in a later beta (#43).
  • A large pandas Styler is read on the UI thread when it first shows, about 0.15 s at pandas' render limit, until tables get their own renderer.
  • A Pixi environment without ipykernel is passed over without a word. Add it with pixi add ipykernel.
  • The first cell sometimes opens without its top border; <C-y> shows it.
  • Two open copies of the same notebook whose markdown cells embed images can save each other's images. Keep one copy open at a time until this is fixed.

Still on the list for v0.5.0

  • A backend restart no longer strands the notebook (#43)
  • Signed releases, also for the remote binary
  • Cell boxes with room to breathe: the first cell's top border on open, a right border that never covers text, and spacing around outputs
  • Terminal colors in outputs, and the kernel's real language in the footer (#42)
  • CI that runs the whole suite on every push
  • Kernel ready in about half a second and the notebook on screen at once
  • The image pipeline in Rust, with no ImageMagick or chafa, images sized to their place on screen and GIF frames uploaded once
  • Smooth output streams and a faster RPC reader
  • SSH, tmux and mosh: images sent directly over SSH, re-sent after a tmux reattach, and a text mode under mosh
  • The shared painter for markdown, tables and widgets...
Read more

v0.4.6

Choose a tag to compare

@github-actions github-actions released this 10 Oct 10:17

jupynvim v0.4.6

Everything from v0.4.6-beta.1, plus output views and fixes that came out of the beta. If you ran the beta, the new parts are right below.

Updating

lazy.nvim users who follow main, which is what the README's spec does, get it with the next :Lazy update, and the matching backend downloads on the first notebook you open. With vim.pack, version = vim.version.range("*") picks it up. mini.deps users can pin checkout = "v0.4.6".

The first time you open a notebook that has a long, cut output, its undo history from before the update isn't read back, because the cut output's text changed. Notebooks without a cut output keep theirs.

Since the beta

  • Hide a cell's whole output, plots included, with <leader>nO (#37). One line like ⋯ output hidden (1 image) takes its place, it stays hidden when the cell runs again and after a save, and the .ipynb never changes.
  • A long output shows its first max_output_lines lines, 500 by default, and its last 5, with a marker such as ⋯ 495 lines hidden (1000 total) between them. It used to show a quarter from the top and the rest from the bottom, and the counts were off by one. <leader>nl asks how many lines one cell shows, and <leader>no then toggles between that and every line.
  • <leader>no says "nothing to expand" when nothing is cut, instead of claiming it expanded a plot (#37). Expanding no longer marks the notebook modified, so :q just quits, and saving with an output expanded no longer loses the undo history on the next open. The key hint after the marker follows your keymaps.
  • image_renderer = "chafa" draws code-cell images in terminals without Kitty graphics, like Windows Terminal (#38, thanks @leolaurindo).
  • A quick re-run whose output has the same length no longer shows the previous run's text (#41, thanks @ClaytonMcCray).
  • Keys that act on a cell, like <S-CR>, pick the cell you see while an output is still arriving or after :undo N.
  • Two copies of one notebook open at once no longer share expanded state or images.

Editing can no longer break a cell

Backspace at the start of a cell, J or Delete at its end, and dj or dG across the boundary merged two cells, and the next :w saved one cell's code under another's id or dropped a cell. Those edits are taken back now, so Backspace at a cell's start does nothing, the way it does in VS Code. Text typed along with them, by . or a macro, is kept. A cell you empty keeps one line to type on, a line moved under an output stays in its cell, and a :s that matches the separator text keeps the rest of its changes.

Undo inside a cell means your edit

u undoes your last edit, not the output a run wrote, and the output stays on screen. Output streaming in while you type no longer ends up in your undo steps, and a long, chatty run no longer pushes your own edits out of the undo history. :undo N and :earlier land exactly where you send them. Undo inside a cell stops at the last cell added, deleted or moved, and u in command mode undoes those. Undo history survives a reopen and :e!.

Moving between cells while editing (#27)

]c and [c move to the next or previous cell and keep you editing. A search, a diagnostic jump or a click that lands in another cell moves the editing there. <leader>nc and the run keys used from a cell's output act on that cell, not the one below.

Several images in one cell (#34)

Every image a cell outputs is shown, stacked in order. clear_output(wait=True) animations replace their frame instead of stacking it, and display(..., display_id=True) handles update in place. Saving an image asks which one when a cell has several, and SVG can be saved.

Language servers (#32)

Reopening a Julia notebook no longer attaches pyright. The kernel's language decides the filetype and whether Python-only setup runs. Each notebook gets its own pyright and keeps it across reopens instead of starting another every time, and an idle pyright left by a .py file is never taken over.

Installing without lazy.nvim (#33)

The backend installs itself on the first notebook you open, with vim.pack, mini.deps or a plain clone. It downloads the release that matches the plugin, checks its SHA256 and makes sure it runs on your machine before installing it. Set auto_install = false to turn that off. :JupynvimInstall installs or reinstalls it by hand, and :checkhealth jupynvim shows what it found. The Linux binary is statically linked now, so it runs on older distributions and HPC login nodes, where the previous one needed glibc 2.39. The README has vim.pack and mini.deps examples.

Also

  • Keymap overrides can set their mode, as in run_advance = { lhs = "<leader>r", mode = "n" } (#31, thanks @ferant2406). An override that starts with a printable key, like a Space leader, no longer maps in insert mode.
  • Images whose base64 contains whitespace render (#35, thanks @linmjie).
  • b then dd typed quickly, in a macro or through :normal act on the right cell.
  • A source line that reads exactly like jupynvim's cell separator no longer splits its cell on save.
  • A click after opening a split lands in the cell you clicked, and 2<CR> while editing moves two lines.
  • Remote: a respawn after an expired job no longer brings back the slow re-probe, and replacing a backend no longer drops the new one from routing.

Known

u right after clearing outputs cannot bring them back, and says so.

Full Changelog: v0.4.5...v0.4.6

v0.4.6-beta.1

Choose a tag to compare

@github-actions github-actions released this 23 Sep 17:28

jupynvim v0.4.6-beta.1

A beta. Ordinary editing can no longer break a cell, undo inside a cell means your edit, and the backend installs itself with any plugin manager. The editing and undo changes touch every keystroke, so please try it and report anything odd.

Trying it

lazy.nvim users who follow main, which is what the README's spec does, get it with the next :Lazy update, and the matching backend downloads on the first notebook you open. With vim.pack, version = vim.version.range("*") picks it up. To stay on the stable release, pin tag = "v0.4.5" in lazy.nvim or version = "v0.4.5" in vim.pack.

Editing can no longer break a cell

Backspace at the start of a cell, J or Delete at its end, and dj or dG across the boundary merged two cells, and the next :w saved one cell's code under another's id or dropped a cell. Those edits are taken back now, so Backspace at a cell's start does nothing, the way it does in VS Code. Text typed along with them, by . or a macro, is kept. A cell you empty keeps one line to type on, a line moved under an output stays in its cell, and a :s that matches the separator text keeps the rest of its changes.

Undo inside a cell means your edit

u undoes your last edit, not the output a run wrote, and the output stays on screen. Output streaming in while you type no longer ends up in your undo steps, and a long, chatty run no longer pushes your own edits out of the undo history. :undo N and :earlier land exactly where you send them. Undo inside a cell stops at the last cell added, deleted or moved, and u in command mode undoes those. Undo history survives a reopen and :e!.

Moving between cells while editing (#27)

]c and [c move to the next or previous cell and keep you editing. A search, a diagnostic jump or a click that lands in another cell moves the editing there. <leader>nc and the run keys used from a cell's output act on that cell, not the one below.

Several images in one cell (#34)

Every image a cell outputs is shown, stacked in order. clear_output(wait=True) animations replace their frame instead of stacking it, and display(..., display_id=True) handles update in place. Saving an image asks which one when a cell has several, and SVG can be saved.

Language servers (#32)

Reopening a Julia notebook no longer attaches pyright. The kernel's language decides the filetype and whether Python-only setup runs. Each notebook gets its own pyright and keeps it across reopens instead of starting another every time, and an idle pyright left by a .py file is never taken over.

Installing without lazy.nvim (#33)

The backend installs itself on the first notebook you open, with vim.pack, mini.deps or a plain clone. It downloads the release that matches the plugin, checks its SHA256 and makes sure it runs on your machine before installing it. Set auto_install = false to turn that off. :JupynvimInstall installs or reinstalls it by hand, and :checkhealth jupynvim shows what it found. The Linux binary is statically linked now, so it runs on older distributions and HPC login nodes, where the previous one needed glibc 2.39. The README has vim.pack and mini.deps examples.

Also

  • Keymap overrides can set their mode, as in run_advance = { lhs = "<leader>r", mode = "n" } (#31, thanks @ferant2406). An override that starts with a printable key, like a Space leader, no longer maps in insert mode.
  • Images whose base64 contains whitespace render (#35, thanks @linmjie).
  • b then dd typed quickly, in a macro or through :normal act on the right cell.
  • A source line that reads exactly like jupynvim's cell separator no longer splits its cell on save.
  • A click after opening a split lands in the cell you clicked, and 2<CR> while editing moves two lines.
  • Remote: a respawn after an expired job no longer brings back the slow re-probe, and replacing a backend no longer drops the new one from routing.

Known

u right after clearing outputs cannot bring them back, and says so.

Full Changelog: v0.4.5...v0.4.6-beta.1

v0.4.5

Choose a tag to compare

@github-actions github-actions released this 28 Aug 04:50

jupynvim v0.4.5

Big notebooks stay responsive.

Stored output no longer freezes the editor

A notebook whose cell holds the output of something like !tree over a dataset directory could peg the editor at ~99% CPU with the main loop starved. Measured on a 2.1 MB notebook of 124 cells, one of which stores a 420 KB listing of 12002 files: 2535 full document rebuilds during 74 seconds of idle time, 97% of wall clock, and the command line never accepted input. Typing three characters cost 5.9 seconds. A single keystroke took 7.6 seconds to echo. The worst stall was 19.7 seconds.

Outputs render as real buffer lines, and the renderer walked the entire stored text through carriage-return and ANSI processing on every call, dozens of times per keystroke because the diagnostic and didChange paths each triggered it. Neither pass changes the line count, so the lines actually shown are now sliced out first and only those are processed, and the result is cached per cell on a content-derived key. Diagnostics also resolved a cell's start line once per diagnostic, each resolution rebuilding the whole document; that is hoisted to once per publish.

Rebuild cost went from 27 ms to 0.62 ms, and 20 seconds of idle went from 2535 rebuilds to one.

Two symptoms that looked unrelated came from the same freeze: a keypress queued during a multi-second stall replays into a duplicate file explorer, and that duplicate drives cmdheight up, leaving a dead region at the bottom of the screen. Both go away with the stall.

Output is capped, and you can tune it

max_output_lines bounds how many lines of a cell's output are rendered, default 500. Set it to 0 to disable. Both ends are kept, so a training log still shows its final epochs, with a marker in between telling you how many lines are hidden. <leader>no expands or re-collapses the cell under the cursor.

This is display only. The .ipynb keeps every line and saving is lossless.

Full Changelog: v0.4.4...v0.4.5

v0.4.4

Choose a tag to compare

@github-actions github-actions released this 07 Aug 04:07

jupynvim v0.4.4

Cell editing behaves the way vim taught you to expect.

Undo, delete, paste

dd then u used to fail with "modifiable is off". Command mode makes the buffer nomodifiable, and deleting a cell also mutates the notebook model and the backend, so vim's text-level undo was blocked and would have restored text into a model that no longer had the cell.

There is a cell-level undo now, and it follows the order of what you did rather than only re-inserting the last delete, so dd then p then u walks back one step at a time instead of leaving a duplicate. It covers every entry point: the cell-mode keys, <leader>na / <leader>nb / <leader>nd, and the :Jupynvim* commands. dd also yanks what it removes, and P pastes above as well as p below. Reported by @benkj in #27.

move_cell and cell-type changes are not on the stack yet, and there is no redo.

]c and [c move between cells again

They have always been bound to next-cell and prev-cell, but they attach during BufReadCmd and LazyVim's treesitter-textobjects binds the same keys on FileType, after us, and won. In a stock LazyVim config they resolved to "Next Class Start". They are rebound after the filetype autocmds settle, so they are ours again.

Clearing output takes effect immediately

<leader>nc and <leader>nC cleared the model but left the old text on screen until you reopened the notebook. Outputs are real buffer lines, so the buffer is rewritten now, and the change survives :w.

Counts work inside a cell

5j moved one line. j and k in edit mode threw away the count. They honour it now, still clamped to the cell so a large count stops at the boundary instead of bleeding into the next one.

Full Changelog: v0.4.3...v0.4.4

v0.4.3

Choose a tag to compare

@github-actions github-actions released this 02 Aug 08:17

jupynvim v0.4.3

Your leader keys are your own again.

Keybindings only while connected

jupynvim used to bind <leader>e, <leader>E, <leader>ff, <leader>/, <leader>sg, <leader><space>, <leader>tr and <C-/> at startup, in every buffer of every filetype, whether or not you ever opened a notebook.

They are borrowed only while an SSH session is active now. If you already had a mapping, jupynvim takes the key on connect and restores yours exactly when the session ends. Keys you had not mapped stay bound and fall back to the local equivalent (#24, thanks @SuperCowProducts).

<leader>e and <leader>E differ again

Both had quietly collapsed onto the same call, so the root-dir versus cwd split your distro gives you vanished once jupynvim loaded. <leader>e opens the project root of the remote file you are in, found by walking up for a .git. <leader>E opens the remote working directory, which :JupynvimRemoteCd sets.

Faster remote listings

fs_list called metadata() and symlink_metadata() on every entry, one after the other, and the frontend only ever reads three fields. On a filesystem where metadata is cheap you never noticed; on an NFS home you waited seconds for a directory that a parallel filesystem rendered instantly. It now takes the kind from the dirent and only follows actual symlinks.

The linux binary keeps itself in step

Deploying to a remote always compared your local cross-build against the one on the remote and uploaded on mismatch, but nothing ever rebuilt it. It could sit weeks behind the source while every connect compared it against its own upload and correctly concluded there was nothing to send.

Connecting now rebuilds it locally first when it has fallen behind core/, then uploads. Never on the remote. If you have the cross-build toolchain, a connect after changing the backend will pause to rebuild; if you do not, you get the same message as before telling you what to install.

Neovim deprecations

vim.loop, nvim_buf_set_option, nvim_buf_add_highlight, termopen and vim.tbl_islist are gone, so jupynvim keeps working as Neovim removes them (#26, thanks @navdeeprana).

Full Changelog: v0.4.2...v0.4.3

v0.4.2

Choose a tag to compare

@github-actions github-actions released this 26 Jun 00:07

jupynvim v0.4.2

Notebooks now remember where you were.

Cursor memory across save and reopen

Reopen a notebook after :wqa or :qa and you land back on the line you left off in each cell, with the highlight, as if you never closed it. Every cell keeps its own last position, restored the moment the notebook renders.

Positions live in a small state file under stdpath("state"), never written into the .ipynb, so the notebooks you commit stay clean.

Full Changelog: v0.4.1...v0.4.2

v0.4.1

Choose a tag to compare

@github-actions github-actions released this 17 Jun 04:43

jupynvim v0.4.1

A polish release for the remote workspace and notebook UI, with colorscheme integration and a supply-chain hardening on top of v0.4.0.

Highlights follow your colorscheme

  • Highlight groups now set default = true and fall back to builtin Neovim groups (#20, thanks @fsiraj), so the UI tracks your theme instead of hardcoded colors. output_color and the cell frame border stay configurable.

Remote explorer and file opening

  • Files opened from the explorer land in the main editor area, never a far corner, whether a bottom or right terminal is open. The terminal is kept and resized back to its slot.
  • Notebooks opened from the explorer render and show as a bufferline tab, and no longer leave a [No Name] buffer or drop the terminal.
  • The explorer sidebar re-pins to its width when the dashboard closes or a file opens, instead of ballooning to fill the pane.
  • :JupynvimRemoteCd location is kept across an explorer toggle.
  • A redundant empty [No Name] tab left behind by leader-bd is cleaned up on the next open.

Notebook UI

  • The whole cell frame runs the busy color while a cell executes, not just the top border.

Security

  • New: the installer verifies the prebuilt against the release SHA256SUMS and builds from source instead of running it on a hash mismatch or a binary not listed in the sums. Releases with no SHA256SUMS at all warn and proceed. Signing, for the case where both the binary and the sums are replaced, is on the roadmap.

Fixes

  • :Jupynvim* commands work when passed buffer 0 (#19, thanks @zggff).
  • Per-write image logging no longer floods lua.log; animated GIFs re-transmit on a timer, so the success logs are debug level now.

Install

lazy.nvim users get the prebuilt mac-arm64 or linux-x64 binary on update, verified against the release SHA256SUMS. Other platforms build via cargo.

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 15 Jun 17:54

jupynvim v0.4.0

Remote workspace over SSH. nvim and the UI stay local while only the Rust backend runs on the remote, so you can edit files, run Jupyter kernels, browse, search, and open terminals on a remote machine or HPC cluster as if it were local. Built on plain ssh, so it works where SFTP/scp are disabled and inbound ports are firewalled (tested on PSC Bridges-2).

Remote workspace (new)

  • Connect over SSH. :JupynvimConnect <alias|user@host> authenticates once (password, 2FA) and keeps a ControlMaster socket alive across nvim restarts. :JupynvimDisconnect and :JupynvimUseLocal switch back.
  • Any file, not just notebooks. Remote paths use the jupynvim://<alias>/<path> scheme. Open and save any file; .ipynb opens as a notebook with the kernel running on the remote.
  • File browser for the remote tree (:JupynvimExplorer, <leader>e while connected).
  • PTY terminals, VSCode-style. A bottom terminal (<C-/>) and a second one on the right (<leader>tr) tile together, so you can run a job in one and a tool like Claude Code in the other, all on the remote. Resize with Shift+hjkl in normal mode (or Ctrl+arrows, also in insert). Full vi editing on the shell prompt.
  • Live ripgrep search across the remote into the quickfix list (:JupynvimGrep, <leader>/), streamed as matches are found.
  • Slurm. :JupynvimUseJob <alias> [<jobid>] routes the kernel through an srun overlay so it lands on an allocated compute node.
  • Multiple remotes coexist with local; each buffer routes to its own connection.
  • Binary auto-deploy. The Linux backend is cross-built and uploaded to the remote on connect when it is missing or out of date.
  • Per-mode Kitty graphics. Remote image bytes are encoded locally, so plot data never crosses the link more than once.
  • Remote LSP relay (partial). Kernel completion and hover work over SSH; a full editor language-server relay is in progress.

Notebook UI

  • VSCode-style cell layout with uniform frames. Outputs are real buffer regions you move through with full vim motions.
  • Per-cell execution timing badge in the cell footer ([n] ✓ 0.1s), persisted in the notebook so it survives save and reopen. Clearing the output clears it.
  • One-shot cell navigation (animated scroll off in notebooks; set smooth_scroll = true to restore it).
  • Markdown: gx on links, table rendering, fuller inline syntax.
  • Hybrid relative line numbers; statuscolumn selection bar.

Kernels

  • Project-local venv discovery (.venv, venv, env) in the picker, plus remote auto-venv.
  • Lists conda envs without ipykernel and auto-installs ipykernel on first pick.
  • Discovers module-loaded anaconda via PATH and surfaces kernel start errors.

Fixes

  • Cell frames stay aligned and stable across layout changes (terminal split, explorer, picker, notify popups). Root cause was reading the gutter width from a transiently wrong textoff.
  • Kernels are killed on SIGTERM, SIGHUP, and disconnect instead of being orphaned, so ipykernel processes no longer pile up.
  • Execution order of "run all cells above/below" (#15, thanks @idanarye; incorporates #14).
  • Many remote terminal, search, and LSP robustness fixes.

Known issues

  • In placeholder image mode, a Kitty image cell can occasionally fall back to its font glyph (a colored block) after a full redraw on some terminals. The image id is derived from the editor background so leaked cells blend on a dark background, but a cell over a light image area can still show. This is terminal-layer behavior and is not reproducible without a Kitty terminal.
  • The right cell border cannot be drawn on wrapped continuation rows (Neovim has no per-visual-row virtual-text API), so very long lines show a gap on the wrapped portion.

Install

lazy.nvim users get the prebuilt mac-arm64 or linux-x64 binary on update; other platforms build via cargo. See the README for remote setup.

v0.3.1

Choose a tag to compare

@github-actions github-actions released this 22 May 07:22
8705984

Bug fix

No more global conceallevel / concealcursor pollution (#9 by @Matheus-OAMK). jupynvim's M.setup was setting vim.opt.conceallevel = 2 and vim.opt.concealcursor = "nc" globally. These are window-local options, but setting them via vim.opt sets the global default that every fresh window inherits — including unrelated buffers like JSON files where you'd suddenly see quotes concealed.

The notebook buffers already apply these via buffer-local setlocal in three places (M.open, _populate_buffer, _attach_lsp), covering every entry path including :e, :tabnew, :split, and reusing a window. The global setting was pure side effect.

Verified before merge that conceal still works for notebook buffers in fresh tabs, splits, and when reusing a non-notebook window. JSON and other file types now keep their default conceallevel = 0.

Thanks to @Matheus-OAMK for the diagnosis and fix.