nvim: scope.lua buffer selection, vim.ui.select

This commit is contained in:
dogeystamp 2024-09-14 13:18:09 -04:00
parent 736499a0ad
commit 5e5b5c818d
Signed by: dogeystamp
GPG Key ID: 7225FE3592EFFA38
6 changed files with 188 additions and 25 deletions

9
.gitmodules vendored
View File

@ -53,12 +53,6 @@
path = src/dot_local/share/nvim/site/pack/3pp/opt/external_nvim-treesitter-textobjects
url = https://github.com/nvim-treesitter/nvim-treesitter-textobjects
# aesthetic changes
# init.lua
[submodule "src/dot_local/share/nvim/site/pack/3pp/start/external_dressing.nvim"]
path = src/dot_local/share/nvim/site/pack/3pp/opt/external_dressing.nvim
url = https://github.com/stevearc/dressing.nvim.git
# plain-text-accounting ledger ftplugin
# ftplugin/ledger.vim
[submodule "src/dot_local/share/nvim/site/pack/3pp/start/external_vim-ledger"]
@ -128,9 +122,6 @@
[submodule "submodule.src/dot_local/share/nvim/site/pack/3pp/start/external_nvim-treesitter-textobjects.path"]
path = src/dot_local/share/nvim/site/pack/3pp/opt/external_nvim-treesitter-textobjects
url = https://github.com/nvim-treesitter/nvim-treesitter-textobjects
[submodule "submodule.src/dot_local/share/nvim/site/pack/3pp/start/external_dressing.nvim.path"]
path = src/dot_local/share/nvim/site/pack/3pp/opt/external_dressing.nvim
url = https://github.com/stevearc/dressing.nvim.git
[submodule "submodule.src/dot_local/share/nvim/site/pack/3pp/start/external_vim-ledger.path"]
path = src/dot_local/share/nvim/site/pack/3pp/start/external_vim-ledger
url = https://github.com/ledger/vim-ledger.git

View File

@ -1,2 +1,5 @@
# For all themes, run `bat --list-themes`
--theme="ansi"
# disable decorations
--plain

View File

@ -2,7 +2,13 @@
local M = {}
-- nnoremap, etc.
---@class KeymapOpts: vim.keymap.set.Opts
--- @field mode? string|string[]
---Keymap helper.
---@param key string
---@param cmd string|function
---@param params? KeymapOpts
function M.keymap(key, cmd, params)
if params == nil then
params = {}
@ -20,7 +26,7 @@ function M.keymap(key, cmd, params)
buffer = false,
}
setmetatable(params, {
__index = function(table, k)
__index = function(_, k)
return default_params[k]
end
})

View File

@ -16,30 +16,21 @@ local dotprofile, profile_table = confutil.dotprofile, confutil.profile_table
-- bind to copy URL under cursor
keymap("<leader>uu", ":let @+ = expand('<cfile>')<cr>")
------
-- fancy prompts
------
vim.cmd.packadd("dressing.nvim")
require('dressing').setup({
input = {
insert_only = false,
}
})
-- requires plenary.nvim
vim.cmd.packadd("telescope.nvim")
--keymap("<leader>ef", "<cmd>Telescope find_files<cr>")
keymap("<leader>eg", "<cmd>Telescope live_grep<cr>")
keymap("<leader>em", "<cmd>Telescope buffers<cr>")
keymap("<leader>eh", "<cmd>Telescope help_tags<cr>")
keymap("<leader>es", "<cmd>Telescope lsp_dynamic_workspace_symbols<cr>")
keymap("<leader>eb", "<cmd>Telescope keymaps<cr>")
--------
-- generic brand fuzzy finder
--------
local scope = require("scope")
scope.setup()
keymap("<leader>ef", scope.file_finder)
keymap("<leader>em", scope.buffer_list)
keymap("<leader>es", vim.lsp.buf.workspace_symbol)
--------------------------------

View File

@ -0,0 +1,173 @@
-- telescope without telescope
-- depends on: fzf, bat
M = {}
--------------------------------
-- helpers
--------------------------------
---Hacky debug print utility (do not use outside testing)
---@param s any Thing to print
---@param pre string? Message that goes before thing
local function dbg_print(s, pre)
vim.system({ "sh", "-c", string.format("echo '%s' >> /tmp/nvim_scope_log", (pre or "") .. vim.inspect(s)) })
end
--------------------------------
--------------------------------
-- main implementation
--------------------------------
--------------------------------
---@class ScopeOpts
---@field fzf_opts string? Command-line flags to pass to fzf.
---@field allow_empty boolean? If true, will call `command` even if user cancelled. Defaults to false.
---Generic brand fuzzy selector
---@param choice_gen string | function Lua function or shell command that generates choices to display in fzf.
---@param command string | function Vim command or Lua function to run on the selected choice.
---@param scope_opts ScopeOpts | nil
function M.scope_fzf(choice_gen, command, scope_opts)
local opts = scope_opts or {}
local buf = vim.api.nvim_create_buf(false, true)
vim.cmd.buf(buf)
vim.wo.statusline = "Scope"
vim.cmd("startinsert")
local fzf_opts = opts.fzf_opts or ""
local choice_cmd = ""
local choices_file = nil
if type(choice_gen) == "string" then
choice_cmd = choice_gen .. " | "
elseif type(choice_gen) == "function" then
choices_file = vim.fn.tempname()
local f = io.open(choices_file, "w")
assert(f, "Stdin file could not be opened.")
f:write(choice_gen())
choice_cmd = "cat " .. choices_file .. " | "
f:close()
end
local stdout_file = vim.fn.tempname()
local fzf_cmd = choice_cmd .. "fzf " .. fzf_opts .. " > " .. stdout_file
dbg_print(fzf_cmd, "fzf_cmd: ")
vim.fn.termopen(fzf_cmd, {
on_stdout = function(_, b, _)
dbg_print(b, "stdout: ")
end,
on_exit = function()
local f = io.open(stdout_file, "r")
assert(f, "Stdout file could not be opened.")
vim.cmd("bp | bd! #") -- see https://stackoverflow.com/a/4468491
local stdout = f:read("*all")
f:close()
os.remove(stdout_file)
if choices_file then
os.remove(choices_file)
end
if (stdout and stdout ~= "") or opts.allow_empty then
if type(command) == "function" then
command(stdout)
elseif type(command) == "string" then
vim.cmd(command .. stdout)
end
end
end
})
end
--------------------------------
--------------------------------
-- vim.ui overwrites
--------------------------------
--------------------------------
--- Replacement for `vim.ui.select`.
---@param items any[] Arbitrary items
---@param opts table? Additional options
--- - prompt (string|nil)
--- - format_item (function item -> text)
--- - kind (string|nil)
---@param on_choice fun(item: any|nil, idx: integer|nil)
local function picker(items, opts, on_choice)
vim.validate({
items = { items, 'table', false },
on_choice = { on_choice, 'function', false },
})
opts = opts or {}
M.scope_fzf(
function()
---@type string[]
local items_fmt = {}
local fmt = opts.format_item or tostring
for i, v in ipairs(items) do
table.insert(items_fmt, string.format("%d: %s", i, fmt(v)))
end
return table.concat(items_fmt, "\n")
end,
function(sel)
if not sel or sel == "" then
on_choice(nil, nil)
return
end
local _, _, idx_str = string.find(sel, "^(%d+):")
local idx = tonumber(idx_str)
assert(idx, "Could not parse fzf output.")
on_choice(items[idx], idx)
end,
{
allow_empty = true,
fzf_opts = string.format("--border=rounded --border-label '%s'", (opts.prompt or "Select"))
}
)
end
---Sets up `vim.ui` hooks to use scope.
function M.setup()
vim.ui.select = picker
end
--------------------------------
--------------------------------
-- preset modes
--------------------------------
--------------------------------
---Find and open a file.
function M.file_finder()
M.scope_fzf(
"rg --files",
":e ",
{ fzf_opts = '--preview "bat --color always --line-range=:500 {}"' }
)
end
---List and navigate buffers
function M.buffer_list()
M.scope_fzf(
function()
return vim.api.nvim_exec2("ls", { output = true }).output
end,
function(s)
local _, _, bufnr = string.find(s, "^%s*(%d+)")
if bufnr then
vim.cmd.buf(bufnr)
end
end
)
end
return M

@ -1 +0,0 @@
Subproject commit 6741f1062d3dc6e4755367a7e9b347b553623f04