mirror of
https://github.com/LazyVim/LazyVim.git
synced 2026-07-22 04:21:08 +00:00
feat(copy_path): add Spacemacs-style <leader>fy keybindings to copy file/directory/project paths
This commit is contained in:
parent
c10948c50b
commit
88ab46530f
4 changed files with 576 additions and 0 deletions
|
|
@ -97,6 +97,20 @@ map("n", "<leader>l", "<cmd>Lazy<cr>", { desc = "Lazy" })
|
|||
-- new file
|
||||
map("n", "<leader>fn", "<cmd>enew<cr>", { desc = "New File" })
|
||||
|
||||
-- copy path
|
||||
local copy_path = require("lazyvim.util.copy_path")
|
||||
map("n", "<leader>fyy", copy_path.copy_relative, { desc = "Path (relative)" })
|
||||
map("n", "<leader>fyY", copy_path.copy_absolute, { desc = "Path (absolute)" })
|
||||
map("n", "<leader>fyl", copy_path.copy_relative_with_line, { desc = "Path (relative, :line)" })
|
||||
map("n", "<leader>fyL", copy_path.copy_absolute_with_line, { desc = "Path (absolute, :line)" })
|
||||
map("n", "<leader>fyc", copy_path.copy_relative_with_line_column, { desc = "Path (relative, :line:col)" })
|
||||
map("n", "<leader>fyC", copy_path.copy_absolute_with_line_column, { desc = "Path (absolute, :line:col)" })
|
||||
map("n", "<leader>fyd", copy_path.copy_relative_directory, { desc = "Directory (relative)" })
|
||||
map("n", "<leader>fyD", copy_path.copy_absolute_directory, { desc = "Directory (absolute)" })
|
||||
map("n", "<leader>fyP", copy_path.copy_project, { desc = "Project Root" })
|
||||
map("n", "<leader>fyn", copy_path.copy_filename, { desc = "Filename" })
|
||||
map("n", "<leader>fyN", copy_path.copy_filename_no_ext, { desc = "Filename (no ext)" })
|
||||
|
||||
-- location list
|
||||
map("n", "<leader>xl", function()
|
||||
local success, err = pcall(vim.fn.getloclist(0, { winid = 0 }).winid ~= 0 and vim.cmd.lclose or vim.cmd.lopen)
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ return {
|
|||
{ "<leader>d", group = "debug" },
|
||||
{ "<leader>dp", group = "profiler" },
|
||||
{ "<leader>f", group = "file/find" },
|
||||
{ "<leader>fy", group = "copy path" },
|
||||
{ "<leader>g", group = "git" },
|
||||
{ "<leader>gh", group = "hunks" },
|
||||
{ "<leader>q", group = "quit/session" },
|
||||
|
|
|
|||
225
lua/lazyvim/util/copy_path.lua
Normal file
225
lua/lazyvim/util/copy_path.lua
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
---@class lazyvim.util.copy_path
|
||||
local M = {}
|
||||
|
||||
--- Get the current buffer's file path. Returns nil if not a file buffer.
|
||||
---@return string|nil
|
||||
function M.bufpath()
|
||||
local name = vim.api.nvim_buf_get_name(0)
|
||||
return name ~= "" and LazyVim.norm(name) or nil
|
||||
end
|
||||
|
||||
--- Absolute file path of the current buffer, normalized.
|
||||
--- Returns nil if not a file buffer.
|
||||
---@return string|nil
|
||||
function M.absolute()
|
||||
local p = M.bufpath()
|
||||
if not p then
|
||||
return nil
|
||||
end
|
||||
-- Expand to absolute (handles ~, .git worktrees, etc.) and normalize
|
||||
return LazyVim.norm(vim.fn.expand(p)) or p
|
||||
end
|
||||
|
||||
--- Parent directory of the current buffer's file.
|
||||
--- Returns nil if not a file buffer.
|
||||
---@return string|nil
|
||||
function M.directory()
|
||||
local p = M.absolute()
|
||||
if not p then
|
||||
return nil
|
||||
end
|
||||
return vim.fs.dirname(p) .. "/"
|
||||
end
|
||||
|
||||
--- File path relative to project root.
|
||||
--- Returns the filename alone if at the project root.
|
||||
--- Returns nil if not a file buffer.
|
||||
---@return string|nil
|
||||
function M.relative()
|
||||
local abs = M.absolute()
|
||||
if not abs then
|
||||
return nil
|
||||
end
|
||||
-- LazyVim.root() can fail in headless/unusual contexts; fall back to absolute
|
||||
local ok, root = pcall(LazyVim.root)
|
||||
if not ok then
|
||||
return abs
|
||||
end
|
||||
-- Ensure root ends with / for consistent string matching
|
||||
if root:sub(-1) ~= "/" then
|
||||
root = root .. "/"
|
||||
end
|
||||
if abs:find(root, 1, true) == 1 then
|
||||
return abs:sub(#root + 1)
|
||||
end
|
||||
-- Not under project root — fall back to absolute
|
||||
return abs
|
||||
end
|
||||
|
||||
--- Filename of current buffer (with extension).
|
||||
--- Returns nil if not a file buffer.
|
||||
---@return string|nil
|
||||
function M.filename()
|
||||
local p = M.bufpath()
|
||||
if not p then
|
||||
return nil
|
||||
end
|
||||
return vim.fs.basename(p)
|
||||
end
|
||||
|
||||
--- Filename of current buffer (without extension).
|
||||
--- Returns nil if not a file buffer.
|
||||
---@return string|nil
|
||||
function M.filename_no_ext()
|
||||
local name = M.filename()
|
||||
if not name then
|
||||
return nil
|
||||
end
|
||||
-- Remove extension (everything after the last dot)
|
||||
local base, ext = name:match("^(.*)%.([^.]*)$")
|
||||
if base and ext then
|
||||
return base
|
||||
end
|
||||
return name -- no extension to strip
|
||||
end
|
||||
|
||||
--- Current line number (1-based).
|
||||
---@return integer
|
||||
function M.line_number()
|
||||
local pos = vim.api.nvim_win_get_cursor(0)
|
||||
return pos[1]
|
||||
end
|
||||
|
||||
--- Current column number (1-based, character offset from start of line).
|
||||
---@return integer
|
||||
function M.column_number()
|
||||
local pos = vim.api.nvim_win_get_cursor(0)
|
||||
-- nvim_win_get_cursor returns 0-based column; convert to 1-based
|
||||
return pos[2] + 1
|
||||
end
|
||||
|
||||
--- Git root directory, or project root as fallback.
|
||||
---@return string
|
||||
function M.project_root()
|
||||
-- LazyVim.root.git() can fail in headless/unusual contexts; fall back to cwd
|
||||
local ok, root = pcall(LazyVim.root.git)
|
||||
if not ok then
|
||||
return vim.uv.cwd() .. "/"
|
||||
end
|
||||
return root .. "/"
|
||||
end
|
||||
|
||||
--- Append ":line" to the given path.
|
||||
---@param path string
|
||||
---@return string
|
||||
function M.with_line(path)
|
||||
return path .. ":" .. M.line_number()
|
||||
end
|
||||
|
||||
--- Append ":line:column" to the given path.
|
||||
---@param path string
|
||||
---@return string
|
||||
function M.with_column(path)
|
||||
return path .. ":" .. M.column_number()
|
||||
end
|
||||
|
||||
--- Copy text to system clipboard and print it via notification.
|
||||
--- If the buffer has no associated file, shows a warning instead.
|
||||
---@param get_path fun(): string|nil Function that returns the path string or nil
|
||||
---@param desc string Description for the notification title and which-key
|
||||
function M.copy(get_path, desc)
|
||||
local text = get_path()
|
||||
if not text then
|
||||
LazyVim.warn("Current buffer is not attached to a file!", { title = "Copy Path" })
|
||||
return
|
||||
end
|
||||
-- Write to system clipboard (+ register), character mode for clean copy
|
||||
vim.fn.setreg("+", text, "c")
|
||||
-- Print the copied value for user feedback
|
||||
LazyVim.info("Copied: " .. text, { title = desc })
|
||||
end
|
||||
|
||||
-- ─── Convenience functions that wire up specific path representations ───
|
||||
|
||||
--- Copy relative-to-project file path + line + column.
|
||||
M.copy_relative_with_line_column = function()
|
||||
M.copy(function()
|
||||
return M.with_column(M.with_line(M.relative()))
|
||||
end, "Copy Path (relative + line:col)")
|
||||
end
|
||||
|
||||
--- Copy relative-to-project file path + line number.
|
||||
M.copy_relative_with_line = function()
|
||||
M.copy(function()
|
||||
return M.with_line(M.relative())
|
||||
end, "Copy Path (relative + line)")
|
||||
end
|
||||
|
||||
--- Copy relative-to-project file path only.
|
||||
M.copy_relative = function()
|
||||
M.copy(function()
|
||||
return M.relative()
|
||||
end, "Copy Path (relative)")
|
||||
end
|
||||
|
||||
--- Copy relative-to-project directory.
|
||||
M.copy_relative_directory = function()
|
||||
M.copy(function()
|
||||
local rel = M.relative()
|
||||
if not rel then
|
||||
return nil
|
||||
end
|
||||
return vim.fs.dirname(rel) .. "/"
|
||||
end, "Copy Directory (relative)")
|
||||
end
|
||||
|
||||
--- Copy absolute file path + line + column.
|
||||
M.copy_absolute_with_line_column = function()
|
||||
M.copy(function()
|
||||
return M.with_column(M.with_line(M.absolute()))
|
||||
end, "Copy Path (absolute + line:col)")
|
||||
end
|
||||
|
||||
--- Copy absolute file path + line number.
|
||||
M.copy_absolute_with_line = function()
|
||||
M.copy(function()
|
||||
return M.with_line(M.absolute())
|
||||
end, "Copy Path (absolute + line)")
|
||||
end
|
||||
|
||||
--- Copy absolute file path only.
|
||||
M.copy_absolute = function()
|
||||
M.copy(function()
|
||||
return M.absolute()
|
||||
end, "Copy Path (absolute)")
|
||||
end
|
||||
|
||||
--- Copy absolute directory.
|
||||
M.copy_absolute_directory = function()
|
||||
M.copy(function()
|
||||
return M.directory()
|
||||
end, "Copy Directory (absolute)")
|
||||
end
|
||||
|
||||
--- Copy project (git root) directory.
|
||||
M.copy_project = function()
|
||||
M.copy(function()
|
||||
return M.project_root()
|
||||
end, "Copy Project Root")
|
||||
end
|
||||
|
||||
--- Copy filename with extension.
|
||||
M.copy_filename = function()
|
||||
M.copy(function()
|
||||
return M.filename()
|
||||
end, "Copy Filename")
|
||||
end
|
||||
|
||||
--- Copy filename without extension.
|
||||
M.copy_filename_no_ext = function()
|
||||
M.copy(function()
|
||||
return M.filename_no_ext()
|
||||
end, "Copy Filename (no ext)")
|
||||
end
|
||||
|
||||
return M
|
||||
336
tests/util/copy_path_spec.lua
Normal file
336
tests/util/copy_path_spec.lua
Normal file
|
|
@ -0,0 +1,336 @@
|
|||
---@module "luassert"
|
||||
|
||||
-- Ensure LazyVim global is available for copy_path module
|
||||
_G.LazyVim = _G.LazyVim or require("lazyvim.util")
|
||||
|
||||
local copy_path = require("lazyvim.util.copy_path")
|
||||
|
||||
describe("copy_path", function()
|
||||
-- Create a temporary file and switch to it for tests that need a real buffer.
|
||||
local tmpdir, tmppath ---@type string, string
|
||||
local old_buf ---@type number|nil
|
||||
|
||||
before_each(function()
|
||||
tmpdir = os.tmpname()
|
||||
vim.fn.delete(tmpdir) -- remove the file so we can mkdir
|
||||
vim.fn.mkdir(tmpdir, "p")
|
||||
tmppath = tmpdir .. "/test_file.lua"
|
||||
-- Write enough lines so cursor positioning works reliably
|
||||
local f = io.open(tmppath, "w")
|
||||
if f then
|
||||
f:write("-- line 1\n-- line 2\nlocal x = 42\n-- line 4\n-- line 5\n")
|
||||
f:close()
|
||||
end
|
||||
|
||||
-- Open the file in a new buffer and make it current
|
||||
old_buf = vim.api.nvim_get_current_buf()
|
||||
local buf = vim.fn.bufadd(tmppath)
|
||||
vim.fn.bufload(buf)
|
||||
vim.api.nvim_set_current_buf(buf)
|
||||
|
||||
-- Set cursor to line 3, column 5 (0-based: row=2, col=4) for predictable tests
|
||||
-- "local x = 42" — column 5 is the 'x' character
|
||||
vim.api.nvim_win_set_cursor(0, { 3, 4 })
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
if old_buf and vim.fn.bufexists(old_buf) == 1 then
|
||||
pcall(vim.api.nvim_set_current_buf, old_buf)
|
||||
end
|
||||
-- Cleanup temp file and dir
|
||||
pcall(vim.fn.delete, tmppath)
|
||||
pcall(vim.fn.delete, tmpdir)
|
||||
end)
|
||||
|
||||
describe("bufpath", function()
|
||||
it("returns the buffer name for a file buffer", function()
|
||||
local p = copy_path.bufpath()
|
||||
assert.is_not_nil(p)
|
||||
assert.truthy(p:find("test_file.lua"))
|
||||
end)
|
||||
|
||||
it("returns nil for non-file buffers", function()
|
||||
local scratch = vim.api.nvim_create_buf(false, true)
|
||||
vim.api.nvim_set_current_buf(scratch)
|
||||
assert.is_nil(copy_path.bufpath())
|
||||
vim.api.nvim_set_current_buf(vim.fn.bufnr(tmppath))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("absolute", function()
|
||||
it("returns the normalized absolute path of the current buffer", function()
|
||||
local p = copy_path.absolute()
|
||||
assert.is_not_nil(p)
|
||||
if LazyVim.is_win() then
|
||||
assert.truthy(p:match("^%a:") ~= nil)
|
||||
else
|
||||
assert.are.equal(string.sub(p, 1, 1), "/")
|
||||
end
|
||||
assert.truthy(p:find("test_file.lua"))
|
||||
end)
|
||||
|
||||
it("returns nil for non-file buffers", function()
|
||||
local scratch = vim.api.nvim_create_buf(false, true)
|
||||
vim.api.nvim_set_current_buf(scratch)
|
||||
assert.is_nil(copy_path.absolute())
|
||||
vim.api.nvim_set_current_buf(vim.fn.bufnr(tmppath))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("directory", function()
|
||||
it("returns the parent directory with trailing slash", function()
|
||||
local d = copy_path.directory()
|
||||
assert.is_not_nil(d)
|
||||
assert.are.equal(string.sub(d, -1), "/")
|
||||
assert.truthy(d:find(tmpdir))
|
||||
end)
|
||||
|
||||
it("returns nil for non-file buffers", function()
|
||||
local scratch = vim.api.nvim_create_buf(false, true)
|
||||
vim.api.nvim_set_current_buf(scratch)
|
||||
assert.is_nil(copy_path.directory())
|
||||
vim.api.nvim_set_current_buf(vim.fn.bufnr(tmppath))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("relative", function()
|
||||
it("returns a path containing the filename (relative if possible, absolute as fallback)", function()
|
||||
local r = copy_path.relative()
|
||||
assert.is_not_nil(r)
|
||||
-- In headless test mode LazyVim.root() may be unavailable, so relative falls back to absolute.
|
||||
-- Either way the result should contain the filename.
|
||||
assert.truthy(r:find("test_file.lua"))
|
||||
end)
|
||||
|
||||
it("returns nil for non-file buffers", function()
|
||||
local scratch = vim.api.nvim_create_buf(false, true)
|
||||
vim.api.nvim_set_current_buf(scratch)
|
||||
assert.is_nil(copy_path.relative())
|
||||
vim.api.nvim_set_current_buf(vim.fn.bufnr(tmppath))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("filename", function()
|
||||
it("returns the filename with extension", function()
|
||||
assert.are.equal(copy_path.filename(), "test_file.lua")
|
||||
end)
|
||||
|
||||
it("returns nil for non-file buffers", function()
|
||||
local scratch = vim.api.nvim_create_buf(false, true)
|
||||
vim.api.nvim_set_current_buf(scratch)
|
||||
assert.is_nil(copy_path.filename())
|
||||
vim.api.nvim_set_current_buf(vim.fn.bufnr(tmppath))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("filename_no_ext", function()
|
||||
it("returns the filename without extension", function()
|
||||
assert.are.equal(copy_path.filename_no_ext(), "test_file")
|
||||
end)
|
||||
|
||||
it("returns the full name when there is no extension", function()
|
||||
local noext_path = tmpdir .. "/README"
|
||||
local f = io.open(noext_path, "w")
|
||||
if f then f:write("no ext"); f:close() end
|
||||
local buf2 = vim.fn.bufadd(noext_path)
|
||||
vim.fn.bufload(buf2)
|
||||
vim.api.nvim_set_current_buf(buf2)
|
||||
assert.are.equal(copy_path.filename_no_ext(), "README")
|
||||
vim.api.nvim_set_current_buf(vim.fn.bufnr(tmppath))
|
||||
pcall(vim.fn.delete, noext_path)
|
||||
end)
|
||||
|
||||
it("returns nil for non-file buffers", function()
|
||||
local scratch = vim.api.nvim_create_buf(false, true)
|
||||
vim.api.nvim_set_current_buf(scratch)
|
||||
assert.is_nil(copy_path.filename_no_ext())
|
||||
vim.api.nvim_set_current_buf(vim.fn.bufnr(tmppath))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("line_number and column_number", function()
|
||||
it("returns the current line number (1-based)", function()
|
||||
-- Cursor was set to row 2 (0-based) = line 3 in before_each
|
||||
assert.are.equal(copy_path.line_number(), 3)
|
||||
end)
|
||||
|
||||
it("returns the current column number (1-based)", function()
|
||||
-- Cursor was set to col 4 (0-based) = column 5 in before_each
|
||||
assert.are.equal(copy_path.column_number(), 5)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("with_line", function()
|
||||
it("appends ':line' to the path", function()
|
||||
local p = copy_path.absolute() .. ":3" -- line was set to 3 in before_each
|
||||
local result = copy_path.with_line(copy_path.absolute())
|
||||
assert.are.equal(result, p)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("with_column", function()
|
||||
it("appends ':line:column' to the path", function()
|
||||
local base = copy_path.absolute() .. ":3" -- line 3 from before_each
|
||||
local result = copy_path.with_column(base)
|
||||
assert.are.equal(result, base .. ":5") -- column 5 from before_each
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("project_root", function()
|
||||
it("returns the git root with trailing slash or cwd fallback", function()
|
||||
local ok, p = pcall(copy_path.project_root)
|
||||
-- In headless test mode LazyVim.root.git() may fail, so we accept either outcome.
|
||||
-- If it succeeds, the result should be a non-empty string ending with /
|
||||
if not ok then
|
||||
return -- skip assertion in headless mode where root detection fails
|
||||
end
|
||||
assert.is_not_nil(p)
|
||||
assert.are.equal(string.sub(p, -1), "/")
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("copy (clipboard + notify)", function()
|
||||
it("copies text to the system clipboard and notifies", function()
|
||||
-- Mock vim.notify so we can capture the message
|
||||
local notified = false
|
||||
local notify_msg = ""
|
||||
_G.original_notify = vim.notify
|
||||
vim.notify = function(msg, level, opts)
|
||||
notified = true
|
||||
notify_msg = msg or ""
|
||||
end
|
||||
|
||||
-- Mock vim.fn.setreg to capture clipboard writes (works in headless CI)
|
||||
local setreg_called = false
|
||||
local captured_reg, captured_text, captured_mode ---@type boolean, string|nil, string|nil, string|nil
|
||||
_G.original_setreg = vim.fn.setreg
|
||||
vim.fn.setreg = function(reg, text, mode)
|
||||
setreg_called = true
|
||||
captured_reg = reg
|
||||
captured_text = text
|
||||
captured_mode = mode
|
||||
end
|
||||
|
||||
copy_path.copy(function() return "test/path.lua" end, "Test Copy")
|
||||
assert.is_true(notified, "vim.notify should have been called")
|
||||
assert.truthy(notify_msg:find("Copied:"), "Notification should contain 'Copied:'")
|
||||
assert.truthy(notify_msg:find("test/path.lua"), "Notification should contain the path")
|
||||
|
||||
-- Check clipboard was written via setreg mock (reliable in headless CI)
|
||||
assert.is_true(setreg_called, "vim.fn.setreg should have been called")
|
||||
assert.are.equal(captured_reg, "+", "Should write to system register (+)")
|
||||
assert.are.equal(captured_text, "test/path.lua", "System clipboard should contain the path")
|
||||
|
||||
-- Restore mocks
|
||||
vim.notify = _G.original_notify
|
||||
_G.original_notify = nil
|
||||
vim.fn.setreg = _G.original_setreg
|
||||
_G.original_setreg = nil
|
||||
end)
|
||||
|
||||
it("warns when buffer has no file (get_path returns nil)", function()
|
||||
local warned = false
|
||||
_G.original_warn = LazyVim.warn
|
||||
LazyVim.warn = function(msg, opts)
|
||||
warned = true
|
||||
end
|
||||
|
||||
copy_path.copy(function() return nil end, "Test Copy")
|
||||
assert.is_true(warned, "Should warn when path is nil")
|
||||
|
||||
LazyVim.warn = _G.original_warn
|
||||
_G.original_warn = nil
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("convenience functions", function()
|
||||
it("copy_absolute writes the absolute path to clipboard and notifies", function()
|
||||
-- Mock vim.notify so we can capture the message
|
||||
local notified = false
|
||||
_G.original_notify = vim.notify
|
||||
vim.notify = function(msg, level, opts)
|
||||
notified = true
|
||||
end
|
||||
|
||||
-- Mock vim.fn.setreg to capture clipboard writes (works in headless CI)
|
||||
local captured_text ---@type string|nil
|
||||
_G.original_setreg = vim.fn.setreg
|
||||
vim.fn.setreg = function(reg, text, mode)
|
||||
captured_text = text
|
||||
end
|
||||
|
||||
copy_path.copy_absolute()
|
||||
assert.is_true(notified)
|
||||
|
||||
-- Check clipboard via setreg mock (reliable in headless CI)
|
||||
if LazyVim.is_win() then
|
||||
assert.truthy(captured_text:match("^%a:") ~= nil or captured_text:find("test_file.lua"))
|
||||
else
|
||||
assert.truthy(string.sub(captured_text, 1, 1) == "/" and captured_text:find("test_file.lua"))
|
||||
end
|
||||
|
||||
-- Restore mocks
|
||||
vim.notify = _G.original_notify
|
||||
_G.original_notify = nil
|
||||
vim.fn.setreg = _G.original_setreg
|
||||
_G.original_setreg = nil
|
||||
end)
|
||||
|
||||
it("copy_relative_with_line_column appends line:column", function()
|
||||
-- In headless mode LazyVim.root() may fail. If relative path falls back to
|
||||
-- absolute (which is valid per the module logic), we still get :line:col appended.
|
||||
local captured_text = ""
|
||||
_G.original_notify = vim.notify
|
||||
vim.notify = function(msg, level, opts)
|
||||
captured_text = msg or ""
|
||||
end
|
||||
|
||||
copy_path.copy_relative_with_line_column()
|
||||
-- Should contain :line:col at the end regardless of whether path was relative or absolute
|
||||
assert.truthy(captured_text:find(":%d+:%d+$"), "Should end with :line:col")
|
||||
|
||||
vim.notify = _G.original_notify
|
||||
_G.original_notify = nil
|
||||
end)
|
||||
|
||||
it("copy_filename writes just the filename", function()
|
||||
local captured_text = ""
|
||||
_G.original_notify = vim.notify
|
||||
vim.notify = function(msg, level, opts)
|
||||
captured_text = msg or ""
|
||||
end
|
||||
|
||||
copy_path.copy_filename()
|
||||
assert.truthy(captured_text:find("test_file.lua"))
|
||||
|
||||
vim.notify = _G.original_notify
|
||||
_G.original_notify = nil
|
||||
end)
|
||||
|
||||
it("copy_filename_no_ext writes the filename without extension", function()
|
||||
local notify_text = ""
|
||||
_G.original_notify = vim.notify
|
||||
vim.notify = function(msg, level, opts)
|
||||
notify_text = msg or ""
|
||||
end
|
||||
|
||||
-- Mock vim.fn.setreg to capture clipboard writes (works in headless CI)
|
||||
local captured_text ---@type string|nil
|
||||
_G.original_setreg = vim.fn.setreg
|
||||
vim.fn.setreg = function(reg, text, mode)
|
||||
captured_text = text
|
||||
end
|
||||
|
||||
copy_path.copy_filename_no_ext()
|
||||
assert.truthy(notify_text:find("test_file"))
|
||||
-- Should NOT contain .lua in the copied register
|
||||
assert.falsy(captured_text:find("%.lua"), "Clipboard should not contain extension")
|
||||
|
||||
-- Restore mocks
|
||||
vim.notify = _G.original_notify
|
||||
_G.original_notify = nil
|
||||
vim.fn.setreg = _G.original_setreg
|
||||
_G.original_setreg = nil
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
Loading…
Add table
Reference in a new issue