local which_key = require('which-key') local icons = require('lib.icons') local util = require('lib.util') local prompts = require('lib.prompts') local setup = { preset = 'helix', plugins = { marks = true, registers = true, spelling = { enabled = true, suggestions = 30, }, presets = { operators = true, motions = true, text_objects = true, windows = true, nav = true, z = true, g = true, }, }, icons = { breadcrumb = icons.ui.ArrowOpen, separator = icons.ui.Arrow, group = '', keys = { Space = icons.ui.Rocket, }, rules = false, -- enable auto icon rules }, show_help = false, show_keys = true, triggers = { { '', mode = 'nvisoct' }, { '', mode = { 'n', 'v' } }, }, } local normal_mappings = { mode = 'n', { 'x', ':x', desc = ' Save and Quit' }, { 'a', group = ' AI' }, { 'aC', ':AvanteClear', desc = 'avante: clear' }, { 'am', ':MCPHub', desc = 'MCPHub' }, { 'an', ':AvanteChatNew', desc = 'avante: new' }, { 'ap', group = 'Insert Prompt' }, { 'apd', prompts.add_prompt('docs'), desc = 'Docs' }, { 'ape', prompts.add_prompt('explain'), desc = 'Explain' }, { 'apf', prompts.add_prompt('fix'), desc = 'Fix' }, { 'apg', prompts.add_prompt('commit'), desc = 'Commit' }, { 'apo', prompts.add_prompt('optimize'), desc = 'Optimize' }, { 'apr', prompts.add_prompt('review'), desc = 'Review' }, { 'apt', prompts.add_prompt('tests'), desc = 'Tests' }, { 'c', group = ' Code' }, { 'cF', ':retab', desc = 'Fix Tabs' }, { 'cP', ':CccConvert', desc = 'Convert Color' }, { 'cR', ':ReloadConfig', desc = 'Reload Configs' }, { 'cc', ':CccHighlighterToggle', desc = 'Highlight Colors' }, { 'cd', ':RootDir', desc = 'Root Directory' }, { 'ce', ':%SnipRun', desc = 'Execute File' }, { 'cf', ':lua vim.lsp.buf.format({async = true})', desc = 'Format File' }, { 'cl', '::g/^\\s*$/d', desc = 'Clean Empty Lines' }, { 'cm', ':MarkdownPreviewToggle', desc = 'Markdown Preview' }, { 'co', ':Dashboard', desc = 'Dashboard' }, { 'cp', ':CccPick', desc = 'Pick Color' }, { 'cs', ':source %', desc = 'Source File' }, { 'C', group = ' Comment' }, { 'Cb', 'CBccbox', desc = 'Comment Box' }, { 'Ct', 'CBllline', desc = 'Tiled line' }, { 'Cl', 'CBline', desc = 'Line' }, { 'Cm', 'CBllbox14', desc = 'Marked' }, { 'Cc', 'CBcatalog', desc = 'Catalog' }, { 'Cd', 'CBd', desc = 'Delete Comment Style' }, { 'e', group = ' Edit' }, { 'ea', ':b#', desc = 'Alternate File' }, { 'ec', group = 'Edit Configs' }, { 'ecg', ':e ~/.gitconfig', desc = 'Git Config' }, { 'eck', ':e ~/.config/kitty/kitty.conf', desc = 'Kitty Config' }, { 'ecn', ':e $MYVIMRC', desc = 'Neovim Init' }, { 'ecp', ':e ~/.config/nvim/lua/plugins/list.lua', desc = 'Plugin List' }, { 'ect', ':e ~/.config/tmux/tmux.conf', desc = 'Tmux Config' }, { 'eE', ':lua Snacks.explorer()', desc = 'File Explorer' }, { 'et', ':lua MiniFiles.open()', desc = 'Explore Tree' }, { 'ef', 'gf', desc = 'File Under Cursor' }, { 'em', ':e README.md', desc = 'Readme' }, { 'en', ':enew', desc = 'New File' }, { 'f', group = ' Find' }, { 'fx', ':%bd|e#|bd#', desc = 'Close except current' }, { 'g', group = ' Git' }, { 'gA', ':Gitsigns stage_buffer', desc = 'Stage Buffer' }, { 'gC', ':CoAuthor', desc = 'Co-Authors' }, { 'gP', ':Git push', desc = 'Push' }, { 'gR', ':Gitsigns reset_buffer', desc = 'Reset Buffer' }, { 'ga', ':Gitsigns stage_hunk', desc = 'Stage Hunk' }, { 'gb', ":lua require('gitsigns').blame_line({full = true})", desc = 'Blame' }, { 'gc', ':Git commit', desc = 'Commit Staged' }, { 'gB', ":lua require('snacks').git.blame_line()", desc = 'Detailed Blame' }, { 'gd', ':Gitsigns diffthis HEAD', desc = 'Git Diff' }, { 'gF', ':Git', desc = 'Fugitive Panel' }, { 'gg', ':lua require("snacks").lazygit()', desc = 'Lazygit' }, { 'gi', ':Gitsigns preview_hunk', desc = 'Hunk Info' }, { 'gj', ':Gitsigns next_hunk', desc = 'Next Hunk' }, { 'gk', ':Gitsigns prev_hunk', desc = 'Prev Hunk' }, { 'go', group = 'Octohub' }, { 'gp', ':Git pull', desc = 'Pull' }, { 'gr', ':Gitsigns reset_hunk', desc = 'Reset Hunk' }, { 'gt', group = 'Toggle' }, { 'gtb', ':Gitsigns toggle_current_line_blame', desc = 'Blame' }, { 'gtd', ':Gitsigns toggle_deleted', desc = 'Deleted' }, { 'gtl', ':Gitsigns toggle_linehl', desc = 'Line HL' }, { 'gtn', ':Gitsigns toggle_numhl', desc = 'Number HL' }, { 'gts', ':Gitsigns toggle_signs', desc = 'Signs' }, { 'gtw', ':Gitsigns toggle_word_diff', desc = 'Word Diff' }, { 'gu', ':Gitsigns undo_stage_hunk', desc = 'Undo Stage Hunk' }, { 'gv', ':Gitsigns select_hunk', desc = 'Select Hunk' }, { 'gw', ':lua require("snacks").gitbrowse()', desc = 'Git Browse' }, { 'i', group = ' Insert' }, { 'id', ":put =strftime('## %a, %d %b, %Y, %r')", desc = 'Date' }, { 'if', ":put =expand('%:t')", desc = 'File Name' }, { 'ip', ':put %', desc = 'Relative Path' }, { 'iP', ':put %:p', desc = 'Absolute Path' }, { 'it', ":put =strftime('## %r')", desc = 'Time' }, { 'j', group = ' Jump' }, { 'jc', '*', desc = 'Word' }, { 'jd', ':FlashDiagnostics', desc = 'Diagnostics' }, { 'jh', '', desc = 'Backward' }, { 'jj', ":lua require('flash').remote()", desc = 'Remote' }, { 'jk', ":lua require('flash').treesitter()", desc = 'Treesitter' }, { 'jl', '', desc = 'Forward' }, { 'jp', ":lua require('flash').jump({continue = true})", desc = 'Previous Jump' }, { 'js', ":lua require('flash').jump()", desc = 'Search' }, { 'jt', ":lua require('flash').treesitter_search()", desc = 'Remote Treesitter' }, { 'jn', ":lua require('flash').jump({search = { forward = true, wrap = false, multi_window = false },})", desc = 'Search Forward', }, { 'jN', ":lua require('flash').jump({search = { forward = false, wrap = false, multi_window = false },})", desc = 'Search Backward', }, { 'jw', ':lua require("flash").jump({ pattern = vim.fn.expand("")})', desc = 'Current Word', }, { 'l', group = ' LSP' }, { 'la', ':Lspsaga code_action', desc = 'Code Action' }, { 'ld', ':Lspsaga goto_definition', desc = 'Goto Definition' }, { 'lf', ':Lspsaga finder', desc = 'Finder' }, { 'lh', ':Lspsaga hover_doc', desc = 'Hover' }, { 'lI', ':LspInfo', desc = 'LSP Info' }, { 'lj', ':Lspsaga diagnostic_jump_next', desc = 'Next Diagnostic' }, { 'lk', ':Lspsaga diagnostic_jump_prev', desc = 'Prev Diagnostic' }, { 'lo', ':Lspsaga outline', desc = 'Outline' }, { 'lp', ':Lspsaga peek_definition', desc = 'Peek Definition' }, { 'lq', ':LspStop', desc = 'Stop LSP' }, { 'lQ', ':LspRestart', desc = 'Restart LSP' }, { 'lr', ':Lspsaga rename', desc = 'Rename' }, { 'lR', ':Lspsaga project_replace', desc = 'Replace' }, { 'lt', ':Lspsaga goto_type_definition', desc = 'Goto Type Definition' }, { 'lT', ':Lspsaga peek_type_definition', desc = 'Peek Type Definition' }, { 'm', group = ' Marks' }, { 'mb', ":lua require('telescope').extensions.markit.bookmarks_list_all()", desc = 'Bookmarks', }, { 'mB', ":lua require('telescope').extensions.markit.bookmarks_list_all({project_only = true})", desc = 'Bookmarks In Project', }, { 'md', ":lua require('markit').delete_line()", desc = 'Delete Marks In Line' }, { 'mD', ":lua require('markit').delete_buf()", desc = 'Delete Marks In Buffer' }, { 'mg', group = 'Group Bookmarks' }, { 'mG', group = 'Group Bookmarks In Project' }, { 'mh', ":lua require('markit').prev_bookmark()", desc = 'Previous Bookmark' }, { 'mj', ":lua require('markit').next()", desc = 'Next' }, { 'mk', ":lua require('markit').prev()", desc = 'Previous' }, { 'ml', ":lua require('markit').next_bookmark()", desc = 'Next Bookmark' }, { 'mn', group = 'Next Bookmark In Group' }, { 'mp', group = 'Previous Bookmark In Group' }, { 'mP', ":lua require('markit').preview()", desc = 'Preview' }, { 'ms', ":lua require('markit').set_next()", desc = 'Set Next' }, { 'mt', ":lua require('markit').toggle()", desc = 'Toggle' }, { 'mx', ":lua require('markit').delete_bookmark()", desc = 'Delete Bookmark' }, { 'o', group = ' Options' }, { 'oi', 'vim.show_pos', desc = 'Inspect Position' }, { 'oN', ':lua Snacks.notifier.show_history()', desc = 'Notification History' }, { 'or', ':set relativenumber!', desc = 'Relative Numbers' }, { 'p', group = ' Packages' }, { 'pc', ':Lazy check', desc = 'Check' }, { 'pd', ':Lazy debug', desc = 'Debug' }, { 'pe', ':lua require("snacks").profiler.scratch()', desc = 'Profiler Scratch' }, { 'pf', ':lua require("snacks").profiler.pick()', desc = 'Profiler Pick' }, { 'pi', ':Lazy install', desc = 'Install' }, { 'pl', ':Lazy log', desc = 'Log' }, { 'pm', ':Mason', desc = 'Mason' }, { 'pp', ':Lazy', desc = 'Plugins' }, { 'pP', ':Lazy profile', desc = 'Profile' }, { 'pr', ':Lazy restore', desc = 'Restore' }, { 'ps', ':Lazy sync', desc = 'Sync' }, { 'pt', ':lua require("snacks").profiler.toggle()', desc = 'Profiler Toggle' }, { 'pu', ':Lazy update', desc = 'Update' }, { 'px', ':Lazy clean', desc = 'Clean' }, { 'q', group = ' Quit' }, { 'qa', ':qall', desc = 'Quit All' }, { 'qb', ':bw', desc = 'Close Buffer' }, { 'qd', ':lua require("snacks").bufdelete()', desc = 'Delete Buffer' }, { 'qf', ':qall!', desc = 'Force Quit' }, { 'qo', ':%bdelete|b#|bdelete#', desc = 'Close Others' }, { 'qq', ':q', desc = 'Quit' }, { 'qs', 'c', desc = 'Close Split' }, { 'qw', ':wq', desc = 'Write and Quit' }, { 'r', group = ' Refactor' }, { 'ra', ":lua require('spectre').open()", desc = 'Replace All' }, { 'rb', ":lua require('spectre').open_file_search()", desc = 'Replace Buffer' }, { 'rd', '', desc = 'Go To Definition' }, -- treesitter navigation { 'rh', '', desc = 'List Definition Head' }, { 'rj', '', desc = 'Next Usage' }, { 'rk', '', desc = 'Previous Usage' }, { 'rl', '', desc = 'List Definition' }, { 'rn', '', desc = 'Swap Next' }, { 'rp', '', desc = 'Swap Previous' }, { 'rr', '', desc = 'Smart Rename' }, { 'rs', ':%s/\\<\\>//gI', desc = 'Replace Word Buffer' }, { 'rw', ":lua require('spectre').open_visual({select_word=true})", desc = 'Replace Word Everywhere' }, { 's', group = ' Split' }, { 's+', ':resize +10', desc = 'Increase window height' }, { 's-', ':vertical resize -20', desc = 'Decrease window width' }, { 's/', 's', desc = 'Split Below' }, { 's=', ':vertical resize +20', desc = 'Increase window width' }, { 'sH', ':vertical resize -10', desc = 'Decrease window width' }, { 'sJ', ':resize -5', desc = 'Decrease window height' }, { 'sK', ':resize +5', desc = 'Increase window height' }, { 'sL', ':vertical resize +10', desc = 'Increase window width' }, { 's\\', 'v', desc = 'Split Right' }, { 's_', ':resize -10', desc = 'Decrease window height' }, { 's`', 'p', desc = 'Previous Window' }, { 'sa', ':split', desc = 'Horizontal Split' }, { 'sc', ':tabclose', desc = 'Close Tab' }, { 'sf', ':tabfirst', desc = 'First Tab' }, { 'sh', 'h', desc = 'Move Left' }, { 'sj', 'j', desc = 'Move Down' }, { 'sk', 'k', desc = 'Move Up' }, { 'sl', 'l', desc = 'Move Right' }, { 'sp', ':NavigatorPrevious', desc = 'Previous Pane' }, { 'sq', 'c', desc = 'Close Split' }, { 'ss', ':vsplit', desc = 'Vertical Split' }, { 't', group = ' Terminal' }, { 't1', '1ToggleTerm', desc = 'Toggle Terminal' }, { 't2', '2ToggleTerm', desc = 'Toggle Terminal' }, { 'th', 'Sterm', desc = 'Horizontal Terminal' }, { 'tv', 'Vterm', desc = 'Vertical Terminal' }, { 'tc', 'close', desc = 'Hide Terminal' }, { 'w', group = ' Writing' }, { 'wc', ':set spell!', desc = 'Spellcheck' }, { 'wd', ':lua require("snacks").dim.enable()', desc = 'Dim On' }, { 'wD', ':lua require("snacks").dim.disable()', desc = 'Dim Off' }, { 'wf', ":lua require'utils'.sudo_write()", desc = 'Force Write' }, { 'wj', ']s', desc = 'Next Misspell' }, { 'wk', '[s', desc = 'Prev Misspell' }, { 'wn', ':WriteNoFormat', desc = 'Write Without Formatting' }, { 'wq', ':wq', desc = 'Write and Quit' }, { 'ww', ':w', desc = 'Write' }, { 'wz', ':lua require("snacks").zen.zen()', desc = 'Zen' }, { 'wZ', ':lua require("snacks").zen.zoom()', desc = 'Zoom' }, { 'y', group = ' Yank' }, { 'yL', ':CopyAbsolutePathWithLine', desc = 'Absolute Path with Line' }, { 'yP', ':CopyAbsolutePath', desc = 'Absolute Path' }, { 'ya', ':%y+', desc = 'Copy Whole File' }, { 'yf', ':CopyFileName', desc = 'File Name' }, { 'yg', ':lua require"gitlinker".get_buf_range_url()', desc = 'Copy Git URL' }, { 'yl', ':CopyRelativePathWithLine', desc = 'Relative Path with Line' }, { 'yp', ':CopyRelativePath', desc = 'Relative Path' }, } -- Numerical mappings for i = 1, 9 do table.insert(normal_mappings, { string.format('n%d', i), string.format(':Tdo %d', i), desc = string.format('Todo %d Days In Future', i), }) table.insert(normal_mappings, { string.format('np%d', i), string.format(':Tdo -%d', i), desc = string.format('Todo %d Days From Past', i), }) table.insert(normal_mappings, { string.format('f%d', i), string.format(':LualineBuffersJump%d', i), desc = string.format('File %d', i), }) table.insert(normal_mappings, { string.format('m%d', i), string.format(':lua require("markit").toggle_bookmark%d()', i), desc = string.format('Toggle Group %d Bookmark', i), }) table.insert(normal_mappings, { string.format('mp%d', i), string.format(':lua require("markit").prev_bookmark%d()', i), desc = string.format('Previous Group %d Bookmarks', i), }) table.insert(normal_mappings, { string.format('mn%d', i), string.format(':lua require("markit").next_bookmark%d()', i), desc = string.format('Next Group %d Bookmarks', i), }) table.insert(normal_mappings, { string.format('mg%d', i), string.format(':lua require("telescope").extensions.markit.bookmarks_list_all({group = %d})', i), desc = string.format('Group %d Bookmarks', i), }) table.insert(normal_mappings, { string.format('mG%d', i), string.format( ':lua require("telescope").extensions.markit.bookmarks_list_all({group = %d, project_only = true})', i ), desc = string.format('Group %d Bookmarks In Project', i), }) end local visual_mappings = { mode = 'v', { 'a', group = ' AI' }, { 'c', group = ' Code' }, { 'ce', ":'<,'>SnipRun", desc = 'Execute Selection' }, { 'cS', ':sort!', desc = 'Sort Desc' }, { 'ci', ':sort i', desc = 'Sort Case Insensitive' }, { 'cs', ':sort', desc = 'Sort Asc' }, { 'cu', ':!uniq', desc = 'Unique' }, { 'cx', ':lua', desc = 'Execute Lua' }, { 'C', group = ' Comment' }, { 'Cb', 'CBccbox', desc = 'Comment Box' }, { 'Ct', 'CBllline', desc = 'Tiled line' }, { 'Cl', 'CBline', desc = 'Line' }, { 'Cm', 'CBllbox14', desc = 'Marked' }, { 'Cc', 'CBcatalog', desc = 'Catalog' }, { 'Cd', 'CBd', desc = 'Delete Comment Style' }, { 'g', group = ' Git' }, { 'ga', ":'<,'>Gitsigns stage_hunk", desc = 'Stage Hunk' }, { 'gr', ":'<,'>Gitsigns reset_hunk", desc = 'Reset Hunk' }, { 'gu', ":'<,'>Gitsigns undo_stage_hunk", desc = 'Undo Stage Hunk' }, { 'j', group = ' Jump' }, { 'jN', ":lua require('flash').jump({search = { forward = false, wrap = false, multi_window = false },})", desc = 'Search Backward', }, { 'jd', ':FlashDiagnostics', desc = 'Diagnostics' }, { 'jj', ":lua require('flash').remote()", desc = 'Remote' }, { 'jk', ":lua require('flash').treesitter()", desc = 'Treesitter' }, { 'jn', ":lua require('flash').jump({search = { forward = true, wrap = false, multi_window = false },})", desc = 'Search Forward', }, { 'jp', ":lua require('flash').jump({continue = true})", desc = 'Previous Jump' }, { 'js', ":lua require('flash').jump()", desc = 'Search' }, { 'jt', ":lua require('flash').treesitter_search()", desc = 'Remote Treesitter' }, { 'jw', ':lua require("flash").jump({ pattern = vim.fn.expand("")})', desc = 'Current Word', }, { 'l', group = ' LSP' }, { 'la', ':Lspsaga range_code_action', desc = 'Code Action' }, { 'p', group = ' ScreenShot' }, { 'py', 'CodeSnap', mode = 'x', desc = 'Save selected code snapshot into clipboard' }, { 'ps', 'CodeSnapSave', mode = 'x', desc = 'Save selected code snapshot in ~/Pictures' }, { 'ph', 'CodeSnapHighlight', mode = 'x', desc = 'Highlight and snapshot selected code into clipboard', }, { 'pi', 'CodeSnapASCII', mode = 'x', desc = 'Save ASCII code snapshot into clipboard' }, { 'y', group = ' Yank' }, { 'yg', ':lua require"gitlinker".get_buf_range_url("v")', desc = 'Copy Git URL' }, } local no_leader_mappings = { mode = 'n', { '', ':resize -10', desc = 'Decrease window height' }, { '', ':vertical resize -10', desc = 'Decrease window width' }, { '', ':vertical resize +10', desc = 'Increase window width' }, { '', ':resize +10', desc = 'Increase window height' }, { '', ':Fterm lazygit', desc = 'Lazygit' }, { '', ':NavigatorLeft', desc = 'Move Left' }, { '', ':NavigatorDown', desc = 'Move Down' }, { '', ':NavigatorUp', desc = 'Move Up' }, { '', ':NavigatorRight', desc = 'Move Right' }, { '', ':NavigatorPrevious', desc = 'Previous Pane' }, { '', ':bprevious', desc = 'Previous Buffer' }, { '', ':bnext', desc = 'Next Buffer' }, { '', ':bnext', desc = 'Next Buffer' }, { '', ':bprevious', desc = 'Previous Buffer' }, { 'K', ':Lspsaga hover_doc', desc = 'LSP Hover' }, { 'Q', ':qall!', desc = 'Force Quit!' }, { 'U', ':redo', desc = 'Redo' }, { '[', group = ' Previous' }, { '[g', ':Gitsigns prev_hunk', desc = 'Git Hunk' }, { '[o', group = 'Textobjects' }, { ']', group = ' Next' }, { ']g', ':Gitsigns next_hunk', desc = 'Git Hunk' }, { ']o', group = 'Textobjects' }, { 'gd', ':Lspsaga goto_definition', desc = 'Goto Definition' }, } which_key.setup(setup) which_key.add(normal_mappings) which_key.add(visual_mappings) which_key.add(no_leader_mappings) if util.get_user_config('enable_test_runner', false) then local test_runner_bindings = { mode = 'n', { 'u', group = ' Test' }, { 'uc', ':lua require("neotest").run.run()', desc = 'Run Current Test' }, { 'uf', ':lua require("neotest").run.run(vim.fn.expand("%"))', desc = 'Run Test File' }, { 'uo', ':Neotest output-panel', desc = 'Test Output' }, { 'us', ':Neotest summary', desc = 'Test Summary' }, } which_key.add(test_runner_bindings) end if util.get_user_config('enable_db_explorer', false) then local db_explorer_bindings = { mode = 'n', { 'd', group = ' Database' }, { 'dS', ':lua require("dbee").store("json", "buffer", { extra_arg = 0 })', desc = 'To JSON' }, { 'db', ':DBToggle', desc = 'DB Explorer' }, { 'dj', ':lua require("dbee").next()', desc = 'DB Next' }, { 'dk', ':lua require("dbee").prev()', desc = 'DB Prev' }, { 'ds', ':lua require("dbee").store("csv", "buffer", { extra_arg = 0 })', desc = 'To CSV' }, { 'dt', ':lua require("dbee").store("table", "buffer", { extra_arg = 0 })', desc = 'To Table' }, } which_key.add(db_explorer_bindings) end if util.get_user_config('enable_debugger', false) then local debugger_bindings = { mode = 'n', { 'b', group = ' Debug' }, { 'bO', ':DapStepOut', desc = 'Out' }, { 'bR', ':DapRestartFrame', desc = 'Restart Frame' }, { 'bb', ':DapToggleBreakpoint', desc = 'Breakpoint' }, { 'bc', ':DapContinue', desc = 'Continue' }, { 'bi', ':DapStepInto', desc = 'Into' }, { 'bl', ":lua require'dap'.run_last()", desc = 'Last' }, { 'bo', ':DapStepOver', desc = 'Over' }, { 'br', ':DapToggleRepl', desc = 'Repl' }, { 'bt', ':DapUIToggle', desc = 'Debugger' }, { 'bx', ':DapTerminate', desc = 'Exit' }, } which_key.add(debugger_bindings) end local user_keybindings = require('lib.util').get_user_config('user_keybindings', {}) which_key.add(user_keybindings)