diff --git a/lua/core/globals.lua b/lua/core/globals.lua index 4ce7d311..3018d778 100644 --- a/lua/core/globals.lua +++ b/lua/core/globals.lua @@ -110,6 +110,14 @@ Glyphs = { task = ' ', list = { '●', '○', '◆', '◇' }, }, + snacksPicker = { + lsp = { + unavailable = '', + enabled = '', + disabled = '', + attached = '', + }, + }, diagnostics = { error = '', warn = '', diff --git a/lua/plugins/fzf-lua.lua b/lua/plugins/fzf-lua.lua index 0eb986e9..fb2353fd 100644 --- a/lua/plugins/fzf-lua.lua +++ b/lua/plugins/fzf-lua.lua @@ -44,16 +44,18 @@ return { fl.live_grep { cwd = '~/.local/share/nvim/lazy/' } end, { desc = 'Grep Neovim plugins src' }) - -- Git specific - vim.keymap.set('n', 'GC', fl.git_bcommits, { desc = 'Git: commits - current buf' }) - vim.keymap.set('n', 'GS', fl.git_stash, { desc = 'Git: stash' }) - vim.keymap.set('n', 'Gb', fl.git_branches, { desc = 'Git: branches' }) - vim.keymap.set('n', 'Gc', fl.git_commits, { desc = 'Git: commits' }) - vim.keymap.set('n', 'Gd', fl.git_diff, { desc = 'Git: diff' }) - vim.keymap.set('n', 'Gf', fl.git_files, { desc = 'Git: files' }) - vim.keymap.set('n', 'Gh', fl.git_hunks, { desc = 'Git: hunks' }) - vim.keymap.set('n', 'Gs', fl.git_status, { desc = 'Git: status' }) - vim.keymap.set('n', 'Gw', fl.git_worktrees, { desc = 'Git: worktrees' }) + -- -- Git specific + -- vim.keymap.set('n', 'GC', fl.git_bcommits, { desc = 'Git: commits - current buf' }) + -- vim.keymap.set('n', 'GS', fl.git_stash, { desc = 'Git: stash' }) + -- vim.keymap.set('n', 'Gb', fl.git_branches, { desc = 'Git: branches' }) + -- vim.keymap.set('n', 'Gc', fl.git_commits, { desc = 'Git: commits' }) + -- vim.keymap.set('n', 'Gd', fl.git_diff, { desc = 'Git: diff' }) + -- vim.keymap.set('n', 'Gf', fl.git_files, { desc = 'Git: files' }) + -- vim.keymap.set('n', 'Gh', fl.git_hunks, { desc = 'Git: hunks' }) + -- vim.keymap.set('n', 'Gs', fl.git_status, { desc = 'Git: status' }) + -- vim.keymap.set('n', 'Gw', fl.git_worktrees, { desc = 'Git: worktrees' }) + -- vim.keymap.set('n', 'vh', fl.git_hunks, { desc = 'Git: hunks' }) + -- vim.keymap.set('n', 'vw', fl.git_worktrees, { desc = 'Git: worktrees' }) -- LSP specific vim.api.nvim_create_autocmd('LspAttach', { diff --git a/lua/plugins/snacks.lua b/lua/plugins/snacks.lua new file mode 100644 index 00000000..f4360bd4 --- /dev/null +++ b/lua/plugins/snacks.lua @@ -0,0 +1,314 @@ +return { + 'folke/snacks.nvim', + config = function() + Snacks = require 'snacks' + Snacks.setup { + picker = { + prompt = Glyphs.ui.prompt .. ' ', + sources = {}, + focus = 'input', + show_delay = 5000, + limit_live = 10000, + layout = { + cycle = true, + --- Use the default layout or vertical if the window is too narrow + preset = function() + return vim.o.columns >= 120 and 'default' or 'vertical' + end, + }, + layouts = { + default = { + layout = { + box = 'horizontal', + width = 0.8, + min_width = 120, + height = 0.8, + { + box = 'vertical', + border = true, + title = '{title} {live} {flags}', + { win = 'input', height = 1, border = 'bottom' }, + { win = 'list', border = 'none' }, + }, + { win = 'preview', title = '{preview}', border = true, width = 0.6 }, + }, + }, + vertical = { + layout = { + backdrop = false, + width = 0.5, + min_width = 80, + height = 0.8, + min_height = 30, + box = 'vertical', + border = true, + title = '{title} {live} {flags}', + title_pos = 'center', + { win = 'input', height = 1, border = 'bottom' }, + { win = 'list', border = 'none' }, + { win = 'preview', title = '{preview}', height = 0.6, border = 'top' }, + }, + }, + }, + ---@class snacks.picker.matcher.Config + matcher = { + fuzzy = true, -- use fuzzy matching + smartcase = true, -- use smartcase + ignorecase = true, -- use ignorecase + sort_empty = false, -- sort results when the search string is empty + filename_bonus = true, -- give bonus for matching file names (last part of the path) + file_pos = true, -- support patterns like `file:line:col` and `file:line` + -- the bonusses below, possibly require string concatenation and path normalization, + -- so this can have a performance impact for large lists and increase memory usage + cwd_bonus = false, -- give bonus for matching files in the cwd + frecency = false, -- frecency bonus + history_bonus = false, -- give more weight to chronological order + }, + sort = { + -- default sort is by score, text length and index + fields = { 'score:desc', '#text', 'idx' }, + }, + ui_select = true, -- replace `vim.ui.select` with the snacks picker + ---@class snacks.picker.formatters.Config + formatters = { + text = { + ft = nil, ---@type string? filetype for highlighting + }, + file = { + filename_first = false, -- display filename before the file path + --- * left: truncate the beginning of the path + --- * center: truncate the middle of the path + --- * right: truncate the end of the path + ---@type "left"|"center"|"right" + truncate = 'center', + min_width = 40, -- minimum length of the truncated path + filename_only = false, -- only show the filename + icon_width = 2, -- width of the icon (in characters) + git_status_hl = true, -- use the git status highlight group for the filename + }, + selected = { + show_always = false, -- only show the selected column when there are multiple selections + unselected = true, -- use the unselected icon for unselected items + }, + severity = { + icons = true, -- show severity icons + level = false, -- show severity level + ---@type "left"|"right" + pos = 'left', -- position of the diagnostics + }, + }, + ---@class snacks.picker.previewers.Config + previewers = { + diff = { + -- fancy: Snacks fancy diff (borders, multi-column line numbers, syntax highlighting) + -- syntax: Neovim's built-in diff syntax highlighting + -- terminal: external command (git's pager for git commands, `cmd` for other diffs) + style = 'fancy', ---@type "fancy"|"syntax"|"terminal" + cmd = { 'delta' }, -- example for using `delta` as the external diff command + ---@type vim.wo?|{} window options for the fancy diff preview window + wo = { + breakindent = true, + wrap = true, + linebreak = true, + showbreak = '', + }, + }, + git = { + args = {}, -- additional arguments passed to the git command. Useful to set pager options usin `-c ...` + }, + file = { + max_size = 1024 * 1024, -- 1MB + max_line_length = 500, -- max line length + ft = nil, ---@type string? filetype for highlighting. Use `nil` for auto detect + }, + man_pager = nil, ---@type string? MANPAGER env to use for `man` preview + }, + ---@class snacks.picker.jump.Config + jump = { + jumplist = true, -- save the current position in the jumplist + tagstack = false, -- save the current position in the tagstack + reuse_win = false, -- reuse an existing window if the buffer is already open + close = true, -- close the picker when jumping/editing to a location (defaults to true) + match = false, -- jump to the first match position. (useful for `lines`) + }, + toggles = { + follow = 'f', + hidden = 'h', + ignored = 'i', + modified = 'm', + regex = { icon = 'R', value = false }, + }, + win = { + -- input window + input = { + keys = { + -- to close the picker on ESC instead of going to normal mode, + -- add the following keymap to your config + -- [""] = { "close", mode = { "n", "i" } }, + ['/'] = 'toggle_focus', + [''] = { 'history_forward', mode = { 'i', 'n' } }, + [''] = { 'history_back', mode = { 'i', 'n' } }, + [''] = { 'cancel', mode = 'i' }, + [''] = { '', mode = { 'i' }, expr = true, desc = 'delete word' }, + [''] = { 'confirm', mode = { 'n', 'i' } }, + [''] = { 'list_down', mode = { 'i', 'n' } }, + [''] = 'cancel', + [''] = { { 'pick_win', 'jump' }, mode = { 'n', 'i' } }, + [''] = { 'select_and_prev', mode = { 'i', 'n' } }, + [''] = { 'select_and_next', mode = { 'i', 'n' } }, + [''] = { 'list_up', mode = { 'i', 'n' } }, + [''] = { 'inspect', mode = { 'n', 'i' } }, + [''] = { 'toggle_follow', mode = { 'i', 'n' } }, + [''] = { 'toggle_hidden', mode = { 'i', 'n' } }, + [''] = { 'toggle_ignored', mode = { 'i', 'n' } }, + [''] = { 'toggle_regex', mode = { 'i', 'n' } }, + [''] = { 'toggle_maximize', mode = { 'i', 'n' } }, + [''] = { 'toggle_preview', mode = { 'i', 'n' } }, + [''] = { 'cycle_win', mode = { 'i', 'n' } }, + [''] = { 'select_all', mode = { 'n', 'i' } }, + [''] = { 'preview_scroll_up', mode = { 'i', 'n' } }, + [''] = { 'list_scroll_down', mode = { 'i', 'n' } }, + [''] = { 'preview_scroll_down', mode = { 'i', 'n' } }, + [''] = { 'toggle_live', mode = { 'i', 'n' } }, + [''] = { 'list_down', mode = { 'i', 'n' } }, + [''] = { 'list_up', mode = { 'i', 'n' } }, + [''] = { 'list_down', mode = { 'i', 'n' } }, + [''] = { 'list_up', mode = { 'i', 'n' } }, + [''] = { 'qflist', mode = { 'i', 'n' } }, + [''] = { 'edit_split', mode = { 'i', 'n' } }, + [''] = { 'tab', mode = { 'n', 'i' } }, + [''] = { 'list_scroll_up', mode = { 'i', 'n' } }, + [''] = { 'edit_vsplit', mode = { 'i', 'n' } }, + ['#'] = { 'insert_alt', mode = 'i' }, + ['%'] = { 'insert_filename', mode = 'i' }, + [''] = { 'insert_cWORD', mode = 'i' }, + [''] = { 'insert_file', mode = 'i' }, + [''] = { 'insert_line', mode = 'i' }, + [''] = { 'insert_file_full', mode = 'i' }, + [''] = { 'insert_cword', mode = 'i' }, + ['H'] = 'layout_left', + ['J'] = 'layout_bottom', + ['K'] = 'layout_top', + ['L'] = 'layout_right', + ['?'] = 'toggle_help_input', + ['G'] = 'list_bottom', + ['gg'] = 'list_top', + ['j'] = 'list_down', + ['k'] = 'list_up', + ['q'] = 'cancel', + }, + b = { + minipairs_disable = true, + }, + }, + -- result list window + list = { + keys = { + ['/'] = 'toggle_focus', + ['<2-LeftMouse>'] = 'confirm', + [''] = 'confirm', + [''] = 'list_down', + [''] = 'cancel', + [''] = { { 'pick_win', 'jump' } }, + [''] = { 'select_and_prev', mode = { 'n', 'x' } }, + [''] = { 'select_and_next', mode = { 'n', 'x' } }, + [''] = 'list_up', + [''] = 'inspect', + [''] = 'toggle_follow', + [''] = 'toggle_hidden', + [''] = 'toggle_ignored', + [''] = 'toggle_maximize', + [''] = 'toggle_preview', + [''] = 'cycle_win', + [''] = 'select_all', + [''] = 'preview_scroll_up', + [''] = 'list_scroll_down', + [''] = 'preview_scroll_down', + [''] = 'list_down', + [''] = 'list_up', + [''] = 'list_down', + [''] = 'list_up', + [''] = 'qflist', + [''] = 'print_path', + [''] = 'edit_split', + [''] = 'tab', + [''] = 'list_scroll_up', + [''] = 'edit_vsplit', + ['H'] = 'layout_left', + ['J'] = 'layout_bottom', + ['K'] = 'layout_top', + ['L'] = 'layout_right', + ['?'] = 'toggle_help_list', + ['G'] = 'list_bottom', + ['gg'] = 'list_top', + ['i'] = 'focus_input', + ['j'] = 'list_down', + ['k'] = 'list_up', + ['q'] = 'cancel', + ['zb'] = 'list_scroll_bottom', + ['zt'] = 'list_scroll_top', + ['zz'] = 'list_scroll_center', + }, + wo = { + conceallevel = 2, + concealcursor = 'nvc', + }, + }, + -- preview window + preview = { + keys = { + [''] = 'cancel', + ['q'] = 'cancel', + ['i'] = 'focus_input', + [''] = 'cycle_win', + }, + }, + }, + ---@class snacks.picker.icons + icons = Glyphs.snacksPicker, + + ---@class snacks.picker.db.Config + db = { + -- path to the sqlite3 library + -- If not set, it will try to load the library by name. + -- On Windows it will download the library from the internet. + sqlite3_path = nil, ---@type string? + }, + ---@class snacks.picker.debug + debug = { + scores = false, -- show scores in the list + leaks = false, -- show when pickers don't get garbage collected + explorer = false, -- show explorer debug info + files = false, -- show file debug info + grep = false, -- show file debug info + proc = false, -- show proc debug info + extmarks = false, -- show extmarks errors + }, + }, + } + + vim.keymap.set('n', 'fy', Snacks.picker.cliphist, { desc = 'Clipboard history' }) + + vim.api.nvim_create_autocmd({ 'VimEnter', 'DirChanged' }, { + group = vim.api.nvim_create_augroup('snacksPicker-git-attach', { clear = true }), + callback = function(event) + -- check if the workspace is a git repo + local code = vim.system({ 'git', 'rev-parse', '--is-inside-work-tree' }, {}, nil):wait().code + if code ~= 0 then + return + end + + vim.keymap.set('n', 'vC', Snacks.picker.git_log_file, { desc = 'Git: commits - current buf' }) + vim.keymap.set('n', 'vS', Snacks.picker.git_stash, { desc = 'Git: stash' }) + vim.keymap.set('n', 'vb', Snacks.picker.git_branches, { desc = 'Git: branches' }) + vim.keymap.set('n', 'vc', Snacks.picker.git_log, { desc = 'Git: commits' }) + vim.keymap.set('n', 'vd', Snacks.picker.git_diff, { desc = 'Git: diff' }) + vim.keymap.set('n', 'vf', Snacks.picker.git_files, { desc = 'Git: files' }) + vim.keymap.set('n', 'vl', Snacks.picker.git_log_line, { desc = 'Git: commits - current line' }) + vim.keymap.set('n', 'vs', Snacks.picker.git_status, { desc = 'Git: status' }) + end, + }) + + vim.keymap.set('n', 'lc', Snacks.picker.lsp_config, { desc = 'LSP: lsp-config info' }) + end, +} diff --git a/lua/plugins/which-key.lua b/lua/plugins/which-key.lua index 7b84cccd..a2c883ec 100644 --- a/lua/plugins/which-key.lua +++ b/lua/plugins/which-key.lua @@ -23,6 +23,7 @@ return { { 'f', group = '[F]uzzy-find', mode = { 'n', 'v' } }, { 'g', group = '[G]rep', mode = { 'n', 'v' } }, { 'G', group = '[G]it', mode = { 'n', 'v' } }, + { 'v', group = '[V]ersion control', mode = { 'n', 'v' } }, { 'l', group = '[L]SP', mode = { 'n', 'v' } }, { 't', group = '[T]oggle' }, { 'd', group = '[D]iangostic' },