refactor: Complete modular migration from kickstart.nvim

Major architectural overhaul to transform the flat kickstart.nvim structure
  into a maintainable, modular configuration while preserving upstream sync capability.

  ## Structure Changes
  - Migrated from flat `lua/custom/` to organized `lua/core/` and `lua/plugins/`
  - Separated plugin specs from configs: `lua/plugins/spec/` and `lua/plugins/config/`
  - Complex configs (LSP, Debug) now use directory structure with sub-modules:
    - `lsp/init.lua`, `lsp/servers.lua`, `lsp/keymaps.lua`
    - `debug/init.lua`, `debug/adapters.lua`, `debug/keymaps.lua`

  ## Core Improvements
  - Created dedicated core modules: options, keymaps, autocmds, bootstrap, health
  - Added comprehensive health check (`lua/core/health.lua`) for diagnostics
  - Simplified init.lua to just orchestrate module loading
  - Better separation of concerns throughout

  ## Plugin Updates
  - Fixed Blink.cmp configuration (removed invalid fuzzy options)
  - Integrated Copilot with Blink.cmp for unified completion experience
  - Added autopairs and indent-line from kickstart examples
  - Optimized for Nix development environments (removed venv assumptions)

  ## Documentation
  - Updated README with modular structure and kickstart sync instructions
  - Created comprehensive KEYBIND_ANALYSIS.md with all mappings
  - Added modular.txt help documentation
  - Created TODO_TEST.md checklist for testing

  ## Benefits
  - Easier to maintain and extend
  - Clean separation allows upstream kickstart merges without conflicts
  - Scalable architecture for adding new languages/tools
  - Better code organization and discoverability

  All kickstart functionality preserved while gaining modularity and maintainability.
This commit is contained in:
dlond 2025-09-02 13:21:18 +12:00 committed by Daniel Lond
parent 277be1e79b
commit f81cab2da3
55 changed files with 2039 additions and 2299 deletions

0
lua/core/autocmds.lua Normal file
View file

13
lua/core/bootstrap.lua Normal file
View file

@ -0,0 +1,13 @@
-- Lazy.nvim installation
local lazypath = vim.fn.stdpath 'data' .. '/lazy/lazy.nvim'
if not vim.loop.fs_stat(lazypath) then
vim.fn.system {
'git',
'clone',
'--filter=blob:none',
'https://github.com/folke/lazy.nvim.git',
'--branch=stable',
lazypath,
}
end
vim.opt.rtp:prepend(lazypath)

98
lua/core/health.lua Normal file
View file

@ -0,0 +1,98 @@
-- Health check for the modular Neovim configuration
local M = {}
local check_version = function()
local verstr = tostring(vim.version())
if not vim.version.ge then
vim.health.error(string.format("Neovim out of date: '%s'. Upgrade to latest stable or nightly", verstr))
return
end
if vim.version.ge(vim.version(), '0.10-dev') then
vim.health.ok(string.format("Neovim version is: '%s'", verstr))
else
vim.health.error(string.format("Neovim out of date: '%s'. Upgrade to latest stable or nightly", verstr))
end
end
local check_external_reqs = function()
-- Basic utils
for _, exe in ipairs { 'git', 'make', 'unzip' } do
local is_executable = vim.fn.executable(exe) == 1
if is_executable then
vim.health.ok(string.format("Found executable: '%s'", exe))
else
vim.health.warn(string.format("Could not find executable: '%s'", exe))
end
end
-- Search tools
for _, exe in ipairs { 'rg', 'fd' } do
local is_executable = vim.fn.executable(exe) == 1
if is_executable then
vim.health.ok(string.format("Found search tool: '%s'", exe))
else
vim.health.warn(string.format("Could not find search tool: '%s' (required for Telescope)", exe))
end
end
end
local check_lsp_servers = function()
-- Check for LSP servers installed via Nix
local servers = {
{ name = 'clangd', desc = 'C/C++ language server' },
{ name = 'pyright', desc = 'Python language server' },
{ name = 'ruff', desc = 'Python linter/formatter' },
{ name = 'nixd', desc = 'Nix language server' },
{ name = 'texlab', desc = 'LaTeX language server' },
{ name = 'cmake-language-server', desc = 'CMake language server' },
}
vim.health.start('LSP Servers (via Nix/Home Manager)')
for _, server in ipairs(servers) do
local is_executable = vim.fn.executable(server.name) == 1
if is_executable then
vim.health.ok(string.format("Found %s: '%s'", server.desc, server.name))
else
vim.health.info(string.format("Not found: '%s' (%s) - install via Nix if needed", server.name, server.desc))
end
end
end
local check_formatters = function()
-- Check for formatters installed via Nix
local formatters = {
{ name = 'stylua', filetype = 'lua' },
{ name = 'clang-format', filetype = 'c/cpp' },
{ name = 'alejandra', filetype = 'nix' },
}
vim.health.start('Formatters (via Nix/Home Manager)')
for _, formatter in ipairs(formatters) do
local is_executable = vim.fn.executable(formatter.name) == 1
if is_executable then
vim.health.ok(string.format("Found formatter for %s: '%s'", formatter.filetype, formatter.name))
else
vim.health.info(string.format("Not found: '%s' (%s) - install via Nix if needed", formatter.name, formatter.filetype))
end
end
end
function M.check()
vim.health.start('Modular Neovim Configuration')
vim.health.info [[NOTE: Not every warning needs to be fixed.
Only install tools for languages you actually use.
All language servers and formatters should be installed via Nix/Home Manager.]]
local uv = vim.uv or vim.loop
vim.health.info('System Information: ' .. vim.inspect(uv.os_uname()))
check_version()
check_external_reqs()
check_lsp_servers()
check_formatters()
end
return M

View file

@ -1,29 +0,0 @@
return {
'saghen/blink.cmp',
dependencies = {
"giuxtaposition/blink-cmp-copilot",
},
opts = {
sources = {
default = { "lsp", "path", "copilot", "buffer" },
providers = {
copilot = {
name = "copilot",
module = "blink-cmp-copilot",
score_offset = 100, -- High priority to show Copilot near the top
async = true,
},
},
},
keymap = {
preset = 'default',
accept = '<C-y>', -- Your preferred accept key
},
appearance = {
-- Show source of completion (LSP/Copilot/Buffer)
use_nvim_cmp_as_default = false,
nerd_font_variant = 'mono',
},
fuzzy = {},
},
}

View file

@ -1,35 +0,0 @@
return {
-- Use copilot.lua for API access (no UI)
{
"zbirenbaum/copilot.lua",
cmd = "Copilot",
event = "InsertEnter",
config = function()
require("copilot").setup({
suggestion = { enabled = false }, -- Disable inline ghost text
panel = { enabled = false }, -- Disable suggestion panel
filetypes = {
yaml = false,
markdown = false,
help = false,
gitcommit = false,
gitrebase = false,
hgcommit = false,
svn = false,
cvs = false,
["."] = false,
},
copilot_node_command = 'node', -- Node.js version must be > 18.x
server_opts_overrides = {},
})
end,
},
-- Bridge between copilot.lua and blink.cmp
{
"giuxtaposition/blink-cmp-copilot",
dependencies = {
"zbirenbaum/copilot.lua",
},
},
}

View file

@ -1,157 +0,0 @@
-- ~/dlond/nvim/lua/custom/plugins/debug.lua
-- Debug Adapter Protocol (DAP) setup, integrating kickstart's UI preferences
return {
-- Main DAP plugin
{
'mfussenegger/nvim-dap',
dependencies = {
-- UI for nvim-dap
{
'rcarriga/nvim-dap-ui',
dependencies = { 'nvim-neotest/nvim-nio' }, -- nvim-dap-ui often needs nio
config = function()
local asyn = require 'plenary.async'
local dapui = require 'dapui'
dapui.setup {
-- Borrowed icon and control settings from kickstart/plugins/debug.lua
icons = { expanded = '', collapsed = '', current_frame = '*' },
controls = {
icons = {
pause = '',
play = '',
step_into = '',
step_over = '',
step_out = '',
step_back = 'b', -- Kickstart uses 'b', nvim-dap default might be different
run_last = '▶▶',
terminate = '',
disconnect = '',
},
},
-- You can customize layouts, floating window behavior, etc.
-- layouts = { ... },
-- floating = { ... },
}
-- Automatically open/close dapui when DAP session starts/stops
local dap = require 'dap'
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,
},
-- Optional: Virtual text for DAP (shows variable values inline)
-- { 'theHamsta/nvim-dap-virtual-text', opts = {} },
-- If you need Go debugging, you would add 'leoluz/nvim-dap-go' here
-- and call its setup in the nvim-dap config function.
-- { 'leoluz/nvim-dap-go' },
},
config = function()
local dap = require 'dap'
local dapui = require 'dapui'
local async = require 'plenary.async'
-- Configure the LLDB DAP adapter for C/C++
-- Assumes 'lldb-dap' executable is in PATH (from pkgs.llvmPackages_XX.lldb)
dap.adapters.lldb = {
type = 'executable',
command = 'lldb-dap',
name = 'lldb-dap (Nix)',
}
dap.configurations.cpp = {
{
name = 'Launch C/C++ (lldb-dap)',
type = 'lldb',
request = 'launch',
program = function()
return vim.fn.input('Path to executable: ', vim.fn.getcwd() .. '/', 'file')
-- local utils = require 'custom.utils'
-- local target = utils:get_target()
-- return utils.pick_executable(vim.fn.getcwd() .. '/' .. target)
end,
cwd = '${workspaceFolder}',
stopOnEntry = false,
args = {},
-- Ensure your C/C++ project is compiled with debug symbols (e.g., -g flag with clang/gcc)
},
}
dap.configurations.c = dap.configurations.cpp -- Use same config for C
-- Python DAP configuration (using debugpy)
-- Ensure python3Packages.debugpy is in your home.packages
dap.adapters.python = {
type = 'executable',
command = 'python', -- Should be the python from your Nix env
args = { '-m', 'debugpy.adapter' },
}
dap.configurations.python = {
{
type = 'python',
request = 'launch',
name = 'Launch Python file',
program = '${file}', -- Debug the current file
pythonPath = function()
local venv = os.getenv 'VIRTUAL_ENV'
if venv then
return venv .. '/bin/python'
end
-- Fallback to trying to find python3, then python in PATH
-- This could be made more robust by getting python path from Nix if needed
local py3 = vim.fn.executable 'python3'
if py3 ~= 0 and py3 ~= '' then
return py3
end
return 'python'
end,
},
}
-- If you added 'leoluz/nvim-dap-go' as a dependency:
-- require('dap-go').setup() -- Call its setup function
-- Launch and Control
vim.keymap.set('n', '<leader>dc', function()
async.run(function()
dap.continue()
if not dapui.windows or vim.tbl_isempty(dapui.windows) then
dapui.open()
end
end)
end, { desc = 'DAP: [C]ontinue show UI (async-safe)' })
vim.keymap.set('n', '<leader>db', dap.toggle_breakpoint, { desc = 'DAP: Toggle [B]reakpoint' })
vim.keymap.set('n', '<leader>dl', dap.run_last, { desc = 'DAP: Run [L]ast' })
-- DAP: Stepping
vim.keymap.set('n', '<leader>di', dap.step_into, { desc = 'DAP: Step [I]nto' })
vim.keymap.set('n', '<leader>dk', dap.step_over, { desc = 'DAP: Step [O]ver (k)' })
vim.keymap.set('n', '<leader>do', dap.step_out, { desc = 'DAP: Step [O]ut' })
vim.keymap.set('n', '<leader>dx', function()
async.run(function()
dap.run_to_cursor()
end)
end, { desc = 'DAP: Run to Cursor (x) (asyn-safe)' })
-- DAP: Termination
vim.keymap.set('n', '<leader>dt', function()
async.run(function()
dap.terminate()
dapui.close()
end)
end, { desc = 'DAP: [T]erminate (async-safe)' })
-- DAP: UI
vim.keymap.set('n', '<leader>dr', dap.repl.open, { desc = 'DAP: Open [R]EPL' })
vim.keymap.set('n', '<leader>du', dapui.toggle, { desc = 'DAP: Toggle [U]I' })
end,
},
}

View file

@ -1,73 +0,0 @@
return {
-- Fugitive - Git integration
{
'tpope/vim-fugitive',
cmd = { 'Git', 'G', 'Gdiff', 'Gread', 'Gwrite', 'Ggrep', 'GMove', 'GDelete', 'GBrowse', 'GRemove' },
keys = {
{ '<leader>gs', '<cmd>Git<cr>', desc = 'Git status' },
{ '<leader>gd', '<cmd>Gdiff<cr>', desc = 'Git diff' },
{ '<leader>gc', '<cmd>Git commit<cr>', desc = 'Git commit' },
{ '<leader>gb', '<cmd>Git blame<cr>', desc = 'Git blame' },
{ '<leader>gl', '<cmd>Git log<cr>', desc = 'Git log' },
{ '<leader>gp', '<cmd>Git push<cr>', desc = 'Git push' },
{ '<leader>gf', '<cmd>Git fetch<cr>', desc = 'Git fetch' },
},
},
-- Gitsigns - Git gutter and hunk operations
{
'lewis6991/gitsigns.nvim',
opts = {
signs = {
add = { text = '+' },
change = { text = '~' },
delete = { text = '_' },
topdelete = { text = '' },
changedelete = { text = '~' },
},
on_attach = function(bufnr)
local gitsigns = require('gitsigns')
local function map(mode, l, r, opts)
opts = opts or {}
opts.buffer = bufnr
vim.keymap.set(mode, l, r, opts)
end
-- Navigation
map('n', ']c', function()
if vim.wo.diff then
vim.cmd.normal({']c', bang = true})
else
gitsigns.nav_hunk('next')
end
end, { desc = 'Next git hunk' })
map('n', '[c', function()
if vim.wo.diff then
vim.cmd.normal({'[c', bang = true})
else
gitsigns.nav_hunk('prev')
end
end, { desc = 'Previous git hunk' })
-- Actions
map('n', '<leader>hs', gitsigns.stage_hunk, { desc = 'Stage hunk' })
map('n', '<leader>hr', gitsigns.reset_hunk, { desc = 'Reset hunk' })
map('v', '<leader>hs', function() gitsigns.stage_hunk {vim.fn.line('.'), vim.fn.line('v')} end, { desc = 'Stage hunk' })
map('v', '<leader>hr', function() gitsigns.reset_hunk {vim.fn.line('.'), vim.fn.line('v')} end, { desc = 'Reset hunk' })
map('n', '<leader>hS', gitsigns.stage_buffer, { desc = 'Stage buffer' })
map('n', '<leader>hu', gitsigns.undo_stage_hunk, { desc = 'Undo stage hunk' })
map('n', '<leader>hR', gitsigns.reset_buffer, { desc = 'Reset buffer' })
map('n', '<leader>hp', gitsigns.preview_hunk, { desc = 'Preview hunk' })
map('n', '<leader>hb', function() gitsigns.blame_line{full=true} end, { desc = 'Blame line' })
map('n', '<leader>tb', gitsigns.toggle_current_line_blame, { desc = 'Toggle line blame' })
map('n', '<leader>hd', gitsigns.diffthis, { desc = 'Diff this' })
map('n', '<leader>hD', function() gitsigns.diffthis('~') end, { desc = 'Diff this ~' })
map('n', '<leader>td', gitsigns.toggle_deleted, { desc = 'Toggle deleted' })
-- Text object
map({'o', 'x'}, 'ih', ':<C-U>Gitsigns select_hunk<CR>', { desc = 'Select hunk' })
end,
},
},
}

View file

@ -1,17 +0,0 @@
-- You can add your own plugins here or in other files in this directory!
-- I promise not to create any merge conflicts in this directory :)
--
-- See the kickstart.nvim README for more information
return {
-- { import = 'custom.plugins.completion' },
-- { import = 'custom.plugins.theme' },
-- { import = 'custom.plugins.avante' },
{ import = 'custom.plugins.copilot' },
{ import = 'custom.plugins.debug' },
{ import = 'custom.plugins.formatting' },
{ import = 'custom.plugins.git' },
{ import = 'custom.plugins.lsp' },
{ import = 'custom.plugins.nvim-tmux-navigator' },
{ import = 'custom.plugins.telescope' },
{ import = 'custom.plugins.treesitter' },
}

View file

@ -1,3 +0,0 @@
return {
require 'custom.plugins.lsp.lsp',
}

View file

@ -1,91 +0,0 @@
-- ~/dlond/nvim/lua/custom/plugins/lsp.lua
-- LSP configuration, assuming LSP servers are installed via Nix/Home Manager
return {
{
'neovim/nvim-lspconfig',
-- only load when editing these filetypes (optional)
ft = {
'c',
'cpp',
'objc',
'objcpp',
'cuda',
'cmake',
--
'go',
'nix',
'python',
'rust',
'tex',
},
opts = function()
local lspconfig = require 'lspconfig'
local capabilities = {}
pcall(function()
capabilities = require('blink.cmp').get_lsp_capabilities()
end)
local util = require 'lspconfig.util'
local query_driver = table.concat({
'/nix/store/*/bin/clang*',
'/opt/homebrew/opt/llvm/bin/clang*',
'/usr/bin/clang*',
}, ';')
local servers = {
clangd = {
cmd = {
'clangd',
'--background-index',
'--clang-tidy',
'--header-insertion=never',
'--query-driver=' .. query_driver,
'--compile-commands-dir=build',
'--resource-dir=' .. (function()
local ok, result = pcall(vim.fn.systemlist, { 'clang++', '--print-resource-dir' })
if ok and result and result[1] then
return result[1]
else
return '/usr/lib/clang/19/include' -- fallback
end
end)(),
},
filetypes = { 'c', 'cpp', 'objc', 'objcpp', 'cuda' },
root_dir = util.root_pattern('CMakeLists.txt', '.git'),
single_file_support = true,
},
pyright = {
settings = {
python = {
analysis = {
autoSearchPaths = true,
diagnosticMode = 'openFilesOnly',
useLibraryCodeForTypes = true,
typeCheckingMode = 'basic',
},
},
},
positionEncoding = 'utf-8',
},
ruff = {},
nixd = {},
texlab = {},
cmake = {
cmd = { 'cmake-language-server' },
filetypes = { 'cmake' },
root_dir = util.root_pattern('CMakeLists.txt', '.git'),
},
}
for name, config in pairs(servers) do
config.capabilities = vim.tbl_deep_extend('force', {}, capabilities, config.capabilities or {})
lspconfig[name].setup(config)
end
end,
},
}

View file

@ -1,11 +0,0 @@
return {
{
'christoomey/vim-tmux-navigator',
config = function()
vim.keymap.set('n', '<C-h>', ':TmuxNavigateLeft<CR>', { desc = 'Navigate to left tmux pane' })
vim.keymap.set('n', '<C-j>', ':TmuxNavigateDown<CR>', { desc = 'Navigate to lower tmux pane' })
vim.keymap.set('n', '<C-k>', ':TmuxNavigateUp<CR>', { desc = 'Navigate to upper tmux pane' })
vim.keymap.set('n', '<C-l>', ':TmuxNavigateRight<CR>', { desc = 'Navigate to right tmux pane' })
end,
},
}

View file

@ -1,85 +0,0 @@
return {
-- ========================================
-- Telescope Override
-- ========================================
{
'nvim-telescope/telescope.nvim',
-- Ensure dependencies are loaded
dependencies = {
'nvim-lua/plenary.nvim',
{
'nvim-telescope/telescope-fzf-native.nvim',
build = 'make',
cond = function()
return vim.fn.executable 'make' == 1
end,
},
{ 'nvim-telescope/telescope-ui-select.nvim' },
},
opts = { -- Use opts to merge/override defaults
pickers = {
find_files = {
-- Use rg for finding files (ensure rg is installed via Nix/Home Manager)
find_command = { 'rg', '--files', '--hidden', '-g', '!.git' },
},
},
-- Configure extensions
extensions = {
['ui-select'] = {
require('telescope.themes').get_dropdown(),
},
-- Configuration for fzf-native extension
fzf = {
fuzzy = true, -- Enable fuzzy matching
override_generic_sorter = true, -- Override the generic sorter
override_file_sorter = true, -- Override the file sorter
case_mode = 'smart_case', -- Ignore case unless capitals are used
},
},
},
-- The config function ensures extensions are loaded after setup
config = function(_, opts)
require('telescope').setup(opts)
-- Load extensions after setup
pcall(require('telescope').load_extension, 'fzf')
pcall(require('telescope').load_extension, 'ui-select')
-- *** ADD TELESCOPE KEYMAPS HERE ***
local builtin = require 'telescope.builtin'
-- Add the find_files keymap
vim.keymap.set('n', '<leader>sf', builtin.find_files, { desc = '[S]earch [F]iles' })
-- Add other Telescope keymaps from kickstart's init.lua (uncomment to enable)
vim.keymap.set('n', '<leader>sh', builtin.help_tags, { desc = '[S]earch [H]elp' })
vim.keymap.set('n', '<leader>sk', builtin.keymaps, { desc = '[S]earch [K]eymaps' })
vim.keymap.set('n', '<leader>ss', builtin.builtin, { desc = '[S]earch [S]elect Telescope' })
vim.keymap.set('n', '<leader>sw', builtin.grep_string, { desc = '[S]earch current [W]ord' })
vim.keymap.set('n', '<leader>sg', builtin.live_grep, { desc = '[S]earch by [G]rep' })
vim.keymap.set('n', '<leader>sd', builtin.diagnostics, { desc = '[S]earch [D]iagnostics' })
vim.keymap.set('n', '<leader>sr', builtin.resume, { desc = '[S]earch [R]esume' })
vim.keymap.set('n', '<leader>s.', builtin.oldfiles, { desc = '[S]earch Recent Files ("." for repeat)' })
vim.keymap.set('n', '<leader><leader>', builtin.buffers, { desc = '[ ] Find existing buffers' })
-- Fuzzy search in current buffer (corrected function body)
vim.keymap.set('n', '<leader>/', function()
builtin.current_buffer_fuzzy_find(require('telescope.themes').get_dropdown {
winblend = 10,
previewer = false,
})
end, { desc = '[/] Fuzzily search in current buffer' })
-- Search in open files (corrected function body)
vim.keymap.set('n', '<leader>s/', function()
builtin.live_grep {
grep_open_files = true,
prompt_title = 'Live Grep in Open Files',
}
end, { desc = '[S]earch [/] in Open Files' })
-- Search Neovim files (corrected function body)
vim.keymap.set('n', '<leader>sn', function()
builtin.find_files { cwd = vim.fn.stdpath 'config' }
end, { desc = '[S]earch [N]eovim files' })
end,
},
}

View file

@ -1,52 +0,0 @@
return {
-- ========================================
-- Treesitter Configuration Override
-- ========================================
{
'nvim-treesitter/nvim-treesitter',
-- build = ':TSUpdate', -- Keep build command if needed from kickstart
-- main = 'nvim-treesitter.configs', -- Keep if needed from kickstart
event = { 'BufReadPost', 'BufNewFile' },
build = ':TSUpdate',
opts = { -- Use opts to merge/override defaults
ensure_installed = {
'bash',
'c',
'cmake',
'cpp',
'diff',
'html',
'lua',
'luadoc',
'make',
'markdown',
'markdown_inline',
'nix',
'python',
'query',
'vim',
'vimdoc',
'yaml',
},
auto_install = true,
-- Keep other kickstart defaults like highlight/indent settings unless you want to change them
highlight = {
enable = true,
-- additional_vim_regex_highlighting = { 'ruby' }, -- Keep if needed
},
indent = {
enable = true,
-- disable = { 'ruby' }, -- Keep if needed
},
},
config = function(_, opts)
require('nvim-treesitter.configs').setup(opts)
end,
-- If kickstart used a config function for treesitter and you need to replicate
-- parts of it that aren't handled by opts, add it here.
-- config = function(_, opts)
-- require('nvim-treesitter.configs').setup(opts)
-- end,
},
}

View file

@ -1,69 +0,0 @@
-- local async = require 'plenary.async'
-- local pickers = require 'telescope.pickers'
-- local finders = require 'telescope.finders'
-- local sorters = require('telescope.config').values
-- local actions = require 'telescope.actions'
-- local action_state = require 'telescope.actions.state'
--
-- local function collect_executables(start_dir)
-- local results = {}
--
-- -- Add '.', start_dir so it works with your fd version
-- local fd = vim.fn.systemlist {
-- 'fd',
-- '.',
-- start_dir,
-- '--exec',
-- 'file',
-- '{}',
-- }
--
-- for _, line in ipairs(fd) do
-- local path, typeinfo = line:match '^(.-):%s*(.+)$'
-- if path and not path:match 'CMakeFiles' and typeinfo and (typeinfo:match 'Mach%-O' or typeinfo:match 'ELF') then
-- table.insert(results, path)
-- end
-- end
--
-- return results
-- end
--
-- local function pick_executable(start_dir)
-- return async.wrap(function(_start_dir, on_choice)
-- local executables = collect_executables(_start_dir)
--
-- if #executables == 0 then
-- vim.notify('No executables found in ' .. _start_dir, vim.log.levels.WARN)
-- on_choice(nil)
-- return
-- end
--
-- pickers
-- .new({}, {
-- prompt_title = 'Select Executable',
-- finder = finders.new_table { results = executables },
-- sorter = sorters.generic_sorter {},
-- attach_mappings = function(_, map)
-- actions.select_default:replace(function(prompt_bufnr)
-- local entry = action_state.get_selected_entry()
-- actions.close(prompt_bufnr)
-- on_choice(entry.value)
-- end)
-- map('i', '<Esc>', function(bufnr)
-- actions.close(bufnr)
-- on_choice(nil)
-- end)
-- map('n', 'q', function(bufnr)
-- actions.close(bufnr)
-- on_choice(nil)
-- end)
-- return true
-- end,
-- })
-- :find()
-- end, 2)(start_dir)
-- end
--
-- return {
-- pick_executable = pick_executable,
-- }

View file

@ -1,52 +0,0 @@
--[[
--
-- This file is not required for your own configuration,
-- but helps people determine if their system is setup correctly.
--
--]]
local check_version = function()
local verstr = tostring(vim.version())
if not vim.version.ge then
vim.health.error(string.format("Neovim out of date: '%s'. Upgrade to latest stable or nightly", verstr))
return
end
if vim.version.ge(vim.version(), '0.10-dev') then
vim.health.ok(string.format("Neovim version is: '%s'", verstr))
else
vim.health.error(string.format("Neovim out of date: '%s'. Upgrade to latest stable or nightly", verstr))
end
end
local check_external_reqs = function()
-- Basic utils: `git`, `make`, `unzip`
for _, exe in ipairs { 'git', 'make', 'unzip', 'rg' } do
local is_executable = vim.fn.executable(exe) == 1
if is_executable then
vim.health.ok(string.format("Found executable: '%s'", exe))
else
vim.health.warn(string.format("Could not find executable: '%s'", exe))
end
end
return true
end
return {
check = function()
vim.health.start 'kickstart.nvim'
vim.health.info [[NOTE: Not every warning is a 'must-fix' in `:checkhealth`
Fix only warnings for plugins and languages you intend to use.
Mason will give warnings for languages that are not installed.
You do not need to install, unless you want to use those languages!]]
local uv = vim.uv or vim.loop
vim.health.info('System Information: ' .. vim.inspect(uv.os_uname()))
check_version()
check_external_reqs()
end,
}

View file

@ -1,8 +0,0 @@
-- autopairs
-- https://github.com/windwp/nvim-autopairs
return {
'windwp/nvim-autopairs',
event = 'InsertEnter',
opts = {},
}

View file

@ -1,127 +0,0 @@
-- debug.lua
--
-- Shows how to use the DAP plugin to debug your code.
--
-- Primarily focused on configuring the debugger for Go, but can
-- be extended to other languages as well. That's why it's called
-- kickstart.nvim and not kitchen-sink.nvim ;)
return {
-- NOTE: Yes, you can install new plugins here!
'mfussenegger/nvim-dap',
-- NOTE: And you can specify dependencies as well
dependencies = {
-- Creates a beautiful debugger UI
'rcarriga/nvim-dap-ui',
-- Required dependency for nvim-dap-ui
'nvim-neotest/nvim-nio',
-- Add your own debuggers here
'leoluz/nvim-dap-go',
},
keys = {
-- Basic debugging keymaps, feel free to change to your liking!
{
'<F5>',
function()
require('dap').continue()
end,
desc = 'Debug: Start/Continue',
},
{
'<F1>',
function()
require('dap').step_into()
end,
desc = 'Debug: Step Into',
},
{
'<F2>',
function()
require('dap').step_over()
end,
desc = 'Debug: Step Over',
},
{
'<F3>',
function()
require('dap').step_out()
end,
desc = 'Debug: Step Out',
},
{
'<leader>b',
function()
require('dap').toggle_breakpoint()
end,
desc = 'Debug: Toggle Breakpoint',
},
{
'<leader>B',
function()
require('dap').set_breakpoint(vim.fn.input 'Breakpoint condition: ')
end,
desc = 'Debug: Set Breakpoint',
},
-- Toggle to see last session result. Without this, you can't see session output in case of unhandled exception.
{
'<F7>',
function()
require('dapui').toggle()
end,
desc = 'Debug: See last session result.',
},
},
config = function()
local dap = require 'dap'
local dapui = require 'dapui'
-- Dap UI setup
-- For more information, see |:help nvim-dap-ui|
dapui.setup {
-- Set icons to characters that are more likely to work in every terminal.
-- Feel free to remove or use ones that you like more! :)
-- Don't feel like these are good choices.
icons = { expanded = '', collapsed = '', current_frame = '*' },
controls = {
icons = {
pause = '',
play = '',
step_into = '',
step_over = '',
step_out = '',
step_back = 'b',
run_last = '▶▶',
terminate = '',
disconnect = '',
},
},
}
-- Change breakpoint icons
-- vim.api.nvim_set_hl(0, 'DapBreak', { fg = '#e51400' })
-- vim.api.nvim_set_hl(0, 'DapStop', { fg = '#ffcc00' })
-- local breakpoint_icons = vim.g.have_nerd_font
-- and { Breakpoint = '', BreakpointCondition = '', BreakpointRejected = '', LogPoint = '', Stopped = '' }
-- or { Breakpoint = '●', BreakpointCondition = '⊜', BreakpointRejected = '⊘', LogPoint = '◆', Stopped = '⭔' }
-- for type, icon in pairs(breakpoint_icons) do
-- local tp = 'Dap' .. type
-- local hl = (type == 'Stopped') and 'DapStop' or 'DapBreak'
-- vim.fn.sign_define(tp, { text = icon, texthl = hl, numhl = hl })
-- end
dap.listeners.after.event_initialized['dapui_config'] = dapui.open
dap.listeners.before.event_terminated['dapui_config'] = dapui.close
dap.listeners.before.event_exited['dapui_config'] = dapui.close
-- Install golang specific config
require('dap-go').setup {
delve = {
-- On Windows delve must be run attached or it crashes.
-- See https://github.com/leoluz/nvim-dap-go/blob/main/README.md#configuring
detached = vim.fn.has 'win32' == 0,
},
}
end,
}

View file

@ -1,61 +0,0 @@
-- Adds git related signs to the gutter, as well as utilities for managing changes
-- NOTE: gitsigns is already included in init.lua but contains only the base
-- config. This will add also the recommended keymaps.
return {
{
'lewis6991/gitsigns.nvim',
opts = {
on_attach = function(bufnr)
local gitsigns = require 'gitsigns'
local function map(mode, l, r, opts)
opts = opts or {}
opts.buffer = bufnr
vim.keymap.set(mode, l, r, opts)
end
-- Navigation
map('n', ']c', function()
if vim.wo.diff then
vim.cmd.normal { ']c', bang = true }
else
gitsigns.nav_hunk 'next'
end
end, { desc = 'Jump to next git [c]hange' })
map('n', '[c', function()
if vim.wo.diff then
vim.cmd.normal { '[c', bang = true }
else
gitsigns.nav_hunk 'prev'
end
end, { desc = 'Jump to previous git [c]hange' })
-- Actions
-- visual mode
map('v', '<leader>hs', function()
gitsigns.stage_hunk { vim.fn.line '.', vim.fn.line 'v' }
end, { desc = 'git [s]tage hunk' })
map('v', '<leader>hr', function()
gitsigns.reset_hunk { vim.fn.line '.', vim.fn.line 'v' }
end, { desc = 'git [r]eset hunk' })
-- normal mode
map('n', '<leader>hs', gitsigns.stage_hunk, { desc = 'git [s]tage hunk' })
map('n', '<leader>hr', gitsigns.reset_hunk, { desc = 'git [r]eset hunk' })
map('n', '<leader>hS', gitsigns.stage_buffer, { desc = 'git [S]tage buffer' })
map('n', '<leader>hu', gitsigns.stage_hunk, { desc = 'git [u]ndo stage hunk' })
map('n', '<leader>hR', gitsigns.reset_buffer, { desc = 'git [R]eset buffer' })
map('n', '<leader>hp', gitsigns.preview_hunk, { desc = 'git [p]review hunk' })
map('n', '<leader>hb', gitsigns.blame_line, { desc = 'git [b]lame line' })
map('n', '<leader>hd', gitsigns.diffthis, { desc = 'git [d]iff against index' })
map('n', '<leader>hD', function()
gitsigns.diffthis '@'
end, { desc = 'git [D]iff against last commit' })
-- Toggles
map('n', '<leader>tb', gitsigns.toggle_current_line_blame, { desc = '[T]oggle git show [b]lame line' })
map('n', '<leader>tD', gitsigns.preview_hunk_inline, { desc = '[T]oggle git show [D]eleted' })
end,
},
},
}

View file

@ -1,9 +0,0 @@
return {
{ -- Add indentation guides even on blank lines
'lukas-reineke/indent-blankline.nvim',
-- Enable `lukas-reineke/indent-blankline.nvim`
-- See `:help ibl`
main = 'ibl',
opts = {},
},
}

View file

@ -1,60 +0,0 @@
return {
{ -- Linting
'mfussenegger/nvim-lint',
event = { 'BufReadPre', 'BufNewFile' },
config = function()
local lint = require 'lint'
lint.linters_by_ft = {
markdown = { 'markdownlint' },
}
-- To allow other plugins to add linters to require('lint').linters_by_ft,
-- instead set linters_by_ft like this:
-- lint.linters_by_ft = lint.linters_by_ft or {}
-- lint.linters_by_ft['markdown'] = { 'markdownlint' }
--
-- However, note that this will enable a set of default linters,
-- which will cause errors unless these tools are available:
-- {
-- clojure = { "clj-kondo" },
-- dockerfile = { "hadolint" },
-- inko = { "inko" },
-- janet = { "janet" },
-- json = { "jsonlint" },
-- markdown = { "vale" },
-- rst = { "vale" },
-- ruby = { "ruby" },
-- terraform = { "tflint" },
-- text = { "vale" }
-- }
--
-- You can disable the default linters by setting their filetypes to nil:
-- lint.linters_by_ft['clojure'] = nil
-- lint.linters_by_ft['dockerfile'] = nil
-- lint.linters_by_ft['inko'] = nil
-- lint.linters_by_ft['janet'] = nil
-- lint.linters_by_ft['json'] = nil
-- lint.linters_by_ft['markdown'] = nil
-- lint.linters_by_ft['rst'] = nil
-- lint.linters_by_ft['ruby'] = nil
-- lint.linters_by_ft['terraform'] = nil
-- lint.linters_by_ft['text'] = nil
-- Create autocommand which carries out the actual linting
-- on the specified events.
local lint_augroup = vim.api.nvim_create_augroup('lint', { clear = true })
vim.api.nvim_create_autocmd({ 'BufEnter', 'BufWritePost', 'InsertLeave' }, {
group = lint_augroup,
callback = function()
-- Only run the linter in buffers that you can modify in order to
-- avoid superfluous noise, notably within the handy LSP pop-ups that
-- describe the hovered symbol using Markdown.
if vim.bo.modifiable then
lint.try_lint()
end
end,
})
end,
},
}

View file

@ -1,25 +0,0 @@
-- Neo-tree is a Neovim plugin to browse the file system
-- https://github.com/nvim-neo-tree/neo-tree.nvim
return {
'nvim-neo-tree/neo-tree.nvim',
version = '*',
dependencies = {
'nvim-lua/plenary.nvim',
'nvim-tree/nvim-web-devicons', -- not strictly required, but recommended
'MunifTanjim/nui.nvim',
},
lazy = false,
keys = {
{ '\\', ':Neotree reveal<CR>', desc = 'NeoTree reveal', silent = true },
},
opts = {
filesystem = {
window = {
mappings = {
['\\'] = 'close_window',
},
},
},
},
}

View file

@ -0,0 +1,126 @@
-- Blink.cmp Configuration
local M = {}
function M.setup()
require('blink.cmp').setup({
-- Keymap configuration
keymap = {
preset = 'default',
['<C-space>'] = { 'show', 'show_documentation', 'hide_documentation' },
['<C-e>'] = { 'hide' },
['<C-y>'] = { 'select_and_accept' },
['<C-p>'] = { 'select_prev', 'fallback' },
['<C-n>'] = { 'select_next', 'fallback' },
['<C-b>'] = { 'scroll_documentation_up', 'fallback' },
['<C-f>'] = { 'scroll_documentation_down', 'fallback' },
['<Tab>'] = { 'snippet_forward', 'fallback' },
['<S-Tab>'] = { 'snippet_backward', 'fallback' },
},
-- Appearance configuration
appearance = {
use_nvim_cmp_as_default = true,
nerd_font_variant = 'mono',
},
-- Sources configuration with Copilot integration
sources = {
default = { 'lsp', 'path', 'snippets', 'buffer', 'copilot' },
providers = {
copilot = {
name = 'copilot',
module = 'blink-cmp-copilot',
score_offset = 100,
async = true,
transform_items = function(_, items)
-- Add copilot icon to copilot suggestions
for _, item in ipairs(items) do
item.kind = 'Copilot'
end
return items
end,
},
},
},
-- Command line configuration (new API)
cmdline = {
enabled = false, -- Disable cmdline completion for now
},
-- Signature help configuration
signature = {
enabled = true,
window = {
border = 'rounded',
},
},
-- Completion configuration
completion = {
accept = {
-- Auto-insert brackets for functions
auto_brackets = {
enabled = true,
},
},
menu = {
draw = {
columns = {
{ 'label', 'label_description', gap = 1 },
{ 'kind_icon', 'kind' }
},
},
border = 'rounded',
winblend = 0,
},
documentation = {
auto_show = true,
auto_show_delay_ms = 200,
window = {
border = 'rounded',
},
},
ghost_text = {
enabled = true,
},
},
-- Fuzzy matching configuration
fuzzy = {
-- Use Rust implementation for better performance
implementation = 'prefer_rust_with_warning',
-- Allow typos based on keyword length
max_typos = function(keyword)
return math.floor(#keyword / 4)
end,
-- Track frequently/recently used items
use_frecency = true,
-- Boost items matching nearby words
use_proximity = true,
-- Prebuilt binaries configuration
prebuilt_binaries = {
download = true,
},
},
-- Snippet configuration
snippets = {
expand = function(snippet)
-- Use native snippet expansion if available
if vim.snippet then
vim.snippet.expand(snippet)
else
-- Fallback to basic expansion
local insert = string.gsub(snippet, '%$%d+', '')
vim.api.nvim_put({ insert }, 'c', true, true)
end
end,
},
})
end
return M

View file

@ -0,0 +1,158 @@
-- Debug Adapters Configuration
local M = {}
-- Helper function to find Python executable
-- In Nix environments, use whatever Python is in PATH
local function get_python_path()
-- Use the Python from current environment (Nix or system)
if vim.fn.executable('python3') == 1 then
return vim.fn.exepath('python3')
elseif vim.fn.executable('python') == 1 then
return vim.fn.exepath('python')
else
-- Fallback to system Python
return '/usr/bin/python3'
end
end
function M.setup()
local dap = require('dap')
-- Setup all language-specific adapters
M.setup_python(dap)
M.setup_cpp(dap)
-- Add more adapters as needed
-- M.setup_rust(dap)
-- M.setup_go(dap)
-- M.setup_javascript(dap)
end
-- Python debugger configuration
function M.setup_python(dap)
dap.adapters.python = {
type = 'executable',
command = vim.fn.exepath('python3') ~= '' and vim.fn.exepath('python3') or 'python',
args = { '-m', 'debugpy.adapter' },
}
dap.configurations.python = {
{
type = 'python',
request = 'launch',
name = 'Launch file',
program = '${file}',
pythonPath = get_python_path,
},
{
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 = get_python_path,
},
{
type = 'python',
request = 'attach',
name = 'Attach to running process',
processId = require('dap.utils').pick_process,
pythonPath = get_python_path,
},
}
end
-- C/C++/Rust debugger configuration (using codelldb)
function M.setup_cpp(dap)
-- CodeLLDB adapter
dap.adapters.codelldb = {
type = 'server',
port = '${port}',
executable = {
command = 'codelldb',
args = { '--port', '${port}' },
},
}
-- Alternative: Use lldb-vscode if codelldb is not available
dap.adapters.lldb = {
type = 'executable',
command = '/usr/bin/lldb-vscode', -- Adjust path as needed
name = 'lldb',
}
-- C++ configuration
dap.configurations.cpp = {
{
name = 'Launch',
type = 'codelldb',
request = 'launch',
program = function()
return vim.fn.input('Path to executable: ', vim.fn.getcwd() .. '/', 'file')
end,
cwd = '${workspaceFolder}',
stopOnEntry = false,
args = {},
runInTerminal = false,
},
{
name = 'Launch with arguments',
type = 'codelldb',
request = 'launch',
program = function()
return vim.fn.input('Path to executable: ', vim.fn.getcwd() .. '/', 'file')
end,
cwd = '${workspaceFolder}',
stopOnEntry = false,
args = function()
local args_string = vim.fn.input('Arguments: ')
return vim.split(args_string, ' ')
end,
runInTerminal = false,
},
{
name = 'Attach to process',
type = 'codelldb',
request = 'attach',
pid = require('dap.utils').pick_process,
args = {},
},
}
-- Share C++ configuration with C and Rust
dap.configurations.c = dap.configurations.cpp
dap.configurations.rust = dap.configurations.cpp
end
-- Example: Go debugger configuration (commented out)
-- function M.setup_go(dap)
-- dap.adapters.delve = {
-- type = 'server',
-- port = '${port}',
-- executable = {
-- command = 'dlv',
-- args = { 'dap', '-l', '127.0.0.1:${port}' },
-- },
-- }
--
-- dap.configurations.go = {
-- {
-- type = 'delve',
-- name = 'Debug',
-- request = 'launch',
-- program = '${file}',
-- },
-- {
-- type = 'delve',
-- name = 'Debug test',
-- request = 'launch',
-- mode = 'test',
-- program = '${file}',
-- },
-- }
-- end
return M

View file

@ -0,0 +1,38 @@
-- Debug Configuration (DAP)
local M = {}
function M.setup()
local dap = require('dap')
local dapui = require('dapui')
-- Setup DAP UI with icons and controls
dapui.setup({
icons = { expanded = '', collapsed = '', current_frame = '*' },
controls = {
icons = {
pause = '',
play = '',
step_into = '',
step_over = '',
step_out = '',
step_back = 'b',
run_last = '▶▶',
terminate = '',
disconnect = '',
},
},
})
-- Automatically open/close DAP UI on debug events
dap.listeners.after.event_initialized['dapui_config'] = dapui.open
dap.listeners.before.event_terminated['dapui_config'] = dapui.close
dap.listeners.before.event_exited['dapui_config'] = dapui.close
-- Configure debug adapters for different languages
require('plugins.config.debug.adapters').setup()
-- Setup debug keymaps
require('plugins.config.debug.keymaps').setup()
end
return M

View file

@ -0,0 +1,59 @@
-- Debug Keymaps Configuration
local M = {}
function M.setup()
local dap = require('dap')
local dapui = require('dapui')
-- Function key mappings for common debug operations
vim.keymap.set('n', '<F5>', dap.continue, { desc = 'Debug: Start/Continue' })
vim.keymap.set('n', '<F10>', dap.step_over, { desc = 'Debug: Step Over' })
vim.keymap.set('n', '<F11>', dap.step_into, { desc = 'Debug: Step Into' })
vim.keymap.set('n', '<F12>', dap.step_out, { desc = 'Debug: Step Out' })
-- Breakpoint management
vim.keymap.set('n', '<leader>db', dap.toggle_breakpoint, { desc = 'Debug: Toggle Breakpoint' })
vim.keymap.set('n', '<leader>dB', function()
dap.set_breakpoint(vim.fn.input 'Breakpoint condition: ')
end, { desc = 'Debug: Set Conditional Breakpoint' })
vim.keymap.set('n', '<leader>lp', function()
dap.set_breakpoint(nil, nil, vim.fn.input('Log point message: '))
end, { desc = 'Debug: Set Log Point' })
-- DAP UI controls
vim.keymap.set('n', '<F7>', dapui.toggle, { desc = 'Debug: Toggle UI' })
vim.keymap.set('n', '<leader>de', dapui.eval, { desc = 'Debug: Eval under cursor' })
vim.keymap.set('v', '<leader>de', dapui.eval, { desc = 'Debug: Eval selection' })
-- REPL and additional features
vim.keymap.set('n', '<leader>dr', dap.repl.open, { desc = 'Debug: Open REPL' })
vim.keymap.set('n', '<leader>dl', dap.run_last, { desc = 'Debug: Run Last' })
-- Widget-based inspections
vim.keymap.set('n', '<leader>dh', function()
require('dap.ui.widgets').hover()
end, { desc = 'Debug: Hover Variables' })
vim.keymap.set('n', '<leader>ds', function()
local widgets = require('dap.ui.widgets')
widgets.centered_float(widgets.scopes)
end, { desc = 'Debug: View Scopes' })
vim.keymap.set('n', '<leader>df', function()
local widgets = require('dap.ui.widgets')
widgets.centered_float(widgets.frames)
end, { desc = 'Debug: View Frames' })
-- Session management
vim.keymap.set('n', '<leader>dt', dap.terminate, { desc = 'Debug: Terminate Session' })
vim.keymap.set('n', '<leader>dc', dap.run_to_cursor, { desc = 'Debug: Continue to Cursor' })
-- Create visual indicators for breakpoints
vim.fn.sign_define('DapBreakpoint', { text = '🔴', texthl = 'DapBreakpoint', linehl = '', numhl = '' })
vim.fn.sign_define('DapBreakpointCondition', { text = '🟡', texthl = 'DapBreakpoint', linehl = '', numhl = '' })
vim.fn.sign_define('DapBreakpointRejected', { text = '', texthl = 'DapBreakpoint', linehl = '', numhl = '' })
vim.fn.sign_define('DapLogPoint', { text = '📝', texthl = 'DapLogPoint', linehl = '', numhl = '' })
vim.fn.sign_define('DapStopped', { text = '▶️', texthl = 'DapStopped', linehl = 'DapStopped', numhl = 'DapStopped' })
end
return M

View file

@ -0,0 +1,59 @@
-- Editor Enhancement Configuration
local M = {}
function M.setup_mini()
-- Better Around/Inside textobjects
require('mini.ai').setup { n_lines = 500 }
-- Add/delete/replace surroundings (brackets, quotes, etc.)
require('mini.surround').setup()
-- Simple and easy statusline
local statusline = require 'mini.statusline'
statusline.setup { use_icons = vim.g.have_nerd_font }
-- Custom statusline location section
---@diagnostic disable-next-line: duplicate-set-field
statusline.section_location = function()
return '%2l:%-2v'
end
end
function M.setup_illuminate()
require('illuminate').configure({
delay = 200,
large_file_cutoff = 2000,
large_file_overrides = {
providers = { 'lsp' },
},
providers = {
'lsp',
'treesitter',
'regex',
},
filetypes_denylist = {
'dirbuf',
'dirvish',
'fugitive',
'alpha',
'NvimTree',
'lazy',
'neogitstatus',
'Trouble',
'lir',
'Outline',
'spectre_panel',
'toggleterm',
'DressingSelect',
'TelescopePrompt',
},
under_cursor = true,
})
end
function M.setup()
M.setup_mini()
M.setup_illuminate()
end
return M

View file

@ -0,0 +1,69 @@
-- Git Configuration
local M = {}
function M.setup_gitsigns()
require('gitsigns').setup({
signs = {
add = { text = '+' },
change = { text = '~' },
delete = { text = '_' },
topdelete = { text = '' },
changedelete = { text = '~' },
},
on_attach = function(bufnr)
local gitsigns = require('gitsigns')
local function map(mode, l, r, opts)
opts = opts or {}
opts.buffer = bufnr
vim.keymap.set(mode, l, r, opts)
end
-- Navigation
map('n', ']c', function()
if vim.wo.diff then
vim.cmd.normal({']c', bang = true})
else
gitsigns.nav_hunk('next')
end
end, { desc = 'Jump to next git [c]hange' })
map('n', '[c', function()
if vim.wo.diff then
vim.cmd.normal({'[c', bang = true})
else
gitsigns.nav_hunk('prev')
end
end, { desc = 'Jump to previous git [c]hange' })
-- Actions
map('n', '<leader>hs', gitsigns.stage_hunk, { desc = 'Git [s]tage hunk' })
map('n', '<leader>hr', gitsigns.reset_hunk, { desc = 'Git [r]eset hunk' })
map('v', '<leader>hs', function()
gitsigns.stage_hunk({vim.fn.line('.'), vim.fn.line('v')})
end, { desc = 'Git [s]tage hunk' })
map('v', '<leader>hr', function()
gitsigns.reset_hunk({vim.fn.line('.'), vim.fn.line('v')})
end, { desc = 'Git [r]eset hunk' })
map('n', '<leader>hS', gitsigns.stage_buffer, { desc = 'Git [S]tage buffer' })
map('n', '<leader>hu', gitsigns.undo_stage_hunk, { desc = 'Git [u]ndo stage hunk' })
map('n', '<leader>hR', gitsigns.reset_buffer, { desc = 'Git [R]eset buffer' })
map('n', '<leader>hp', gitsigns.preview_hunk, { desc = 'Git [p]review hunk' })
map('n', '<leader>hb', gitsigns.blame_line, { desc = 'Git [b]lame line' })
map('n', '<leader>hd', gitsigns.diffthis, { desc = 'Git [d]iff against index' })
map('n', '<leader>hD', function()
gitsigns.diffthis('@')
end, { desc = 'Git [D]iff against last commit' })
-- Toggles
map('n', '<leader>tb', gitsigns.toggle_current_line_blame, { desc = '[T]oggle git show [b]lame line' })
map('n', '<leader>tD', gitsigns.toggle_deleted, { desc = '[T]oggle git show [D]eleted' })
-- Text object
map({'o', 'x'}, 'ih', ':<C-U>Gitsigns select_hunk<CR>', { desc = 'Select git hunk' })
end,
})
end
return M

View file

@ -0,0 +1,26 @@
-- LSP Configuration Module
local M = {}
function M.setup()
local lspconfig = require 'lspconfig'
-- Get capabilities from blink.cmp if available
local capabilities = {}
pcall(function()
capabilities = require('blink.cmp').get_lsp_capabilities()
end)
-- Load server configurations
local servers = require('plugins.config.lsp.servers').get_servers()
-- Setup each server with capabilities
for name, config in pairs(servers) do
config.capabilities = vim.tbl_deep_extend('force', {}, capabilities, config.capabilities or {})
lspconfig[name].setup(config)
end
-- Setup LSP keymaps
require('plugins.config.lsp.keymaps').setup()
end
return M

View file

@ -0,0 +1,57 @@
-- LSP Keymaps Configuration
local M = {}
function M.setup()
-- Setup keymaps when LSP attaches to a buffer
vim.api.nvim_create_autocmd('LspAttach', {
group = vim.api.nvim_create_augroup('lsp-attach-keymaps', { clear = true }),
callback = function(event)
-- Helper function to define keymaps
local map = function(keys, func, desc, mode)
mode = mode or 'n'
vim.keymap.set(mode, keys, func, { buffer = event.buf, desc = 'LSP: ' .. desc })
end
-- Navigation keymaps (using kickstart.nvim patterns)
map('gd', require('telescope.builtin').lsp_definitions, '[G]oto [D]efinition')
map('grr', require('telescope.builtin').lsp_references, '[G]oto [R]eferences')
map('gri', require('telescope.builtin').lsp_implementations, '[G]oto [I]mplementation')
map('grt', require('telescope.builtin').lsp_type_definitions, '[G]oto [T]ype definition')
map('grD', vim.lsp.buf.declaration, '[G]oto [D]eclaration')
-- Symbol operations
map('grn', vim.lsp.buf.rename, '[G]oto [R]e[n]ame')
map('gra', vim.lsp.buf.code_action, '[G]oto code [A]ction', { 'n', 'x' })
map('gO', require('telescope.builtin').lsp_document_symbols, '[G]oto [O]pen document symbols')
map('gW', require('telescope.builtin').lsp_dynamic_workspace_symbols, '[G]oto [W]orkspace symbols')
-- Documentation
map('K', vim.lsp.buf.hover, 'Hover Documentation')
-- Formatting
map('<leader>f', function()
vim.lsp.buf.format { async = true }
end, '[F]ormat buffer')
-- The following keymaps are available but not mapped by default:
-- vim.lsp.buf.signature_help - Show function signature help
-- vim.lsp.buf.add_workspace_folder - Add workspace folder
-- vim.lsp.buf.remove_workspace_folder - Remove workspace folder
-- vim.lsp.buf.list_workspace_folders - List workspace folders
-- Optional: Add a message when LSP attaches
local client = vim.lsp.get_client_by_id(event.data.client_id)
if client then
vim.notify('LSP attached: ' .. client.name, vim.log.levels.INFO)
end
end,
})
-- Diagnostic keymaps (available globally, not just when LSP attaches)
vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, { desc = 'Go to previous [D]iagnostic message' })
vim.keymap.set('n', ']d', vim.diagnostic.goto_next, { desc = 'Go to next [D]iagnostic message' })
vim.keymap.set('n', '<leader>e', vim.diagnostic.open_float, { desc = 'Show diagnostic [E]rror messages' })
vim.keymap.set('n', '<leader>q', vim.diagnostic.setloclist, { desc = 'Open diagnostic [Q]uickfix list' })
end
return M

View file

@ -0,0 +1,88 @@
-- LSP Server Configurations
local M = {}
local util = require 'lspconfig.util'
-- Query driver for clangd to find compilers in various locations
local function get_clangd_query_driver()
return table.concat({
'/nix/store/*/bin/clang*',
'/opt/homebrew/opt/llvm/bin/clang*',
'/usr/bin/clang*',
}, ';')
end
-- Get clang resource directory
local function get_clang_resource_dir()
local ok, result = pcall(vim.fn.systemlist, { 'clang++', '--print-resource-dir' })
if ok and result and result[1] then
return result[1]
else
return '/usr/lib/clang/19/include' -- fallback
end
end
function M.get_servers()
return {
-- C/C++ Language Server
clangd = {
cmd = {
'clangd',
'--background-index',
'--clang-tidy',
'--header-insertion=never',
'--query-driver=' .. get_clangd_query_driver(),
'--compile-commands-dir=build',
'--resource-dir=' .. get_clang_resource_dir(),
},
filetypes = { 'c', 'cpp', 'objc', 'objcpp', 'cuda' },
root_dir = util.root_pattern('CMakeLists.txt', '.git'),
single_file_support = true,
},
-- Python Language Server
pyright = {
settings = {
python = {
analysis = {
autoSearchPaths = true,
diagnosticMode = 'openFilesOnly',
useLibraryCodeForTypes = true,
typeCheckingMode = 'basic',
},
},
},
positionEncoding = 'utf-8',
},
-- Python Linter/Formatter
ruff = {},
-- Nix Language Server
nixd = {},
-- LaTeX Language Server
texlab = {},
-- CMake Language Server
cmake = {
cmd = { 'cmake-language-server' },
filetypes = { 'cmake' },
root_dir = util.root_pattern('CMakeLists.txt', '.git'),
},
-- Add more servers here as needed
-- Example:
-- rust_analyzer = {
-- settings = {
-- ['rust-analyzer'] = {
-- checkOnSave = {
-- command = 'clippy',
-- },
-- },
-- },
-- },
}
end
return M

View file

@ -0,0 +1,84 @@
-- Telescope Configuration
local M = {}
function M.setup()
local telescope = require('telescope')
local builtin = require('telescope.builtin')
telescope.setup({
defaults = {
prompt_prefix = '> ',
selection_caret = '> ',
path_display = { 'truncate' },
sorting_strategy = 'ascending',
layout_config = {
horizontal = {
prompt_position = 'top',
preview_width = 0.55,
},
vertical = {
mirror = false,
},
width = 0.87,
height = 0.80,
preview_cutoff = 120,
},
},
pickers = {
find_files = {
-- Use rg for finding files (ensure rg is installed via Nix/Home Manager)
find_command = { 'rg', '--files', '--hidden', '-g', '!.git' },
},
},
extensions = {
['ui-select'] = {
require('telescope.themes').get_dropdown(),
},
fzf = {
fuzzy = true,
override_generic_sorter = true,
override_file_sorter = true,
case_mode = 'smart_case',
},
},
})
-- Load extensions
pcall(telescope.load_extension, 'fzf')
pcall(telescope.load_extension, 'ui-select')
-- Setup keymaps
vim.keymap.set('n', '<leader>sf', builtin.find_files, { desc = '[S]earch [F]iles' })
vim.keymap.set('n', '<leader>sg', builtin.live_grep, { desc = '[S]earch by [G]rep' })
vim.keymap.set('n', '<leader>sh', builtin.help_tags, { desc = '[S]earch [H]elp' })
vim.keymap.set('n', '<leader>sk', builtin.keymaps, { desc = '[S]earch [K]eymaps' })
vim.keymap.set('n', '<leader>ss', builtin.builtin, { desc = '[S]earch [S]elect Telescope' })
vim.keymap.set('n', '<leader>sw', builtin.grep_string, { desc = '[S]earch current [W]ord' })
vim.keymap.set('n', '<leader>sd', builtin.diagnostics, { desc = '[S]earch [D]iagnostics' })
vim.keymap.set('n', '<leader>sr', builtin.resume, { desc = '[S]earch [R]esume' })
vim.keymap.set('n', '<leader>s.', builtin.oldfiles, { desc = '[S]earch Recent Files ("." for repeat)' })
vim.keymap.set('n', '<leader><leader>', builtin.buffers, { desc = '[ ] Find existing buffers' })
-- Fuzzy search in current buffer
vim.keymap.set('n', '<leader>/', function()
builtin.current_buffer_fuzzy_find(require('telescope.themes').get_dropdown {
winblend = 10,
previewer = false,
})
end, { desc = '[/] Fuzzily search in current buffer' })
-- Search in open files
vim.keymap.set('n', '<leader>s/', function()
builtin.live_grep {
grep_open_files = true,
prompt_title = 'Live Grep in Open Files',
}
end, { desc = '[S]earch [/] in Open Files' })
-- Search in neovim config
vim.keymap.set('n', '<leader>sn', function()
builtin.find_files { cwd = vim.fn.stdpath 'config' }
end, { desc = '[S]earch [N]eovim files' })
end
return M

57
lua/plugins/config/ui.lua Normal file
View file

@ -0,0 +1,57 @@
-- UI Configuration
local M = {}
function M.setup_which_key()
local wk = require 'which-key'
wk.setup({
delay = 0,
icons = {
mappings = vim.g.have_nerd_font,
keys = vim.g.have_nerd_font and {} or {
Up = '<Up> ',
Down = '<Down> ',
Left = '<Left> ',
Right = '<Right> ',
C = '<C-…> ',
M = '<M-…> ',
D = '<D-…> ',
S = '<S-…> ',
CR = '<CR> ',
Esc = '<Esc> ',
ScrollWheelDown = '<ScrollWheelDown> ',
ScrollWheelUp = '<ScrollWheelUp> ',
NL = '<NL> ',
BS = '<BS> ',
Space = '<Space> ',
Tab = '<Tab> ',
F1 = '<F1>',
F2 = '<F2>',
F3 = '<F3>',
F4 = '<F4>',
F5 = '<F5>',
F6 = '<F6>',
F7 = '<F7>',
F8 = '<F8>',
F9 = '<F9>',
F10 = '<F10>',
F11 = '<F11>',
F12 = '<F12>',
},
},
})
-- Document existing key chains
wk.add {
{ '<leader>c', group = '[C]ode' },
{ '<leader>d', group = '[D]ocument/[D]ebug' },
{ '<leader>r', group = '[R]ename' },
{ '<leader>s', group = '[S]earch' },
{ '<leader>w', group = '[W]orkspace' },
{ '<leader>t', group = '[T]oggle' },
{ '<leader>g', group = '[G]it' },
{ '<leader>h', group = 'Git [H]unk', mode = { 'n', 'v' } },
}
end
return M

View file

@ -0,0 +1,24 @@
-- Auto-pairs - Automatically close brackets, quotes, etc.
return {
'windwp/nvim-autopairs',
event = 'InsertEnter',
opts = {
check_ts = true,
ts_config = {
lua = { 'string', 'source' },
javascript = { 'string', 'template_string' },
},
disable_filetype = { 'TelescopePrompt', 'spectre_panel' },
fast_wrap = {
map = '<M-e>',
chars = { '{', '[', '(', '"', "'" },
pattern = string.gsub([[ [%'%"%)%>%]%)%}%,] ]], '%s+', ''),
offset = 0,
end_key = '$',
keys = 'qwertyuiopzxcvbnmasdfghjkl',
check_comma = true,
highlight = 'PmenuSel',
highlight_grey = 'LineNr',
},
},
}

View file

@ -0,0 +1,12 @@
-- Blink.cmp - Modern completion plugin
return {
'saghen/blink.cmp',
lazy = false, -- Lazy loading handled internally
dependencies = {
'giuxtaposition/blink-cmp-copilot',
},
version = 'v0.*', -- Use stable releases
config = function()
require('plugins.config.blink').setup()
end,
}

View file

@ -0,0 +1,21 @@
-- GitHub Copilot integration
return {
'zbirenbaum/copilot.lua',
cmd = 'Copilot',
event = 'InsertEnter',
opts = {
suggestion = { enabled = false }, -- Disable inline ghost text (handled by blink.cmp)
panel = { enabled = false }, -- Disable panel view
filetypes = {
yaml = false,
markdown = false,
help = false,
gitcommit = false,
gitrebase = false,
hgcommit = false,
svn = false,
cvs = false,
['.'] = false,
},
},
}

View file

@ -0,0 +1,20 @@
-- Debug Adapter Protocol (DAP) support
return {
'mfussenegger/nvim-dap',
dependencies = {
-- DAP UI
{
'rcarriga/nvim-dap-ui',
dependencies = { 'nvim-neotest/nvim-nio' },
},
-- Virtual text for debugging
{
'theHamsta/nvim-dap-virtual-text',
opts = {},
},
},
config = function()
require('plugins.config.debug').setup()
end,
}

View file

@ -0,0 +1,36 @@
-- Editor enhancement plugins
return {
-- Collection of various small independent plugins/modules
{
'echasnovski/mini.nvim',
config = function()
require('plugins.config.editor').setup_mini()
end,
},
-- Highlight, edit, and navigate code
{
'nvim-treesitter/nvim-treesitter-textobjects',
event = 'VeryLazy',
dependencies = { 'nvim-treesitter/nvim-treesitter' },
},
-- Detect tabstop and shiftwidth automatically
{ 'tpope/vim-sleuth' },
-- Comment plugin
{
'numToStr/Comment.nvim',
event = 'VeryLazy',
opts = {},
},
-- Highlight word under cursor
{
'RRethy/vim-illuminate',
event = { 'BufReadPost', 'BufNewFile' },
config = function()
require('plugins.config.editor').setup_illuminate()
end,
},
}

26
lua/plugins/spec/git.lua Normal file
View file

@ -0,0 +1,26 @@
-- Git integration plugins
return {
-- Fugitive - Git integration
{
'tpope/vim-fugitive',
cmd = { 'Git', 'G', 'Gdiff', 'Gread', 'Gwrite', 'Ggrep', 'GMove', 'GDelete', 'GBrowse', 'GRemove' },
keys = {
{ '<leader>gs', '<cmd>Git<cr>', desc = 'Git status' },
{ '<leader>gd', '<cmd>Gdiff<cr>', desc = 'Git diff' },
{ '<leader>gc', '<cmd>Git commit<cr>', desc = 'Git commit' },
{ '<leader>gb', '<cmd>Git blame<cr>', desc = 'Git blame' },
{ '<leader>gl', '<cmd>Git log<cr>', desc = 'Git log' },
{ '<leader>gp', '<cmd>Git push<cr>', desc = 'Git push' },
{ '<leader>gf', '<cmd>Git fetch<cr>', desc = 'Git fetch' },
},
},
-- Gitsigns - Git gutter and hunk operations
{
'lewis6991/gitsigns.nvim',
event = 'VeryLazy',
config = function()
require('plugins.config.git').setup_gitsigns()
end,
},
}

View file

@ -0,0 +1,33 @@
-- Indent guides - Show vertical lines at indentation levels
return {
'lukas-reineke/indent-blankline.nvim',
event = { 'BufReadPost', 'BufNewFile' },
main = 'ibl',
opts = {
indent = {
char = '',
tab_char = '',
},
scope = {
enabled = true,
show_start = true,
show_end = false,
injected_languages = false,
highlight = { 'Function', 'Label' },
},
exclude = {
filetypes = {
'help',
'alpha',
'dashboard',
'neo-tree',
'Trouble',
'lazy',
'mason',
'notify',
'toggleterm',
'lazyterm',
},
},
},
}

25
lua/plugins/spec/init.lua Normal file
View file

@ -0,0 +1,25 @@
-- Main plugin loader - imports all plugin specifications
return {
-- UI and Theme
{ import = 'plugins.spec.ui' },
{ import = 'plugins.spec.editor' },
{ import = 'plugins.spec.autopairs' },
{ import = 'plugins.spec.indent-line' },
-- Core functionality
{ import = 'plugins.spec.lsp' },
{ import = 'plugins.spec.treesitter' },
{ import = 'plugins.spec.telescope' },
{ import = 'plugins.spec.blink' },
-- Git integration
{ import = 'plugins.spec.git' },
-- Development tools
{ import = 'plugins.spec.copilot' },
{ import = 'plugins.spec.debug' },
{ import = 'plugins.spec.formatting' },
-- Navigation
{ import = 'plugins.spec.nvim-tmux-navigator' },
}

26
lua/plugins/spec/lsp.lua Normal file
View file

@ -0,0 +1,26 @@
-- LSP Plugin Specification
return {
{
'neovim/nvim-lspconfig',
event = { 'BufReadPost', 'BufNewFile' },
dependencies = {
{ 'j-hui/fidget.nvim', opts = {} },
'folke/lazydev.nvim',
},
config = function()
require('plugins.config.lsp').setup()
end,
},
-- LazyDev for better Neovim Lua development
{
'folke/lazydev.nvim',
ft = 'lua',
opts = {
library = {
{ path = 'luvit-meta/library', words = { 'vim%.uv' } },
},
},
},
}

View file

@ -0,0 +1,11 @@
-- Tmux navigation integration
return {
'christoomey/vim-tmux-navigator',
keys = {
{ '<C-h>', ':TmuxNavigateLeft<CR>', desc = 'Navigate to left tmux pane' },
{ '<C-j>', ':TmuxNavigateDown<CR>', desc = 'Navigate to down tmux pane' },
{ '<C-k>', ':TmuxNavigateUp<CR>', desc = 'Navigate to up tmux pane' },
{ '<C-l>', ':TmuxNavigateRight<CR>', desc = 'Navigate to right tmux pane' },
{ '<C-\\>', ':TmuxNavigatePrevious<CR>', desc = 'Navigate to previous tmux pane' },
},
}

View file

@ -0,0 +1,21 @@
-- Telescope - Fuzzy finder
return {
'nvim-telescope/telescope.nvim',
event = 'VimEnter',
branch = '0.1.x',
dependencies = {
'nvim-lua/plenary.nvim',
{
'nvim-telescope/telescope-fzf-native.nvim',
build = 'make',
cond = function()
return vim.fn.executable 'make' == 1
end,
},
{ 'nvim-telescope/telescope-ui-select.nvim' },
{ 'nvim-tree/nvim-web-devicons', enabled = vim.g.have_nerd_font },
},
config = function()
require('plugins.config.telescope').setup()
end,
}

View file

@ -0,0 +1,45 @@
-- Treesitter - Syntax highlighting and text objects
return {
'nvim-treesitter/nvim-treesitter',
event = { 'BufReadPost', 'BufNewFile' },
build = ':TSUpdate',
main = 'nvim-treesitter.configs',
opts = {
ensure_installed = {
'bash',
'c',
'cmake',
'cpp',
'diff',
'html',
'lua',
'luadoc',
'make',
'markdown',
'markdown_inline',
'nix',
'python',
'query',
'vim',
'vimdoc',
'yaml',
},
auto_install = true,
highlight = {
enable = true,
additional_vim_regex_highlighting = false,
},
indent = {
enable = true,
},
incremental_selection = {
enable = true,
keymaps = {
init_selection = '<c-space>',
node_incremental = '<c-space>',
scope_incremental = false,
node_decremental = '<bs>',
},
},
},
}

29
lua/plugins/spec/ui.lua Normal file
View file

@ -0,0 +1,29 @@
-- UI and Theme plugins
return {
-- Color scheme
{
'folke/tokyonight.nvim',
priority = 1000,
init = function()
vim.cmd.colorscheme 'tokyonight-night'
vim.cmd.hi 'Comment gui=none'
end,
},
-- Which-key for keybind hints
{
'folke/which-key.nvim',
event = 'VimEnter',
config = function()
require('plugins.config.ui').setup_which_key()
end,
},
-- Todo comments highlighting
{
'folke/todo-comments.nvim',
event = 'VimEnter',
dependencies = { 'nvim-lua/plenary.nvim' },
opts = { signs = false }
},
}