fix: reflow results to show valid ones (#123)

* fix: clear non-matched results in results buffer

* fix: show high-scored results in the first view

This is for sorting_strategy = 'descending'
This commit is contained in:
JINNOUCHI Yasushi 2023-08-12 15:30:25 +09:00 committed by GitHub
parent 9b17c17744
commit 2ac311a266
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 86 additions and 9 deletions

View File

@ -3,17 +3,20 @@ local async = require "plenary.async" --[[@as PlenaryAsync]]
---@class FrecencyAsyncFinder ---@class FrecencyAsyncFinder
---@field closed boolean ---@field closed boolean
---@field entries FrecencyEntry[] ---@field entries FrecencyEntry[]
---@field reflowed boolean
---@field rx PlenaryAsyncControlChannelRx ---@field rx PlenaryAsyncControlChannelRx
---@field state FrecencyState
---@overload fun(_: string, process_result: (fun(entry: FrecencyEntry): nil), process_complete: fun(): nil): nil ---@overload fun(_: string, process_result: (fun(entry: FrecencyEntry): nil), process_complete: fun(): nil): nil
local AsyncFinder = {} local AsyncFinder = {}
---@param fs FrecencyFS ---@param fs FrecencyFS
---@param state FrecencyState
---@param path string ---@param path string
---@param entry_maker fun(file: FrecencyFile): FrecencyEntry ---@param entry_maker fun(file: FrecencyFile): FrecencyEntry
---@param initial_results FrecencyFile[] ---@param initial_results FrecencyFile[]
---@return FrecencyAsyncFinder ---@return FrecencyAsyncFinder
AsyncFinder.new = function(fs, path, entry_maker, initial_results) AsyncFinder.new = function(state, fs, path, entry_maker, initial_results)
local self = setmetatable({ closed = false, entries = {} }, { local self = setmetatable({ closed = false, entries = {}, reflowed = false, state = state }, {
__index = AsyncFinder, __index = AsyncFinder,
---@param self FrecencyAsyncFinder ---@param self FrecencyAsyncFinder
__call = function(self, ...) __call = function(self, ...)
@ -47,6 +50,7 @@ AsyncFinder.new = function(fs, path, entry_maker, initial_results)
table.insert(self.entries, entry) table.insert(self.entries, entry)
tx.send(entry) tx.send(entry)
if count % 1000 == 0 then if count % 1000 == 0 then
self:reflow_results()
-- NOTE: This is needed not to lock text input. -- NOTE: This is needed not to lock text input.
async.util.sleep(50) async.util.sleep(50)
end end
@ -88,4 +92,32 @@ function AsyncFinder:close()
self.closed = true self.closed = true
end end
---@return nil
function AsyncFinder:reflow_results()
local picker = self.state:get()
if not picker then
return
end
local bufnr = picker.results_bufnr
local win = picker.results_win
if not bufnr or not win then
return
end
picker:clear_extra_rows(bufnr)
if picker.sorting_strategy == "descending" then
local manager = picker.manager
if not manager then
return
end
local worst_line = picker:get_row(manager:num_results())
---@type WinInfo
local wininfo = vim.fn.getwininfo(win)[1]
local bottom = vim.api.nvim_buf_line_count(bufnr)
if not self.reflowed or worst_line > wininfo.botline then
self.reflowed = true
vim.api.nvim_win_set_cursor(win, { bottom, 0 })
end
end
end
return AsyncFinder return AsyncFinder

View File

@ -27,11 +27,12 @@ end
---@field workspace string? ---@field workspace string?
---@field workspace_tag string? ---@field workspace_tag string?
---@param state FrecencyState
---@param filepath_formatter FrecencyFilepathFormatter ---@param filepath_formatter FrecencyFilepathFormatter
---@param initial_results table ---@param initial_results table
---@param opts FrecencyFinderOptions ---@param opts FrecencyFinderOptions
---@return table ---@return table
function Finder:start(filepath_formatter, initial_results, opts) function Finder:start(state, filepath_formatter, initial_results, opts)
local entry_maker = self.entry_maker:create(filepath_formatter, opts.workspace, opts.workspace_tag) local entry_maker = self.entry_maker:create(filepath_formatter, opts.workspace, opts.workspace_tag)
if not opts.need_scandir then if not opts.need_scandir then
return finders.new_table { return finders.new_table {
@ -40,7 +41,7 @@ function Finder:start(filepath_formatter, initial_results, opts)
} }
end end
log.debug { finder = opts } log.debug { finder = opts }
return AsyncFinder.new(self.fs, opts.workspace, entry_maker, initial_results) return AsyncFinder.new(state, self.fs, opts.workspace, entry_maker, initial_results)
end end
return Finder return Finder

View File

@ -1,3 +1,4 @@
local State = require "frecency.state"
local log = require "plenary.log" local log = require "plenary.log"
local Path = require "plenary.path" --[[@as PlenaryPath]] local Path = require "plenary.path" --[[@as PlenaryPath]]
local actions = require "telescope.actions" local actions = require "telescope.actions"
@ -83,8 +84,10 @@ function Picker:start(opts)
self.results = self:fetch_results(self.workspace) self.results = self:fetch_results(self.workspace)
end end
local state = State.new()
local filepath_formatter = self:filepath_formatter(opts) local filepath_formatter = self:filepath_formatter(opts)
local finder = self.finder:start(filepath_formatter, self.results, { local finder = self.finder:start(state, filepath_formatter, self.results, {
need_scandir = self.workspace and self.config.show_unindexed and true or false, need_scandir = self.workspace and self.config.show_unindexed and true or false,
workspace = self.workspace, workspace = self.workspace,
workspace_tag = self.config.initial_workspace_tag, workspace_tag = self.config.initial_workspace_tag,
@ -95,11 +98,12 @@ function Picker:start(opts)
finder = finder, finder = finder,
previewer = config_values.file_previewer(opts), previewer = config_values.file_previewer(opts),
sorter = sorters.get_substr_matcher(), sorter = sorters.get_substr_matcher(),
on_input_filter_cb = self:on_input_filter_cb(opts), on_input_filter_cb = self:on_input_filter_cb(state, opts),
attach_mappings = function(prompt_bufnr) attach_mappings = function(prompt_bufnr)
return self:attach_mappings(prompt_bufnr) return self:attach_mappings(prompt_bufnr)
end, end,
}) })
state:set(picker)
picker:find() picker:find()
self:set_prompt_options(picker.prompt_bufnr) self:set_prompt_options(picker.prompt_bufnr)
end end
@ -227,9 +231,10 @@ function Picker:get_lsp_workspace()
end end
---@private ---@private
---@param state FrecencyState
---@param picker_opts table ---@param picker_opts table
---@return fun(prompt: string): table ---@return fun(prompt: string): table
function Picker:on_input_filter_cb(picker_opts) function Picker:on_input_filter_cb(state, picker_opts)
local filepath_formatter = self:filepath_formatter(picker_opts) local filepath_formatter = self:filepath_formatter(picker_opts)
return function(prompt) return function(prompt)
local workspace local workspace
@ -243,7 +248,7 @@ function Picker:on_input_filter_cb(picker_opts)
if self.workspace ~= workspace then if self.workspace ~= workspace then
self.workspace = workspace self.workspace = workspace
self.results = self:fetch_results(workspace) self.results = self:fetch_results(workspace)
opts.updated_finder = self.finder:start(filepath_formatter, self.results, { opts.updated_finder = self.finder:start(state, filepath_formatter, self.results, {
initial_results = self.results, initial_results = self.results,
need_scandir = self.workspace and self.config.show_unindexed and true or false, need_scandir = self.workspace and self.config.show_unindexed and true or false,
workspace = self.workspace, workspace = self.workspace,

21
lua/frecency/state.lua Normal file
View File

@ -0,0 +1,21 @@
---@class FrecencyState
---@field picker TelescopePicker?
local State = {}
---@return FrecencyState
State.new = function()
return setmetatable({}, { __index = State, __meta = "kv" })
end
---@param picker TelescopePicker?
---@return nil
function State:set(picker)
self.picker = picker
end
---@return TelescopePicker?
function State:get()
return self.picker
end
return State

View File

@ -1,5 +1,6 @@
---@diagnostic disable: invisible ---@diagnostic disable: invisible
local AsyncFinder = require "frecency.async_finder" local AsyncFinder = require "frecency.async_finder"
local State = require "frecency.state"
local FS = require "frecency.fs" local FS = require "frecency.fs"
local EntryMaker = require "frecency.entry_maker" local EntryMaker = require "frecency.entry_maker"
local WebDevicons = require "frecency.web_devicons" local WebDevicons = require "frecency.web_devicons"
@ -22,7 +23,7 @@ local function with_files(files, initial_results, callback)
local initials = vim.tbl_map(function(v) local initials = vim.tbl_map(function(v)
return { path = (dir / v):absolute() } return { path = (dir / v):absolute() }
end, initial_results) end, initial_results)
local async_finder = AsyncFinder.new(fs, dir:absolute(), entry_maker, initials) local async_finder = AsyncFinder.new(State.new(), fs, dir:absolute(), entry_maker, initials)
callback(async_finder, dir) callback(async_finder, dir)
close() close()
end end

View File

@ -117,3 +117,20 @@ function PlenaryAsyncUtil.sleep(ms) end
---@field path_tail fun(path: string): string ---@field path_tail fun(path: string): string
---@field transform_path fun(opts: table, path: string): string ---@field transform_path fun(opts: table, path: string): string
---@field buf_is_loaded fun(filename: string): boolean ---@field buf_is_loaded fun(filename: string): boolean
---@class TelescopePicker
---@field clear_extra_rows fun(self: TelescopePicker, results_bufnr: integer): nil
---@field get_row fun(self: TelescopePicker, index: integer): integer
---@field manager TelescopeEntryManager|false
---@field results_bufnr integer?
---@field results_win integer?
---@field sorting_strategy 'ascending'|'descending'
---@class TelescopeEntryManager
---@field num_results fun(): integer
-- NOTE: types for default functions
---@class WinInfo
---@field topline integer
---@field botline integer