From 7ed2303648bf83bb081d9bd863660ebf2344ce47 Mon Sep 17 00:00:00 2001 From: srdusr Date: Wed, 24 Sep 2025 04:19:28 +0200 Subject: Squashed 'common/config/nvim/' changes from 2a8020a..966d12a 966d12a Update/Overhaul git-subtree-dir: common/config/nvim git-subtree-split: 966d12ac730c83da90d60ab24eae539b2ea69441 --- lua/user/keys.lua | 752 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 604 insertions(+), 148 deletions(-) mode change 100644 => 100755 lua/user/keys.lua (limited to 'lua/user/keys.lua') diff --git a/lua/user/keys.lua b/lua/user/keys.lua old mode 100644 new mode 100755 index 87d852b..63b64fa --- a/lua/user/keys.lua +++ b/lua/user/keys.lua @@ -1,19 +1,134 @@ -local keymap = vim.keymap +-- ============================================================================ +-- Key Mappings +-- ============================================================================ + local map = function(mode, l, r, opts) - opts = opts or {} - opts.silent = true - opts.noremap = true - keymap.set(mode, l, r, opts) + if r == nil then + vim.notify("Attempted to map key '" .. l .. "' but RHS is nil", vim.log.levels.WARN) + return + end + opts = vim.tbl_extend('force', { + silent = true, + noremap = true + }, opts or {}) + vim.keymap.set(mode, l, r, opts) end -local term_opts = { noremap = true, silent = false } -local mods = require("user.mods") -local bufnr = vim.api.nvim_get_current_buf() --- Semi-colon as leader key +-- Leader key vim.g.mapleader = ";" +vim.g.maplocalleader = "\\" + +-- Tmux/Vim navigation +local function smart_move(direction, tmux_cmd) + local curwin = vim.api.nvim_get_current_win() + vim.cmd('wincmd ' .. direction) + if curwin == vim.api.nvim_get_current_win() then + vim.fn.system('tmux select-pane ' .. tmux_cmd) + end +end + +-- Window Navigation +map('n', '', function() smart_move('h', '-L') end) +map('n', '', function() smart_move('j', '-D') end) +map('n', '', function() smart_move('k', '-U') end) +map('n', '', function() smart_move('l', '-R') end) + +-- Buffer Navigation +map('n', 'bn', 'bnext') +map('n', 'bp', 'bprevious') +--map('n', 'bd', 'bdelete') +map('n', 'ba', '%bdelete') + + + +-- Get list of loaded buffers in order +local function get_buffers() + local bufs = {} + for _, buf in ipairs(vim.api.nvim_list_bufs()) do + if vim.api.nvim_buf_is_loaded(buf) then + table.insert(bufs, buf) + end + end + return bufs +end + +-- Swap two buffers by index in the buffer list +local function swap_buffers(idx1, idx2) + local bufs = get_buffers() + local buf1 = bufs[idx1] + local buf2 = bufs[idx2] + if not buf1 or not buf2 then return end + local name1 = vim.api.nvim_buf_get_name(buf1) + local name2 = vim.api.nvim_buf_get_name(buf2) + vim.cmd("b " .. buf1) + vim.cmd("file " .. name2) + vim.cmd("b " .. buf2) + vim.cmd("file " .. name1) +end + +-- Move current buffer left +vim.keymap.set("n", "bh", function() + local bufs = get_buffers() + local curr = vim.api.nvim_get_current_buf() + local idx + for i, b in ipairs(bufs) do if b == curr then idx = i break end end + if idx and idx > 1 then + swap_buffers(idx, idx-1) + end +end, { noremap = true, silent = true }) + +-- Move current buffer right +vim.keymap.set("n", "bl", function() + local bufs = get_buffers() + local curr = vim.api.nvim_get_current_buf() + local idx + for i, b in ipairs(bufs) do if b == curr then idx = i break end end + if idx and idx < #bufs then + swap_buffers(idx, idx+1) + end +end, { noremap = true, silent = true }) +-- Save and Quit +map('n', 'w', 'w') +map('n', 'q', 'q') +map('n', 'wq', 'wq') +map('n', 'Q', 'qa!') + +-- Resize Windows +map('n', '', 'resize -2') +map('n', '', 'resize +2') +map('n', '', 'vertical resize -2') +map('n', '', 'vertical resize +2') + +-- Quickfix and Location List +map('n', ']q', 'cnextzz') +map('n', '[q', 'cprevzz') +map('n', ']l', 'lnextzz') +map('n', '[l', 'lprevzz') + +-- Terminal Mode +map('t', '', '') +map('t', '', 'h') +map('t', '', 'j') +map('t', '', 'k') +map('t', '', 'l') + +-- Insert mode escape +map('i', 'jk', '') + +-- Tmux/(n)vim navigation +local function smart_move(direction, tmux_cmd) + local curwin = vim.api.nvim_get_current_win() + vim.cmd('wincmd ' .. direction) + if curwin == vim.api.nvim_get_current_win() then + vim.fn.system('tmux select-pane ' .. tmux_cmd) + end +end + +map('n', '', function() smart_move('h', '-L') end, {silent = true}) +map('n', '', function() smart_move('j', '-D') end, {silent = true}) +map('n', '', function() smart_move('k', '-U') end, {silent = true}) +map('n', '', function() smart_move('l', '-R') end, {silent = true}) --- "jk" and "kj" to exit insert-mode -map("i", "jk", "") -- Jump to next match on line using `.` instead of `;` NOTE: commented out in favour of "ggandor/flit.nvim" --map("n", ".", ";") @@ -23,29 +138,84 @@ map("i", "jk", "") -- Reload nvim config map("n", "", - "luafile ~/.config/nvim/init.lua | :echom ('Nvim config loading...') | :sl! | echo ('')") +"luafile ~/.config/nvim/init.lua | :echom ('Nvim config loading...') | :sl! | echo ('')") + +vim.keymap.set("t", "", "", { desc = "Exit terminal mode" }) +vim.keymap.set("t", "", "", { desc = "Exit terminal mode" }) --------------- Extended Operations --------------- -- Conditional 'q' to quit on floating/quickfix/help windows otherwise still use it for macros -- TODO: Have a list of if available on system/packages, example "Zen Mode" to not work on it (quit Zen Mode) map("n", "q", function() - local config = vim.api.nvim_win_get_config(0) - if config.relative ~= "" then -- is_floating_window? - return ":silent! close!" - elseif vim.o.buftype == "quickfix" then - return ":quit" - elseif vim.o.buftype == "help" then - return ":close" - else - return "q" - end + local config = vim.api.nvim_win_get_config(0) + if config.relative ~= "" then -- is_floating_window? + return ":silent! close!" + elseif vim.o.buftype == "quickfix" then + return ":quit" + elseif vim.o.buftype == "help" then + return ":close" + else + return "q" + end end, { expr = true, replace_keycodes = true }) +-- Minimalist Tab Completion +map("i", "", function() + local col = vim.fn.col('.') - 1 + local line = vim.fn.getline('.') + local prev_char = line:sub(col, col) + if vim.fn.pumvisible() == 1 or prev_char:match("%w") then + return vim.api.nvim_replace_termcodes("", true, true, true) + else + return vim.api.nvim_replace_termcodes("", true, true, true) + end +end, { expr = true }) + +-- Shift-Tab for reverse completion +map("i", "", function() + if vim.fn.pumvisible() == 1 then + return vim.api.nvim_replace_termcodes("", true, true, true) + else + return vim.api.nvim_replace_termcodes("", true, true, true) + end +end, { expr = true }) + + +-- Toggle completion +map("n", "tc", ':lua require("user.mods").toggle_completion()') + +-- Minimalist Auto Completion +map("i", "", function() + -- Exit this keymap if nvim-cmp is present + local cmp_is_present, _ = pcall(require, "cmp") + if cmp_is_present and require("cmp").visible() then + return vim.api.nvim_replace_termcodes("", true, true, true) + elseif cmp_is_present then + return vim.api.nvim_replace_termcodes("", true, true, true) + end + + -- when cmp is NOT present + if vim.fn.pumvisible() == 1 then + return vim.api.nvim_replace_termcodes("", true, true, true) + else + return vim.api.nvim_replace_termcodes("", true, true, true) + end +end, { expr = true }) + +-- Closing compaction in insert mode +map("i", "[", "[]") +map("i", "(", "()") +map("i", "{", "{}") +map("i", "/*", "/**/") + -- Edit new file -map("n", ";", [[:e =expand("%:h")..'/']], { noremap = true, silent = true, desc = "New file" }) +map("n", "e", [[:e =expand("%:h")..'/']], { noremap = true, silent = true, desc = "New file" }) -- Write as sudo -map("c", "W", "exe 'w !sudo tee >/dev/null %:p:S' | setl nomod", { silent = true, desc = "Write as Sudo" }) +map("c", "W!", "exe 'w !sudo tee >/dev/null %:p:S' | setl nomod", { silent = true, desc = "Write as Sudo" }) + +-- Don't format on save +map("c", "F!", ":noautocmd w") -- Combine buffers list with buffer name map("n", "b", ":buffers:buffer") @@ -60,20 +230,25 @@ map("n", "d", ":bd") map("n", "", ":bnext") map("n", "", ":bprevious") +-- Close all buffers and reopen last one +map("n", "D", ":update | %bdelete | edit # | normal `") + -- Delete file of current buffer map("n", "rm", "call delete(expand('%')) | bdelete!") -- List marks -map("n", "m", ":marks") +map("n", "M", ":marks") -- Messages -map("n", "M", ":messages") +map("n", "m", ":messages") --- Clear messages or just refresh/redraw the screen -map("n", "i", "lua require('notify').dismiss()") - --- Unsets the 'last search pattern' register by hitting return ---map("n", "", "!silent :noh") +map("n", "i", function() + local ok, notify = pcall(require, "notify") + if ok then + notify.dismiss() + end +end) -- Toggle set number map("n", "$", ":NumbersToggle") @@ -89,20 +264,36 @@ map("t", "", "") -- Split window map("n", "-", ":split") map("n", "\\", ":vsplit") -map("n", "c", "c") + +-- Close window +--map("n", "c", "c") +map({ "n", "t", "c" }, "c", function() + local winid = vim.api.nvim_get_current_win() + local config = vim.api.nvim_win_get_config(winid) + + if config.relative ~= "" then + -- This is a floating window + vim.cmd("CloseFloatingWindows") + else + -- Not a float/close window + vim.cmd("close") + end +end, { desc = "Close current float or all floating windows" }) -- Resize Panes ---map('n', '+', ':resize +5') ---map('n', '-', ':resize -5') map("n", "<", ":vertical resize +5") map("n", ">", ":vertical resize -5") map("n", "=", "=") +-- Mapping for left and right arrow keys in command-line mode +vim.api.nvim_set_keymap("c", "", "", { noremap = true, silent = false }) -- Left Arrow +vim.api.nvim_set_keymap("c", "", "", { noremap = true, silent = false }) -- Right Arrow + -- Map Alt+(h/j/k/l) in insert(include terminal/command) mode to move directional -map({ "i", "t", "c" }, "", "") -map({ "i", "t", "c" }, "", "") -map({ "i", "t", "c" }, "", "") -map({ "i", "t", "c" }, "", "") +map({ "i", "t" }, "", "") +map({ "i", "t" }, "", "") +map({ "i", "t" }, "", "") +map({ "i", "t" }, "", "") -- Create tab, edit and move between them map("n", "n", ":tabnew") @@ -110,10 +301,6 @@ map("n", "e", ":tabedit") map("n", "[", ":tabprev") map("n", "]", ":tabnext") --- "Zoom" a split window into a tab and/or close it ---map("n", ",", ":tabnew %") ---map("n", ".", ":tabclose") - -- Vim TABs map("n", "1", "1gt") map("n", "2", "2gt") @@ -134,10 +321,26 @@ map("n", "0", "10gt") --map("n", ">", ">>", term_opts) --map("x", "<", "", ">gv", term_opts) -map("v", "<", "", ">gv") -map("n", "<", "<") -map("n", ">", ">") +--map("v", "<", "", ">gv") +--map("n", "<", "<change mode to normal") +--map("n", ">", ">change mode to normal") + +-- Visual mode: Indent and reselect the visual area, like default behavior but explicit +map("v", "<", "", ">gv", { desc = "Indent right and reselect" }) + +-- Normal mode: Indent current line and enter Visual Line mode to repeat easily +map("n", "<", "v<<", { desc = "Indent left and select" }) +map("n", ">", "v>>", { desc = "Indent right and select" }) + +---- Visual mode: Indent and reselect the visual area, like default behavior but explicit +--map("v", "<", "<", { desc = "Indent left" }) +--map("v", ">", ">", { desc = "Indent right" }) +-- +---- Normal mode: Indent current line and enter Visual Line mode to repeat easily +--map("n", "<", "v<<", { desc = "Indent left and select" }) +--map("n", ">", "v>>", { desc = "Indent right and select" }) -- Set alt+(j/k) to switch lines of texts or simply move them map("n", "", ':let save_a=@a"add"ap:let @a=save_a') @@ -163,33 +366,31 @@ map("n", "", "!clear") -- Change file to an executable map("n", "x", - ":lua require('user.mods').Toggle_executable() | :echom ('Toggle executable') | :sl! | echo ('')") +":lua require('user.mods').Toggle_executable() | :echom ('Toggle executable') | :sl! | echo ('')") -- map("n", "x", ":!chmod +x %") +vim.keymap.set("n", "cm", function() + vim.cmd("redir @+") + vim.cmd("silent messages") + vim.cmd("redir END") + vim.notify("Copied :messages to clipboard") +end, { desc = "Copy :messages to clipboard" }) + -- Paste without replace clipboard map("v", "p", '"_dP') --- Swap two pieces of text, use x to cut in visual mode, then use Ctrl-x in --- visual mode to select text to swap with ---map("v", "", "`.``gvP``P") +map("n", "]p", 'm`o"+p``', opts) + +map("n", "[p", 'm`O"+p``', opts) + +-- Bind Ctrl-V to paste in insert/normal/command mode +map("i", "", "u+", opts) +map("n", "", '"+p', { noremap = true, silent = true }) +vim.api.nvim_set_keymap("c", "", "=getreg('+')", { noremap = true, silent = false }) -- Change Working Directory to current project map("n", "cd", ":cd %:p:h:pwd") --- Open the current file in the default program (on Mac this should just be just `open`) -map("n", "o", ":!xdg-open %") - --- URL handling -if vim.fn.has("mac") == 1 then - map("", "gx", 'call jobstart(["open", expand("")], {"detach": v:true})', {}) -elseif vim.fn.has("unix") == 1 then - map("", "gx", 'call jobstart(["xdg-open", expand("")], {"detach": v:true})', {}) -elseif vim.fn.has("wsl") == 1 then - map("", "gx", 'call jobstart(["wslview", expand("")], {"detach": v:true})', {}) -else - map[""].gx = { 'lua print("Error: gx is not supported on this OS!")' } -end - -- Search and replace map("v", "sr", 'y:%s/"//gc') @@ -197,13 +398,6 @@ map("v", "sr", 'y:%s/"//gc') map("n", "s", ":%s//g") map("v", "s", ":s//g") --- Toggle completion -map("n", "tc", ':lua require("user.mods").toggle_completion()') - --- Disable default completion. -map("i", "", "") -map("i", "", "") - -- Set line wrap map("n", "", function() local wrap_status = vim.api.nvim_exec("set wrap ?", true) @@ -223,12 +417,14 @@ map("n", "", "&foldlevel ? 'zM' : 'zR'", { expr = true }) -- Use space to toggle fold --map("n", "", "za") --- Make a copy of current file ---vim.cmd([[ --- map s :up \| saveas! %:p:r-=strftime("%y.%m.%d-%H:%M")-bak.=expand("%:e") \| 3sleep \| e # ---]]) map("n", ".b", ":!cp % %.backup") +-- Go to next window +map("n", "wn", "w", { desc = "Next window" }) + +-- Go to previous window +map("n", "wp", "W", { desc = "Previous window" }) + -- Toggle transparency map("n", "tb", ":call utils#Toggle_transparent_background()") @@ -240,7 +436,136 @@ map("n", "z", "|_") map("n", "sl", ":call utils#ToggleHiddenAll()") -- Open last closed buffer -map("n", "", ":call OpenLastClosed()") +map("n", "", ":call utils#OpenLastClosed()") + + +-- Automatically set LSP keymaps when LSP attaches to a buffer +--vim.api.nvim_create_autocmd("LspAttach", { +-- callback = function(args) +-- local bufnr = args.buf +-- local opts = { buffer = bufnr } +-- map("n", "K", vim.lsp.buf.hover) +-- map("n", "gd", "lua require('goto-preview').goto_preview_definition()") +-- map("n", "gi", "lua require('goto-preview').goto_preview_implementation()") +-- map("n", "gr", "lua require('goto-preview').goto_preview_references()") +-- map("n", "gD", vim.lsp.buf.declaration) +-- map("n", "k", vim.lsp.buf.signature_help) +-- map("n", "gt", "lua require('goto-preview').goto_preview_type_definition()") +-- map("n", "gn", vim.lsp.buf.rename) +-- map("n", "ga", vim.lsp.buf.code_action) +-- map("n", "gf", function() vim.lsp.buf.format({ async = true }) end) +-- map("n", "go", vim.diagnostic.open_float) +-- map("n", "go", ":call utils#ToggleDiagnosticsOpenFloat() | :echom ('Toggle Diagnostics Float open/close...') | :sl! | echo ('')") +-- map("n", "gq", vim.diagnostic.setloclist) +-- map("n", "[d", vim.diagnostic.goto_prev) +-- map("n", "]d", vim.diagnostic.goto_next) +-- map("n", "gs", vim.lsp.buf.document_symbol) +-- map("n", "gw", vim.lsp.buf.workspace_symbol) +-- map("n", "wa", vim.lsp.buf.add_workspace_folder) +-- map("n", "wr", vim.lsp.buf.remove_workspace_folder) +-- map("n", "wl", function() +-- print(vim.inspect(vim.lsp.buf.list_workspace_folders())) +-- end) +-- end, +--}) + +---- LSP Global Keymaps (available in all buffers) +--map("n", "[d", vim.diagnostic.goto_prev, { desc = "LSP: Previous Diagnostic" }) +--map("n", "]d", vim.diagnostic.goto_next, { desc = "LSP: Next Diagnostic" }) +--map("n", "go", vim.diagnostic.open_float, { desc = "LSP: Open Diagnostic Float" }) +-- +---- LSP Buffer-local keymaps function (to be called from LSP on_attach) +--_G.setup_lsp_keymaps = function(bufnr) +-- local bmap = function(mode, l, r, opts) +-- opts = opts or {} +-- opts.silent = true +-- opts.noremap = true +-- opts.buffer = bufnr +-- vim.keymap.set(mode, l, r, opts) +-- end +-- +-- bmap("n", "K", vim.lsp.buf.hover, { desc = "LSP: Hover Documentation" }) +-- bmap("n", "gd", vim.lsp.buf.definition, { desc = "LSP: Go to Definition" }) +-- bmap("n", "gD", vim.lsp.buf.declaration, { desc = "LSP: Go to Declaration" }) +-- bmap("n", "gi", vim.lsp.buf.implementation, { desc = "LSP: Go to Implementation" }) +-- bmap("n", "gt", vim.lsp.buf.type_definition, { desc = "LSP: Go to Type Definition" }) +-- bmap("n", "gr", vim.lsp.buf.references, { desc = "LSP: Go to References" }) +-- bmap("n", "gn", vim.lsp.buf.rename, { desc = "LSP: Rename" }) +-- bmap("n", "ga", vim.lsp.buf.code_action, { desc = "LSP: Code Action" }) +-- bmap("n", "k", vim.lsp.buf.signature_help, { desc = "LSP: Signature Help" }) +-- bmap("n", "gs", vim.lsp.buf.document_symbol, { desc = "LSP: Document Symbols" }) +--end + +-- LSP Global Keymaps (available in all buffers) +map("n", "[d", vim.diagnostic.goto_prev, { desc = "LSP: Previous Diagnostic" }) +map("n", "]d", vim.diagnostic.goto_next, { desc = "LSP: Next Diagnostic" }) +map("n", "go", vim.diagnostic.open_float, { desc = "LSP: Open Diagnostic Float" }) +map("n", "go", ":call utils#ToggleDiagnosticsOpenFloat() | :echom ('Toggle Diagnostics Float open/close...') | :sl! | echo ('')") + +-- LSP Buffer-local keymaps function (to be called from LSP on_attach) +_G.setup_lsp_keymaps = function(bufnr) + local bmap = function(mode, l, r, opts) + opts = opts or {} + opts.silent = true + opts.noremap = true + opts.buffer = bufnr + vim.keymap.set(mode, l, r, opts) + end + + -- Your preferred keybindings + bmap("n", "K", function() + vim.lsp.buf.hover { border = "single", max_height = 25, max_width = 120 } + end, { desc = "LSP: Hover Documentation" }) + + bmap("n", "gd", function() + vim.lsp.buf.definition { + on_list = function(options) + -- Custom logic to avoid showing multiple definitions for Lua patterns like: + -- `local M.my_fn_name = function() ... end` + local unique_defs = {} + local def_loc_hash = {} + + for _, def_location in pairs(options.items) do + local hash_key = def_location.filename .. def_location.lnum + if not def_loc_hash[hash_key] then + def_loc_hash[hash_key] = true + table.insert(unique_defs, def_location) + end + end + + options.items = unique_defs + vim.fn.setloclist(0, {}, " ", options) + + -- Open location list if multiple definitions, otherwise jump directly + if #options.items > 1 then + vim.cmd.lopen() + else + vim.cmd([[silent! lfirst]]) + end + end, + } + end, { desc = "LSP: Go to Definition" }) + + bmap("n", "", vim.lsp.buf.definition, { desc = "LSP: Go to Definition (Alt)" }) + bmap("n", "gD", vim.lsp.buf.declaration, { desc = "LSP: Go to Declaration" }) + bmap("n", "gi", vim.lsp.buf.implementation, { desc = "LSP: Go to Implementation" }) + bmap("n", "gt", vim.lsp.buf.type_definition, { desc = "LSP: Go to Type Definition" }) + bmap("n", "gr", vim.lsp.buf.references, { desc = "LSP: Go to References" }) + bmap("n", "gn", vim.lsp.buf.rename, { desc = "LSP: Rename" }) + bmap("n", "rn", vim.lsp.buf.rename, { desc = "LSP: Rename (Alt)" }) + bmap("n", "ga", vim.lsp.buf.code_action, { desc = "LSP: Code Action" }) + bmap("n", "ca", vim.lsp.buf.code_action, { desc = "LSP: Code Action (Alt)" }) + bmap("n", "k", vim.lsp.buf.signature_help, { desc = "LSP: Signature Help" }) + bmap("n", "", vim.lsp.buf.signature_help, { desc = "LSP: Signature Help (Alt)" }) + bmap("n", "gs", vim.lsp.buf.document_symbol, { desc = "LSP: Document Symbols" }) + + -- Workspace folder management + bmap("n", "wa", vim.lsp.buf.add_workspace_folder, { desc = "LSP: Add Workspace Folder" }) + bmap("n", "wr", vim.lsp.buf.remove_workspace_folder, { desc = "LSP: Remove Workspace Folder" }) + bmap("n", "wl", function() + vim.print(vim.lsp.buf.list_workspace_folders()) + end, { desc = "LSP: List Workspace Folders" }) +end ---------------- Plugin Operations ---------------- -- Packer @@ -250,12 +575,6 @@ map("n", "Ps", "PackerSync") map("n", "PS", "PackerStatus") map("n", "Pu", "PackerUpdate") --- Tmux navigation (aserowy/tmux.nvim) -map("n", "", "NavigatorLeft") -map("n", "", "NavigatorRight") -map("n", "", "NavigatorUp") -map("n", "", "NavigatorDown") - -- ToggleTerm map({ "n", "t" }, "tt", "ToggleTerm") map({ "n", "t" }, "th", "lua Horizontal_term_toggle()") @@ -270,9 +589,9 @@ map("n", "tg", "lua Gh_dash()") map("n", "gs", vim.cmd.Git) map("n", "ga", ":Git add %:p") --map("n", "gs", ":Gstatus") -map("n", "gc", ":Gcommit -v -q") +--map("n", "gc", ":Gcommit -v -q") map("n", "gt", ":Gcommit -v -q %:p") ---map("n", "gd", ":Gdiff") +map("n", "gd", ":Gdiff") map("n", "ge", ":Gedit") --map("n", "gr", ":Gread") map("n", "gw", ":Gwrite") @@ -287,42 +606,128 @@ map("n", "gm", ":Gmove") --map("n", "gpl", ":Dispatch! git pull") -- Telescope -map("n", "ff", ":cd %:p:h:pwdlua require('telescope.builtin').find_files()") -- find files with hidden option +-- Safe load of your custom Telescope module +-- This initial pcall for "plugins.telescope" is fine because it just checks if YOUR module is there. +-- The actual checks for Telescope's core modules happen *inside* your wrapper functions when called. +local telescope_ok, telescope_module = pcall(require, "plugins.telescope") + +if telescope_ok and telescope_module then + + -- Direct function calls from your plugins.telescope module + -- M.safe_find_files handles its own internal `builtin` check + map("n", "ff", telescope_module.safe_find_files, { desc = "Find files" }) + + -- For `find all files`, use your `safe_telescope_builtin` wrapper + -- You need to wrap it in a function to pass the options correctly. + map("n", "f.", function() + telescope_module.safe_telescope_builtin("find_files")({ hidden = true, no_ignore = true }) + end, { desc = "Find all files" }) + + + --- + --- Built-in Telescope functions + --- Note: safe_telescope_builtin returns a function, so you map directly to it. + --- + map("n", "fg", function() telescope_module.safe_telescope_builtin("live_grep")() end, { desc = "Live grep" }) + map("n", "fb", function() telescope_module.safe_telescope_builtin("buffers")() end, { desc = "Find buffers" }) + map("n", "fh", function() telescope_module.safe_telescope_builtin("help_tags")() end, { desc = "Help tags" }) + map("n", "fc", function() telescope_module.safe_telescope_builtin("commands")() end, { desc = "Commands" }) + map("n", "fd", function() telescope_module.safe_telescope_builtin("diagnostics")() end, { desc = "Diagnostics" }) + map("n", "fk", function() telescope_module.safe_telescope_builtin("keymaps")() end, { desc = "Keymaps" }) + map("n", "fr", function() telescope_module.safe_telescope_builtin("registers")() end, { desc = "Registers" }) + map("n", "ffc", function() telescope_module.safe_telescope_builtin("current_buffer_fuzzy_find")() end, { desc = "Current buffer fuzzy find" }) + -- Corrected the previous `fp` mapping that pointed to `pickers` + map("n", "fp", function() telescope_module.safe_telescope_builtin("oldfiles")() end, { desc = "Recently opened files" }) + + + --- + --- Telescope Extension functions + --- Note: safe_telescope_extension returns a function, so you map directly to it. + --- + map("n", "cf", function() telescope_module.safe_telescope_extension("changed_files", "changed_files")() end, { desc = "Changed files" }) + map("n", "fm", function() telescope_module.safe_telescope_extension("media_files", "media_files")() end, { desc = "Media files" }) + map("n", "fi", function() telescope_module.safe_telescope_extension("notify", "notify")() end, { desc = "Notifications" }) + map("n", "fs", function() telescope_module.safe_telescope_extension("session-lens", "search_session")() end, { desc = "Search sessions" }) + map("n", "frf", function() telescope_module.safe_telescope_extension("recent_files", "pick")() end, { desc = "Recent files" }) + map("n", "f/", function() telescope_module.safe_telescope_extension("file_browser", "file_browser")() end, { desc = "File browser" }) + + + --- + --- Custom functions defined in plugins.telescope.lua + --- Note: safe_telescope_call returns a function, so you map directly to it. + --- (These were already correct as safe_telescope_call returns a callable function) + --- + map("n", "ffd", telescope_module.safe_telescope_call("plugins.telescope", "find_dirs"), { desc = "Find directories" }) + map("n", "ff.", telescope_module.safe_telescope_call("plugins.telescope", "find_configs"), { desc = "Find configs" }) + map("n", "ffs", telescope_module.safe_telescope_call("plugins.telescope", "find_scripts"), { desc = "Find scripts" }) + map("n", "ffw", telescope_module.safe_telescope_call("plugins.telescope", "find_projects"), { desc = "Find projects" }) + map("n", "ffB", telescope_module.safe_telescope_call("plugins.telescope", "find_books"), { desc = "Find books" }) + map("n", "ffn", telescope_module.safe_telescope_call("plugins.telescope", "find_notes"), { desc = "Find notes" }) + map("n", "fgn", telescope_module.safe_telescope_call("plugins.telescope", "grep_notes"), { desc = "Grep notes" }) + map("n", "fpp", telescope_module.safe_telescope_call("plugins.telescope", "find_private"), { desc = "Find private notes" }) + map("n", "fgc", telescope_module.safe_telescope_call("plugins.telescope", "grep_current_dir"), { desc = "Grep current directory" }) + +end +---- Fallback keymaps when telescope is not available +--map("n", "ff", function() +-- local file = vim.fn.input("Open file: ", "", "file") +-- if file ~= "" then +-- vim.cmd("edit " .. file) +-- end +--end, { desc = "Find files (fallback)" }) + +---- You can add other basic fallbacks here +--map("n", "fg", function() +-- vim.notify("Live grep requires telescope plugin", vim.log.levels.WARN) +--end, { desc = "Live grep (unavailable)" }) +----end + + map("n", "fF", ":cd %:p:h:pwdlua require('user.mods').findFilesInCwd()", - { noremap = true, silent = true, desc = "Find files in cwd" }) -map("n", "f.", function() - require("telescope.builtin").find_files({ hidden = true, no_ignore = true }) -end) -- find all files -map("n", "fg", "lua require('telescope.builtin').live_grep()") -map("n", "fb", "lua require('telescope.builtin').buffers()") -map("n", "fh", "lua require('telescope.builtin').help_tags()") -map("n", "fc", "lua require('telescope.builtin').commands()") -map("n", "cf", "Telescope changed_files") -map("n", "fp", "Telescope pickers") -map("n", "fd", "lua require('telescope.builtin').diagnostics()") -map("n", "fk", "lua require('telescope.builtin').keymaps()") -map("n", "fr", "lua require('telescope.builtin').registers({})") -- registers picker -map("n", "fm", "lua require('telescope').extensions.media_files.media_files({})") -- find media files -map("n", "fi", "lua require('telescope').extensions.notify.notify({})") -- find notifications -map("n", "fs", 'lua require("session-lens").search_session()') -map("n", "ffd", [[lua require'plugins.telescope'.find_dirs()]]) -- find dies -map("n", "ff.", [[lua require'plugins.telescope'.find_configs()]]) -- find configs -map("n", "ffs", [[lua require'plugins.telescope'.find_scripts()]]) -- find scripts -map("n", "ffw", [[lua require'plugins.telescope'.find_projects()]]) -- find projects -map("n", "ffb", [[lua require'plugins.telescope'.find_books()]]) -- find books -map("n", "ffn", [[lua require'plugins.telescope'.find_notes()]]) -- find notes -map("n", "fgn", [[lua require'plugins.telescope'.grep_notes()]]) -- search notes -map("n", "frf", "lua require('telescope').extensions.recent_files.pick()") -map("n", "ffc", "lua require('telescope.builtin').current_buffer_fuzzy_find()") -map("n", "f/", "lua require('telescope').extensions.file_browser.file_browser()") ---map("n", "f/", "lua require('plugins.telescope').curbuf()") -- find files with hidden option --- Map a shortcut to open the picker. +{ noremap = true, silent = true, desc = "Find files in cwd" }) -- FZF -map("n", "fz", "lua require('fzf-lua').files()") +map("n", "fz", function() + local ok, fzf_lua = pcall(require, "fzf-lua") + if ok then + fzf_lua.files() -- no config, just open + else + local handle = io.popen("find . -type f | fzf") + if handle then + local result = handle:read("*a") + handle:close() + result = result:gsub("\n", "") + if result ~= "" then + vim.cmd("edit " .. vim.fn.fnameescape(result)) + end + else + vim.notify("fzf not found or failed to run", vim.log.levels.ERROR) + end + end +end, { desc = "FZF file picker (fzf-lua or fallback)" }) + +map("n", "gA", ":FzfLua lsp_code_actions") -- Nvim-tree -map("n", "e", "Rooter:NvimTreeToggle", {}) +local function safe_nvim_tree_toggle() + local ok_tree, tree_api = pcall(require, "nvim-tree.api") + if ok_tree then + pcall(vim.cmd, "Rooter") -- silently run Rooter if available + tree_api.tree.toggle() + else + -- Fallback to netrw + local cur_buf = vim.api.nvim_get_current_buf() + local ft = vim.api.nvim_get_option_value("filetype", { buf = cur_buf }) + + if ft == "netrw" then + vim.cmd("close") + else + vim.cmd("Lexplore") + end + end +end + +map("n", "f", safe_nvim_tree_toggle, { desc = "Toggle file explorer" }) -- Undotree map("n", "u", vim.cmd.UndotreeToggle) @@ -338,29 +743,77 @@ map("n", "ww", "lua require('user.mods').Toggle_autopairs()") map("n", "zm", "ZenMode | :echom ('Zen Mode') | :sl! | echo ('')") -- Vim-rooter -map("n", "ro", "Rooter | :echom ('cd to root/project directory') | :sl! | echo ('')", term_opts) +local function safe_project_root() + if vim.fn.exists(":Rooter") == 2 then + vim.cmd("Rooter") + else + vim.cmd("cd %:p:h") + end +end +vim.keymap.set("n", "ro", safe_project_root, { desc = "Project root" }) -- Trouble (UI to show diagnostics) -map("n", "t", ":cd %:p:h:pwdTroubleToggle") -map("n", "tw", ":cd %:p:h:pwdTroubleToggle workspace_diagnostics") -map("n", "td", ":cd %:p:h:pwdTroubleToggle document_diagnostics") -map("n", "tq", ":cd %:p:h:pwdTroubleToggle quickfix") -map("n", "tl", ":cd %:p:h:pwdTroubleToggle loclist") -map("n", "gR", "TroubleToggle lsp_references") +local function safe_trouble_toggle(view, opts) + local ok, _ = pcall(require, "trouble") + if ok then + local cmd = "Trouble" + if view then + cmd = cmd .. " " .. view .. " toggle" + if opts then + cmd = cmd .. " " .. opts + end + else + cmd = cmd .. " diagnostics toggle" + end + vim.cmd(cmd) + else + vim.cmd("copen") + end +end + +-- Replace 'map' with 'vim.keymap.set' if not already a global alias +vim.keymap.set("n", "t", function() + safe_trouble_toggle() +end, { desc = "Diagnostics (Workspace)" }) + +vim.keymap.set("n", "tw", function() + vim.cmd("cd %:p:h | pwd") + safe_trouble_toggle("diagnostics") +end, { desc = "Diagnostics (Workspace)" }) + +vim.keymap.set("n", "td", function() + vim.cmd("cd %:p:h | pwd") + safe_trouble_toggle("diagnostics", "filter.buf=0") +end, { desc = "Diagnostics (Buffer)" }) + +vim.keymap.set("n", "tq", function() + vim.cmd("cd %:p:h | pwd") + safe_trouble_toggle("qflist") +end, { desc = "Quickfix List" }) + +vim.keymap.set("n", "tl", function() + vim.cmd("cd %:p:h | pwd") + safe_trouble_toggle("loclist") +end, { desc = "Location List" }) + +vim.keymap.set("n", "gR", function() + safe_trouble_toggle("lsp") +end, { desc = "LSP References/Definitions" }) -- Null-ls -map("n", "ls", "NullLsToggle") +map("n", "ls", ':lua require("null-ls").toggle({})') + -- Replacer map("n", "qr", ':lua require("replacer").run()') -- Quickfix map("n", "q", function() - if vim.fn.getqflist({ winid = 0 }).winid ~= 0 then - require("plugins.quickfix").close() - else - require("plugins.quickfix").open() - end + if vim.fn.getqflist({ winid = 0 }).winid ~= 0 then + require("plugins.quickfix").close() + else + require("plugins.quickfix").open() + end end, { desc = "Toggle quickfix window" }) -- Move to the next and previous item in the quickfixlist @@ -375,17 +828,17 @@ local dap_ok, dap = pcall(require, "dap") local dap_ui_ok, ui = pcall(require, "dapui") if not (dap_ok and dap_ui_ok) then - require("notify")("nvim-dap or dap-ui not installed!", "warning") - return + --require("notify")("nvim-dap or dap-ui not installed!", "warning") + return end vim.fn.sign_define("DapBreakpoint", { text = "🐞" }) -- Start debugging session map("n", "ds", function() - dap.continue() - ui.toggle({}) - vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("=", false, true, true), "n", false) -- Spaces buffers evenly + dap.continue() + ui.toggle({}) + vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("=", false, true, true), "n", false) -- Spaces buffers evenly end) -- Set breakpoints, get variable values, step into/out of functions, etc. @@ -394,31 +847,34 @@ map("n", "dC", dap.continue) -- map("n", "dt", dap.terminate) map("n", "dt", ui.toggle) map("n", "dd", function() - dap.disconnect({ terminateDebuggee = true }) + dap.disconnect({ terminateDebuggee = true }) end) map("n", "dn", dap.step_over) map("n", "di", dap.step_into) map("n", "do", dap.step_out) map("n", "db", dap.toggle_breakpoint) map("n", "dB", function() - dap.clear_breakpoints() - require("notify")("Breakpoints cleared", "warn") + dap.clear_breakpoints() + require("notify")("Breakpoints cleared", "warn") +end) +map("n", "dl", function() + local ok, dap_widgets = pcall(require, "dap.ui.widgets") + if ok then dap_widgets.hover() end end) -map("n", "dl", require("dap.ui.widgets").hover) map("n", "de", function() - require("dapui").float_element() + require("dapui").float_element() end, { desc = "Open Element" }) map("n", "dq", function() - require("dapui").close() - require("dap").repl.close() - local session = require("dap").session() - if session then - require("dap").terminate() - end - require("nvim-dap-virtual-text").refresh() + require("dapui").close() + require("dap").repl.close() + local session = require("dap").session() + if session then + require("dap").terminate() + end + require("nvim-dap-virtual-text").refresh() end, { desc = "Terminate Debug" }) map("n", "dc", function() - require("telescope").extensions.dap.commands() + require("telescope").extensions.dap.commands() end, { desc = "DAP-Telescope: Commands" }) --vim.keymap.set("n", "B", ":lua require'dap'.set_breakpoint(vim.fn.input('Breakpoint condition: '))") --vim.keymap.set("v", "B", ":lua require'dap'.set_breakpoint(vim.fn.input('Breakpoint condition: '))") @@ -459,10 +915,10 @@ map("n", "rr", 'lua require("user.mods").toggleCodeRunner()') -- Run executable file map("n", "rx", - ":lua require('user.mods').RunCurrentFile():echom 'Running executable file...':sl!:echo ''") +":lua require('user.mods').RunCurrentFile():echom 'Running executable file...':sl!:echo ''") --- Close all floating windows -map({ "n", "t", "c" }, "w", "CloseFloatingWindows") +-- Set Files to current location as dir +map({ "n" }, "cf", "e %:h") -- Vimtex map("n", "lc", ":VimtexCompile") -- cgit v1.2.3