Skip to content
Merged
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
102 changes: 101 additions & 1 deletion home-manager/programs/neovim/lua/autocmds.lua
Original file line number Diff line number Diff line change
@@ -1,13 +1,113 @@
local augroup = vim.api.nvim_create_augroup
local autocmd = vim.api.nvim_create_autocmd
local utils = require("utils")

-- Highlight on yank
-- ====================================================================================
-- HIGHLIGHT ON YANK WITH REGISTER ROTATION
-- From: https://github.com/dmtrKovalenko/dotfiles
-- ====================================================================================
local highlight_yank_group = augroup("HighlightYank", { clear = true })
autocmd("TextYankPost", {
group = highlight_yank_group,
pattern = "*",
callback = function()
vim.highlight.on_yank()
-- Rotate registers on yank to preserve yank history
if vim.v.event.operator == "y" then

Copilot AI Dec 6, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The register rotation runs on every yank operation, including yanks to named registers (e.g., "ayy), which may not be the desired behavior. This could pollute the numbered register history with intentional named register operations.

Consider checking vim.v.event.regname to only rotate when yanking to the unnamed register:

if vim.v.event.operator == "y" and vim.v.event.regname == "" then
	utils.yank_shift()
end
Suggested change
if vim.v.event.operator == "y" then
if vim.v.event.operator == "y" and vim.v.event.regname == "" then

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High

This yank register rotation fundamentally breaks Vim's numbered register semantics. In standard Vim, registers 1-9 store the last 9 deletions (not yanks), and Vim manages this automatically. By rotating registers on every yank operation:

  1. You're overwriting the deletion history that users expect with "1p, "2p, etc.
  2. This triggers on ALL yank events including plugin-initiated ones, potentially causing unexpected side effects
  3. It conflicts with standard Vim behavior documented everywhere

If keeping this feature, strongly consider:

  • Adding a configuration flag to opt-in (vim.g.enable_yank_rotation)
  • Documenting this non-standard behavior prominently in README
  • Filtering by v:event.regname to avoid affecting special registers
  • Adding guards against recursive or plugin-initiated yanks

Agent: 🏛 Architecture • Fix in Cursor • Fix in Claude

Prompt for Agent
Task: Address review feedback left on GitHub.
Repository: shunkakinoki/dotfiles#393
File: home-manager/programs/neovim/lua/autocmds.lua#L16
Action: Open this file location in your editor, inspect the highlighted code, and resolve the issue described below.

Feedback:
This yank register rotation fundamentally breaks Vim's numbered register semantics. In standard Vim, registers 1-9 store the last 9 **deletions** (not yanks), and Vim manages this automatically. By rotating registers on every yank operation:

1. You're overwriting the deletion history that users expect with `"1p`, `"2p`, etc.
2. This triggers on ALL yank events including plugin-initiated ones, potentially causing unexpected side effects
3. It conflicts with standard Vim behavior documented everywhere

If keeping this feature, strongly consider:
- Adding a configuration flag to opt-in (`vim.g.enable_yank_rotation`)
- Documenting this non-standard behavior prominently in README
- Filtering by `v:event.regname` to avoid affecting special registers
- Adding guards against recursive or plugin-initiated yanks

utils.yank_shift()
end
end,
})

-- ====================================================================================
-- AUTO-SAVE ON BUFFER LEAVE / FOCUS LOSS
-- From: https://github.com/dmtrKovalenko/dotfiles
-- ====================================================================================
local autosave_group = augroup("AutoSave", { clear = true })
autocmd({ "BufLeave", "FocusLost" }, {
group = autosave_group,
pattern = "*",
callback = function()
-- Only save if buffer is modified and has a filename
if vim.bo.modified and vim.fn.expand("%") ~= "" and vim.bo.buftype == "" then
vim.cmd("silent! update")

Copilot AI Dec 6, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The auto-save logic may fail silently for unwritable files. The silent! command suppresses all errors, which could hide important issues like permission errors or readonly files. Users may not realize their changes aren't being saved.

Consider using pcall to handle errors gracefully while still logging them:

local ok, err = pcall(vim.cmd, "update")
if not ok then
	vim.notify("Auto-save failed: " .. err, vim.log.levels.WARN)
end
Suggested change
vim.cmd("silent! update")
local ok, err = pcall(vim.cmd, "update")
if not ok then
vim.notify("Auto-save failed: " .. err, vim.log.levels.WARN)
end

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium

The silent! suppresses all errors including critical ones like filesystem permission problems, disk full conditions, or network filesystem timeouts. Consider removing silent! and handling errors explicitly, or at minimum add checks for file writability before attempting save. Also consider adding configuration options:

  • Global flag: vim.g.auto_save_enabled
  • Buffer-local opt-out: vim.b.disable_auto_save
  • Per-filetype configuration to avoid interfering with git rebase/merge workflows

Agent: 🏛 Architecture • Fix in Cursor • Fix in Claude

Prompt for Agent
Task: Address review feedback left on GitHub.
Repository: shunkakinoki/dotfiles#393
File: home-manager/programs/neovim/lua/autocmds.lua#L33
Action: Open this file location in your editor, inspect the highlighted code, and resolve the issue described below.

Feedback:
The `silent!` suppresses all errors including critical ones like filesystem permission problems, disk full conditions, or network filesystem timeouts. Consider removing `silent!` and handling errors explicitly, or at minimum add checks for file writability before attempting save. Also consider adding configuration options:
- Global flag: `vim.g.auto_save_enabled`
- Buffer-local opt-out: `vim.b.disable_auto_save`
- Per-filetype configuration to avoid interfering with git rebase/merge workflows

end
end,
})

-- ====================================================================================
-- CUSTOM TERMINAL TITLE WITH FILE ICONS
-- From: https://github.com/dmtrKovalenko/dotfiles
-- ====================================================================================
local title_group = augroup("TerminalTitle", { clear = true })
autocmd({ "BufEnter", "BufFilePost" }, {

Copilot AI Dec 6, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BufFilePost is not a standard Neovim autocmd event. This appears to be a typo - the correct event name is likely BufFilePre or BufReadPost. This event will never trigger, meaning the terminal title won't be updated when files are read.

Consider using BufReadPost or BufWinEnter instead, which are standard events that trigger when buffers are loaded or displayed in windows.

Suggested change
autocmd({ "BufEnter", "BufFilePost" }, {
autocmd({ "BufEnter", "BufReadPost" }, {

Copilot uses AI. Check for mistakes.
group = title_group,
pattern = "*",
callback = function()
local filename = vim.fn.expand("%:t")
local dir = vim.fn.fnamemodify(vim.fn.getcwd(), ":t")
local icon = utils.get_file_icon(filename)
if filename ~= "" then
vim.opt.titlestring = icon .. " " .. filename .. " - " .. dir
else
vim.opt.titlestring = dir
end
end,
})
vim.opt.title = true

-- ====================================================================================
-- FILETYPE-SPECIFIC KEYWORD EXTENSIONS
-- From: https://github.com/dmtrKovalenko/dotfiles
-- ====================================================================================
local keyword_group = augroup("KeywordExtensions", { clear = true })
autocmd("FileType", {
group = keyword_group,
pattern = { "typescript", "typescriptreact", "javascript", "javascriptreact" },
callback = function()
-- Add @ and - to keyword characters for better word navigation
vim.opt_local.iskeyword:append("@-@")
vim.opt_local.iskeyword:append("-")
end,
})
autocmd("FileType", {
group = keyword_group,
pattern = { "css", "scss", "sass", "less" },
callback = function()
vim.opt_local.iskeyword:append("-")
vim.opt_local.iskeyword:append("#")
end,
})
autocmd("FileType", {
group = keyword_group,
pattern = { "html", "xml", "vue", "svelte" },
callback = function()
vim.opt_local.iskeyword:append("-")
vim.opt_local.iskeyword:append(":")
end,
})
autocmd("FileType", {
group = keyword_group,
pattern = { "json", "jsonc" },
callback = function()
vim.opt_local.iskeyword:append("-")
vim.opt_local.iskeyword:append("$")
end,
})
autocmd("FileType", {
group = keyword_group,
pattern = { "yaml", "toml" },
callback = function()
vim.opt_local.iskeyword:append("-")
vim.opt_local.iskeyword:append(".")
end,
})
autocmd("FileType", {
group = keyword_group,
pattern = "markdown",
callback = function()
vim.opt_local.iskeyword:append("-")
vim.opt_local.iskeyword:append("#")
end,
})
Comment on lines +64 to 112

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There's a lot of repetition in the creation of FileType autocommands for setting iskeyword. This can be refactored into a more concise, data-driven approach to improve maintainability. You can define a table of configurations and loop through it to create the autocommands.

This also allows for merging the rules for css, scss, sass, less, and markdown since they share the same keyword additions.

Additionally, vim.opt_local.iskeyword:append("@-@") is functionally equivalent to vim.opt_local.iskeyword:append("@") but is less clear. The suggested refactoring simplifies this as well.

local keyword_extensions = {
	{
		patterns = { "typescript", "typescriptreact", "javascript", "javascriptreact" },
		keywords = { "@", "-" },
	},
	{
		patterns = { "css", "scss", "sass", "less", "markdown" },
		keywords = { "-", "#" },
	},
	{
		patterns = { "html", "xml", "vue", "svelte" },
		keywords = { "-", ":" },
	},
	{
		patterns = { "json", "jsonc" },
		keywords = { "-", "$" },
	},
	{
		patterns = { "yaml", "toml" },
		keywords = { "-", "." },
	},
}

for _, config in ipairs(keyword_extensions) do
	autocmd("FileType", {
		group = keyword_group,
		pattern = config.patterns,
		callback = function()
			for _, keyword in ipairs(config.keywords) do
				vim.opt_local.iskeyword:append(keyword)
			end
		end,
	})
end


Expand Down
12 changes: 12 additions & 0 deletions home-manager/programs/neovim/lua/keymaps.lua
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,18 @@ keymap("n", "<leader>py", ':let @" = expand("%:p")<CR>', opts)
-- @keymap <leader>d: Delete to blackhole register
keymap({ "n", "v" }, "<leader>d", '"_d', opts)

-- @keymap dd: Smart delete (uses blackhole register for empty lines)
-- From: https://github.com/dmtrKovalenko/dotfiles
keymap("n", "dd", function()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium

Overriding dd (one of Vim's most fundamental commands) is architecturally risky and changes muscle memory for all Vim users. Consider:

  • Using a different keymap like <leader>dd instead to avoid breaking standard behavior
  • Making this opt-in via configuration
  • Adding a toggle command to enable/disable
  • Document this breaking change prominently if you keep it

The expr mapping adds indirection and could interfere with plugins that rely on standard dd behavior.

Agent: 🏛 Architecture • Fix in Cursor • Fix in Claude

Prompt for Agent
Task: Address review feedback left on GitHub.
Repository: shunkakinoki/dotfiles#393
File: home-manager/programs/neovim/lua/keymaps.lua#L115
Action: Open this file location in your editor, inspect the highlighted code, and resolve the issue described below.

Feedback:
Overriding `dd` (one of Vim's most fundamental commands) is architecturally risky and changes muscle memory for all Vim users. Consider:
- Using a different keymap like `<leader>dd` instead to avoid breaking standard behavior
- Making this opt-in via configuration
- Adding a toggle command to enable/disable
- Document this breaking change prominently if you keep it

The expr mapping adds indirection and could interfere with plugins that rely on standard `dd` behavior.

return utils.smart_delete("dd")
end, { noremap = true, expr = true })

-- @keymap <Esc>: Close floating windows
keymap("n", "<Esc>", function()
Comment on lines +119 to +120

Copilot AI Dec 6, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overriding the <Esc> key in normal mode could interfere with other plugins or user workflows that expect <Esc> to only clear search highlights. Some plugins use <Esc> as a cancellation key, and closing all floating windows might be too aggressive in certain contexts (e.g., when a user wants to cancel an action without closing all floating windows).

Consider using a different key combination like <leader><Esc> or <C-c> for this functionality, or make the floating window closing conditional.

Suggested change
-- @keymap <Esc>: Close floating windows
keymap("n", "<Esc>", function()
-- @keymap <leader><Esc>: Close floating windows
keymap("n", "<leader><Esc>", function()

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium

Remapping <Esc> globally changes fundamental Vim behavior. The floating window close could interfere with:

  • Plugin UI elements that need manual dismissal (telescope, which-key, lazy.nvim)
  • Intentionally persistent floating windows
  • Custom workflows that rely on keeping floating windows open

Consider using a different key like <leader><Esc> or <C-l>, or add checks to exclude certain floating windows from being closed.

Agent: 🏛 Architecture • Fix in Cursor • Fix in Claude

Prompt for Agent
Task: Address review feedback left on GitHub.
Repository: shunkakinoki/dotfiles#393
File: home-manager/programs/neovim/lua/keymaps.lua#L120
Action: Open this file location in your editor, inspect the highlighted code, and resolve the issue described below.

Feedback:
Remapping `<Esc>` globally changes fundamental Vim behavior. The floating window close could interfere with:
- Plugin UI elements that need manual dismissal (telescope, which-key, lazy.nvim)
- Intentionally persistent floating windows
- Custom workflows that rely on keeping floating windows open

Consider using a different key like `<leader><Esc>` or `<C-l>`, or add checks to exclude certain floating windows from being closed.

utils.close_floating_wins()
vim.cmd("nohlsearch")
end, opts)
Comment on lines +120 to +123

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Overriding the <Esc> key to close all floating windows is quite aggressive and may lead to unexpected behavior. For instance, many plugins use floating windows where <Esc> is used to return to normal mode within that window. This mapping would close the window entirely, along with any other floating windows that might be open (like diagnostics). Consider using a more specific keymap (e.g., <leader><Esc>) or making the function less aggressive, for example, by only closing the current window if it's a floating window.


-- ====================================================================================
-- GIT OPERATIONS
-- ====================================================================================
Expand Down
56 changes: 56 additions & 0 deletions home-manager/programs/neovim/lua/settings.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,30 @@ vim.opt.termsync = true
vim.opt.hidden = true
vim.opt.updatetime = 300
vim.opt.mouse = "a"

-- ====================================================================================
-- SSH / OSC52 CLIPBOARD HANDLING
-- From: https://github.com/dmtrKovalenko/dotfiles
-- Uses OSC 52 protocol for clipboard when running over SSH
-- ====================================================================================
local function is_ssh()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium

Duplicate code: is_ssh() function is defined identically in utils.lua (lines 55-57). This should use require("utils").is_ssh() instead. Additionally, the require("vim.ui.clipboard.osc52") below lacks error handling - OSC52 is only available in Neovim >= 0.10. Add pcall protection:

local utils = require("utils")
if utils.is_ssh() then
  local ok, osc52 = pcall(require, "vim.ui.clipboard.osc52")
  if not ok then
    vim.notify("OSC52 clipboard not available", vim.log.levels.WARN)
    return
  end
  -- ... rest of config
end

Agent: 🏛 Architecture • Fix in Cursor • Fix in Claude

Prompt for Agent
Task: Address review feedback left on GitHub.
Repository: shunkakinoki/dotfiles#393
File: home-manager/programs/neovim/lua/settings.lua#L15
Action: Open this file location in your editor, inspect the highlighted code, and resolve the issue described below.

Feedback:
Duplicate code: `is_ssh()` function is defined identically in `utils.lua` (lines 55-57). This should use `require("utils").is_ssh()` instead. Additionally, the `require("vim.ui.clipboard.osc52")` below lacks error handling - OSC52 is only available in Neovim >= 0.10. Add `pcall` protection:
```lua
local utils = require("utils")
if utils.is_ssh() then
  local ok, osc52 = pcall(require, "vim.ui.clipboard.osc52")
  if not ok then
    vim.notify("OSC52 clipboard not available", vim.log.levels.WARN)
    return
  end
  -- ... rest of config
end

</details>

return os.getenv("SSH_CLIENT") ~= nil or os.getenv("SSH_TTY") ~= nil
end

if is_ssh() then
Comment on lines +15 to +19

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The is_ssh function is duplicated here and in lua/utils.lua. To adhere to the DRY (Don't Repeat Yourself) principle and improve maintainability, you should remove this local implementation and use the one from the utils module. You can require the module inline to avoid adding it at the top of the file.

if require("utils").is_ssh() then

Comment on lines +15 to +19

Copilot AI Dec 6, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The is_ssh() function is duplicated - it's defined both here and in utils.lua (line 55). This creates code duplication and potential maintenance issues if the logic needs to be updated.

Consider removing this local definition and using require("utils").is_ssh() instead, or if this file is loaded before utils.lua, keep it here and remove the duplicate from utils.lua.

Suggested change
local function is_ssh()
return os.getenv("SSH_CLIENT") ~= nil or os.getenv("SSH_TTY") ~= nil
end
if is_ssh() then
if require("utils").is_ssh() then

Copilot uses AI. Check for mistakes.
-- Use OSC 52 for clipboard when in SSH session
vim.g.clipboard = {
name = "OSC 52",
copy = {
["+"] = require("vim.ui.clipboard.osc52").copy("+"),
["*"] = require("vim.ui.clipboard.osc52").copy("*"),
},
paste = {
["+"] = require("vim.ui.clipboard.osc52").paste("+"),
["*"] = require("vim.ui.clipboard.osc52").paste("*"),
},
}
end
vim.opt.inccommand = "nosplit"
vim.opt.splitbelow = true
vim.opt.splitright = true
Expand Down Expand Up @@ -44,6 +68,38 @@ vim.opt.cursorline = true
vim.opt.grepprg = "rg --vimgrep --smart-case --follow"
-- Background will be set automatically based on system theme
vim.opt.termguicolors = true

-- ====================================================================================
-- VISIBLE WHITESPACE
-- From: https://github.com/dmtrKovalenko/dotfiles
-- ====================================================================================
vim.opt.list = true
vim.opt.listchars = {
tab = "→ ",
trail = "·",
extends = "»",
precedes = "«",
nbsp = "␣",
}

-- ====================================================================================
-- DIAGNOSTIC DISPLAY SETTINGS
-- From: https://github.com/dmtrKovalenko/dotfiles
-- ====================================================================================
vim.diagnostic.config({
virtual_text = {
prefix = "●",
spacing = 2,
},
signs = true,
underline = true,
update_in_insert = false,
severity_sort = true,
float = {
border = "rounded",
source = true,
},
})
vim.opt.shortmess:append("c")
vim.opt.timeoutlen = 300
vim.opt.winborder = "none"
Expand Down
72 changes: 72 additions & 0 deletions home-manager/programs/neovim/lua/utils.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,77 @@
local M = {}

-- ====================================================================================
-- SMART DELETE FUNCTION
-- Avoids polluting registers with whitespace-only lines
-- From: https://github.com/dmtrKovalenko/dotfiles
-- ====================================================================================
function M.smart_delete(key)
local line = vim.api.nvim_get_current_line()
-- If the line is empty or contains only whitespace, delete to blackhole register
if line:match("^%s*$") then
return '"_' .. key
end
return key
end

-- ====================================================================================
-- YANK REGISTER ROTATION
-- Rotates registers 1-9 when yanking to preserve yank history
-- From: https://github.com/dmtrKovalenko/dotfiles
-- ====================================================================================
function M.yank_shift()
-- Rotate registers 9 <- 8 <- ... <- 2 <- 1 <- "
for i = 9, 2, -1 do
local prev_content = vim.fn.getreg(tostring(i - 1))
local prev_type = vim.fn.getregtype(tostring(i - 1))
vim.fn.setreg(tostring(i), prev_content, prev_type)
end
-- Move unnamed register to register 1
local unnamed_content = vim.fn.getreg('"')
local unnamed_type = vim.fn.getregtype('"')
vim.fn.setreg("1", unnamed_content, unnamed_type)
end

-- ====================================================================================
-- CLOSE FLOATING WINDOWS
-- Utility to close all floating windows
-- From: https://github.com/dmtrKovalenko/dotfiles
-- ====================================================================================
function M.close_floating_wins()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium

This function closes ALL floating windows without discrimination, which could close important plugin UIs (lazy.nvim, mason.nvim, telescope previews, LSP hover docs). Add:

  1. pcall protection around nvim_win_close
  2. Filetype filtering to exclude important windows
  3. Optional parameter to specify exclude list

Example:

function M.close_floating_wins(opts)
  opts = opts or {}
  local exclude_fts = opts.exclude_filetypes or {}
  for _, win in ipairs(vim.api.nvim_list_wins()) do
    if vim.api.nvim_win_is_valid(win) then
      local config = vim.api.nvim_win_get_config(win)
      if config.relative ~= "" then
        local buf = vim.api.nvim_win_get_buf(win)
        local ft = vim.bo[buf].filetype
        if not vim.tbl_contains(exclude_fts, ft) then
          pcall(vim.api.nvim_win_close, win, false)
        end
      end
    end
  end
end

Agent: 🏛 Architecture • Fix in Cursor • Fix in Claude

Prompt for Agent
Task: Address review feedback left on GitHub.
Repository: shunkakinoki/dotfiles#393
File: home-manager/programs/neovim/lua/utils.lua#L40
Action: Open this file location in your editor, inspect the highlighted code, and resolve the issue described below.

Feedback:
This function closes ALL floating windows without discrimination, which could close important plugin UIs (lazy.nvim, mason.nvim, telescope previews, LSP hover docs). Add:
1. `pcall` protection around `nvim_win_close`
2. Filetype filtering to exclude important windows
3. Optional parameter to specify exclude list

Example:
```lua
function M.close_floating_wins(opts)
  opts = opts or {}
  local exclude_fts = opts.exclude_filetypes or {}
  for _, win in ipairs(vim.api.nvim_list_wins()) do
    if vim.api.nvim_win_is_valid(win) then
      local config = vim.api.nvim_win_get_config(win)
      if config.relative ~= "" then
        local buf = vim.api.nvim_win_get_buf(win)
        local ft = vim.bo[buf].filetype
        if not vim.tbl_contains(exclude_fts, ft) then
          pcall(vim.api.nvim_win_close, win, false)
        end
      end
    end
  end
end

</details>

for _, win in ipairs(vim.api.nvim_list_wins()) do
if vim.api.nvim_win_is_valid(win) then
local config = vim.api.nvim_win_get_config(win)
if config.relative ~= "" then
vim.api.nvim_win_close(win, false)
end
end
end
Comment on lines +41 to +48

Copilot AI Dec 6, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function may fail to close some floating windows if closing one window invalidates others in the iteration. When a floating window is closed, it's removed from the window list, but the iteration continues with indices that may now be stale. This could result in errors or some floating windows not being closed.

Consider collecting window handles first, then closing them, or iterate in reverse order:

function M.close_floating_wins()
	local floating_wins = {}
	for _, win in ipairs(vim.api.nvim_list_wins()) do
		if vim.api.nvim_win_is_valid(win) then
			local config = vim.api.nvim_win_get_config(win)
			if config.relative ~= "" then
				table.insert(floating_wins, win)
			end
		end
	end
	for _, win in ipairs(floating_wins) do
		if vim.api.nvim_win_is_valid(win) then
			vim.api.nvim_win_close(win, false)
		end
	end
end
Suggested change
for _, win in ipairs(vim.api.nvim_list_wins()) do
if vim.api.nvim_win_is_valid(win) then
local config = vim.api.nvim_win_get_config(win)
if config.relative ~= "" then
vim.api.nvim_win_close(win, false)
end
end
end
local floating_wins = {}
for _, win in ipairs(vim.api.nvim_list_wins()) do
if vim.api.nvim_win_is_valid(win) then
local config = vim.api.nvim_win_get_config(win)
if config.relative ~= "" then
table.insert(floating_wins, win)
end
end
end
for _, win in ipairs(floating_wins) do
if vim.api.nvim_win_is_valid(win) then
vim.api.nvim_win_close(win, false)
end
end

Copilot uses AI. Check for mistakes.
end

-- ====================================================================================
-- SSH DETECTION
-- Detect if running in SSH session for clipboard handling
-- ====================================================================================
function M.is_ssh()
return os.getenv("SSH_CLIENT") ~= nil or os.getenv("SSH_TTY") ~= nil
end

-- ====================================================================================
-- FILE ICON RETRIEVAL
-- Get file icon using nvim-web-devicons if available
-- ====================================================================================
function M.get_file_icon(filename)
local ok, devicons = pcall(require, "nvim-web-devicons")
if ok then
local icon, _ = devicons.get_icon(filename, vim.fn.fnamemodify(filename, ":e"), { default = true })
return icon or ""
end
return ""
end

-- ====================================================================================
-- BUFFER CYCLING
-- ====================================================================================
function M.cycle_buffer(direction)
local current_buf = vim.api.nvim_get_current_buf()

Expand Down
Loading