bd7bc4d9fc
A buffer managed by nvr sets the b:nvr variable. It contains the channel IDs of all connected nvr clients. nvr clients understand two RPC messages, BufDelete and Exit. The latter always required the exit code as argument and the former optionally takes one as well now. let exitcode = 1 for chan in b:nvr call rpcnotify(chan, 'BufDelete', exitcode) endfor Closes #89 |
6 years ago | |
---|---|---|
images | 7 years ago | |
nvr | 6 years ago | |
tests | 6 years ago | |
.gitignore | 8 years ago | |
.travis.yml | 6 years ago | |
INSTALLATION.md | 6 years ago | |
LICENSE | 9 years ago | |
Makefile | 6 years ago | |
README.md | 6 years ago | |
setup.py | 6 years ago |
README.md
neovim-remote
This package provides an executable called nvr which solves these cases:
- Controlling nvim processes from the shell. E.g. opening files in another terminal window.
- Opening files from within
:terminal
without starting a nested nvim process.
Installation
pip3 install neovim-remote
If you encounter any issues, e.g. permission denied errors or you can't find the
nvr
executable, read INSTALLATION.md.
Theory
Nvim always starts a server. Get its address via :echo $NVIM_LISTEN_ADDRESS
or
:echo v:servername
. Or specify an address at startup:
NVIM_LISTEN_ADDRESS=/tmp/nvimsocket nvim
.
nvr will use $NVIM_LISTEN_ADDRESS
or any address given to it via
--servername
.
If the targeted address does not exist, nvr starts a new process by running
"nvim". You can change the command by setting $NVR_CMD
. (This requires
forking, so it won't work on Windows.)
First steps
Start a nvim process (which acts as a server) in one shell:
NVIM_LISTEN_ADDRESS=/tmp/nvimsocket nvim
And do this in another shell:
# nvr uses /tmp/nvimsocket by default, so we're good.
# Open two files:
nvr --remote file1 file2
# Send keys to the current buffer:
nvr --remote-send 'iabc<esc>'
# Enter insert mode, insert 'abc', and go back to normal mode again.
# Evaluate any VimL expression, e.g. get the current buffer:
nvr --remote-expr 'bufname("")'
README.md
click here to see all nvr options
$ nvr -h
usage: nvr [arguments]
Remote control Neovim processes.
If no process is found, a new one will be started.
$ nvr --remote-send 'iabc<cr><esc>'
$ nvr --remote-expr 'map([1,2,3], "v:val + 1")'
Any arguments not consumed by options will be fed to --remote-silent:
$ nvr --remote-silent file1 file2
$ nvr file1 file2
All --remote options take optional commands.
Exception: --remote-expr, --remote-send.
$ nvr +10 file
$ nvr +'echomsg "foo" | echomsg "bar"' file
$ nvr --remote-tab-wait +'set bufhidden=delete' file
Open files in a new window from a terminal buffer:
$ nvr -cc split file1 file2
Use nvr from git to edit commit messages:
$ git config --global core.editor 'nvr --remote-wait-silent'
optional arguments:
-h, --help show this help message and exit
--remote [<file> [<file> ...]]
Use :edit to open files. If no process is found, throw
an error and start a new one.
--remote-wait [<file> [<file> ...]]
Like --remote, but block until all buffers opened by
this option get deleted or the process exits.
--remote-silent [<file> [<file> ...]]
Like --remote, but throw no error if no process is
found.
--remote-wait-silent [<file> [<file> ...]]
Combines --remote-wait and --remote-silent.
--remote-tab [<file> [<file> ...]]
Like --remote, but use :tabedit.
--remote-tab-wait [<file> [<file> ...]]
Like --remote-wait, but use :tabedit.
--remote-tab-silent [<file> [<file> ...]]
Like --remote-silent, but use :tabedit.
--remote-tab-wait-silent [<file> [<file> ...]]
Like --remote-wait-silent, but use :tabedit.
--remote-send <keys> Send key presses.
--remote-expr <expr> Evaluate expression and print result in shell.
--servername <addr> Set the address to be used. This overrides the default
"/tmp/nvimsocket" and $NVIM_LISTEN_ADDRESS.
--serverlist Print the TCPv4 and Unix domain socket addresses of
all nvim processes.
-cc <cmd> Execute a command before every other option.
-c <cmd> Execute a command after every other option.
-d Diff mode. Use :diffthis on all to be opened buffers.
-l Change to previous window via ":wincmd p".
-o <file> [<file> ...]
Open files via ":split".
-O <file> [<file> ...]
Open files via ":vsplit".
-p <file> [<file> ...]
Open files via ":tabedit".
-q <errorfile> Read errorfile into quickfix list and display first
error.
-s Silence "no server found" message.
-t <tag> Jump to file and position of given tag.
--nostart If no process is found, do not start a new one.
--version Show the nvr version.
Development: https://github.com/mhinz/neovim-remote
Happy hacking!
Typical use cases
-
Use nvr as git mergetool.
If you want to use nvr for
git difftool
andgit mergetool
, put this in your gitconfig:[diff] tool = nvr [difftool "nvr"] cmd = nvr -s -d $LOCAL $REMOTE [merge] tool = nvr [mergetool "nvr"] cmd = nvr -s -d $LOCAL $BASE $REMOTE $MERGED -c 'wincmd J | wincmd ='
nvr -d
is a shortcut fornvr -d -O
and acts likevim -d
, thus it uses:vsplit
to open the buffers. If you want them to be opened via:split
instead, usenvr -d -o
.When used as mergetool and all four buffers got opened, the cursor is in the window containing the $MERGED buffer. We move it to the bottom via
:wincmd J
and then equalize the size of all windows via:wincmd =
. -
Open files from within
:terminal
without starting a nested nvim.Easy-peasy! Just
nvr file
.This works without any prior setup, because
$NVIM_LISTEN_ADDRESS
is always set within Nvim. Andnvr
will default to that address.I often work with two windows next to each other. If one contains the terminal, I can use
nvr -l foo
to open the file in the other window. -
Open files always in the same nvim no matter which terminal you're in.
If you just run
nvr -s
, a new nvim process will start and set its address to/tmp/nvimsocket
automatically.Now, no matter in which terminal you are,
nvr file
will always work on that nvim process. That is akin toemacsclient
from Emacs. -
Use nvr as temporary editor.
Imagine Neovim is set as your default editor:
VISUAL=nvim
.Now run
git commit
. In a regular shell, a new nvim process starts. That's exactly what you want.But in a terminal buffer (
:terminal
), a new nvim process starts as well. Now you have one nvim nested within another. You don't want that. Put this in your vimrc:if has('nvim') let $VISUAL = 'nvr -cc split --remote-wait' endif
That way, you get a new window for entering the commit message instead of a nested nvim process.
Alternatively, you can make git always using nvr. In a regular shell, nvr will create a new nvim process. In a terminal buffer, nvr will open a new buffer.
$ git config --global core.editor 'nvr --remote-wait-silent'
-
Use nvr in plugins.
Some plugins rely on the
--remote
family of options from Vim. Nvim had to remove those when they switched to outsource a lot of manual code to libuv. These options are planned to be added back, though.In these cases nvr can be used as a drop-in replacement. E.g. vimtex can be configured to use nvr to jump to a certain file and line: read.
Demos
(Click on the GIFs to watch them full-size.)
Using nvr from within :terminal
:
FAQ
-
How to open directories?
:e /tmp
opens a directory view via netrw. Netrw works by hooking into certain events,BufEnter
in this case (see:au FileExplorer
for all of them).Unfortunately Neovim's API doesn't trigger any autocmds on its own, so simply
nvr /tmp
won't work. Meanwhile you can work around it like this:$ nvr /tmp -c 'doautocmd BufEnter'
-
Reading from stdin?
Yes! E.g.
echo "foo\nbar" | nvr -o -
andcat file | nvr --remote -
work just as you would expect them to work. -
Exit code?
If you use a recent enough Neovim, nvr will use the same exit code as the linked nvim.
E.g.
nvr --remote-wait <file>
and then:cquit
in the linked nvim will make nvr return with 1. -
How to send a message to all waiting clients?
If you open a buffer with any of the wait options, that buffer will get a variable
b:nvr
. The variable contains a list of channels wheres each channel is a waiting nvr client.Currently nvr only understands the
Exit
message. You could use it to disconnect all waiting nvr clients at once:command! DisconnectClients \ if exists('b:nvr') \| for client in b:nvr \| silent! call rpcnotify(client, 'Exit', 1) \| endfor \| endif