Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: enable to use multi dirs for each workspace #268

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lua/frecency/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ local os_util = require "frecency.os_util"
---@field show_scores? boolean default: false
---@field show_unindexed? boolean default: true
---@field workspace_scan_cmd? "LUA"|string[] default: nil
---@field workspaces? table<string, string> default: {}
---@field workspaces? table<string, string|string[]> default: {}

---@class FrecencyConfig: FrecencyRawConfig
---@field ext_config FrecencyRawConfig
Expand Down Expand Up @@ -55,7 +55,7 @@ local Config = {}
---@field show_scores boolean default: false
---@field show_unindexed boolean default: true
---@field workspace_scan_cmd? "LUA"|string[] default: nil
---@field workspaces table<string, string> default: {}
---@field workspaces table<string, string|string[]> default: {}

---@return FrecencyConfig
Config.new = function()
Expand Down
19 changes: 16 additions & 3 deletions lua/frecency/database.lua
Original file line number Diff line number Diff line change
Expand Up @@ -170,14 +170,27 @@ function Database:update(path, epoch)
end

---@async
---@param workspace? string
---@param workspaces? string[]
---@param epoch? integer
---@return FrecencyDatabaseEntry[]
function Database:get_entries(workspace, epoch)
function Database:get_entries(workspaces, epoch)
local now = epoch or os.time()
---@param path string
---@return boolean
local function in_workspace(path)
if not workspaces then
return true
end
for _, workspace in ipairs(workspaces) do
if fs.starts_with(path, workspace) then
return true
end
end
return false
end
local items = {}
for path, record in pairs(self.tbl.records) do
if fs.starts_with(path, workspace) then
if in_workspace(path) then
table.insert(items, {
path = path,
count = record.count,
Expand Down
8 changes: 4 additions & 4 deletions lua/frecency/finder.lua
Original file line number Diff line number Diff line change
Expand Up @@ -252,13 +252,13 @@ function Finder:process_channel(process_result, entries, rx, start_index)
end
end

---@param workspace? string
---@param workspaces? string[]
---@param epoch? integer
---@return FrecencyFile[]
function Finder:get_results(workspace, epoch)
log.debug { workspace = workspace or "NONE" }
function Finder:get_results(workspaces, epoch)
log.debug { workspaces = workspaces or "NONE" }
timer.track "fetching start"
local files = self.database:get_entries(workspace, epoch)
local files = self.database:get_entries(workspaces, epoch)
timer.track "fetching finish"
for _, file in ipairs(files) do
file.score = file.ages and recency.calculate(file.count, file.ages) or 0
Expand Down
5 changes: 3 additions & 2 deletions lua/frecency/klass.lua
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ end
---@field limit? integer default: 100
---@field order? FrecencyQueryOrder default: "score"
---@field record? boolean default: false
---@field workspace? string default: nil
---@field workspace? string|string[] default: nil

---@class FrecencyQueryEntry
---@field count integer
Expand All @@ -223,6 +223,7 @@ function Frecency:query(opts, epoch)
order = "score",
record = false,
}, opts or {})
local workspaces=type(opts.workspace)=='table'and opts.workspace or type(opts.workspace)=='string'and {opts.workspace}or nil
---@param entry FrecencyDatabaseEntry
local entries = vim.tbl_map(function(entry)
return {
Expand All @@ -231,7 +232,7 @@ function Frecency:query(opts, epoch)
score = entry.ages and recency.calculate(entry.count, entry.ages) or 0,
timestamps = entry.timestamps,
}
end, self.database:get_entries(opts.workspace, epoch))
end, self.database:get_entries(workspaces, epoch))
table.sort(entries, self:query_sorter(opts.order, opts.direction))
local results = opts.record and entries or vim.tbl_map(function(entry)
return entry.path
Expand Down
76 changes: 50 additions & 26 deletions lua/frecency/picker.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ local uv = vim.loop or vim.uv
---@field private lsp_workspaces string[]
---@field private namespace integer
---@field private state FrecencyState
---@field private workspace string?
---@field private workspaces string[]?
---@field private workspace_tag_regex string
local Picker = {}

Expand Down Expand Up @@ -64,20 +64,20 @@ end
---| "shorten"
---| "truncate"
---| fun(opts: FrecencyPickerOptions, path: string): string
---@field workspace? string
---@field workspace? string|string[]

---@param opts table
---@param workspace? string
---@param workspaces? string[]
---@param workspace_tag? string
function Picker:finder(opts, workspace, workspace_tag)
function Picker:finder(opts, workspaces, workspace_tag)
local filepath_formatter = self:filepath_formatter(opts)
local entry_maker = self.entry_maker:create(filepath_formatter, workspace, workspace_tag)
local need_scandir = not not (workspace and config.show_unindexed)
local entry_maker = self.entry_maker:create(filepath_formatter, workspaces, workspace_tag)
local need_scandir = not not (workspaces and #workspaces > 0 and config.show_unindexed)
return Finder.new(
self.database,
entry_maker,
need_scandir,
workspace,
workspaces,
self.state,
{ ignore_filenames = self.config.ignore_filenames }
)
Expand All @@ -91,11 +91,10 @@ function Picker:start(opts)
return self:default_path_display(picker_opts, path)
end,
}, telescope_config.values, opts or {}) --[[@as FrecencyPickerOptions]]
self.workspace = self:get_workspace(opts.cwd, self.config.initial_workspace_tag or config.default_workspace)
log.debug { workspace = self.workspace }
self.workspaces = self:get_workspaces(opts.cwd, self.config.initial_workspace_tag or config.default_workspace)

self.state = State.new()
local finder = self:finder(opts, self.workspace, self.config.initial_workspace_tag or config.default_workspace)
local finder = self:finder(opts, self.workspaces, self.config.initial_workspace_tag or config.default_workspace)
local picker = pickers.new(opts, {
prompt_title = "Frecency",
finder = finder,
Expand Down Expand Up @@ -140,7 +139,7 @@ end
function Picker:workspace_tags()
local tags = vim.tbl_keys(config.workspaces)
table.insert(tags, "CWD")
if self:get_lsp_workspace() then
if self:get_lsp_workspaces() then
table.insert(tags, "LSP")
end
return tags
Expand All @@ -152,7 +151,7 @@ end
---@return string
function Picker:default_path_display(opts, path)
local filename = Path:new(path):make_relative(opts.cwd)
if not self.workspace then
if not self.workspaces or #self.workspaces == 0 then
if vim.startswith(filename, fs.os_homedir) then
filename = "~" .. Path.path.sep .. fs.relative_from_home(filename)
elseif filename ~= path then
Expand All @@ -165,40 +164,41 @@ end
---@private
---@param cwd string
---@param tag? string
---@return string?
function Picker:get_workspace(cwd, tag)
---@return string[]?
function Picker:get_workspaces(cwd, tag)
if not tag then
return nil
elseif config.workspaces[tag] then
return config.workspaces[tag]
local w = config.workspaces[tag]
return type(w) == "table" and w or { w }
elseif tag == "LSP" then
return self:get_lsp_workspace()
return self:get_lsp_workspaces()
elseif tag == "CWD" then
return cwd
return { cwd }
end
end

---@private
---@return string?
function Picker:get_lsp_workspace()
---@return string[]?
function Picker:get_lsp_workspaces()
if vim.tbl_isempty(self.lsp_workspaces) then
self.lsp_workspaces = vim.api.nvim_buf_call(self.config.editing_bufnr, vim.lsp.buf.list_workspace_folders)
end
return self.lsp_workspaces[1]
return self.lsp_workspaces
end

---@private
---@param picker_opts table
---@return fun(prompt: string): table
function Picker:on_input_filter_cb(picker_opts)
return function(prompt)
local workspace
local workspaces
local start, finish, tag = prompt:find(self.workspace_tag_regex)
local opts = { prompt = start and prompt:sub(finish + 1) or prompt }
if prompt == "" then
workspace = self:get_workspace(picker_opts.cwd, self.config.initial_workspace_tag or config.default_workspace)
workspaces = self:get_workspaces(picker_opts.cwd, self.config.initial_workspace_tag or config.default_workspace)
else
workspace = self:get_workspace(picker_opts.cwd, tag) or self.workspace
workspaces = self:get_workspaces(picker_opts.cwd, tag) or self.workspaces
end
local picker = self.state:get()
if picker then
Expand All @@ -217,10 +217,34 @@ function Picker:on_input_filter_cb(picker_opts)
)
end
end
if self.workspace ~= workspace then
self.workspace = workspace

---@param a? string[]
---@param b? string[]
---@return boolean
local function same_workspaces(a, b)
if not a or not b or #a ~= #b then
return false
end
local function list_to_map(list)
local tmp = {}
for _, v in ipairs(list) do
tmp[v] = true
end
return tmp
end
local a_map, b_map = list_to_map(a), list_to_map(b)
for _, v in ipairs(a_map) do
if not b_map[v] then
return false
end
end
return true
end

if not same_workspaces(self.workspaces, workspaces) then
self.workspaces = workspaces
opts.updated_finder =
self:finder(picker_opts, self.workspace, tag or self.config.initial_workspace_tag or config.default_workspace)
self:finder(picker_opts, self.workspaces, tag or self.config.initial_workspace_tag or config.default_workspace)
opts.updated_finder:start()
end
return opts
Expand Down
Loading