Buffers
For buffers managed by distant, the plugin interface exposes a buf
field that
enables you to access and manipulate distant-specific information tied to a
buffer as well as search for specific remote buffers.
Buffer interface
By default, if you access the buf
field, all data operations will apply to
the current buffer:
-- Will retrieve distant-specific data for the current buffer
plugin.buf.get_data()
If you want to access or manipulate data for a specific buffer, you can instead
invoke buf
as a function, providing the buffer's id as the argument:
-- Will retrieve distant-specific data for buffer whose number is 123
plugin.buf(123).get_data()
Data API
The primary API exposed by the buffer interface is retrieving and manipulating
distant-specific information. All of the information is stored in the
buffer-local variable distant
, which you can access within neovim through the
scoped variable b:distant
.
The buffer interface exposes methods to simplify accessing and manipulating specific portions or the entire data stored in the buffer.
Data table
If you directly access the data stored in b:distant
, you will find a table
comprised of the following fields, not all of which may be present:
Field | Description |
---|---|
client_id | Numeric id of the connection associated with the buffer |
path | Path on the remote machine (no scheme) |
alt_paths | Alternative paths, usually relative, that also map to the primary path |
type | Indicates the path type (dir or file ) |
mtime | Numeric UNIX timestamp (in seconds) representing last modified time remotely |
watched | Watched state, which can be false , true , or "locked" |
Retrieving data
You can retrieve the data as a Lua table using data
like below:
-- This can be a Lua table or nil if b:distant is not present
local data = plugin.buf.data()
If you want to check for the presence of data before accessing it, you can use
the has_data
function:
if plugin.buf.has_data() then
-- Do something if the buffer has data.
-- You can use this to assert that a buffer is remote!
end
Modifying data
If you want to modify the data as a whole, there are two means to do this:
- Call
set_data(data)
, passing it a new table to use. Be careful with this method, is it is easy to corrupt the state of a buffer. Prefer more specific methods instead. - Call
mutate_data(fn)
, which takes a function to modify and return a table to be used as the new data.
-- Set distant data directly
-- Will return true if successful
plugin.buf.set_data({ client_id = 123, path = '/path/to/file.txt' })
-- Mutate distant data
-- Will return true if successful
plugin.buf.mutate_data(function(data)
data.path = '/path/to/file.txt'
return data
end)
Lastly, if you want to remove all remote information from a buffer, you can
call clear
; however, this is discouraged unless you REALLY know what you are
doing:
-- Will return true if successful
plugin.buf.clear()
Client id
If you need to work with the client id (aka connection) associated with the buffer, there are two methods:
set_client_id(id)
is used to update the client id of the bufferclient_id()
is used to retrieve the client id of the buffer
local id = plugin.buf.client_id()
-- Will return true if successful
plugin.buf.set_client_id(123)
Path
Representing the primary remote path associated with the buffer, this is
populated when a file or directory is first opened. The path
should be the
canonicalized path provided by the server, meaning that any symlinks or
relative components are resolved.
set_path(path)
is used to update the buffer's pathpath()
is used to retrieve the buffer's path
local path = plugin.buf.path()
-- Will return true if successful
plugin.buf.set_path('/path/to/file.txt')
Alternate paths
Representing the alternative remote path associated with the buffer, this is a
list of strings representing other paths that evaluate to the path
when they
are canonicalized. This list is updated whenever a request to open a path is
provided that resolves to an existing buffer's path. For instance, if .
resolves to /path/to/file.txt
and you then open /path/to/./file.txt
, the
alternative paths should include both .
and /path/to/./file.txt
.
set_alt_paths(paths)
is used to update the buffer's alternate pathsadd_alt_path(path, opts)
is used to append the path to the buffer's alternate paths. Opts is an optional table, where specifyingdedup = true
will result in the alternate paths being deduplicated.alt_paths()
is used to retrieve the buffer's alternate paths
-- List of paths: { '.', '/path/to/./file.txt' }
local paths = plugin.buf.alt_paths()
-- Append a path to our list
plugin.buf.add_alt_path('./file.txt')
-- Append a path to our list and deduplicate the list
plugin.buf.add_alt_path('./file.txt', { dedup = true })
-- Will return true if successful
plugin.buf.set_alt_paths({ '.', '/path/to/./file.txt' })
Type
Representing the file type of the remote path associated with the buffer, this is populated when a file or directory is first opened.
set_type(ty)
is used to update the buffer's typetype()
is used to retrieve the buffer's type
-- Could be 'dir' or 'file'
local ty = plugin.buf.type()
-- Will return true if successful
plugin.buf.set_type('dir')
Modification time
Representing the last time (in seconds as Unix timestamp) the remote path associated with the buffer was modified. This is populated when a file or directory is first opened, and is updated whenever the file is reopened, written to locally, or a watch event is received for this buffer's path.
set_mtime(mtime)
is used to update the buffer's modification timemtime()
is used to retrieve the buffer's modification time
local mtime = plugin.buf.mtime()
-- Will return true if successful
plugin.buf.set_mtime(1234)
Watched
Representing the watch status of the remote path associated with the buffer. This is populated when a file or directory is first opened, and is updated whenever during the process of watching a file and once a file is successfully being watched.
set_watched(watched)
is used to update the buffer's watch statuswatched()
is used to retrieve the buffer's watch status
-- Could be false (not watched), true (actively watching), or "locked" meaning
-- that the file is in the process of being watched or avoiding triggering
-- watch events (such as when writing the file from neovim)
local watched = plugin.buf.watched()
-- Will return true if successful
plugin.buf.set_watched(true)
Name API
Another feature available through the buffer interface is working with buffer
names. In order for distant to operate on multiple connections, it uses a
distinct name format that encodes both a scheme (distant
) and a client id
(aka connection). There are two supported ways that this name can be
represented:
modern
-[{SCHEME}[+{CONNECTION}]://PATH
(e.g.distant+1234://some/file.txt
)legacy
-[{SCHEME}://[{CONNECTION}://]PATH
(e.g.distant://1234://some/file.txt
)
Note
As of today, neovim will always use the legacy
format. If
neovim/23834 gets
implemented, we can detect the neovim version and use the modern format;
otherwise, we will be stuck with "legacy" forever.
All name API methods are accessible from the name
table:
plugin.buf.name.parse('...')
Default format
Returns the default format used for parsing and building a buffer's name. Until
neovim/23834 is merged, this
will return legacy
:
local format = plugin.buf.name.default_format()
assert(format == 'legacy')
Prefix
Returns the prefix tied to the buffer's name, a provided name, or builds a prefix from the given components. The function accepts an optional table to dictate what to parse or use to construct the prefix.
Parsing from an explicit name
If you provide name
, it will be parsed for the prefix:
-- You can supply an optional `format` field to override the prefix format
-- such as `format = 'legacy'`
local prefix = plugin.buf.name.prefix({ name = 'distant://1234//some/file.txt' })
assert(prefix == 'distant://1234')
Parsing from the buffer's name
If you provide no name
or scheme
, the buffer's name will be retrieved and
parsed for the prefix:
-- You can supply an optional table to override the prefix format
-- using { format = 'legacy' }
local prefix = plugin.buf.name.prefix()
-- Assuming the buffer's name was something like distant://1234://some/file.txt
assert(prefix == 'distant://1234')
Building from components
If you provide a scheme
and an optional connection
, it will be used to
build a prefix:
-- You can supply an optional `format` field to override the prefix format
-- such as `format = 'legacy'`
local prefix = plugin.buf.name.prefix({ scheme = 'distant', connection = 1234 })
assert(prefix == 'distant://1234')
Building a name
The build
function is provided to construct a complete buffer name. The
function takes a single table as an argument, which is comprised of these
fields:
path
: (required) the path to the file or directory.scheme
: (optional) the scheme to use. Ideally, this isdistant
. If you do not supply a scheme, the name created will resemble a local buffer.connection
: (optional) the id of the specific connection tied to the buffer. If you do not supply one, it will not be included, which means that the buffer would be represented by the active connection. In most cases, you will want to provide the connection's id to ensure the buffer doesn't switch to a different remote machine.format
: (optional) the format to use when constructing the name. If not supplied, this will leveragedefault_format()
.
local name = plugin.buf.name.build({
path = 'some/file.txt',
scheme = 'distant',
connection = 1234,
format = 'legacy',
})
assert(name == 'distant://1234://some/file.txt')
Parsing a name
The parse
function is provided to parse a buffer's name into its components.
The function takes an optional table as an argument, which is comprised of
these fields:
name
: (optional) the buffer name to parse. If not provided, will parse the buffer's name.format
: (optional) the format to use when parsing the name. If not supplied, this will leveragedefault_format()
.
The returned value is a table that contains one or more of these fields:
path
: the path represented by the buffer. This will always be populated.connection
: the numeric id of the connection. Will only appear if contained in the parsed name.scheme
: the scheme associated with the buffer. Will only appear if contained in the parsed name.
-- Parses the current buffer's name with the default format
local pieces = plugin.buf.name.parse()
-- Parses the specific buffer's name with the default format
local pieces = plugin.buf(123).name.parse()
-- Parses the specific name with the default format
local pieces = plugin.buf.name.parse({ name = 'distant://1234://some/file.txt' })
assert(pieces.path == 'some/file.txt')
assert(pieces.connection == 1234)
assert(pieces.scheme == 'distant')
Search API
Alongside the other APIs, the buffer interface also exposes a simplified experience in locating buffers by their paths. Specifically, there are three methods available:
-
has_matching_path(path, opts)
: checks if the buffer has a matching path within itspath
oralt_paths
data. The opts table is optional and can contain aconnection
field to require that the buffer not only has the specifiedpath
but also is the same connection. -
find(opts)
: searches through all buffers for one that that meets the specified conditions. If a match is found, a buffer interface is returned for the matched buffer:opts.path
: looks for a buffer with the specified path either as itspath
or within itsalt_paths
.opts.connection
: if provided, will limit the search to only buffers with the specified connection id.opts.format
: format of buffer names to search. If not provided, usesname.default_format()
.
-
find_bufnr(opts)
: same asfind(opts)
, but returns the number of the buffer instead of the buffer interface.
-- Check if the current buffer is pointing to the specified path for the
-- specific connection
if plugin.buf.has_matching_path('some/file.txt', { connection = 1234 }) then
-- Do something
end
-- Search for a buffer, returning nil if nothing found
-- The returned buffer has the same buffer interface
local buffer = plugin.buf.find({ path = '.', connection = 1234 })
if buffer then
-- Print out the buffer's number
print(buffer.bufnr())
-- Print out the true path of the buffer
print(buffer.path())
end
-- Retrieves the id of the buffer above, returning nil if not found
local bufnr = plugin.buf.find_bufnr({ path = '.', connection = 1234 })