The bridge between Neovim and Jupyter Lab, edit in Neovim and preview/run in Jupyter Lab.
This project includes two parts: a JupyterLab extension
and a Neovim plugin
JupyterLab extension
exposes functions of Jupyter lab
, and provides a remote procedure call(RPC) serviceNeovim plugin
calls the RPC service when it receives events from Neovim
via autocmd
This project provides two work modes for different network environments. If the browser where your jupyter lab is
located cannot directly access nvim, you must use proxy
mode; If you need to collaborate and use the same Jupyter with
others, you must use direct mode
direct
mode: (default, recommended) In this mode, neovim is server and neovim plugin(neopyter) is listening to remote_address
,
the browser where jupyter lab is located will connect to neovim
proxy
mode: In this mode, Jupyter lab server(server side, the host you run jupyter lab
to start JupyterLab) is server
and jupyter lab server extension(neopyter) is listening to ${IP}:{Port}
, the neovim plugin(neopyter) will connect to ${IP}:{Port}
Ultimately, Neopyter
can control Juppyter lab
. Neopyter
can implement abilities like jupynium.nvim.
nvim-lua/plenary.nvim
AbaoFromCUG/websocket.nvim
(optional for mode="direct"
)To install the jupyterlab extension, execute:
pip install neopyter
Configure JupyterLab
in side panel
mode
: Refer to the previous introduction about modeIP
: If mode=proxy
, set to the IP of the host where jupyter server is located. If proxy=direct
, set to the IP of the
host where neovim is locatedPort
: Idle port of the IP
's' hostNOTICE: all settings is saved to localStorage
With 💤lazy.nvim:
{
"SUSTech-data/neopyter",
---@type neopyter.Option
opts = {
mode="direct",
remote_address = "127.0.0.1:9001",
file_pattern = { "*.ju.*" },
on_attach = function(bufnr)
-- do some buffer keymap
end,
highlight = {
enable = true,
shortsighted = false,
},
parser = {
-- trim leading/tailing whitespace of cell
trim_whitespace = false,
}
},
}
Suggest keymaps(neopyter
don't provide default keymap):
on_attach = function(buf)
local function map(mode, lhs, rhs, desc)
vim.keymap.set(mode, lhs, rhs, { desc = desc, buffer = buf })
end
-- same, recommend the former
map("n", "<C-Enter>", "<cmd>Neopyter execute notebook:run-cell<cr>", "run selected")
-- map("n", "<C-Enter>", "<cmd>Neopyter run current<cr>", "run selected")
-- same, recommend the former
map("n", "<space>X", "<cmd>Neopyter execute notebook:run-all-above<cr>", "run all above cell")
-- map("n", "<space>X", "<cmd>Neopyter run allAbove<cr>", "run all above cell")
-- same, recommend the former, but the latter is silent
map("n", "<space>nt", "<cmd>Neopyter execute kernelmenu:restart<cr>", "restart kernel")
-- map("n", "<space>nt", "<cmd>Neopyter kernel restart<cr>", "restart kernel")
map("n", "<S-Enter>", "<cmd>Neopyter execute runmenu:run<cr>", "run selected and select next")
map("n", "<M-Enter>", "<cmd>Neopyter execute run-cell-and-insert-below<cr>", "run selected and insert below")
map("n", "<F5>", "<cmd>Neopyter execute notebook:restart-run-all<cr>", "restart kernel and run all")
end
jupyter lab
, there is a sidebar named Neopyter
, which display neopyter ip+port*.ju.py
file in neovim# %%
in Neovim to create a code cell.:Neopyter status
alias to :checkhealth neopyter
currently:Neopyter connect [remote 'ip:port']
, e.g. :Neopyter command 127.0.0.1:9001
, connect Jupyter lab
manually:Neopyter disconnect
:Neopyter sync current
, make sync current *.ju.*
file with the currently open *.ipynb
:Neopyter sync [filename]
, e.g. :Neopyter sync main.ipynb
:Neopyter run current
, same as Run
>Run Selected Cell and Do not Advance
menu in Jupyter lab
:Neopyter run allAbove
, same as Run
>Run All Above Selected Cell
menu in Jupyter lab
:Neopyter run allBelow
, same as Run
>Run Selected Cell and All Below
menu in Jupyter lab
:Neopyter run all
, same as Run
>Run All Cells
menu in Jupyter lab
:Neopyter kernel restart
, same as Kernel
>Restart Kernel
menu in Jupyter lab
:Neopyter kernel restartRunAll
, same as Kernel
>Restart Kernel and Run All Cells
menu in Jupyter lab
:Neopyter execute [command_id] [args]
, execute Jupyter lab
's
command
directly, e.g. :Neopyter execute notebook:export-to-format {"format":"html"}
If neoconf.nvim is available, neopyter
will automatically register/read neoconf
settings
{
"neopyter": {
"mode": "proxy",
"remote_address": "127.0.0.1:9001"
}
}
nvim-cmp
lspkind.nvim
local lspkind = require("lspkind")
local cmp = require("cmp")
cmp.setup({
sources = cmp.config.sources({
-- default: all source, maybe some noice
{ name = "neopyter" },
-- only kernel source, like jupynium, support jupyterlab completer id:
-- * "CompletionProvider:kernel"
-- * "CompletionProvider:context"
-- * "lsp" if jupyterlab-lsp is installed
-- * ...
-- { name = "neopyter", option={ completers = { "CompletionProvider:kernel" } } },
}),
formatting = {
format = lspkind.cmp_format({
mode = "symbol_text",
maxwidth = 50,
ellipsis_char = "...",
menu = {
neopyter = "[Neopyter]",
},
symbol_map = {
-- specific complete item kind icon
["Magic"] = "🪄",
["Path"] = "📁",
["Dict key"] = "🔑",
["Instance"]="",
["Statement"]="",
},
}),
},
)}
-- menu item highlight
vim.api.nvim_set_hl(0, "CmpItemKindMagic", { bg = "NONE", fg = "#D4D434" })
vim.api.nvim_set_hl(0, "CmpItemKindPath", { link = "CmpItemKindFolder" })
vim.api.nvim_set_hl(0, "CmpItemKindDictkey", { link = "CmpItemKindKeyword" })
vim.api.nvim_set_hl(0, "CmpItemKindInstance", { link = "CmpItemKindVariable" })
vim.api.nvim_set_hl(0, "CmpItemKindStatement", { link = "CmpItemKindVariable" })
More information, see nvim-cmp wiki
Supported captures in textobjects
query group
require'nvim-treesitter.configs'.setup {
textobjects = {
move = {
enable = true,
goto_next_start = {
["]j"] = "@cellseparator",
["]c"] = "@cellcontent",
},
goto_previous_start = {
["[j"] = "@cellseparator",
["[c"] = "@cellcontent",
},
},
},
}
Neopyter
provides rich lua APIs
Jupyter Lab
Neopyter execute ...
<-> require("neopyter.jupyter").jupyterlab:execute_command(...)
:lua =require("neopyter.jupyter.jupyterlab").__injected_methods
Notebook
:Neopyter run current
<-> require("neopyter.jupyter").notebook:run_selected_cell()
:Neopyter run allAbove
<-> require("neopyter.jupyter").notebook:run_all_above()
:Neopyter run allBelow
<-> require("neopyter.jupyter").notebook:run_all_below()
:lua =require("neopyter.jupyter.notebook").__injected_methods
.ipynb
manuallyip:port
RpcClient
, support async RPC request
vim.rpcrequest
and vim.rpcnotify