feat: Add scrolling through results (#1232)

* some scrollin

* [WIP]: Fri 10 Sep 2021 02:24:20 PM EDT

* ok, I think scrolling works

* change to 1000 for now, dont need to scroll that far :)
This commit is contained in:
TJ DeVries
2021-10-08 07:56:01 -07:00
committed by GitHub
parent ec6c13fc09
commit dea927d0eb
5 changed files with 101 additions and 116 deletions

View File

@@ -213,28 +213,17 @@ function Picker:clear_extra_rows(results_bufnr)
end
if not ok then
log.debug(msg)
log.debug("Failed to set lines:", msg)
end
log.trace("Clearing:", worst_line)
end
function Picker:highlight_displayed_rows(results_bufnr, prompt)
if not self.sorter or not self.sorter.highlighter then
function Picker:highlight_one_row(results_bufnr, prompt, display, row)
if not self.sorter.highlighter then
return
end
vim.api.nvim_buf_clear_namespace(results_bufnr, ns_telescope_matching, 0, -1)
local displayed_rows = vim.api.nvim_buf_get_lines(results_bufnr, 0, -1, false)
for row_index = 1, math.min(#displayed_rows, self.max_results) do
local display = displayed_rows[row_index]
self:highlight_one_row(results_bufnr, prompt, display, row_index - 1)
end
end
function Picker:highlight_one_row(results_bufnr, prompt, display, row)
local highlights = self.sorter:highlighter(prompt, display)
if highlights then
@@ -352,22 +341,19 @@ function Picker:find()
self.prompt_prefix = prompt_prefix
self:_reset_prefix_color()
-- First thing we want to do is set all the lines to blank.
self.max_results = popup_opts.results.height
-- TODO: This could be configurable in the future, but I don't know why you would
-- want to scroll through more than 10,000 items.
--
-- This just lets us stop doing stuff after tons of things.
self.max_results = 1000
-- TODO(scrolling): This may be a hack when we get a little further into implementing scrolling.
vim.api.nvim_buf_set_lines(results_bufnr, 0, self.max_results, false, utils.repeated_table(self.max_results, ""))
-- TODO(status): I would love to get the status text not moving back and forth. Perhaps it is just a problem with
-- virtual text & prompt buffers or something though. I can't figure out why it would redraw the way it does.
--
-- A "hacked" version of this would be to calculate where the area I want the status to go and put a new window there.
-- With this method, I do not need to worry about padding or antying, just make it take up X characters or something.
local status_updater = self:get_status_updater(prompt_win, prompt_bufnr)
local debounced_status = debounce.throttle_leading(status_updater, 50)
local tx, rx = channel.mpsc()
self.__on_lines = tx.send
self._on_lines = tx.send
local find_id = self:_next_find_id()
@@ -412,25 +398,14 @@ function Picker:find()
local start_time = vim.loop.hrtime()
local prompt = self:_get_prompt()
local on_input_result = self._on_input_filter_cb(prompt) or {}
local new_prompt = on_input_result.prompt
if new_prompt then
prompt = new_prompt
end
local new_finder = on_input_result.updated_finder
if new_finder then
self.finder:close()
self.finder = new_finder
end
local prompt = self:_get_next_filtered_prompt()
-- TODO: Entry manager should have a "bulk" setter. This can prevent a lot of redraws from display
if self.cache_picker == false or not (self.cache_picker.is_cached == true) then
self.sorter:_start(prompt)
self.manager = EntryManager:new(self.max_results, self.entry_adder, self.stats)
vim.api.nvim_buf_clear_namespace(results_bufnr, ns_telescope_matching, 0, -1)
local process_result = self:get_result_processor(find_id, prompt, debounced_status)
local process_complete = self:get_result_completor(self.results_bufnr, find_id, prompt, status_updater)
@@ -447,26 +422,8 @@ function Picker:find()
async.util.sleep(self.debounce - diff_time)
end
else
-- resume previous picker
local index = 1
for entry in self.manager:iter() do
self:entry_adder(index, entry, _, true)
index = index + 1
end
self.cache_picker.is_cached = false
-- if text changed, required to set anew to restart finder; otherwise hl and selection
if self.cache_picker.cached_prompt ~= self.default_text then
self:reset_prompt()
self:set_prompt(self.default_text)
else
-- scheduling required to apply highlighting and selection appropriately
await_schedule(function()
self:highlight_displayed_rows(self.results_bufnr, self.cache_picker.cached_prompt)
if self.cache_picker.selection_row ~= nil then
self:set_selection(self.cache_picker.selection_row)
end
end)
end
-- TODO(scroll): This can only happen once, I don't like where it is.
self:_resume_picker()
end
end
end)
@@ -476,10 +433,10 @@ function Picker:find()
on_lines = function(...)
find_id = self:_next_find_id()
self._result_completed = false
status_updater { completed = false }
tx.send(...)
self._on_lines(...)
end,
on_detach = function()
self:_detach()
end,
@@ -753,7 +710,7 @@ function Picker:refresh(finder, opts)
self._multi = MultiSelect:new()
end
self.__on_lines(nil, nil, nil, 0, 1)
self._on_lines(nil, nil, nil, 0, 1)
end
function Picker:set_selection(row)
@@ -856,6 +813,8 @@ function Picker:set_selection(row)
self._selection_row = row
self:refresh_previewer()
vim.api.nvim_win_set_cursor(self.results_win, { row + 1, 0 })
end
function Picker:refresh_previewer()
@@ -918,43 +877,41 @@ function Picker:entry_adder(index, entry, _, insert)
self:_increment "displayed"
-- TODO: Don't need to schedule this if we schedule the adder.
local offset = insert and 0 or 1
vim.schedule(function()
if not vim.api.nvim_buf_is_valid(self.results_bufnr) then
log.debug "ON_ENTRY: Invalid buffer"
return
end
if not vim.api.nvim_buf_is_valid(self.results_bufnr) then
log.debug "ON_ENTRY: Invalid buffer"
return
end
-- TODO: Does this every get called?
-- local line_count = vim.api.nvim_win_get_height(self.results_win)
local line_count = vim.api.nvim_buf_line_count(self.results_bufnr)
if row > line_count then
return
end
-- TODO: Does this every get called?
-- local line_count = vim.api.nvim_win_get_height(self.results_win)
local line_count = vim.api.nvim_buf_line_count(self.results_bufnr)
if row > line_count then
return
end
if insert then
if self.sorting_strategy == "descending" then
vim.api.nvim_buf_set_lines(self.results_bufnr, 0, 1, false, {})
end
if insert then
if self.sorting_strategy == "descending" then
vim.api.nvim_buf_set_lines(self.results_bufnr, 0, 1, false, {})
end
end
local set_ok, msg = pcall(vim.api.nvim_buf_set_lines, self.results_bufnr, row, row + offset, false, { display })
if set_ok and display_highlights then
self.highlighter:hi_display(row, prefix, display_highlights)
end
local set_ok, msg = pcall(vim.api.nvim_buf_set_lines, self.results_bufnr, row, row + offset, false, { display })
if set_ok and display_highlights then
self.highlighter:hi_display(row, prefix, display_highlights)
self:highlight_one_row(self.results_bufnr, self:_get_prompt(), display, row)
end
if not set_ok then
log.debug("Failed to set lines...", msg)
end
if not set_ok then
log.debug("Failed to set lines...", msg)
end
-- This pretty much only fails when people leave newlines in their results.
-- So we'll clean it up for them if it fails.
if not set_ok and display:find "\n" then
display = display:gsub("\n", " | ")
vim.api.nvim_buf_set_lines(self.results_bufnr, row, row + 1, false, { display })
end
end)
-- This pretty much only fails when people leave newlines in their results.
-- So we'll clean it up for them if it fails.
if not set_ok and display:find "\n" then
display = display:gsub("\n", " | ")
vim.api.nvim_buf_set_lines(self.results_bufnr, row, row + 1, false, { display })
end
end
function Picker:_reset_track()
@@ -1025,6 +982,8 @@ function Picker:get_status_updater(prompt_win, prompt_bufnr)
end
function Picker:get_result_processor(find_id, prompt, status_updater)
local count = 0
local cb_add = function(score, entry)
self.manager:add_entry(self, score, entry)
status_updater { completed = false }
@@ -1045,6 +1004,8 @@ function Picker:get_result_processor(find_id, prompt, status_updater)
return
end
count = count + 1
-- TODO: Probably should asyncify this / cache this / do something because this probably takes
-- a ton of time on large results.
log.trace("Processing result... ", entry)
@@ -1060,6 +1021,13 @@ function Picker:get_result_processor(find_id, prompt, status_updater)
end
self.sorter:score(prompt, entry, cb_add, cb_filter)
-- Only on the first addition do we want to set the selection.
-- This allows us to handle moving the cursor to the bottom or top of the window
-- depending on the strategy.
if count == 1 then
self:_do_selection(prompt)
end
end
end
@@ -1075,12 +1043,9 @@ function Picker:get_result_completor(results_bufnr, find_id, prompt, status_upda
status_updater { completed = true }
self:clear_extra_rows(results_bufnr)
self:highlight_displayed_rows(results_bufnr, prompt)
self.sorter:_finish(prompt)
self:_on_complete()
self._result_completed = true
end)
end
@@ -1226,6 +1191,46 @@ function Picker:_detach()
self.closed = true
end
function Picker:_get_next_filtered_prompt()
local prompt = self:_get_prompt()
local on_input_result = self._on_input_filter_cb(prompt) or {}
local new_prompt = on_input_result.prompt
if new_prompt then
prompt = new_prompt
end
local new_finder = on_input_result.updated_finder
if new_finder then
self.finder:close()
self.finder = new_finder
end
return prompt
end
function Picker:_resume_picker()
-- resume previous picker
local index = 1
for entry in self.manager:iter() do
self:entry_adder(index, entry, _, true)
index = index + 1
end
self.cache_picker.is_cached = false
-- if text changed, required to set anew to restart finder; otherwise hl and selection
if self.cache_picker.cached_prompt ~= self.default_text then
self:reset_prompt()
self:set_prompt(self.default_text)
else
-- scheduling required to apply highlighting and selection appropriately
await_schedule(function()
if self.cache_picker.selection_row ~= nil then
self:set_selection(self.cache_picker.selection_row)
end
end)
end
end
pickers._Picker = Picker
return pickers