replink is a CLI tool for piping code to a REPL running in a different pane and executing it there.
Handy when you want to evaluate code interactively, but your favorite code editor doesn't have a plugin system (yet) but can pipe selected text to a shell command!
replink sends code from your editor to a REPL running elsewhere.
Example: Python code to an IPython console inside a TMUX pane.
Sound easy enough? The 'sending' part may be, but getting code to show up in the right format on arrival is tricky.
As prior work like vim-slime figured out long ago, the solution lies in preprocessing code before sending it and accounting for whether the target expects bracketed paste or not. To make things extra fun, each language and each REPL presents subtle edge cases.
I built replink because I got used to sending Python code to a REPL early on in my career -- and Pycharm, VS Code, and Vim have all served to reinforce that habit. If I enjoyed maintaing a (Neo)vim config more, I would just use vim-slime or iron.nvim. But I like Helix, even if it doesn't have a plugin system. It makes up for it though with its :pipe-to command, which lets you send-and-forget selected text as stdin to any shell command -- replink, in this case. Tell replink what you're sending ('language') and where it needs to go ('target'); bind the complete command to a Helix keybinding, and you nearly have something that feels like a plugin.
replink supports these languages and targets:
Languages & REPLs:
- Python
- stock console
- Tested against various python3 REPLs.
- For python <= 3.12, use
--no-bpaste/-N. Python >= 3.13 uses bracketed paste.
- ipython
- Special --ipy-cpaste command for
%cpastepasting (I rarely need this).
- Special --ipy-cpaste command for
- ptpython
- Behaves similarly to python3.13 and above.
- stock console
Targets:
- TMUX
- Zellij
Adding new languages and targets is straightforward. Any language or target available in vim-slime can be ported over. This is because replink's architecture borrows heavily from vim-slime.
FRs and PRs welcome!
Use python >= 3.12.
uv tool install --python 3.12 replinkreplink send -l LANGUAGE -t TARGET [OPTIONS] [TEXT/-]-l, --lang: Language (currently onlypython)-t, --target: Target configuration- TMUX:
tmux:p=<pane>(e.g.,tmux:p=right,tmux:p=1) - Zellij:
zellij:p=<direction>orzellij:s=<session>:p=<direction>
- TMUX:
-N, --no-bpaste: Disable bracketed paste (for Python < 3.13)--ipy-cpaste: Use IPython's %cpaste command--debug: Enable debug logging
This is how I usually use replink, except I pipe in whatever is selected in my editor.
cat script.py | replink send -l python -t tmux:p=righttmux:p=right means 'use TMUX and send to the pane on the right of the current pane'. (The value of p is anything that can be interpreted by tmux selectp -t $VALUE.)
Specifying the TMUX target using the pane number is also valid. (Hitting <prefix-key> q shows the pane numbers.)
echo 'print("well hello there")' | replink send -l python -t tmux:p=4cat script.py | replink send -l python -t zellij:p=rightzellij:p=right means 'use Zellij and send to the pane on the right of the current pane'.
Zellij only supports directional positioning: current, right, left, up, down.
You can also target a specific Zellij session:
cat script.py | replink send -l python -t zellij:s=dev:p=downCode can also be passed to replink as a positional argument.
replink send -l python -t tmux:p=right 'print("oh hi!")'I only really use this when I'm debugging, since Python's built-in debugger doesn't play nice with active pipes.
However, it makes the following slightly easier to write:
replink send -l python -t tmux:p=right 'exit()'Up to and including Python 3.12, the standard Python console doesn't support bracketed paste, so make sure to disable it with --no-bpaste (or -N).
# TMUX
cat script.py | replink send -l python -t tmux:p=right --no-bpaste
# Zellij
cat script.py | replink send -l python -t zellij:p=right --no-bpasteAdd to your ~/.config/helix/config.toml:
[keys.normal."minus"]
# For TMUX
x = ":pipe-to replink send -l python -t tmux:p=right"
# For Zellij
x = ":pipe-to replink send -l python -t zellij:p=right"Now you can select code and press <minus>x to send it to your Python REPL. (I use minus/dash (-) as my leader for custom keybindings.)
Pro tip: If you're building Helix from master, you can specify the language dynamically by passing it in as a command line expansion. For example:
[keys.normal."minus"]
# TMUX
"x" = ":pipe-to replink send -l %{language} -t tmux:p=right"
# Zellij
"x" = ":pipe-to replink send -l %{language} -t zellij:p=right"I'm not sure why you would use replink in Vim, where better options exist. But here's what Claude has to say!
" Send current line
nnoremap <leader>x :.!replink send -l python -t tmux:p=right<CR>
" Send visual selection
vnoremap <leader>x :!replink send -l python -t tmux:p=right<CR>Create a task in .vscode/tasks.json:
{
"version": "2.0.0",
"tasks": [
{
"label": "Send to REPL",
"type": "shell",
"command": "replink",
"args": ["send", "-l", "python", "-t", "tmux:p=right", "${selectedText}"]
}
]
}Adding languages means implementing the Language_P protocol in replink/languages/. You handle the formatting quirks and REPL-specific behavior for your language.
Adding targets means implementing the Target_P protocol in replink/targets/. You handle the mechanics of getting text to wherever the REPL is running.
Right now there's just Python and tmux/zellij, but the design should make it straightforward to add JavaScript/Node, Ruby, R, or whatever. Same for targets like GNU Screen or terminal emulators with their own APIs.
PRs welcome, especially for new languages and targets. The architecture should make this pretty straightforward.
Heavily inspired by vim-slime, which figured out all the hard parts years ago. (I've copied from this project liberally and have opted for the same license.) Also looked at iron.nvim for ideas.
Licensed under the MIT License. See LICENSE.txt for details.

