Neovim Buffer Filename Operations

Posted on:June 25, 2024

Using lua to perform operations on neovim buffers. Specifically, showcasing operations related to using a buffer’s filename. By the end of this post, I will have showcased: copying all current buffers (w/ filenames), copying the current buffers filename, expanding a buffers filename to it’s absolute path, and formatting output from the lua code showcased here, so that it’s useful in a shell enviornment.

Motivation

I tend to have many open buffers when I program in neovim. In particularly nested project structures, I commonly run into the issue of where were all those files I was just editing? While I can certainly go find the files (most of the time), having their names accessible to my system’s clipboard signifcantly improves text-editing efficiency.

Simply Copying a File’s buffer name in Lua/Vim

If you’re not very experienced or haven’t ever cared to read vim/neovim’s manual, than the ‘simple’ operation

referred to above, might not be very straightforward. The demo below shows one possible method for implementing this operation.

local filename = vim.api.nvim_buf_get_name(0) -- `:lua print(vim.api.nvim_buf_get_name(0))`
local absolute_path = vim.fn.expand('%:p') -- `:lua print(vim.fn.expand('%p'))`
--- in vimscript this is made simple by the much shorter command, `:echo expand('%:p')`

Writing a function to copy all open filenames

local function copy_filenames_to_clipboard()
  -- Get the list of all open buffers
  local buffers = vim.api.nvim_list_bufs()
  local filenames = {}

  -- Loop through each buffer
  for _, buf in ipairs(buffers) do
    -- Check if the buffer is loaded and has a filename
    if vim.api.nvim_buf_is_loaded(buf) and vim.api.nvim_buf_get_name(buf) ~= "" then
      -- Get the expanded file name and add it to the list
      table.insert(filenames, vim.fn.fnamemodify(vim.api.nvim_buf_get_name(buf), ":p"))
    end
  end

  -- Join filenames with newline
  local result = table.concat(filenames, clipboard_item_seperator)

  -- Copy to clipboard
  vim.fn.setreg('+', result)
  print("Copied filenames to clipboard!")
end

Writing a function to copy a files absolute path

local function copy_abs_path_to_clipboard()
  local fn = vim.fn.expand('%:p')
  vim.api.nvim_exec("!echo -n "..fn.." | copy-to-clip", true)
  print('Copied to absolute filepath clipboard: ' .. fn ..'')
end

Binding a function to a user command

We can call local functions from a vimscript user command, by modifying the example below.

local function hello_from_file()
  local fn = vim.fn.expand('%:p')
  print('Hello from file: ' .. fn ..'')
end

vim.api.nvim_create_user_command('HelloFromFile', hello_from_file, {})

After sourcing this snippet to the init.lua/init.vim configuration of neovim, we can execute the command :HelloFromFile. You could also improve on this general example, by binding the normal mode input <cmd>HelloFromFile<cr> to a keybind.

Putting it all together

Now, we can write a file that encapsulates all of the relevant ideas and make sure to require it in our ~/.config/nvim/init.lua configuration. Where this file is defined is entirely up to the user’s preference.

local clipboard_item_seperator = '\n' -- examples include: ' ' | ',' | '\n' | string

local function copy_filenames_to_clipboard()
  -- Get the list of all open buffers
  local buffers = vim.api.nvim_list_bufs()
  local filenames = {}

  -- Loop through each buffer
  for _, buf in ipairs(buffers) do
    -- Check if the buffer is loaded and has a filename
    if vim.api.nvim_buf_is_loaded(buf) and vim.api.nvim_buf_get_name(buf) ~= "" then
      -- Get the expanded file name and add it to the list
      table.insert(filenames, vim.fn.fnamemodify(vim.api.nvim_buf_get_name(buf), ":p"))
    end
  end

  -- Join filenames with newline
  local result = table.concat(filenames, clipboard_item_seperator)

  -- Copy to clipboard
  vim.fn.setreg('+', result)
  print("Copied filenames to clipboard!")
end

local function copy_abs_path_to_clipboard()
  local fn = vim.fn.expand('%:p')
  vim.api.nvim_exec("!echo -n "..fn.." | copy-to-clip", true)
  print('Copied to absolute filepath clipboard: ' .. fn ..'')
end

--- Create a command to call the function
vim.api.nvim_create_user_command('CopyFilenamesToClipboard', copy_filenames_to_clipboard, {})
vim.api.nvim_create_user_command('CopyAbsolutePathToClipboard',  copy_abs_path_to_clipboard, {})

Conclusion

The post above is meant to display simple method for familiarizing newcomers to neovim’s lua runtime. While remaining relatively straightforward, user’s can replicate the behavior achieved without needing any external decencies/plugins.

Here is a gist that includes a complete example.

Join the Newsletter!