-- Keymaps are automatically loaded on the VeryLazy event -- Default keymaps that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/keymaps.lua -- Add any additional keymaps here -- KEYMAPS SPIDER vim.keymap.set({ "n", "o", "x" }, "w", "lua require('spider').motion('w')", { desc = "Spider-w" }) vim.keymap.set({ "n", "o", "x" }, "e", "lua require('spider').motion('e')", { desc = "Spider-e" }) vim.keymap.set({ "n", "o", "x" }, "b", "lua require('spider').motion('b')", { desc = "Spider-b" }) vim.keymap.set({ "n", "o", "x" }, "C-D", "", { desc = "page down" }) local bm = require("bookmarks") local map = vim.keymap.set map("n", "mm", bm.bookmark_toggle, { desc = "Toggle bookmark" }) map("n", "mi", bm.bookmark_ann, { desc = "Edit annotation" }) map("n", "mc", bm.bookmark_clean, { desc = "Clean marks" }) map("n", "mn", bm.bookmark_next, { desc = "Next mark" }) map("n", "mp", bm.bookmark_prev, { desc = "Prev mark" }) map("n", "ml", "Telescope bookmarks list", { desc = "List marks" }) map("n", "mx", bm.bookmark_clear_all, { desc = "Clear all bookmarks" }) map("n", "srf", function() local file_path = vim.api.nvim_buf_get_name(0) print(file_path) require("grug-far").open({ transient = true, prefills = { paths = file_path, }, }) end, { desc = "Search n replace in file" }) map("n", "ff", "FzfLua", { desc = "FZF commands" }) -- tab to accept copilot suggestion map("i", "", function() require("copilot.suggestion").accept() end, { desc = "Accept Copilot suggestion" }) -- -- Terminal Mappings -- map("t", "", "close", { desc = "Hide Terminal" }) -- map("t", "", "close", { desc = "which_key_ignore" }) map("n", "qw", "wq", { desc = "save & quit" }) vim.keymap.set("n", "\\", function() vim.cmd("!tmux-td") end, { desc = "Toggle TD CLI floating terminal and run tmux-td" }) -- vim.keymap.set("t", "", "ToggleTerm", { noremap = true, silent = true }) -- -- local harpoon = require("harpoon") vim.keymap.set("n", "H", function() harpoon:list("file_with_line"):add() end, { desc = "Harpoon add" }) vim.keymap.set("n", "h", function() harpoon.ui:toggle_quick_menu(harpoon:list("file_with_line")) end, { desc = "Harpoon list" }) -- DIFFVIEW local function diffOpenWithInput() local user_input = vim.fn.input("Revision to Open: ") vim.cmd("DiffviewOpen " .. user_input) end local function diffOpenFileHistory() local user_input = vim.fn.input("Files to Open: ") vim.cmd("DiffviewFileHistory" .. user_input) end local function command(cmd) return function() vim.cmd(cmd) end end require("which-key").add({ { "gvf", diffOpenFileHistory, desc = "Open DiffView on Files" }, { "gvt", command("DiffviewToggleFiles"), desc = "toggle diffviewfiles" }, { "gvc", command("DiffviewClose"), desc = "Open DiffView on Files" }, { "gvh", function() print("gvf with . opens commit wise history of entire codebase.") print("gvf with % opens commit wise history of current file.") print("gvf with opens commit wise history of that file.") print("gvo with HEAD opens diff of latest commit.") print("gvo with HEAD~3 opens diff of last 3 commits.") print("gvo with master..HEAD opens changes of your feature branch.") end, desc = "gvo help", }, { "gvo", diffOpenWithInput, desc = "Open DiffView" }, }) -- -- vim.api.nvim_set_keymap("c", "", "", { noremap = true, silent = true }) vim.api.nvim_set_keymap("c", "", "", { noremap = true, silent = true }) print("dupsko") -- exec lua map("v", "ce", "'<,'>lua", { desc = "exec Lua" }) -- GP map("n", "agf", "GpChatFinder", { desc = "gp chat finder" }) map("n", "agt", "GpChatToggle", { desc = "gp chat toggle" }) map("n", "agn", "GpChatNew", { desc = "gp chat new " }) map("n", "agr", "GpChatRespond", { desc = "gp chat respond" }) -- JSON FORMAT map("n", "cjf", "%!jq .", { desc = "Json Format" }) vim.keymap.set("n", "s", "(leap-anywhere)") local function jump_to_file_line() local line = vim.api.nvim_get_current_line() local file, linenum = string.match(line, "([^:%s]+):(%d+)") if file and linenum then vim.cmd("edit " .. file) vim.cmd(linenum) else print("No valid file:line pattern found on the current line.") end end -- Map it to j (typically \j) vim.keymap.set("n", "j", jump_to_file_line, { noremap = true, silent = true, desc = "Jump to file:line" }) -- Function to insert TODO comment with task number function insert_todo_comment() -- Get the current branch name local handle = io.popen("git branch --show-current 2>/dev/null") local branch if handle then branch = handle:read("*a"):match("%S+") handle:close() end -- Extract the task number (e.g., HS-4798) from the branch name local task_number = branch and branch:match("HS%-%d+") -- If a task number is found, insert the TODO comment if task_number then local todo_comment = "# TODO: " .. task_number vim.api.nvim_put({ todo_comment }, "l", true, true) else print("Task number not found in branch name!") end end -- Keybind for inserting TODO comment vim.api.nvim_set_keymap("n", "t", "lua insert_todo_comment()", { noremap = true, silent = true }) local function git_output(args) local output = vim.fn.system(args) if vim.v.shell_error ~= 0 then return nil end return vim.split(output, "\n", { trimempty = true }) end local function branch_todos_base() if vim.g.branch_todos_base then return vim.g.branch_todos_base end for _, ref in ipairs({ "origin/main", "origin/master", "main", "master" }) do if git_output({ "git", "rev-parse", "--verify", ref }) then return ref end end end local function branch_todos_entries() local base = branch_todos_base() if not base then return { "No git base found. Set vim.g.branch_todos_base." } end local merge_base = git_output({ "git", "merge-base", base, "HEAD" }) if not merge_base or not merge_base[1] then return { "Could not find merge-base against " .. base .. "." } end local lines = git_output({ "git", "diff", "--unified=0", merge_base[1] }) if not lines then return { "Could not read git diff against " .. base .. "." } end local added_lines = {} local file local new_line local todo_keywords = { "TODO", "FIXME", "HACK", "XXX", "BUG", "BUGS" } for _, line in ipairs(lines) do local diff_file = line:match("^%+%+%+ b/(.+)$") if diff_file then file = diff_file new_line = nil else local hunk_start = line:match("^@@ %-%d+,?%d* %+(%d+),?%d* @@") if hunk_start then new_line = tonumber(hunk_start) elseif new_line and line:sub(1, 1) == "+" and not line:match("^%+%+%+") then local text = line:sub(2) if file then table.insert(added_lines, { file = file, line = new_line, text = text }) end new_line = new_line + 1 elseif new_line and line:sub(1, 1) ~= "-" then new_line = new_line + 1 end end end local function has_todo_keyword(text) local upper_text = text:upper() for _, keyword in ipairs(todo_keywords) do local start = 1 while true do local match_start, match_end = upper_text:find(keyword, start, true) if not match_start then break end local before = match_start > 1 and upper_text:sub(match_start - 1, match_start - 1) or "" local after = match_end < #upper_text and upper_text:sub(match_end + 1, match_end + 1) or "" if not before:match("[%w_]") and not after:match("[%w_]") then return true end start = match_end + 1 end end return false end local function list_depth_delta(text) local _, opens = text:gsub("%[", "") local _, closes = text:gsub("%]", "") return opens - closes end local entries = {} local index = 1 while index <= #added_lines do local item = added_lines[index] if has_todo_keyword(item.text) then table.insert(entries, string.format("%s:%d", item.file, item.line)) table.insert(entries, item.text) if item.text:lower():match('todo:%s*"""') and not item.text:match('""".*"""') then index = index + 1 while index <= #added_lines do local next_item = added_lines[index] if next_item.file ~= item.file then break end table.insert(entries, next_item.text) if next_item.text:find('"""', 1, true) then break end index = index + 1 end elseif item.text:match("[=:]%s*%[") and list_depth_delta(item.text) > 0 then local depth = list_depth_delta(item.text) index = index + 1 while index <= #added_lines do local next_item = added_lines[index] if next_item.file ~= item.file then break end table.insert(entries, next_item.text) depth = depth + list_depth_delta(next_item.text) if depth <= 0 then break end index = index + 1 end elseif item.text:match("^%s*#") then index = index + 1 while index <= #added_lines do local next_item = added_lines[index] if next_item.file ~= item.file or not next_item.text:match("^%s*#") then break end table.insert(entries, next_item.text) index = index + 1 end index = index - 1 end table.insert(entries, "") end index = index + 1 end if #entries == 0 then return { "No TODOs added on this branch against " .. base .. "." } end return entries end local function jump_to_branch_todo() local line = vim.api.nvim_get_current_line() local file, linenum = line:match("([^:%s]+):(%d+)") if not file then local cursor = vim.api.nvim_win_get_cursor(0) for row = cursor[1] - 1, 1, -1 do local previous_line = vim.api.nvim_buf_get_lines(0, row - 1, row, false)[1] or "" file, linenum = previous_line:match("([^:%s]+):(%d+)") if file then break end end end if file and linenum then local current_win = vim.api.nvim_get_current_win() vim.cmd("wincmd h") if current_win == vim.api.nvim_get_current_win() then vim.api.nvim_set_current_win(current_win) end vim.cmd("edit " .. vim.fn.fnameescape(file)) vim.api.nvim_win_set_cursor(0, { tonumber(linenum), 0 }) if vim.api.nvim_win_is_valid(current_win) and current_win ~= vim.api.nvim_get_current_win() then vim.api.nvim_set_current_win(current_win) end end end local function refresh_branch_todos(buf) local cursor = vim.api.nvim_win_get_cursor(0) vim.bo[buf].modifiable = true vim.api.nvim_buf_set_lines(buf, 0, -1, false, branch_todos_entries()) vim.bo[buf].modifiable = false local line_count = vim.api.nvim_buf_line_count(buf) vim.api.nvim_win_set_cursor(0, { math.min(cursor[1], line_count), cursor[2] }) end local function open_branch_todos() local name = "branch-todos" local buf = vim.fn.bufnr(name) if buf == -1 then buf = vim.api.nvim_create_buf(true, false) vim.api.nvim_buf_set_name(buf, name) end vim.api.nvim_set_current_buf(buf) vim.bo[buf].buftype = "nofile" vim.bo[buf].bufhidden = "hide" vim.bo[buf].swapfile = false vim.bo[buf].filetype = "branch-todos" refresh_branch_todos(buf) vim.keymap.set("n", "", jump_to_branch_todo, { buffer = buf, desc = "Jump to branch TODO" }) vim.keymap.set("n", "r", function() refresh_branch_todos(buf) end, { buffer = buf, desc = "Refresh branch TODOs" }) vim.keymap.set("n", "q", "bdelete", { buffer = buf, desc = "Close branch TODOs" }) end vim.api.nvim_create_user_command("BranchTodos", open_branch_todos, {}) vim.keymap.set("n", "xb", open_branch_todos, { desc = "Branch TODOs" }) -- floating NOTES function open_notes() local notes_file = vim.env.HOME .. "/git/notes/todo.md" -- Path to your notes file -- Check if the file exists, create it if not if vim.fn.filereadable(notes_file) == 0 then vim.fn.writefile({}, notes_file) -- Create an empty file end -- Create a buffer linked to the notes file local buf = vim.fn.bufadd(notes_file) vim.fn.bufload(buf) -- Configure floating window size and position local width = math.floor(vim.o.columns * 0.8) -- 80% of the screen width local height = math.floor(vim.o.lines * 0.8) -- 80% of the screen height local row = math.floor((vim.o.lines - height) / 2) -- Center the window vertically local col = math.floor((vim.o.columns - width) / 2) -- Center the window horizontally -- Create the window local win = vim.api.nvim_open_win(buf, true, { relative = "editor", width = width, height = height, row = row, col = col, style = "minimal", border = "rounded", }) -- Enable saving and other standard buffer options vim.api.nvim_buf_set_option(buf, "modifiable", true) vim.api.nvim_buf_set_option(buf, "buftype", "") vim.api.nvim_buf_set_option(buf, "filetype", "markdown") -- vim.api.nvim_buf_set_option(buf, "fil", "text") -- Scroll to the end of the file local last_line = vim.api.nvim_buf_line_count(buf) vim.api.nvim_win_set_cursor(win, { last_line, 0 }) -- Close the popup with 'q' vim.api.nvim_buf_set_keymap( buf, "n", "q", "lua vim.api.nvim_win_close(" .. win .. ", true)", { noremap = true, silent = true } ) end -- Keybind for opening the notes file in a floating window vim.api.nvim_set_keymap("n", "n", "lua open_notes()", { noremap = false, silent = true }) -- Define the function to start the timer function start_timer(duration) local timer = vim.loop.new_timer() timer:start( duration * 60000, 0, vim.schedule_wrap(function() vim.api.nvim_out_write("Time's up!\n") os.execute('osascript -e "display notification \\"Times up\\" with title \\"Timer"" ') end) ) end -- Define the function to prompt the user for the desired time using fzf-lua function choose_timer() local times = { 1, 3, 5, 10 } require("fzf-lua").fzf_exec(times, { prompt = "Choose timer duration (minutes): ", actions = { ["default"] = function(selected) local duration = tonumber(selected[1]) if duration then start_timer(duration) else vim.api.nvim_out_write("Invalid choice. Please choose a valid duration.\n") end end, }, }) end vim.api.nvim_set_keymap("n", "T", "lua choose_timer()", { noremap = true, silent = true }) -- Remap arrow keys to hjkl in Normal and Visual modes vim.keymap.set({ "n", "v" }, "", "k", { noremap = true, silent = true }) vim.keymap.set({ "n", "v" }, "", "j", { noremap = true, silent = true }) vim.keymap.set({ "n", "v" }, "", "h", { noremap = true, silent = true }) vim.keymap.set({ "n", "v" }, "", "l", { noremap = true, silent = true }) vim.keymap.set({ "n", "v" }, "", "k", { noremap = true, silent = true }) vim.keymap.set({ "n", "v" }, "", "j", { noremap = true, silent = true }) vim.keymap.set({ "n", "v" }, "", "h", { noremap = true, silent = true }) vim.keymap.set({ "n", "v" }, "", "l", { noremap = true, silent = true }) -- map leader u v c to CsvViewEnable display_mode=border with description `CSV View (commas)` vim.keymap.set("n", "uvc", "CsvViewEnable display_mode=border", { desc = "CSV View (commas)" }) -- map leader u v t to CsvViewEnable delimiter=\t display_mode=border with description `CSV View (tabs)` vim.keymap.set( "n", "uvt", "CsvViewEnable delimiter=\\t display_mode=border", { desc = "CSV View (tabs)" } ) -- map leader u v d to CsvViewDisable with description `CSV View Disable` vim.keymap.set("n", "uvd", "CsvViewDisable", { desc = "CSV View Disable" })