Compare commits

...
Sign in to create a new pull request.

7 commits

Author SHA1 Message Date
Claude
a1eb8dc2ba
feat(nvim): add testing and debugging support
Add neotest for running tests:
- Jest adapter for Angular/JS/TS
- Python adapter with pytest support
- Rust adapter via rustaceanvim
- Keymaps: <leader>t* for test operations

Add nvim-dap for debugging:
- Python with debugpy (auto-detects venv)
- JavaScript/TypeScript with js-debug-adapter
- Chrome debugging for Angular (port 4200)
- Rust via codelldb (rustaceanvim integration)
- DAP UI with auto-open on debug start
- Keymaps: <leader>d* for debug operations

https://claude.ai/code/session_01UcDoC4n6CWMttYFJPw17ie
2026-01-31 12:26:03 +00:00
Claude
f25236fe40
feat(lazygit): add config with ctrl+j/k scroll keybindings
- Add lazygit to .gitignore allowlist
- Configure <C-j>/<C-k> for scrolling main panel

https://claude.ai/code/session_01UcDoC4n6CWMttYFJPw17ie
2026-01-31 09:15:35 +00:00
Claude
71571ef613
fix(nvim): move hover scroll keymaps to noice config
Move <C-j>/<C-k> scroll keymaps from LspAttach to noice plugin
keys for proper global binding that works with noice hover windows

https://claude.ai/code/session_01UcDoC4n6CWMttYFJPw17ie
2026-01-31 09:09:39 +00:00
Claude
c8336a73ac
feat(nvim): add scrollable hover docs with rounded border
- Configure K to show hover docs in floating window with rounded border
- Add <C-j>/<C-k> keymaps to scroll hover documentation
- Enable lsp_doc_border in noice for consistent styling

https://claude.ai/code/session_01UcDoC4n6CWMttYFJPw17ie
2026-01-31 09:02:59 +00:00
Claude
9ff2996863
feat(nvim): use Telescope for go-to-declaration
All LSP navigation keymaps now use Telescope floating picker:
- gd: definitions
- gD: declarations
- gR: references
- gi: implementations
- gt: type definitions

https://claude.ai/code/session_01UcDoC4n6CWMttYFJPw17ie
2026-01-31 08:56:08 +00:00
Claude
71401aefa9
feat(nvim): use Telescope for go-to-definition
Show definitions in floating picker instead of quickfix list
for consistent UX with references/implementations keymaps

https://claude.ai/code/session_01UcDoC4n6CWMttYFJPw17ie
2026-01-31 08:53:08 +00:00
Claude
3ef592767b
feat(nvim): show diagnostics in popup instead of inline
- Disable virtual_text to remove inline diagnostic hints
- Configure float with rounded border and source info
- Diagnostics now appear in popup via <leader>d or when navigating with [d/]d

https://claude.ai/code/session_01UcDoC4n6CWMttYFJPw17ie
2026-01-31 08:30:21 +00:00
7 changed files with 474 additions and 4 deletions

View file

@ -0,0 +1,6 @@
keybinding:
universal:
scrollUpMain: '<c-k>'
scrollDownMain: '<c-j>'
scrollUpMain-alt1: '<pgup>'
scrollDownMain-alt1: '<pgdown>'

View file

@ -11,10 +11,10 @@ vim.api.nvim_create_autocmd('LspAttach', {
keymap.set('n', 'gR', '<cmd>Telescope lsp_references<CR>', opts) -- show definition, references
opts.desc = 'Go to declaration'
keymap.set('n', 'gD', vim.lsp.buf.declaration, opts) -- go to declaration
keymap.set('n', 'gD', '<cmd>Telescope lsp_declarations<CR>', opts) -- go to declaration
opts.desc = 'Show LSP definition'
keymap.set('n', 'gd', vim.lsp.buf.definition, opts) -- show lsp definition
keymap.set('n', 'gd', '<cmd>Telescope lsp_definitions<CR>', opts) -- show lsp definition
opts.desc = 'Show LSP implementations'
keymap.set('n', 'gi', '<cmd>Telescope lsp_implementations<CR>', opts) -- show lsp implementations
@ -45,7 +45,9 @@ vim.api.nvim_create_autocmd('LspAttach', {
end, opts) -- jump to next diagnostic in buffer
opts.desc = 'Show documentation for what is under cursor'
keymap.set('n', 'K', vim.lsp.buf.hover, opts) -- show documentation for what is under cursor
keymap.set('n', 'K', function()
vim.lsp.buf.hover { border = 'rounded' }
end, opts)
opts.desc = 'Restart LSP'
keymap.set('n', '<leader>rs', ':LspRestart<CR>', opts) -- mapping to restart lsp if necessary
@ -57,6 +59,11 @@ vim.lsp.inlay_hint.enable(true)
local severity = vim.diagnostic.severity
vim.diagnostic.config {
virtual_text = false, -- Disable inline diagnostics
float = {
border = 'rounded',
source = true, -- Show diagnostic source
},
signs = {
text = {
[severity.ERROR] = '',

View file

@ -0,0 +1,307 @@
return {
'mfussenegger/nvim-dap',
dependencies = {
-- UI
{
'rcarriga/nvim-dap-ui',
dependencies = { 'nvim-neotest/nvim-nio' },
keys = {
{
'<leader>du',
function()
require('dapui').toggle {}
end,
desc = 'Toggle DAP UI',
},
{
'<leader>de',
function()
require('dapui').eval()
end,
mode = { 'n', 'v' },
desc = 'Eval expression',
},
},
opts = {},
config = function(_, opts)
local dap = require 'dap'
local dapui = require 'dapui'
dapui.setup(opts)
dap.listeners.after.event_initialized['dapui_config'] = function()
dapui.open {}
end
dap.listeners.before.event_terminated['dapui_config'] = function()
dapui.close {}
end
dap.listeners.before.event_exited['dapui_config'] = function()
dapui.close {}
end
end,
},
-- Virtual text for variable values
{
'theHamsta/nvim-dap-virtual-text',
opts = {},
},
-- Mason integration for installing debug adapters
{
'jay-babu/mason-nvim-dap.nvim',
dependencies = 'mason.nvim',
cmd = { 'DapInstall', 'DapUninstall' },
opts = {
automatic_installation = true,
handlers = {},
ensure_installed = {
'python',
'js',
'codelldb',
},
},
},
},
keys = {
{
'<leader>dB',
function()
require('dap').set_breakpoint(vim.fn.input 'Breakpoint condition: ')
end,
desc = 'Conditional breakpoint',
},
{
'<leader>db',
function()
require('dap').toggle_breakpoint()
end,
desc = 'Toggle breakpoint',
},
{
'<leader>dc',
function()
require('dap').continue()
end,
desc = 'Continue',
},
{
'<leader>dC',
function()
require('dap').run_to_cursor()
end,
desc = 'Run to cursor',
},
{
'<leader>dg',
function()
require('dap').goto_()
end,
desc = 'Go to line (no execute)',
},
{
'<leader>di',
function()
require('dap').step_into()
end,
desc = 'Step into',
},
{
'<leader>dj',
function()
require('dap').down()
end,
desc = 'Down in stack',
},
{
'<leader>dk',
function()
require('dap').up()
end,
desc = 'Up in stack',
},
{
'<leader>dl',
function()
require('dap').run_last()
end,
desc = 'Run last',
},
{
'<leader>do',
function()
require('dap').step_out()
end,
desc = 'Step out',
},
{
'<leader>dO',
function()
require('dap').step_over()
end,
desc = 'Step over',
},
{
'<leader>dp',
function()
require('dap').pause()
end,
desc = 'Pause',
},
{
'<leader>dr',
function()
require('dap').repl.toggle()
end,
desc = 'Toggle REPL',
},
{
'<leader>ds',
function()
require('dap').session()
end,
desc = 'Session',
},
{
'<leader>dt',
function()
require('dap').terminate()
end,
desc = 'Terminate',
},
{
'<leader>dw',
function()
require('dap.ui.widgets').hover()
end,
desc = 'Widgets',
},
},
config = function()
local dap = require 'dap'
-- Signs
vim.fn.sign_define('DapBreakpoint', { text = '', texthl = 'DiagnosticError', linehl = '', numhl = '' })
vim.fn.sign_define('DapBreakpointCondition', { text = '', texthl = 'DiagnosticWarn', linehl = '', numhl = '' })
vim.fn.sign_define('DapLogPoint', { text = '', texthl = 'DiagnosticInfo', linehl = '', numhl = '' })
vim.fn.sign_define('DapStopped', { text = '', texthl = 'DiagnosticOk', linehl = 'DapStoppedLine', numhl = '' })
vim.fn.sign_define('DapBreakpointRejected', { text = '', texthl = 'DiagnosticError', linehl = '', numhl = '' })
-- Highlight for stopped line
vim.api.nvim_set_hl(0, 'DapStoppedLine', { default = true, link = 'Visual' })
-- Python configuration
dap.adapters.python = function(cb, config)
if config.request == 'attach' then
local port = (config.connect or config).port
local host = (config.connect or config).host or '127.0.0.1'
cb {
type = 'server',
port = assert(port, '`connect.port` is required for a python `attach` configuration'),
host = host,
options = {
source_filetype = 'python',
},
}
else
cb {
type = 'executable',
command = vim.fn.exepath 'python3',
args = { '-m', 'debugpy.adapter' },
options = {
source_filetype = 'python',
},
}
end
end
dap.configurations.python = {
{
type = 'python',
request = 'launch',
name = 'Launch file',
program = '${file}',
pythonPath = function()
local cwd = vim.fn.getcwd()
if vim.fn.executable(cwd .. '/venv/bin/python') == 1 then
return cwd .. '/venv/bin/python'
elseif vim.fn.executable(cwd .. '/.venv/bin/python') == 1 then
return cwd .. '/.venv/bin/python'
else
return vim.fn.exepath 'python3'
end
end,
},
{
type = 'python',
request = 'launch',
name = 'Launch file with arguments',
program = '${file}',
args = function()
local args_string = vim.fn.input 'Arguments: '
return vim.split(args_string, ' +')
end,
pythonPath = function()
local cwd = vim.fn.getcwd()
if vim.fn.executable(cwd .. '/venv/bin/python') == 1 then
return cwd .. '/venv/bin/python'
elseif vim.fn.executable(cwd .. '/.venv/bin/python') == 1 then
return cwd .. '/.venv/bin/python'
else
return vim.fn.exepath 'python3'
end
end,
},
}
-- JavaScript/TypeScript configuration
local js_debug_path = vim.fn.stdpath 'data' .. '/mason/packages/js-debug-adapter'
dap.adapters['pwa-node'] = {
type = 'server',
host = 'localhost',
port = '${port}',
executable = {
command = 'node',
args = { js_debug_path .. '/js-debug/src/dapDebugServer.js', '${port}' },
},
}
dap.adapters['pwa-chrome'] = {
type = 'server',
host = 'localhost',
port = '${port}',
executable = {
command = 'node',
args = { js_debug_path .. '/js-debug/src/dapDebugServer.js', '${port}' },
},
}
local js_config = {
{
type = 'pwa-node',
request = 'launch',
name = 'Launch file',
program = '${file}',
cwd = '${workspaceFolder}',
},
{
type = 'pwa-node',
request = 'attach',
name = 'Attach to process',
processId = require('dap.utils').pick_process,
cwd = '${workspaceFolder}',
},
{
type = 'pwa-chrome',
request = 'launch',
name = 'Launch Chrome',
url = 'http://localhost:4200', -- Angular default port
webRoot = '${workspaceFolder}',
},
}
dap.configurations.javascript = js_config
dap.configurations.typescript = js_config
dap.configurations.javascriptreact = js_config
dap.configurations.typescriptreact = js_config
-- Rust/C/C++ uses codelldb (configured via rustaceanvim)
end,
}

View file

@ -57,10 +57,12 @@ return {
'ast_grep',
'cbfmt',
'csharpier',
'debugpy',
'editorconfig-checker',
'eslint_d',
'goimports',
'hadolint',
'js-debug-adapter',
'luacheck',
'prettier',
'prettierd',

View file

@ -0,0 +1,123 @@
return {
'nvim-neotest/neotest',
dependencies = {
'nvim-neotest/nvim-nio',
'nvim-lua/plenary.nvim',
'antoinemadec/FixCursorHold.nvim',
'nvim-treesitter/nvim-treesitter',
-- Adapters
'nvim-neotest/neotest-jest',
'nvim-neotest/neotest-python',
-- Rust uses rustaceanvim's built-in neotest adapter
},
keys = {
{
'<leader>tt',
function()
require('neotest').run.run()
end,
desc = 'Run nearest test',
},
{
'<leader>tf',
function()
require('neotest').run.run(vim.fn.expand '%')
end,
desc = 'Run current file tests',
},
{
'<leader>ta',
function()
require('neotest').run.run(vim.uv.cwd())
end,
desc = 'Run all tests',
},
{
'<leader>ts',
function()
require('neotest').summary.toggle()
end,
desc = 'Toggle test summary',
},
{
'<leader>to',
function()
require('neotest').output.open { enter = true, auto_close = true }
end,
desc = 'Show test output',
},
{
'<leader>tO',
function()
require('neotest').output_panel.toggle()
end,
desc = 'Toggle output panel',
},
{
'<leader>tS',
function()
require('neotest').run.stop()
end,
desc = 'Stop test run',
},
{
'<leader>tw',
function()
require('neotest').watch.toggle(vim.fn.expand '%')
end,
desc = 'Toggle test watch',
},
{
'<leader>td',
function()
require('neotest').run.run { strategy = 'dap' }
end,
desc = 'Debug nearest test',
},
{
'[t',
function()
require('neotest').jump.prev { status = 'failed' }
end,
desc = 'Previous failed test',
},
{
']t',
function()
require('neotest').jump.next { status = 'failed' }
end,
desc = 'Next failed test',
},
},
config = function()
require('neotest').setup {
adapters = {
require 'neotest-jest' {
jestCommand = 'npm test --',
jestConfigFile = 'jest.config.js',
env = { CI = true },
cwd = function()
return vim.fn.getcwd()
end,
},
require 'neotest-python' {
dap = { justMyCode = false },
args = { '--log-level', 'DEBUG' },
runner = 'pytest',
},
require 'rustaceanvim.neotest',
},
status = {
virtual_text = true,
},
output = {
open_on_run = true,
},
quickfix = {
open = function()
vim.cmd 'copen'
end,
},
}
end,
}

View file

@ -17,7 +17,7 @@ return {
command_palette = true, -- position the cmdline and popupmenu together
long_message_to_split = true, -- long messages will be sent to a split
inc_rename = false, -- enables an input dialog for inc-rename.nvim
lsp_doc_border = false, -- add a border to hover docs and signature help
lsp_doc_border = true, -- add a border to hover docs and signature help
},
},
dependencies = {
@ -48,5 +48,29 @@ return {
mode = 'n',
desc = 'Show Noice Message History',
},
{
'<C-j>',
function()
if not require('noice.lsp').scroll(4) then
return '<C-j>'
end
end,
mode = { 'n', 'i', 's' },
silent = true,
expr = true,
desc = 'Scroll hover docs down',
},
{
'<C-k>',
function()
if not require('noice.lsp').scroll(-4) then
return '<C-k>'
end
end,
mode = { 'n', 'i', 's' },
silent = true,
expr = true,
desc = 'Scroll hover docs up',
},
},
}

1
.gitignore vendored
View file

@ -58,6 +58,7 @@ tags
.config/*
!.config/nvim/
!.config/lazygit/
!.config/starship/
!.config/wezterm/
!.config/karabiner/