Repository: nvim-lua/plenary.nvim (lua)

Issue:
Picking a file to open outside the current directory can mangle the filename
### Description

Hello! :wave:

My `$HOME` is `/Users/mattr-` and I use [homeshick] to manage my [dotfiles]. I've created a mapping so that I can open my dotfiles from anywhere, but if I use this mapping from a path that's not in the directory tree of my dotfiles, the path that neovim opens is mangled and not what I expect. I've provided the best reproduction steps I can manage and hopefully this is reproducible and not reliant on the fact that my username is `mattr-`. 😅 

[homeshick]: https://github.com/andsens/homeshick
[dotfiles]: https://github.com/mattr-/dotfiles


### Neovim version

```markdown
NVIM v0.6.0-dev+2050-g2ef9d2a66
Build type: Release
LuaJIT 2.1.0-beta3
Compiled by mattr-@knid

Features: +acl +iconv +tui
See ":help feature-compile"

   system vimrc file: "$VIM/sysinit.vim"
  fall-back for $VIM: "/opt/homebrew/Cellar/neovim/HEAD-2ef9d2a_1/share/nvim"

Run :checkhealth for more info
```


### Operating system and version

macOS 11.6.1

### checkhealth telescope

```markdown
telescope: require("telescope.health").check()
========================================================================
## Checking for required plugins
  - OK: plenary installed.
  - OK: nvim-treesitter installed.

## Checking external dependencies
  - OK: rg: found ripgrep 13.0.0
  - OK: fd: found fd 8.2.1

## ===== Installed extensions =====

## Telescope Extension: `fzf`
  - INFO: No healthcheck provided
```


### Steps to reproduce

1. Create the following directory structure `~/.homesick/repos/dotfiles/home/.vim/after/ftplugin`:
```
mkdir -p ~/.homesick/repos/dotfiles/home/.vim/after/ftplugin
```
2. Put a markdown.vim file in the previously created directory with the following content (the mapping here isn't important. this is simply the contents of the file in my dotfiles repo)
```
setlocal tw=0 wrap nolist foldlevel=1 foldmethod=syntax

nmap ,mdp <Plug>MarkdownPreviewToggle
```
3. cd to `~/Downloads`
4. run the `,df` mapping from the minimal config and open the `markdown.vim` file

### Expected behavior

The file `~/.homesick/repos/dotfiles/home/.vim/after/ftplugin/markdown.vim` is loaded correctly

### Actual behavior

A blank file is loaded and the filename as seen on the minimal config statusline and by hitting `<Ctrl-g>` is
```
"~r-/.homesick/repos/dotfiles/home/.vim/after/ftplugin/markdown.vim" [New] --No lines in buffer--
```

### Minimal config

```Lua
vim.cmd [[set runtimepath=$VIMRUNTIME]]
vim.cmd [[set packpath=/tmp/nvim/site]]
local package_root = '/tmp/nvim/site/pack'
local install_path = package_root .. '/packer/start/packer.nvim'
local function load_plugins()
  require('packer').startup {
    {
      'wbthomason/packer.nvim',
      {
        'nvim-telescope/telescope.nvim',
        requires = {
          'nvim-lua/plenary.nvim',
          { 'nvim-telescope/telescope-fzf-native.nvim', run = 'make' },
        },
      },
      -- ADD PLUGINS THAT ARE _NECESSARY_ FOR REPRODUCING THE ISSUE
    },
    config = {
      package_root = package_root,
      compile_path = install_path .. '/plugin/packer_compiled.lua',
      display = { non_interactive = true },
    },
  }
end

function dotfiles()
  local themes = require('telescope.themes')
  local opts_with_preview

  opts_with_preview = themes.get_ivy {
    prompt_title = " dotfiles ",
    layout_config = {
      height = 15,
    },
    shorten_path = false,
    cwd = "~/.homesick/repos/dotfiles",
    hidden = true,
  }

  require("telescope.builtin").find_files(opts_with_preview)
end

_G.load_config = function()
  require('telescope').setup()
  require('telescope').load_extension('fzf')

  -- ADD INIT.LUA SETTINGS THAT ARE _NECESSARY_ FOR REPRODUCING THE ISSUE
end
if vim.fn.isdirectory(install_path) == 0 then
  print("Installing Telescope and dependencies.")
  vim.fn.system { 'git', 'clone', '--depth=1', 'https://github.com/wbthomason/packer.nvim', install_path }
end
load_plugins()
require('packer').sync()
vim.cmd [[autocmd User PackerComplete ++once echo "Ready!" | lua load_config()]]
vim.api.nvim_set_keymap("n", ",df", "<cmd>lua dotfiles()<CR>", { noremap = true, silent = true })
```

Pull request description:
This fixes https://github.com/nvim-telescope/telescope.nvim/issues/1521. The problem is that if $HOME directory contains trailing slash, then Path:normalize() will convert `/home/user/my_file` into `~my_file`.

Patch:
diff --git a/lua/plenary/path.lua b/lua/plenary/path.lua
index 9a1f52a6..17adde58 100644
--- a/lua/plenary/path.lua
+++ b/lua/plenary/path.lua
@@ -340,7 +340,7 @@ function Path:normalize(cwd)
   self:make_relative(cwd)
 
   -- Substitute home directory w/ "~"
-  self.filename = self.filename:gsub("^" .. path.home, "~", 1)
+  self.filename = self.filename:gsub("^" .. path.home, "~" .. path.sep, 1)
 
   return _normalize_path(self.filename, self._cwd)
 end


Test patch:
diff --git a/tests/plenary/path_spec.lua b/tests/plenary/path_spec.lua
index bba181f3..def3e931 100644
--- a/tests/plenary/path_spec.lua
+++ b/tests/plenary/path_spec.lua
@@ -205,6 +205,22 @@ describe("Path", function()
       p._cwd = "/tmp/lua"
       assert.are.same("/tmp/lua/plenary/path.lua", p:normalize())
     end)
+
+    it("can normalize ~ when file is within home directory (traling slash)", function()
+      local home = "/home/test/"
+      local p = Path:new { home, "./test_file" }
+      p.path.home = home
+      p._cwd = "/tmp/lua"
+      assert.are.same("~/./test_file", p:normalize())
+    end)
+
+    it("can normalize ~ when file is within home directory (no trailing slash)", function()
+      local home = "/home/test"
+      local p = Path:new { home, "./test_file" }
+      p.path.home = home
+      p._cwd = "/tmp/lua"
+      assert.are.same("~//./test_file", p:normalize())
+    end)
   end)
 
   describe(":shorten", function()