1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-24 09:50:04 +08:00
SpaceVim/bundle/telescope.nvim-0.1.8/lua/telescope/builtin/__internal.lua

1417 lines
41 KiB
Lua

local actions = require "telescope.actions"
local action_set = require "telescope.actions.set"
local action_state = require "telescope.actions.state"
local finders = require "telescope.finders"
local make_entry = require "telescope.make_entry"
local Path = require "plenary.path"
local pickers = require "telescope.pickers"
local previewers = require "telescope.previewers"
local p_window = require "telescope.pickers.window"
local state = require "telescope.state"
local utils = require "telescope.utils"
local conf = require("telescope.config").values
-- Makes sure aliased options are set correctly
local function apply_cwd_only_aliases(opts)
local has_cwd_only = opts.cwd_only ~= nil
local has_only_cwd = opts.only_cwd ~= nil
if has_only_cwd and not has_cwd_only then
-- Internally, use cwd_only
opts.cwd_only = opts.only_cwd
opts.only_cwd = nil
end
return opts
end
---@return boolean
local function buf_in_cwd(bufname, cwd)
if cwd:sub(-1) ~= Path.path.sep then
cwd = cwd .. Path.path.sep
end
local bufname_prefix = bufname:sub(1, #cwd)
return bufname_prefix == cwd
end
local internal = {}
internal.builtin = function(opts)
opts.include_extensions = vim.F.if_nil(opts.include_extensions, false)
opts.use_default_opts = vim.F.if_nil(opts.use_default_opts, false)
local objs = {}
for k, v in pairs(require "telescope.builtin") do
local debug_info = debug.getinfo(v)
table.insert(objs, {
filename = string.sub(debug_info.source, 2),
text = k,
})
end
local title = "Telescope Builtin"
if opts.include_extensions then
title = "Telescope Pickers"
for ext, funcs in pairs(require("telescope").extensions) do
for func_name, func_obj in pairs(funcs) do
-- Only include exported functions whose name doesn't begin with an underscore
if type(func_obj) == "function" and string.sub(func_name, 0, 1) ~= "_" then
local debug_info = debug.getinfo(func_obj)
table.insert(objs, {
filename = string.sub(debug_info.source, 2),
text = string.format("%s : %s", ext, func_name),
})
end
end
end
end
table.sort(objs, function(a, b)
return a.text < b.text
end)
opts.bufnr = vim.api.nvim_get_current_buf()
opts.winnr = vim.api.nvim_get_current_win()
pickers
.new(opts, {
prompt_title = title,
finder = finders.new_table {
results = objs,
entry_maker = function(entry)
return make_entry.set_default_entry_mt({
value = entry,
text = entry.text,
display = entry.text,
ordinal = entry.text,
filename = entry.filename,
}, opts)
end,
},
previewer = previewers.builtin.new(opts),
sorter = conf.generic_sorter(opts),
attach_mappings = function(_)
actions.select_default:replace(function(prompt_bufnr)
local selection = action_state.get_selected_entry()
if not selection then
utils.__warn_no_selection "builtin.builtin"
return
end
-- we do this to avoid any surprises
opts.include_extensions = nil
local picker_opts
if not opts.use_default_opts then
picker_opts = opts
end
actions.close(prompt_bufnr)
if string.match(selection.text, " : ") then
-- Call appropriate function from extensions
local split_string = vim.split(selection.text, " : ")
local ext = split_string[1]
local func = split_string[2]
require("telescope").extensions[ext][func](picker_opts)
else
-- Call appropriate telescope builtin
require("telescope.builtin")[selection.text](picker_opts)
end
end)
return true
end,
})
:find()
end
internal.resume = function(opts)
opts = opts or {}
opts.cache_index = vim.F.if_nil(opts.cache_index, 1)
local cached_pickers = state.get_global_key "cached_pickers"
if cached_pickers == nil or vim.tbl_isempty(cached_pickers) then
utils.notify("builtin.resume", {
msg = "No cached picker(s).",
level = "INFO",
})
return
end
local picker = cached_pickers[opts.cache_index]
if picker == nil then
utils.notify("builtin.resume", {
msg = string.format("Index too large as there are only '%s' pickers cached", #cached_pickers),
level = "ERROR",
})
return
end
-- reset layout strategy and get_window_options if default as only one is valid
-- and otherwise unclear which was actually set
if picker.layout_strategy == conf.layout_strategy then
picker.layout_strategy = nil
end
if picker.get_window_options == p_window.get_window_options then
picker.get_window_options = nil
end
picker.cache_picker.index = opts.cache_index
-- avoid partial `opts.cache_picker` at picker creation
if opts.cache_picker ~= false then
picker.cache_picker = vim.tbl_extend("keep", opts.cache_picker or {}, picker.cache_picker)
else
picker.cache_picker.disabled = true
end
opts.cache_picker = nil
picker.previewer = picker.all_previewers
if picker.hidden_previewer then
picker.hidden_previewer = nil
opts.previewer = vim.F.if_nil(opts.previewer, false)
end
opts.resumed_picker = true
pickers.new(opts, picker):find()
end
internal.pickers = function(opts)
local cached_pickers = state.get_global_key "cached_pickers"
if cached_pickers == nil or vim.tbl_isempty(cached_pickers) then
utils.notify("builtin.pickers", {
msg = "No cached picker(s).",
level = "INFO",
})
return
end
opts = opts or {}
-- clear cache picker for immediate pickers.new and pass option to resumed picker
if opts.cache_picker ~= nil then
opts._cache_picker = opts.cache_picker
opts.cache_picker = nil
end
pickers
.new(opts, {
prompt_title = "Pickers",
finder = finders.new_table {
results = cached_pickers,
entry_maker = make_entry.gen_from_picker(opts),
},
previewer = previewers.pickers.new(opts),
sorter = conf.generic_sorter(opts),
cache_picker = false,
attach_mappings = function(_, map)
actions.select_default:replace(function(prompt_bufnr)
local curr_picker = action_state.get_current_picker(prompt_bufnr)
local curr_entry = action_state.get_selected_entry()
if not curr_entry then
return
end
actions.close(prompt_bufnr)
local selection_index, _ = utils.list_find(function(v)
if curr_entry.value == v.value then
return true
end
return false
end, curr_picker.finder.results)
opts.cache_picker = opts._cache_picker
opts["cache_index"] = selection_index
opts["initial_mode"] = cached_pickers[selection_index].initial_mode
internal.resume(opts)
end)
map({ "i", "n" }, "<C-x>", actions.remove_selected_picker)
return true
end,
})
:find()
end
internal.planets = function(opts)
local show_pluto = opts.show_pluto or false
local show_moon = opts.show_moon or false
local sourced_file = require("plenary.debug_utils").sourced_filepath()
local base_directory = vim.fn.fnamemodify(sourced_file, ":h:h:h:h")
local globbed_files = vim.fn.globpath(base_directory .. "/data/memes/planets/", "*", true, true)
local acceptable_files = {}
for _, v in ipairs(globbed_files) do
if (show_pluto or not v:find "pluto") and (show_moon or not v:find "moon") then
table.insert(acceptable_files, vim.fn.fnamemodify(v, ":t"))
end
end
pickers
.new(opts, {
prompt_title = "Planets",
finder = finders.new_table {
results = acceptable_files,
entry_maker = function(line)
return make_entry.set_default_entry_mt({
ordinal = line,
display = line,
filename = base_directory .. "/data/memes/planets/" .. line,
}, opts)
end,
},
previewer = previewers.cat.new(opts),
sorter = conf.generic_sorter(opts),
attach_mappings = function(prompt_bufnr)
actions.select_default:replace(function()
local selection = action_state.get_selected_entry()
if selection == nil then
utils.__warn_no_selection "builtin.planets"
return
end
actions.close(prompt_bufnr)
print("Enjoy astronomy! You viewed:", selection.display)
end)
return true
end,
})
:find()
end
internal.symbols = function(opts)
local initial_mode = vim.fn.mode()
local files = vim.api.nvim_get_runtime_file("data/telescope-sources/*.json", true)
local data_path = (function()
if not opts.symbol_path then
return Path:new { vim.fn.stdpath "data", "telescope", "symbols" }
else
return Path:new { opts.symbol_path }
end
end)()
if data_path:exists() then
for _, v in ipairs(require("plenary.scandir").scan_dir(data_path:absolute(), { search_pattern = "%.json$" })) do
table.insert(files, v)
end
end
if #files == 0 then
utils.notify("builtin.symbols", {
msg = "No sources found! Check out https://github.com/nvim-telescope/telescope-symbols.nvim "
.. "for some prebuild symbols or how to create you own symbol source.",
level = "ERROR",
})
return
end
local sources = {}
if opts.sources then
for _, v in ipairs(files) do
for _, s in ipairs(opts.sources) do
if v:find(s) then
table.insert(sources, v)
end
end
end
else
sources = files
end
local results = {}
for _, source in ipairs(sources) do
local data = vim.json.decode(Path:new(source):read())
for _, entry in ipairs(data) do
table.insert(results, entry)
end
end
pickers
.new(opts, {
prompt_title = "Symbols",
finder = finders.new_table {
results = results,
entry_maker = function(entry)
return make_entry.set_default_entry_mt({
value = entry,
ordinal = entry[1] .. " " .. entry[2],
display = entry[1] .. " " .. entry[2],
}, opts)
end,
},
sorter = conf.generic_sorter(opts),
attach_mappings = function(_)
if initial_mode == "i" then
actions.select_default:replace(actions.insert_symbol_i)
else
actions.select_default:replace(actions.insert_symbol)
end
return true
end,
})
:find()
end
internal.commands = function(opts)
pickers
.new(opts, {
prompt_title = "Commands",
finder = finders.new_table {
results = (function()
local command_iter = vim.api.nvim_get_commands {}
local commands = {}
for _, cmd in pairs(command_iter) do
table.insert(commands, cmd)
end
local need_buf_command = vim.F.if_nil(opts.show_buf_command, true)
if need_buf_command then
local buf_command_iter = vim.api.nvim_buf_get_commands(0, {})
buf_command_iter[true] = nil -- remove the redundant entry
for _, cmd in pairs(buf_command_iter) do
table.insert(commands, cmd)
end
end
return commands
end)(),
entry_maker = opts.entry_maker or make_entry.gen_from_commands(opts),
},
sorter = conf.generic_sorter(opts),
attach_mappings = function(prompt_bufnr)
actions.select_default:replace(function()
local selection = action_state.get_selected_entry()
if selection == nil then
utils.__warn_no_selection "builtin.commands"
return
end
actions.close(prompt_bufnr)
local val = selection.value
local cmd = string.format([[:%s ]], val.name)
if val.nargs == "0" then
local cr = vim.api.nvim_replace_termcodes("<cr>", true, false, true)
cmd = cmd .. cr
end
vim.cmd [[stopinsert]]
vim.api.nvim_feedkeys(cmd, "nt", false)
end)
return true
end,
})
:find()
end
internal.quickfix = function(opts)
local qf_identifier = opts.id or vim.F.if_nil(opts.nr, "$")
local locations = vim.fn.getqflist({ [opts.id and "id" or "nr"] = qf_identifier, items = true }).items
if vim.tbl_isempty(locations) then
utils.notify("builtin.quickfix", { msg = "No quickfix items", level = "INFO" })
return
end
pickers
.new(opts, {
prompt_title = "Quickfix",
finder = finders.new_table {
results = locations,
entry_maker = opts.entry_maker or make_entry.gen_from_quickfix(opts),
},
previewer = conf.qflist_previewer(opts),
sorter = conf.generic_sorter(opts),
})
:find()
end
internal.quickfixhistory = function(opts)
local qflists = {}
for i = 1, 10 do -- (n)vim keeps at most 10 quickfix lists in full
-- qf weirdness: id = 0 gets id of quickfix list nr
local qflist = vim.fn.getqflist { nr = i, id = 0, title = true, items = true }
if not vim.tbl_isempty(qflist.items) then
table.insert(qflists, qflist)
end
end
local entry_maker = opts.make_entry
or function(entry)
return make_entry.set_default_entry_mt({
value = entry.title or "Untitled",
ordinal = entry.title or "Untitled",
display = entry.title or "Untitled",
nr = entry.nr,
id = entry.id,
items = entry.items,
}, opts)
end
local qf_entry_maker = make_entry.gen_from_quickfix(opts)
pickers
.new(opts, {
prompt_title = "Quickfix History",
finder = finders.new_table {
results = qflists,
entry_maker = entry_maker,
},
previewer = previewers.new_buffer_previewer {
title = "Quickfix List Preview",
dyn_title = function(_, entry)
return entry.title
end,
get_buffer_by_name = function(_, entry)
return "quickfixlist_" .. tostring(entry.nr)
end,
define_preview = function(self, entry)
if self.state.bufname then
return
end
local entries = vim.tbl_map(function(i)
return qf_entry_maker(i):display()
end, entry.items)
vim.api.nvim_buf_set_lines(self.state.bufnr, 0, -1, false, entries)
end,
},
sorter = conf.generic_sorter(opts),
attach_mappings = function(_, _)
action_set.select:replace(function(prompt_bufnr)
local nr = action_state.get_selected_entry().nr
actions.close(prompt_bufnr)
internal.quickfix { nr = nr }
end)
return true
end,
})
:find()
end
internal.loclist = function(opts)
local locations = vim.fn.getloclist(0)
local filenames = {}
for _, value in pairs(locations) do
local bufnr = value.bufnr
if filenames[bufnr] == nil then
filenames[bufnr] = vim.api.nvim_buf_get_name(bufnr)
end
value.filename = filenames[bufnr]
end
if vim.tbl_isempty(locations) then
utils.notify("builtin.loclist", { msg = "No loclist items", level = "INFO" })
return
end
pickers
.new(opts, {
prompt_title = "Loclist",
finder = finders.new_table {
results = locations,
entry_maker = opts.entry_maker or make_entry.gen_from_quickfix(opts),
},
previewer = conf.qflist_previewer(opts),
sorter = conf.generic_sorter(opts),
})
:find()
end
internal.oldfiles = function(opts)
opts = apply_cwd_only_aliases(opts)
opts.include_current_session = vim.F.if_nil(opts.include_current_session, true)
local current_buffer = vim.api.nvim_get_current_buf()
local current_file = vim.api.nvim_buf_get_name(current_buffer)
local results = {}
if opts.include_current_session then
for _, buffer in ipairs(vim.split(vim.fn.execute ":buffers! t", "\n")) do
local match = tonumber(string.match(buffer, "%s*(%d+)"))
local open_by_lsp = string.match(buffer, "line 0$")
if match and not open_by_lsp then
local file = vim.api.nvim_buf_get_name(match)
if vim.loop.fs_stat(file) and match ~= current_buffer then
table.insert(results, file)
end
end
end
end
for _, file in ipairs(vim.v.oldfiles) do
local file_stat = vim.loop.fs_stat(file)
if file_stat and file_stat.type == "file" and not vim.tbl_contains(results, file) and file ~= current_file then
table.insert(results, file)
end
end
if opts.cwd_only or opts.cwd then
local cwd = opts.cwd_only and vim.loop.cwd() or opts.cwd
cwd = cwd .. utils.get_separator()
results = vim.tbl_filter(function(file)
return buf_in_cwd(file, cwd)
end, results)
end
pickers
.new(opts, {
prompt_title = "Oldfiles",
finder = finders.new_table {
results = results,
entry_maker = opts.entry_maker or make_entry.gen_from_file(opts),
},
sorter = conf.file_sorter(opts),
previewer = conf.file_previewer(opts),
})
:find()
end
internal.command_history = function(opts)
local history_string = vim.fn.execute "history cmd"
local history_list = vim.split(history_string, "\n")
local results = {}
for i = #history_list, 3, -1 do
local item = history_list[i]
local _, finish = string.find(item, "%d+ +")
table.insert(results, string.sub(item, finish + 1))
end
pickers
.new(opts, {
prompt_title = "Command History",
finder = finders.new_table(results),
sorter = conf.generic_sorter(opts),
attach_mappings = function(_, map)
actions.select_default:replace(actions.set_command_line)
map({ "i", "n" }, "<C-e>", actions.edit_command_line)
-- TODO: Find a way to insert the text... it seems hard.
-- map('i', '<C-i>', actions.insert_value, { expr = true })
return true
end,
})
:find()
end
internal.search_history = function(opts)
local search_string = vim.fn.execute "history search"
local search_list = vim.split(search_string, "\n")
local results = {}
for i = #search_list, 3, -1 do
local item = search_list[i]
local _, finish = string.find(item, "%d+ +")
table.insert(results, string.sub(item, finish + 1))
end
pickers
.new(opts, {
prompt_title = "Search History",
finder = finders.new_table(results),
sorter = conf.generic_sorter(opts),
attach_mappings = function(_, map)
actions.select_default:replace(actions.set_search_line)
map({ "i", "n" }, "<C-e>", actions.edit_search_line)
-- TODO: Find a way to insert the text... it seems hard.
-- map('i', '<C-i>', actions.insert_value, { expr = true })
return true
end,
})
:find()
end
internal.vim_options = function(opts)
local res = {}
for _, v in pairs(vim.api.nvim_get_all_options_info()) do
table.insert(res, v)
end
table.sort(res, function(left, right)
return left.name < right.name
end)
pickers
.new(opts, {
prompt_title = "options",
finder = finders.new_table {
results = res,
entry_maker = opts.entry_maker or make_entry.gen_from_vimoptions(opts),
},
sorter = conf.generic_sorter(opts),
attach_mappings = function()
actions.select_default:replace(function()
local selection = action_state.get_selected_entry()
if selection == nil then
utils.__warn_no_selection "builtin.vim_options"
return
end
local esc = ""
if vim.fn.mode() == "i" then
esc = vim.api.nvim_replace_termcodes("<esc>", true, false, true)
end
vim.api.nvim_feedkeys(
string.format("%s:set %s=%s", esc, selection.value.name, selection.value.value),
"m",
true
)
end)
return true
end,
})
:find()
end
internal.help_tags = function(opts)
opts.lang = vim.F.if_nil(opts.lang, vim.o.helplang)
opts.fallback = vim.F.if_nil(opts.fallback, true)
opts.file_ignore_patterns = {}
local langs = vim.split(opts.lang, ",", true)
if opts.fallback and not vim.tbl_contains(langs, "en") then
table.insert(langs, "en")
end
local langs_map = {}
for _, lang in ipairs(langs) do
langs_map[lang] = true
end
local tag_files = {}
local function add_tag_file(lang, file)
if langs_map[lang] then
if tag_files[lang] then
table.insert(tag_files[lang], file)
else
tag_files[lang] = { file }
end
end
end
local help_files = {}
local all_files = vim.api.nvim_get_runtime_file("doc/*", true)
for _, fullpath in ipairs(all_files) do
local file = utils.path_tail(fullpath)
if file == "tags" then
add_tag_file("en", fullpath)
elseif file:match "^tags%-..$" then
local lang = file:sub(-2)
add_tag_file(lang, fullpath)
else
help_files[file] = fullpath
end
end
local tags = {}
local tags_map = {}
local delimiter = string.char(9)
for _, lang in ipairs(langs) do
for _, file in ipairs(tag_files[lang] or {}) do
local lines = vim.split(Path:new(file):read(), "\n", true)
for _, line in ipairs(lines) do
-- TODO: also ignore tagComment starting with ';'
if not line:match "^!_TAG_" then
local fields = vim.split(line, delimiter, true)
if #fields == 3 and not tags_map[fields[1]] then
if fields[1] ~= "help-tags" or fields[2] ~= "tags" then
table.insert(tags, {
name = fields[1],
filename = help_files[fields[2]],
cmd = fields[3],
lang = lang,
})
tags_map[fields[1]] = true
end
end
end
end
end
end
pickers
.new(opts, {
prompt_title = "Help",
finder = finders.new_table {
results = tags,
entry_maker = function(entry)
return make_entry.set_default_entry_mt({
value = entry.name .. "@" .. entry.lang,
display = entry.name,
ordinal = entry.name,
filename = entry.filename,
cmd = entry.cmd,
}, opts)
end,
},
previewer = previewers.help.new(opts),
sorter = conf.generic_sorter(opts),
attach_mappings = function(prompt_bufnr)
action_set.select:replace(function(_, cmd)
local selection = action_state.get_selected_entry()
if selection == nil then
utils.__warn_no_selection "builtin.help_tags"
return
end
actions.close(prompt_bufnr)
if cmd == "default" or cmd == "horizontal" then
vim.cmd("help " .. selection.value)
elseif cmd == "vertical" then
vim.cmd("vert help " .. selection.value)
elseif cmd == "tab" then
vim.cmd("tab help " .. selection.value)
end
end)
return true
end,
})
:find()
end
internal.man_pages = function(opts)
opts.sections = vim.F.if_nil(opts.sections, { "1" })
assert(utils.islist(opts.sections), "sections should be a list")
opts.man_cmd = utils.get_lazy_default(opts.man_cmd, function()
local uname = vim.loop.os_uname()
local sysname = string.lower(uname.sysname)
if sysname == "darwin" then
local major_version = tonumber(vim.fn.matchlist(uname.release, [[^\(\d\+\)\..*]])[2]) or 0
return major_version >= 22 and { "apropos", "." } or { "apropos", " " }
elseif sysname == "freebsd" then
return { "apropos", "." }
else
return { "apropos", "" }
end
end)
opts.entry_maker = opts.entry_maker or make_entry.gen_from_apropos(opts)
opts.env = { PATH = vim.env.PATH, MANPATH = vim.env.MANPATH }
pickers
.new(opts, {
prompt_title = "Man",
finder = finders.new_oneshot_job(opts.man_cmd, opts),
previewer = previewers.man.new(opts),
sorter = conf.generic_sorter(opts),
attach_mappings = function(prompt_bufnr)
action_set.select:replace(function(_, cmd)
local selection = action_state.get_selected_entry()
if selection == nil then
utils.__warn_no_selection "builtin.man_pages"
return
end
local args = selection.section .. " " .. selection.value
actions.close(prompt_bufnr)
if cmd == "default" or cmd == "horizontal" then
vim.cmd("Man " .. args)
elseif cmd == "vertical" then
vim.cmd("vert Man " .. args)
elseif cmd == "tab" then
vim.cmd("tab Man " .. args)
end
end)
return true
end,
})
:find()
end
internal.reloader = function(opts)
local package_list = vim.tbl_keys(package.loaded)
-- filter out packages we don't want and track the longest package name
local column_len = 0
for index, module_name in pairs(package_list) do
if
type(require(module_name)) ~= "table"
or module_name:sub(1, 1) == "_"
or package.searchpath(module_name, package.path) == nil
then
table.remove(package_list, index)
elseif #module_name > column_len then
column_len = #module_name
end
end
opts.column_len = vim.F.if_nil(opts.column_len, column_len)
pickers
.new(opts, {
prompt_title = "Packages",
finder = finders.new_table {
results = package_list,
entry_maker = opts.entry_maker or make_entry.gen_from_packages(opts),
},
-- previewer = previewers.vim_buffer.new(opts),
sorter = conf.generic_sorter(opts),
attach_mappings = function(prompt_bufnr)
actions.select_default:replace(function()
local selection = action_state.get_selected_entry()
if selection == nil then
utils.__warn_no_selection "builtin.reloader"
return
end
actions.close(prompt_bufnr)
require("plenary.reload").reload_module(selection.value)
utils.notify("builtin.reloader", {
msg = string.format("[%s] - module reloaded", selection.value),
level = "INFO",
})
end)
return true
end,
})
:find()
end
internal.buffers = function(opts)
opts = apply_cwd_only_aliases(opts)
local bufnrs = vim.tbl_filter(function(bufnr)
if 1 ~= vim.fn.buflisted(bufnr) then
return false
end
-- only hide unloaded buffers if opts.show_all_buffers is false, keep them listed if true or nil
if opts.show_all_buffers == false and not vim.api.nvim_buf_is_loaded(bufnr) then
return false
end
if opts.ignore_current_buffer and bufnr == vim.api.nvim_get_current_buf() then
return false
end
local bufname = vim.api.nvim_buf_get_name(bufnr)
if opts.cwd_only and not buf_in_cwd(bufname, vim.loop.cwd()) then
return false
end
if not opts.cwd_only and opts.cwd and not buf_in_cwd(bufname, opts.cwd) then
return false
end
return true
end, vim.api.nvim_list_bufs())
if not next(bufnrs) then
utils.notify("builtin.buffers", { msg = "No buffers found with the provided options", level = "INFO" })
return
end
if opts.sort_mru then
table.sort(bufnrs, function(a, b)
return vim.fn.getbufinfo(a)[1].lastused > vim.fn.getbufinfo(b)[1].lastused
end)
end
local buffers = {}
local default_selection_idx = 1
for _, bufnr in ipairs(bufnrs) do
local flag = bufnr == vim.fn.bufnr "" and "%" or (bufnr == vim.fn.bufnr "#" and "#" or " ")
if opts.sort_lastused and not opts.ignore_current_buffer and flag == "#" then
default_selection_idx = 2
end
local element = {
bufnr = bufnr,
flag = flag,
info = vim.fn.getbufinfo(bufnr)[1],
}
if opts.sort_lastused and (flag == "#" or flag == "%") then
local idx = ((buffers[1] ~= nil and buffers[1].flag == "%") and 2 or 1)
table.insert(buffers, idx, element)
else
table.insert(buffers, element)
end
end
if not opts.bufnr_width then
local max_bufnr = math.max(unpack(bufnrs))
opts.bufnr_width = #tostring(max_bufnr)
end
pickers
.new(opts, {
prompt_title = "Buffers",
finder = finders.new_table {
results = buffers,
entry_maker = opts.entry_maker or make_entry.gen_from_buffer(opts),
},
previewer = conf.grep_previewer(opts),
sorter = conf.generic_sorter(opts),
default_selection_index = default_selection_idx,
})
:find()
end
internal.colorscheme = function(opts)
local before_background = vim.o.background
local before_color = vim.api.nvim_exec("colorscheme", true)
local need_restore = true
local colors = opts.colors or { before_color }
if not vim.tbl_contains(colors, before_color) then
table.insert(colors, 1, before_color)
end
colors = vim.list_extend(
colors,
vim.tbl_filter(function(color)
return not vim.tbl_contains(colors, color)
end, vim.fn.getcompletion("", "color"))
)
local previewer
if opts.enable_preview then
-- define previewer
local bufnr = vim.api.nvim_get_current_buf()
local p = vim.api.nvim_buf_get_name(bufnr)
-- show current buffer content in previewer
previewer = previewers.new_buffer_previewer {
get_buffer_by_name = function()
return p
end,
define_preview = function(self)
if vim.loop.fs_stat(p) then
conf.buffer_previewer_maker(p, self.state.bufnr, { bufname = self.state.bufname })
else
local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
vim.api.nvim_buf_set_lines(self.state.bufnr, 0, -1, false, lines)
end
end,
}
end
local picker = pickers.new(opts, {
prompt_title = "Change Colorscheme",
finder = finders.new_table {
results = colors,
},
sorter = conf.generic_sorter(opts),
previewer = previewer,
attach_mappings = function(prompt_bufnr)
actions.select_default:replace(function()
local selection = action_state.get_selected_entry()
if selection == nil then
utils.__warn_no_selection "builtin.colorscheme"
return
end
actions.close(prompt_bufnr)
need_restore = false
vim.cmd("colorscheme " .. selection.value)
end)
action_set.shift_selection:enhance {
post = function()
local selection = action_state.get_selected_entry()
if selection == nil then
utils.__warn_no_selection "builtin.colorscheme"
return
end
need_restore = true
if opts.enable_preview then
vim.cmd.colorscheme(selection.value)
end
end,
}
actions.close:enhance {
post = function()
if need_restore then
vim.cmd.colorscheme(before_color)
end
end,
}
return true
end,
on_complete = {
function()
local selection = action_state.get_selected_entry()
if selection == nil then
utils.__warn_no_selection "builtin.colorscheme"
return
end
need_restore = true
vim.cmd.colorscheme(selection.value)
end,
},
})
if opts.enable_preview then
-- rewrite picker.close_windows. restore color if needed
local close_windows = picker.close_windows
picker.close_windows = function(status)
close_windows(status)
if need_restore then
vim.o.background = before_background
vim.cmd("colorscheme " .. before_color)
end
end
end
picker:find()
end
internal.marks = function(opts)
local local_marks = {
items = vim.fn.getmarklist(opts.bufnr),
name_func = function(_, line)
return vim.api.nvim_buf_get_lines(opts.bufnr, line - 1, line, false)[1]
end,
}
local global_marks = {
items = vim.fn.getmarklist(),
name_func = function(mark, _)
-- get buffer name if it is opened, otherwise get file name
return vim.api.nvim_get_mark(mark, {})[4]
end,
}
local marks_table = {}
local marks_others = {}
local bufname = vim.api.nvim_buf_get_name(opts.bufnr)
for _, cnf in ipairs { local_marks, global_marks } do
for _, v in ipairs(cnf.items) do
-- strip the first single quote character
local mark = string.sub(v.mark, 2, 3)
local _, lnum, col, _ = unpack(v.pos)
local name = cnf.name_func(mark, lnum)
-- same format to :marks command
local line = string.format("%s %6d %4d %s", mark, lnum, col - 1, name)
local row = {
line = line,
lnum = lnum,
col = col,
filename = utils.path_expand(v.file or bufname),
}
-- non alphanumeric marks goes to last
if mark:match "%w" then
table.insert(marks_table, row)
else
table.insert(marks_others, row)
end
end
end
marks_table = vim.fn.extend(marks_table, marks_others)
pickers
.new(opts, {
prompt_title = "Marks",
finder = finders.new_table {
results = marks_table,
entry_maker = opts.entry_maker or make_entry.gen_from_marks(opts),
},
previewer = conf.grep_previewer(opts),
sorter = conf.generic_sorter(opts),
push_cursor_on_edit = true,
push_tagstack_on_edit = true,
})
:find()
end
internal.registers = function(opts)
local registers_table = { '"', "-", "#", "=", "/", "*", "+", ":", ".", "%" }
-- named
for i = 0, 9 do
table.insert(registers_table, tostring(i))
end
-- alphabetical
for i = 65, 90 do
table.insert(registers_table, string.char(i))
end
pickers
.new(opts, {
prompt_title = "Registers",
finder = finders.new_table {
results = registers_table,
entry_maker = opts.entry_maker or make_entry.gen_from_registers(opts),
},
sorter = conf.generic_sorter(opts),
attach_mappings = function(_, map)
actions.select_default:replace(actions.paste_register)
map({ "i", "n" }, "<C-e>", actions.edit_register)
return true
end,
})
:find()
end
-- TODO: make filtering include the mapping and the action
internal.keymaps = function(opts)
opts.modes = vim.F.if_nil(opts.modes, { "n", "i", "c", "x" })
opts.show_plug = vim.F.if_nil(opts.show_plug, true)
local keymap_encountered = {} -- used to make sure no duplicates are inserted into keymaps_table
local keymaps_table = {}
local max_len_lhs = 0
-- helper function to populate keymaps_table and determine max_len_lhs
local function extract_keymaps(keymaps)
for _, keymap in pairs(keymaps) do
local keymap_key = keymap.buffer .. keymap.mode .. keymap.lhs -- should be distinct for every keymap
if not keymap_encountered[keymap_key] then
keymap_encountered[keymap_key] = true
if opts.show_plug or not string.find(keymap.lhs, "<Plug>") then
table.insert(keymaps_table, keymap)
max_len_lhs = math.max(max_len_lhs, #utils.display_termcodes(keymap.lhs))
end
end
end
end
for _, mode in pairs(opts.modes) do
local global = vim.api.nvim_get_keymap(mode)
local buf_local = vim.api.nvim_buf_get_keymap(0, mode)
extract_keymaps(global)
extract_keymaps(buf_local)
end
opts.width_lhs = max_len_lhs + 1
pickers
.new(opts, {
prompt_title = "Key Maps",
finder = finders.new_table {
results = keymaps_table,
entry_maker = opts.entry_maker or make_entry.gen_from_keymaps(opts),
},
sorter = conf.generic_sorter(opts),
attach_mappings = function(prompt_bufnr)
actions.select_default:replace(function()
local selection = action_state.get_selected_entry()
if selection == nil then
utils.__warn_no_selection "builtin.keymaps"
return
end
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(selection.value.lhs, true, false, true), "t", true)
return actions.close(prompt_bufnr)
end)
return true
end,
})
:find()
end
internal.filetypes = function(opts)
local filetypes = vim.fn.getcompletion("", "filetype")
pickers
.new(opts, {
prompt_title = "Filetypes",
finder = finders.new_table {
results = filetypes,
},
sorter = conf.generic_sorter(opts),
attach_mappings = function(prompt_bufnr)
actions.select_default:replace(function()
local selection = action_state.get_selected_entry()
if selection == nil then
print "[telescope] Nothing currently selected"
return
end
actions.close(prompt_bufnr)
vim.cmd("setfiletype " .. selection[1])
end)
return true
end,
})
:find()
end
internal.highlights = function(opts)
local highlights = vim.fn.getcompletion("", "highlight")
pickers
.new(opts, {
prompt_title = "Highlights",
finder = finders.new_table {
results = highlights,
entry_maker = opts.entry_maker or make_entry.gen_from_highlights(opts),
},
sorter = conf.generic_sorter(opts),
attach_mappings = function(prompt_bufnr)
actions.select_default:replace(function()
local selection = action_state.get_selected_entry()
if selection == nil then
utils.__warn_no_selection "builtin.highlights"
return
end
actions.close(prompt_bufnr)
vim.cmd("hi " .. selection.value)
end)
return true
end,
previewer = previewers.highlights.new(opts),
})
:find()
end
internal.autocommands = function(opts)
local autocmds = vim.api.nvim_get_autocmds {}
table.sort(autocmds, function(lhs, rhs)
return lhs.event < rhs.event
end)
pickers
.new(opts, {
prompt_title = "autocommands",
finder = finders.new_table {
results = autocmds,
entry_maker = opts.entry_maker or make_entry.gen_from_autocommands(opts),
},
previewer = previewers.autocommands.new(opts),
sorter = conf.generic_sorter(opts),
attach_mappings = function(prompt_bufnr)
action_set.select:replace_if(function()
local selection = action_state.get_selected_entry()
if selection == nil then
return false
end
local val = selection.value
local group_name = val.group_name ~= "<anonymous>" and val.group_name or ""
local output =
vim.fn.execute("verb autocmd " .. group_name .. " " .. val.event .. " " .. val.pattern, "silent")
for line in output:gmatch "[^\r\n]+" do
local source_file = line:match "Last set from (.*) line %d*$" or line:match "Last set from (.*)$"
if source_file and source_file ~= "Lua" then
selection.filename = source_file
local source_lnum = line:match "line (%d*)$" or "1"
selection.lnum = tonumber(source_lnum)
selection.col = 1
return false
end
end
return true
end, function()
local selection = action_state.get_selected_entry()
actions.close(prompt_bufnr)
print("You selected autocmd: " .. vim.inspect(selection.value))
end)
return true
end,
})
:find()
end
internal.spell_suggest = function(opts)
local cursor_word = vim.fn.expand "<cword>"
local suggestions = vim.fn.spellsuggest(cursor_word)
pickers
.new(opts, {
prompt_title = "Spelling Suggestions",
finder = finders.new_table {
results = suggestions,
},
sorter = conf.generic_sorter(opts),
attach_mappings = function(prompt_bufnr)
actions.select_default:replace(function()
local selection = action_state.get_selected_entry()
if selection == nil then
utils.__warn_no_selection "builtin.spell_suggest"
return
end
action_state.get_current_picker(prompt_bufnr)._original_mode = "i"
actions.close(prompt_bufnr)
vim.cmd('normal! "_ciw' .. selection[1])
vim.cmd "stopinsert"
end)
return true
end,
})
:find()
end
internal.tagstack = function(opts)
opts = opts or {}
local tagstack = vim.fn.gettagstack().items
local tags = {}
for i = #tagstack, 1, -1 do
local tag = tagstack[i]
tag.bufnr = tag.from[1]
if vim.api.nvim_buf_is_valid(tag.bufnr) then
tags[#tags + 1] = tag
tag.filename = vim.fn.bufname(tag.bufnr)
tag.lnum = tag.from[2]
tag.col = tag.from[3]
tag.text = vim.api.nvim_buf_get_lines(tag.bufnr, tag.lnum - 1, tag.lnum, false)[1] or ""
end
end
if vim.tbl_isempty(tags) then
utils.notify("builtin.tagstack", {
msg = "No tagstack available",
level = "WARN",
})
return
end
pickers
.new(opts, {
prompt_title = "TagStack",
finder = finders.new_table {
results = tags,
entry_maker = make_entry.gen_from_quickfix(opts),
},
previewer = conf.qflist_previewer(opts),
sorter = conf.generic_sorter(opts),
})
:find()
end
internal.jumplist = function(opts)
opts = opts or {}
local jumplist = vim.fn.getjumplist()[1]
-- reverse the list
local sorted_jumplist = {}
for i = #jumplist, 1, -1 do
if vim.api.nvim_buf_is_valid(jumplist[i].bufnr) then
jumplist[i].text = vim.api.nvim_buf_get_lines(jumplist[i].bufnr, jumplist[i].lnum - 1, jumplist[i].lnum, false)[1]
or ""
table.insert(sorted_jumplist, jumplist[i])
end
end
pickers
.new(opts, {
prompt_title = "Jumplist",
finder = finders.new_table {
results = sorted_jumplist,
entry_maker = make_entry.gen_from_quickfix(opts),
},
previewer = conf.qflist_previewer(opts),
sorter = conf.generic_sorter(opts),
})
:find()
end
local function apply_checks(mod)
for k, v in pairs(mod) do
mod[k] = function(opts)
opts = opts or {}
v(opts)
end
end
return mod
end
return apply_checks(internal)