mirror of
https://github.com/kristoferssolo/telescope-frecency.nvim.git
synced 2025-10-21 20:10:38 +00:00
Simplify code with using frecency.config (#189)
* chore: change the position of `?` * fix: use config module to simplify code * test: fix tests to use frecency.config * test: remove macOS with nightly Neovim temporarily
This commit is contained in:
parent
9f4b0faae4
commit
2a22815b09
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
@ -9,7 +9,8 @@ jobs:
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- macos-latest
|
||||
# FIX: Now macos with nightly Neovim fails to test
|
||||
# - macos-latest
|
||||
- windows-latest
|
||||
version:
|
||||
- v0.9.5
|
||||
|
||||
@ -9,16 +9,16 @@ local Config = {}
|
||||
---@field db_root string default: vim.fn.stdpath "data"
|
||||
---@field db_safe_mode boolean default: true
|
||||
---@field db_validate_threshold integer default: 10
|
||||
---@field default_workspace string default: nil
|
||||
---@field default_workspace? string default: nil
|
||||
---@field disable_devicons boolean default: false
|
||||
---@field filter_delimiter string default: ":"
|
||||
---@field hide_current_buffer boolean default: false
|
||||
---@field ignore_patterns string[] default: { "*.git/*", "*/tmp/*", "term://*" }
|
||||
---@field max_timestamps integer default: 10
|
||||
---@field show_filter_column boolean|string[]|nil default: true
|
||||
---@field show_filter_column boolean|string[] default: true
|
||||
---@field show_scores boolean default: false
|
||||
---@field show_unindexed boolean default: true
|
||||
---@field workspace_scan_cmd "LUA"|string[]|nil default: nil
|
||||
---@field workspace_scan_cmd? "LUA"|string[] default: nil
|
||||
---@field workspaces table<string, string> default: {}
|
||||
|
||||
---@return FrecencyConfig
|
||||
|
||||
@ -1,17 +1,11 @@
|
||||
local Table = require "frecency.database.table"
|
||||
local FileLock = require "frecency.file_lock"
|
||||
local config = require "frecency.config"
|
||||
local watcher = require "frecency.watcher"
|
||||
local log = require "plenary.log"
|
||||
local async = require "plenary.async" --[[@as FrecencyPlenaryAsync]]
|
||||
local Path = require "plenary.path" --[[@as FrecencyPlenaryPath]]
|
||||
|
||||
---@class FrecencyDatabaseConfig
|
||||
---@field root string
|
||||
|
||||
---@class FrecencyDatabaseGetFilesOptions
|
||||
---@field path string?
|
||||
---@field workspace string?
|
||||
|
||||
---@class FrecencyDatabaseEntry
|
||||
---@field ages number[]
|
||||
---@field count integer
|
||||
@ -20,7 +14,6 @@ local Path = require "plenary.path" --[[@as FrecencyPlenaryPath]]
|
||||
|
||||
---@class FrecencyDatabase
|
||||
---@field tx FrecencyPlenaryAsyncControlChannelTx
|
||||
---@field private config FrecencyDatabaseConfig
|
||||
---@field private file_lock FrecencyFileLock
|
||||
---@field private filename string
|
||||
---@field private fs FrecencyFS
|
||||
@ -29,17 +22,15 @@ local Path = require "plenary.path" --[[@as FrecencyPlenaryPath]]
|
||||
local Database = {}
|
||||
|
||||
---@param fs FrecencyFS
|
||||
---@param config FrecencyDatabaseConfig
|
||||
---@return FrecencyDatabase
|
||||
Database.new = function(fs, config)
|
||||
Database.new = function(fs)
|
||||
local version = "v1"
|
||||
local self = setmetatable({
|
||||
config = config,
|
||||
fs = fs,
|
||||
tbl = Table.new(version),
|
||||
version = version,
|
||||
}, { __index = Database })
|
||||
self.filename = Path.new(self.config.root, "file_frecency.bin").filename
|
||||
self.filename = Path.new(config.db_root, "file_frecency.bin").filename
|
||||
self.file_lock = FileLock.new(self.filename)
|
||||
local rx
|
||||
self.tx, rx = async.control.channel.mpsc()
|
||||
@ -101,16 +92,15 @@ function Database:remove_files(paths)
|
||||
end
|
||||
|
||||
---@param path string
|
||||
---@param max_count integer
|
||||
---@param datetime string?
|
||||
function Database:update(path, max_count, datetime)
|
||||
---@param datetime? string
|
||||
function Database:update(path, datetime)
|
||||
local record = self.tbl.records[path] or { count = 0, timestamps = {} }
|
||||
record.count = record.count + 1
|
||||
local now = self:now(datetime)
|
||||
table.insert(record.timestamps, now)
|
||||
if #record.timestamps > max_count then
|
||||
if #record.timestamps > config.max_timestamps then
|
||||
local new_table = {}
|
||||
for i = #record.timestamps - max_count + 1, #record.timestamps do
|
||||
for i = #record.timestamps - config.max_timestamps + 1, #record.timestamps do
|
||||
table.insert(new_table, record.timestamps[i])
|
||||
end
|
||||
record.timestamps = new_table
|
||||
@ -119,8 +109,8 @@ function Database:update(path, max_count, datetime)
|
||||
self.tx.send "save"
|
||||
end
|
||||
|
||||
---@param workspace string?
|
||||
---@param datetime string?
|
||||
---@param workspace? string
|
||||
---@param datetime? string
|
||||
---@return FrecencyDatabaseEntry[]
|
||||
function Database:get_entries(workspace, datetime)
|
||||
local now = self:now(datetime)
|
||||
|
||||
@ -1,24 +1,19 @@
|
||||
local WebDevicons = require "frecency.web_devicons"
|
||||
local config = require "frecency.config"
|
||||
local Path = require "plenary.path" --[[@as FrecencyPlenaryPath]]
|
||||
local entry_display = require "telescope.pickers.entry_display" --[[@as FrecencyTelescopeEntryDisplay]]
|
||||
local utils = require "telescope.utils" --[[@as FrecencyTelescopeUtils]]
|
||||
|
||||
---@class FrecencyEntryMaker
|
||||
---@field config FrecencyEntryMakerConfig
|
||||
---@field fs FrecencyFS
|
||||
---@field loaded table<string,boolean>
|
||||
---@field web_devicons WebDevicons
|
||||
local EntryMaker = {}
|
||||
|
||||
---@class FrecencyEntryMakerConfig
|
||||
---@field show_filter_column boolean|string[]
|
||||
---@field show_scores boolean
|
||||
|
||||
---@param fs FrecencyFS
|
||||
---@param web_devicons WebDevicons
|
||||
---@param config FrecencyEntryMakerConfig
|
||||
---@return FrecencyEntryMaker
|
||||
EntryMaker.new = function(fs, web_devicons, config)
|
||||
local self = setmetatable({ config = config, fs = fs, web_devicons = web_devicons }, { __index = EntryMaker })
|
||||
EntryMaker.new = function(fs)
|
||||
local self = setmetatable({ fs = fs, web_devicons = WebDevicons.new() }, { __index = EntryMaker })
|
||||
local loaded_bufnrs = vim.tbl_filter(function(v)
|
||||
return vim.api.nvim_buf_is_loaded(v)
|
||||
end, vim.api.nvim_list_bufs())
|
||||
@ -49,8 +44,8 @@ end
|
||||
---@alias FrecencyEntryMakerInstance fun(file: FrecencyFile): FrecencyEntry
|
||||
|
||||
---@param filepath_formatter FrecencyFilepathFormatter
|
||||
---@param workspace string?
|
||||
---@param workspace_tag string?
|
||||
---@param workspace? string
|
||||
---@param workspace_tag? string
|
||||
---@return FrecencyEntryMakerInstance
|
||||
function EntryMaker:create(filepath_formatter, workspace, workspace_tag)
|
||||
local displayer = entry_display.create {
|
||||
@ -76,18 +71,18 @@ function EntryMaker:create(filepath_formatter, workspace, workspace_tag)
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param workspace string?
|
||||
---@param workspace_tag string?
|
||||
---@param workspace? string
|
||||
---@param workspace_tag? string
|
||||
---@return table[]
|
||||
function EntryMaker:displayer_items(workspace, workspace_tag)
|
||||
local items = {}
|
||||
if self.config.show_scores then
|
||||
if config.show_scores then
|
||||
table.insert(items, { width = 8 })
|
||||
end
|
||||
if self.web_devicons.is_enabled then
|
||||
table.insert(items, { width = 2 })
|
||||
end
|
||||
if self.config.show_filter_column and workspace and workspace_tag then
|
||||
if config.show_filter_column and workspace and workspace_tag then
|
||||
table.insert(items, { width = self:calculate_filter_column_width(workspace, workspace_tag) })
|
||||
end
|
||||
table.insert(items, { remaining = true })
|
||||
@ -96,19 +91,19 @@ end
|
||||
|
||||
---@private
|
||||
---@param entry FrecencyEntry
|
||||
---@param workspace string?
|
||||
---@param workspace_tag string?
|
||||
---@param workspace? string
|
||||
---@param workspace_tag? string
|
||||
---@param formatter fun(filename: string): string
|
||||
---@return table[]
|
||||
function EntryMaker:items(entry, workspace, workspace_tag, formatter)
|
||||
local items = {}
|
||||
if self.config.show_scores then
|
||||
if config.show_scores then
|
||||
table.insert(items, { entry.score, "TelescopeFrecencyScores" })
|
||||
end
|
||||
if self.web_devicons.is_enabled then
|
||||
table.insert(items, { self.web_devicons:get_icon(entry.name, entry.name:match "%a+$", { default = true }) })
|
||||
end
|
||||
if self.config.show_filter_column and workspace and workspace_tag then
|
||||
if config.show_filter_column and workspace and workspace_tag then
|
||||
local filtered = self:should_show_tail(workspace_tag) and utils.path_tail(workspace) .. Path.path.sep
|
||||
or self.fs:relative_from_home(workspace) .. Path.path.sep
|
||||
table.insert(items, { filtered, "Directory" })
|
||||
@ -130,7 +125,7 @@ end
|
||||
---@param workspace_tag string
|
||||
---@return boolean
|
||||
function EntryMaker:should_show_tail(workspace_tag)
|
||||
local show_filter_column = self.config.show_filter_column
|
||||
local show_filter_column = config.show_filter_column
|
||||
local filters = type(show_filter_column) == "table" and show_filter_column or { "LSP", "CWD" }
|
||||
return vim.tbl_contains(filters, workspace_tag)
|
||||
end
|
||||
|
||||
@ -13,10 +13,10 @@ local FileLock = {}
|
||||
---@field interval integer default: 500
|
||||
|
||||
---@param path string
|
||||
---@param opts FrecencyFileLockConfig?
|
||||
---@param file_lock_config? FrecencyFileLockConfig
|
||||
---@return FrecencyFileLock
|
||||
FileLock.new = function(path, opts)
|
||||
local config = vim.tbl_extend("force", { retry = 5, unlink_retry = 5, interval = 500 }, opts or {})
|
||||
FileLock.new = function(path, file_lock_config)
|
||||
local config = vim.tbl_extend("force", { retry = 5, unlink_retry = 5, interval = 500 }, file_lock_config or {})
|
||||
local self = setmetatable({ config = config }, { __index = FileLock })
|
||||
self.filename = path .. ".lock"
|
||||
return self
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
local config = require "frecency.config"
|
||||
local os_util = require "frecency.os_util"
|
||||
local Job = require "plenary.job"
|
||||
local async = require "plenary.async" --[[@as FrecencyPlenaryAsync]]
|
||||
@ -10,7 +11,7 @@ local log = require "plenary.log"
|
||||
---@field scanned_entries FrecencyEntry[]
|
||||
---@field entry_maker FrecencyEntryMakerInstance
|
||||
---@field fs FrecencyFS
|
||||
---@field path string?
|
||||
---@field path? string
|
||||
---@field private database FrecencyDatabase
|
||||
---@field private rx FrecencyPlenaryAsyncControlChannelRx
|
||||
---@field private tx FrecencyPlenaryAsyncControlChannelTx
|
||||
@ -25,10 +26,9 @@ local log = require "plenary.log"
|
||||
local Finder = {}
|
||||
|
||||
---@class FrecencyFinderConfig
|
||||
---@field chunk_size integer? default: 1000
|
||||
---@field ignore_filenames string[]? default: {}
|
||||
---@field sleep_interval integer? default: 50
|
||||
---@field workspace_scan_cmd "LUA"|string[]|nil default: nil
|
||||
---@field chunk_size? integer default: 1000
|
||||
---@field ignore_filenames? string[] default: {}
|
||||
---@field sleep_interval? integer default: 50
|
||||
|
||||
---@param database FrecencyDatabase
|
||||
---@param entry_maker FrecencyEntryMakerInstance
|
||||
@ -37,13 +37,13 @@ local Finder = {}
|
||||
---@param path string?
|
||||
---@param recency FrecencyRecency
|
||||
---@param state FrecencyState
|
||||
---@param config FrecencyFinderConfig?
|
||||
---@param finder_config? FrecencyFinderConfig
|
||||
---@return FrecencyFinder
|
||||
Finder.new = function(database, entry_maker, fs, need_scandir, path, recency, state, config)
|
||||
Finder.new = function(database, entry_maker, fs, need_scandir, path, recency, state, finder_config)
|
||||
local tx, rx = async.control.channel.mpsc()
|
||||
local scan_tx, scan_rx = async.control.channel.mpsc()
|
||||
local self = setmetatable({
|
||||
config = vim.tbl_extend("force", { chunk_size = 1000, sleep_interval = 50 }, config or {}),
|
||||
config = vim.tbl_extend("force", { chunk_size = 1000, sleep_interval = 50 }, finder_config or {}),
|
||||
closed = false,
|
||||
database = database,
|
||||
entry_maker = entry_maker,
|
||||
@ -76,14 +76,14 @@ Finder.new = function(database, entry_maker, fs, need_scandir, path, recency, st
|
||||
return self
|
||||
end
|
||||
|
||||
---@param datetime string?
|
||||
---@param datetime? string
|
||||
---@return nil
|
||||
function Finder:start(datetime)
|
||||
local cmd = self.config.workspace_scan_cmd
|
||||
local ok
|
||||
if cmd ~= "LUA" and self.need_scan_dir then
|
||||
if config.workspace_scan_cmd ~= "LUA" and self.need_scan_dir then
|
||||
---@type string[][]
|
||||
local cmds = cmd and { cmd } or { { "rg", "-.g", "!.git", "--files" }, { "fdfind", "-Htf" }, { "fd", "-Htf" } }
|
||||
local cmds = config.workspace_scan_cmd and { config.workspace_scan_cmd }
|
||||
or { { "rg", "-.g", "!.git", "--files" }, { "fdfind", "-Htf" }, { "fd", "-Htf" } }
|
||||
for _, c in ipairs(cmds) do
|
||||
ok = self:scan_dir_cmd(c)
|
||||
if ok then
|
||||
@ -227,7 +227,7 @@ end
|
||||
---@param process_result fun(entry: FrecencyEntry): nil
|
||||
---@param entries FrecencyEntry[]
|
||||
---@param rx FrecencyPlenaryAsyncControlChannelRx
|
||||
---@param start_index integer?
|
||||
---@param start_index? integer
|
||||
---@return boolean?
|
||||
function Finder:process_channel(process_result, entries, rx, start_index)
|
||||
-- HACK: This is needed for small workspaces that it shows up entries fast.
|
||||
@ -254,8 +254,8 @@ function Finder:process_channel(process_result, entries, rx, start_index)
|
||||
end
|
||||
end
|
||||
|
||||
---@param workspace string?
|
||||
---@param datetime string?
|
||||
---@param workspace? string
|
||||
---@param datetime? string
|
||||
---@return FrecencyFile[]
|
||||
function Finder:get_results(workspace, datetime)
|
||||
log.debug { workspace = workspace or "NONE" }
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
local config = require "frecency.config"
|
||||
local os_util = require "frecency.os_util"
|
||||
local Path = require "plenary.path" --[[@as FrecencyPlenaryPath]]
|
||||
local scandir = require "plenary.scandir"
|
||||
@ -12,13 +13,12 @@ local FS = {}
|
||||
|
||||
---@class FrecencyFSConfig
|
||||
---@field scan_depth integer?
|
||||
---@field ignore_patterns string[]
|
||||
|
||||
---@param config FrecencyFSConfig
|
||||
---@param fs_config? FrecencyFSConfig
|
||||
---@return FrecencyFS
|
||||
FS.new = function(config)
|
||||
FS.new = function(fs_config)
|
||||
local self = setmetatable(
|
||||
{ config = vim.tbl_extend("force", { scan_depth = 100 }, config), os_homedir = assert(uv.os_homedir()) },
|
||||
{ config = vim.tbl_extend("force", { scan_depth = 100 }, fs_config or {}), os_homedir = assert(uv.os_homedir()) },
|
||||
{ __index = FS }
|
||||
)
|
||||
---@param pattern string
|
||||
@ -26,11 +26,11 @@ FS.new = function(config)
|
||||
local escaped = pattern:gsub("[%-%.%+%[%]%(%)%$%^%%%?%*]", "%%%1")
|
||||
local regex = escaped:gsub("%%%*", ".*"):gsub("%%%?", ".")
|
||||
return "^" .. regex .. "$"
|
||||
end, self.config.ignore_patterns)
|
||||
end, config.ignore_patterns)
|
||||
return self
|
||||
end
|
||||
|
||||
---@param path string?
|
||||
---@param path? string
|
||||
---@return boolean
|
||||
function FS:is_valid_path(path)
|
||||
return not not path and Path:new(path):is_file() and not self:is_ignored(path)
|
||||
@ -70,7 +70,7 @@ end
|
||||
local with_sep = {}
|
||||
|
||||
---@param path string
|
||||
---@param base string?
|
||||
---@param base? string
|
||||
---@return boolean
|
||||
function FS:starts_with(path, base)
|
||||
if not base then
|
||||
|
||||
@ -3,7 +3,6 @@ local EntryMaker = require "frecency.entry_maker"
|
||||
local FS = require "frecency.fs"
|
||||
local Picker = require "frecency.picker"
|
||||
local Recency = require "frecency.recency"
|
||||
local WebDevicons = require "frecency.web_devicons"
|
||||
local config = require "frecency.config"
|
||||
local log = require "plenary.log"
|
||||
|
||||
@ -19,14 +18,10 @@ local Frecency = {}
|
||||
---@return Frecency
|
||||
Frecency.new = function()
|
||||
local self = setmetatable({ buf_registered = {} }, { __index = Frecency }) --[[@as Frecency]]
|
||||
self.fs = FS.new { ignore_patterns = config.ignore_patterns }
|
||||
self.database = Database.new(self.fs, { root = config.db_root })
|
||||
local web_devicons = WebDevicons.new(not config.disable_devicons)
|
||||
self.entry_maker = EntryMaker.new(self.fs, web_devicons, {
|
||||
show_filter_column = config.show_filter_column,
|
||||
show_scores = config.show_scores,
|
||||
})
|
||||
self.recency = Recency.new { max_count = config.max_timestamps }
|
||||
self.fs = FS.new()
|
||||
self.database = Database.new(self.fs)
|
||||
self.entry_maker = EntryMaker.new(self.fs)
|
||||
self.recency = Recency.new()
|
||||
return self
|
||||
end
|
||||
|
||||
@ -40,7 +35,7 @@ function Frecency:setup()
|
||||
end
|
||||
|
||||
---This can be calledBy `require("telescope").extensions.frecency.frecency`.
|
||||
---@param opts FrecencyPickerOptions?
|
||||
---@param opts? FrecencyPickerOptions
|
||||
---@return nil
|
||||
function Frecency:start(opts)
|
||||
local start = os.clock()
|
||||
@ -54,14 +49,9 @@ function Frecency:start(opts)
|
||||
ignore_filenames = { vim.api.nvim_buf_get_name(0) }
|
||||
end
|
||||
self.picker = Picker.new(self.database, self.entry_maker, self.fs, self.recency, {
|
||||
default_workspace_tag = config.default_workspace,
|
||||
editing_bufnr = vim.api.nvim_get_current_buf(),
|
||||
filter_delimiter = config.filter_delimiter,
|
||||
ignore_filenames = ignore_filenames,
|
||||
initial_workspace_tag = opts.workspace,
|
||||
show_unindexed = config.show_unindexed,
|
||||
workspace_scan_cmd = config.workspace_scan_cmd,
|
||||
workspaces = config.workspaces,
|
||||
})
|
||||
self.picker:start(vim.tbl_extend("force", config.get(), opts))
|
||||
log.debug(("Frecency:start picker:start takes %f seconds"):format(os.clock() - start))
|
||||
@ -85,7 +75,7 @@ function Frecency:assert_db_entries()
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param force boolean?
|
||||
---@param force? boolean
|
||||
---@return nil
|
||||
function Frecency:validate_database(force)
|
||||
local unlinked = self.database:unlinked_entries()
|
||||
@ -117,13 +107,13 @@ function Frecency:validate_database(force)
|
||||
end
|
||||
|
||||
---@param bufnr integer
|
||||
---@param datetime string? ISO8601 format string
|
||||
---@param datetime? string ISO8601 format string
|
||||
function Frecency:register(bufnr, datetime)
|
||||
local path = vim.api.nvim_buf_get_name(bufnr)
|
||||
if self.buf_registered[bufnr] or not self.fs:is_valid_path(path) then
|
||||
return
|
||||
end
|
||||
self.database:update(path, self.recency.config.max_count, datetime)
|
||||
self.database:update(path, datetime)
|
||||
self.buf_registered[bufnr] = true
|
||||
end
|
||||
|
||||
@ -139,7 +129,7 @@ end
|
||||
|
||||
---@private
|
||||
---@param fmt string
|
||||
---@param ... any?
|
||||
---@param ...? any
|
||||
---@return string
|
||||
function Frecency:message(fmt, ...)
|
||||
return ("[Telescope-Frecency] " .. fmt):format(unpack { ... })
|
||||
@ -147,7 +137,7 @@ end
|
||||
|
||||
---@private
|
||||
---@param fmt string
|
||||
---@param ... any?
|
||||
---@param ...? any
|
||||
---@return nil
|
||||
function Frecency:notify(fmt, ...)
|
||||
vim.notify(self:message(fmt, ...))
|
||||
@ -155,7 +145,7 @@ end
|
||||
|
||||
---@private
|
||||
---@param fmt string
|
||||
---@param ... any?
|
||||
---@param ...? any
|
||||
---@return nil
|
||||
function Frecency:warn(fmt, ...)
|
||||
vim.notify(self:message(fmt, ...), vim.log.levels.WARN)
|
||||
@ -163,7 +153,7 @@ end
|
||||
|
||||
---@private
|
||||
---@param fmt string
|
||||
---@param ... any?
|
||||
---@param ...? any
|
||||
---@return nil
|
||||
function Frecency:error(fmt, ...)
|
||||
vim.notify(self:message(fmt, ...), vim.log.levels.ERROR)
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
local State = require "frecency.state"
|
||||
local Finder = require "frecency.finder"
|
||||
local config = require "frecency.config"
|
||||
local sorters = require "telescope.sorters"
|
||||
local log = require "plenary.log"
|
||||
local Path = require "plenary.path" --[[@as FrecencyPlenaryPath]]
|
||||
@ -23,14 +24,9 @@ local uv = vim.loop or vim.uv
|
||||
local Picker = {}
|
||||
|
||||
---@class FrecencyPickerConfig
|
||||
---@field default_workspace_tag string?
|
||||
---@field editing_bufnr integer
|
||||
---@field filter_delimiter string
|
||||
---@field ignore_filenames string[]?
|
||||
---@field initial_workspace_tag string?
|
||||
---@field show_unindexed boolean
|
||||
---@field workspace_scan_cmd "LUA"|string[]|nil
|
||||
---@field workspaces table<string, string>
|
||||
---@field ignore_filenames? string[]
|
||||
---@field initial_workspace_tag? string
|
||||
|
||||
---@class FrecencyPickerEntry
|
||||
---@field display fun(entry: FrecencyPickerEntry): string
|
||||
@ -43,11 +39,11 @@ local Picker = {}
|
||||
---@param entry_maker FrecencyEntryMaker
|
||||
---@param fs FrecencyFS
|
||||
---@param recency FrecencyRecency
|
||||
---@param config FrecencyPickerConfig
|
||||
---@param picker_config FrecencyPickerConfig
|
||||
---@return FrecencyPicker
|
||||
Picker.new = function(database, entry_maker, fs, recency, config)
|
||||
Picker.new = function(database, entry_maker, fs, recency, picker_config)
|
||||
local self = setmetatable({
|
||||
config = config,
|
||||
config = picker_config,
|
||||
database = database,
|
||||
entry_maker = entry_maker,
|
||||
fs = fs,
|
||||
@ -55,14 +51,14 @@ Picker.new = function(database, entry_maker, fs, recency, config)
|
||||
namespace = vim.api.nvim_create_namespace "frecency",
|
||||
recency = recency,
|
||||
}, { __index = Picker })
|
||||
local d = self.config.filter_delimiter
|
||||
local d = config.filter_delimiter
|
||||
self.workspace_tag_regex = "^%s*" .. d .. "(%S+)" .. d
|
||||
return self
|
||||
end
|
||||
|
||||
---@class FrecencyPickerOptions
|
||||
---@field cwd string
|
||||
---@field hide_current_buffer boolean?
|
||||
---@field hide_current_buffer? boolean
|
||||
---@field path_display
|
||||
---| "hidden"
|
||||
---| "tail"
|
||||
@ -71,15 +67,15 @@ end
|
||||
---| "shorten"
|
||||
---| "truncate"
|
||||
---| fun(opts: FrecencyPickerOptions, path: string): string
|
||||
---@field workspace string?
|
||||
---@field workspace? string
|
||||
|
||||
---@param opts table
|
||||
---@param workspace string?
|
||||
---@param workspace_tag string?
|
||||
---@param workspace? string
|
||||
---@param workspace_tag? string
|
||||
function Picker:finder(opts, workspace, 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 self.config.show_unindexed)
|
||||
local need_scandir = not not (workspace and config.show_unindexed)
|
||||
return Finder.new(
|
||||
self.database,
|
||||
entry_maker,
|
||||
@ -88,11 +84,11 @@ function Picker:finder(opts, workspace, workspace_tag)
|
||||
workspace,
|
||||
self.recency,
|
||||
self.state,
|
||||
{ ignore_filenames = self.config.ignore_filenames, workspace_scan_cmd = self.config.workspace_scan_cmd }
|
||||
{ ignore_filenames = self.config.ignore_filenames }
|
||||
)
|
||||
end
|
||||
|
||||
---@param opts FrecencyPickerOptions?
|
||||
---@param opts? FrecencyPickerOptions
|
||||
function Picker:start(opts)
|
||||
opts = vim.tbl_extend("force", {
|
||||
cwd = uv.cwd(),
|
||||
@ -100,12 +96,11 @@ function Picker:start(opts)
|
||||
return self:default_path_display(picker_opts, path)
|
||||
end,
|
||||
}, opts or {}) --[[@as FrecencyPickerOptions]]
|
||||
self.workspace = self:get_workspace(opts.cwd, self.config.initial_workspace_tag or self.config.default_workspace_tag)
|
||||
self.workspace = self:get_workspace(opts.cwd, self.config.initial_workspace_tag or config.default_workspace)
|
||||
log.debug { workspace = self.workspace }
|
||||
|
||||
self.state = State.new()
|
||||
local finder =
|
||||
self:finder(opts, self.workspace, self.config.initial_workspace_tag or self.config.default_workspace_tag)
|
||||
local finder = self:finder(opts, self.workspace, self.config.initial_workspace_tag or config.default_workspace)
|
||||
local picker = pickers.new(opts, {
|
||||
prompt_title = "Frecency",
|
||||
finder = finder,
|
||||
@ -128,11 +123,10 @@ end
|
||||
---@return integer|string[]|''
|
||||
function Picker:complete(findstart, base)
|
||||
if findstart == 1 then
|
||||
local delimiter = self.config.filter_delimiter
|
||||
local line = vim.api.nvim_get_current_line()
|
||||
local start = line:find(delimiter)
|
||||
local start = line:find(config.filter_delimiter)
|
||||
-- don't complete if there's already a completed `:tag:` in line
|
||||
if not start or line:find(delimiter, start + 1) then
|
||||
if not start or line:find(config.filter_delimiter, start + 1) then
|
||||
return -3
|
||||
end
|
||||
return start
|
||||
@ -149,7 +143,7 @@ end
|
||||
---@private
|
||||
---@return string[]
|
||||
function Picker:workspace_tags()
|
||||
local tags = vim.tbl_keys(self.config.workspaces)
|
||||
local tags = vim.tbl_keys(config.workspaces)
|
||||
table.insert(tags, "CWD")
|
||||
if self:get_lsp_workspace() then
|
||||
table.insert(tags, "LSP")
|
||||
@ -175,14 +169,14 @@ end
|
||||
|
||||
---@private
|
||||
---@param cwd string
|
||||
---@param tag string?
|
||||
---@param tag? string
|
||||
---@return string?
|
||||
function Picker:get_workspace(cwd, tag)
|
||||
tag = tag or self.config.default_workspace_tag
|
||||
tag = tag or config.default_workspace
|
||||
if not tag then
|
||||
return nil
|
||||
elseif self.config.workspaces[tag] then
|
||||
return self.config.workspaces[tag]
|
||||
elseif config.workspaces[tag] then
|
||||
return config.workspaces[tag]
|
||||
elseif tag == "LSP" then
|
||||
return self:get_lsp_workspace()
|
||||
elseif tag == "CWD" then
|
||||
@ -231,11 +225,8 @@ function Picker:on_input_filter_cb(picker_opts)
|
||||
end
|
||||
if self.workspace ~= workspace then
|
||||
self.workspace = workspace
|
||||
opts.updated_finder = self:finder(
|
||||
picker_opts,
|
||||
self.workspace,
|
||||
tag or self.config.initial_workspace_tag or self.config.default_workspace_tag
|
||||
)
|
||||
opts.updated_finder =
|
||||
self:finder(picker_opts, self.workspace, tag or self.config.initial_workspace_tag or config.default_workspace)
|
||||
opts.updated_finder:start()
|
||||
end
|
||||
return opts
|
||||
|
||||
@ -1,16 +1,12 @@
|
||||
local config = require "frecency.config"
|
||||
|
||||
---@class FrecencyRecency
|
||||
---@field config FrecencyRecencyConfig
|
||||
---@field private modifier table<integer, { age: integer, value: integer }>
|
||||
local Recency = {}
|
||||
|
||||
---@class FrecencyRecencyConfig
|
||||
---@field max_count integer default: 10
|
||||
|
||||
---@param config FrecencyRecencyConfig?
|
||||
---@return FrecencyRecency
|
||||
Recency.new = function(config)
|
||||
Recency.new = function()
|
||||
return setmetatable({
|
||||
config = vim.tbl_extend("force", { max_count = 10 }, config or {}),
|
||||
modifier = {
|
||||
{ age = 240, value = 100 }, -- past 4 hours
|
||||
{ age = 1440, value = 80 }, -- past day
|
||||
@ -36,7 +32,7 @@ function Recency:calculate(count, ages)
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
return count * score / self.config.max_count
|
||||
return count * score / config.max_timestamps
|
||||
end
|
||||
|
||||
return Recency
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
---@class FrecencyState
|
||||
---@field picker FrecencyTelescopePicker?
|
||||
---@field picker? FrecencyTelescopePicker
|
||||
local State = {}
|
||||
|
||||
---@return FrecencyState
|
||||
@ -7,7 +7,7 @@ State.new = function()
|
||||
return setmetatable({}, { __index = State, __meta = "kv" })
|
||||
end
|
||||
|
||||
---@param picker FrecencyTelescopePicker?
|
||||
---@param picker? FrecencyTelescopePicker
|
||||
---@return nil
|
||||
function State:set(picker)
|
||||
self.picker = picker
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
local FS = require "frecency.fs"
|
||||
local Database = require "frecency.database"
|
||||
local config = require "frecency.config"
|
||||
local async = require "plenary.async" --[[@as FrecencyPlenaryAsync]]
|
||||
local util = require "frecency.tests.util"
|
||||
async.tests.add_to_env()
|
||||
@ -9,7 +10,8 @@ local function with_database(f)
|
||||
local dir, close = util.tmpdir()
|
||||
dir:joinpath("file_frecency.bin"):touch()
|
||||
return function()
|
||||
local database = Database.new(fs, { root = dir.filename })
|
||||
config.setup { db_root = dir.filename }
|
||||
local database = Database.new(fs)
|
||||
f(database)
|
||||
close()
|
||||
end
|
||||
|
||||
@ -33,7 +33,7 @@ local function with_files(files, cb_or_config, callback)
|
||||
frecency.entry_maker,
|
||||
frecency.fs,
|
||||
frecency.recency,
|
||||
{ editing_bufnr = 0, filter_delimiter = ":", show_unindexed = false, workspaces = {} }
|
||||
{ editing_bufnr = 0 }
|
||||
)
|
||||
local finder = frecency.picker:finder {}
|
||||
callback(frecency, finder, dir)
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
-- NOTE: types are borrowed from plenary.nvim
|
||||
|
||||
---@class FrecencyPlenaryPath
|
||||
---@field new fun(self: FrecencyPlenaryPath|string, path: string?): FrecencyPlenaryPath
|
||||
---@field new fun(self: FrecencyPlenaryPath|string, path?: string): FrecencyPlenaryPath
|
||||
---@field absolute fun(): string
|
||||
---@field is_file fun(self: FrecencyPlenaryPath): boolean
|
||||
---@field filename string
|
||||
@ -11,8 +11,8 @@
|
||||
---@field make_relative fun(self: FrecencyPlenaryPath, cwd: string): string
|
||||
---@field parent FrecencyPlenaryPath
|
||||
---@field path { sep: string }
|
||||
---@field rm fun(self: FrecencyPlenaryPath, opts: { recursive: boolean }?): nil
|
||||
---@field touch fun(self: FrecencyPlenaryPath, opts: { parents: boolean }?): nil
|
||||
---@field rm fun(self: FrecencyPlenaryPath, opts?: { recursive: boolean }): nil
|
||||
---@field touch fun(self: FrecencyPlenaryPath, opts?: { parents: boolean }): nil
|
||||
|
||||
---@class FrecencyPlenaryScanDirOptions
|
||||
---@field hidden boolean if true hidden files will be added
|
||||
@ -48,7 +48,7 @@ function FrecencyPlenaryAsync.run(f) end
|
||||
---@field counter fun(): FrecencyPlenaryAsyncControlChannelTx, FrecencyPlenaryAsyncControlChannelRx
|
||||
|
||||
---@class FrecencyPlenaryAsyncControlChannelTx
|
||||
---@field send fun(entry: any?): nil
|
||||
---@field send fun(entry?: any): nil
|
||||
local FrecencyPlenaryAsyncControlChannelTx = {}
|
||||
|
||||
---@class FrecencyPlenaryAsyncControlChannelRx
|
||||
@ -94,7 +94,7 @@ function FrecencyPlenaryAsyncUv.fs_open(path, flags, mode) end
|
||||
---@async
|
||||
---@param fd integer
|
||||
---@param size integer
|
||||
---@param offset integer?
|
||||
---@param offset? integer
|
||||
---@return string? err
|
||||
---@return string data
|
||||
function FrecencyPlenaryAsyncUv.fs_read(fd, size, offset) end
|
||||
@ -102,7 +102,7 @@ function FrecencyPlenaryAsyncUv.fs_read(fd, size, offset) end
|
||||
---@async
|
||||
---@param fd integer
|
||||
---@param data string
|
||||
---@param offset integer?
|
||||
---@param offset? integer
|
||||
---@return string? err
|
||||
---@return integer bytes
|
||||
function FrecencyPlenaryAsyncUv.fs_write(fd, data, offset) end
|
||||
@ -132,8 +132,8 @@ function FrecencyPlenaryAsyncUtil.scheduler() end
|
||||
---@alias FrecencyTelescopeEntryDisplayer fun(items: string[]): table
|
||||
|
||||
---@class FrecencyTelescopeEntryDisplayOptions
|
||||
---@field separator string?
|
||||
---@field hl_chars table<string, string>?
|
||||
---@field separator? string
|
||||
---@field hl_chars? table<string, string>
|
||||
---@field items string[]
|
||||
|
||||
---@class FrecencyTelescopeEntryDisplay
|
||||
@ -150,9 +150,9 @@ function FrecencyPlenaryAsyncUtil.scheduler() end
|
||||
---@field manager FrecencyTelescopeEntryManager|false
|
||||
---@field prompt_bufnr integer
|
||||
---@field prompt_prefix string
|
||||
---@field results_bufnr integer?
|
||||
---@field results_win integer?
|
||||
---@field sorting_strategy 'ascending'|'descending'
|
||||
---@field results_bufnr? integer
|
||||
---@field results_win? integer
|
||||
---@field sorting_strategy "ascending"|"descending"
|
||||
|
||||
---@class FrecencyTelescopeEntryManager
|
||||
---@field num_results fun(): integer
|
||||
@ -161,7 +161,7 @@ function FrecencyPlenaryAsyncUtil.scheduler() end
|
||||
|
||||
---@class UvFsEventHandle
|
||||
---@field stop fun(self: UvFsEventHandle): nil
|
||||
---@field start fun(self: UvFsEventHandle, path: string, opts: { recursive: boolean }, cb: fun(err: string?, filename: string?, events: string[])): nil
|
||||
---@field start fun(self: UvFsEventHandle, path: string, opts: { recursive: boolean }, cb: fun(err?: string, filename?: string, events: string[])): nil
|
||||
---@field close fun(self: UvFsEventHandle): nil
|
||||
|
||||
--- @class VimSystemObj
|
||||
|
||||
@ -1,16 +1,20 @@
|
||||
local config = require "frecency.config"
|
||||
|
||||
---@class WebDeviconsModule
|
||||
---@field get_icon fun(name: string?, ext: string?, opts: table?): string, string
|
||||
---@field get_icon fun(name?: string, ext?: string, opts?: table): string, string
|
||||
|
||||
---@class WebDevicons
|
||||
---@field is_enabled boolean
|
||||
---@field private web_devicons WebDeviconsModule
|
||||
local WebDevicons = {}
|
||||
|
||||
---@param enable boolean
|
||||
---@return WebDevicons
|
||||
WebDevicons.new = function(enable)
|
||||
WebDevicons.new = function()
|
||||
local ok, web_devicons = pcall(require, "nvim-web-devicons")
|
||||
return setmetatable({ is_enabled = enable and ok, web_devicons = web_devicons }, { __index = WebDevicons })
|
||||
return setmetatable(
|
||||
{ is_enabled = not config.disable_devicons and ok, web_devicons = web_devicons },
|
||||
{ __index = WebDevicons }
|
||||
)
|
||||
end
|
||||
|
||||
---@param name string?
|
||||
|
||||
Loading…
Reference in New Issue
Block a user