chore: remove local/unused plugins and refactor core configs

- Remove locally-developed or rarely-used plugin packages (codetyper, curls, edgy, flash) to reduce maintenance surface, external deps, and startup cost; these were local/optional and caused complexity.
- Clean up stale/keymap docs and small duplicate or experimental files (keymaps/README.md, sudoku keymaps).
- Apply targeted refactors to core modules for readability, robustness, and to align Java/DAP/Copilot integrations with local environment.
- Removed plugin modules:
  - lua/cargdev/plugins/codetyper.lua (deleted)
  - lua/cargdev/plugins/curls.lua (deleted)
  - lua/cargdev/plugins/edgy.lua (deleted)
  - lua/cargdev/plugins/flash.lua (deleted)
  - Added .codetyper to .gitignore
- Java / JDTLS:
  - ftplugin/java.lua: pin jdtls java executable to JDK 25, switch to mac_arm config, enable LSP formatter and declare multiple runtimes (JavaSE-17, JavaSE-25).
- Notifications & startup UX:
  - lua/cargdev/core/function/notification_manager.lua: large refactor — use local aliases (api, cmd, loop, opt), improved docs, dashboard-aware handling, nvim-notify fallback, safer tracking and cleanup of notifications.
- Utilities & monitors:
  - lua/cargdev/core/function/performance_monitor.lua: use local references, better notify usage and docs.
  - lua/cargdev/core/function/project_commands.lua: add docs, use local api/fn/notify, clearer RunProject/DebugProject commands.
- Terminal helper:
  - lua/cargdev/core/function/openTerminal.lua: add module docs and small refactor to use local cmd/api aliases and expose keymap.
- Keymaps & docs:
  - Removed stale keymaps README (lua/cargdev/core/keymaps/README.md).
  - Reworked many keymap files: docstrings, renamed/moved mappings to avoid conflicts, moved DAP mappings into dap plugin config, removed/disabled experimental mappings (see files under lua/cargdev/core/keymaps/*).
  - Adjusted quick keybindings and prefixes to reduce overlaps.
- Plugins & integrations:
  - lua/cargdev/plugins/formatting.lua: disabled google-java-format fallback for java (prefer JDTLS).
  - lua/cargdev/plugins/dap.lua: added additional DAP configs (Bun launch, attach helper), moved/registered dap keymaps here.
  - lua/cargdev/plugins/copilot.lua: reorganized Copilot/Copilot-cmp/CopilotChat config and added copilot source to nvim-cmp.
  - lua/cargdev/plugins/nvim-cmp.lua: added copilot source and small formatting tweak.
This commit is contained in:
2026-02-10 12:17:36 -05:00
parent 832a664fa0
commit 06dbe4d892
34 changed files with 899 additions and 950 deletions

1
.gitignore vendored
View File

@@ -28,3 +28,4 @@ local.lua
*.coder.*
.coder/
.vscode/
.codetyper/

3
.luarc.json Normal file
View File

@@ -0,0 +1,3 @@
{
"Lua": { "diagnostics": { "globals": ["vim"] } }
}

View File

@@ -4,6 +4,9 @@ local project_name = vim.fn.fnamemodify(vim.fn.getcwd(), ":p:h:t")
local workspace_dir = workspace_path .. project_name
local keymap = vim.keymap.set
-- JDTLS requires JDK 21+ to run; use JDK 25 for the server process
local jdtls_java = "/opt/homebrew/Cellar/openjdk/25.0.2/libexec/openjdk.jdk/Contents/Home/bin/java"
local status, jdtls = pcall(require, "jdtls")
if not status then
@@ -44,7 +47,7 @@ end
local config = {
cmd = {
"java",
jdtls_java,
"-Declipse.application=org.eclipse.jdt.ls.core.id1",
"-Dosgi.bundles.defaultStartLevel=4",
"-Declipse.product=org.eclipse.jdt.ls.core.product",
@@ -60,7 +63,7 @@ local config = {
"-jar",
vim.fn.glob(home .. "/.local/share/nvim/mason/packages/jdtls/plugins/org.eclipse.equinox.launcher_*.jar"),
"-configuration",
home .. "/.local/share/nvim/mason/packages/jdtls/config_mac",
home .. "/.local/share/nvim/mason/packages/jdtls/config_mac_arm",
"-data",
workspace_dir,
},
@@ -85,7 +88,20 @@ local config = {
},
},
format = {
enabled = false,
enabled = true,
},
configuration = {
runtimes = {
{
name = "JavaSE-17",
path = "/opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home",
},
{
name = "JavaSE-25",
path = "/opt/homebrew/Cellar/openjdk/25.0.2/libexec/openjdk.jdk/Contents/Home",
default = true,
},
},
},
},
},

View File

@@ -1,5 +1,12 @@
-- Highlight .njk files as htmldjango for better templating syntax
vim.api.nvim_create_autocmd({"BufRead", "BufNewFile"}, {
--- Custom filetype detection for unsupported or ambiguous file extensions.
--- Registers autocmds that assign the correct filetype when buffers are
--- opened, enabling proper syntax highlighting and LSP support.
--- @module highlights
--- Set .njk (Nunjucks) files to use the htmldjango filetype,
--- which provides the closest built-in syntax support for
--- Nunjucks/Jinja-style template syntax (blocks, extends, includes).
vim.api.nvim_create_autocmd({ "BufRead", "BufNewFile" }, {
pattern = "*.njk",
callback = function()
vim.cmd("set filetype=htmldjango")

View File

@@ -1,13 +1,31 @@
-- Custom notification manager to handle overlapping and improve UX
--- Custom notification manager to handle overlapping and improve UX.
--- Provides a centralized notification system that prevents overlapping,
--- supports dashboard-aware notifications, and integrates with nvim-notify
--- when available, falling back to cmd echo otherwise.
--- @module notification_manager
local M = {}
local log = vim.log
local api = vim.api
local cmd = vim.cmd
local o = vim.o
local loop = vim.loop
local opt = vim.opt
local deferFn = vim.defer_fn
-- Track active notifications to prevent overlapping
--- List of currently displayed notifications (each entry has win, message, timestamp).
--- @type table[]
local active_notifications = {}
local notification_queue = {}
-- Function to show a notification without overlapping
--- Show a notification without overlapping existing ones.
--- Uses nvim-notify if available; otherwise falls back to echo.
--- Automatically detects the alpha dashboard and delegates to
--- `show_dashboard_notification` when appropriate.
--- @param message string The notification message to display.
--- @param level number|nil Log level from log.levels (default: INFO).
--- @param opts table|nil Optional overrides (timeout, title, render, position, etc.).
--- @return number|nil notification_id The nvim-notify notification id, or nil on fallback.
function M.show_notification(message, level, opts)
level = level or vim.log.levels.INFO
level = level or log.levels.INFO
opts = opts or {}
-- Default options
@@ -31,8 +49,8 @@ function M.show_notification(message, level, opts)
end
-- Check if we're in alpha dashboard
local current_buf = vim.api.nvim_get_current_buf()
local current_ft = vim.api.nvim_buf_get_option(current_buf, "filetype")
local current_buf = api.nvim_get_current_buf()
local current_ft = api.nvim_buf_get_option(current_buf, "filetype")
if current_ft == "alpha" then
-- If in dashboard, use a different approach
@@ -49,22 +67,22 @@ function M.show_notification(message, level, opts)
opts.on_open = function(win)
-- Calculate position to avoid overlapping with other notifications
local row = 2
local col = vim.o.columns - 60
local col = o.columns - 60
-- Adjust position if there are other notifications
for _, notif in ipairs(active_notifications) do
if notif.win and vim.api.nvim_win_is_valid(notif.win) then
if notif.win and api.nvim_win_is_valid(notif.win) then
row = row + 10 -- Stack notifications vertically
end
end
-- Ensure notification doesn't go off-screen
if row > vim.o.lines - 15 then
if row > o.lines - 15 then
row = 2
col = col - 20
end
vim.api.nvim_win_set_config(win, {
api.nvim_win_set_config(win, {
row = row,
col = col,
relative = "editor",
@@ -76,7 +94,7 @@ function M.show_notification(message, level, opts)
table.insert(active_notifications, {
win = win,
message = message,
timestamp = vim.loop.now(),
timestamp = loop.now(),
})
end
@@ -96,33 +114,38 @@ function M.show_notification(message, level, opts)
else
-- Fallback to echo instead of vim.notify to avoid circular dependency
local icon = "💬"
if level == vim.log.levels.ERROR then
if level == log.levels.ERROR then
icon = ""
elseif level == vim.log.levels.WARN then
elseif level == log.levels.WARN then
icon = "⚠️"
elseif level == vim.log.levels.INFO then
elseif level == log.levels.INFO then
icon = ""
end
-- Use echo for fallback notifications
vim.cmd("echo '" .. icon .. " " .. message .. "'")
cmd("echo '" .. icon .. " " .. message .. "'")
-- Clear message after a delay
vim.defer_fn(function()
vim.cmd("echo ''")
deferFn(function()
cmd("echo ''")
end, opts.timeout or 3000)
end
end
-- Function to show notifications specifically for dashboard
--- Show a minimal notification tailored for the alpha dashboard.
--- Truncates messages longer than 50 characters and uses echo
--- to avoid interfering with the dashboard layout.
--- @param message string The notification message to display.
--- @param level number|nil Log level from log.levels.
--- @param opts table|nil Optional overrides (timeout, etc.).
function M.show_dashboard_notification(message, level, opts)
-- In dashboard, show minimal notifications
local icon = "💬"
if level == vim.log.levels.ERROR then
if level == log.levels.ERROR then
icon = ""
elseif level == vim.log.levels.WARN then
elseif level == log.levels.WARN then
icon = "⚠️"
elseif level == vim.log.levels.INFO then
elseif level == log.levels.INFO then
icon = ""
end
@@ -133,25 +156,29 @@ function M.show_dashboard_notification(message, level, opts)
end
-- Use echo for dashboard notifications to avoid overlapping
vim.cmd("echo '" .. icon .. " " .. short_message .. "'")
cmd("echo '" .. icon .. " " .. short_message .. "'")
-- Clear message after a delay
vim.defer_fn(function()
vim.cmd("echo ''")
deferFn(function()
cmd("echo ''")
end, opts.timeout or 3000)
end
-- Function to clear all notifications
--- Close and clear all active notifications.
--- Iterates through `active_notifications`, closes any valid windows,
--- and resets the tracking list.
function M.clear_all_notifications()
for _, notif in ipairs(active_notifications) do
if notif.win and vim.api.nvim_win_is_valid(notif.win) then
vim.api.nvim_win_close(notif.win, true)
if notif.win and api.nvim_win_is_valid(notif.win) then
api.nvim_win_close(notif.win, true)
end
end
active_notifications = {}
end
-- Function to show performance notification
--- Show a performance-related notification with a chart icon prefix.
--- @param message string The performance message to display.
--- @param level number|nil Log level from log.levels.
function M.show_performance_notification(message, level)
M.show_notification("📊 " .. message, level, {
title = "Performance Monitor",
@@ -160,7 +187,9 @@ function M.show_performance_notification(message, level)
})
end
-- Function to show LSP notification
--- Show an LSP status notification with a wrench icon prefix.
--- @param message string The LSP status message to display.
--- @param level number|nil Log level from log.levels.
function M.show_lsp_notification(message, level)
M.show_notification("🔧 " .. message, level, {
title = "LSP Status",
@@ -169,7 +198,9 @@ function M.show_lsp_notification(message, level)
})
end
-- Function to show file operation notification
--- Show a file operation notification with a folder icon prefix.
--- @param message string The file operation message to display.
--- @param level number|nil Log level from log.levels.
function M.show_file_notification(message, level)
M.show_notification("📁 " .. message, level, {
title = "File Operation",
@@ -178,7 +209,9 @@ function M.show_file_notification(message, level)
})
end
-- Function to show plugin notification
--- Show a plugin manager notification with a sloth icon prefix.
--- @param message string The plugin-related message to display.
--- @param level number|nil Log level from log.levels.
function M.show_plugin_notification(message, level)
M.show_notification("🦥 " .. message, level, {
title = "Plugin Manager",
@@ -187,7 +220,9 @@ function M.show_plugin_notification(message, level)
})
end
-- Function to show startup notification
--- Show a startup notification with a rocket icon prefix and a short timeout.
--- @param message string The startup message to display.
--- @param level number|nil Log level from log.levels.
function M.show_startup_notification(message, level)
M.show_notification("🚀 " .. message, level, {
title = "Startup",
@@ -196,57 +231,64 @@ function M.show_startup_notification(message, level)
})
end
-- Function to handle startup messages aggressively
--- Aggressively suppress startup messages and "Press ENTER" prompts.
--- Configures `shortmess` with all relevant flags, sets `cmdheight` to 0,
--- disables `showmode`, and schedules deferred redraws to clear any
--- lingering messages.
function M.handle_startup_messages()
-- Clear any existing messages immediately
vim.cmd("redraw!")
vim.cmd("echo ''")
cmd("redraw!")
cmd("echo ''")
-- Suppress all startup messages
vim.opt.shortmess = vim.opt.shortmess + "I" -- No intro message
vim.opt.shortmess = vim.opt.shortmess + "c" -- No completion messages
vim.opt.shortmess = vim.opt.shortmess + "F" -- No file info message
vim.opt.shortmess = vim.opt.shortmess + "W" -- No "written" message
vim.opt.shortmess = vim.opt.shortmess + "A" -- No attention message
vim.opt.shortmess = vim.opt.shortmess + "o" -- No overwrite messages
vim.opt.shortmess = vim.opt.shortmess + "t" -- No truncation messages
vim.opt.shortmess = vim.opt.shortmess + "T" -- No truncation messages
vim.opt.shortmess = vim.opt.shortmess + "f" -- No file info messages
vim.opt.shortmess = vim.opt.shortmess + "i" -- No intro messages
vim.opt.shortmess = vim.opt.shortmess + "l" -- No line number messages
vim.opt.shortmess = vim.opt.shortmess + "m" -- No modification messages
vim.opt.shortmess = vim.opt.shortmess + "n" -- No line number messages
vim.opt.shortmess = vim.opt.shortmess + "r" -- No read messages
vim.opt.shortmess = vim.opt.shortmess + "s" -- No search messages
vim.opt.shortmess = vim.opt.shortmess + "x" -- No truncation messages
vim.opt.shortmess = vim.opt.shortmess + "O" -- No overwrite messages
opt.shortmess = opt.shortmess + "I" -- No intro message
opt.shortmess = opt.shortmess + "c" -- No completion messages
opt.shortmess = opt.shortmess + "F" -- No file info message
opt.shortmess = opt.shortmess + "W" -- No "written" message
opt.shortmess = opt.shortmess + "A" -- No attention message
opt.shortmess = opt.shortmess + "o" -- No overwrite messages
opt.shortmess = opt.shortmess + "t" -- No truncation messages
opt.shortmess = opt.shortmess + "T" -- No truncation messages
opt.shortmess = opt.shortmess + "f" -- No file info messages
opt.shortmess = opt.shortmess + "i" -- No intro messages
opt.shortmess = opt.shortmess + "l" -- No line number messages
opt.shortmess = opt.shortmess + "m" -- No modification messages
opt.shortmess = opt.shortmess + "n" -- No line number messages
opt.shortmess = opt.shortmess + "r" -- No read messages
opt.shortmess = opt.shortmess + "s" -- No search messages
opt.shortmess = opt.shortmess + "x" -- No truncation messages
opt.shortmess = opt.shortmess + "O" -- No overwrite messages
-- Disable command line messages
vim.opt.cmdheight = 0
vim.opt.showmode = false
opt.cmdheight = 0
opt.showmode = false
-- Clear any existing messages
vim.cmd("echo ''")
cmd("echo ''")
-- Force clear any pending messages
vim.defer_fn(function()
vim.cmd("redraw!")
vim.cmd("echo ''")
deferFn(function()
cmd("redraw!")
cmd("echo ''")
end, 100)
end
-- Function to eliminate "Press ENTER" prompts completely
--- Eliminate "Press ENTER" prompts by overriding `cmd.echo` and
--- installing autocmds that forcibly clear messages on VimEnter and
--- BufReadPost events.
function M.eliminate_enter_prompts()
-- Override the message display to prevent "Press ENTER" prompts
local original_echo = vim.cmd.echo
vim.cmd.echo = function(msg)
local original_echo = cmd.echo
cmd.echo = function(msg)
local msg_str = tostring(msg)
-- Block any messages that might cause "Press ENTER" prompts
if msg_str:match("Press ENTER") or
msg_str:match("lazyredraw") or
msg_str:match("You have enabled") or
msg_str:match("This is only meant") or
msg_str:match("You'll experience issues") then
if
msg_str:match("Press ENTER")
or msg_str:match("lazyredraw")
or msg_str:match("You have enabled")
or msg_str:match("This is only meant")
or msg_str:match("You'll experience issues")
then
return -- Don't show these messages
end
-- Allow other messages
@@ -254,17 +296,17 @@ function M.eliminate_enter_prompts()
end
-- Create autocmd to handle any remaining prompts
vim.api.nvim_create_autocmd("VimEnter", {
api.nvim_create_autocmd("VimEnter", {
callback = function()
-- Clear any startup messages immediately
vim.cmd("redraw!")
vim.cmd("echo ''")
cmd("redraw!")
cmd("echo ''")
-- Force clear any pending messages multiple times
for i = 1, 5 do
vim.defer_fn(function()
vim.cmd("redraw!")
vim.cmd("echo ''")
deferFn(function()
cmd("redraw!")
cmd("echo ''")
end, i * 50)
end
end,
@@ -272,18 +314,21 @@ function M.eliminate_enter_prompts()
})
-- Create autocmd to handle message events - use valid events
vim.api.nvim_create_autocmd("BufReadPost", {
api.nvim_create_autocmd("BufReadPost", {
callback = function()
-- Clear messages that might cause prompts
vim.cmd("redraw!")
cmd("redraw!")
end,
})
end
-- Function to setup notification system
--- Initialize the notification system.
--- Registers VimEnter and FileType autocmds to handle startup messages
--- and dashboard transitions, and calls `eliminate_enter_prompts`.
--- Called automatically when the module is first required.
function M.setup()
-- Create autocmd to handle startup messages
vim.api.nvim_create_autocmd("VimEnter", {
api.nvim_create_autocmd("VimEnter", {
callback = function()
M.handle_startup_messages()
end,
@@ -291,7 +336,7 @@ function M.setup()
})
-- Create autocmd to handle alpha dashboard
vim.api.nvim_create_autocmd("FileType", {
api.nvim_create_autocmd("FileType", {
pattern = "alpha",
callback = function()
M.handle_startup_messages()
@@ -305,7 +350,7 @@ function M.setup()
-- Let the system handle notifications naturally
end
-- Initialize notification manager
--- Initialize notification manager on require.
M.setup()
return M

View File

@@ -1,48 +1,54 @@
--- Terminal toggle utility.
--- Provides a function and keybinding (`<Leader>ter`) to open or close a
--- vertical-split zsh terminal on the right side of the editor. The terminal
--- automatically enters insert mode on focus and exits insert mode on blur.
--- @module openTerminal
vim.g.mapleader = " "
local keymap = vim.keymap
local cmd = vim.cmd
local api = vim.api
-- Function to open terminal
--- Toggle a terminal split on the rightmost side of the editor.
--- If the rightmost buffer is already a terminal, it closes it.
--- Otherwise, opens a new vertical split running zsh with line numbers
--- disabled and auto insert-mode behavior on focus/blur.
local function open_terminal()
-- Move to the rightmost buffer (equivalent to `<C-l>` multiple times)
vim.cmd("wincmd l")
vim.cmd("wincmd l")
vim.cmd("wincmd l")
vim.cmd("wincmd l")
cmd("wincmd l")
cmd("wincmd l")
cmd("wincmd l")
cmd("wincmd l")
-- Get current buffer number and type
local buf_num = vim.api.nvim_get_current_buf()
local buf_type = vim.api.nvim_buf_get_option(buf_num, "buftype")
local buf_num = apinvim_get_current_buf()
local buf_type = apinvim_buf_get_option(buf_num, "buftype")
if buf_type == "terminal" then
-- If already in a terminal, close it
vim.cmd("q")
cmd("q")
else
-- Open terminal in a vertical split
vim.cmd("vsp | term zsh")
cmd("vsp | term zsh")
-- Disable line numbers in terminal
vim.cmd("setlocal nonumber norelativenumber")
cmd("setlocal nonumber norelativenumber")
-- Auto-start insert mode in terminal
vim.api.nvim_create_autocmd({ "BufWinEnter", "WinEnter" }, {
apinvim_create_autocmd({ "BufWinEnter", "WinEnter" }, {
buffer = 0,
command = "startinsert!",
})
vim.api.nvim_create_autocmd("BufLeave", {
apinvim_create_autocmd("BufLeave", {
buffer = 0,
command = "stopinsert!",
})
-- Terminal key mappings
vim.keymap.set("t", "<C-h>", "<C-\\><C-n><C-w>h", { buffer = true })
vim.keymap.set("t", "<C-t>", "<C-\\><C-n>:q<CR>", { buffer = true })
vim.keymap.set("t", "<C-\\><C-\\>", "<C-\\><C-n>", { buffer = true })
-- Start terminal in insert mode
vim.cmd("startinsert!")
cmd("startinsert!")
end
end
-- Keybinding to open terminal
--- Map `<Leader>ter` in normal mode to toggle the terminal split.
keymap.set("n", "<Leader>ter", open_terminal, { noremap = true, silent = true })

View File

@@ -1,11 +1,22 @@
--- Performance and LSP health monitoring utilities.
--- Provides functions to inspect memory usage, startup time, loaded plugins,
--- active LSP clients, and per-buffer diagnostic summaries.
--- @module performance_monitor
local M = {}
-- Check overall Neovim performance
local fn = vim.fn
local notify = vim.notify
local lsp = vim.lsp
--- Collect and display overall Neovim performance statistics.
--- Reports memory usage, open buffer count, active LSP clients, and
--- (when lazy.nvim is available) loaded plugin count and startup time.
--- Results are shown via `vim.notify` at INFO level.
function M.check_performance()
local stats = {}
-- Startup time
stats.startup = vim.fn.reltimefloat(vim.fn.reltime(vim.g.start_time or vim.fn.reltime()))
stats.startup = fn.reltimefloat(fn.reltime(vim.g.start_time or fn.reltime()))
-- Memory usage
local mem = collectgarbage("count")
@@ -13,7 +24,7 @@ function M.check_performance()
stats.memory_mb = string.format("%.2f", mem / 1024)
-- Buffer count
stats.buffers = #vim.fn.getbufinfo({ buflisted = 1 })
stats.buffers = #fn.getbufinfo({ buflisted = 1 })
-- Loaded plugins (lazy.nvim)
local lazy_ok, lazy = pcall(require, "lazy")
@@ -25,7 +36,7 @@ function M.check_performance()
end
-- Active LSP clients
stats.lsp_clients = #vim.lsp.get_clients()
stats.lsp_clients = #lsp.get_clients()
-- Display results
local lines = {
@@ -41,15 +52,19 @@ function M.check_performance()
table.insert(lines, string.format("Startup Time: %s ms", stats.startup_ms))
end
vim.notify(table.concat(lines, "\n"), vim.log.levels.INFO, { title = "Performance" })
notify(table.concat(lines, "\n"), vim.log.levels.INFO, { title = "Performance" })
end
-- Check LSP health for current buffer
--- Check LSP health for the current buffer.
--- Lists all attached LSP clients with their root directory and
--- server capabilities (completion, hover, definition, references,
--- formatting, code_actions), followed by a diagnostic severity summary.
--- Warns if no LSP clients are attached.
function M.check_lsp_health()
local clients = vim.lsp.get_clients({ bufnr = 0 })
local clients = lsp.get_clients({ bufnr = 0 })
if #clients == 0 then
vim.notify("No LSP clients attached to this buffer", vim.log.levels.WARN, { title = "LSP Health" })
notify("No LSP clients attached to this buffer", vim.log.levels.WARN, { title = "LSP Health" })
return
end
@@ -103,10 +118,18 @@ function M.check_lsp_health()
end
table.insert(lines, "")
table.insert(lines, string.format("Diagnostics: %d errors, %d warnings, %d hints, %d info",
counts.errors, counts.warnings, counts.hints, counts.info))
table.insert(
lines,
string.format(
"Diagnostics: %d errors, %d warnings, %d hints, %d info",
counts.errors,
counts.warnings,
counts.hints,
counts.info
)
)
vim.notify(table.concat(lines, "\n"), vim.log.levels.INFO, { title = "LSP Health" })
notify(table.concat(lines, "\n"), vim.log.levels.INFO, { title = "LSP Health" })
end
return M

View File

@@ -1,27 +1,43 @@
vim.api.nvim_create_user_command("RunProject", function()
--- Project-level user commands for running and debugging.
--- Reads a per-project configuration file at `.nvim/project.lua` that should
--- return a table with `run` and/or `debug` keys containing shell commands.
--- Registers the `:RunProject` and `:DebugProject` user commands.
--- @module project_commands
local api = vim.api
local fn = vim.fn
local notify = vim.notify
--- Run the project using the `run` command from `.nvim/project.lua`.
--- Opens a vertical split terminal with the configured run command.
--- Notifies the user if the config file or run command is missing.
api.nvim_create_user_command("RunProject", function()
local config_path = ".nvim/project.lua"
if vim.fn.filereadable(config_path) == 0 then
vim.notify("No project config found. Run `:e` on any file to generate it.", vim.log.levels.WARN)
if fn.filereadable(config_path) == 0 then
notify("No project config found. Run `:e` on any file to generate it.", vim.log.levels.WARN)
return
end
local config = loadfile(config_path)()
if config and config.run then
vim.cmd("vsplit | terminal " .. config.run)
else
vim.notify("Run command not found in project config.", vim.log.levels.ERROR)
notify("Run command not found in project config.", vim.log.levels.ERROR)
end
end, {})
vim.api.nvim_create_user_command("DebugProject", function()
--- Debug the project using the `debug` command from `.nvim/project.lua`.
--- Opens a vertical split terminal with the configured debug command.
--- Notifies the user if the config file or debug command is missing.
api.nvim_create_user_command("DebugProject", function()
local config_path = ".nvim/project.lua"
if vim.fn.filereadable(config_path) == 0 then
vim.notify("No project config found. Run `:e` on any file to generate it.", vim.log.levels.WARN)
if fn.filereadable(config_path) == 0 then
notify("No project config found. Run `:e` on any file to generate it.", vim.log.levels.WARN)
return
end
local config = loadfile(config_path)()
if config and config.debug then
vim.cmd("vsplit | terminal " .. config.debug)
else
vim.notify("Debug command not found in project config.", vim.log.levels.ERROR)
notify("Debug command not found in project config.", vim.log.levels.ERROR)
end
end, {})

View File

@@ -1,99 +0,0 @@
# Keymaps Structure
This folder contains all the keymaps organized by category for better maintainability.
## File Structure
```
keymaps/
├── README.md # This file
├── general.lua # General keymaps (leader, basic navigation, obsidian)
├── personal.lua # Personal workflow keymaps
├── lsp.lua # LSP and function navigation keymaps
├── dap.lua # DAP debugging keymaps
├── snacks.lua # Snacks search and navigation keymaps
├── window.lua # Window management keymaps
├── copilot.lua # Copilot AI keymaps
├── plugins.lua # Plugin-specific keymaps (Telescope, trouble, etc.)
├── project.lua # Project-specific keymaps
├── ufo.lua # Folding keymaps
├── leet.lua # LeetCode keymaps
├── sudoku.lua # Sudoku game keymaps
└── database.lua # Database keymaps
```
## How It Works
The main `keymaps.lua` file automatically loads all `.lua` files from this folder:
```lua
local function load_keymaps()
local keymaps_path = vim.fn.stdpath("config") .. "/lua/cargdev/core/keymaps"
local scan = vim.fn.globpath(keymaps_path, "*.lua", false, true)
for _, file in ipairs(scan) do
local module_name = "cargdev.core.keymaps." .. file:match("([^/]+)%.lua$")
pcall(require, module_name)
end
end
```
## Keymap Categories
| Category | File | Description |
|----------|------|-------------|
| General | `general.lua` | Basic setup, escape, obsidian links |
| Personal | `personal.lua` | Your workflow shortcuts |
| LSP | `lsp.lua` | Function navigation and LSP features |
| Debugging | `dap.lua` | DAP debugging (Java, Node.js, Python) |
| Search | `snacks.lua` | File and text search (Snacks) |
| Window | `window.lua` | Window/split management |
| Copilot | `copilot.lua` | AI assistant keymaps |
| Plugins | `plugins.lua` | Plugin-specific (Telescope, trouble, etc.) |
| Project | `project.lua` | Project commands |
| Folding | `ufo.lua` | Code folding |
| LeetCode | `leet.lua` | LeetCode integration |
| Database | `database.lua` | Database operations |
## Adding New Keymaps
1. **Choose the appropriate file** based on the category
2. **Add your keymaps** using the standard format:
```lua
local keymap = vim.keymap
keymap.set("n", "<leader>key", "<cmd>command<cr>", { desc = "Description" })
```
3. **The keymaps will be automatically loaded** when Neovim starts
## Leader Key Prefixes
| Prefix | Category |
|--------|----------|
| `<leader>f` | Find/Files (Telescope) |
| `<leader>g` | Git |
| `<leader>d` | Debug |
| `<leader>l` | LSP/LeetCode |
| `<leader>x` | Trouble/Diagnostics |
| `<leader>s` | Search/Session |
| `<leader>t` | Toggle/Text/Treesj |
| `<leader>h` | Harpoon |
| `<leader>k` | Kulala (HTTP) |
| `<leader>o` | Overseer/Octo |
| `<leader>n` | NPM/Navbuddy |
| `<leader>c` | Code/Crates |
| `<leader>v` | Vim learning |
| `<leader>z` | Zen mode |
| `<leader>q` | Session (persistence) |
| `<leader>r` | Rename/Regex |
| `<leader>p` | Portal/Projects |
## Full Reference
See [KEYMAPS.md](../../../../KEYMAPS.md) in the root directory for complete keybinding reference.
## Notes
- All files are automatically loaded by `keymaps.lua`
- Each file should have its own `local keymap = vim.keymap` declaration
- Use descriptive `desc` for all keymaps (shows in which-key)
- Follow the existing naming conventions for consistency

View File

@@ -1,24 +1,32 @@
-- Copilot keymaps
--- Copilot keymaps.
--- Bindings for GitHub Copilot panel navigation (normal mode) and inline
--- suggestion cycling (insert mode). All Copilot modules are loaded via
--- pcall to avoid errors when Copilot is not installed or authenticated.
--- @module keymaps.copilot
local keymap = vim.keymap
-- Helper function to safely get Copilot modules
--- Safely require the copilot.panel module.
--- @return table|nil panel The panel module, or nil if unavailable.
local function get_copilot_panel()
local ok, panel = pcall(require, "copilot.panel")
return ok and panel or nil
end
--- Safely require the copilot.suggestion module.
--- @return table|nil suggestion The suggestion module, or nil if unavailable.
local function get_copilot_suggestion()
local ok, suggestion = pcall(require, "copilot.suggestion")
return ok and suggestion or nil
end
-- Copilot panel and status
--- Copilot commands — open panel, disable, enable, and check status.
keymap.set("n", "<leader>cp", ":Copilot panel<CR>", { desc = "Copilot: Open copilot panel" })
keymap.set("n", "<leader>cd", ":Copilot disable<CR>", { desc = "Copilot: Disable" })
keymap.set("n", "<leader>ce", ":Copilot enable<CR>", { desc = "Copilot: Enable" })
keymap.set("n", "<leader>cD", ":Copilot disable<CR>", { desc = "Copilot: Disable" })
keymap.set("n", "<leader>cE", ":Copilot enable<CR>", { desc = "Copilot: Enable" })
keymap.set("n", "<leader>cs", ":Copilot status<CR>", { desc = "Copilot: Status" })
-- Copilot panel keymaps
--- Panel navigation — jump previous/next, accept, refresh, and open.
keymap.set("n", "[[", function()
local panel = get_copilot_panel()
if panel and panel.is_open() then
@@ -40,7 +48,7 @@ keymap.set("n", "<CR>", function()
end
end, { desc = "Copilot: Accept suggestion in panel" })
keymap.set("n", "gr", function()
keymap.set("n", "rp", function()
local panel = get_copilot_panel()
if panel and panel.is_open() then
panel.refresh()
@@ -49,10 +57,7 @@ end, { desc = "Copilot: Refresh panel" })
keymap.set("n", "<M-CR>", ":Copilot panel<CR>", { desc = "Copilot: Open panel" })
-- Copilot suggestion keymaps (insert mode)
-- Note: Tab mapping is handled in nvim-cmp.lua to avoid conflicts
-- Tab is reserved exclusively for Copilot inline suggestions
--- Inline suggestion cycling (insert mode) — next, previous, dismiss.
keymap.set("i", "<leader>]", function()
local suggestion = get_copilot_suggestion()
if suggestion and suggestion.is_visible() then
@@ -73,6 +78,3 @@ keymap.set("i", "<C-]>", function()
suggestion.dismiss()
end
end, { desc = "Copilot: Dismiss suggestion" })
-- CodeCompanion keymaps
keymap.set("n", "<leader>cc", ":CodeCompanion<CR>", { desc = "CodeCompanion: Open CodeCompanion" })

View File

@@ -1,35 +1,6 @@
-- DAP (Debug Adapter Protocol) keymaps
local ok_dap, dap = pcall(require, "dap")
local ok_dapui, dapui = pcall(require, "dapui")
local fn = vim.fn
local keymap = vim.keymap.set
if ok_dap and ok_dapui then
keymap("n", "<leader>dcr", dap.continue, { desc = "▶ Start Debugging" })
keymap("n", "<leader>do", dap.step_over, { desc = "⏭ Step Over" })
keymap("n", "<leader>di", dap.step_into, { desc = "⤵ Step Into" })
keymap("n", "<leader>dot", dap.step_out, { desc = "⤴ Step Out" })
keymap("n", "<leader>db", dap.toggle_breakpoint, { desc = "🔴 Toggle Breakpoint" })
keymap("n", "<leader>dB", function()
dap.set_breakpoint(fn.input("Breakpoint condition: "))
end, { desc = "⚠ Conditional Breakpoint" })
keymap("n", "<leader>dr", dap.repl.open, { desc = "💬 Open REPL" })
keymap("n", "<leader>dl", dap.run_last, { desc = "🔁 Run Last Debug" })
keymap("n", "<leader>du", dapui.toggle, { desc = "🧩 Toggle DAP UI" })
keymap("n", "<leader>dq", dap.terminate, { desc = "⛔ Stop Debugging" })
-- 🧼 Reset UI
keymap("n", "<leader>drt", function()
dap.terminate()
dapui.close()
vim.defer_fn(function()
dapui.open()
end, 200)
end, { desc = "🧼 Reset DAP UI Layout" })
-- 🔭 Snacks Integration (replacing Telescope)
keymap("n", "<leader>dcf", "<cmd>lua require('snacks.picker').dap_configurations()<cr>", { desc = "🔭 DAP Configs" })
keymap("n", "<leader>dcb", "<cmd>lua require('snacks.picker').dap_list_breakpoints()<cr>", { desc = "🧷 List Breakpoints" })
keymap("n", "<leader>dco", "<cmd>lua require('snacks.picker').dap_commands()<cr>", { desc = "⚙️ DAP Commands" })
end
--- DAP (Debug Adapter Protocol) keymaps.
--- All DAP keymaps are registered in `plugins/dap.lua` inside the plugin's
--- config function to ensure nvim-dap and nvim-dap-ui are fully loaded
--- before any keybindings reference them. This file is intentionally empty.
--- @module keymaps.dap
--- @see plugins.dap

View File

@@ -1,53 +1,57 @@
-- Database keymaps
-- Using <leader>D prefix to avoid conflicts with DAP keymaps (<leader>d)
--- Database keymaps (vim-dadbod, MongoDB, Redis).
--- Uses `<leader>D` prefix to avoid conflicts with DAP keymaps (`<leader>d`).
--- Covers DBUI toggle, connections, query execution/saving, buffer management,
--- and quick-connect shortcuts for PostgreSQL Docker, MongoDB, and Redis.
--- @module keymaps.database
local keymap = vim.keymap
-- =============================================================================
-- DATABASE KEYMAPS (vim-dadbod)
-- =============================================================================
-- Toggle database UI
--- Toggle the vim-dadbod Database UI panel.
keymap.set("n", "<leader>Du", "<cmd>DBUIToggle<CR>", { desc = "Toggle Database UI" })
-- Add a new database connection
--- Add a new database connection interactively.
keymap.set("n", "<leader>Da", "<cmd>DBUIAddConnection<CR>", { desc = "Add DB Connection" })
-- Find buffer (useful when you have multiple query buffers)
--- Find a DBUI query buffer (useful when multiple query buffers are open).
keymap.set("n", "<leader>Df", "<cmd>DBUIFindBuffer<CR>", { desc = "Find DB Buffer" })
-- Execute query (works in sql buffers)
--- Execute a SQL query (full buffer in normal mode, selection in visual mode).
keymap.set("n", "<leader>De", "<Plug>(DBUI_ExecuteQuery)", { desc = "Execute Query" })
keymap.set("v", "<leader>De", "<Plug>(DBUI_ExecuteQuery)", { desc = "Execute Selected Query" })
-- Save query
--- Save the current query buffer to disk.
keymap.set("n", "<leader>Dw", "<Plug>(DBUI_SaveQuery)", { desc = "Save Query" })
-- Rename buffer
--- Rename the current DBUI query buffer.
keymap.set("n", "<leader>Dr", "<Plug>(DBUI_RenameBuf)", { desc = "Rename DB Buffer" })
-- =============================================================================
-- QUICK CONNECTIONS
-- =============================================================================
-- PostgreSQL Docker (default: 5432 postgres postgres postgres)
--- Connect to a PostgreSQL instance running in Docker (default port 5432).
keymap.set("n", "<leader>Dp", "<cmd>DBPostgresDocker<CR>", { desc = "Connect PostgreSQL Docker" })
-- =============================================================================
-- MONGODB
-- =============================================================================
-- Open MongoDB shell (local)
--- Open a local MongoDB shell.
keymap.set("n", "<leader>Dm", "<cmd>MongoDB<CR>", { desc = "Open MongoDB Shell" })
-- Open MongoDB in Docker container
--- Open a MongoDB shell inside a Docker container.
keymap.set("n", "<leader>DM", "<cmd>MongoDBDocker<CR>", { desc = "MongoDB Docker Shell" })
-- =============================================================================
-- REDIS
-- =============================================================================
-- Open Redis CLI (local)
--- Open a local Redis CLI session.
keymap.set("n", "<leader>Di", "<cmd>Redis<CR>", { desc = "Open Redis CLI" })
-- Open Redis in Docker container
--- Open a Redis CLI session inside a Docker container.
keymap.set("n", "<leader>DI", "<cmd>RedisDocker<CR>", { desc = "Redis Docker CLI" })

View File

@@ -1,4 +1,8 @@
-- General keymaps
--- General-purpose keymaps.
--- Provides essential editor-wide shortcuts: insert-mode escape (`jj`),
--- search highlight clearing, and quit-all.
--- @module keymaps.general
local keymap = vim.keymap
local opts = { noremap = true, silent = true }
@@ -6,116 +10,12 @@ local opts = { noremap = true, silent = true }
-- GENERAL KEYMAPS
-- =============================================================================
-- General keymaps
-- Changed from "jk" to "jj" to avoid conflicts when typing words containing 'j' followed by other letters
-- "jj" is much less likely to appear in normal typing and won't interfere
keymap.set("i", "jj", "<ESC>", opts) -- Exit insert mode with jj
keymap.set("n", "<leader>nh", ":nohl<CR>", opts) -- Clear search highlights
--- Exit insert mode by pressing `jj` (chosen over `jk` to avoid
--- conflicts when typing words containing "j" followed by other letters).
keymap.set("i", "jj", "<ESC>", opts)
-- Save and quit (additional)
--- Clear search highlights.
keymap.set("n", "<leader>nh", ":nohl<CR>", opts)
--- Quit all open buffers and windows without saving.
keymap.set("n", "<leader>Q", ":qa!<CR>", { desc = "Quit all" })
-- Obsidian vault path with validation
local vault_path = vim.env.IDEA_DIR
if not vault_path or vault_path == "" then
-- Silently skip Obsidian link setup if IDEA_DIR is not configured
return
end
local function follow_obsidian_link()
-- Extract the full [[...]] link from the current line under/around the cursor
local line = vim.api.nvim_get_current_line()
local col = vim.fn.col('.')
local start_idx, end_idx, raw
-- Search for all [[...]] in the line, pick the one under/around the cursor
local i = 1
while true do
local s, e = line:find('%[%[.-%]%]', i)
if not s then break end
if col >= s and col <= e + 1 then
start_idx, end_idx = s, e
break
end
i = e + 1
end
if not start_idx then
vim.notify('No [[link]] under cursor', vim.log.levels.WARN)
return
end
raw = line:sub(start_idx, end_idx)
raw = raw:gsub('^!%[%[', '[[') -- strip leading ! from embeds
local link = raw:gsub('%[%[', ''):gsub('%]%]', '')
-- split off alias (|) and heading (#) only after extracting the full link
local alias
local heading
-- first, split off alias if present
local pipe_idx = link:find("|", 1, true)
if pipe_idx then
alias = link:sub(pipe_idx + 1)
link = link:sub(1, pipe_idx - 1)
end
-- then, split off heading if present
local hash_idx = link:find("#", 1, true)
if hash_idx then
heading = link:sub(hash_idx + 1)
link = link:sub(1, hash_idx - 1)
end
-- normalize spaces
link = link:gsub("\\ ", " "):gsub("^%s+", ""):gsub("%s+$", "")
local function goto_heading(h)
if not h or h == "" then
return
end
-- crude jump: search for markdown heading or block that contains it
vim.cmd("keepjumps normal! gg")
local pat = "^%s*#+%s*" .. vim.pesc(h)
if vim.fn.search(pat) == 0 then
-- fallback: plain search
vim.fn.search(vim.pesc(h))
end
end
-- if link contains a '/', treat it as a relative path inside the vault
if link:find("/") then
local target = vault_path .. "/" .. link .. ".md"
vim.cmd.edit(target)
goto_heading(heading)
return
end
-- otherwise search recursively for basename match anywhere in the vault
local pattern = "**/" .. link .. ".md"
local matches = vim.fn.globpath(vault_path, pattern, false, true) -- list
if #matches == 1 then
vim.cmd.edit(matches[1])
goto_heading(heading)
elseif #matches > 1 then
vim.ui.select(matches, { prompt = "Multiple matches for " .. link .. ":" }, function(choice)
if choice then
vim.cmd.edit(choice)
goto_heading(heading)
end
end)
else
-- not found: offer to create at vault root
local target = vault_path .. "/" .. link .. ".md"
vim.ui.input({ prompt = "Create " .. target .. " ? (y/N) " }, function(ans)
if ans and ans:lower():sub(1, 1) == "y" then
vim.cmd.edit(target)
-- optional: insert a title
if vim.fn.line("$") == 1 and vim.fn.getline(1) == "" then
vim.api.nvim_buf_set_lines(0, 0, 0, false, { "# " .. (alias or link), "" })
end
goto_heading(heading)
end
end)
end
end
vim.keymap.set("n", "<leader>o", follow_obsidian_link, { noremap = true, silent = true })

View File

@@ -1,6 +1,16 @@
-- Leet keymaps
--- LeetCode keymaps.
--- Bindings for testing, submitting, and retrieving solutions via the
--- leetcode.nvim plugin. All mappings use the `<leader>l` prefix.
--- @module keymaps.leet
local keymap = vim.keymap
keymap.set("n", "<leader>lr", ":Leet test<CR>", { desc = "Test the leet current problem code" })
keymap.set("n", "<leader>ls", ":Leet submit<CR>", { desc = "Submit the leet solution" })
keymap.set("n", "<leader>lls", ":Leet last_submit<CR>", { desc = "Brings the latest submition from leetcode" })
--- LeetCode — run, submit, daily challenge, list, console, cookie, hints.
keymap.set("n", "<leader>lr", "<cmd>Leet run<CR>", { desc = "LeetCode: Run Code" })
keymap.set("n", "<leader>ls", "<cmd>Leet submit<CR>", { desc = "LeetCode: Submit Code" })
keymap.set("n", "<leader>ld", "<cmd>Leet daily<CR>", { desc = "LeetCode: Daily Challenge" })
keymap.set("n", "<leader>ll", "<cmd>Leet list<CR>", { desc = "LeetCode: List Problems" })
keymap.set("n", "<leader>lc", "<cmd>Leet console<CR>", { desc = "LeetCode: Open Console" })
keymap.set("n", "<leader>lu", "<cmd>Leet cookie update<CR>", { desc = "LeetCode: Update Cookie" })
keymap.set("n", "<leader>lh", "<cmd>Leet hints<cr>", { desc = "LeetCode: Open hints" })
keymap.set("n", "<leader>lls", "<cmd>Leet last<cr>", { desc = "LeetCode: Get latest submission" })

View File

@@ -1,27 +1,33 @@
-- LSP and function navigation keymaps
--- LSP and function navigation keymaps.
--- Uses fzf-lua pickers for go-to-definition, implementation, references,
--- type definitions, symbol search, code actions, rename, hover docs,
--- and diagnostic navigation.
--- @module keymaps.lsp
local keymap = vim.keymap
-- =============================================================================
-- LSP NAVIGATION (FUNCTION NAVIGATION) - Using fzf-lua
-- =============================================================================
-- Primary LSP navigation
--- Primary LSP navigation — definition, implementation, references, type def.
keymap.set("n", "gd", "<cmd>FzfLua lsp_definitions<cr>", { desc = "Go to definition" })
keymap.set("n", "gi", "<cmd>FzfLua lsp_implementations<cr>", { desc = "Go to implementation" })
keymap.set("n", "gr", "<cmd>FzfLua lsp_references<cr>", { desc = "Show references" })
keymap.set("n", "gt", "<cmd>FzfLua lsp_typedefs<cr>", { desc = "Go to type definition" })
-- Symbol search
--- Symbol search — document and workspace symbols via fzf-lua.
keymap.set("n", "<leader>ds", "<cmd>FzfLua lsp_document_symbols<cr>", { desc = "Document symbols" })
keymap.set("n", "<leader>lw", "<cmd>FzfLua lsp_workspace_symbols<cr>", { desc = "LSP: Workspace symbols" })
-- Code actions and documentation
--- Code actions, rename, and hover documentation.
keymap.set("n", "<leader>ca", "<cmd>FzfLua lsp_code_actions<cr>", { desc = "Code actions" })
keymap.set("n", "<leader>rn", "<cmd>lua vim.lsp.buf.rename()<cr>", { desc = "Rename" })
keymap.set("n", "K", "<cmd>lua vim.lsp.buf.hover()<cr>", { desc = "Hover documentation" })
keymap.set("n", "H", "<cmd>lua vim.lsp.buf.hover()<cr>", { desc = "Hover documentation" })
-- Diagnostics
--- Diagnostics — workspace list, line float, and prev/next navigation.
keymap.set("n", "<leader>D", "<cmd>FzfLua diagnostics_workspace<cr>", { desc = "Show diagnostics" })
keymap.set("n", "<leader>dd", "<cmd>lua vim.diagnostic.open_float()<cr>", { desc = "Line diagnostics" })
keymap.set("n", "[d", "<cmd>lua vim.diagnostic.goto_prev()<cr>", { desc = "Previous diagnostic" })
keymap.set("n", "]d", "<cmd>lua vim.diagnostic.goto_next()<cr>", { desc = "Next diagnostic" })

View File

@@ -0,0 +1,17 @@
--- Terminal-mode keymaps.
--- Provides shortcuts for navigating out of terminal buffers and closing them.
--- - `Ctrl+H` — switch to the left window from terminal mode.
--- - `Ctrl+T` — close the terminal window.
--- - `Ctrl+\ Ctrl+\` — escape to normal mode from terminal mode.
--- @module keymaps.openterminal
local keymap = vim.keymap
--- Switch to the left window from terminal mode.
keymap.set("t", "<C-h>", "<C-\\><C-n><C-w>h", { buffer = true })
--- Close the terminal window.
keymap.set("t", "<C-t>", "<C-\\><C-n>:q<CR>", { buffer = true })
--- Escape terminal mode to normal mode.
keymap.set("t", "<C-\\><C-\\>", "<C-\\><C-n>", { buffer = true })

View File

@@ -1,66 +1,50 @@
-- Personal keymaps (original workflow)
--- Personal keymaps — custom workflow shortcuts.
--- Includes text selection helpers, file management (save, quit, source),
--- number increment/decrement, buffer management with smart close via
--- snacks.bufdelete, coding shortcuts (React import, semicolons, commas,
--- console.log), Copilot Chat commands, clipboard HTML-to-Markdown paste,
--- and quickfix/location list navigation.
--- @module keymaps.personal
local keymap = vim.keymap
-- =============================================================================
-- PERSONAL KEYMAPS (ORIGINAL WORKFLOW)
-- =============================================================================
--- Select the entire file contents (visual mode).
keymap.set("n", "<leader>u", function()
vim.cmd("normal! ggVG$")
end, { desc = "Select the whole file" })
--- Duplicate the current line below.
keymap.set("n", "<leader>4", function()
-- Copy current line and paste below
vim.cmd("normal! yy")
vim.cmd("normal! p")
end, { desc = "Copy the entire line and paste just below" })
-- file management
--- File management — save, quit, force quit, source, and clear search.
keymap.set("n", "<leader>w", ":w<CR>", { desc = "Save the current file" })
keymap.set("n", "<leader>xa", ":xa<CR>", { desc = "Save and close all the files" })
keymap.set("n", "<leader>q", ":q<CR>", { desc = "Quit" })
keymap.set("n", "<leader>Q", ":q!<CR>", { desc = "Force quit" })
keymap.set("n", "<leader>so", ":source %<CR>", { desc = "Reload nvim" })
keymap.set("n", "<leader>no", ":noh <CR>", { desc = "Reset search a word" })
-- increment/decrement numbers
keymap.set("n", "<leader>+", "<C-a>", { desc = "Increment number" }) -- increment
keymap.set("n", "<leader>-", "<C-x>", { desc = "Decrement number" }) -- decrement
--- Increment/decrement the number under the cursor.
keymap.set("n", "<leader>+", "<C-a>", { desc = "Increment number" })
keymap.set("n", "<leader>-", "<C-x>", { desc = "Decrement number" })
-- Window management keymaps are centralized in lua/cargdev/core/keymaps/window.lua
-- sintax fixer
--- Re-indent the entire file using Neovim's built-in `=` operator.
keymap.set("n", "<leader>sy", "gg=G<CR>", { desc = "Format current file" })
--- Fast scroll — 10 lines at a time with Ctrl+E / Ctrl+Y.
keymap.set("n", "<C-e>", "10<C-e>", { noremap = true, silent = true })
keymap.set("n", "<C-y>", "10<C-y>", { noremap = true, silent = true })
-- Buffer management with safe close (confirms if unsaved changes)
-- Uses snacks.bufdelete for smart buffer deletion, shows dashboard on last buffer
local function close_buffer(force)
local ok, snacks = pcall(require, "snacks")
if ok and snacks.bufdelete then
-- snacks.bufdelete handles everything smartly
snacks.bufdelete({ force = force })
else
-- Fallback to manual handling
local current_buf = vim.api.nvim_get_current_buf()
local buffers = vim.tbl_filter(function(buf)
return vim.api.nvim_buf_is_valid(buf) and vim.bo[buf].buflisted
end, vim.api.nvim_list_bufs())
if #buffers > 1 then
vim.cmd("bprevious")
vim.cmd((force and "bdelete! " or "bdelete ") .. current_buf)
else
-- Last buffer: show dashboard instead of quitting
vim.cmd("enew")
if ok and snacks.dashboard then
snacks.dashboard()
end
end
end
end
--- Close the current buffer with a confirmation prompt if modified.
keymap.set("n", "<leader>bd", function()
if vim.bo.modified then
vim.ui.select({ "Save & Close", "Discard & Close", "Cancel" }, {
@@ -68,26 +52,24 @@ keymap.set("n", "<leader>bd", function()
}, function(choice)
if choice == "Save & Close" then
vim.cmd("w")
close_buffer(false)
vim.cmd("bd")
elseif choice == "Discard & Close" then
close_buffer(true)
vim.cmd("bd!")
end
end)
else
close_buffer(false)
vim.cmd("bd")
end
end, { desc = "Buffer: Close (safe)" })
-- Force close buffer without confirmation
keymap.set("n", "<leader>bD", function()
close_buffer(true)
end, { desc = "Buffer: Force close" })
--- Force close the current buffer, discarding unsaved changes.
keymap.set("n", "<leader>bD", ":db!<CR>", { desc = "Buffer: Force close" })
-- Set buftabline mappings
--- Buftabline navigation — Ctrl+P next buffer, Ctrl+N previous buffer.
keymap.set("n", "<C-p>", ":bnext<CR>", { noremap = true, silent = true })
keymap.set("n", "<C-n>", ":bprev<CR>", { noremap = true, silent = true })
-- Coding hacks
--- Coding shortcuts — React import, trailing comma/semicolon, run with Node.
keymap.set(
"n",
"<leader>re",
@@ -100,11 +82,7 @@ keymap.set("n", "<leader>xr", ":!node %<CR>", { desc = "Run file with node" })
-- Resize splits keymaps are centralized in lua/cargdev/core/keymaps/window.lua
-- Run and Debug Project
keymap.set("n", "<leader>pr", ":RunProject<CR>", { desc = "Run Project" })
keymap.set("n", "<leader>pd", ":DebugProject<CR>", { desc = "Debug Project" })
-- Copilot Chat (all Copilot keymaps moved to lua/cargdev/core/keymaps/copilot.lua)
--- Copilot Chat — rename, explain, review, fix, optimize, and generate docs.
keymap.set("v", "<leader>zn", ":CopilotChatRename<CR>", { desc = "Rename variable (Copilot Chat)" })
keymap.set("n", "<leader>zc", ":CopilotChat<CR>", { desc = "Open Copilot Chat" })
keymap.set("v", "<leader>ze", ":CopilotChatExplain<CR>", { desc = "Explain code (Copilot Chat)" })
@@ -113,15 +91,17 @@ keymap.set("v", "<leader>zf", ":CopilotChatFix<CR>", { desc = "Fix code issues (
keymap.set("v", "<leader>zo", ":CopilotChatOptimize<CR>", { desc = "Optimize code (Copilot Chat)" })
keymap.set("v", "<leader>zd", ":CopilotChatDocs<CR>", { desc = "Generate docs (Copilot Chat)" })
-- Paste HTML as Markdown using pandoc
keymap.set("n", "<leader>p", function()
vim.cmd("read !pbpaste -Prefer html | pandoc -f html -t gfm")
end, { desc = "Paste HTML clipboard as Markdown" })
--- Paste HTML from the system clipboard as GitHub-Flavored Markdown (via pandoc).
--- TODO: Fix this keymap
-- keymap.set("n", "<leader>p", function()
-- vim.cmd("read !pbpaste -Prefer html | pandoc -f html -t gfm")
-- end, { desc = "Paste HTML clipboard as Markdown" })
-- =============================================================================
-- QUICKFIX NAVIGATION (under <leader>x for Trouble/Diagnostics group)
-- =============================================================================
--- Quickfix list navigation — next, previous, open, close, first, last.
keymap.set("n", "<leader>xn", ":cnext<CR>zz", { desc = "Quickfix: Next item" })
keymap.set("n", "<leader>xp", ":cprev<CR>zz", { desc = "Quickfix: Previous item" })
keymap.set("n", "<leader>xo", ":copen<CR>", { desc = "Quickfix: Open list" })
@@ -129,7 +109,7 @@ keymap.set("n", "<leader>xq", ":cclose<CR>", { desc = "Quickfix: Close list" })
keymap.set("n", "<leader>xf", ":cfirst<CR>zz", { desc = "Quickfix: First item" })
keymap.set("n", "<leader>xl", ":clast<CR>zz", { desc = "Quickfix: Last item" })
-- Location list navigation
--- Location list navigation — next, previous, open, close.
keymap.set("n", "<leader>ln", ":lnext<CR>zz", { desc = "Location: Next item" })
keymap.set("n", "<leader>lp", ":lprev<CR>zz", { desc = "Location: Previous item" })
keymap.set("n", "<leader>lo", ":lopen<CR>", { desc = "Location: Open list" })

View File

@@ -1,125 +1,140 @@
-- Plugin-specific keymaps
--- Plugin-specific keymaps. Centralizes keybindings for third-party plugins: NvimTree, Comment,
--- LazyGit, DAP/DAP-UI, Trouble, ToggleTerm, sessions, formatting,
--- Substitute, Surround, LeetCode, Telescope/safe_files, database clients,
--- text wrapping, and auto-wrap controls.
--- @module keymaps.plugins
local keymap = vim.keymap
-- =============================================================================
-- PLUGIN KEYMAPS
-- =============================================================================
-- NvimTree
--- Toggle the NvimTree file explorer sidebar.
keymap.set("n", "<leader>e", "<cmd>NvimTreeToggle<CR>", { desc = "Toggle file explorer" })
-- Buffer management
--- Buffer management — cycle through listed buffers with Shift+L / Shift+H.
keymap.set("n", "<S-l>", ":bnext<CR>", { noremap = true, silent = true })
keymap.set("n", "<S-h>", ":bprevious<CR>", { noremap = true, silent = true })
-- Comment
keymap.set("n", "<leader>/", "<cmd>lua require('Comment.api').toggle_current_linewise()<CR>", { desc = "Toggle comment" })
keymap.set("v", "<leader>/", "<ESC><cmd>lua require('Comment.api').toggle_linewise_op(vim.fn.visualmode())<CR>", { desc = "Toggle comment" })
--- Comment.nvim — toggle line/block comments in normal and visual mode.
keymap.set(
"n",
"<leader>/",
"<cmd>lua require('Comment.api').toggle_current_linewise()<CR>",
{ desc = "Toggle comment" }
)
keymap.set(
"v",
"<leader>/",
"<ESC><cmd>lua require('Comment.api').toggle_linewise_op(vim.fn.visualmode())<CR>",
{ desc = "Toggle comment" }
)
-- Git
--- Open LazyGit in a floating terminal.
keymap.set("n", "<leader>gg", "<cmd>LazyGit<CR>", { desc = "LazyGit" })
-- DAP
keymap.set("n", "<leader>db", "<cmd>lua require'dap'.toggle_breakpoint()<cr>", { desc = "Toggle breakpoint" })
keymap.set("n", "<leader>dcc", "<cmd>lua require'dap'.continue()<cr>", { desc = "Continue" })
keymap.set("n", "<leader>di", "<cmd>lua require'dap'.step_into()<cr>", { desc = "Step into" })
keymap.set("n", "<leader>do", "<cmd>lua require'dap'.step_over()<cr>", { desc = "Step over" })
keymap.set("n", "<leader>dO", "<cmd>lua require'dap'.step_out()<cr>", { desc = "Step out" })
keymap.set("n", "<leader>dr", "<cmd>lua require'dap'.repl.toggle()<cr>", { desc = "Toggle REPL" })
keymap.set("n", "<leader>dl", "<cmd>lua require'dap'.run_last()<cr>", { desc = "Run last" })
keymap.set("n", "<leader>du", "<cmd>lua require'dapui'.toggle()<cr>", { desc = "Toggle DAP UI" })
keymap.set("n", "<leader>dt", "<cmd>lua require'dapui'.float_element()<cr>", { desc = "Float element" })
--- Trouble — diagnostics, workspace errors, location list, and quickfix viewer.
keymap.set("n", "<leader>Xx", "<cmd>TroubleToggle<cr>", { desc = "Toggle Trouble" })
keymap.set("n", "<leader>Xw", "<cmd>TroubleToggle workspace_diagnostics<cr>", { desc = "Workspace diagnostics" })
keymap.set("n", "<leader>Xd", "<cmd>TroubleToggle document_diagnostics<cr>", { desc = "Document diagnostics" })
keymap.set("n", "<leader>Xl", "<cmd>TroubleToggle loclist<cr>", { desc = "Location list" })
keymap.set("n", "<leader>Xq", "<cmd>TroubleToggle quickfix<cr>", { desc = "Quickfix list" })
-- Trouble
keymap.set("n", "<leader>xx", "<cmd>TroubleToggle<cr>", { desc = "Toggle Trouble" })
keymap.set("n", "<leader>xw", "<cmd>TroubleToggle workspace_diagnostics<cr>", { desc = "Workspace diagnostics" })
keymap.set("n", "<leader>xd", "<cmd>TroubleToggle document_diagnostics<cr>", { desc = "Document diagnostics" })
keymap.set("n", "<leader>xl", "<cmd>TroubleToggle loclist<cr>", { desc = "Location list" })
keymap.set("n", "<leader>xq", "<cmd>TroubleToggle quickfix<cr>", { desc = "Quickfix list" })
-- Terminal
--- ToggleTerm — open terminals as float, horizontal, or vertical splits.
keymap.set("n", "<leader>tf", "<cmd>ToggleTerm direction=float<cr>", { desc = "ToggleTerm float" })
keymap.set("n", "<leader>th", "<cmd>ToggleTerm size=10 direction=horizontal<cr>", { desc = "ToggleTerm horizontal split" })
keymap.set(
"n",
"<leader>th",
"<cmd>ToggleTerm size=10 direction=horizontal<cr>",
{ desc = "ToggleTerm horizontal split" }
)
keymap.set("n", "<leader>tv", "<cmd>ToggleTerm size=80 direction=vertical<cr>", { desc = "ToggleTerm vertical split" })
-- Session management (using <leader>sS and <leader>sR to avoid conflicts with substitute)
--- Session management — save/restore sessions (uppercase S/R to avoid substitute conflicts).
keymap.set("n", "<leader>sS", "<cmd>SessionSave<cr>", { desc = "Session: Save" })
keymap.set("n", "<leader>sR", "<cmd>SessionRestore<cr>", { desc = "Session: Restore" })
-- Formatting
keymap.set("n", "<leader>f", "<cmd>lua vim.lsp.buf.format()<cr>", { desc = "Format buffer" })
--- Format the current buffer using the attached LSP formatter.
--- TODO: add format buffer keymap
--- keymap.set("n", "<leader>f", "<cmd>lua vim.lsp.buf.format()<cr>", { desc = "Format buffer" })
-- Substitute
--- Substitute.nvim — operator, line, and end-of-line substitution.
keymap.set("n", "<leader>sub", "<cmd>lua require('substitute').operator()<cr>", { desc = "Substitute: With motion" })
keymap.set("n", "<leader>sl", "<cmd>lua require('substitute').line()<cr>", { desc = "Substitute: Line" })
keymap.set("n", "<leader>S", "<cmd>lua require('substitute').eol()<cr>", { desc = "Substitute: To end of line" })
-- Surround
--- nvim-surround — add, delete, and replace surrounding pairs.
keymap.set("n", "<leader>sa", "<cmd>lua require('nvim-surround').surround_add()<cr>", { desc = "Add surrounding" })
keymap.set("n", "<leader>sd", "<cmd>lua require('nvim-surround').surround_delete()<cr>", { desc = "Delete surrounding" })
keymap.set("n", "<leader>sr", "<cmd>lua require('nvim-surround').surround_replace()<cr>", { desc = "Replace surrounding" })
keymap.set(
"n",
"<leader>sd",
"<cmd>lua require('nvim-surround').surround_delete()<cr>",
{ desc = "Delete surrounding" }
)
keymap.set(
"n",
"<leader>sr",
"<cmd>lua require('nvim-surround').surround_replace()<cr>",
{ desc = "Replace surrounding" }
)
-- Git conflicts (moved to lua/cargdev/core/keymaps/gitconflict.lua)
-- LeetCode
keymap.set("n", "<leader>lr", "<cmd>Leet run<CR>", { desc = "LeetCode: Run Code" })
keymap.set("n", "<leader>ls", "<cmd>Leet submit<CR>", { desc = "LeetCode: Submit Code" })
keymap.set("n", "<leader>ld", "<cmd>Leet daily<CR>", { desc = "LeetCode: Daily Challenge" })
keymap.set("n", "<leader>ll", "<cmd>Leet list<CR>", { desc = "LeetCode: List Problems" })
keymap.set("n", "<leader>lc", "<cmd>Leet console<CR>", { desc = "LeetCode: Open Console" })
keymap.set("n", "<leader>lu", "<cmd>Leet cookie update<CR>", { desc = "LeetCode: Update Cookie" })
keymap.set("n", "<leader>lh", "<cmd>Leet hints<cr>", { desc = "LeetCode: Open hints" })
keymap.set("n", "<leader>lls", "<cmd>Leet last<cr>", { desc = "LeetCode: Get latest submission" })
--- Run project command via project_commands module.
keymap.set(
"n",
"<leader>p",
"<cmd>lua require('cargdev.core.function.project_commands').run_project()<cr>",
{ desc = "Run project" }
)
-- Linting
keymap.set("n", "<leader>l", "<cmd>Lint<cr>", { desc = "Lint current file" })
-- Project commands
keymap.set("n", "<leader>p", "<cmd>lua require('cargdev.core.function.project_commands').run_project()<cr>", { desc = "Run project" })
-- Console log (different from personal <leader>con)
--- Insert a `console.log()` snippet on the line below and enter insert mode.
keymap.set("n", "<leader>cl", "oconsole.log()<ESC>i", { desc = "Add console.log" })
-- DAP UI reset
keymap.set("n", "<leader>drt", "<cmd>lua require('dapui').float_element()<cr>", { desc = "Reset DAP UI layout" })
-- DAP commands
keymap.set("n", "<leader>dco", "<cmd>lua require('dap').commands()<cr>", { desc = "DAP commands" })
keymap.set("n", "<leader>dcf", "<cmd>lua require('dap').list_breakpoints()<cr>", { desc = "DAP configs" })
keymap.set("n", "<leader>dcb", "<cmd>lua require('dap').list_breakpoints()<cr>", { desc = "List breakpoints" })
-- Step out
keymap.set("n", "<leader>dot", "<cmd>lua require('dap').step_out()<cr>", { desc = "Step out" })
-- Todos in trouble
--- Open TODO comments in the Trouble panel.
keymap.set("n", "<leader>xt", "<cmd>TodoTrouble<cr>", { desc = "Open todos in trouble" })
-- Surround mappings
--- nvim-surround classic-style mappings (ys, yss, yS, ySS).
keymap.set("n", "ys", "<cmd>lua require('nvim-surround').surround_add()<cr>", { desc = "Add surrounding" })
keymap.set("n", "yss", "<cmd>lua require('nvim-surround').surround_add()<cr>", { desc = "Add surrounding to line" })
keymap.set("n", "yS", "<cmd>lua require('nvim-surround').surround_add()<cr>", { desc = "Add surrounding on new lines" })
keymap.set("n", "ySS", "<cmd>lua require('nvim-surround').surround_add()<cr>", { desc = "Add surrounding to line on new lines" })
keymap.set(
"n",
"ySS",
"<cmd>lua require('nvim-surround').surround_add()<cr>",
{ desc = "Add surrounding to line on new lines" }
)
-- Comment mappings
--- Comment.nvim classic-style mappings (gc, gcc, gco, gcO, gcA, gb, gbc).
keymap.set("n", "gc", "<cmd>lua require('Comment.api').toggle_current_linewise()<cr>", { desc = "Toggle comment" })
keymap.set("n", "gcc", "<cmd>lua require('Comment.api').toggle_current_linewise()<cr>", { desc = "Toggle current line comment" })
keymap.set(
"n",
"gcc",
"<cmd>lua require('Comment.api').toggle_current_linewise()<cr>",
{ desc = "Toggle current line comment" }
)
keymap.set("n", "gco", "<cmd>lua require('Comment.api').insert_below()<cr>", { desc = "Insert comment below" })
keymap.set("n", "gcO", "<cmd>lua require('Comment.api').insert_above()<cr>", { desc = "Insert comment above" })
keymap.set("n", "gcA", "<cmd>lua require('Comment.api').insert_eol()<cr>", { desc = "Insert comment at end of line" })
keymap.set("n", "gb", "<cmd>lua require('Comment.api').toggle_current_blockwise()<cr>", { desc = "Toggle block comment" })
keymap.set("n", "gbc", "<cmd>lua require('Comment.api').toggle_current_blockwise()<cr>", { desc = "Toggle current block comment" })
keymap.set(
"n",
"gb",
"<cmd>lua require('Comment.api').toggle_current_blockwise()<cr>",
{ desc = "Toggle block comment" }
)
keymap.set(
"n",
"gbc",
"<cmd>lua require('Comment.api').toggle_current_blockwise()<cr>",
{ desc = "Toggle current block comment" }
)
-- =============================================================================
-- TELESCOPE KEYMAPS (Enhanced with safe file searching)
-- =============================================================================
-- Safe file search (prevents LSP errors and image freezing)
keymap.set("n", "<leader>ff", "<cmd>Telescope safe_files find_files<CR>", { desc = "Find files (safe)" })
keymap.set("n", "<leader>fs", "<cmd>Telescope live_grep<CR>", { desc = "Live grep (safe)" })
keymap.set("n", "<leader>fg", "<cmd>Telescope git_files<CR>", { desc = "Git files (safe)" })
keymap.set("n", "<leader>ft", "<cmd>Telescope text_files find_files<CR>", { desc = "Text files only" })
-- Regular telescope (use with caution)
--- Unfiltered Telescope file search (may include binaries — use with caution).
keymap.set("n", "<leader>fF", "<cmd>Telescope find_files<CR>", { desc = "Find files (all)" })
-- =============================================================================
@@ -158,12 +173,12 @@ keymap.set("n", "<leader>fF", "<cmd>Telescope find_files<CR>", { desc = "Find fi
-- keymap.set("n", "<leader>dus", "<cmd>DBUISaveBuffer<CR>", { desc = "Save database buffer" })
-- keymap.set("n", "<leader>dul", "<cmd>DBUILoadBuffer<CR>", { desc = "Load database buffer" })
-- Redis specific
--- Redis CLI — open, list keys, show info.
keymap.set("n", "<leader>rds", "<cmd>Redis<CR>", { desc = "Open Redis" })
keymap.set("n", "<leader>rdk", "<cmd>RedisKeys<CR>", { desc = "Show Redis keys" })
keymap.set("n", "<leader>rdi", "<cmd>RedisInfo<CR>", { desc = "Show Redis info" })
-- MongoDB specific
--- MongoDB — open shell, connect, disconnect.
keymap.set("n", "<leader>mdb", "<cmd>MongoDB<CR>", { desc = "Open MongoDB" })
keymap.set("n", "<leader>mdc", "<cmd>MongoDBConnect<CR>", { desc = "Connect to MongoDB" })
keymap.set("n", "<leader>mdd", "<cmd>MongoDBDisconnect<CR>", { desc = "Disconnect from MongoDB" })
@@ -172,30 +187,30 @@ keymap.set("n", "<leader>mdd", "<cmd>MongoDBDisconnect<CR>", { desc = "Disconnec
-- NATIVE AUTO WRAPPER KEYMAPS
-- =============================================================================
-- Text wrapping controls
--- Text wrapping controls — toggle wrap, linebreak, and column guide.
keymap.set("n", "<leader>tw", "<cmd>set wrap!<cr>", { desc = "Toggle line wrapping" })
keymap.set("n", "<leader>tl", "<cmd>set linebreak!<cr>", { desc = "Toggle line break" })
keymap.set("n", "<leader>tc", "<cmd>set colorcolumn=80<cr>", { desc = "Show 80 char column" })
keymap.set("n", "<leader>tC", "<cmd>set colorcolumn=<cr>", { desc = "Hide column guide" })
keymap.set("n", "<leader>tx", "<cmd>set colorcolumn=80<cr>", { desc = "Show 80 char column" })
keymap.set("n", "<leader>tH", "<cmd>set colorcolumn=<cr>", { desc = "Hide column guide" })
-- Format text using native Neovim commands
keymap.set("n", "<leader>tf", "gqap", { desc = "Format paragraph" })
--- Format text using native Neovim `gq` command (paragraph, selection, file).
keymap.set("n", "<leader>tpg", "gqap", { desc = "Format paragraph" })
keymap.set("v", "<leader>tf", "gq", { desc = "Format selection" })
keymap.set("n", "<leader>tF", "gggqG", { desc = "Format entire file" })
-- Text width adjustments
--- Text width adjustments — set to 80, 100, 120, or disable (0).
keymap.set("n", "<leader>t80", "<cmd>set textwidth=80<cr>", { desc = "Set text width to 80" })
keymap.set("n", "<leader>t100", "<cmd>set textwidth=100<cr>", { desc = "Set text width to 100" })
keymap.set("n", "<leader>t120", "<cmd>set textwidth=120<cr>", { desc = "Set text width to 120" })
keymap.set("n", "<leader>t0", "<cmd>set textwidth=0<cr>", { desc = "Disable text width" })
-- Auto-wrap controls
--- Auto-wrap controls — toggle `formatoptions` flags for text and comments.
keymap.set("n", "<leader>ta", "<cmd>set formatoptions+=t<cr>", { desc = "Enable auto-wrap text" })
keymap.set("n", "<leader>tA", "<cmd>set formatoptions-=t<cr>", { desc = "Disable auto-wrap text" })
keymap.set("n", "<leader>tc", "<cmd>set formatoptions+=c<cr>", { desc = "Enable auto-wrap comments" })
keymap.set("n", "<leader>tC", "<cmd>set formatoptions-=c<cr>", { desc = "Disable auto-wrap comments" })
-- Indent and wrap
--- Indent and wrap — toggle break indent and show/hide break indicator.
keymap.set("n", "<leader>ti", "<cmd>set breakindent!<cr>", { desc = "Toggle break indent" })
keymap.set("n", "<leader>ts", "<cmd>set showbreak=↪ <cr>", { desc = "Show break indicator" })
keymap.set("n", "<leader>tS", "<cmd>set showbreak=<cr>", { desc = "Hide break indicator" })

View File

@@ -1,5 +1,12 @@
-- Project Run/Debug keymaps
--- Project run and debug keymaps.
--- Provides `<leader>p` prefixed shortcuts that invoke the `:RunProject`
--- and `:DebugProject` user commands defined in `project_commands.lua`.
--- @module keymaps.project
local keymap = vim.keymap
--- Execute the project run command from `.nvim/project.lua`.
keymap.set("n", "<leader>pr", ":RunProject<CR>", { desc = "Run Project" })
--- Execute the project debug command from `.nvim/project.lua`.
keymap.set("n", "<leader>pd", ":DebugProject<CR>", { desc = "Debug Project" })

View File

@@ -1,28 +1,33 @@
-- Snacks keymaps (replacing Telescope)
--- Snacks.nvim picker keymaps (replacing Telescope for most navigation).
--- Uses snacks.picker for file, grep, buffer, marks, keymaps, and command
--- searching. Falls back to Telescope for git operations and TODO search
--- where Snacks pickers are not yet available.
--- @module keymaps.snacks
local keymap = vim.keymap
-- =============================================================================
-- SNACKS NAVIGATION
-- =============================================================================
-- File navigation
--- File navigation — find files, live grep, grep string, recent files.
keymap.set("n", "<leader>ff", "<cmd>lua require('snacks.picker').files()<cr>", { desc = "Find files" })
keymap.set("n", "<leader>fs", "<cmd>lua require('snacks.picker').grep()<cr>", { desc = "Live grep" })
keymap.set("n", "<leader>fc", "<cmd>lua require('snacks.picker').grep_string()<cr>", { desc = "Grep string" })
keymap.set("n", "<leader>fr", "<cmd>lua require('snacks.picker').oldfiles()<cr>", { desc = "Recent files" })
-- Buffer and session management
--- Buffer and session management — buffers, help tags, marks, keymaps, commands.
keymap.set("n", "<leader>fb", "<cmd>lua require('snacks.picker').buffers()<cr>", { desc = "Find buffers" })
keymap.set("n", "<leader>fh", "<cmd>lua require('snacks.picker').help_tags()<cr>", { desc = "Help tags" })
keymap.set("n", "<leader>fm", "<cmd>lua require('snacks.picker').marks()<cr>", { desc = "Find marks" })
keymap.set("n", "<leader>fk", "<cmd>lua require('snacks.picker').keymaps()<cr>", { desc = "Find keymaps" })
keymap.set("n", "<leader>fC", "<cmd>lua require('snacks.picker').commands()<cr>", { desc = "Find commands" })
-- Git (using Telescope for git features as Snacks may not have all git pickers)
--- Git — commits, buffer commits, branches, and status (via Telescope fallback).
keymap.set("n", "<leader>fG", "<cmd>Telescope git_commits<cr>", { desc = "Git commits" })
keymap.set("n", "<leader>fB", "<cmd>Telescope git_bcommits<cr>", { desc = "Git buffer commits" })
keymap.set("n", "<leader>fg", "<cmd>Telescope git_branches<cr>", { desc = "Git branches" })
keymap.set("n", "<leader>gs", "<cmd>Telescope git_status<cr>", { desc = "Git status" })
-- Todos (keep Telescope for todos as Snacks may not have this)
--- Search TODO/FIXME/HACK comments (via Telescope — Snacks lacks this picker).
keymap.set("n", "<leader>ft", "<cmd>TodoTelescope<cr>", { desc = "Find todos" })

View File

@@ -1,18 +0,0 @@
-- Sudoku keymaps
-- WARNING: <leader>sng is mapped to two different commands below. Only the last one will take effect in Neovim.
-- Consider changing one of the mappings if you want both actions available.
local keymap = vim.keymap
keymap.set("n", "<leader>si1", ":Sudoku insert=1<CR>", { desc = "Add number 1" })
keymap.set("n", "<leader>si2", ":Sudoku insert=2<CR>", { desc = "Add number 2" })
keymap.set("n", "<leader>si3", ":Sudoku insert=3<CR>", { desc = "Add number 3" })
keymap.set("n", "<leader>si4", ":Sudoku insert=4<CR>", { desc = "Add number 4" })
keymap.set("n", "<leader>si5", ":Sudoku insert=5<CR>", { desc = "Add number 5" })
keymap.set("n", "<leader>si6", ":Sudoku insert=6<CR>", { desc = "Add number 6" })
keymap.set("n", "<leader>si7", ":Sudoku insert=7<CR>", { desc = "Add number 7" })
keymap.set("n", "<leader>si8", ":Sudoku insert=8<CR>", { desc = "Add number 8" })
keymap.set("n", "<leader>si9", ":Sudoku insert=9<CR>", { desc = "Add number 9" })
keymap.set("n", "<leader>scc", ":Sudoku clear_cell<CR>", { desc = "Clear current cell" })
keymap.set("n", "<leader>su", ":Sudoku undo<CR>", { desc = "Undo last action" })
keymap.set("n", "<leader>sng", ":Sudoku new_game<CR>", { desc = "Starts new game" })
keymap.set("n", "<leader>sng", ":Sudoku view=settings<CR>", { desc = "Display the settings" })

View File

@@ -1,12 +1,27 @@
-- nvim-ufo folding keymaps
--- nvim-ufo folding keymaps.
--- Overrides the default `z` fold commands with nvim-ufo equivalents for
--- improved fold rendering. Also overrides `K` to peek folded lines under
--- the cursor, falling back to LSP hover when no fold is present.
--- All keymaps are only registered when nvim-ufo loads successfully.
--- @module keymaps.ufo
local ok_ufo, ufo = pcall(require, "ufo")
local keymap = vim.keymap.set
if ok_ufo then
--- Open every fold in the buffer.
keymap("n", "zR", ufo.openAllFolds, { desc = "Open all folds" })
--- Close every fold in the buffer.
keymap("n", "zM", ufo.closeAllFolds, { desc = "Close all folds" })
--- Open folds except specific kinds (e.g. imports, comments).
keymap("n", "zr", ufo.openFoldsExceptKinds, { desc = "Open folds except kinds" })
--- Incrementally close folds by level.
keymap("n", "zm", ufo.closeFoldsWith, { desc = "Close folds with" })
--- Peek the folded lines under the cursor; fall back to LSP hover.
keymap("n", "K", function()
local winid = ufo.peekFoldedLinesUnderCursor()
if not winid then

View File

@@ -1,15 +1,24 @@
-- Window management keymaps
--- Window and tab management keymaps.
--- Provides split creation/closing, tab navigation, and Ctrl-based
--- resize shortcuts for both vertical and horizontal splits.
--- @module keymaps.window
local keymap = vim.keymap
--- Split management — vertical, horizontal, equalize, and close.
keymap.set("n", "<leader>sv", "<C-w>v", { desc = "Split window vertically" })
keymap.set("n", "<leader>sh", "<C-w>s", { desc = "Split window horizontally" })
keymap.set("n", "<leader>se", "<C-w>=", { desc = "Make splits equal size" })
keymap.set("n", "<leader>sx", "<cmd>close<CR>", { desc = "Close current split" })
--- Tab management — new, close, next, previous, and open buffer in new tab.
keymap.set("n", "<leader>to", "<cmd>tabnew<CR>", { desc = "Open new tab" })
keymap.set("n", "<leader>tx", "<cmd>tabclose<CR>", { desc = "Close current tab" })
keymap.set("n", "<leader>cx", "<cmd>tabclose<CR>", { desc = "Close current tab" })
keymap.set("n", "<leader>tn", "<cmd>tabn<CR>", { desc = "Go to next tab" })
keymap.set("n", "<leader>tp", "<cmd>tabp<CR>", { desc = "Go to previous tab" })
keymap.set("n", "<leader>tf", "<cmd>tabnew %<CR>", { desc = "Open current buffer in new tab" })
keymap.set("n", "<leader>tt", "<cmd>tabnew %<CR>", { desc = "Open current buffer in new tab" })
--- Resize splits — Ctrl+H/L for width, Ctrl+K/J for height (step of 5).
keymap.set("n", "<C-l>", ":vertical resize -5<CR>", { noremap = true, silent = true })
keymap.set("n", "<C-h>", ":vertical resize +5<CR>", { noremap = true, silent = true })
keymap.set("n", "<C-k>", ":resize +5<CR>", { noremap = true, silent = true })

View File

@@ -1,125 +0,0 @@
-- ============================================================================
-- CODETYPER.NVIM: AI-powered coding assistant plugin
-- ============================================================================
-- A local development plugin that provides AI-assisted coding capabilities
-- using various LLM providers (Ollama, Claude, OpenAI, Gemini, Copilot).
-- Features include: inline code transformation with /@ @/ tags, Ask panel
-- for interactive queries, Agent panel for autonomous coding tasks,
-- Tree-sitter integration for scope detection, and diff review.
--
-- Key keymaps:
-- <leader>co - Open Coder view <leader>ca - Open Ask panel
-- <leader>ct - Toggle Coder view <leader>cg - Open Agent panel
-- <leader>cp - Process prompt <leader>cd - Open Diff Review
-- <leader>ctt - Transform tag at cursor (also works in visual mode)
-- ============================================================================
-- Get local config (loaded in core/init.lua)
local local_cfg = vim.g.cargdev_local or {}
-- Skip plugin if local config is missing required values
if not local_cfg.CODE_TYPER_DIR then
return {}
end
return {
-- Codetyper.nvim - AI-powered coding partner
-- Local development version
dir = local_cfg.CODE_TYPER_DIR,
name = "codetyper.nvim",
lazy = false, -- Load on startup to create .coder folder
priority = 100, -- Load early
dependencies = {
"nvim-lua/plenary.nvim", -- Required: async utilities
-- "nvim-treesitter/nvim-treesitter", -- Required: scope detection via Tree-sitter
-- "nvim-treesitter/nvim-treesitter-textobjects", -- Optional: better text object support
"MunifTanjim/nui.nvim", -- Optional: UI components
},
event = {
"BufReadPre *.coder.*",
"BufNewFile *.coder.*",
},
cmd = {
"Coder",
"CoderOpen",
"CoderClose",
"CoderToggle",
"CoderProcess",
"CoderTree",
"CoderTreeView",
-- Ask commands
"CoderAsk",
"CoderAskToggle",
"CoderAskClear",
-- Agent commands
"CoderAgent",
"CoderAgentToggle",
"CoderAgentStop",
"CoderMode",
},
keys = {
-- Coder view commands
{ "<leader>co", "<cmd>Coder open<cr>", desc = "Coder: Open view" },
{ "<leader>cC", "<cmd>Coder close<cr>", desc = "Coder: Close view" },
{ "<leader>ct", "<cmd>Coder toggle<cr>", desc = "Coder: Toggle view" },
{ "<leader>cp", "<cmd>Coder process<cr>", desc = "Coder: Process prompt" },
{ "<leader>cs", "<cmd>Coder status<cr>", desc = "Coder: Show status" },
{ "<leader>cf", "<cmd>Coder focus<cr>", desc = "Coder: Switch focus" },
{ "<leader>cv", "<cmd>Coder tree-view<cr>", desc = "Coder: View tree" },
{ "<leader>cr", "<cmd>Coder tree<cr>", desc = "Coder: Refresh tree" },
-- Ask panel commands
{ "<leader>ca", "<cmd>Coder ask<cr>", desc = "Coder: Open Ask panel" },
{ "<leader>cA", "<cmd>Coder ask-toggle<cr>", desc = "Coder: Toggle Ask panel" },
{ "<leader>cx", "<cmd>Coder ask-clear<cr>", desc = "Coder: Clear Ask history" },
-- Agent panel commands
{ "<leader>cg", "<cmd>Coder agent<cr>", desc = "Coder: Open Agent panel" },
{ "<leader>cG", "<cmd>Coder agent-toggle<cr>", desc = "Coder: Toggle Agent panel" },
{ "<leader>cS", "<cmd>Coder agent-stop<cr>", desc = "Coder: Stop Agent" },
{ "<leader>cd", "<cmd>CoderDiffReview<cr>", desc = "Coder: Open Diff Review" },
-- Transform commands (inline /@ @/ replacement)
{ "<leader>ctt", mode = "n", desc = "Coder: Transform tag at cursor" },
{ "<leader>ctt", mode = "v", desc = "Coder: Transform selected tags" },
{ "<leader>ctT", "<cmd>Coder transform<cr>", desc = "Coder: Transform all tags" },
},
config = function()
require("codetyper").setup({
llm = {
-- Available providers: "ollama", "claude", "openai", "gemini", "copilot"
provider = "copilot", -- Using GitHub Copilot
-- Ollama (local LLM)
ollama = {
host = "http://localhost:11434",
model = "deepseek-coder:6.7b",
-- model = "codellama:7b",
-- model = "qwen2.5-coder:7b",
},
-- GitHub Copilot (uses OAuth from copilot.vim/copilot.lua)
copilot = {
model = "gpt-4o", -- or "gpt-4", "gpt-3.5-turbo"
},
},
window = {
width = 0.25, -- 1/4 of window
position = "left",
border = "rounded",
},
patterns = {
open_tag = "/@",
close_tag = "@/",
file_pattern = "*.coder.*",
},
auto_gitignore = true,
auto_open_ask = false, -- Don't auto-open Ask panel on startup
scheduler = {
enabled = true,
ollama_scout = false, -- Disabled since using Copilot directly
escalation_threshold = 0.7,
max_concurrent = 2,
completion_delay_ms = 100, -- Delay before checking completion visibility
apply_delay_ms = 2000, -- Wait 2 seconds before applying code
},
})
end,
}

View File

@@ -1,27 +1,33 @@
-- ============================================================================
-- COPILOT: GitHub AI code completion and chat
-- ============================================================================
-- AI-powered code suggestions that appear as ghost text while typing.
-- Includes copilot-cmp for completion menu integration and codecompanion
-- for AI chat/refactoring. Disabled for LaTeX files. Accept with <C-l>.
-- AI-powered code suggestions (ghost text + cmp menu) and chat.
-- Autocomplete: <C-l> accept ghost text, also shows in cmp menu.
-- Chat: <leader>cc toggle, <leader>cq quick chat, <leader>ce explain.
--
-- MODEL SELECTION:
-- Chat: :CopilotChatModels (pick from gpt-4o, claude-sonnet-4, o3-mini, etc.)
-- Autocomplete: controlled server-side by GitHub, not user-selectable.
-- ============================================================================
return {
-- Copilot core: ghost text suggestions + LSP backend
{
"zbirenbaum/copilot.lua",
cmd = "Copilot",
event = "InsertEnter",
config = function()
require("copilot").setup({
copilot_model = "gpt-41-copilot",
panel = {
enabled = true,
auto_refresh = false,
layout = {
position = "bottom", -- | top | left | right
position = "bottom",
ratio = 0.4,
},
},
suggestion = {
enabled = true, -- Codetyper will use copilot when available
enabled = true,
auto_trigger = true,
debounce = 75,
keymap = {
@@ -39,10 +45,10 @@ return {
hgcommit = true,
svn = true,
cvs = true,
tex = false, -- Disable Copilot for LaTeX files by default
tex = false,
["."] = true,
},
copilot_node_command = "node", -- Node.js version must be > 16.x
copilot_node_command = "node",
server_opts_overrides = {},
})
@@ -50,18 +56,18 @@ return {
vim.api.nvim_create_autocmd({ "FileType", "BufEnter" }, {
pattern = "tex",
callback = function()
-- Safely dismiss any active suggestions
local ok, suggestion = pcall(require, "copilot.suggestion")
if ok and suggestion and suggestion.is_visible() then
suggestion.dismiss()
end
-- Disable Copilot for this buffer
vim.cmd("Copilot disable")
end,
desc = "Disable Copilot for LaTeX files",
})
end,
},
-- Copilot CMP: adds Copilot as a completion source in nvim-cmp menu
{
"zbirenbaum/copilot-cmp",
dependencies = { "zbirenbaum/copilot.lua" },
@@ -69,28 +75,58 @@ return {
require("copilot_cmp").setup()
end,
},
-- CopilotChat: full chat interface with model selection
{
"olimorris/codecompanion.nvim",
"CopilotC-Nvim/CopilotChat.nvim",
dependencies = {
"zbirenbaum/copilot.lua",
"nvim-lua/plenary.nvim",
"nvim-telescope/telescope.nvim",
},
cmd = { "CodeCompanion" },
build = "make tiktoken",
cmd = {
"CopilotChat",
"CopilotChatToggle",
"CopilotChatModels",
"CopilotChatExplain",
"CopilotChatReview",
"CopilotChatFix",
"CopilotChatOptimize",
"CopilotChatDocs",
"CopilotChatTests",
"CopilotChatCommit",
},
keys = {
{ "<leader>cc", "<cmd>CopilotChatToggle<cr>", desc = "CopilotChat: Toggle chat window" },
{ "<leader>cq", function()
local input = vim.fn.input("Quick Chat: ")
if input ~= "" then
require("CopilotChat").ask(input, { selection = require("CopilotChat.select").buffer })
end
end, desc = "CopilotChat: Quick chat (whole buffer)" },
{ "<leader>ce", "<cmd>CopilotChatExplain<cr>", mode = { "n", "v" }, desc = "CopilotChat: Explain code" },
{ "<leader>cr", "<cmd>CopilotChatReview<cr>", mode = { "n", "v" }, desc = "CopilotChat: Review code" },
{ "<leader>cf", "<cmd>CopilotChatFix<cr>", mode = { "n", "v" }, desc = "CopilotChat: Fix code" },
{ "<leader>co", "<cmd>CopilotChatOptimize<cr>", mode = { "n", "v" }, desc = "CopilotChat: Optimize code" },
{ "<leader>cd", "<cmd>CopilotChatDocs<cr>", mode = { "n", "v" }, desc = "CopilotChat: Generate docs" },
{ "<leader>ct", "<cmd>CopilotChatTests<cr>", mode = { "n", "v" }, desc = "CopilotChat: Generate tests" },
{ "<leader>cm", "<cmd>CopilotChatModels<cr>", desc = "CopilotChat: Select model" },
},
config = function()
require("codecompanion").setup({
-- Use GitHub Copilot as the provider
providers = {
copilot = {
enabled = true,
},
require("CopilotChat").setup({
-- Default model (change with :CopilotChatModels at runtime)
-- Options include: gpt-4o, claude-sonnet-4, o3-mini, gemini-2.0-flash, etc.
model = "claude-sonnet-4",
window = {
layout = "vertical",
width = 0.35,
border = "rounded",
},
-- Configure the UI
ui = {
window = {
width = 0.8,
height = 0.8,
},
mappings = {
complete = { insert = "<Tab>" },
close = { normal = "q", insert = "<C-c>" },
reset = { normal = "<C-x>", insert = "<C-x>" },
submit_prompt = { normal = "<CR>", insert = "<C-s>" },
},
})
end,

View File

@@ -1,87 +0,0 @@
-- ============================================================================
-- REST.NVIM: HTTP client for making API requests from Neovim
-- ============================================================================
-- A fork of rest.nvim that allows executing HTTP requests directly from
-- .http files within Neovim. Features include request highlighting,
-- automatic response formatting, cookie management, and environment
-- variable support. Requires LuaRocks dependencies: mimetypes and xml2lua.
--
-- Key UI keybinds:
-- H - Navigate to previous response
-- L - Navigate to next response
-- ============================================================================
return {
"CarGDev/rest.nvim",
build = function()
-- Install LuaRocks dependencies for Lua 5.1 (Neovim uses LuaJIT which is Lua 5.1 compatible)
local packages = { "mimetypes", "xml2lua" }
for _, pkg in ipairs(packages) do
local result = vim.fn.system("luarocks install --local --lua-version=5.1 " .. pkg .. " 2>&1")
if vim.v.shell_error ~= 0 and not result:match("already installed") then
vim.notify("Warning: Failed to install " .. pkg .. ": " .. result, vim.log.levels.WARN)
end
end
end,
dependencies = {
"nvim-treesitter/nvim-treesitter",
opts = function(_, opts)
opts.ensure_installed = opts.ensure_installed or {}
table.insert(opts.ensure_installed, "http")
end,
},
config = function()
-- Verify LuaRocks dependencies are available
local function check_dependency(name)
local success = pcall(require, name)
if not success then
vim.notify(
string.format(
"rest.nvim: Missing dependency '%s'. Please run: luarocks install --local %s",
name,
name
),
vim.log.levels.WARN
)
end
return success
end
-- Check for required dependencies
check_dependency("mimetypes")
check_dependency("xml2lua")
-- Basic configuration for rest.nvim
vim.g.rest_nvim = {
-- Enable request highlighting
highlight = {
enable = true,
timeout = 750,
},
-- Enable response formatting
response = {
hooks = {
format = true,
decode_url = true,
},
},
-- Enable cookies
cookies = {
enable = true,
},
-- Enable environment variables
env = {
enable = true,
pattern = ".*%.env.*",
},
-- UI configuration
ui = {
winbar = true,
keybinds = {
prev = "H",
next = "L",
},
},
}
end,
}

View File

@@ -88,7 +88,9 @@ return {
require("mason-nvim-dap").setup({
ensure_installed = { "python", "js", "javadbg", "javatest" },
automatic_installation = true,
handlers = {},
handlers = {
firefox = function() end, -- Disable Firefox auto-config for TS/JS
},
})
-- 🔍 Virtual Text
@@ -232,6 +234,20 @@ return {
}
dap.configurations.typescript = {
{
name = "Launch with Bun",
type = "pwa-node",
request = "launch",
runtimeExecutable = "bun",
runtimeArgs = { "--inspect-brk" },
program = "${file}",
cwd = "${workspaceFolder}",
sourceMaps = true,
resolveSourceMapLocations = { "${workspaceFolder}/**", "!**/node_modules/**" },
console = "internalConsole",
skipFiles = { "<node_internals>/**", "node_modules/**" },
attachSimplePort = 6499,
},
{
name = "Launch NestJS (dist/main.js)",
type = "pwa-node",
@@ -245,7 +261,7 @@ return {
skipFiles = { "<node_internals>/**", "node_modules/**" },
},
{
name = "Launch Current File",
name = "Launch Current File (Node)",
type = "pwa-node",
request = "launch",
program = "${file}",
@@ -289,6 +305,74 @@ return {
},
}
-- 🎮 DAP Keymaps (registered here so dap/dapui are already loaded)
keymap("n", "<leader>dcr", dap.continue, { desc = "▶ Start Debugging" })
keymap("n", "<leader>do", dap.step_over, { desc = "⏭ Step Over" })
keymap("n", "<leader>di", dap.step_into, { desc = "⤵ Step Into" })
keymap("n", "<leader>dot", dap.step_out, { desc = "⤴ Step Out" })
keymap("n", "<leader>db", dap.toggle_breakpoint, { desc = "🔴 Toggle Breakpoint" })
keymap("n", "<leader>dB", function()
dap.set_breakpoint(fn.input("Breakpoint condition: "))
end, { desc = "⚠ Conditional Breakpoint" })
keymap("n", "<leader>dr", dap.repl.open, { desc = "💬 Open REPL" })
keymap("n", "<leader>dl", dap.run_last, { desc = "🔁 Run Last Debug" })
keymap("n", "<leader>du", dapui.toggle, { desc = "🧩 Toggle DAP UI" })
keymap("n", "<leader>dq", dap.terminate, { desc = "⛔ Stop Debugging" })
keymap("n", "<leader>drt", function()
dap.terminate()
dapui.close()
vim.defer_fn(function()
dapui.open()
end, 200)
end, { desc = "🧼 Reset DAP UI Layout" })
keymap("n", "<leader>dcf", function()
local ft = vim.bo.filetype
local configs = dap.configurations[ft] or {}
if #configs == 0 then
vim.notify("No DAP configurations for filetype: " .. ft, vim.log.levels.WARN)
return
end
vim.ui.select(configs, {
prompt = "Select DAP configuration:",
format_item = function(item) return item.name end,
}, function(config)
if config then dap.run(config) end
end)
end, { desc = "🔭 DAP Configs" })
keymap("n", "<leader>dcb", function()
dap.list_breakpoints()
vim.cmd("copen")
end, { desc = "🧷 List Breakpoints" })
keymap("n", "<leader>dco", dap.repl.open, { desc = "⚙️ DAP Commands" })
-- 🔌 Dynamic Debug Attach (no hardcoded ports)
-- Bun requires --inspect=host:port/debug to set a known WebSocket path
-- because it doesn't implement /json/list for auto-discovery.
keymap("n", "<leader>jd", function()
vim.ui.input({ prompt = "Inspector port (default 6499): " }, function(input)
if input == nil then return end -- cancelled
local port = input ~= "" and input or "6499"
local port_num = tonumber(port)
if not port_num then
vim.notify("Invalid port number", vim.log.levels.ERROR)
return
end
local ws_url = "ws://localhost:" .. port .. "/debug"
vim.notify("Attaching to " .. ws_url, vim.log.levels.INFO)
dap.run({
name = "Attach (" .. ws_url .. ")",
type = "pwa-node",
request = "attach",
websocketAddress = ws_url,
cwd = fn.getcwd(),
sourceMaps = true,
resolveSourceMapLocations = { "${workspaceFolder}/**", "!**/node_modules/**" },
skipFiles = { "<node_internals>/**", "node_modules/**" },
restart = true,
})
end)
end, { desc = "🔌 Debug Attach (dynamic)" })
-- JavaScript uses same configurations as TypeScript
dap.configurations.javascript = {
{
@@ -309,5 +393,9 @@ return {
skipFiles = { "<node_internals>/**", "node_modules/**" },
},
}
-- TSX/JSX use the same configurations as their base languages
dap.configurations.typescriptreact = dap.configurations.typescript
dap.configurations.javascriptreact = dap.configurations.javascript
end,
}

View File

@@ -1,48 +0,0 @@
-- ============================================================================
-- EDGY: Window layout management
-- ============================================================================
-- Manages fixed window layouts for sidebars and panels (file tree, outline, etc.).
-- Keeps special windows docked at consistent positions and sizes.
-- Configures NvimTree (left), Outline (right), and various bottom panels.
-- ============================================================================
return {
"folke/edgy.nvim",
event = "VeryLazy",
opts = {
left = {
{
ft = "NvimTree",
size = { width = 35 },
},
},
right = {
{
ft = "Outline",
size = { width = 30 },
},
},
bottom = {
{
ft = "snacks_terminal",
size = { height = 0.25 },
},
{
ft = "trouble",
size = { height = 0.25 },
},
{
ft = "qf",
size = { height = 0.2 },
},
},
animate = { enabled = false },
exit_when_last = true,
wo = {
winbar = false,
winfixwidth = true,
winfixheight = false,
signcolumn = "no",
},
},
}

View File

@@ -1,61 +0,0 @@
-- ============================================================================
-- FLASH: Fast navigation with search labels
-- ============================================================================
-- Enhanced motion plugin - type a few chars, then jump directly to any match
-- using labeled hints. Works across windows. Press 's' to start flash jump,
-- or use with 'f', 't' motions. Much faster than repeated w/b movements.
-- ============================================================================
return {
"folke/flash.nvim",
event = "VeryLazy",
opts = {
labels = "asdfghjklqwertyuiopzxcvbnm",
search = {
multi_window = true,
forward = true,
wrap = true,
},
jump = {
jumplist = true,
pos = "start",
history = false,
register = false,
nohlsearch = false,
autojump = false,
},
label = {
uppercase = false,
rainbow = {
enabled = true,
shade = 5,
},
},
modes = {
search = {
enabled = false, -- set to true to enable flash in search mode
},
char = {
enabled = true,
jump_labels = true,
multi_line = false,
},
treesitter = {
labels = "asdfghjklqwertyuiopzxcvbnm",
jump = { pos = "range" },
search = { incremental = false },
label = { before = true, after = true, style = "inline" },
highlight = {
backdrop = false,
matches = false,
},
},
},
},
keys = {
{ "s", mode = { "n", "x", "o" }, function() require("flash").jump() end, desc = "Flash" },
{ "S", mode = { "n", "x", "o" }, function() require("flash").treesitter() end, desc = "Flash Treesitter" },
{ "r", mode = "o", function() require("flash").remote() end, desc = "Remote Flash" },
{ "R", mode = { "o", "x" }, function() require("flash").treesitter_search() end, desc = "Treesitter Search" },
{ "<c-s>", mode = { "c" }, function() require("flash").toggle() end, desc = "Toggle Flash Search" },
},
}

View File

@@ -45,7 +45,8 @@ return {
lua = { "stylua" },
python = { "isort", "black" },
sql = { "sqlfluff" }, -- SQL formatting
java = { "google-java-format" },
-- java: no conform formatter (google-java-format needs JDK 21+)
-- falls through to JDTLS LSP via lsp_fallback = true
},
format_on_save = function(bufnr)
-- Disable autoformat for certain filetypes

View File

@@ -88,7 +88,7 @@ return {
end,
})
keymap.set("n", "<leader>l", function()
keymap.set("n", "<leader>lf", function()
lint.try_lint()
end, { desc = "Trigger linting for current file" })
end,

View File

@@ -75,6 +75,7 @@ return {
}),
-- sources for autocompletion
sources = cmp.config.sources({
{ name = "copilot", priority = 1100, group_index = 1 }, -- Copilot suggestions in menu
{ name = "nvim_lsp", priority = 1000 },
{ name = "luasnip", priority = 750 }, -- snippets
{ name = "buffer", priority = 500, keyword_length = 3 }, -- text within current buffer
@@ -86,6 +87,7 @@ return {
format = lspkind.cmp_format({
maxwidth = 50,
ellipsis_char = "...",
symbol_map = { Copilot = "" },
}),
},

View File

@@ -0,0 +1,53 @@
-- ============================================================================
-- OBSIDIAN: Full Obsidian vault integration for Neovim
-- ============================================================================
-- Wiki-link completion, daily notes, templates, backlinks, Telescope search,
-- and more. Replaces the custom follow_obsidian_link() function.
-- ============================================================================
return {
"epwalsh/obsidian.nvim",
version = "*",
dependencies = {
"nvim-lua/plenary.nvim",
"hrsh7th/nvim-cmp",
"nvim-telescope/telescope.nvim",
},
event = {
"BufReadPre " .. vim.fn.expand("~") .. "/Nextcloud/ObsidianVault/**.md",
"BufNewFile " .. vim.fn.expand("~") .. "/Nextcloud/ObsidianVault/**.md",
},
ft = "markdown",
keys = {
{ "<leader>on", "<cmd>ObsidianNew<cr>", desc = "New note" },
{ "<leader>od", "<cmd>ObsidianToday<cr>", desc = "Today's daily note" },
{ "<leader>os", "<cmd>ObsidianSearch<cr>", desc = "Search notes" },
{ "<leader>ob", "<cmd>ObsidianBacklinks<cr>", desc = "Show backlinks" },
{ "<leader>ot", "<cmd>ObsidianTemplate<cr>", desc = "Insert template" },
{ "<leader>of", "<cmd>ObsidianFollowLink<cr>", desc = "Follow link" },
{ "<leader>ol", "<cmd>ObsidianLink<cr>", mode = "v", desc = "Link selection to note" },
},
opts = {
workspaces = {
{
name = "vault",
path = "/Users/carlos/Nextcloud/ObsidianVault",
},
},
daily_notes = {
folder = "daily",
date_format = "%Y-%m-%d",
},
templates = {
folder = "templates",
},
completion = {
nvim_cmp = true,
min_chars = 2,
},
preferred_link_style = "wiki",
use_advanced_uri = false,
picker = {
name = "telescope.nvim",
},
},
}

View File

@@ -0,0 +1,149 @@
--- detect_keymap_conflicts.lua
--- Detects duplicate keymap bindings across neovim config files.
--- Run from the nvim config root: lua scripts/detect_keymap_conflicts.lua
local handle = io.popen("find lua -name '*.lua' -print")
if not handle then
print("Error: could not search for lua files")
os.exit(1)
end
local files = {}
for path in handle:lines() do
files[#files + 1] = path
end
handle:close()
--- Build a lookup table: line_starts[i] = byte position where line i begins.
local function build_line_index(content)
local starts = { 1 }
for i = 1, #content do
if content:sub(i, i) == "\n" then
starts[#starts + 1] = i + 1
end
end
return starts
end
--- Binary search to find the line number for a byte position.
local function line_at(line_starts, pos)
local lo, hi = 1, #line_starts
while lo < hi do
local mid = math.floor((lo + hi + 1) / 2)
if line_starts[mid] <= pos then
lo = mid
else
hi = mid - 1
end
end
return lo
end
--- Return true if `pos` sits after a "--" comment marker on the same line.
local function is_in_comment(content, line_starts, pos)
local ln = line_at(line_starts, pos)
local line_start = line_starts[ln]
local before = content:sub(line_start, pos - 1)
return before:match("%-%-") ~= nil
end
--- Split a mode argument into individual mode strings.
--- "n" -> {"n"}, {"n", "v"} -> {"n", "v"}
local function extract_modes(mode_arg)
local modes = {}
for m in mode_arg:gmatch([=["([^"]+)"]=]) do
modes[#modes + 1] = m
end
if #modes == 0 then
for m in mode_arg:gmatch("'([^']+)'") do
modes[#modes + 1] = m
end
end
if #modes == 0 then
local trimmed = mode_arg:gsub("^%s+", ""):gsub("%s+$", "")
if #trimmed > 0 then
modes[#modes + 1] = trimmed
end
end
return modes
end
-- Patterns to match keymap setter calls.
-- Two variants per caller style: single-string mode and table mode.
-- Using [=[...]=] to avoid issues with ]] inside patterns.
-- () captures the byte position for line-number lookup.
local patterns = {
-- vim.keymap.set("n", "<key>", ...)
[=[()vim%.keymap%.set%(%s*["']([^"']+)["']%s*,%s*["']([^"']+)["']]=],
-- vim.keymap.set({"n", "v"}, "<key>", ...)
[=[()vim%.keymap%.set%(%s*(%b{})%s*,%s*["']([^"']+)["']]=],
-- keymap.set("n", "<key>", ...)
[=[()keymap%.set%(%s*["']([^"']+)["']%s*,%s*["']([^"']+)["']]=],
-- keymap.set({"n", "v"}, "<key>", ...)
[=[()keymap%.set%(%s*(%b{})%s*,%s*["']([^"']+)["']]=],
-- keymap("n", "<key>", ...) — when local keymap = vim.keymap.set
[=[()keymap%(%s*["']([^"']+)["']%s*,%s*["']([^"']+)["']]=],
-- keymap({"n", "v"}, "<key>", ...)
[=[()keymap%(%s*(%b{})%s*,%s*["']([^"']+)["']]=],
-- map("n", "<key>", ...) — wrapper function
[=[()map%(%s*["']([^"']+)["']%s*,%s*["']([^"']+)["']]=],
-- map({"n", "v"}, "<key>", ...)
[=[()map%(%s*(%b{})%s*,%s*["']([^"']+)["']]=],
}
local keymaps = {} -- "mode|lhs" -> list of "file:line"
local seen = {} -- dedup: "file:line:lhs" -> true
for _, f in ipairs(files) do
local fh = io.open(f, "r")
if fh then
-- Read entire file so patterns can span multiple lines (%s matches \n).
local content = fh:read("*a")
fh:close()
local line_starts = build_line_index(content)
for _, pat in ipairs(patterns) do
for pos, mode_arg, lhs in content:gmatch(pat) do
if not is_in_comment(content, line_starts, pos) then
local ln = line_at(line_starts, pos)
local dedup_key = f .. ":" .. ln .. ":" .. lhs
if not seen[dedup_key] then
seen[dedup_key] = true
local modes = extract_modes(mode_arg)
for _, mode in ipairs(modes) do
local key = mode .. "|" .. lhs
keymaps[key] = keymaps[key] or {}
keymaps[key][#keymaps[key] + 1] = string.format("%s:%d", f, ln)
end
end
end
end
end
end
end
-- Collect and sort conflicts
local conflicts = {}
for key, locations in pairs(keymaps) do
if #locations > 1 then
local mode, lhs = key:match("^(.-)|(.*)")
conflicts[#conflicts + 1] = { mode = mode, lhs = lhs, locations = locations }
end
end
table.sort(conflicts, function(a, b)
if a.mode == b.mode then return a.lhs < b.lhs end
return a.mode < b.mode
end)
if #conflicts == 0 then
print("No duplicate keymaps found.")
else
print(string.format("Found %d conflicting keymap(s):\n", #conflicts))
for _, c in ipairs(conflicts) do
print(string.format(" [%s] %s", c.mode, c.lhs))
for _, loc in ipairs(c.locations) do
print(" - " .. loc)
end
print()
end
end