diff --git a/lua/telescope/_.lua b/lua/telescope/_.lua index 266f70b..6adc5a6 100644 --- a/lua/telescope/_.lua +++ b/lua/telescope/_.lua @@ -5,6 +5,7 @@ local log = require "plenary.log" local async = require "plenary.async" local channel = require("plenary.async").control.channel +local utils = require "telescope.utils" local M = {} @@ -21,7 +22,7 @@ function AsyncJob.new(opts) self.stderr = opts.stderr or M.NullPipe() 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, -- 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 diff --git a/lua/telescope/actions/history.lua b/lua/telescope/actions/history.lua index 9d7efc4..2b08689 100644 --- a/lua/telescope/actions/history.lua +++ b/lua/telescope/actions/history.lua @@ -73,7 +73,7 @@ function histories.History:new(opts) if conf.history.limit then obj.limit = conf.history.limit end - obj.path = vim.fn.expand(conf.history.path) + obj.path = utils.path_expand(conf.history.path) obj.content = {} obj.index = 1 obj.cycle_wrap = conf.history.cycle_wrap diff --git a/lua/telescope/builtin/__files.lua b/lua/telescope/builtin/__files.lua index 878768f..286e622 100644 --- a/lua/telescope/builtin/__files.lua +++ b/lua/telescope/builtin/__files.lua @@ -115,12 +115,12 @@ files.live_grep = function(opts) end local search_dirs = opts.search_dirs 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) if search_dirs then for i, path in ipairs(search_dirs) do - search_dirs[i] = vim.fn.expand(path) + search_dirs[i] = utils.path_expand(path) end end @@ -246,7 +246,7 @@ files.grep_string = function(opts) end elseif opts.search_dirs then for _, path in ipairs(opts.search_dirs) do - table.insert(args, vim.fn.expand(path)) + table.insert(args, utils.path_expand(path)) end end @@ -299,7 +299,7 @@ files.find_files = function(opts) if search_dirs then for k, v in pairs(search_dirs) do - search_dirs[k] = vim.fn.expand(v) + search_dirs[k] = utils.path_expand(v) end end @@ -376,7 +376,7 @@ files.find_files = function(opts) end if opts.cwd then - opts.cwd = vim.fn.expand(opts.cwd) + opts.cwd = utils.path_expand(opts.cwd) end 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) -- 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 lines = vim.api.nvim_buf_get_lines(opts.bufnr, 0, -1, false) diff --git a/lua/telescope/builtin/__git.lua b/lua/telescope/builtin/__git.lua index b98f01f..e8595bc 100644 --- a/lua/telescope/builtin/__git.lua +++ b/lua/telescope/builtin/__git.lua @@ -459,7 +459,7 @@ end local set_opts_cwd = function(opts) opts.use_git_root = vim.F.if_nil(opts.use_git_root, true) if opts.cwd then - opts.cwd = vim.fn.expand(opts.cwd) + opts.cwd = utils.path_expand(opts.cwd) elseif opts.use_file_path then opts.cwd = current_path_toplevel() if not opts.cwd then diff --git a/lua/telescope/from_entry.lua b/lua/telescope/from_entry.lua index 4592d9b..4a66d47 100644 --- a/lua/telescope/from_entry.lua +++ b/lua/telescope/from_entry.lua @@ -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. --============================================================================= ]] +local utils = require "telescope.utils" 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 -- this would lead to cache misses in the perviewer. -- 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 return end diff --git a/lua/telescope/make_entry.lua b/lua/telescope/make_entry.lua index 7805600..2217fd8 100644 --- a/lua/telescope/make_entry.lua +++ b/lua/telescope/make_entry.lua @@ -149,7 +149,7 @@ do function make_entry.gen_from_file(opts) 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 @@ -310,7 +310,7 @@ do local display_string = "%s%s%s" 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) 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) -- bufnr_width + modes + icon + 3 spaces + : + lnum @@ -1011,7 +1011,7 @@ end function make_entry.gen_from_ctags(opts) 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 display_items = { diff --git a/lua/telescope/previewers/buffer_previewer.lua b/lua/telescope/previewers/buffer_previewer.lua index 7668cfe..b239a3d 100644 --- a/lua/telescope/previewers/buffer_previewer.lua +++ b/lua/telescope/previewers/buffer_previewer.lua @@ -262,7 +262,7 @@ previewers.file_maker = function(filepath, bufnr, opts) end if opts.bufname ~= filepath then if not vim.in_fast_event() then - filepath = vim.fn.expand(filepath) + filepath = utils.path_expand(filepath) end vim.loop.fs_stat(filepath, function(_, stat) if not stat then diff --git a/lua/telescope/previewers/term_previewer.lua b/lua/telescope/previewers/term_previewer.lua index 6eeaa65..e4063ca 100644 --- a/lua/telescope/previewers/term_previewer.lua +++ b/lua/telescope/previewers/term_previewer.lua @@ -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 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 local list_dir = (function() if vim.fn.has "win32" == 1 then return function(dirname) - return { "cmd.exe", "/c", "dir", vim.fn.expand(dirname) } + return { "cmd.exe", "/c", "dir", utils.path_expand(dirname) } end else return function(dirname) - return { "ls", "-la", vim.fn.expand(dirname) } + return { "ls", "-la", utils.path_expand(dirname) } end end end)() @@ -55,7 +55,7 @@ local bat_maker = function(filename, lnum, start, finish) command, bat_options, "--", - vim.fn.expand(filename), + utils.path_expand(filename), } end @@ -74,15 +74,15 @@ local cat_maker = function(filename, _, start, _) if has_less 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 - return { "less", "-RS", vim.fn.expand(filename) } + return { "less", "-RS", utils.path_expand(filename) } end else return { "cat", "--", - vim.fn.expand(filename), + utils.path_expand(filename), } end end diff --git a/lua/telescope/utils.lua b/lua/telescope/utils.lua index ff7339d..59d8899 100644 --- a/lua/telescope/utils.lua +++ b/lua/telescope/utils.lua @@ -15,6 +15,43 @@ local get_status = require("telescope.state").get_status 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() return Path.path.sep end @@ -244,7 +281,7 @@ utils.transform_path = function(opts, path) if opts.cwd then cwd = opts.cwd if not vim.in_fast_event() then - cwd = vim.fn.expand(opts.cwd) + cwd = utils.path_expand(opts.cwd) end else cwd = vim.loop.cwd() diff --git a/lua/tests/helpers.lua b/lua/tests/helpers.lua index bdb5f17..73bd0c8 100644 --- a/lua/tests/helpers.lua +++ b/lua/tests/helpers.lua @@ -3,6 +3,7 @@ local make_entry = require "telescope.make_entry" local previewers = require "telescope.previewers" local pickers = require "telescope.pickers" local sorters = require "telescope.sorters" +local utils = require "telescope.utils" local helpers = {} @@ -24,7 +25,7 @@ helpers.auto_find_files = function(opts) end if opts.cwd then - opts.cwd = vim.fn.expand(opts.cwd) + opts.cwd = utils.path_expand(opts.cwd) end opts.entry_maker = opts.entry_maker or make_entry.gen_from_file(opts)