feat: v1 options menu (#133)
Still has a bunch of improvements that can be done, but wanted to merge in some of the related changes. * options parser * wip: vimoptions finder * feat: pre-populate ex-command line with `:set foo=` * use options current value when populating command line * fix: use result.raw_value to store original option value * . * options: Continue work on option finder * [WIP]: Tue 27 Oct 2020 10:34:09 PM EDT * [WIP]: Mon 02 Nov 2020 08:20:13 PM EST * [WIP]: Mon 02 Nov 2020 09:04:23 PM EST Co-authored-by: TJ DeVries <devries.timothyj@gmail.com>
This commit is contained in:
@@ -24,14 +24,13 @@ if 2 > vim.o.report then
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- TODO: Give some bonus weight to files we've picked before
|
|
||||||
-- TODO: Give some bonus weight to oldfiles
|
|
||||||
|
|
||||||
local actions = require('telescope.actions')
|
local actions = require('telescope.actions')
|
||||||
local finders = require('telescope.finders')
|
local finders = require('telescope.finders')
|
||||||
|
local log = require('telescope.log')
|
||||||
local make_entry = require('telescope.make_entry')
|
local make_entry = require('telescope.make_entry')
|
||||||
local previewers = require('telescope.previewers')
|
local path = require('telescope.path')
|
||||||
local pickers = require('telescope.pickers')
|
local pickers = require('telescope.pickers')
|
||||||
|
local previewers = require('telescope.previewers')
|
||||||
local sorters = require('telescope.sorters')
|
local sorters = require('telescope.sorters')
|
||||||
local utils = require('telescope.utils')
|
local utils = require('telescope.utils')
|
||||||
|
|
||||||
@@ -46,11 +45,17 @@ local builtin = {}
|
|||||||
builtin.git_files = function(opts)
|
builtin.git_files = function(opts)
|
||||||
opts = opts or {}
|
opts = opts or {}
|
||||||
|
|
||||||
|
local show_untracked = utils.get_default(opts.show_untracked, true)
|
||||||
|
|
||||||
if opts.cwd then
|
if opts.cwd then
|
||||||
opts.cwd = vim.fn.expand(opts.cwd)
|
opts.cwd = vim.fn.expand(opts.cwd)
|
||||||
else
|
else
|
||||||
--- Find root of git directory and remove trailing newline characters
|
--- Find root of git directory and remove trailing newline characters
|
||||||
opts.cwd = string.gsub(vim.fn.system("git rev-parse --show-toplevel"), '[\n\r]+', '')
|
opts.cwd = vim.fn.systemlist("git rev-parse --show-toplevel")[1]
|
||||||
|
|
||||||
|
if not vim.fn.isdirectory(opts.cwd) then
|
||||||
|
error("Not a working directory for git_files:", opts.cwd)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- By creating the entry maker after the cwd options,
|
-- By creating the entry maker after the cwd options,
|
||||||
@@ -60,7 +65,7 @@ builtin.git_files = function(opts)
|
|||||||
pickers.new(opts, {
|
pickers.new(opts, {
|
||||||
prompt_title = 'Git File',
|
prompt_title = 'Git File',
|
||||||
finder = finders.new_oneshot_job(
|
finder = finders.new_oneshot_job(
|
||||||
{ "git", "ls-tree", "--full-tree", "-r", "--name-only", "HEAD" },
|
{ "git", "ls-files", "--exclude-standard", "--cached", show_untracked and "--others" },
|
||||||
opts
|
opts
|
||||||
),
|
),
|
||||||
previewer = previewers.cat.new(opts),
|
previewer = previewers.cat.new(opts),
|
||||||
@@ -412,6 +417,72 @@ builtin.command_history = function(opts)
|
|||||||
}):find()
|
}):find()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
builtin.vim_options = function(opts)
|
||||||
|
opts = opts or {}
|
||||||
|
|
||||||
|
-- Load vim options.
|
||||||
|
local vim_opts = loadfile(utils.data_directory() .. path.separator .. 'options' .. path.separator .. 'options.lua')().options
|
||||||
|
|
||||||
|
pickers.new(opts, {
|
||||||
|
prompt = 'options',
|
||||||
|
finder = finders.new_table {
|
||||||
|
results = vim_opts,
|
||||||
|
entry_maker = make_entry.gen_from_vimoptions(opts),
|
||||||
|
},
|
||||||
|
-- TODO: previewer for Vim options
|
||||||
|
-- previewer = previewers.help.new(opts),
|
||||||
|
sorter = sorters.get_fzy_sorter(),
|
||||||
|
attach_mappings = function(prompt_bufnr, map)
|
||||||
|
local edit_option = function()
|
||||||
|
local selection = actions.get_selected_entry(prompt_bufnr)
|
||||||
|
local esc = ""
|
||||||
|
|
||||||
|
|
||||||
|
if vim.fn.mode() == "i" then
|
||||||
|
-- TODO: don't make this local
|
||||||
|
esc = vim.api.nvim_replace_termcodes("<esc>", true, false, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO: Make this actually work.
|
||||||
|
|
||||||
|
-- actions.close(prompt_bufnr)
|
||||||
|
-- vim.api.nvim_win_set_var(vim.fn.nvim_get_current_win(), "telescope", 1)
|
||||||
|
-- print(prompt_bufnr)
|
||||||
|
-- print(vim.fn.bufnr())
|
||||||
|
-- vim.cmd([[ autocmd BufEnter <buffer> ++nested ++once startinsert!]])
|
||||||
|
-- print(vim.fn.winheight(0))
|
||||||
|
|
||||||
|
-- local prompt_winnr = vim.fn.getbufinfo(prompt_bufnr)[1].windows[1]
|
||||||
|
-- print(prompt_winnr)
|
||||||
|
|
||||||
|
-- local float_opts = {}
|
||||||
|
-- float_opts.relative = "editor"
|
||||||
|
-- float_opts.anchor = "sw"
|
||||||
|
-- float_opts.focusable = false
|
||||||
|
-- float_opts.style = "minimal"
|
||||||
|
-- float_opts.row = vim.api.nvim_get_option("lines") - 2 -- TODO: include `cmdheight` and `laststatus` in this calculation
|
||||||
|
-- float_opts.col = 2
|
||||||
|
-- float_opts.height = 10
|
||||||
|
-- float_opts.width = string.len(selection.last_set_from)+15
|
||||||
|
-- local buf = vim.fn.nvim_create_buf(false, true)
|
||||||
|
-- vim.fn.nvim_buf_set_lines(buf, 0, 0, false, {"default value: abcdef", "last set from: " .. selection.last_set_from})
|
||||||
|
-- local status_win = vim.fn.nvim_open_win(buf, false, float_opts)
|
||||||
|
-- -- vim.api.nvim_win_set_option(status_win, "winblend", 100)
|
||||||
|
-- vim.api.nvim_win_set_option(status_win, "winhl", "Normal:PmenuSel")
|
||||||
|
-- -- vim.api.nvim_set_current_win(status_win)
|
||||||
|
-- vim.cmd[[redraw!]]
|
||||||
|
-- vim.cmd("autocmd CmdLineLeave : ++once echom 'beep'")
|
||||||
|
vim.api.nvim_feedkeys(string.format("%s:set %s=%s", esc, selection.name, selection.current_value), "m", true)
|
||||||
|
end
|
||||||
|
|
||||||
|
map('i', '<CR>', edit_option)
|
||||||
|
map('n', '<CR>', edit_option)
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
}):find()
|
||||||
|
end
|
||||||
|
|
||||||
builtin.help_tags = function(opts)
|
builtin.help_tags = function(opts)
|
||||||
opts = opts or {}
|
opts = opts or {}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
local has_devicons, devicons = pcall(require, 'nvim-web-devicons')
|
local has_devicons, devicons = pcall(require, 'nvim-web-devicons')
|
||||||
|
|
||||||
local conf = require('telescope.config').values
|
local conf = require('telescope.config').values
|
||||||
|
local entry_display = require('telescope.pickers.entry_display')
|
||||||
local path = require('telescope.path')
|
local path = require('telescope.path')
|
||||||
local utils = require('telescope.utils')
|
local utils = require('telescope.utils')
|
||||||
|
|
||||||
@@ -465,4 +466,110 @@ function make_entry.gen_from_marks(_)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function make_entry.gen_from_vimoptions(opts)
|
||||||
|
-- TODO: Can we just remove this from `options.lua`?
|
||||||
|
function N_(s)
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
|
||||||
|
local process_one_opt = function(o)
|
||||||
|
local ok, value_origin
|
||||||
|
|
||||||
|
local option = {
|
||||||
|
name = "",
|
||||||
|
description = "",
|
||||||
|
current_value = "",
|
||||||
|
default_value = "",
|
||||||
|
value_type = "",
|
||||||
|
set_by_user = false,
|
||||||
|
last_set_from = "",
|
||||||
|
}
|
||||||
|
|
||||||
|
local is_global = false
|
||||||
|
for _, v in ipairs(o.scope) do
|
||||||
|
if v == "global" then
|
||||||
|
is_global = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not is_global then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if is_global then
|
||||||
|
option.name = o.full_name
|
||||||
|
|
||||||
|
ok, option.current_value = pcall(vim.api.nvim_get_option, o.full_name)
|
||||||
|
if not ok then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local str_funcname = o.short_desc()
|
||||||
|
option.description = assert(loadstring("return " .. str_funcname))()
|
||||||
|
-- if #option.description > opts.desc_col_length then
|
||||||
|
-- opts.desc_col_length = #option.description
|
||||||
|
-- end
|
||||||
|
|
||||||
|
if o.defaults ~= nil then
|
||||||
|
option.default_value = o.defaults.if_true.vim or o.defaults.if_true.vi
|
||||||
|
end
|
||||||
|
|
||||||
|
if type(option.default_value) == "function" then
|
||||||
|
option.default_value = "Macro: " .. option.default_value()
|
||||||
|
end
|
||||||
|
|
||||||
|
option.value_type = (type(option.current_value) == "boolean" and "bool" or type(option.current_value))
|
||||||
|
|
||||||
|
if option.current_value ~= option.default_value then
|
||||||
|
option.set_by_user = true
|
||||||
|
value_origin = vim.fn.execute("verbose set " .. o.full_name .. "?")
|
||||||
|
if string.match(value_origin, "Last set from") then
|
||||||
|
-- TODO: parse file and line number as separate items
|
||||||
|
option.last_set_from = value_origin:gsub("^.*Last set from ", "")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return option
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO: don't call this 'line'
|
||||||
|
local displayer = entry_display.create {
|
||||||
|
separator = "│",
|
||||||
|
items = {
|
||||||
|
{ width = 25 },
|
||||||
|
{ width = 50 },
|
||||||
|
{ remaining = true },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local make_display = function(entry)
|
||||||
|
|
||||||
|
return displayer {
|
||||||
|
entry.name,
|
||||||
|
string.format(
|
||||||
|
"[%s] %s",
|
||||||
|
entry.value_type,
|
||||||
|
utils.display_termcodes(tostring(entry.current_value))),
|
||||||
|
entry.description,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
return function(line)
|
||||||
|
local entry = process_one_opt(line)
|
||||||
|
if not entry then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
entry.valid = true
|
||||||
|
entry.display = make_display
|
||||||
|
entry.value = line
|
||||||
|
entry.ordinal = line.full_name
|
||||||
|
-- entry.raw_value = d.raw_value
|
||||||
|
-- entry.last_set_from = d.last_set_from
|
||||||
|
|
||||||
|
return entry
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return make_entry
|
return make_entry
|
||||||
|
|||||||
@@ -7,12 +7,14 @@ local actions = require('telescope.actions')
|
|||||||
local config = require('telescope.config')
|
local config = require('telescope.config')
|
||||||
local debounce = require('telescope.debounce')
|
local debounce = require('telescope.debounce')
|
||||||
local resolve = require('telescope.config.resolve')
|
local resolve = require('telescope.config.resolve')
|
||||||
local layout_strategies = require('telescope.pickers.layout_strategies')
|
|
||||||
local log = require('telescope.log')
|
local log = require('telescope.log')
|
||||||
local mappings = require('telescope.mappings')
|
local mappings = require('telescope.mappings')
|
||||||
local state = require('telescope.state')
|
local state = require('telescope.state')
|
||||||
local utils = require('telescope.utils')
|
local utils = require('telescope.utils')
|
||||||
|
|
||||||
|
local layout_strategies = require('telescope.pickers.layout_strategies')
|
||||||
|
local entry_display = require('telescope.pickers.entry_display')
|
||||||
|
|
||||||
local EntryManager = require('telescope.entry_manager')
|
local EntryManager = require('telescope.entry_manager')
|
||||||
|
|
||||||
local get_default = utils.get_default
|
local get_default = utils.get_default
|
||||||
@@ -307,7 +309,9 @@ function Picker:find()
|
|||||||
|
|
||||||
local results_win, results_opts = popup.create('', popup_opts.results)
|
local results_win, results_opts = popup.create('', popup_opts.results)
|
||||||
local results_bufnr = a.nvim_win_get_buf(results_win)
|
local results_bufnr = a.nvim_win_get_buf(results_win)
|
||||||
|
|
||||||
self.results_bufnr = results_bufnr
|
self.results_bufnr = results_bufnr
|
||||||
|
self.results_win = results_win
|
||||||
|
|
||||||
-- TODO: Should probably always show all the line for results win, so should implement a resize for the windows
|
-- TODO: Should probably always show all the line for results win, so should implement a resize for the windows
|
||||||
a.nvim_win_set_option(results_win, 'wrap', false)
|
a.nvim_win_set_option(results_win, 'wrap', false)
|
||||||
@@ -785,13 +789,8 @@ function Picker:entry_adder(index, entry, score)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local display, display_highlights
|
local display, display_highlights = entry_display.resolve(self, entry)
|
||||||
if type(entry.display) == 'function' then
|
if not display then
|
||||||
self:_increment("display_fn")
|
|
||||||
display, display_highlights = entry:display()
|
|
||||||
elseif type(entry.display) == 'string' then
|
|
||||||
display = entry.display
|
|
||||||
else
|
|
||||||
log.info("Weird entry", entry)
|
log.info("Weird entry", entry)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|||||||
100
lua/telescope/pickers/entry_display.lua
Normal file
100
lua/telescope/pickers/entry_display.lua
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
local log = require('telescope.log')
|
||||||
|
|
||||||
|
local entry_display = {}
|
||||||
|
|
||||||
|
-- index are used to determine the correct order
|
||||||
|
-- elements = {
|
||||||
|
-- [1] = { element, max width }, -- max width should be greater than 0
|
||||||
|
-- [2] = { a, 0 } -- Use 0 to disable max width
|
||||||
|
-- [3] = { b, 0 } -- If b is nil, skip this column, should skip column for all rows
|
||||||
|
-- },
|
||||||
|
-- separator = " " -- either arbitrary string, when you wanna use the same separator between all elements
|
||||||
|
-- separator = { " ", ":" } -- or table, where [1] is separator between elements[1] and elements[2], etc
|
||||||
|
|
||||||
|
-- TODO: Remove this and move ONLY to create method.
|
||||||
|
|
||||||
|
local table_format = function(picker, elements, separator)
|
||||||
|
-- TODO: Truncate...
|
||||||
|
local win_width = vim.api.nvim_win_get_width(picker.results_win)
|
||||||
|
|
||||||
|
local output = ""
|
||||||
|
for k, v in ipairs(elements) do
|
||||||
|
local text = v[1]
|
||||||
|
local width = v[2]
|
||||||
|
if text ~= nil then
|
||||||
|
if k > 1 then
|
||||||
|
output = output .. (type(separator) == "table" and separator[k - 1] or separator)
|
||||||
|
end
|
||||||
|
if width then
|
||||||
|
if width == 0 then
|
||||||
|
output = output .. string.format("%s", text)
|
||||||
|
elseif width < 1 then
|
||||||
|
output = output .. string.format("%-" .. math.floor(width * win_width) .. "s", text)
|
||||||
|
else
|
||||||
|
output = output .. string.format("%-" .. width .."s", text)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
output = output .. text
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return output
|
||||||
|
end
|
||||||
|
|
||||||
|
local function truncate(str, len)
|
||||||
|
-- TODO: This doesn't handle multi byte chars...
|
||||||
|
if vim.fn.strdisplaywidth(str) > len - 1 then
|
||||||
|
str = str:sub(1, len)
|
||||||
|
str = str .. "…"
|
||||||
|
end
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
|
||||||
|
entry_display.create = function(configuration)
|
||||||
|
local generator = {}
|
||||||
|
for _, v in ipairs(configuration.items) do
|
||||||
|
if v.width then
|
||||||
|
local justify = not v.right_justify and "-" or ""
|
||||||
|
local format_str = "%" .. justify .. v.width .. "s"
|
||||||
|
table.insert(generator, function(item)
|
||||||
|
return string.format(format_str, truncate(item, v.width))
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
table.insert(generator, function(item)
|
||||||
|
return item
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return function(self, picker)
|
||||||
|
local results = {}
|
||||||
|
for k, v in ipairs(self) do
|
||||||
|
table.insert(results, generator[k](v, picker))
|
||||||
|
end
|
||||||
|
|
||||||
|
return table.concat(results, configuration.separator or "│")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
entry_display.resolve = function(self, entry)
|
||||||
|
local display, display_highlights
|
||||||
|
if type(entry.display) == 'function' then
|
||||||
|
self:_increment("display_fn")
|
||||||
|
display, display_highlights = entry:display(self)
|
||||||
|
|
||||||
|
if type(display) == 'string' then
|
||||||
|
return display, display_highlights
|
||||||
|
end
|
||||||
|
else
|
||||||
|
display = entry.display
|
||||||
|
end
|
||||||
|
|
||||||
|
if type(display) == 'string' then
|
||||||
|
return display, display_highlights
|
||||||
|
elseif type(display) == 'table' then
|
||||||
|
return table_format(self, display, "│"), display_highlights
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return entry_display
|
||||||
@@ -178,4 +178,16 @@ function utils.max_split(s, pattern, maxsplit)
|
|||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function utils.data_directory()
|
||||||
|
local sourced_file = require('plenary.debug_utils').sourced_filepath()
|
||||||
|
local base_directory = vim.fn.fnamemodify(sourced_file, ":h:h:h")
|
||||||
|
|
||||||
|
return base_directory .. pathlib.separator .. 'data' .. pathlib.separator
|
||||||
|
end
|
||||||
|
|
||||||
|
function utils.display_termcodes(str)
|
||||||
|
return str:gsub(string.char(9), "<TAB>"):gsub("", "<C-F>"):gsub(" ", "<Space>")
|
||||||
|
end
|
||||||
|
|
||||||
return utils
|
return utils
|
||||||
|
|||||||
Reference in New Issue
Block a user