diff --git a/lua/frecency/database.lua b/lua/frecency/database.lua index d82e62a..e6ff339 100644 --- a/lua/frecency/database.lua +++ b/lua/frecency/database.lua @@ -1,11 +1,13 @@ local Table = require "frecency.database.table" local FileLock = require "frecency.file_lock" +local Timer = require "frecency.timer" local config = require "frecency.config" local fs = require "frecency.fs" local watcher = require "frecency.watcher" local log = require "frecency.log" -local async = require "plenary.async" --[[@as FrecencyPlenaryAsync]] -local Path = require "plenary.path" --[[@as FrecencyPlenaryPath]] +local lazy_require = require "frecency.lazy_require" +local async = lazy_require "plenary.async" --[[@as FrecencyPlenaryAsync]] +local Path = lazy_require "plenary.path" --[[@as FrecencyPlenaryPath]] ---@class FrecencyDatabaseEntry ---@field ages number[] @@ -184,7 +186,7 @@ end ---@async ---@return nil function Database:load() - local start = os.clock() + local timer = Timer.new "load()" local err, data = self:file_lock():with(function(target) local err, stat = async.uv.fs_stat(target) if err then @@ -203,13 +205,13 @@ function Database:load() assert(not err, err) local tbl = vim.F.npcall(loadstring(data or "")) self.tbl:set(tbl) - log.debug(("load() takes %f seconds"):format(os.clock() - start)) + timer:finish() end ---@async ---@return nil function Database:save() - local start = os.clock() + local timer = Timer.new "save()" local err = self:file_lock():with(function(target) self:raw_save(self.tbl:raw(), target) local err, stat = async.uv.fs_stat(target) @@ -218,7 +220,7 @@ function Database:save() return nil end) assert(not err, err) - log.debug(("save() takes %f seconds"):format(os.clock() - start)) + timer:finish() end ---@async diff --git a/lua/frecency/database/table.lua b/lua/frecency/database/table.lua index 8618ca2..a7e41d2 100644 --- a/lua/frecency/database/table.lua +++ b/lua/frecency/database/table.lua @@ -1,5 +1,6 @@ -local log = require "frecency.log" -local async = require "plenary.async" +local Timer = require "frecency.timer" +local lazy_require = require "frecency.lazy_require" +local async = lazy_require "plenary.async" --[[@as FrecencyPlenaryAsync]] ---@class FrecencyDatabaseRecordValue ---@field count integer @@ -47,13 +48,13 @@ end ---@async ---@return nil function Table:wait_ready() - local start = os.clock() + local timer = Timer.new "wait_ready()" local t = 0.2 while not rawget(self, "is_ready") do async.util.sleep(t) t = t * 2 end - log.debug(("wait_ready() takes %f seconds"):format(os.clock() - start)) + timer:finish() end return Table diff --git a/lua/frecency/entry_maker.lua b/lua/frecency/entry_maker.lua index 2fa4af7..17bea10 100644 --- a/lua/frecency/entry_maker.lua +++ b/lua/frecency/entry_maker.lua @@ -1,18 +1,18 @@ -local WebDevicons = require "frecency.web_devicons" +local web_devicons = require "frecency.web_devicons" local config = require "frecency.config" local fs = require "frecency.fs" -local Path = require "plenary.path" --[[@as FrecencyPlenaryPath]] -local entry_display = require "telescope.pickers.entry_display" --[[@as FrecencyTelescopeEntryDisplay]] -local utils = require "telescope.utils" --[[@as FrecencyTelescopeUtils]] +local Path = require "plenary.path" +local lazy_require = require "frecency.lazy_require" +local entry_display = lazy_require "telescope.pickers.entry_display" --[[@as FrecencyTelescopeEntryDisplay]] +local utils = lazy_require "telescope.utils" --[[@as FrecencyTelescopeUtils]] ---@class FrecencyEntryMaker ---@field loaded table ----@field web_devicons WebDevicons local EntryMaker = {} ---@return FrecencyEntryMaker EntryMaker.new = function() - return setmetatable({ web_devicons = WebDevicons.new() }, { __index = EntryMaker }) + return setmetatable({}, { __index = EntryMaker }) end ---@class FrecencyEntry @@ -86,7 +86,7 @@ function EntryMaker:width_items(workspace, workspace_tag) table.insert(width_items, { width = 6 }) -- fuzzy score end end - if self.web_devicons.is_enabled then + if not config.disable_devicons then table.insert(width_items, { width = 2 }) end if config.show_filter_column and workspace and workspace_tag then @@ -116,12 +116,11 @@ function EntryMaker:items(entry, workspace, workspace_tag, formatter) table.insert(items, { score, "TelescopeFrecencyScores" }) end end - if self.web_devicons.is_enabled then + if not config.disable_devicons then local basename = utils.path_tail(entry.name) - local icon, icon_highlight = - self.web_devicons:get_icon(basename, utils.file_extension(basename), { default = false }) + local icon, icon_highlight = web_devicons.get_icon(basename, utils.file_extension(basename), { default = false }) if not icon then - icon, icon_highlight = self.web_devicons:get_icon(basename, nil, { default = true }) + icon, icon_highlight = web_devicons.get_icon(basename, nil, { default = true }) end table.insert(items, { icon, icon_highlight }) end diff --git a/lua/frecency/file_lock.lua b/lua/frecency/file_lock.lua index 3c19ac0..a4fbacb 100644 --- a/lua/frecency/file_lock.lua +++ b/lua/frecency/file_lock.lua @@ -1,6 +1,7 @@ local log = require "frecency.log" -local Path = require "plenary.path" --[[@as FrecencyPlenaryPath]] -local async = require "plenary.async" --[[@as FrecencyPlenaryAsync]] +local lazy_require = require "frecency.lazy_require" +local Path = lazy_require "plenary.path" --[[@as FrecencyPlenaryPath]] +local async = lazy_require "plenary.async" --[[@as FrecencyPlenaryAsync]] ---@class FrecencyFileLock ---@field base string diff --git a/lua/frecency/finder.lua b/lua/frecency/finder.lua index 6bbccc3..d6df044 100644 --- a/lua/frecency/finder.lua +++ b/lua/frecency/finder.lua @@ -1,9 +1,12 @@ +local Timer = require "frecency.timer" local config = require "frecency.config" local fs = require "frecency.fs" local os_util = require "frecency.os_util" +local recency = require "frecency.recency" local log = require "frecency.log" -local Job = require "plenary.job" -local async = require "plenary.async" --[[@as FrecencyPlenaryAsync]] +local lazy_require = require "frecency.lazy_require" +local Job = lazy_require "plenary.job" --[[@as FrecencyPlenaryJob]] +local async = lazy_require "plenary.async" --[[@as FrecencyPlenaryAsync]] ---@class FrecencyFinder ---@field config FrecencyFinderConfig @@ -21,7 +24,6 @@ local async = require "plenary.async" --[[@as FrecencyPlenaryAsync]] ---@field private need_scan_dir boolean ---@field private seen table ---@field private process VimSystemObj? ----@field private recency FrecencyRecency ---@field private state FrecencyState local Finder = {} @@ -34,11 +36,10 @@ local Finder = {} ---@param entry_maker FrecencyEntryMakerInstance ---@param need_scandir boolean ---@param path string? ----@param recency FrecencyRecency ---@param state FrecencyState ---@param finder_config? FrecencyFinderConfig ---@return FrecencyFinder -Finder.new = function(database, entry_maker, need_scandir, path, recency, state, finder_config) +Finder.new = function(database, entry_maker, need_scandir, path, state, finder_config) local tx, rx = async.control.channel.mpsc() local scan_tx, scan_rx = async.control.channel.mpsc() local self = setmetatable({ @@ -47,7 +48,6 @@ Finder.new = function(database, entry_maker, need_scandir, path, recency, state, database = database, entry_maker = entry_maker, path = path, - recency = recency, state = state, seen = {}, @@ -257,25 +257,21 @@ end ---@return FrecencyFile[] function Finder:get_results(workspace, epoch) log.debug { workspace = workspace or "NONE" } - local start_fetch = os.clock() + local timer_fetch = Timer.new "fetching entries" local files = self.database:get_entries(workspace, epoch) - log.debug(("it takes %f seconds in fetching entries"):format(os.clock() - start_fetch)) - local start_results = os.clock() - local elapsed_recency = 0 + timer_fetch:finish() + local timer_results = Timer.new "making results" for _, file in ipairs(files) do - local start_recency = os.clock() - file.score = file.ages and self.recency:calculate(file.count, file.ages) or 0 + file.score = file.ages and recency.calculate(file.count, file.ages) or 0 file.ages = nil - elapsed_recency = elapsed_recency + (os.clock() - start_recency) end - log.debug(("it takes %f seconds in calculating recency"):format(elapsed_recency)) - log.debug(("it takes %f seconds in making results"):format(os.clock() - start_results)) + timer_results:finish() - local start_sort = os.clock() + local timer_sort = Timer.new "sorting" table.sort(files, function(a, b) return a.score > b.score or (a.score == b.score and a.path > b.path) end) - log.debug(("it takes %f seconds in sorting"):format(os.clock() - start_sort)) + timer_sort:finish() return files end diff --git a/lua/frecency/fs.lua b/lua/frecency/fs.lua index ef57152..6741032 100644 --- a/lua/frecency/fs.lua +++ b/lua/frecency/fs.lua @@ -1,11 +1,13 @@ local config = require "frecency.config" local os_util = require "frecency.os_util" local log = require "frecency.log" -local Path = require "plenary.path" --[[@as FrecencyPlenaryPath]] -local async = require "plenary.async" --[[@as FrecencyPlenaryAsync]] -local scandir = require "plenary.scandir" +local lazy_require = require "frecency.lazy_require" +local Path = lazy_require "plenary.path" --[[@as FrecencyPlenaryPath]] +local async = lazy_require "plenary.async" --[[@as FrecencyPlenaryAsync]] +local scandir = lazy_require "plenary.scandir" local uv = vim.uv or vim.loop +---@class FrecencyFS local M = { os_homedir = assert(uv.os_homedir()), } diff --git a/lua/frecency/fuzzy_sorter.lua b/lua/frecency/fuzzy_sorter.lua index b4db10b..299776c 100644 --- a/lua/frecency/fuzzy_sorter.lua +++ b/lua/frecency/fuzzy_sorter.lua @@ -1,5 +1,6 @@ local config = require "frecency.config" -local sorters = require "telescope.sorters" +local lazy_require = require "frecency.lazy_require" +local sorters = lazy_require "telescope.sorters" ---@param opts any options for get_fzy_sorter() return function(opts) diff --git a/lua/frecency/init.lua b/lua/frecency/init.lua index b83d860..b861b44 100644 --- a/lua/frecency/init.lua +++ b/lua/frecency/init.lua @@ -5,7 +5,7 @@ ---@field complete fun(findstart: 1|0, base: string): integer|''|string[] ---@field delete async fun(path: string): nil ---@field query fun(opts?: FrecencyQueryOpts): FrecencyQueryEntry[]|string[] ----@field register fun(bufnr: integer, datetime: string?): nil +---@field register async fun(bufnr: integer, datetime: string?): nil ---@field start fun(opts: FrecencyPickerOptions?): nil ---@field validate_database async fun(force: boolean?): nil local frecency = setmetatable({}, { @@ -43,7 +43,9 @@ local function setup(ext_config) return end - require("frecency.config").setup(ext_config) + local config = require "frecency.config" + + config.setup(ext_config) vim.api.nvim_set_hl(0, "TelescopeBufferLoaded", { link = "String", default = true }) vim.api.nvim_set_hl(0, "TelescopePathSeparator", { link = "Directory", default = true }) @@ -76,9 +78,10 @@ local function setup(ext_config) return end local is_floatwin = vim.api.nvim_win_get_config(0).relative ~= "" - if not is_floatwin then - frecency.register(args.buf) + if is_floatwin or (config.ignore_register and config.ignore_register(args.buf)) then + return end + async_call(frecency.register, args.buf, vim.api.nvim_buf_get_name(args.buf)) end, }) diff --git a/lua/frecency/klass.lua b/lua/frecency/klass.lua index fdfc951..9120b6f 100644 --- a/lua/frecency/klass.lua +++ b/lua/frecency/klass.lua @@ -1,54 +1,46 @@ local Database = require "frecency.database" -local EntryMaker = require "frecency.entry_maker" local Picker = require "frecency.picker" -local Recency = require "frecency.recency" +local Timer = require "frecency.timer" local config = require "frecency.config" local fs = require "frecency.fs" local log = require "frecency.log" -local async = require "plenary.async" --[[@as FrecencyPlenaryAsync]] +local recency = require "frecency.recency" +local wait = require "frecency.wait" +local lazy_require = require "frecency.lazy_require" +local async = lazy_require "plenary.async" --[[@as FrecencyPlenaryAsync]] ---@class Frecency ---@field private buf_registered table flag to indicate the buffer is registered to the database. ---@field private database FrecencyDatabase ----@field private entry_maker FrecencyEntryMaker ---@field private picker FrecencyPicker ----@field private recency FrecencyRecency local Frecency = {} ---@return Frecency Frecency.new = function() local self = setmetatable({ buf_registered = {} }, { __index = Frecency }) --[[@as Frecency]] self.database = Database.new() - self.entry_maker = EntryMaker.new() - self.recency = Recency.new() return self end ---This is called when `:Telescope frecency` is called at the first time. ---@return nil function Frecency:setup() - local done = false ---@async local function init() + local timer = Timer.new "init()" self.database:start() self:assert_db_entries() if config.auto_validate then self:validate_database() end - done = true + timer:finish() end local is_async = not not coroutine.running() if is_async then init() else - async.void(init)() - local ok, status = vim.wait(10000, function() - return done - end) - if not ok then - error("failed to setup:" .. (status == -1 and "timed out" or "interrupted")) - end + wait(init) end end @@ -56,7 +48,7 @@ end ---@param opts? FrecencyPickerOptions ---@return nil function Frecency:start(opts) - local start = os.clock() + local timer = Timer.new "start()" log.debug "Frecency:start" opts = opts or {} if opts.cwd then @@ -66,13 +58,13 @@ function Frecency:start(opts) if opts.hide_current_buffer or config.hide_current_buffer then ignore_filenames = { vim.api.nvim_buf_get_name(0) } end - self.picker = Picker.new(self.database, self.entry_maker, self.recency, { + self.picker = Picker.new(self.database, { editing_bufnr = vim.api.nvim_get_current_buf(), ignore_filenames = ignore_filenames, initial_workspace_tag = opts.workspace, }) self.picker:start(vim.tbl_extend("force", config.get(), opts)) - log.debug(("Frecency:start picker:start takes %f seconds"):format(os.clock() - start)) + timer:finish() end ---This can be calledBy `require("telescope").extensions.frecency.complete`. @@ -128,25 +120,21 @@ function Frecency:assert_db_entries() end end +---@async ---@param bufnr integer +---@param path string ---@param epoch? integer -function Frecency:register(bufnr, epoch) - if (config.ignore_register and config.ignore_register(bufnr)) or self.buf_registered[bufnr] then +function Frecency:register(bufnr, path, epoch) + if self.buf_registered[bufnr] or not fs.is_valid_path(path) then return end - local path = vim.api.nvim_buf_get_name(bufnr) - async.void(function() - if not fs.is_valid_path(path) then - return - end - local err, realpath = async.uv.fs_realpath(path) - if err or not realpath then - return - end - self.database:update(realpath, epoch) - self.buf_registered[bufnr] = true - log.debug("registered:", bufnr, path) - end)() + local err, realpath = async.uv.fs_realpath(path) + if err or not realpath then + return + end + self.database:update(realpath, epoch) + self.buf_registered[bufnr] = true + log.debug("registered:", bufnr, path) end ---@async @@ -191,7 +179,7 @@ function Frecency:query(opts, epoch) return { count = entry.count, path = entry.path, - score = entry.ages and self.recency:calculate(entry.count, entry.ages) or 0, + score = entry.ages and recency.calculate(entry.count, entry.ages) or 0, timestamps = entry.timestamps, } end, self.database:get_entries(opts.workspace, epoch)) diff --git a/lua/frecency/lazy_require.lua b/lua/frecency/lazy_require.lua new file mode 100644 index 0000000..cf3e333 --- /dev/null +++ b/lua/frecency/lazy_require.lua @@ -0,0 +1,11 @@ +---@param module string +return function(module) + return setmetatable({}, { + __index = function(_, key) + return require(module)[key] + end, + __call = function(_, ...) + return require(module)(...) + end, + }) +end diff --git a/lua/frecency/log.lua b/lua/frecency/log.lua index 6b198d9..61cc91e 100644 --- a/lua/frecency/log.lua +++ b/lua/frecency/log.lua @@ -1,8 +1,11 @@ local config = require "frecency.config" -local log = require "plenary.log" +local lazy_require = require "frecency.lazy_require" +local log = lazy_require "plenary.log" return setmetatable({}, { __index = function(_, key) - return config.debug and log[key] or function() end + return config.debug and vim.schedule_wrap(function(...) + log[key](...) + end) or function() end end, }) diff --git a/lua/frecency/os_util.lua b/lua/frecency/os_util.lua index bf297de..b8e39e8 100644 --- a/lua/frecency/os_util.lua +++ b/lua/frecency/os_util.lua @@ -1,6 +1,8 @@ -local Path = require "plenary.path" +local lazy_require = require "frecency.lazy_require" +local Path = lazy_require "plenary.path" --[[@as FrecencyPlenaryPath]] local uv = vim.uv or vim.loop +---@class FrecencyOSUtil local M = { is_windows = uv.os_uname().sysname == "Windows_NT", } diff --git a/lua/frecency/picker.lua b/lua/frecency/picker.lua index 297b4a5..9cfafda 100644 --- a/lua/frecency/picker.lua +++ b/lua/frecency/picker.lua @@ -1,3 +1,4 @@ +local EntryMaker = require "frecency.entry_maker" local State = require "frecency.state" local Finder = require "frecency.finder" local config = require "frecency.config" @@ -5,11 +6,12 @@ local fs = require "frecency.fs" local fuzzy_sorter = require "frecency.fuzzy_sorter" local substr_sorter = require "frecency.substr_sorter" local log = require "frecency.log" -local Path = require "plenary.path" --[[@as FrecencyPlenaryPath]] -local actions = require "telescope.actions" -local config_values = require("telescope.config").values -local pickers = require "telescope.pickers" -local utils = require "telescope.utils" --[[@as FrecencyTelescopeUtils]] +local lazy_require = require "frecency.lazy_require" +local Path = lazy_require "plenary.path" --[[@as FrecencyPlenaryPath]] +local actions = lazy_require "telescope.actions" +local telescope_config = lazy_require "telescope.config" +local pickers = lazy_require "telescope.pickers" +local utils = lazy_require "telescope.utils" --[[@as FrecencyTelescopeUtils]] local uv = vim.loop or vim.uv ---@class FrecencyPicker @@ -18,7 +20,6 @@ local uv = vim.loop or vim.uv ---@field private entry_maker FrecencyEntryMaker ---@field private lsp_workspaces string[] ---@field private namespace integer ----@field private recency FrecencyRecency ---@field private state FrecencyState ---@field private workspace string? ---@field private workspace_tag_regex string @@ -37,18 +38,15 @@ local Picker = {} ---@field score number ---@param database FrecencyDatabase ----@param entry_maker FrecencyEntryMaker ----@param recency FrecencyRecency ---@param picker_config FrecencyPickerConfig ---@return FrecencyPicker -Picker.new = function(database, entry_maker, recency, picker_config) +Picker.new = function(database, picker_config) local self = setmetatable({ config = picker_config, database = database, - entry_maker = entry_maker, + entry_maker = EntryMaker.new(), lsp_workspaces = {}, namespace = vim.api.nvim_create_namespace "frecency", - recency = recency, }, { __index = Picker }) local d = config.filter_delimiter self.workspace_tag_regex = "^%s*" .. d .. "(%S+)" .. d @@ -80,7 +78,6 @@ function Picker:finder(opts, workspace, workspace_tag) entry_maker, need_scandir, workspace, - self.recency, self.state, { ignore_filenames = self.config.ignore_filenames } ) @@ -93,7 +90,7 @@ function Picker:start(opts) path_display = function(picker_opts, path) return self:default_path_display(picker_opts, path) end, - }, config_values, opts or {}) --[[@as FrecencyPickerOptions]] + }, 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 } @@ -102,7 +99,7 @@ function Picker:start(opts) local picker = pickers.new(opts, { prompt_title = "Frecency", finder = finder, - previewer = config_values.file_previewer(opts), + previewer = telescope_config.values.file_previewer(opts), sorter = config.matcher == "default" and substr_sorter() or fuzzy_sorter(opts), on_input_filter_cb = self:on_input_filter_cb(opts), attach_mappings = function(prompt_bufnr) diff --git a/lua/frecency/recency.lua b/lua/frecency/recency.lua index 8f4edd5..0ed2ea0 100644 --- a/lua/frecency/recency.lua +++ b/lua/frecency/recency.lua @@ -1,23 +1,15 @@ local config = require "frecency.config" ---@class FrecencyRecency ----@field private modifier table -local Recency = {} - ----@return FrecencyRecency -Recency.new = function() - return setmetatable({ - modifier = config.recency_values, - }, { __index = Recency }) -end +local M = {} ---@param count integer ---@param ages number[] ---@return number -function Recency:calculate(count, ages) +function M.calculate(count, ages) local score = 0 for _, age in ipairs(ages) do - for _, rank in ipairs(self.modifier) do + for _, rank in ipairs(config.recency_values) do if age <= rank.age then score = score + rank.value goto continue @@ -28,4 +20,4 @@ function Recency:calculate(count, ages) return count * score / config.max_timestamps end -return Recency +return M diff --git a/lua/frecency/substr_sorter.lua b/lua/frecency/substr_sorter.lua index 205bed0..08502ec 100644 --- a/lua/frecency/substr_sorter.lua +++ b/lua/frecency/substr_sorter.lua @@ -1,8 +1,9 @@ -- TODO: use this module until telescope's release include this below. -- https://github.com/nvim-telescope/telescope.nvim/pull/2950 -local sorters = require "telescope.sorters" -local util = require "telescope.utils" +local lazy_require = require "frecency.lazy_require" +local sorters = lazy_require "telescope.sorters" +local util = lazy_require "telescope.utils" local substr_highlighter = function(make_display) return function(_, prompt, display) diff --git a/lua/frecency/tests/frecency_spec.lua b/lua/frecency/tests/frecency_spec.lua index 41a807c..31128b3 100644 --- a/lua/frecency/tests/frecency_spec.lua +++ b/lua/frecency/tests/frecency_spec.lua @@ -2,6 +2,7 @@ -- https://github.com/nvim-lua/plenary.nvim/blob/663246936325062427597964d81d30eaa42ab1e4/lua/plenary/test_harness.lua#L86-L86 vim.opt.runtimepath:append(vim.env.TELESCOPE_PATH) +local Timer = require "frecency.timer" local util = require "frecency.tests.util" local log = require "plenary.log" @@ -183,7 +184,7 @@ describe("frecency", function() register(file, make_epoch "2023-07-29T00:00:00+09:00") log.new({}, true) end - local start = os.clock() + local timer = Timer.new "all results" local results = vim.tbl_map(function(result) result.timestamps = nil return result @@ -191,11 +192,10 @@ describe("frecency", function() table.sort(results, function(a, b) return a.path < b.path end) - local elapsed = os.clock() - start - log.info(("it takes %f seconds in fetching all results"):format(elapsed)) + timer:finish() it("returns appropriate latency (<1.0 second)", function() - assert.are.is_true(elapsed < 1.0) + assert.are.is_true(timer.elapsed < 1.0) end) it("returns valid response", function() diff --git a/lua/frecency/tests/recency_spec.lua b/lua/frecency/tests/recency_spec.lua index 7de6ba6..9c4cd03 100644 --- a/lua/frecency/tests/recency_spec.lua +++ b/lua/frecency/tests/recency_spec.lua @@ -1,5 +1,4 @@ -local Recency = require "frecency.recency" -local recency = Recency.new() +local recency = require "frecency.recency" describe("frecency.recency", function() for _, c in ipairs { @@ -13,7 +12,7 @@ describe("frecency.recency", function() } do local dumped = vim.inspect(c.ages, { indent = "", newline = "" }) it(("%d, %s => %d"):format(c.count, dumped, c.score), function() - assert.are.same(c.score, recency:calculate(c.count, c.ages)) + assert.are.same(c.score, recency.calculate(c.count, c.ages)) end) end end) diff --git a/lua/frecency/tests/util.lua b/lua/frecency/tests/util.lua index 933b396..122f246 100644 --- a/lua/frecency/tests/util.lua +++ b/lua/frecency/tests/util.lua @@ -7,7 +7,7 @@ local log = require "plenary.log" local async = require "plenary.async" --[[@as FrecencyPlenaryAsync]] local Path = require "plenary.path" local Job = require "plenary.job" -local wait = require "frecency.tests.wait" +local wait = require "frecency.wait" ---@return FrecencyPlenaryPath ---@return fun(): nil close swwp all entries @@ -101,7 +101,7 @@ local function with_files(files, cb_or_config, callback) frecency.database:start() frecency.database.tbl:wait_ready() end) - frecency.picker = Picker.new(frecency.database, frecency.entry_maker, frecency.recency, { editing_bufnr = 0 }) + frecency.picker = Picker.new(frecency.database, { editing_bufnr = 0 }) local finder = frecency.picker:finder {} callback(frecency, finder, dir) close() @@ -116,16 +116,28 @@ end ---@return fun(file: string, epoch: integer, reset: boolean?, wipeout?: boolean): nil reset: boolean?): nil local function make_register(frecency, dir) return function(file, epoch, reset, wipeout) + -- NOTE: this function does the same thing as BufWinEnter autocmd. + ---@param bufnr integer + local function register(bufnr) + if vim.api.nvim_buf_get_name(bufnr) == "" then + return + end + local is_floatwin = vim.api.nvim_win_get_config(0).relative ~= "" + if is_floatwin or (config.ignore_register and config.ignore_register(bufnr)) then + return + end + async.util.block_on(function() + frecency:register(bufnr, vim.api.nvim_buf_get_name(bufnr), epoch) + end) + end + local path = filepath(dir, file) vim.cmd.edit(path) local bufnr = assert(vim.fn.bufnr(path)) if reset then frecency.buf_registered[bufnr] = nil end - frecency:register(bufnr, epoch) - vim.wait(1000, function() - return not not frecency.buf_registered[bufnr] - end) + register(bufnr) -- HACK: This is needed because almost the same filenames use the same -- buffer. if wipeout then @@ -154,7 +166,7 @@ local function with_fake_register(frecency, dir, callback) bufnr = bufnr + 1 buffers[bufnr] = path async.util.block_on(function() - frecency:register(bufnr, epoch) + frecency:register(bufnr, path, epoch) end) end callback(register) diff --git a/lua/frecency/timer.lua b/lua/frecency/timer.lua new file mode 100644 index 0000000..ac39ae9 --- /dev/null +++ b/lua/frecency/timer.lua @@ -0,0 +1,26 @@ +local config = require "frecency.config" +local log = require "frecency.log" +local uv = vim.uv or vim.loop + +---@class FrecencyTimer +---@field elapsed number +---@field start integer +---@field title string +local Timer = {} + +---@param title string +---@return FrecencyTimer +Timer.new = function(title) + return setmetatable({ start = uv.hrtime(), title = title }, { __index = Timer }) +end + +---@return nil +function Timer:finish() + if not config.debug then + return + end + self.elapsed = (uv.hrtime() - self.start) / 1000000000 + log.debug(("[%s] takes %.3f seconds"):format(self.title, self.elapsed)) +end + +return Timer diff --git a/lua/frecency/types.lua b/lua/frecency/types.lua index 88b9cb2..bd024f8 100644 --- a/lua/frecency/types.lua +++ b/lua/frecency/types.lua @@ -2,6 +2,20 @@ -- NOTE: types are borrowed from plenary.nvim +---@class FrecencyPlenaryJob +---@field new fun(self: FrecencyPlenaryJob, opts: FrecencyPlenaryJobOpts): FrecencyPlenaryJob +---@field start fun(self: FrecencyPlenaryJob): nil +---@field handle VimSystemObj uv_process_t + +---@class FrecencyPlenaryJobOpts +---@field cwd? string +---@field command? string +---@field args? string[] +---@field on_stdout? FrecencyPlenaryJobCallback +---@field on_stderr? FrecencyPlenaryJobCallback + +---@alias FrecencyPlenaryJobCallback fun(error: string, data: string, self?: FrecencyPlenaryJob) + ---@class FrecencyPlenaryPath ---@field new fun(self: FrecencyPlenaryPath|string, path?: string): FrecencyPlenaryPath ---@field absolute fun(): string diff --git a/lua/frecency/tests/wait.lua b/lua/frecency/wait.lua similarity index 100% rename from lua/frecency/tests/wait.lua rename to lua/frecency/wait.lua diff --git a/lua/frecency/watcher.lua b/lua/frecency/watcher.lua index d412580..f838ef6 100644 --- a/lua/frecency/watcher.lua +++ b/lua/frecency/watcher.lua @@ -1,19 +1,20 @@ local log = require "frecency.log" -local async = require "plenary.async" --[[@as FrecencyPlenaryAsync]] +local lazy_require = require "frecency.lazy_require" +local async = lazy_require "plenary.async" --[[@as FrecencyPlenaryAsync]] local uv = vim.loop or vim.uv ----@class FrecencyNativeWatcherMtime +---@class FrecencyWatcherMtime ---@field sec integer ---@field nsec integer local Mtime = {} ---@param mtime FsStatMtime ----@return FrecencyNativeWatcherMtime +---@return FrecencyWatcherMtime Mtime.new = function(mtime) return setmetatable({ sec = mtime.sec, nsec = mtime.nsec }, Mtime) end ----@param other FrecencyNativeWatcherMtime +---@param other FrecencyWatcherMtime ---@return boolean function Mtime:__eq(other) return self.sec == other.sec and self.nsec == other.nsec @@ -24,13 +25,13 @@ function Mtime:__tostring() return string.format("%d.%d", self.sec, self.nsec) end ----@class FrecencyNativeWatcher +---@class FrecencyWatcher ---@field handler UvFsEventHandle ---@field path string ----@field mtime FrecencyNativeWatcherMtime +---@field mtime FrecencyWatcherMtime local Watcher = {} ----@return FrecencyNativeWatcher +---@return FrecencyWatcher Watcher.new = function() return setmetatable({ path = "", mtime = Mtime.new { sec = 0, nsec = 0 } }, { __index = Watcher }) end diff --git a/lua/frecency/web_devicons.lua b/lua/frecency/web_devicons.lua index 2cdd1ce..cf1ef69 100644 --- a/lua/frecency/web_devicons.lua +++ b/lua/frecency/web_devicons.lua @@ -1,32 +1,14 @@ -local config = require "frecency.config" +---@class FrecencyWebDevicons +local M = { + ---@param name string? + ---@param ext string? + ---@param opts table? + ---@return string + ---@return string + get_icon = function(name, ext, opts) + local ok, web_devicons = pcall(require, "nvim-web-devicons") + return ok and web_devicons.get_icon(name, ext, opts) or "", "" + end, +} ----@class WebDeviconsModule ----@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 = {} - ----@return WebDevicons -WebDevicons.new = function() - local ok, web_devicons = pcall(require, "nvim-web-devicons") - return setmetatable( - { is_enabled = not config.disable_devicons and ok, web_devicons = web_devicons }, - { __index = WebDevicons } - ) -end - ----@param name string? ----@param ext string? ----@param opts table? ----@return string ----@return string -function WebDevicons:get_icon(name, ext, opts) - if self.is_enabled then - return self.web_devicons.get_icon(name, ext, opts) - end - return "", "" -end - -return WebDevicons +return M