From 427403f3d2208b6d2cae320669aa37b1dd9d83b6 Mon Sep 17 00:00:00 2001 From: Tony Duco Date: Thu, 29 May 2025 00:36:56 -0400 Subject: [PATCH 1/6] feat: nvchad statusline integration --- README.md | 46 +++++++++++++++++++ lua/remote-sshfs/statusline.lua | 79 +++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 lua/remote-sshfs/statusline.lua diff --git a/README.md b/README.md index dc98be3..c107b42 100644 --- a/README.md +++ b/README.md @@ -174,6 +174,52 @@ With this plugin you can: To learn more about SSH configs and how to write/style one you can read more [here](https://linuxize.com/post/using-the-ssh-config-file/) +## 🧩 Status-line integrations + +`remote-sshfs.nvim` ships a tiny helper module that exposes the current +connection (if any) as a **single, reusable component** – so every status-line +framework can opt-in without additional boiler-plate. + +The module returns an **empty string** when no host is mounted which makes it +safe to drop into existing layouts. + +
+NvChad / Heirline + +```lua +-- custom/chadrc.lua (NvChad ≥ v2.*) + +local st = require "nvchad.statusline.default" -- or your own layout table + +-- 🔌 add remote-sshfs block (shows: 󰀻 when connected) +local remote = require("remote-sshfs.statusline").nvchad_component { + -- optional highlight group + highlight = { fg = "green" }, +} + +-- place it wherever you like in the active component list +table.insert(st.active_components, remote) + +return st +``` + +Custom icon: + +```lua +vim.g.remote_sshfs_status_icon = "" -- must be set BEFORE the plugin loads +``` + +That’s it! When `RemoteSSHFSConnect` succeeds your status-line will now read + +``` +󰀻 myserver +``` + +and disappears once you disconnect. + +
+ + ## 🤝 Contributing If you find a bug or have a suggestion for how to improve remote-sshfs.nvim or additional functionality, please feel free to submit an issue or a pull request. We welcome contributions from the community and are committed to making remote-sshfs.nvim as useful as possible for everyone who uses it. diff --git a/lua/remote-sshfs/statusline.lua b/lua/remote-sshfs/statusline.lua new file mode 100644 index 0000000..69ac3ba --- /dev/null +++ b/lua/remote-sshfs/statusline.lua @@ -0,0 +1,79 @@ +local M = {} + +-- Default icon displayed when a connection is active. Nerd-font compatible. +-- Users can override this by setting `vim.g.remote_sshfs_status_icon` before +-- the plugin is loaded or by changing `M.icon` afterwards. +M.icon = vim.g.remote_sshfs_status_icon or "󰀻" -- nf-mdi-server + +-- Return a short human-readable string that represents the current connection +-- state. If no connection is active an empty string is returned so that the +-- statusline stays unchanged. +-- +-- Examples: +-- "" – when not connected +-- "󰀻 myserver" – when connected to host *myserver* +function M.status() + local ok, conn = pcall(require, "remote-sshfs.connections") + if not ok or type(conn) ~= "table" then + return "" + end + + if not conn.is_connected or not conn.is_connected() then + return "" + end + + local host_tbl = conn.get_current_host and conn.get_current_host() or nil + local name = "remote" + if host_tbl and type(host_tbl) == "table" then + -- Prefer the explicit entries we create while parsing the ssh-config. + name = host_tbl.Name or host_tbl.Host or host_tbl.host or name + end + + return string.format("%s %s", M.icon, name) +end + +------------------------------------------------------------------------------- +-- READY-MADE COMPONENTS ------------------------------------------------------- +------------------------------------------------------------------------------- + +-- NvChad (Heirline) component factory. +-- +-- Usage inside `custom/chadrc.lua` (NvChad > v2.*): +-- +-- local remote = require("remote-sshfs.statusline").nvchad_component() +-- table.insert(M.active_components, remote) -- wherever you like +-- +-- The returned table follows Heirline's component specification used by +-- NvChad, i.e. `provider`, `condition` and `hl` keys. +-- +-- `opts` (all optional): +-- highlight (table) – Highlight table passed as-is to Heirline. +function M.nvchad_component(opts) + opts = opts or {} + + -- Lazily require within the closures because the statusline component is + -- evaluated *after* the plugin init code has run. + return { + condition = function() + local ok, conn = pcall(require, "remote-sshfs.connections") + return ok and conn.is_connected and conn.is_connected() + end, + provider = function() + return M.status() + end, + hl = opts.highlight or { fg = "green" }, + } +end + +------------------------------------------------------------------------------- +-- Fall-back plain string for easy integration in classic statuslines --------- +------------------------------------------------------------------------------- + +-- For simple `statusline` settings ("set statusline=%!v:lua..."), return a Lua +-- callable that expands to the status string. Example: +-- vim.o.statusline = "%!v:lua.require('remote-sshfs.statusline').status()" +function M.vim_statusline() + return M.status() +end + +return M From 4942b292cb835f02c58b7a1a0364ca6037bd93e4 Mon Sep 17 00:00:00 2001 From: Tony Duco Date: Thu, 29 May 2025 00:40:08 -0400 Subject: [PATCH 2/6] docs: update readme for nvchad integration --- README.md | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index c107b42..d095142 100644 --- a/README.md +++ b/README.md @@ -184,38 +184,50 @@ The module returns an **empty string** when no host is mounted which makes it safe to drop into existing layouts.
-NvChad / Heirline +NvChad / Heirline (v2.*) + +NvChad exposes its UI configuration through the return table of +`lua/chadrc.lua`. The snippet below **extends** the default status-line instead +of replacing it. ```lua --- custom/chadrc.lua (NvChad ≥ v2.*) +-- ~/.config/nvim/lua/chadrc.lua (or wherever your NvChad chadrc lives) + +local M = {} -local st = require "nvchad.statusline.default" -- or your own layout table +-- 1️⃣ Fetch the default lay-out that ships with NvChad +local default = require "nvchad.statusline.default" --- 🔌 add remote-sshfs block (shows: 󰀻 when connected) +-- 2️⃣ Create the remote-sshfs component (shows: 󰀻 while connected) local remote = require("remote-sshfs.statusline").nvchad_component { - -- optional highlight group - highlight = { fg = "green" }, + highlight = { fg = "green" }, -- (optional) colour override } --- place it wherever you like in the active component list -table.insert(st.active_components, remote) +-- 3️⃣ Inject it wherever you want. Here we append at the end. +table.insert(default, remote) + +-- 4️⃣ Expose the modified layout back to NvChad +M.ui = { + statusline = default, +} -return st +return M ``` Custom icon: ```lua -vim.g.remote_sshfs_status_icon = "" -- must be set BEFORE the plugin loads +-- has to be set *before* `require("remote-sshfs")` is executed +vim.g.remote_sshfs_status_icon = "" ``` -That’s it! When `RemoteSSHFSConnect` succeeds your status-line will now read +When `RemoteSSHFSConnect` succeeds your status-line reads e.g. ``` 󰀻 myserver ``` -and disappears once you disconnect. +and vanishes as soon as you disconnect.
From 7d499d3366c70b064db7a4462ef57caf0da76310 Mon Sep 17 00:00:00 2001 From: Tony Duco Date: Thu, 29 May 2025 00:46:49 -0400 Subject: [PATCH 3/6] refactor: nvchad status line integration --- README.md | 26 +++++++++++++++----------- lua/remote-sshfs/statusline.lua | 31 +++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index d095142..c80bea8 100644 --- a/README.md +++ b/README.md @@ -184,7 +184,7 @@ The module returns an **empty string** when no host is mounted which makes it safe to drop into existing layouts.
-NvChad / Heirline (v2.*) +NvChad (built-in statusline) NvChad exposes its UI configuration through the return table of `lua/chadrc.lua`. The snippet below **extends** the default status-line instead @@ -196,19 +196,23 @@ of replacing it. local M = {} -- 1️⃣ Fetch the default lay-out that ships with NvChad -local default = require "nvchad.statusline.default" - --- 2️⃣ Create the remote-sshfs component (shows: 󰀻 while connected) -local remote = require("remote-sshfs.statusline").nvchad_component { - highlight = { fg = "green" }, -- (optional) colour override +-- 1️⃣ Create a callable module for NvChad’s statusline +local remote_module = require("remote-sshfs.statusline").nvchad_module { + highlight = "St_gitIcons", -- highlight group (optional) } --- 3️⃣ Inject it wherever you want. Here we append at the end. -table.insert(default, remote) - --- 4️⃣ Expose the modified layout back to NvChad +-- 2️⃣ Add it to `modules` *and* reference it in `order` M.ui = { - statusline = default, + statusline = { + -- theme / separator_style as you already have… + + -- insert the module name wherever you like + order = { "mode", "f", "git", "%=", "remote", "%=", "lsp", "cwd" }, + + modules = { + remote = remote_module, + }, + }, } return M diff --git a/lua/remote-sshfs/statusline.lua b/lua/remote-sshfs/statusline.lua index 69ac3ba..3cd5152 100644 --- a/lua/remote-sshfs/statusline.lua +++ b/lua/remote-sshfs/statusline.lua @@ -65,6 +65,37 @@ function M.nvchad_component(opts) } end +------------------------------------------------------------------------------- +-- NvChad (classic v3 statusline) module helper -------------------------------- +------------------------------------------------------------------------------- + +-- NvChad’s in-house statusline (documented under `:h nvui.statusline`) expects +-- plain strings or Lua callables in the `modules` table. This helper returns +-- such a callable, so users can simply do +-- +-- M.ui = { +-- statusline = { +-- modules = { +-- remote = require("remote-sshfs.statusline").nvchad_module(), +-- } +-- } +-- } +-- +-- `opts.highlight` – optional highlight group name, e.g. "St_gitIcons". +function M.nvchad_module(opts) + opts = opts or {} + local hl_begin = opts.highlight and ("%#" .. opts.highlight .. "#") or "" + local hl_end = opts.highlight and "%*" or "" + + return function() + local s = M.status() + if s == "" then + return "" + end + return hl_begin .. s .. hl_end + end +end + ------------------------------------------------------------------------------- -- Fall-back plain string for easy integration in classic statuslines --------- ------------------------------------------------------------------------------- From cad21d398bb23b3a4333158758d5e9795a515a88 Mon Sep 17 00:00:00 2001 From: Tony Duco Date: Thu, 29 May 2025 00:52:32 -0400 Subject: [PATCH 4/6] docs: update readme for nvchad integration --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c80bea8..1e8a771 100644 --- a/README.md +++ b/README.md @@ -187,15 +187,14 @@ safe to drop into existing layouts. NvChad (built-in statusline) NvChad exposes its UI configuration through the return table of -`lua/chadrc.lua`. The snippet below **extends** the default status-line instead -of replacing it. +`lua/chadrc.lua`. The snippet below shows a minimal way to **add one custom +module** (named `remote`) without touching the rest of the default layout. ```lua --- ~/.config/nvim/lua/chadrc.lua (or wherever your NvChad chadrc lives) +-- ~/.config/nvim/lua/chadrc.lua local M = {} --- 1️⃣ Fetch the default lay-out that ships with NvChad -- 1️⃣ Create a callable module for NvChad’s statusline local remote_module = require("remote-sshfs.statusline").nvchad_module { highlight = "St_gitIcons", -- highlight group (optional) From 340d82a244c405ccea0ca3efb9e739ca721e81d0 Mon Sep 17 00:00:00 2001 From: Tony Duco Date: Thu, 29 May 2025 00:58:42 -0400 Subject: [PATCH 5/6] refactor: nvchad status line integration --- README.md | 15 ++++++++++----- lua/remote-sshfs/statusline.lua | 27 +++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 1e8a771..bbd0e55 100644 --- a/README.md +++ b/README.md @@ -200,13 +200,19 @@ local remote_module = require("remote-sshfs.statusline").nvchad_module { highlight = "St_gitIcons", -- highlight group (optional) } +-- Option A: use an *existing* highlight group by name (as above). +-- Option B: provide a colour table and the plugin will create a group for you: +-- local remote_module = require("remote-sshfs.statusline").nvchad_module { +-- highlight = { fg = "#6A9955", bold = true }, +-- } + -- 2️⃣ Add it to `modules` *and* reference it in `order` M.ui = { statusline = { -- theme / separator_style as you already have… -- insert the module name wherever you like - order = { "mode", "f", "git", "%=", "remote", "%=", "lsp", "cwd" }, + order = { "mode", "file", "git", "%=", "lsp_msg", "%=", "diagnostics", "remote", "lsp", "cwd", "cursor" }, modules = { remote = remote_module, @@ -221,7 +227,7 @@ Custom icon: ```lua -- has to be set *before* `require("remote-sshfs")` is executed -vim.g.remote_sshfs_status_icon = "" +vim.g.remote_sshfs_status_icon = "" -- VS Code-style lock icon ``` When `RemoteSSHFSConnect` succeeds your status-line reads e.g. @@ -234,7 +240,6 @@ and vanishes as soon as you disconnect.
- ## 🤝 Contributing If you find a bug or have a suggestion for how to improve remote-sshfs.nvim or additional functionality, please feel free to submit an issue or a pull request. We welcome contributions from the community and are committed to making remote-sshfs.nvim as useful as possible for everyone who uses it. @@ -243,8 +248,8 @@ If you find a bug or have a suggestion for how to improve remote-sshfs.nvim or a This repository provides two test suites: -* **Unit tests** – pure-Lua logic, run via [Busted](https://olivinelabs.com/busted/) -* **Integration tests** – Neovim + [plenary.nvim](https://github.com/nvim-lua/plenary.nvim) harness +- **Unit tests** – pure-Lua logic, run via [Busted](https://olivinelabs.com/busted/) +- **Integration tests** – Neovim + [plenary.nvim](https://github.com/nvim-lua/plenary.nvim) harness ### Unit tests diff --git a/lua/remote-sshfs/statusline.lua b/lua/remote-sshfs/statusline.lua index 3cd5152..483ccc5 100644 --- a/lua/remote-sshfs/statusline.lua +++ b/lua/remote-sshfs/statusline.lua @@ -84,8 +84,31 @@ end -- `opts.highlight` – optional highlight group name, e.g. "St_gitIcons". function M.nvchad_module(opts) opts = opts or {} - local hl_begin = opts.highlight and ("%#" .. opts.highlight .. "#") or "" - local hl_end = opts.highlight and "%*" or "" + + -- Determine highlight behaviour. + -- 1) string → assume existing highlight group name + -- 2) table → dynamically create a group once and use it + -- 3) nil → no colour decorations + local hl_begin, hl_end = "", "" + + if opts.highlight then + local group_name + + if type(opts.highlight) == "string" then + group_name = opts.highlight + elseif type(opts.highlight) == "table" then + group_name = "RemoteSSHFSStl" + -- Only define once per session. + if vim.fn.hlexists(group_name) == 0 then + vim.api.nvim_set_hl(0, group_name, opts.highlight) + end + end + + if group_name then + hl_begin = "%#" .. group_name .. "#" + hl_end = "%*" + end + end return function() local s = M.status() From 38ae8818f2e2b7a618758f6a3e1f2bc00f7ec9e7 Mon Sep 17 00:00:00 2001 From: Tony Duco Date: Thu, 29 May 2025 01:06:33 -0400 Subject: [PATCH 6/6] feat: oil integration and statusline integration cleanup --- README.md | 34 ++++++++++++ lua/remote-sshfs/filebrowser/oil.lua | 77 ++++++++++++++++++++++++++++ lua/remote-sshfs/integration.lua | 44 ++++++++++++++++ lua/remote-sshfs/statusline.lua | 35 +++---------- 4 files changed, 162 insertions(+), 28 deletions(-) create mode 100644 lua/remote-sshfs/filebrowser/oil.lua create mode 100644 lua/remote-sshfs/integration.lua diff --git a/README.md b/README.md index bbd0e55..7143660 100644 --- a/README.md +++ b/README.md @@ -240,6 +240,40 @@ and vanishes as soon as you disconnect. +### File-browser / tree integrations + +
+Oil.nvim + +`remote-sshfs.nvim` also provides convenience helpers for +[oil.nvim](https://github.com/stevearc/oil.nvim): + +```lua +-- lua/plugins/oil.lua / wherever you configure oil.nvim + +require("oil").setup { + columns = { + "icon", + require("remote-sshfs.filebrowser.oil").column { hl = "DiagnosticHint" }, + "mtime", + }, +} + +-- Alternatively (or additionally) show the host in the win-bar of every Oil +-- buffer: +require("remote-sshfs.filebrowser.oil").attach_winbar { hl = "DiagnosticHint" } +``` + +Result (only while connected): + +``` +󰀻 myserver … +``` + +The helpers automatically hide themselves when you disconnect. + +
+ ## 🤝 Contributing If you find a bug or have a suggestion for how to improve remote-sshfs.nvim or additional functionality, please feel free to submit an issue or a pull request. We welcome contributions from the community and are committed to making remote-sshfs.nvim as useful as possible for everyone who uses it. diff --git a/lua/remote-sshfs/filebrowser/oil.lua b/lua/remote-sshfs/filebrowser/oil.lua new file mode 100644 index 0000000..326d513 --- /dev/null +++ b/lua/remote-sshfs/filebrowser/oil.lua @@ -0,0 +1,77 @@ +-- remote-sshfs ⇄ oil.nvim integration +-- +-- This helper adds visual cues inside Oil buffers when the user browses a +-- directory located on a remote-sshfs mount. +-- +-- 1. Column – shows "󰀻 " in the root row +-- 2. Winbar – sets the same label in the local winbar for Oil buffers + +local helper = require "remote-sshfs.integration" + +local M = {} + +------------------------------------------------------------------------------- +-- utils ---------------------------------------------------------------------- +------------------------------------------------------------------------------- + +local function host_label() + return helper.label() +end + +------------------------------------------------------------------------------- +-- 1. Column ------------------------------------------------------------------ +------------------------------------------------------------------------------- + +---Create an Oil column module displaying the current host label. +---@param opts table|nil { hl = 'HighlightGroup' } +function M.column(opts) + opts = opts or {} + + return function() + local label = host_label() + if not label then + return nil + end + + local hl = opts.hl or "DiagnosticHint" + return { + ---@param entry table Oil row entry + ---@return string, string? text, highlight + get_text = function(entry) + if entry.name == "." then + return label, hl + end + return "", nil + end, + column_width = #label, + } + end +end + +------------------------------------------------------------------------------- +-- 2. Winbar ------------------------------------------------------------------ +------------------------------------------------------------------------------- + +function M.attach_winbar(opts) + opts = opts or {} + + vim.api.nvim_create_autocmd("FileType", { + pattern = "oil", + group = vim.api.nvim_create_augroup("RemoteSSHFSOilWinbar", { clear = true }), + callback = function() + local label = host_label() + if not label then + vim.opt_local.winbar = nil + return + end + + local hl = opts.hl or "DiagnosticHint" + if hl and vim.fn.hlexists(hl) == 1 then + label = string.format("%%#%s#%s%%*", hl, label) + end + vim.opt_local.winbar = label + end, + }) +end + +return M diff --git a/lua/remote-sshfs/integration.lua b/lua/remote-sshfs/integration.lua new file mode 100644 index 0000000..76a5971 --- /dev/null +++ b/lua/remote-sshfs/integration.lua @@ -0,0 +1,44 @@ +-- Shared helper functions used by various optional UI integrations +-- (statusline, file browser columns, etc.). Keeping them here avoids code +-- duplication between individual adapters like *statusline.lua* or +-- *filebrowser/oil.lua*. + +local M = {} + +------------------------------------------------------------------------------- +-- Icon ----------------------------------------------------------------------- +------------------------------------------------------------------------------- + +M.icon = vim.g.remote_sshfs_status_icon or "󰀻" -- nf-mdi-server (similar to VSCode) + +------------------------------------------------------------------------------- +-- Host info ------------------------------------------------------------------ +------------------------------------------------------------------------------- + +-- Returns current host table or nil +local function current_host() + local ok, conn = pcall(require, "remote-sshfs.connections") + if not ok or type(conn) ~= "table" then + return nil + end + if not conn.is_connected or not conn.is_connected() then + return nil + end + if not conn.get_current_host then + return nil + end + return conn.get_current_host() +end + +-- Public helper: Returns nil when not connected, else "󰀻 hostname" +function M.label() + local host = current_host() + if not host then + return nil + end + + local name = host.Name or host.Host or host.HostName or host.host or "remote" + return string.format("%s %s", M.icon, name) +end + +return M diff --git a/lua/remote-sshfs/statusline.lua b/lua/remote-sshfs/statusline.lua index 483ccc5..a0953ad 100644 --- a/lua/remote-sshfs/statusline.lua +++ b/lua/remote-sshfs/statusline.lua @@ -1,35 +1,14 @@ -local M = {} - --- Default icon displayed when a connection is active. Nerd-font compatible. --- Users can override this by setting `vim.g.remote_sshfs_status_icon` before --- the plugin is loaded or by changing `M.icon` afterwards. -M.icon = vim.g.remote_sshfs_status_icon or "󰀻" -- nf-mdi-server +local helper = require "remote-sshfs.integration" --- Return a short human-readable string that represents the current connection --- state. If no connection is active an empty string is returned so that the --- statusline stays unchanged. --- --- Examples: --- "" – when not connected --- "󰀻 myserver" – when connected to host *myserver* -function M.status() - local ok, conn = pcall(require, "remote-sshfs.connections") - if not ok or type(conn) ~= "table" then - return "" - end +local M = {} - if not conn.is_connected or not conn.is_connected() then - return "" - end +-- Expose icon through the same table (backwards-compat). +M.icon = helper.icon - local host_tbl = conn.get_current_host and conn.get_current_host() or nil - local name = "remote" - if host_tbl and type(host_tbl) == "table" then - -- Prefer the explicit entries we create while parsing the ssh-config. - name = host_tbl.Name or host_tbl.Host or host_tbl.host or name - end +-- Delegated helpers ---------------------------------------------------------- - return string.format("%s %s", M.icon, name) +function M.status() + return helper.label() or "" end -------------------------------------------------------------------------------