A Neovim plugin that provides convenient commands to copy (yank) file paths to the system clipboard. Supports various path formats including relative paths, absolute paths, and file names only.
- 🚀 Copy current file path in multiple formats (relative, absolute, from home, filename only)
- 🎯 Copy file paths relative to project root (auto-detects .git, package.json, etc.)
- 📍 Copy file paths with current line numbers for precise referencing
- 📁 Copy multiple buffer paths at once with customizable separators
- 🔧 Configurable root markers for project detection
- 📋 Automatic system clipboard integration
- 🔔 Visual feedback with notifications
- ⚙️ Runtime configuration support
- 📚 Comprehensive documentation and help files
- 🧪 Fully tested with comprehensive test suite
Using lazy.nvim
{
"neumachen/yank-file-path.nvim",
config = function()
require("yank-file-path").setup({
-- Optional: customize root markers for root-relative paths
root_markers = { ".git", ".hg", "package.json", "Cargo.toml", "pyproject.toml" }
})
end,
}
Or with minimal configuration:
{
"neumachen/yank-file-path.nvim",
-- Plugin loads automatically with default settings
}
Using packer.nvim
use {
"neumachen/yank-file-path.nvim",
config = function()
require("yank-file-path").setup({
-- Optional: customize root markers
root_markers = { ".git", "package.json", "go.mod" }
})
end
}
Or with minimal configuration:
use "neumachen/yank-file-path.nvim"
Using vim-plug
Plug 'neumachen/yank-file-path.nvim'
" Add to your init.lua or init.vim:
lua << EOF
require("yank-file-path").setup({
-- Optional: customize root markers
root_markers = { ".git", "package.json", "go.mod" }
})
EOF
Or with minimal configuration (uses defaults):
Plug 'neumachen/yank-file-path.nvim'
Command | Description | Example Output |
---|---|---|
:YankRelativeFilePath |
Copy relative file path | src/main.lua |
:YankAbsoluteFilePath |
Copy absolute file path | /home/user/project/src/main.lua |
:YankRelativeFilePathFromHome |
Copy path relative to home | ~/project/src/main.lua |
:YankFileName |
Copy just the filename | main.lua |
:YankRootRelativeFilePath |
Copy path relative to project root | src/main.lua |
:YankFilePath |
Alias for :YankRelativeFilePath |
src/main.lua |
Command | Description | Example Output |
---|---|---|
:YankRelativeFilePathWithLine |
Copy relative file path with line number | src/main.lua:42 |
:YankAbsoluteFilePathWithLine |
Copy absolute file path with line number | /home/user/project/src/main.lua:42 |
:YankRelativeFilePathFromHomeWithLine |
Copy path relative to home with line number | ~/project/src/main.lua:42 |
:YankFileNameWithLine |
Copy filename with line number | main.lua:42 |
:YankRootRelativeFilePathWithLine |
Copy path relative to project root with line number | src/main.lua:42 |
Command | Description | Default Separator |
---|---|---|
:YankAllRelativeFilePaths [separator] |
Copy all relative paths | space |
:YankAllAbsoluteFilePaths [separator] |
Copy all absolute paths | space |
:YankAllRelativeFilePathsFromHome [separator] |
Copy all paths from home | space |
:YankAllFileNames [separator] |
Copy all filenames | space |
:YankAllRootRelativeFilePaths [separator] |
Copy all root-relative paths | space |
" Copy current file's relative path
:YankRelativeFilePath
" Copy current file's absolute path
:YankAbsoluteFilePath
" Copy just the filename
:YankFileName
" Copy all relative paths separated by newlines
:YankAllRelativeFilePaths \n
" Copy all filenames separated by commas
:YankAllFileNames ,
" Copy all absolute paths separated by tabs
:YankAllAbsoluteFilePaths \t
\n
- newline character\t
- tab character- Any other string is used as-is (e.g.,
,
,|
, etc.)
You can create your own key mappings for frequently used commands:
-- Single file commands
vim.keymap.set('n', '<leader>yp', ':YankRelativeFilePath<CR>', { desc = 'Yank relative file path' })
vim.keymap.set('n', '<leader>yP', ':YankAbsoluteFilePath<CR>', { desc = 'Yank absolute file path' })
vim.keymap.set('n', '<leader>yh', ':YankRelativeFilePathFromHome<CR>', { desc = 'Yank path from home' })
vim.keymap.set('n', '<leader>yn', ':YankFileName<CR>', { desc = 'Yank filename only' })
vim.keymap.set('n', '<leader>yr', ':YankRootRelativeFilePath<CR>', { desc = 'Yank root-relative path' })
-- Single file commands with line numbers
vim.keymap.set('n', '<leader>ypl', ':YankRelativeFilePathWithLine<CR>', { desc = 'Yank relative path with line' })
vim.keymap.set('n', '<leader>yPl', ':YankAbsoluteFilePathWithLine<CR>', { desc = 'Yank absolute path with line' })
vim.keymap.set('n', '<leader>yhl', ':YankRelativeFilePathFromHomeWithLine<CR>', { desc = 'Yank path from home with line' })
vim.keymap.set('n', '<leader>ynl', ':YankFileNameWithLine<CR>', { desc = 'Yank filename with line' })
vim.keymap.set('n', '<leader>yrl', ':YankRootRelativeFilePathWithLine<CR>', { desc = 'Yank root-relative path with line' })
-- Multiple files commands
vim.keymap.set('n', '<leader>yap', ':YankAllRelativeFilePaths<CR>', { desc = 'Yank all relative paths' })
vim.keymap.set('n', '<leader>yaP', ':YankAllAbsoluteFilePaths<CR>', { desc = 'Yank all absolute paths' })
vim.keymap.set('n', '<leader>yan', ':YankAllFileNames<CR>', { desc = 'Yank all filenames' })
vim.keymap.set('n', '<leader>yar', ':YankAllRootRelativeFilePaths<CR>', { desc = 'Yank all root-relative paths' })
-- Copy all paths with newline separator
vim.keymap.set('n', '<leader>yanl', ':YankAllRelativeFilePaths \\n<CR>', { desc = 'Yank all paths (newlines)' })
-- Copy all paths with comma separator
vim.keymap.set('n', '<leader>yac', ':YankAllRelativeFilePaths ,<CR>', { desc = 'Yank all paths (commas)' })
-- Copy all filenames with tab separator
vim.keymap.set('n', '<leader>yant', ':YankAllFileNames \\t<CR>', { desc = 'Yank all filenames (tabs)' })
If you use which-key.nvim, you can organize the mappings:
local wk = require("which-key")
wk.register({
y = {
name = "Yank File Paths",
p = { ":YankRelativeFilePath<CR>", "Relative path" },
P = { ":YankAbsoluteFilePath<CR>", "Absolute path" },
h = { ":YankRelativeFilePathFromHome<CR>", "Path from home" },
n = { ":YankFileName<CR>", "Filename only" },
r = { ":YankRootRelativeFilePath<CR>", "Root-relative path" },
l = {
name = "With Line Numbers",
p = { ":YankRelativeFilePathWithLine<CR>", "Relative path with line" },
P = { ":YankAbsoluteFilePathWithLine<CR>", "Absolute path with line" },
h = { ":YankRelativeFilePathFromHomeWithLine<CR>", "Path from home with line" },
n = { ":YankFileNameWithLine<CR>", "Filename with line" },
r = { ":YankRootRelativeFilePathWithLine<CR>", "Root-relative path with line" },
},
a = {
name = "All Files",
p = { ":YankAllRelativeFilePaths<CR>", "All relative paths" },
P = { ":YankAllAbsoluteFilePaths<CR>", "All absolute paths" },
n = { ":YankAllFileNames<CR>", "All filenames" },
r = { ":YankAllRootRelativeFilePaths<CR>", "All root-relative paths" },
l = { ":YankAllRelativeFilePaths \\n<CR>", "All paths (newlines)" },
c = { ":YankAllRelativeFilePaths ,<CR>", "All paths (commas)" },
},
},
}, { prefix = "<leader>" })
The plugin works out of the box without any configuration. All commands are automatically available after the plugin is loaded.
You can customize the root markers used for root-relative path detection:
-- Using lazy.nvim
{
"neumachen/yank-file-path.nvim",
config = function()
require("yank-file-path").setup({
root_markers = { ".git", ".hg", "package.json", "Cargo.toml", "pyproject.toml" }
})
end,
}
-- Or call setup directly
require("yank-file-path").setup({
root_markers = { ".git", "package.json", "go.mod" }
})
The plugin comes with these default root markers:
.git
.hg
.svn
package.json
Cargo.toml
go.mod
pyproject.toml
Makefile
You can also change root markers at runtime:
require("yank-file-path").set_root_markers({ ".git", "custom.toml" })
The plugin uses vim.notify()
for user feedback:
- INFO level: Successful copy operations
- WARN level: Warnings (e.g., when no buffers are found)
The plugin includes comprehensive tests using plenary.nvim:
# Run all tests
nvim --headless -c "PlenaryBustedDirectory tests/ {minimal_init = 'tests/minimal_init.lua'}"
yank-file-path.nvim/
├── doc/
│ └── yank-file-path.txt # Vim help documentation
├── lua/
│ └── yank-file-path/
│ ├── init.lua # Main module entry point
│ ├── config.lua # Configuration management
│ ├── utils.lua # Core utility functions
│ └── commands.lua # User command definitions
├── plugin/
│ └── yank-file-path.lua # Plugin loader
├── tests/
│ ├── yank-file-path_spec.lua # Test suite
│ └── minimal_init.lua # Minimal init for testing
├── LICENSE # MIT License
└── README.md # This file
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
- Clone the repository
- Install plenary.nvim for testing
- Run tests to ensure everything works
- Make your changes
- Add tests for new functionality
- Ensure all tests pass
This project is licensed under the MIT License - see the LICENSE file for details.
- Inspired by the need for quick file path copying in Neovim workflows
- Built with modern Neovim Lua APIs
- Thanks to the Neovim community for excellent plugin development resources
If this plugin doesn't meet your needs, you might want to check out:
- nvim-tree.lua - File explorer with copy path functionality
- telescope.nvim - Fuzzy finder with path copying features
Happy yanking! 🎯