fix: fix joining paths in Windows (#168)

* fix: use plenary.path to manage paths in Windows

* fix: filter out paths validly in Windows

* fix: detect default `ignore_patterns` in Windows

fix: #169

* fix: join paths validly in Windows

* docs: fix value for `ignore_patterns` in Windows

* fix: avoid duplication of separators in paths

Fix: #171
This fixes only in native logic. The one with SQLite has still bugs.
……but that may not be fixed.
This commit is contained in:
JINNOUCHI Yasushi 2024-01-28 15:52:47 +09:00 committed by GitHub
parent 1189184484
commit a3e818d001
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 62 additions and 14 deletions

View File

@ -188,7 +188,9 @@ See [default configuration](https://github.com/nvim-telescope/telescope.nvim#tel
Delimiters to indicate the filter like `:CWD:`. Delimiters to indicate the filter like `:CWD:`.
- `ignore_patterns` (default: `{ "*.git/*", "*/tmp/*", "term://*" }`) - `ignore_patterns`
(default: for non-Windows → `{ "*.git/*", "*/tmp/*", "term://*" }`,
for Windows → `{ [[*.git\*]], [[*\tmp\*]], "term://*" }`)
Patterns in this table control which files are indexed (and subsequently Patterns in this table control which files are indexed (and subsequently
which you'll see in the finder results). which you'll see in the finder results).

View File

@ -115,7 +115,7 @@ function Native:get_entries(workspace, datetime)
local now = self:now(datetime) local now = self:now(datetime)
local items = {} local items = {}
for path, record in pairs(self.table.records) do for path, record in pairs(self.table.records) do
if not workspace or path:find(workspace .. "/", 1, true) then if self.fs:starts_with(path, workspace) then
table.insert(items, { table.insert(items, {
path = path, path = path,
count = record.count, count = record.count,

View File

@ -1,3 +1,4 @@
local os_util = require "frecency.os_util"
local Job = require "plenary.job" local Job = require "plenary.job"
local async = require "plenary.async" --[[@as PlenaryAsync]] local async = require "plenary.async" --[[@as PlenaryAsync]]
local log = require "plenary.log" local log = require "plenary.log"
@ -88,6 +89,7 @@ function Finder:start(datetime)
-- NOTE: return to the main loop to show the main window -- NOTE: return to the main loop to show the main window
async.util.scheduler() async.util.scheduler()
for _, file in ipairs(self:get_results(self.path, datetime)) do for _, file in ipairs(self:get_results(self.path, datetime)) do
file.path = os_util.normalize_sep(file.path)
local entry = self.entry_maker(file) local entry = self.entry_maker(file)
self.tx.send(entry) self.tx.send(entry)
end end
@ -107,7 +109,7 @@ function Finder:scan_dir_cmd(cmd)
if not self.closed and not err and chunk then if not self.closed and not err and chunk then
for name in chunk:gmatch "[^\n]+" do for name in chunk:gmatch "[^\n]+" do
local cleaned = name:gsub("^%./", "") local cleaned = name:gsub("^%./", "")
local fullpath = self.fs.joinpath(self.path, cleaned) local fullpath = os_util.join_path(self.path, cleaned)
local entry = self.entry_maker { id = 0, count = 0, path = fullpath, score = 0 } local entry = self.entry_maker { id = 0, count = 0, path = fullpath, score = 0 }
self.scan_tx.send(entry) self.scan_tx.send(entry)
end end
@ -163,7 +165,7 @@ function Finder:scan_dir_lua()
if self.closed then if self.closed then
break break
end end
local fullpath = self.fs.joinpath(self.path, name) local fullpath = os_util.join_path(self.path, name)
local entry = self.entry_maker { id = 0, count = 0, path = fullpath, score = 0 } local entry = self.entry_maker { id = 0, count = 0, path = fullpath, score = 0 }
self.scan_tx.send(entry) self.scan_tx.send(entry)
count = count + 1 count = count + 1

View File

@ -7,6 +7,7 @@ local Picker = require "frecency.picker"
local Recency = require "frecency.recency" local Recency = require "frecency.recency"
local WebDevicons = require "frecency.web_devicons" local WebDevicons = require "frecency.web_devicons"
local sqlite_module = require "frecency.sqlite" local sqlite_module = require "frecency.sqlite"
local os_util = require "frecency.os_util"
local log = require "plenary.log" local log = require "plenary.log"
---@class Frecency ---@class Frecency
@ -49,7 +50,8 @@ Frecency.new = function(opts)
default_workspace = nil, default_workspace = nil,
disable_devicons = false, disable_devicons = false,
filter_delimiter = ":", filter_delimiter = ":",
ignore_patterns = { "*.git/*", "*/tmp/*", "term://*" }, ignore_patterns = os_util.is_windows and { [[*.git\*]], [[*\tmp\*]], "term://*" }
or { "*.git/*", "*/tmp/*", "term://*" },
max_timestamps = 10, max_timestamps = 10,
show_filter_column = true, show_filter_column = true,
show_scores = false, show_scores = false,

View File

@ -1,3 +1,4 @@
local os_util = require "frecency.os_util"
local Path = require "plenary.path" --[[@as PlenaryPath]] local Path = require "plenary.path" --[[@as PlenaryPath]]
local scandir = require "plenary.scandir" local scandir = require "plenary.scandir"
local log = require "plenary.log" local log = require "plenary.log"
@ -5,7 +6,6 @@ local uv = vim.uv or vim.loop
---@class FrecencyFS ---@class FrecencyFS
---@field os_homedir string ---@field os_homedir string
---@field joinpath fun(...: string): string
---@field private config FrecencyFSConfig ---@field private config FrecencyFSConfig
---@field private ignore_regexes string[] ---@field private ignore_regexes string[]
local FS = {} local FS = {}
@ -27,10 +27,6 @@ FS.new = function(config)
local regex = escaped:gsub("%%%*", ".*"):gsub("%%%?", ".") local regex = escaped:gsub("%%%*", ".*"):gsub("%%%?", ".")
return "^" .. regex .. "$" return "^" .. regex .. "$"
end, self.config.ignore_patterns) end, self.config.ignore_patterns)
---This is needed for Neovim v0.9.0.
self.joinpath = vim.fs.joinpath or function(...)
return (table.concat({ ... }, "/"):gsub("//+", "/"))
end
return self return self
end end
@ -50,13 +46,13 @@ function FS:scan_dir(path)
vim.fs.dir(path, { vim.fs.dir(path, {
depth = self.config.scan_depth, depth = self.config.scan_depth,
skip = function(dirname) skip = function(dirname)
if self:is_ignored(self.joinpath(path, dirname)) then if self:is_ignored(os_util.join_path(path, dirname)) then
return false return false
end end
end, end,
}) })
do do
local fullpath = self.joinpath(path, name) local fullpath = os_util.join_path(path, name)
if type == "file" and not self:is_ignored(fullpath) and gitignore({ path }, fullpath) then if type == "file" and not self:is_ignored(fullpath) and gitignore({ path }, fullpath) then
coroutine.yield(name) coroutine.yield(name)
end end
@ -70,6 +66,22 @@ function FS:relative_from_home(path)
return Path:new(path):make_relative(self.os_homedir) return Path:new(path):make_relative(self.os_homedir)
end end
---@type table<string,string>
local with_sep = {}
---@param path string
---@param base string?
---@return boolean
function FS:starts_with(path, base)
if not base then
return true
end
if not with_sep[base] then
with_sep[base] = base .. (base:sub(#base) == Path.path.sep and "" or Path.path.sep)
end
return path:find(with_sep[base], 1, true) == 1
end
---@private ---@private
---@param path string ---@param path string
---@return boolean ---@return boolean

30
lua/frecency/os_util.lua Normal file
View File

@ -0,0 +1,30 @@
local Path = require "plenary.path"
local uv = vim.uv or vim.loop
local M = {
is_windows = uv.os_uname().sysname == "Windows_NT",
}
---@type fun(filename: string): string
M.normalize_sep = M.is_windows
and function(filename)
if not filename:find("/", 1, true) or filename:match "^%a+://" then
return filename
end
local replaced = filename:gsub("/", Path.path.sep)
return replaced
end
or function(filename)
return filename
end
--- Join path segments into a single path string.
--- NOTE: Do not use vim.fs.joinpath because it does not work on Windows.
---@type fun(...: string): string
M.join_path = M.is_windows and function(...)
return M.normalize_sep(Path:new(...).filename)
end or function(...)
return Path:new(...).filename
end
return M

View File

@ -163,9 +163,9 @@ function Picker:default_path_display(opts, path)
local filename = Path:new(path):make_relative(opts.cwd) local filename = Path:new(path):make_relative(opts.cwd)
if not self.workspace then if not self.workspace then
if vim.startswith(filename, self.fs.os_homedir) then if vim.startswith(filename, self.fs.os_homedir) then
filename = "~/" .. self.fs:relative_from_home(filename) filename = "~" .. Path.path.sep .. self.fs:relative_from_home(filename)
elseif filename ~= path then elseif filename ~= path then
filename = "./" .. filename filename = "." .. Path.path.sep .. filename
end end
end end
return filename return filename