#!/usr/bin/python3 import neovim, os, re, sys, time # Get a list of buffers that haven't been deleted. `nvim.buffers` includes # buffers that have had `:bdelete` called on them and aren't in the buffer # list, so we have to filter those out. def get_listed_buffers(nvim): return set(buf.number for buf in nvim.buffers \ if nvim.eval('buflisted(%d)' % buf.number)) # Many terminals now support undercurl, but Neovim still looks for xterm-kitty # to enable it. if os.environ["TERM"] in ["alactritty", "xterm-256color"]: os.environ["TERM"] = "xterm-kitty" # For now, treat all arguments that don't start with - or + as filenames. This # is good enough to recognize '-f' and `+11`, which is all this script really # needs right now. filenames = [ os.path.abspath(arg) for arg in sys.argv[1:] if not arg[0] in ['-', '+'] ] try: nvim_socket = os.environ["NVIM"] except KeyError: # If we aren't running inside a `:terminal`, just exec nvim. os.execvp(u'nvim', list(filter(lambda a: a != "--float", sys.argv))) nvim = neovim.attach('socket', path=nvim_socket) existing_buffers = get_listed_buffers(nvim) if '--float' in sys.argv: float_title = filenames[0] if len(filenames) > 0 else "" nvim.command('call nvim_open_win(0, 1, {' + "'relative': 'editor'," + "'width': 90," + "'height': 40," + "'col': (nvim_list_uis()[0].width / 2) - (90 / 2)," + "'row': (nvim_list_uis()[0].height / 2) - (40 / 2)," + "'anchor': 'NW'," + "'style': 'minimal'," + "'border': 'single'," + "'title': [['" + float_title + "', 'Statement']]" + "})") nvim.command("set winhighlight=Normal:Normal") else: nvim.command('split') nvim.command('args %s' % ' '.join(filenames)) new_buffers = get_listed_buffers(nvim).difference(existing_buffers) for arg in sys.argv: if arg[0] == '+': nvim.command(arg[1:]) # The '-f' flag is a signal that we're in a situation like a `git commit` # invocation where we need to block until the user is done with the file(s). if '-f' in sys.argv and len(new_buffers) > 0: # The rule here is that the user is 'done' with the opened files when none # of them are visible onscreen. This allows for use cases like hitting `:q` # on a `git commit` tempfile. However, we can't just poll to see if they're # visible, because using `nvim.windows`, `nvim.eval()`, or `nvim.call()` # will interrupt any multi-key mappings the user may be inputting. The # solution is to set a buffer-local autocmd on each opened buffer so that # we only check for visibility immediately after the user either closes or # hides one of the buffers. channel_id = nvim.channel_id for buffer in new_buffers: nvim.command( ('autocmd BufDelete,BufHidden,QuitPre ' + 'call rpcnotify(%d, "check_buffers")') % (buffer, channel_id)) stay_open = True while stay_open: nvim.next_message() # block until `rpcnotify` is called open_buffers = [window.buffer.number for window in nvim.windows] stay_open = any([buffer in open_buffers for buffer in new_buffers]) # Now that none of the opened files are visible anymore, we do a few # cleanup steps before ending the script: # * Clear the arg list, since otherwise `:next` would reopen the tempfile # or whatever. # * Clear the autocmds we added, since `bdelete` just hides the buffer and # the autocmds will still be active if the user reopens the file(s). # * Delete each of the buffers we created. nvim.command('argdel *') for buffer in new_buffers: nvim.command('autocmd! BufDelete,BufHidden,QuitPre ' % buffer) nvim.command('bdelete! %d' % buffer)