Search code examples
luaeditorcloneneovim

Clone buffer function in Neovim


I have been trying to create a Lua function that allows me to clone a Neovim buffer. Here is what I have in my init.lua file:

-- Set max optimum columns
vim.opt.colorcolumn = "80"
-- function to clone buffers
Clone_buffer = function()
  local rfp = vim.fn.expand("%:h")
  local  ft = vim.bo.filetype
  vim.cmd(string.format("%s" .. "/copy" .. ".%s", rfp, ft))
end

I have mapped it but every time I use it I get the next error:

E5108: Error executing lua vim/_editor.lua:0: nvim_exec2(): Vim(lua):E5107: Error loading lua [string ":lua"]:1: unexpected symbol near '/'
stack traceback:
        [C]: in function 'nvim_exec2'
        vim/_editor.lua: in function 'cmd'
        ~/.config/nvim/lua/custom/init.lua:7: in function 'Clone_buffer'
        [string ":lua"]:1: in main chunk

I don't know what unexpected symbol near '/' means. If anyone can help me I would appreciate it.

I have also tried changing "/copy" to "copy" but the same exception is raised, so I assume it has something to do with rfp and ft variables.


Solution

  • It's not clear how you intend to select which buffer to clone, nor where you want the cloned (copied) version to go. I'll assume that you want to clone the current buffer and output the contents to a duplicate file in the same directory as the file open in the current buffer. Upon pressing Alt+d, the following solution:

    1. Gets the current buffer number, name and its content.
    2. Increments the current buffer's name until a unique one is found.
    3. Writes the content of the current buffer to the unique "cloned" name.
    4. Prints a completion message showing the location of the cloned file.
    local function inc_file_name_until_unique(path_to_file)
        -- Get the file name (with extension)
        local file_name = string.match(path_to_file, "[^/]+$")
        -- Get the file extension
        local file_ext = string.match(path_to_file, "[.][^.]+$")
        -- Get the file name (without extension) (use gsub to escape Lua magic characters with "%" symbol)
        local file_name_wo_ext = string.gsub(file_name, file_ext:gsub("%W", "%%%1"), "")
        -- Get the directory of the file (use gsub to escape Lua magic characters with "%" symbol)
        local file_path = string.gsub(path_to_file, file_name:gsub("%W", "%%%1"), "")
    
        local inc = 1
        -- Create new file name
        local new_file_name = file_path .. file_name_wo_ext .. "-clone" .. tostring(inc) .. file_ext
        -- Check new file name is unique, if not, increment its counter until it is
        while vim.fn.filereadable(new_file_name) == 1 do 
            inc = inc + 1
            new_file_name = file_path .. file_name_wo_ext .. "-clone" .. tostring(inc) .. file_ext
        end
        return new_file_name
    end
    
    local function clone_buffer()
        local curr_bufnr = vim.api.nvim_get_current_buf()
        local curr_buf_content = vim.api.nvim_buf_get_lines(curr_bufnr, 0, -1, false)
        local curr_buf_content_str = table.concat(curr_buf_content, "\n")
        local curr_buf_name = vim.api.nvim_buf_get_name(curr_bufnr)
        local clone_name = inc_file_name_until_unique(curr_buf_name)
        local clone_file = io.output(clone_name)
        clone_file:write(curr_buf_content_str)
        clone_file:close()
        vim.api.nvim_echo({{"Cloned current buffer to \"" .. clone_name .. "\""}}, false, {})
    end
    
    vim.keymap.set({'n'}, '<A-d>', '', { 
        callback = clone_buffer
    })