From a3e818d001baad9ee2f6800d3bbc71c4275364ae Mon Sep 17 00:00:00 2001 From: JINNOUCHI Yasushi Date: Sun, 28 Jan 2024 15:52:47 +0900 Subject: [PATCH] fix: fix joining paths in Windows (#168) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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. --- README.md | 4 +++- lua/frecency/database/native.lua | 2 +- lua/frecency/finder.lua | 6 ++++-- lua/frecency/frecency.lua | 4 +++- lua/frecency/fs.lua | 26 +++++++++++++++++++------- lua/frecency/os_util.lua | 30 ++++++++++++++++++++++++++++++ lua/frecency/picker.lua | 4 ++-- 7 files changed, 62 insertions(+), 14 deletions(-) create mode 100644 lua/frecency/os_util.lua diff --git a/README.md b/README.md index 71f3a0e..fdbc413 100644 --- a/README.md +++ b/README.md @@ -188,7 +188,9 @@ See [default configuration](https://github.com/nvim-telescope/telescope.nvim#tel 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 which you'll see in the finder results). diff --git a/lua/frecency/database/native.lua b/lua/frecency/database/native.lua index 4f3890f..ccd7dd2 100644 --- a/lua/frecency/database/native.lua +++ b/lua/frecency/database/native.lua @@ -115,7 +115,7 @@ function Native:get_entries(workspace, datetime) local now = self:now(datetime) local items = {} 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, { path = path, count = record.count, diff --git a/lua/frecency/finder.lua b/lua/frecency/finder.lua index 313d269..9bd34c3 100644 --- a/lua/frecency/finder.lua +++ b/lua/frecency/finder.lua @@ -1,3 +1,4 @@ +local os_util = require "frecency.os_util" local Job = require "plenary.job" local async = require "plenary.async" --[[@as PlenaryAsync]] local log = require "plenary.log" @@ -88,6 +89,7 @@ function Finder:start(datetime) -- NOTE: return to the main loop to show the main window async.util.scheduler() 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) self.tx.send(entry) end @@ -107,7 +109,7 @@ function Finder:scan_dir_cmd(cmd) if not self.closed and not err and chunk then for name in chunk:gmatch "[^\n]+" do 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 } self.scan_tx.send(entry) end @@ -163,7 +165,7 @@ function Finder:scan_dir_lua() if self.closed then break 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 } self.scan_tx.send(entry) count = count + 1 diff --git a/lua/frecency/frecency.lua b/lua/frecency/frecency.lua index ce7db73..ecfbae2 100644 --- a/lua/frecency/frecency.lua +++ b/lua/frecency/frecency.lua @@ -7,6 +7,7 @@ local Picker = require "frecency.picker" local Recency = require "frecency.recency" local WebDevicons = require "frecency.web_devicons" local sqlite_module = require "frecency.sqlite" +local os_util = require "frecency.os_util" local log = require "plenary.log" ---@class Frecency @@ -49,7 +50,8 @@ Frecency.new = function(opts) default_workspace = nil, disable_devicons = false, filter_delimiter = ":", - ignore_patterns = { "*.git/*", "*/tmp/*", "term://*" }, + ignore_patterns = os_util.is_windows and { [[*.git\*]], [[*\tmp\*]], "term://*" } + or { "*.git/*", "*/tmp/*", "term://*" }, max_timestamps = 10, show_filter_column = true, show_scores = false, diff --git a/lua/frecency/fs.lua b/lua/frecency/fs.lua index 9e6f188..ccaa59d 100644 --- a/lua/frecency/fs.lua +++ b/lua/frecency/fs.lua @@ -1,3 +1,4 @@ +local os_util = require "frecency.os_util" local Path = require "plenary.path" --[[@as PlenaryPath]] local scandir = require "plenary.scandir" local log = require "plenary.log" @@ -5,7 +6,6 @@ local uv = vim.uv or vim.loop ---@class FrecencyFS ---@field os_homedir string ----@field joinpath fun(...: string): string ---@field private config FrecencyFSConfig ---@field private ignore_regexes string[] local FS = {} @@ -27,10 +27,6 @@ FS.new = function(config) local regex = escaped:gsub("%%%*", ".*"):gsub("%%%?", ".") return "^" .. regex .. "$" 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 end @@ -50,13 +46,13 @@ function FS:scan_dir(path) vim.fs.dir(path, { depth = self.config.scan_depth, 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 end end, }) 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 coroutine.yield(name) end @@ -70,6 +66,22 @@ function FS:relative_from_home(path) return Path:new(path):make_relative(self.os_homedir) end +---@type table +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 ---@param path string ---@return boolean diff --git a/lua/frecency/os_util.lua b/lua/frecency/os_util.lua new file mode 100644 index 0000000..bf297de --- /dev/null +++ b/lua/frecency/os_util.lua @@ -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 diff --git a/lua/frecency/picker.lua b/lua/frecency/picker.lua index f082eb8..7922105 100644 --- a/lua/frecency/picker.lua +++ b/lua/frecency/picker.lua @@ -163,9 +163,9 @@ function Picker:default_path_display(opts, path) local filename = Path:new(path):make_relative(opts.cwd) if not self.workspace 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 - filename = "./" .. filename + filename = "." .. Path.path.sep .. filename end end return filename