olimorris / persisted.nvim

💾 Simple session management for Neovim with git branching, autoloading and Telescope support
MIT License
418 stars 24 forks source link

`string.gsub(session, save_dir, "")` will fail if special characters are not escaped #57

Closed dstanberry closed 1 year ago

dstanberry commented 1 year ago

https://github.com/olimorris/persisted.nvim/blob/03f11b519fc4b47a1be96f2f22710b5df0ced539/lua/persisted/utils.lua#L52-L60

https://github.com/olimorris/persisted.nvim/blob/fb8b3b4f112314be5ddd1d926af722fbe8840918/lua/persisted/init.lua#L200-L235

:gsub(save_dir, "") can fail if session or save_dir contains lua special characters. There's an explanation on s/o about this with a nifty function to handle the substitution: https://stackoverflow.com/a/29379912

The following change works for me and includes an improvement to get the paths displayed properly on windows os:

local function replace(str, what, with, repl)
    what = string.gsub(what, "[%(%)%.%+%-%*%?%[%]%^%$%%]", "%%%1") -- escape pattern
    with = string.gsub(with, "[%%]", "%%%%") -- escape replacement
    return string.gsub(str, what, with, repl)
end

---List all of the sessions
---@return table
function M.list()
  local save_dir = config.options.save_dir
  local session_files = vim.fn.glob(save_dir .. "*.vim", true, true)
  local branch_separator = config.options.branch_separator

  local sessions = {}
  for _, session in pairs(session_files) do
    local session_name = replace(session, save_dir, "")
      -- :gsub(save_dir, "")
      :gsub("%%", utils.get_dir_pattern())
      :gsub(vim.fn.expand("~"), utils.get_dir_pattern())
      :gsub("//", "")
      :gsub("//", "")
      :sub(1, -5)

      if vim.fn.has("win32") == 1 then
        -- format drive letter (no trailing separator)
        session_name = replace(session_name, utils.get_dir_pattern(), ":", 1)
        -- format filepath separator
        session_name = replace(session_name, utils.get_dir_pattern(), "\\")
      end

    local branch, dir_path

    if string.find(session_name, branch_separator, 1, true) then
      local splits = vim.split(session_name, branch_separator, { plain = true })
      branch = table.remove(splits, #splits)
      dir_path = vim.fn.join(splits, branch_separator)
    else
      dir_path = session_name
    end

    table.insert(sessions, {
      ["name"] = session_name,
      ["file_path"] = session,
      ["branch"] = branch,
      ["dir_path"] = dir_path,
    })
  end
  return sessions
end

If this is acceptable, I can submit a PR.

olimorris commented 1 year ago

This is absolutely acceptable 😄 and I welcome a PR.

dstanberry commented 1 year ago

Submitted #58.

olimorris commented 1 year ago

Approved and merged. Thanks again for this. A really awesome PR.