[RFC] Inject distant support into neovim lua functions #119
Replies: 3 comments
-
nvimlsp-config supportFor this plugin, I'm taking a quick look at all references to io
vim.fn
vim.loop
vim.lsp
There's a bunch of others for For |
Beta Was this translation helpful? Give feedback.
-
nvim-dap supportFor this plugin, I'm taking a quick look at all references to io
vim.fn
vim.loop
For In terms of gotchas, the |
Beta Was this translation helpful? Give feedback.
-
From the two examples above, this is clearly quite complex and I don't think the automatic injection will be feasible unless we do something like one of these options:
|
Beta Was this translation helpful? Give feedback.
-
I'd given this thought before and dismissed the idea, but I want to bring it back into the backlog with a refresh look. The idea is to support injecting custom replacement functions into
vim.loop
,vim.fs
, andvim.fn
(and maybe others?) where methods that would perform IO or spawn processes get changed to ones that can work remotely.How would it work?
For each function we want to wrap, we write some custom function that takes in the same arguments and returns a structure that maps to whatever the function would normally return.
The trick is to detect whether we're working remotely or locally. We can already check if there is an active client, but that still wouldn't solve the situation of mixing local and remote commands together. The next thought is to check the buffer to see if it is remote or not. If we're in a non-remote buffer (e.g.
plugin.buf.has_data() == false
), fall back to the default implementation. Otherwise, use our custom one for distant.The caveat would be for plugins that create their own buffers, which obviously would not have remote data. The only thought I have there is to also overwrite methods like
vim.api.nvim_buf_create
so we can automatically set the client id viaplugin.buf.set_client_id(...)
. Not sure how well this would work.We'd obviously want to make this opt-in as it would break many people's setups. And another option to provide alongside would be a temporary conversion via something like
plugin.inject(function() end)
where everything is injected, the function is called, and then everything is reset.Rolling release of feature
It would take a LOT of work to map every function before releasing this. The thought is to handle some of the ones below, and override the
__index
ofloop
and other metatables to check what is being accessed. If we want__index
to work, we'd need to remove all of the other fields of the table to make sure it always goes through__index
since it is only triggered when a field is absent.In the case that we can get
__index
to work as a proxy, we can check what is being accessed AND if we are going to try to use the distant API. If we know we need to invoke the distant API and the accessed method is not supported, we can error out.Processes
vim.fn.system({cmd} [, {input}])
system()
of vim. You feed it a command as either a string or list of strings, and it returns a a string.<CR><NL>
is replaced with<NL>
NUL
characters are replaced withSOH
(0x01)v:shell_error
Seems straightforward to support by doing a
plugin.api.wrap
and then invoking this.Job Control
vim.fn.jobstart({cmd} [, {opts}])
cwd
,env
,pty
/width
/height
detach
- we would remember if this is false and, if neovim is exiting, trigger a kill commandoverlapped
- ignore thisrpc
- error out if this is trueCan support this by doing
plugin.api.wrap
and then invoking this. We need to capture some of the options to add to our wrap likecwd
,env
,pty
/width
/height
. For the others, I think we can leave as-is.The other job control methods related to this should all work as expected because neovim just thinks we're running a normal process.
File System
vim.loop.new_fs_event()
uv_fs_event_t
handle for watching some path.change
andrename
as the possibilities.watch_entry
- ???stat
- ???recursive
- I'm assuming to watch directory changes, but don't knowWe should be able to map this to our
plugin.api.watch
API, and map our changes to those they offer. I'm not sure what the flags do, so would need to figure that out. The other watch methods likefs_event_stop()
should work fine if we return an equivalent object.vim.loop.fs_stat(path, [callback])
atime
,mtime
,ctime
we can get parse from the unix time of metadata'saccessed
,modified
,created
type
we can get from thefile_type
of metadatasize
we can get from thelen
of metadatamode
we can get fromunix
if set and convert back into the bits for the number AND set the bit for the directory100000 111 101 101
and has a directory bit setbirthtime
is unsupported (don't know what this is and how it's different)blksize
andblock
are unsupporteddev
,flags
,gen
,gid
,ino
,nlink
,rdev
,uid
are supportedShould correspond to our
plugin.api.metadata
method withresolve_file_type
as true. There is also fs_fstat and fs_lstat. Forfs_lstat
, we would haveresolve_file_type
as false.From https://stackoverflow.com/a/37268695:
For the file descriptor, we should be able to keep track of those from calls to
fs_open
, which returns a file descriptor.vim.loop.fs_realpath(path, [callback])
path
of symbolic links, extra slashes, and relative references. Will also error out if part of the path is missing.Should be able to use
plugin.api.metadata
withcanonicalize
set to true. I can't remember if distant will give an error if canonicalization fails. If it falls back to a default, we may need to add a flag to support reporting an error, or change the behavior.System Information
There's a lot of these, all with the
os_
prefix. I'm going to take a stab at listing a couple, but many of the others beyond these won't have easy support unless we try to retrieve the information using some spawned process trickery.vim.loop.os_uname()
machine
: corresponds to ourarch
from system_infouname -m
release
: has nothing equivalent right now from system_infouname -r
sysname
: is ouroperating system
from system_infouname -s
os_uname()
reports "Darwin" whereas we report "macos"version
: has nothing equivalentuname -v
This is used in
nvimlsp-config
, so we need to support it. We could potentially spawn fouruname
processes that map to the above, but not sure what this executes on Windows.vim.loop.os_gethostname()
hostname
on Unix systems and Windows.Could potentially just farm this out to a spawned process, unless we update system information to include the hostname.
vim.loop.os_getenv(name, [size])
We don't actually have a way to retrieve environment variables with distant unless you farm it out to a process. Maybe system information could do this?
Miscellaneous
vim.loop.cwd()
Should be able to use
plugin.api.system_info
to get the current working directory of the server. If we have a custom cwd specified from our settings, we would return that instead.Beta Was this translation helpful? Give feedback.
All reactions