summaryrefslogtreecommitdiff
path: root/lua/telescope
diff options
context:
space:
mode:
authorTJ DeVries <devries.timothyj@gmail.com>2021-10-08 07:56:01 -0700
committerGitHub <noreply@github.com>2021-10-08 10:56:01 -0400
commitdea927d0eb22255632dd82d2efff1a68d621c871 (patch)
treee7dbec3210c551e664fc0b6c85ebbe901c014014 /lua/telescope
parentec6c13fc092fe8447df77e35013df907a6f3761e (diff)
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 :)
Diffstat (limited to 'lua/telescope')
-rw-r--r--lua/telescope/entry_manager.lua21
-rw-r--r--lua/telescope/finders/async_job_finder.lua1
-rw-r--r--lua/telescope/log.lua4
-rw-r--r--lua/telescope/pickers.lua189
4 files changed, 99 insertions, 116 deletions
diff --git a/lua/telescope/entry_manager.lua b/lua/telescope/entry_manager.lua
index 5055171..1e94c80 100644
--- a/lua/telescope/entry_manager.lua
+++ b/lua/telescope/entry_manager.lua
@@ -2,27 +2,6 @@ local log = require "telescope.log"
local LinkedList = require "telescope.algos.linked_list"
---[[
-
-OK, new idea.
-We can do linked list here.
-To convert at the end to quickfix, just run the list.
-...
-
-start node
-end node
-
-if past loop of must have scores,
- then we can just add to end node and shift end node to current node.
- etc.
-
-
- always inserts a row, because we clear everything before?
-
- can also optimize by keeping worst acceptable score around.
-
---]]
-
local EntryManager = {}
EntryManager.__index = EntryManager
diff --git a/lua/telescope/finders/async_job_finder.lua b/lua/telescope/finders/async_job_finder.lua
index 17799e8..5a96d1d 100644
--- a/lua/telescope/finders/async_job_finder.lua
+++ b/lua/telescope/finders/async_job_finder.lua
@@ -7,6 +7,7 @@ local log = require "telescope.log"
return function(opts)
log.trace("Creating async_job:", opts)
local entry_maker = opts.entry_maker or make_entry.gen_from_string()
+
local fn_command = function(prompt)
local command_list = opts.command_generator(prompt)
if command_list == nil then
diff --git a/lua/telescope/log.lua b/lua/telescope/log.lua
index 0d2e0eb..c74378f 100644
--- a/lua/telescope/log.lua
+++ b/lua/telescope/log.lua
@@ -1,6 +1,4 @@
-local user = vim.loop.os_getenv "USER"
-
return require("plenary.log").new {
plugin = "telescope",
- level = ((user == "tj" or user == "tjdevries") and "debug") or "warn",
+ level = "info",
}
diff --git a/lua/telescope/pickers.lua b/lua/telescope/pickers.lua
index 09a062f..6b9db5e 100644
--- a/lua/telescope/pickers.lua
+++ b/lua/telescope/pickers.lua
@@ -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