fix: expand/normalize paths more selectively (#2628)

This commit is contained in:
James Trew
2024-03-19 18:55:27 -04:00
committed by GitHub
parent c816406bd5
commit 3b8399c273
10 changed files with 64 additions and 24 deletions

View File

@@ -5,6 +5,7 @@ local log = require "plenary.log"
local async = require "plenary.async" local async = require "plenary.async"
local channel = require("plenary.async").control.channel local channel = require("plenary.async").control.channel
local utils = require "telescope.utils"
local M = {} local M = {}
@@ -21,7 +22,7 @@ function AsyncJob.new(opts)
self.stderr = opts.stderr or M.NullPipe() self.stderr = opts.stderr or M.NullPipe()
if opts.cwd and opts.cwd ~= "" then if opts.cwd and opts.cwd ~= "" then
self.uv_opts.cwd = vim.fn.expand(vim.fn.escape(opts.cwd, "$")) self.uv_opts.cwd = utils.path_expand(opts.cwd)
-- this is a "illegal" hack for windows. E.g. If the git command returns `/` rather than `\` as delimiter, -- this is a "illegal" hack for windows. E.g. If the git command returns `/` rather than `\` as delimiter,
-- vim.fn.expand might just end up returning an empty string. Weird -- vim.fn.expand might just end up returning an empty string. Weird
-- Because empty string is not allowed in libuv the job will not spawn. Solution is we just set it to opts.cwd -- Because empty string is not allowed in libuv the job will not spawn. Solution is we just set it to opts.cwd

View File

@@ -73,7 +73,7 @@ function histories.History:new(opts)
if conf.history.limit then if conf.history.limit then
obj.limit = conf.history.limit obj.limit = conf.history.limit
end end
obj.path = vim.fn.expand(conf.history.path) obj.path = utils.path_expand(conf.history.path)
obj.content = {} obj.content = {}
obj.index = 1 obj.index = 1
obj.cycle_wrap = conf.history.cycle_wrap obj.cycle_wrap = conf.history.cycle_wrap

View File

@@ -115,12 +115,12 @@ files.live_grep = function(opts)
end end
local search_dirs = opts.search_dirs local search_dirs = opts.search_dirs
local grep_open_files = opts.grep_open_files local grep_open_files = opts.grep_open_files
opts.cwd = opts.cwd and vim.fn.expand(opts.cwd) or vim.loop.cwd() opts.cwd = opts.cwd and utils.path_expand(opts.cwd) or vim.loop.cwd()
local filelist = get_open_filelist(grep_open_files, opts.cwd) local filelist = get_open_filelist(grep_open_files, opts.cwd)
if search_dirs then if search_dirs then
for i, path in ipairs(search_dirs) do for i, path in ipairs(search_dirs) do
search_dirs[i] = vim.fn.expand(path) search_dirs[i] = utils.path_expand(path)
end end
end end
@@ -246,7 +246,7 @@ files.grep_string = function(opts)
end end
elseif opts.search_dirs then elseif opts.search_dirs then
for _, path in ipairs(opts.search_dirs) do for _, path in ipairs(opts.search_dirs) do
table.insert(args, vim.fn.expand(path)) table.insert(args, utils.path_expand(path))
end end
end end
@@ -299,7 +299,7 @@ files.find_files = function(opts)
if search_dirs then if search_dirs then
for k, v in pairs(search_dirs) do for k, v in pairs(search_dirs) do
search_dirs[k] = vim.fn.expand(v) search_dirs[k] = utils.path_expand(v)
end end
end end
@@ -376,7 +376,7 @@ files.find_files = function(opts)
end end
if opts.cwd then if opts.cwd then
opts.cwd = vim.fn.expand(opts.cwd) opts.cwd = utils.path_expand(opts.cwd)
end end
opts.entry_maker = opts.entry_maker or make_entry.gen_from_file(opts) opts.entry_maker = opts.entry_maker or make_entry.gen_from_file(opts)
@@ -466,7 +466,7 @@ end
files.current_buffer_fuzzy_find = function(opts) files.current_buffer_fuzzy_find = function(opts)
-- All actions are on the current buffer -- All actions are on the current buffer
local filename = vim.fn.expand(vim.api.nvim_buf_get_name(opts.bufnr)) local filename = vim.api.nvim_buf_get_name(opts.bufnr)
local filetype = vim.api.nvim_buf_get_option(opts.bufnr, "filetype") local filetype = vim.api.nvim_buf_get_option(opts.bufnr, "filetype")
local lines = vim.api.nvim_buf_get_lines(opts.bufnr, 0, -1, false) local lines = vim.api.nvim_buf_get_lines(opts.bufnr, 0, -1, false)

View File

@@ -459,7 +459,7 @@ end
local set_opts_cwd = function(opts) local set_opts_cwd = function(opts)
opts.use_git_root = vim.F.if_nil(opts.use_git_root, true) opts.use_git_root = vim.F.if_nil(opts.use_git_root, true)
if opts.cwd then if opts.cwd then
opts.cwd = vim.fn.expand(opts.cwd) opts.cwd = utils.path_expand(opts.cwd)
elseif opts.use_file_path then elseif opts.use_file_path then
opts.cwd = current_path_toplevel() opts.cwd = current_path_toplevel()
if not opts.cwd then if not opts.cwd then

View File

@@ -7,6 +7,7 @@ This file is still WIP, so expect some changes if you're trying to consume these
This will provide standard mechanism for accessing information from an entry. This will provide standard mechanism for accessing information from an entry.
--============================================================================= ]] --============================================================================= ]]
local utils = require "telescope.utils"
local from_entry = {} local from_entry = {}
@@ -30,7 +31,7 @@ function from_entry.path(entry, validate, escape)
-- TODO(conni2461): we are not going to return the expanded path because -- TODO(conni2461): we are not going to return the expanded path because
-- this would lead to cache misses in the perviewer. -- this would lead to cache misses in the perviewer.
-- Requires overall refactoring in previewer interface -- Requires overall refactoring in previewer interface
local expanded = vim.fn.expand(vim.fn.escape(path, "$?*[]")) local expanded = utils.path_expand(path)
if (vim.fn.filereadable(expanded) + vim.fn.isdirectory(expanded)) == 0 then if (vim.fn.filereadable(expanded) + vim.fn.isdirectory(expanded)) == 0 then
return return
end end

View File

@@ -149,7 +149,7 @@ do
function make_entry.gen_from_file(opts) function make_entry.gen_from_file(opts)
opts = opts or {} opts = opts or {}
local cwd = vim.fn.expand(opts.cwd or vim.loop.cwd()) local cwd = utils.path_expand(opts.cwd or vim.loop.cwd())
local disable_devicons = opts.disable_devicons local disable_devicons = opts.disable_devicons
@@ -310,7 +310,7 @@ do
local display_string = "%s%s%s" local display_string = "%s%s%s"
mt_vimgrep_entry = { mt_vimgrep_entry = {
cwd = vim.fn.expand(opts.cwd or vim.loop.cwd()), cwd = utils.path_expand(opts.cwd or vim.loop.cwd()),
display = function(entry) display = function(entry)
local display_filename = utils.transform_path(opts, entry.filename) local display_filename = utils.transform_path(opts, entry.filename)
@@ -592,7 +592,7 @@ function make_entry.gen_from_buffer(opts)
}, },
} }
local cwd = vim.fn.expand(opts.cwd or vim.loop.cwd()) local cwd = utils.path_expand(opts.cwd or vim.loop.cwd())
local make_display = function(entry) local make_display = function(entry)
-- bufnr_width + modes + icon + 3 spaces + : + lnum -- bufnr_width + modes + icon + 3 spaces + : + lnum
@@ -1011,7 +1011,7 @@ end
function make_entry.gen_from_ctags(opts) function make_entry.gen_from_ctags(opts)
opts = opts or {} opts = opts or {}
local cwd = vim.fn.expand(opts.cwd or vim.loop.cwd()) local cwd = utils.path_expand(opts.cwd or vim.loop.cwd())
local current_file = Path:new(vim.api.nvim_buf_get_name(opts.bufnr)):normalize(cwd) local current_file = Path:new(vim.api.nvim_buf_get_name(opts.bufnr)):normalize(cwd)
local display_items = { local display_items = {

View File

@@ -262,7 +262,7 @@ previewers.file_maker = function(filepath, bufnr, opts)
end end
if opts.bufname ~= filepath then if opts.bufname ~= filepath then
if not vim.in_fast_event() then if not vim.in_fast_event() then
filepath = vim.fn.expand(filepath) filepath = utils.path_expand(filepath)
end end
vim.loop.fs_stat(filepath, function(_, stat) vim.loop.fs_stat(filepath, function(_, stat)
if not stat then if not stat then

View File

@@ -13,17 +13,17 @@ local bat_options = { "--style=plain", "--color=always", "--paging=always" }
local has_less = (vim.fn.executable "less" == 1) and conf.use_less local has_less = (vim.fn.executable "less" == 1) and conf.use_less
local get_file_stat = function(filename) local get_file_stat = function(filename)
return vim.loop.fs_stat(vim.fn.expand(filename)) or {} return vim.loop.fs_stat(utils.path_expand(filename)) or {}
end end
local list_dir = (function() local list_dir = (function()
if vim.fn.has "win32" == 1 then if vim.fn.has "win32" == 1 then
return function(dirname) return function(dirname)
return { "cmd.exe", "/c", "dir", vim.fn.expand(dirname) } return { "cmd.exe", "/c", "dir", utils.path_expand(dirname) }
end end
else else
return function(dirname) return function(dirname)
return { "ls", "-la", vim.fn.expand(dirname) } return { "ls", "-la", utils.path_expand(dirname) }
end end
end end
end)() end)()
@@ -55,7 +55,7 @@ local bat_maker = function(filename, lnum, start, finish)
command, command,
bat_options, bat_options,
"--", "--",
vim.fn.expand(filename), utils.path_expand(filename),
} }
end end
@@ -74,15 +74,15 @@ local cat_maker = function(filename, _, start, _)
if has_less then if has_less then
if start then if start then
return { "less", "-RS", string.format("+%s", start), vim.fn.expand(filename) } return { "less", "-RS", string.format("+%s", start), utils.path_expand(filename) }
else else
return { "less", "-RS", vim.fn.expand(filename) } return { "less", "-RS", utils.path_expand(filename) }
end end
else else
return { return {
"cat", "cat",
"--", "--",
vim.fn.expand(filename), utils.path_expand(filename),
} }
end end
end end

View File

@@ -15,6 +15,43 @@ local get_status = require("telescope.state").get_status
local utils = {} local utils = {}
local iswin = vim.loop.os_uname().sysname == "Windows_NT"
--- `vim.fs.normalize` co-opted for 0.1.x (neovim 0.7) compat
--- TODO: get rid of this and use `vim.fs.normalize` directly for future releases
---@param path string
---@return string
local function path_normalize(path)
vim.validate {
path = { path, { "string" } },
}
if path:sub(1, 1) == "~" then
local home = vim.loop.os_homedir() or "~"
if home:sub(-1) == "\\" or home:sub(-1) == "/" then
home = home:sub(1, -2)
end
path = home .. path:sub(2)
end
path = path:gsub("%$([%w_]+)", vim.loop.os_getenv)
path = path:gsub("\\", "/"):gsub("/+", "/")
if iswin and path:match "^%w:/$" then
return path
end
return (path:gsub("(.)/$", "%1"))
end
--- Selective `expand`.
--- `vim.fn.expand` is overly aggressive, sometimes expanding valid absolute paths into
--- non-existent paths or straight up erroring
---
---@param path string
---@return string
utils.path_expand = function(path)
return path:match "^[%%#<]" and vim.fn.expand(path) or path_normalize(path)
end
utils.get_separator = function() utils.get_separator = function()
return Path.path.sep return Path.path.sep
end end
@@ -244,7 +281,7 @@ utils.transform_path = function(opts, path)
if opts.cwd then if opts.cwd then
cwd = opts.cwd cwd = opts.cwd
if not vim.in_fast_event() then if not vim.in_fast_event() then
cwd = vim.fn.expand(opts.cwd) cwd = utils.path_expand(opts.cwd)
end end
else else
cwd = vim.loop.cwd() cwd = vim.loop.cwd()

View File

@@ -3,6 +3,7 @@ local make_entry = require "telescope.make_entry"
local previewers = require "telescope.previewers" local previewers = require "telescope.previewers"
local pickers = require "telescope.pickers" local pickers = require "telescope.pickers"
local sorters = require "telescope.sorters" local sorters = require "telescope.sorters"
local utils = require "telescope.utils"
local helpers = {} local helpers = {}
@@ -24,7 +25,7 @@ helpers.auto_find_files = function(opts)
end end
if opts.cwd then if opts.cwd then
opts.cwd = vim.fn.expand(opts.cwd) opts.cwd = utils.path_expand(opts.cwd)
end end
opts.entry_maker = opts.entry_maker or make_entry.gen_from_file(opts) opts.entry_maker = opts.entry_maker or make_entry.gen_from_file(opts)