---@param picker string ---@param opts? table local function pick(picker, opts) opts = opts or {} return function() require('fzf-lua')[picker](opts) end end local projectPick = nil projectPick = function() local has_project, _ = pcall(require, 'project_nvim') if not has_project then return end local fzf_lua = require('fzf-lua') local project = require('project_nvim.project') local history = require('project_nvim.utils.history') local results = history.get_recent_projects() local utils = require('fzf-lua.utils') local function hl_validate(hl) return not utils.is_hl_cleared(hl) and hl or nil end local function ansi_from_hl(hl, s) return utils.ansi_from_hl(hl_validate(hl), s) end local opts = { fzf_opts = { ['--header'] = string.format( ':: <%s> to %s | <%s> to %s | <%s> to %s | <%s> to %s | <%s> to %s', ansi_from_hl('FzfLuaHeaderBind', 'ctrl-t'), ansi_from_hl('FzfLuaHeaderText', 'tabedit'), ansi_from_hl('FzfLuaHeaderBind', 'ctrl-s'), ansi_from_hl('FzfLuaHeaderText', 'live_grep'), ansi_from_hl('FzfLuaHeaderBind', 'ctrl-r'), ansi_from_hl('FzfLuaHeaderText', 'oldfiles'), ansi_from_hl('FzfLuaHeaderBind', 'ctrl-w'), ansi_from_hl('FzfLuaHeaderText', 'change_dir'), ansi_from_hl('FzfLuaHeaderBind', 'ctrl-d'), ansi_from_hl('FzfLuaHeaderText', 'delete') ), }, fzf_colors = true, actions = { ['default'] = { function(selected) fzf_lua.files({ cwd = selected[1] }) end, }, ['ctrl-t'] = { function(selected) vim.cmd('tabedit') fzf_lua.files({ cwd = selected[1] }) end, }, ['ctrl-s'] = { function(selected) fzf_lua.live_grep({ cwd = selected[1] }) end, }, ['ctrl-r'] = { function(selected) fzf_lua.oldfiles({ cwd = selected[1] }) end, }, ['ctrl-w'] = { function(selected) local path = selected[1] local ok = project.set_pwd(path) if ok then vim.api.nvim_win_close(0, false) vim.notify('Change project dir to ' .. path, 'info') end end, }, ['ctrl-d'] = function(selected) local path = selected[1] local choice = vim.fn.confirm("Delete '" .. path .. "' project? ", '&Yes\n&No') if choice == 1 then history.delete_project({ value = path }) end ---@diagnostic disable-next-line:need-check-nil projectPick() end, }, } fzf_lua.fzf_exec(results, opts) end return { 'fzf-lua', event = { 'DeferredUIEnter' }, cmd = { 'FzfLua' }, keys = { -- Find. { 'fb', pick('buffers', { sort_mru = true, sort_lastused = true }), desc = 'buffers', }, { 'ff', pick('files'), desc = 'find files (root dir)' }, { 'fF', pick('files', { root = false }), desc = 'find files (cwd)', }, { 'fg', pick('git_files'), desc = 'find files (git)' }, { 'fp', projectPick, desc = 'projects' }, { 'fr', pick('oldfiles'), desc = 'recent' }, { 'fR', pick('oldfiles', { cwd = vim.uv.cwd() }), desc = 'recent (cwd)', }, -- Git. { 'gc', pick('git_commits'), desc = 'commits' }, { 'gs', pick('git_status'), desc = 'status' }, -- Search. { 'sa', pick('autocmds'), desc = 'auto-commands' }, { 'sb', pick('grep_curbuf'), desc = 'buffer' }, { 'sc', pick('command_history'), desc = 'command history' }, { 'sC', pick('commands'), desc = 'commands' }, { 'sd', pick('diagnostics_document'), desc = 'document diagnostics', }, { 'sD', pick('diagnostics_workspace'), desc = 'workspace diagnostics', }, { 'sg', pick('live_grep'), desc = 'grep (root dir)' }, { 'sG', pick('live_grep', { root = false }), desc = 'grep (cwd)' }, { 'sh', pick('help_tags'), desc = 'help pages' }, { 'sH', pick('highlights'), desc = 'search highlight groups' }, { 'sj', pick('jumps'), desc = 'jumplist' }, { 'sk', pick('keymaps'), desc = 'keymaps' }, { 'sl', pick('loclist'), desc = 'location list' }, { 'sm', pick('marks'), desc = 'jump to mark' }, { 'sM', pick('man_pages'), desc = 'man pages' }, { 'sq', pick('quickfix'), desc = 'quickfix list' }, { 'sR', pick('resume'), desc = 'resume last picker' }, { 'sw', pick('grep_cword'), desc = 'word under cursor (root dir)' }, { 'sw', pick('grep_visual'), mode = 'v', desc = 'selection (root dir)', }, { 'sW', pick('grep_cword', { root = false }), desc = 'word under cursor (cwd)', }, { 'sW', pick('grep_visual', { root = false }), mode = 'v', desc = 'selection (cwd)', }, { 's"', pick('registers'), desc = 'registers' }, -- Misc. { 'uC', pick('colorschemes'), desc = 'colorschemes' }, { '', pick('files'), desc = 'find files (root dir)' }, { ',', pick('buffers', { sort_mru = true, sort_lastused = true }), desc = 'switch buffer', }, { '/', pick('live_grep'), desc = 'grep (root dir)' }, { ':', pick('command_history'), desc = 'command history' }, }, after = function() local config = require('fzf-lua.config') local actions = require('fzf-lua.actions') -- quickfix config.defaults.keymap.fzf['ctrl-q'] = 'select-all+accept' config.defaults.keymap.fzf['ctrl-u'] = 'half-page-up' config.defaults.keymap.fzf['ctrl-d'] = 'half-page-down' config.defaults.keymap.fzf['ctrl-x'] = 'jump' config.defaults.keymap.fzf['ctrl-f'] = 'preview-page-down' config.defaults.keymap.fzf['ctrl-b'] = 'preview-page-up' config.defaults.keymap.builtin[''] = 'preview-page-down' config.defaults.keymap.builtin[''] = 'preview-page-up' -- trouble.nvim local has_trouble, _ = pcall(require, 'trouble') if has_trouble then config.defaults.actions.files['ctrl-t'] = require('trouble.sources.fzf').actions.open end local img_previewer = { 'chafa', '{file}', '--format=symbols' } local opts = { -- Base profile. 'default-title', fzf_colors = true, fzf_opts = { ['--no-scrollbar'] = true, }, defaults = { formatter = 'path.dirname_first', }, previewers = { builtin = { extensions = { ['png'] = img_previewer, ['jpg'] = img_previewer, ['jpeg'] = img_previewer, ['gif'] = img_previewer, ['webp'] = img_previewer, }, }, }, winopts = { width = 0.8, height = 0.8, row = 0.5, col = 0.5, preview = { scrollchars = { '┃', '' }, }, }, files = { cwd_prompt = false, actions = { ['alt-i'] = { actions.toggle_ignore }, ['alt-h'] = { actions.toggle_hidden }, }, }, grep = { actions = { ['alt-i'] = { actions.toggle_ignore }, ['alt-h'] = { actions.toggle_hidden }, }, }, lsp = { symbols = { symbol_hl = function(s) return 'TroubleIcon' .. s end, symbol_fmt = function(s) return s:lower() .. '\t' end, child_prefix = false, }, code_actions = { previewer = 'codeaction_native', }, }, } -- Use the same prompt for all pickers for profile 'default-title'. local function fix(table) table.prompt = table.prompt ~= nil and ' ' or nil -- Recurse into subtables. for _, value in pairs(table) do if type(value) == 'table' then fix(value) end end return table end opts = vim.tbl_deep_extend( 'force', fix(require('fzf-lua.profiles.default-title')), opts ) -- Don't let fzf-lua apply the profile as we've already done so above. opts[1] = nil require('fzf-lua').setup(opts) require('fzf-lua').register_ui_select(function(fzf_opts, items) return vim.tbl_deep_extend('force', fzf_opts, { prompt = ' ', winopts = { title = ' ' .. vim.trim((fzf_opts.prompt or 'Select'):gsub('%s*:%s*$', '')) .. ' ', title_pos = 'center', }, }, fzf_opts.kind == 'codeaction' and { winopts = { layout = 'vertical', height = math.floor( math.min(vim.o.lines * 0.8 - 16, #items + 2) + 0.5 ) + 16, preview = not vim.tbl_isempty( vim.lsp.get_clients({ bufnr = 0, name = 'vtsls' }) ) and { layout = 'vertical', vertical = 'down:15,border-top', hidden = 'hidden', } or { layout = 'vertical', vertical = 'down:15,border-top', }, }, } or { winopts = { width = 0.5, height = math.floor(math.min(vim.o.lines * 0.8, #items + 2) + 0.5), }, }) end) -- LSP keybinds. MarleyVim.lsp.on_attach(function(client) local set = vim.keymap.set local pickOpts = { jump_to_single_result = true, ignore_current_line = true } set( 'n', 'gI', pick('lsp_implementations', pickOpts), { desc = 'implementation' } ) set( 'n', 'gr', pick('lsp_references', pickOpts), { desc = 'references', nowait = true } ) set( 'n', 'gy', pick('lsp_typedefs', pickOpts), { desc = 't[y]pe definition' } ) if client.supports_method('textDocument/definition') then set( 'n', 'gd', pick('lsp_definitions', pickOpts), { desc = 'definition' } ) end end) end, }