A JupyterLab extension. Integrate JupyterLab and Neovim
Project description
Introduction
The bridge between Neovim and Jupyter Lab, edit in Neovim and preview/run in Jupyter Lab.
How does it work?
This project includes two parts: a JupyterLab extension
and a Neovim plugin
- The
JupyterLab extension
exposes functions ofJupyter lab
, and provides a remote procedure call(RPC) service - The
Neovim plugin
calls the RPC service when it receives events fromNeovim
viaautocmd
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 | proxy | |
---|---|---|
Architecture |
|
|
Advantage |
|
|
Disadvantage |
|
|
-
direct
mode: (default, recommended) In this mode, neovim is server and neovim plugin(neopyter) is listening toremote_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 runjupyter 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.
Specifications
Please refer to doc/specification.ipynb and doc/specification.ju.py
Screenshots
[Completion](#blinkcmp) | Cell Magic | Line Magic | |
---|---|---|---|
|
|
|
Requirements
- 📔JupyterLab >= 4.0.0
- ✌️ Neovim latest
- 👍
nvim-lua/plenary.nvim
- 🤏
AbaoFromCUG/websocket.nvim
(optional formode="direct"
)
- 👍
Installation
Neopyter
support two parts, so we need to install them separately.
JupyterLab Extension
To install the jupyterlab extension, execute:
pip install neopyter
Configure JupyterLab
in side panel
mode
: Refer to the previous introduction about modeIP
: Ifmode=proxy
, set to the IP of the host where jupyter server is located. Ifproxy=direct
, set to the IP of the host where neovim is locatedPort
: Idle port of theIP
's' host
NOTICE: all settings is saved to localStorage
Neovim Plugin
- 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,
},
}
Default configuration
---@type neopyter.Option
local default_config = {
remote_address = "127.0.0.1:9001",
file_pattern = { "*.ju.*" },
filename_mapper = function(ju_path)
local ipynb_path = vim.fn.fnamemodify(ju_path, ":r:r:r") .. ".ipynb"
return ipynb_path
end,
--- auto attach to buffer
auto_attach = true,
--- auto connect with remote jupyterlab
auto_connect = true,
mode = "direct",
---@type neopyter.JupyterOption # ref `:h neopyter.JupyterOption`
jupyter = {
auto_activate_file = true,
-- Always scroll to the current cell.
scroll = {
enable = true,
align = "center",
},
},
---@type neopyter.HighlightOption # ref `:h neopyter.HighlightOption`
highlight = {
enable = true,
mode = "separator",
},
---@type neopyter.TextObjectOption # ref `:h neopyter.TextObjectOption`
textobject = {
enable = true,
queries = { "cellseparator" },
},
---@type neopyter.InjectionOption # ref `:h neopyter.InjectionOption`
injection = {
enable = true,
},
---@type neopyter.ParserOption # ref `:h neopyter.ParserOption`
parser = {
trim_whitespace = false,
python = {},
},
}
See :h neopyter-configuration-types
for all option type description.
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
Usage
- Open JupyterLab
jupyter lab
, there is a sidebar namedNeopyter
, which display neopyter ip+port - Open a
*.ju.py
file in neovim - Now you can type
# %%
in Neovim to create a code cell.- You'll see everything you type below that will be synchronised in the browser
Available Vim Commands
- Status
:Neopyter status
alias to:checkhealth neopyter
currently
- Server
:Neopyter connect [remote 'ip:port']
, e.g.:Neopyter command 127.0.0.1:9001
, connectJupyter lab
manually:Neopyter disconnect
- Sync
:Neopyter sync current
, make sync current*.ju.*
file with the currently open*.ipynb
:Neopyter sync [filename]
, e.g.:Neopyter sync main.ipynb
- Run
:Neopyter run current
, same asRun
>Run Selected Cell and Do not Advance
menu inJupyter lab
:Neopyter run allAbove
, same asRun
>Run All Above Selected Cell
menu inJupyter lab
:Neopyter run allBelow
, same asRun
>Run Selected Cell and All Below
menu inJupyter lab
:Neopyter run all
, same asRun
>Run All Cells
menu inJupyter lab
- Kernel
:Neopyter kernel restart
, same asKernel
>Restart Kernel
menu inJupyter lab
:Neopyter kernel restartRunAll
, same asKernel
>Restart Kernel and Run All Cells
menu inJupyter lab
- Jupyter
:Neopyter execute [command_id] [args]
, executeJupyter lab
's command directly, e.g.:Neopyter execute notebook:export-to-format {"format":"html"}
Integration
neoconf.nvim
If neoconf.nvim is available, neopyter
will automatically register/read neoconf
settings
{
"neopyter": {
"mode": "proxy",
"remote_address": "127.0.0.1:9001"
}
}
nvim-cmp
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" },
-- { name = "neopyter", option={ source = { "CompletionProvider:kernel" } } },
}),
formatting = {
format = lspkind.cmp_format({
mode = "symbol_text",
menu = {
buffer = "[Buf]",
nvim_lsp = "[LSP]",
nvim_lua = "[Lua]",
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
blink.cmp
blink.cmp
require("blink-cmp").setup({
sources = {
default = {
"neopyter",
},
providers = {
neopyter = {
name = "Neopyter",
module = "neopyter.blink",
---@type neopyter.CompleterOption
opts = {},
},
},
},
})
textobjects
Supported captures in textobjects
query group
@cell
@cell.code
@cell.magic
@cell.markdown
@cell.raw
@cellseparator
@cellseparator.code
@cellseparator.magic
@cellseparator.markdown
@cellseparator.raw
@cellbody
@cellbody.code
@cellbody.magic
@cellbody.markdown
@cellbody.raw
@cellcontent
@cellcontent.code
@cellcontent.magic
@cellcontent.markdown
@cellcontent.raw
@cellborder
@cellborder.start
@cellborder.start.markdown
@cellborder.start.raw
@cellborder.end
@cellborder.end.markdown
@cellborder.end.raw
@linemagic
require'nvim-treesitter.configs'.setup {
textobjects = {
move = {
enable = true,
goto_next_start = {
["]j"] = "@cellseparator",
},
goto_previous_start = {
["[j"] = "@cellseparator",
},
},
},
}
API
Neopyter
provides rich lua APIs, you could use below code as initialization:
-- Reference to `:h neopyter-jupyterlab-api` for all api document
local current_lab = require("neopyter.jupyter").jupyterlab
current_lab:execute_command("notebook:export-to-format", {format="html"})
-- Reference to `:h neopyter-notebook-api` for all api document
local current_notebook = require("neopyter.jupyter").notebook
current_notebook:run_selected_cell()
current_notebook:run_all_above()
current_notebook:run_all_below()
- Notebook API:
:h neopyter-notebook-api
- JupyterLab API
:h neopyter-jupyterlab-api-api
Async
Notebook
and JupyterLab
APIs are wrapped by async context automatically.
- If you call api from async context, anything is OK. Otherwise, the calling order cannot be guaranteed
- A single API call always works
vim.defer_fn(function()
-- non-async context, API response may be unordered
current_notebook:run_selected_cell()
current_notebook:run_all_above()
current_notebook:run_all_below()
end, 0)
require("neopyter.async").run(function()
-- async context, so which will call and return in order
current_notebook:run_selected_cell()
current_notebook:run_all_above()
current_notebook:run_all_below()
end)
Features
- Neovim
- Full sync
- Partial sync
- Scroll view automatically
- Activate cell automatically
- Save notebook automatically
- Completion
- Magic completion item
- Path completion item
- Tree-sitter
- Highlight
- Separator+non-code
- Shortsighted
- Textobjects
- Fold
- Highlight
- Kernel management
- Restart kernel
- Restart kernel and run all
- Run cell
- Run selected cell
- Run all above selected cell
- Run selected cell and all below
- Run all cell
- Sync
- Set synchronized
.ipynb
manually
- Set synchronized
- Notebook manager
- Open corresponding notebook if exists
- Sync with untitled notebook default
- Close notebook when buffer unload
- Jupyter Lab
- Settings
- TCP server host/port settings
- Status Sidebar
- Settings
ip:port
- Display client info
- Settings
- Settings
- Performance
- Rewrite
RpcClient
, support async RPC requestvim.rpcrequest
andvim.rpcnotify
- Rewrite
highlights
andtextobjects
queries - Rewrite parser with tree-sitter
- Unified
highlights
,textobjects
,parser
to unified parser
- Rewrite
- Document
- API Document
Acknowledges
- jupynium.nvim: Selenium-automated Jupyter Notebook that is synchronised with Neovim in real-time.
- snacks.nvim: The
zen
highlight is inspired bysnacks.zen
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file neopyter-0.3.1.tar.gz
.
File metadata
- Download URL: neopyter-0.3.1.tar.gz
- Upload date:
- Size: 2.8 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.0.1 CPython/3.12.8
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | c824e6297c8fba74fd4969a83bb0a59afdda10a7281dd4ba53c267518d6a50bc |
|
MD5 | f8464f3f194213b23a2121b26ce20030 |
|
BLAKE2b-256 | e251c2dcdcaa27219ee1a3b8bc1494dc62a3d49faa7589809908f40ca98f4410 |
Provenance
The following attestation bundles were made for neopyter-0.3.1.tar.gz
:
Publisher:
publish.yaml
on SUSTech-data/neopyter
-
Statement:
- Statement type:
https://in-toto.io/Statement/v1
- Predicate type:
https://docs.pypi.org/attestations/publish/v1
- Subject name:
neopyter-0.3.1.tar.gz
- Subject digest:
c824e6297c8fba74fd4969a83bb0a59afdda10a7281dd4ba53c267518d6a50bc
- Sigstore transparency entry: 161972086
- Sigstore integration time:
- Permalink:
SUSTech-data/neopyter@ef38c1c036639beaa5351af3d22319c88619dd6f
- Branch / Tag:
refs/tags/v0.3.1
- Owner: https://github.com/SUSTech-data
- Access:
public
- Token Issuer:
https://token.actions.githubusercontent.com
- Runner Environment:
github-hosted
- Publication workflow:
publish.yaml@ef38c1c036639beaa5351af3d22319c88619dd6f
- Trigger Event:
release
- Statement type:
File details
Details for the file neopyter-0.3.1-py3-none-any.whl
.
File metadata
- Download URL: neopyter-0.3.1-py3-none-any.whl
- Upload date:
- Size: 651.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.0.1 CPython/3.12.8
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | b901f8d4f356ba9aadadc33a8c3be4bf0b1bd547ee11460e047c9b6ffdc841e3 |
|
MD5 | 8a50d6db8e1017c387ed66c64af041e0 |
|
BLAKE2b-256 | 6748aff68ddf7a17eb5500c21dd55490b83b57b2e4dab0a72d2c4f60ee832275 |
Provenance
The following attestation bundles were made for neopyter-0.3.1-py3-none-any.whl
:
Publisher:
publish.yaml
on SUSTech-data/neopyter
-
Statement:
- Statement type:
https://in-toto.io/Statement/v1
- Predicate type:
https://docs.pypi.org/attestations/publish/v1
- Subject name:
neopyter-0.3.1-py3-none-any.whl
- Subject digest:
b901f8d4f356ba9aadadc33a8c3be4bf0b1bd547ee11460e047c9b6ffdc841e3
- Sigstore transparency entry: 161972091
- Sigstore integration time:
- Permalink:
SUSTech-data/neopyter@ef38c1c036639beaa5351af3d22319c88619dd6f
- Branch / Tag:
refs/tags/v0.3.1
- Owner: https://github.com/SUSTech-data
- Access:
public
- Token Issuer:
https://token.actions.githubusercontent.com
- Runner Environment:
github-hosted
- Publication workflow:
publish.yaml@ef38c1c036639beaa5351af3d22319c88619dd6f
- Trigger Event:
release
- Statement type: