Luigit
repositories / dotfiles

dotfiles

bugabingas dorkfiles

owned by admin

neovim/lua/std/rename.lua

Raw
-- stolen from https://github.com/folke/snacks.nvim/blob/main/lua/snacks/rename.lua

--- Lets LSP clients know that a file has been renamed
---@param from string
---@param to string
---@param rename? fun()
local function on_rename_file(from, to, rename)
  local changes = {
    files = { {
      oldUri = vim.uri_from_fname(from),
      newUri = vim.uri_from_fname(to),
    } }
  }

  local clients = vim.lsp.get_clients { bufnr = 0 }
  for _, client in ipairs(clients) do
    if client:supports_method("workspace/willRenameFiles") then
      local resp = client:request_sync("workspace/willRenameFiles", changes, 1000, 0)
      if resp and resp.result ~= nil then
        vim.lsp.util.apply_workspace_edit(resp.result, client.offset_encoding)
      end
    end
  end

  if rename then
    rename()
  end

  for _, client in ipairs(clients) do
    if client:supports_method("workspace/didRenameFiles") then
      client:notify("workspace/didRenameFiles", changes)
    end
  end
end

--- Rename a file and update buffers
---@param from string
---@param to string
---@return boolean ok
local function _rename(from, to)
  from = vim.fn.fnamemodify(from, ":p")
  to = vim.fn.fnamemodify(to, ":p")
  -- rename the file
  local ret = vim.fn.rename(from, to)
  if ret ~= 0 then
    vim.notify("Failed to rename file: `" .. from .. "`", vim.log.levels.ERROR)
    return false
  end

  -- replace buffer in all windows
  local from_buf = vim.fn.bufnr(from)
  if from_buf >= 0 then
    local to_buf = vim.fn.bufadd(to)
    vim.bo[to_buf].buflisted = true
    for _, win in ipairs(vim.fn.win_findbuf(from_buf)) do
      vim.api.nvim_win_call(win, function()
        vim.cmd("buffer " .. to_buf)
      end)
    end
    vim.api.nvim_buf_delete(from_buf, { force = true })
  end
  return true
end

-- Renames the provided file, or the current buffer's file.
-- Prompt for the new filename if `to` is not provided.
-- do the rename, and trigger LSP handlers
---@param opts? {from?: string, to?:string, file?:string, on_rename?: fun(to:string, from:string, ok:boolean)}
local function rename_file(opts)
  opts = opts or {}
  local from = vim.fn.fnamemodify(opts.from or opts.file or vim.api.nvim_buf_get_name(0), ":p")
  local to = opts.to and vim.fn.fnamemodify(opts.to, ":p") or nil

  local function rename()
    assert(to, "to is required")
    on_rename_file(from, to, function()
      local ok = _rename(from, to)
      if opts.on_rename then
        opts.on_rename(to, from, ok)
      end
    end)
  end

  if to then
    return rename()
  end

  local root = vim.fn.getcwd()

  if from:find(root, 1, true) ~= 1 then
    root = vim.fn.fnamemodify(from, ":p:h")
  end

  local extra = from:sub(#root + 2)

  vim.ui.input({
    prompt = "New File Name: ",
    default = extra,
    completion = "file",
  }, function(value)
    if not value or value == "" or value == extra then
      return
    end
    to = vim.fs.normalize(root .. "/" .. value)
    rename()
  end)
end

return {
  rename_file = rename_file,
  on_rename_file = on_rename_file,
}