Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,13 @@ require("remote-nvim").setup({
additional_opts = { "--exclude-vcs" }, -- Any arguments that can be passed to `tar` for compression can be specified here to improve your compression
},
},
-- dot_config = {
-- base = vim.fn.stdpath("config").."/../", -- Assumed config directory
-- dirs = {},
-- compression = {
-- enabled = true,
-- },
-- },
-- cache = {
-- base = vim.fn.stdpath("cache"),
-- dirs = {},
Expand All @@ -553,6 +560,8 @@ require("remote-nvim").setup({
The above configuration indicates that the `lazy` directory inside your Neovim `data` directory should be copied over
onto the remote in it's `data` directory. You can similarly specify what should be copied inside the `data`, `state`,
`cache` or `config` directory on remote.
`dot_config` is an alias for `.config` and directories specified in `dot_config.dirs` will be acessible in
remote workspace. Useful when neovim calls external tools since remote neovim is launched with modified `XDG_CONFIG_HOME`.

If specified directories are going to contain a lot of data, it's _highly recommended_ to enable compression when
uploading by setting `compression.enabled` to `true` for those particular uploads.
Expand All @@ -564,8 +573,7 @@ uploading by setting `compression.enabled` to `true` for those particular upload
and prevent orphan Neovim servers.
- The current implementation launches a headless server on the remote machine and then launches a TUI to connect
to it. This means that if you quit the TUI using regular operations, the server also gets closed. If you just want
to close the TUI, that is currently not possible. You can read more in [this Neovim
discussion](https://github.com/neovim/neovim/issues/23093).
to close the TUI, use :detach command.
- Neovim versions `< v0.9.2` are incompatible with versions `>= v0.9.2` due to a breaking UI change introduced in
`v0.9.2`. For more information, read the [release notes for
v0.9.2](https://github.com/neovim/neovim/releases/tag/v0.9.2).
Expand All @@ -581,7 +589,7 @@ This plugins provide some additional nice-to have features on top:
- Can copy over your local Neovim configuration to remote
- Allows easy re-connection to past sessions
- Makes it easy to clean up remote machine changes once you are done
- It launches Neovim server on the remote server and connects a UI to it locally.
- It launches Neovim server on the remote server and connects a UI to it locally.

You can read more in [this Neovim discussion](https://github.com/amitds1997/remote-nvim.nvim/discussions/145)

Expand Down
140 changes: 123 additions & 17 deletions lua/remote-nvim/command.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@ function M.RemoteStart(opts)
else
---@type remote-nvim.providers.WorkspaceConfig
local workspace_config =
remote_nvim.session_provider:get_config_provider():get_workspace_config(vim.trim(host_identifier))
remote_nvim.session_provider:get_config_provider():get_workspace_config(vim.trim(host_identifier))
if vim.tbl_isempty(workspace_config) then
vim.notify("Unknown host identifier. Run :RemoteStart to connect to a new host", vim.log.levels.ERROR)
else
remote_nvim.session_provider
:get_or_initialize_session({
host = workspace_config.host,
provider_type = workspace_config.provider,
conn_opts = { workspace_config.connection_options },
unique_host_id = host_identifier,
devpod_opts = devpod_utils.get_workspace_devpod_opts(workspace_config),
})
:launch_neovim()
:get_or_initialize_session({
host = workspace_config.host,
provider_type = workspace_config.provider,
conn_opts = { workspace_config.connection_options },
unique_host_id = host_identifier,
devpod_opts = devpod_utils.get_workspace_devpod_opts(workspace_config),
})
:launch_neovim()
end
end
end
Expand All @@ -42,6 +42,112 @@ vim.api.nvim_create_user_command("RemoteStart", M.RemoteStart, {
end,
})

function M.RemoteSync(opts)
local host_identifier = vim.trim(opts.args)
if host_identifier == "" then
require("telescope").extensions["remote-nvim"].connect({ session_action = "sync" })
else
---@type remote-nvim.providers.WorkspaceConfig
local workspace_config =
remote_nvim.session_provider:get_config_provider():get_workspace_config(vim.trim(host_identifier))
if vim.tbl_isempty(workspace_config) then
vim.notify("Unknown host identifier. Run :RemoteStart or :RemoteSync to setup new host", vim.log.levels.ERROR)
else
remote_nvim.session_provider
:get_or_initialize_session({
host = workspace_config.host,
provider_type = workspace_config.provider,
conn_opts = { workspace_config.connection_options },
unique_host_id = host_identifier,
devpod_opts = devpod_utils.get_workspace_devpod_opts(workspace_config),
})
:sync()
end
end
end

vim.api.nvim_create_user_command("RemoteShow", function()
require("remote-nvim.ui.dashboard"):show()
end, { desc = "Show Remote Status", })

vim.api.nvim_create_user_command("RemoteSync", M.RemoteSync, {
nargs = "?",
desc = "Sync Neovim config with the remote machine",
complete = function(_, line)
local args = vim.split(vim.trim(line), "%s+")
table.remove(args, 1)
local hosts = remote_nvim.session_provider:get_config_provider():get_workspace_config()
local valid_hosts = {}
for k, v in pairs(hosts) do
if v.provider == "ssh" then
table.insert(valid_hosts, k)
end
end
if #args == 0 then
return valid_hosts
end
return vim.fn.matchfuzzy(valid_hosts, args[1])
end,
})

function M.RemoteSpawn(opts)
local host_identifier = vim.trim(opts.args)
if host_identifier == "" then
require("telescope").extensions["remote-nvim"].connect({ session_action = "spawn" })
else
---@type remote-nvim.providers.WorkspaceConfig
local workspace_config =
remote_nvim.session_provider:get_config_provider():get_workspace_config(vim.trim(host_identifier))
if vim.tbl_isempty(workspace_config) then
vim.notify("Unknown host identifier. Run :RemoteStart or :RemoteSync to setup new host", vim.log.levels.ERROR)
else
remote_nvim.session_provider
:get_or_initialize_session({
host = workspace_config.host,
provider_type = workspace_config.provider,
conn_opts = { workspace_config.connection_options },
unique_host_id = host_identifier,
devpod_opts = devpod_utils.get_workspace_devpod_opts(workspace_config),
})
:spawn()
end
end
end

vim.api.nvim_create_user_command("RemoteSpawn", M.RemoteSpawn, {
nargs = "?",
desc = "Spawn Neovim server on ssh and create local forwarding",
complete = function(_, line)
local args = vim.split(vim.trim(line), "%s+")
table.remove(args, 1)
local hosts = remote_nvim.session_provider:get_config_provider():get_workspace_config()
local valid_hosts = {}
for k, v in pairs(hosts) do
if v.provider == "ssh" then
table.insert(valid_hosts, k)
end
end
if #args == 0 then
return valid_hosts
end
return vim.fn.matchfuzzy(valid_hosts, args[1])
end,
})

vim.api.nvim_create_user_command("RemoteKillAll", function()
local ssh_executor = require("remote-nvim.providers.ssh.ssh_executor")()
local ssh_connections = require("remote-nvim.providers.ssh.ssh_connections")({ executor = ssh_executor })
local connections = ssh_connections:update_connections()
local connection_ids = {}
for id, _ in pairs(connections) do
table.insert(connection_ids, id)
end
ssh_connections:close_connections(connection_ids)
end, {
nargs = 0,
desc = "Kill all spawned sessions",
})

function M.RemoteLog()
vim.api.nvim_cmd({
cmd = "tabnew",
Expand All @@ -66,14 +172,14 @@ function M.RemoteCleanup(opts)
vim.notify("Unknown host identifier. Run :RemoteStart to connect to a new host", vim.log.levels.ERROR)
else
remote_nvim.session_provider
:get_or_initialize_session({
host = workspace_config.host,
provider_type = workspace_config.provider,
conn_opts = { workspace_config.connection_options },
unique_host_id = host_id,
devpod_opts = devpod_utils.get_workspace_devpod_opts(workspace_config),
})
:clean_up_remote_host()
:get_or_initialize_session({
host = workspace_config.host,
provider_type = workspace_config.provider,
conn_opts = { workspace_config.connection_options },
unique_host_id = host_id,
devpod_opts = devpod_utils.get_workspace_devpod_opts(workspace_config),
})
:clean_up_remote_host()
end
end
end
Expand Down
22 changes: 21 additions & 1 deletion lua/remote-nvim/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
---@field config remote-nvim.config.PluginConfig Plugin configuration
---@field session_provider remote-nvim.providers.SessionProvider Session provider for each unique host
---@field setup fun(opts: remote-nvim.config.PluginConfig) Setup the plugin
---@field dashboard remove-nvim.ui.Dashboard
local M = {}

local constants = require("remote-nvim.constants")
Expand Down Expand Up @@ -68,6 +69,7 @@ local utils = require("remote-nvim.utils")

---@class remote-nvim.config.PluginConfig.Remote.CopyDirs
---@field config remote-nvim.config.PluginConfig.Remote.CopyDirs.FolderStructure Directory to copy over into remote XDG_CONFIG_HOME/nvim. Default is output of :lua= vim.fn.stdpath("config"). Default `base` when not specified is vim.fn.stdpath("config").
---@field dot_config remote-nvim.config.PluginConfig.Remote.CopyDirs.FolderStructure Directory to copy over into remote XDG_CONFIG_HOME. Default is nothing. If base is not specified, it is assumed to be :lua= vim.fn.stdpath("config").."/.."
---@field data remote-nvim.config.PluginConfig.Remote.CopyDirs.FolderStructure Directory to copy over into remote XDG_DATA_HOME/nvim. Default is nothing. If base is not specified, it is assumed to be :lua= vim.fn.stdpath("data")
---@field state remote-nvim.config.PluginConfig.Remote.CopyDirs.FolderStructure Directory to copy over into remote XDG_STATE_HOME/nvim. Default is nothing. If base is not specified, it is assumed to be :lua= vim.fn.stdpath("state")
---@field cache remote-nvim.config.PluginConfig.Remote.CopyDirs.FolderStructure Directory to copy over into remote XDG_CACHE_HOME/nvim. Default is nothing. If base is not specified, it is assumed to be :lua= vim.fn.stdpath("cache")
Expand All @@ -76,6 +78,10 @@ local utils = require("remote-nvim.utils")
---@field copy_dirs remote-nvim.config.PluginConfig.Remote.CopyDirs Which directories should be copied over to the remote
---@field app_name string Neovim app name which should be used throughout

---@class remote-nvim.config.PluginConfig.UiConfig
---@field last_sync_date_format string Date format for last sync
---@field connection_start_date_format string Date format for start time of a connection

---@class remote-nvim.config.PluginConfig
---@field devpod remote-nvim.config.PluginConfig.DevpodConfig Devcontainer configuration
---@field ssh_config remote-nvim.config.PluginConfig.SSHConfig SSH configuration
Expand All @@ -88,6 +94,7 @@ local utils = require("remote-nvim.utils")
---@field client_callback function<string, remote-nvim.providers.WorkspaceConfig> Function that would be called upon to start a Neovim client
---@field offline_mode remote-nvim.config.PluginConfig.OfflineModeConfig Offline mode configuration
---@field log remote-nvim.config.PluginConfig.LogConfig Plugin logging options
---@field ui remote-nvim.config.PluginConfig.UiConfig Plugin ui options

M.default_opts = {
devpod = {
Expand Down Expand Up @@ -146,6 +153,14 @@ M.default_opts = {
remote = {
app_name = "nvim",
copy_dirs = {
dot_config = {
---@diagnostic disable-next-line:assign-type-mismatch
base = utils.path_join(utils.is_windows, vim.fn.stdpath("config"), ".."),
dirs = {},
compression = {
enabled = true,
},
},
config = {
---@diagnostic disable-next-line:assign-type-mismatch
base = vim.fn.stdpath("config"),
Expand Down Expand Up @@ -208,6 +223,10 @@ M.default_opts = {
level = "info",
max_size = 1024 * 1024 * 2, -- 2MB
},
ui = {
last_sync_date_format = "%d-%m-%Y %H:%M",
connection_start_date_format = "%d-%m-%Y %H:%M",
}
}

---Setup for the plugin
Expand All @@ -223,9 +242,10 @@ M.setup = function(opts)
)
end
M.config =
require("remote-nvim.deprecation").handle_deprecations(vim.tbl_deep_extend("force", M.default_opts, opts or {}))
require("remote-nvim.deprecation").handle_deprecations(vim.tbl_deep_extend("force", M.default_opts, opts or {}))

M.session_provider = require("remote-nvim.providers.session_provider")()
M.dashboard = require("remote-nvim.ui.dashboard")
require("remote-nvim.command")
require("remote-nvim.colors").setup()

Expand Down
40 changes: 40 additions & 0 deletions lua/remote-nvim/providers/connections.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---@class remote-nvim.providers.Connections.ConnectionInfo
---@field unique_host_id string Host name
---@field workspace_id string Host workspace identifier
---@field connection_id? string Session identifier
---@field cwd? string CWD of neovim instance
---@field local_port string
---@field workspace remote-nvim.providers.WorkspaceConfig
---@field started string time of start

---@class remote-nvim.providers.Connections: remote-nvim.Object
---@field private _connections table<string, remote-nvim.providers.Provider> Map of host and associated session
---@field private remote_workspaces_config remote-nvim.ConfigProvider
local Connections = require("remote-nvim.middleclass")("Connections")

---Initialize session provider
---@diagnostic disable-next-line: unused-local
function Connections:init(opts)
end

---@return table<string, remote-nvim.providers.Connections.ConnectionInfo> connections Currently active connections
function Connections:update_connections()
error("not implemented")
end

---@param connection_info remote-nvim.providers.Connections.ConnectionInfo
---@param cmd string command to launch inside the connection
---@param executor remote-nvim.providers.Executor Executor to run remote command on
---@param extra_opts string|string[] extra options passed to the underlying command
---@diagnostic disable-next-line: unused-local
function Connections:new_connection(connection_info, cmd, executor, extra_opts)
error("not implemented")
end

---@param ids string|string[] Connecion ids to close
---@diagnostic disable-next-line: unused-local
function Connections:close_connections(ids)
error("not implemented")
end

return Connections
Loading