summaryrefslogtreecommitdiff
path: root/lua
diff options
context:
space:
mode:
authorTJ DeVries <devries.timothyj@gmail.com>2020-09-03 23:56:49 -0400
committerTJ DeVries <devries.timothyj@gmail.com>2020-09-03 23:56:49 -0400
commit839f57efb37cba7a9542b67b31370e1babaf194a (patch)
tree2e502a58d83bc528e78b3d44d92134ec96d1345a /lua
parent737363097b8710566cf624776f1d0a18c03a0d8b (diff)
feat: Major improvements in API. Particularly relating to entries.
Diffstat (limited to 'lua')
-rw-r--r--lua/telescope/actions.lua39
-rw-r--r--lua/telescope/builtin.lua197
-rw-r--r--lua/telescope/entry.lua27
-rw-r--r--lua/telescope/finders.lua155
-rw-r--r--lua/telescope/make_entry.lua162
-rw-r--r--lua/telescope/pickers.lua36
-rw-r--r--lua/telescope/previewers.lua56
-rw-r--r--lua/telescope/utils.lua4
-rw-r--r--lua/tests/manual/newline_tables.lua16
9 files changed, 478 insertions, 214 deletions
diff --git a/lua/telescope/actions.lua b/lua/telescope/actions.lua
index f1b4a38..dd47f4d 100644
--- a/lua/telescope/actions.lua
+++ b/lua/telescope/actions.lua
@@ -42,23 +42,32 @@ function actions.goto_file_selection(prompt_bufnr)
print("[telescope] Nothing currently selected")
return
else
- local value = entry.value
- if not value then
- print("Could not do anything with blank line...")
- return
+ local filename, row, col
+ if entry.filename then
+ filename = entry.filename
+ -- TODO: Check for off-by-one
+ row = entry.row or entry.lnum
+ col = entry.col
+ else
+ -- TODO: Might want to remove this and force people
+ -- to put stuff into `filename`
+ local value = entry.value
+ if not value then
+ print("Could not do anything with blank line...")
+ return
+ end
+
+ if type(value) == "table" then
+ value = entry.display
+ end
+
+ local sections = vim.split(value, ":")
+
+ filename = sections[1]
+ row = tonumber(sections[2])
+ col = tonumber(sections[3])
end
- -- TODO: This is not great.
- if type(value) == "table" then
- value = entry.display
- end
-
- local sections = vim.split(value, ":")
-
- local filename = sections[1]
- local row = tonumber(sections[2])
- local col = tonumber(sections[3])
-
vim.cmd(string.format([[bwipeout! %s]], prompt_bufnr))
a.nvim_set_current_win(picker.original_win_id or 0)
diff --git a/lua/telescope/builtin.lua b/lua/telescope/builtin.lua
index d207b99..0430d09 100644
--- a/lua/telescope/builtin.lua
+++ b/lua/telescope/builtin.lua
@@ -11,94 +11,69 @@ This will use the default configuration options.
Other configuration options still in flux at the moment
--]]
+-- TODO: Give some bonus weight to files we've picked before
+-- TODO: Give some bonus weight to oldfiles
+
local actions = require('telescope.actions')
local finders = require('telescope.finders')
+local make_entry = require('telescope.make_entry')
local previewers = require('telescope.previewers')
local pickers = require('telescope.pickers')
local sorters = require('telescope.sorters')
local utils = require('telescope.utils')
+local flatten = vim.tbl_flatten
+
+-- TODO: Support silver search here.
+-- TODO: Support normal grep here (in case neither are installed).
+local vimgrep_arguments = {'rg', '--color=never', '--no-heading', '--with-filename', '--line-number', '--column'}
+
local builtin = {}
builtin.git_files = function(opts)
opts = opts or {}
- local make_entry = (
- opts.shorten_path
- and function(value)
- local result = {
- valid = true,
- display = utils.path_shorten(value),
- ordinal = value,
- value = value
- }
-
- return result
- end)
-
- or nil
-
pickers.new(opts, {
prompt = 'Git File',
- finder = finders.new_oneshot_job({ "git", "ls-files" }, make_entry),
+ finder = finders.new_oneshot_job(
+ { "git", "ls-files", "-o", "--exclude-standard", "-c" },
+ make_entry.gen_from_file(opts)
+ ),
previewer = previewers.cat,
sorter = sorters.get_fuzzy_file(),
}):find()
end
builtin.live_grep = function(opts)
- local live_grepper = finders.new {
- fn_command = function(_, prompt)
- -- TODO: Make it so that we can start searching on the first character.
+ opts = opts or {}
+
+ local live_grepper = finders.new_job(function(prompt)
+ -- TODO: Probably could add some options for smart case and whatever else rg offers.
+
if not prompt or prompt == "" then
return nil
end
- return {
- command = 'rg',
- args = {"--vimgrep", prompt},
- }
- end
- }
+ return flatten { vimgrep_arguments, prompt }
+ end,
+ opts.entry_maker or make_entry.gen_from_vimgrep(opts),
+ opts.max_results
+ )
pickers.new(opts, {
prompt = 'Live Grep',
finder = live_grepper,
previewer = previewers.vimgrep,
}):find()
-
- -- TODO: Incorporate this.
- -- Weight the results somehow to be more likely to be the ones that you've opened.
- -- local old_files = {}
- -- for _, f in ipairs(vim.v.oldfiles) do
- -- old_files[f] = true
- -- end
-
- -- local oldfiles_sorter = sorters.new {
- -- scoring_function = function(prompt, entry)
- -- local line = entry.value
-
- -- if not line then
- -- return
- -- end
-
- -- local _, finish = string.find(line, ":")
- -- local filename = string.sub(line, 1, finish - 1)
- -- local expanded_fname = vim.fn.fnamemodify(filename, ':p')
- -- if old_files[expanded_fname] then
- -- print("Found oldfiles: ", entry.value)
- -- return 0
- -- else
- -- return 1
- -- end
- -- end
- -- }
end
-- TODO: document_symbol
-- TODO: workspace_symbol
builtin.lsp_references = function(opts)
+ opts = opts or {}
+ opts.shorten_path = utils.get_default(opts.shorten_path, true)
+
local params = vim.lsp.util.make_position_params()
params.context = { includeDeclaration = true }
@@ -108,15 +83,74 @@ builtin.lsp_references = function(opts)
vim.list_extend(locations, vim.lsp.util.locations_to_items(server_results.result) or {})
end
- local results = utils.quickfix_items_to_entries(locations)
-
- if vim.tbl_isempty(results) then
+ if vim.tbl_isempty(locations) then
return
end
- local reference_picker = pickers.new(opts, {
+ pickers.new(opts, {
prompt = 'LSP References',
- finder = finders.new_table(results),
+ finder = finders.new_table {
+ results = locations,
+ entry_maker = make_entry.gen_from_quickfix(opts),
+ },
+ previewer = previewers.qflist,
+ sorter = sorters.get_norcalli_sorter(),
+ }):find()
+end
+
+builtin.lsp_document_symbols = function(opts)
+ local params = vim.lsp.util.make_position_params()
+ local results_lsp = vim.lsp.buf_request_sync(0, "textDocument/documentSymbol", params)
+
+ if not results_lsp or vim.tbl_isempty(results_lsp) then
+ print("No results from textDocument/documentSymbol")
+ return
+ end
+
+ local locations = {}
+ for _, server_results in pairs(results_lsp) do
+ vim.list_extend(locations, vim.lsp.util.symbols_to_items(server_results.result, 0) or {})
+ end
+
+ if vim.tbl_isempty(locations) then
+ return
+ end
+
+ pickers.new(opts, {
+ prompt = 'LSP Document Symbols',
+ finder = finders.new_table {
+ results = locations,
+ entry_maker = make_entry.gen_from_quickfix(opts)
+ },
+ previewer = previewers.vim_buffer,
+ sorter = sorters.get_norcalli_sorter(),
+ }):find()
+end
+
+builtin.lsp_workspace_symbols = function(opts)
+ local params = {query = opts.query or ''}
+ local results_lsp = vim.lsp.buf_request_sync(0, "workspace/symbol", params, 1000)
+
+ if not results_lsp or vim.tbl_isempty(results_lsp) then
+ print("No results from textDocument/documentSymbol")
+ return
+ end
+
+ local locations = {}
+ for _, server_results in pairs(results_lsp) do
+ vim.list_extend(locations, vim.lsp.util.symbols_to_items(server_results.result, 0) or {})
+ end
+
+ if vim.tbl_isempty(locations) then
+ return
+ end
+
+ pickers.new(opts, {
+ prompt = 'LSP Workspace Symbols',
+ finder = finders.new_table {
+ results = locations,
+ entry_maker = make_entry.gen_from_quickfix(opts)
+ },
previewer = previewers.qflist,
sorter = sorters.get_norcalli_sorter(),
}):find()
@@ -124,15 +158,17 @@ end
builtin.quickfix = function(opts)
local locations = vim.fn.getqflist()
- local results = utils.quickfix_items_to_entries(locations)
- if vim.tbl_isempty(results) then
+ if vim.tbl_isempty(locations) then
return
end
pickers.new(opts, {
prompt = 'Quickfix',
- finder = finders.new_table(results),
+ finder = finders.new_table {
+ results = locations,
+ entry_maker = make_entry.gen_from_quickfix(opts),
+ },
previewer = previewers.qflist,
sorter = sorters.get_norcalli_sorter(),
}):find()
@@ -146,15 +182,16 @@ builtin.loclist = function(opts)
value.filename = filename
end
- local results = utils.quickfix_items_to_entries(locations)
-
- if vim.tbl_isempty(results) then
+ if vim.tbl_isempty(locations) then
return
end
pickers.new(opts, {
prompt = 'Loclist',
- finder = finders.new_table(results),
+ finder = finders.new_table {
+ results = locations,
+ entry_maker = make_entry.gen_from_quickfix(opts),
+ },
previewer = previewers.qflist,
sorter = sorters.get_norcalli_sorter(),
}):find()
@@ -165,9 +202,12 @@ builtin.grep_string = function(opts)
local search = opts.search or vim.fn.expand("<cword>")
- local file_picker = pickers.new(opts, {
+ pickers.new(opts, {
prompt = 'Find Word',
- finder = finders.new_oneshot_job {'rg', '--vimgrep', search},
+ finder = finders.new_oneshot_job(
+ flatten { vimgrep_arguments, search},
+ make_entry.gen_from_vimgrep(opts)
+ ),
previewer = previewers.vimgrep,
sorter = sorters.get_norcalli_sorter(),
}):find()
@@ -218,27 +258,32 @@ end
-- vim.fn.setreg("+", "nnoremap $TODO :lua require('telescope.builtin').<whatever>()<CR>")
-- TODO: Can we just do the names instead?
builtin.builtin = function(opts)
+ opts = opts or {}
+ opts.hide_filename = utils.get_default(opts.hide_filename, true)
+ opts.ignore_filename = utils.get_default(opts.ignore_filename, true)
+
local objs = {}
for k, v in pairs(builtin) do
local debug_info = debug.getinfo(v)
table.insert(objs, {
- vimgrep_str = k,
filename = string.sub(debug_info.source, 2),
lnum = debug_info.linedefined,
col = 0,
+ text = k,
start = debug_info.linedefined,
finish = debug_info.lastlinedefined,
})
end
- local entries = utils.quickfix_items_to_entries(objs)
-
pickers.new(opts, {
prompt = 'Telescope Builtin',
- finder = finders.new_table(entries),
+ finder = finders.new_table {
+ results = objs,
+ entry_maker = make_entry.gen_from_quickfix(opts),
+ },
previewer = previewers.qflist,
sorter = sorters.get_norcalli_sorter(),
}):find()
@@ -269,14 +314,10 @@ builtin.fd = function(opts)
pickers.new(opts, {
prompt = 'Find Files',
- finder = finders.new {
- fn_command = function()
- return {
- command = fd_string,
- cwd = cwd,
- }
- end,
- },
+ finder = finders.new_oneshot_job(
+ {fd_string},
+ make_entry.gen_from_file(opts)
+ ),
previewer = previewers.cat,
sorter = sorters.get_fuzzy_file(),
}):find()
diff --git a/lua/telescope/entry.lua b/lua/telescope/entry.lua
deleted file mode 100644
index 97b5414..0000000
--- a/lua/telescope/entry.lua
+++ /dev/null
@@ -1,27 +0,0 @@
-local Entry = {}
-Entry.__index = Entry
-
--- TODO: Can we / should we make it so that "display" and "ordinal" are just values, instead of functions.
--- It seems like that's what you'd want... No need to call the functions a million times.
-
--- Pass in a table, that contains some state
--- Table determines it's ordinal value
-function Entry:new(line_or_obj)
- if type(line_or_obj) == "string" then
- return setmetatable({
- valid = line_or_obj ~= "",
-
- value = line_or_obj,
- ordinal = line_or_obj,
- display = line_or_obj,
- }, self)
- else
- return line_or_obj
- end
-end
-
-function Entry:__tostring()
- return "<" .. self.display .. ">"
-end
-
-return Entry
diff --git a/lua/telescope/finders.lua b/lua/telescope/finders.lua
index b44dd71..7682aeb 100644
--- a/lua/telescope/finders.lua
+++ b/lua/telescope/finders.lua
@@ -1,5 +1,6 @@
local Job = require('plenary.job')
+local make_entry = require('telescope.make_entry')
local log = require('telescope.log')
local utils = require('telescope.utils')
@@ -10,35 +11,43 @@ local finders = {}
-- FunctionFinder(my_func)
-- JobFinder(my_job_args)
----@class Finder
-local Finder = {}
+local _callable_obj = function()
+ local obj = {}
-Finder.__index = Finder
-Finder.__call = function(t, ... ) return t:_find(...) end
+ obj.__index = obj
+ obj.__call = function(t, ...) return t:_find(...) end
+
+ return obj
+end
+
+
+--[[ =============================================================
+
+ JobFinder
+
+Uses an external Job to get results. Processes results as they arrive.
+
+For more information about how Jobs are implemented, checkout 'plenary.job'
+
+-- ============================================================= ]]
+local JobFinder = _callable_obj()
--- Create a new finder command
---
---@param opts table Keys:
-- fn_command function The function to call
-function Finder:new(opts)
+function JobFinder:new(opts)
opts = opts or {}
- -- TODO: Add config for:
- -- - cwd
-
+ assert(not opts.results, "`results` should be used with finder.new_table")
-- TODO:
-- - `types`
-- job
-- pipe
-- vim.loop.new_pipe (stdin / stdout). stdout => filter pipe
-- rg huge_search | fzf --filter prompt_is > buffer. buffer could do stuff do w/ preview callback
- -- string
- -- list
- -- ...
local obj = setmetatable({
- results = opts.results,
-
- entry_maker = opts.entry_maker,
+ entry_maker = opts.entry_maker or make_entry.from_string,
fn_command = opts.fn_command,
static = opts.static,
state = {},
@@ -51,26 +60,7 @@ function Finder:new(opts)
return obj
end
--- Probably should use the word apply here, since we're apply the callback passed to us by
--- the picker... But I'm not sure how we want to say that.
-
--- find_incremental
--- find_prompt
--- process_prompt
--- process_search
--- do_your_job
--- process_plz
-function Finder:_find(prompt, process_result, process_complete)
- if self.results then
- assert(type(self.results) == 'table', "self.results must be a table")
- for _, v in ipairs(self.results) do
- process_result(v)
- end
-
- process_complete()
- return
- end
-
+function JobFinder:_find(prompt, process_result, process_complete)
if self.job and not self.job.is_shutdown then
self.job:shutdown()
end
@@ -140,22 +130,66 @@ function Finder:_find(prompt, process_result, process_complete)
self.job:start()
end
+--[[ =============================================================
+Static Finders
+
+A static finder has results that never change.
+They are passed in directly as a result.
+-- ============================================================= ]]
+local StaticFinder = _callable_obj()
+
+function StaticFinder:new(opts)
+ assert(opts, "Options are required. See documentation for usage")
+
+ local input_results
+ if vim.tbl_islist(opts) then
+ input_results = opts
+ else
+ input_results = opts.results
+ end
+
+ local entry_maker = opts.entry_maker or make_entry.gen_from_string()
+
+ assert(input_results)
+ assert(input_results, "Results are required for static finder")
+ assert(type(input_results) == 'table', "self.results must be a table")
+
+ local results = {}
+ for _, v in ipairs(input_results) do
+ table.insert(results, entry_maker(v))
+ end
+
+ return setmetatable({ results = results }, self)
+end
+
+function StaticFinder:_find(_, process_result, process_complete)
+ for _, v in ipairs(self.results) do
+ process_result(v)
+ end
+
+ process_complete()
+end
+
+
+-- local
+
+
--- Return a new Finder
--
---@return Finder
-finders.new = function(opts)
- return Finder:new(opts)
-end
+-- Use at your own risk.
+-- This opts dictionary is likely to change, but you are welcome to use it right now.
+-- I will try not to change it needlessly, but I will change it sometimes and I won't feel bad.
+finders._new = function(opts)
+ if opts.results then
+ print("finder.new is deprecated with `results`. You should use `finder.new_table`")
+ return StaticFinder:new(opts)
+ end
--- TODO: Is this worth making?
--- finders.new_responsive_job = function(opts)
--- return finders.new {
--- maximum_results = get_default(opts.maximum_results, 2000),
--- }
--- end
+ return JobFinder:new(opts)
+end
-finders.new_job = function(command_generator)
- return finders.new {
+finders.new_job = function(command_generator, entry_maker, maximum_results)
+ return JobFinder:new {
fn_command = function(_, prompt)
local command_list = command_generator(prompt)
if command_list == nil then
@@ -168,19 +202,24 @@ finders.new_job = function(command_generator)
command = command,
args = command_list,
}
- end
+ end,
+
+ entry_maker = entry_maker,
+ maximum_results = maximum_results,
}
end
+---@param command_list string[] Command list to execute.
+---@param entry_maker function Optional: function(line: string) => table
finders.new_oneshot_job = function(command_list, entry_maker)
command_list = vim.deepcopy(command_list)
local command = table.remove(command_list, 1)
- return finders.new {
+ return JobFinder:new {
static = true,
- entry_maker = entry_maker,
+ entry_maker = entry_maker or make_entry.from_string,
fn_command = function()
return {
@@ -191,18 +230,14 @@ finders.new_oneshot_job = function(command_list, entry_maker)
}
end
+--- Used to create a finder for a Lua table.
+-- If you only pass a table of results, then it will use that as the entries.
+--
+-- If you pass a table, and then a function, it's used as:
+-- results table, the results to run on
+-- entry_maker function, the function to convert results to entries.
finders.new_table = function(t)
- return finders.new {
- results = t
- }
+ return StaticFinder:new(t)
end
--- We should add a few utility functions here...
---
--- finders.new_job
--- finders.new_one_shot_job
--- finders.new_table
-
--- finders.Finder = Finder
-
return finders
diff --git a/lua/telescope/make_entry.lua b/lua/telescope/make_entry.lua
new file mode 100644
index 0000000..aca8894
--- /dev/null
+++ b/lua/telescope/make_entry.lua
@@ -0,0 +1,162 @@
+local has_devicons, devicons = pcall(require, 'nvim-web-devicons')
+
+local utils = require('telescope.utils')
+
+local make_entry = {}
+
+make_entry.types = {
+ GENERIC = 0,
+ FILE = 1,
+}
+
+local transform_devicons
+if has_devicons then
+ transform_devicons = function(filename, display, opts)
+ if opts.disable_devicons then
+ return display
+ end
+
+ return (devicons.get_icon(filename, string.match(filename, '%a+$')) or ' ') .. ' ' .. display
+ end
+else
+ transform_devicons = function(_, display, _)
+ return display
+ end
+end
+
+function make_entry.gen_from_string()
+ return function(line)
+ return {
+ valid = line ~= "",
+ entry_type = make_entry.types.SIMPLE,
+
+ value = line,
+ ordinal = line,
+ display = line,
+ }
+ end
+end
+
+function make_entry.gen_from_file(opts)
+ opts = opts or {}
+
+ local make_display = function(line)
+ local display = line
+ if opts.shorten_path then
+ display = utils.path_shorten(line)
+ end
+
+ display = transform_devicons(line, display, opts)
+
+ return display
+ end
+
+ return function(line)
+ local entry = {
+ ordinal = line,
+ value = line,
+
+ entry_type = make_entry.types.FILE,
+ filename = line,
+ }
+
+ entry.display = make_display(line)
+
+ return entry
+ end
+end
+
+function make_entry.gen_from_vimgrep(opts)
+ opts = opts or {}
+
+ local display_string = "%s:%s%s"
+
+ local make_display = function(entry)
+ local display = entry.value
+
+ local display_filename
+ if opts.shorten_path then
+ display_filename = utils.path_shorten(entry.filename)
+ else
+ display_filename = entry.filename
+ end
+
+ local coordinates = ""
+ if not opts.disable_coordinates then
+ coordinates = string.format("%s:%s:", entry.lnum, entry.col)
+ end
+
+ display = transform_devicons(
+ entry.filename,
+ string.format(display_string, display_filename, coordinates, entry.text),
+ opts
+ )
+
+ return display
+ end
+
+ return function(line)
+ -- TODO: Consider waiting to do this string.find
+ -- TODO: Is this the fastest way to get each of these?
+ -- Or could we just walk the text and check for colons faster?
+ local _, _, filename, lnum, col, text = string.find(line, [[([^:]+):(%d+):(%d+):(.*)]])
+
+ return {
+ valid = line ~= "",
+
+ value = line,
+ ordinal = line,
+ display = make_display,
+
+ entry_type = make_entry.types.FILE,
+ filename = filename,
+ lnum = lnum,
+ col = col,
+ text = text,
+ }
+ end
+end
+
+function make_entry.gen_from_quickfix(opts)
+ opts = opts or {}
+
+ local make_display = function(entry)
+ local to_concat = {}
+
+ if not opts.hide_filename then
+ local filename = entry.filename
+ if opts.shorten_path then
+ filename = utils.path_shorten(filename)
+ end
+
+ table.insert(to_concat, filename)
+ table.insert(to_concat, ":")
+ end
+
+ table.insert(to_concat, entry.text)
+
+ return table.concat(to_concat, "")
+ end
+
+ return function(entry)
+ return {
+ valid = true,
+
+ value = entry,
+ ordinal = (
+ not opts.ignore_filename and entry.filename
+ or ''
+ ) .. ' ' .. entry.text,
+ display = make_display,
+
+ filename = entry.filename,
+ lnum = entry.lnum,
+ col = entry.col,
+ text = entry.text,
+ start = entry.start,
+ finish = entry.finish,
+ }
+ end
+end
+
+return make_entry
diff --git a/lua/telescope/pickers.lua b/lua/telescope/pickers.lua
index 23b5917..f109db7 100644
--- a/lua/telescope/pickers.lua
+++ b/lua/telescope/pickers.lua
@@ -1,6 +1,5 @@
local a = vim.api
local popup = require('popup')
-local has_devicons, devicons = pcall(require, 'nvim-web-devicons')
local actions = require('telescope.actions')
local log = require('telescope.log')
@@ -8,8 +7,6 @@ local mappings = require('telescope.mappings')
local state = require('telescope.state')
local utils = require('telescope.utils')
-local Entry = require('telescope.entry')
-
local get_default = utils.get_default
-- TODO: Make this work with deep extend I think.
@@ -255,14 +252,19 @@ function Picker:find()
return
end
- -- TODO: This really isn't the place to do this.
- local display = entry.display
-
- if has_devicons then
- local icon = devicons.get_icon(display, vim.fn.fnamemodify(display, ":e"))
- display = (icon or ' ') .. ' ' .. display
+ local display
+ if type(entry.display) == 'function' then
+ display = entry:display()
+ elseif type(entry.display) == 'string' then
+ display = entry.display
+ else
+ log.info("Weird entry", entry)
+ return
end
+ -- This is the two spaces to manage the '> ' stuff.
+ -- Maybe someday we can use extmarks or floaty text or something to draw this and not insert here.
+ -- until then, insert two spaces
display = ' ' .. display
-- log.info("Setting row", row, "with value", entry)
@@ -277,10 +279,9 @@ function Picker:find()
end
))
- local process_result = function(line)
- local entry = Entry:new(line)
-
- if not entry.valid then
+ local process_result = function(entry)
+ -- TODO: Should we even have valid?
+ if entry.valid == false then
return
end
@@ -559,10 +560,7 @@ pickers.entry_manager = function(max_results, set_entry)
return setmetatable({
add_entry = function(self, score, entry)
- -- TODO: Consider forcing people to make these entries before we add them.
- if type(entry) == "string" then
- entry = Entry:new(entry)
- end
+ assert(type(entry) == "table", "entry must be a table by the time it reaches here")
score = score or 0
@@ -647,6 +645,10 @@ function pickers.on_close_prompt(prompt_bufnr)
local picker = status.picker
picker:close_windows(status)
+
+ if picker.previewer then
+ picker.previewer:teardown()
+ end
end
diff --git a/lua/telescope/previewers.lua b/lua/telescope/previewers.lua
index 224cda0..c1acbee 100644
--- a/lua/telescope/previewers.lua
+++ b/lua/telescope/previewers.lua
@@ -8,6 +8,7 @@ local Previewer = {}
Previewer.__index = Previewer
local bat_options = " --style=grid --paging=always "
+local previewer_ns = vim.api.nvim_create_namespace('telescope.previewers')
-- --terminal-width=%s
-- TODO: We shoudl make sure that all our terminals close all the way.
@@ -20,6 +21,7 @@ function Previewer:new(opts)
return setmetatable({
state = nil,
_setup_func = opts.setup,
+ _teardown_func = opts.teardown,
preview_fn = opts.preview_fn,
}, Previewer)
end
@@ -29,13 +31,22 @@ function Previewer:preview(entry, status)
return
end
- if not self.state and self._setup_func then
- self.state = self._setup_func()
+ if not self.state then
+ if self._setup_func then
+ self.state = self._setup_func()
+ end
end
+ self:teardown()
return self:preview_fn(entry, status)
end
+function Previewer:teardown()
+ if self._teardown_func then
+ self:_teardown_func()
+ end
+end
+
previewers.new = function(...)
return Previewer:new(...)
end
@@ -69,20 +80,36 @@ previewers.new_termopen = function(opts)
end
previewers.vim_buffer = previewers.new {
- preview_fn = function(_, entry, status)
- local value = entry.value
- if value == nil then
+ setup = function() return { last_set_bufnr = nil } end,
+
+ teardown = function(self)
+ if self.state.last_set_bufnr then
+ vim.api.nvim_buf_clear_namespace(self.state.last_set_bufnr, previewer_ns, 0, -1)
+ end
+ end,
+
+ preview_fn = function(self, entry, status)
+ local filename = entry.filename
+
+ if filename == nil then
+ local value = entry.value
+ filename = vim.split(value, ":")[1]
+ end
+
+ if filename == nil then
return
end
- local file_name = vim.split(value, ":")[1]
- log.trace("Previewing File: %s", file_name)
+ log.trace("Previewing File: %s", filename)
- -- vim.fn.termopen(
- -- string.format("bat --color=always --style=grid %s"),
- -- vim.fn.fnamemodify(file_name, ":p")
- local bufnr = vim.fn.bufadd(file_name)
- vim.fn.bufload(bufnr)
+ local bufnr = vim.fn.bufnr(filename)
+ if bufnr == -1 then
+ -- TODO: Is this the best way to load the buffer?... I'm not sure tbh
+ bufnr = vim.fn.bufadd(bufnr)
+ vim.fn.bufload(bufnr)
+ end
+
+ self.state.last_set_bufnr = bufnr
-- TODO: We should probably call something like this because we're not always getting highlight and all that stuff.
-- api.nvim_command('doautocmd filetypedetect BufRead ' .. vim.fn.fnameescape(filename))
@@ -92,6 +119,11 @@ previewers.vim_buffer = previewers.new {
-- vim.api.nvim_win_set_option(preview_win, 'winblend', 20)
vim.api.nvim_win_set_option(status.preview_win, 'signcolumn', 'no')
vim.api.nvim_win_set_option(status.preview_win, 'foldlevel', 100)
+
+ if entry.lnum then
+ vim.api.nvim_buf_add_highlight(bufnr, previewer_ns, "Visual", entry.lnum - 1, 0, -1)
+ -- print("LNUM:", entry.lnum)
+ end
end,
}
diff --git a/lua/telescope/utils.lua b/lua/telescope/utils.lua
index 030d942..b95f626 100644
--- a/lua/telescope/utils.lua
+++ b/lua/telescope/utils.lua
@@ -99,6 +99,10 @@ utils.path_shorten = (function()
]]
return function(path)
+ if not path then
+ return path
+ end
+
local c_str = ffi.new("char[?]", #path + 1)
ffi.copy(c_str, path)
return ffi.string(ffi.C.shorten_dir(c_str))
diff --git a/lua/tests/manual/newline_tables.lua b/lua/tests/manual/newline_tables.lua
index 879d006..26d2b89 100644
--- a/lua/tests/manual/newline_tables.lua
+++ b/lua/tests/manual/newline_tables.lua
@@ -1,15 +1,21 @@
-RELOAD('telescope')
+require('plenary.reload').reload_module('telescope')
-local actions = require('telescope.actions')
local finders = require('telescope.finders')
-local previewers = require('telescope.previewers')
local pickers = require('telescope.pickers')
local sorters = require('telescope.sorters')
-local utils = require('telescope.utils')
pickers.new({
prompt = 'Telescope Builtin',
- finder = finders.new_table({"hello\nworld", "other", "item"}),
+ finder = finders.new_table {
+ results = {"hello\nworld", "other", "item"},
+ entry_maker = false and function(line)
+ return {
+ value = line,
+ ordinal = line,
+ display = "wow: // " .. line,
+ }
+ end,
+ },
sorter = sorters.get_norcalli_sorter(),
}):find()