diff --git a/README.md b/README.md index 144eb56..d989976 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Neovim Configuration -Portable Neovim configuration using lazy.nvim and native LSP (Neovim 0.11+, tested on 0.12.1). +Portable Neovim configuration using lazy.nvim and native LSP (Neovim 0.11+). ## Installation @@ -16,9 +16,8 @@ git clone --recurse-submodules git@github.com:itme-brain/nixos.git ## Features -- **Native LSP** (`vim.lsp.config` / `vim.lsp.enable`) - no manual server list needed +- **Native LSP** (`vim.lsp.config`) - no manual server list needed - **Smart LSP picker** (`css`) - auto-detects installed servers for current filetype -- **Neovim 0.12 compatible** - uses built-in `:lsp` commands and keeps legacy `:Lsp*` aliases working - **Portable** - works on NixOS (LSPs via extraPackages) or any system (LSPs via Mason) - **Mason** - auto-disabled on NixOS, auto-installs essentials elsewhere @@ -40,7 +39,6 @@ On other systems, Mason auto-installs: - `yamlls` - YAML The smart picker (`css`) scans all lspconfig servers and shows only those with binaries installed. -On Neovim 0.12+, start/stop/restart uses the built-in `:lsp` commands under the hood. ## Key Bindings @@ -56,8 +54,8 @@ On Neovim 0.12+, start/stop/restart uses the built-in `:lsp` commands under the | `gr` | Find references | | `e` | Toggle file explorer | | `bd` | Delete buffer | -| `/` | Live grep from git root | -| `ff` | Find files from git root | +| `/` | Live grep | +| `ff` | Find files | ## Plugins diff --git a/init.lua b/init.lua index fad0bd2..dd3b61d 100644 --- a/init.lua +++ b/init.lua @@ -1,11 +1,9 @@ local function load_config_directory(directory) local config_path = vim.fn.stdpath("config") .. "/lua/" .. directory - local files = vim.fn.readdir(config_path, function(name) - return name:sub(-4) == ".lua" - end) + local files = vim.fn.glob(config_path .. "/*.lua", false, true) for _, file in ipairs(files) do - local file_name = file:sub(1, -5) + local file_name = vim.fn.fnamemodify(file, ":t:r") -- Extract filename without extension require(directory .. "." .. file_name) end end diff --git a/lua/config/options.lua b/lua/config/options.lua index 3bb30b8..96163da 100644 --- a/lua/config/options.lua +++ b/lua/config/options.lua @@ -26,23 +26,10 @@ vim.opt.guicursor = "n-v-c:block,i:block,r:block" vim.opt.fillchars = { eob = " " } -local options_group = vim.api.nvim_create_augroup("config_options", { clear = true }) +vim.cmd([[ + autocmd FileType python,haskell,c,cpp setlocal tabstop=4 shiftwidth=4 softtabstop=4 +]]) -vim.api.nvim_create_autocmd("FileType", { - group = options_group, - pattern = { "python", "haskell", "c", "cpp" }, - callback = function() - local opt = vim.opt_local - opt.tabstop = 4 - opt.shiftwidth = 4 - opt.softtabstop = 4 - end, -}) - -vim.api.nvim_create_autocmd({ "BufRead", "BufNewFile" }, { - group = options_group, - pattern = "*.purs", - callback = function(event) - vim.bo[event.buf].filetype = "purescript" - end, -}) +vim.cmd([[ + au BufRead,BufNewFile *.purs set filetype=purescript +]]) diff --git a/lua/plugins/colorscheme.lua b/lua/plugins/colorscheme.lua index a5ab11e..d637c4e 100644 --- a/lua/plugins/colorscheme.lua +++ b/lua/plugins/colorscheme.lua @@ -1,101 +1,69 @@ return { - { - "chriskempson/base16-vim", - config = function() - local color_group = vim.api.nvim_create_augroup("config_colorscheme", { clear = true }) + { + "chriskempson/base16-vim", + config = function() + vim.cmd("colorscheme base16-onedark") + vim.cmd([[ + hi Normal guibg=NONE ctermbg=NONE guifg=#FFFFFF + hi Visual ctermbg=Gray ctermfg=Black guibg=Gray guifg=Black + hi NonText guibg=NONE ctermbg=NONE + hi LineNr guibg=NONE ctermbg=NONE + hi CursorLine guibg=NONE ctermbg=NONE + hi CursorLineNr guibg=NONE ctermbg=NONE guifg=#E5C07B ctermfg=Yellow cterm=bold + hi Search ctermfg=Black guifg=#000000 ctermbg=Gray guibg=#FFCC66 + hi Pmenu ctermbg=Black ctermfg=White cterm=NONE guibg=Black guifg=White gui=NONE + hi PmenuSel ctermbg=Green ctermfg=Black cterm=NONE guibg=Green guifg=Black gui=NONE + hi PmenuThumb ctermbg=Green guibg=Green + hi PmenuSbar ctermbg=Black guibg=Black + hi WinSeparator guibg=NONE ctermbg=NONE - local highlights = { - Normal = { bg = "NONE", fg = "#FFFFFF" }, - Visual = { bg = "Gray", fg = "Black" }, - NonText = { bg = "NONE" }, - LineNr = { bg = "NONE" }, - CursorLine = { bg = "NONE" }, - CursorLineNr = { bg = "NONE", fg = "#E5C07B", bold = true }, - Search = { bg = "#FFCC66", fg = "#000000" }, - Pmenu = { bg = "Black", fg = "White" }, - PmenuSel = { bg = "Green", fg = "Black" }, - PmenuThumb = { bg = "Green" }, - PmenuSbar = { bg = "Black" }, - WinSeparator = { bg = "NONE" }, - GitGutterChange = { bg = "NONE" }, - GitGutterAdd = { bg = "NONE" }, - GitGutterDelete = { bg = "NONE" }, - GitSignsAddNr = { bg = "NONE", fg = "#98c379" }, - GitSignsChangeNr = { bg = "NONE", fg = "#61afef" }, - GitSignsDeleteNr = { bg = "NONE", fg = "#e06c75" }, - SignColumn = { bg = "NONE" }, - NeoTreeGitAdded = { bg = "NONE", fg = "#98c379" }, - NeoTreeGitModified = { bg = "NONE", fg = "#e5c07b" }, - NeoTreeGitDeleted = { bg = "NONE", fg = "#e06c75" }, - NeoTreeGitConflict = { bg = "NONE", fg = "#e06c75" }, - NeoTreeGitUntracked = { bg = "NONE", fg = "#61afef" }, - TelescopeSelection = { bg = "Gray", fg = "Green", bold = true }, - TelescopePreviewMatch = { bg = "Yellow", fg = "Black" }, - TreesitterContext = { bg = "NONE" }, - LazyH1 = { bg = "Black", fg = "Green" }, - IblScope = { bg = "NONE", fg = "Yellow" }, - ConflictMarker = { fg = "red" }, - DiffAdd = { bg = "NONE" }, - DiffChange = { bg = "NONE" }, - DiffDelete = { bg = "NONE" }, - DiffText = { bg = "NONE" }, - BufferLineFill = { bg = "NONE" }, - BufferLineBackground = { bg = "NONE", fg = "#5c6370" }, - BufferLineBuffer = { bg = "NONE", fg = "#5c6370" }, - BufferLineBufferSelected = { bg = "NONE", fg = "#FFFFFF", bold = true }, - BufferLineBufferVisible = { bg = "NONE", fg = "#abb2bf" }, - BufferLineCloseButton = { bg = "NONE", fg = "#5c6370" }, - BufferLineCloseButtonSelected = { bg = "NONE", fg = "#e06c75" }, - BufferLineCloseButtonVisible = { bg = "NONE", fg = "#5c6370" }, - BufferLineModified = { bg = "NONE", fg = "#e5c07b" }, - BufferLineModifiedSelected = { bg = "NONE", fg = "#e5c07b" }, - BufferLineModifiedVisible = { bg = "NONE", fg = "#e5c07b" }, - BufferLineSeparator = { bg = "NONE", fg = "#3e4452" }, - BufferLineSeparatorSelected = { bg = "NONE", fg = "#3e4452" }, - BufferLineSeparatorVisible = { bg = "NONE", fg = "#3e4452" }, - BufferLineIndicatorSelected = { bg = "NONE", fg = "#61afef" }, - YankHighlight = { bg = "yellow", fg = "black" }, - } + hi GitGutterChange guibg=NONE ctermbg=NONE + hi GitGutterAdd guibg=NONE ctermbg=NONE + hi GitGutterDelete guibg=NONE ctermbg=NONE + hi SignColumn ctermbg=NONE guibg=NONE - local function apply_highlights() - for group, spec in pairs(highlights) do - vim.api.nvim_set_hl(0, group, spec) - end - end + hi TelescopeSelection guibg=Gray guifg=Green gui=bold ctermbg=Black ctermfg=Green cterm=bold + hi TelescopePreviewMatch ctermbg=Yellow ctermfg=Black guibg=Yellow guifg=Black - local conflict_pattern = [[<<<<<<< HEAD\|=======\|>>>>>>> .\+]] - local function apply_conflict_match(win) - if vim.w[win].conflict_marker_match_id then - pcall(vim.fn.matchdelete, vim.w[win].conflict_marker_match_id, win) - end - vim.w[win].conflict_marker_match_id = vim.fn.matchadd("ConflictMarker", conflict_pattern, 10, -1, { - window = win, - }) - end + hi TreesitterContext guibg=NONE ctermbg=NONE - vim.cmd.colorscheme("base16-onedark") - apply_highlights() + hi LazyH1 ctermbg=Green ctermfg=Black guibg=Black guifg=Green + hi IblScope guibg=NONE guifg=Yellow ctermbg=NONE ctermfg=Yellow + + hi ConflictMarker ctermfg=red guifg=red + match ConflictMarker /<<<<<<< HEAD\|=======\|>>>>>>> .\+/ - vim.api.nvim_create_autocmd("ColorScheme", { - group = color_group, - callback = apply_highlights, - }) + hi DiffAdd ctermbg=none guibg=none + hi DiffChange ctermbg=none guibg=none + hi DiffDelete ctermbg=none guibg=none + hi DiffText ctermbg=none guibg=none - vim.api.nvim_create_autocmd({ "BufWinEnter", "WinEnter" }, { - group = color_group, - callback = function(event) - apply_conflict_match(vim.api.nvim_get_current_win()) - end, - }) + " Bufferline - dark background, readable text + hi BufferLineFill guibg=NONE ctermbg=NONE + hi BufferLineBackground guibg=NONE ctermbg=NONE guifg=#5c6370 ctermfg=Gray + hi BufferLineBuffer guibg=NONE ctermbg=NONE guifg=#5c6370 ctermfg=Gray + hi BufferLineBufferSelected guibg=NONE ctermbg=NONE guifg=#FFFFFF ctermfg=White gui=bold cterm=bold + hi BufferLineBufferVisible guibg=NONE ctermbg=NONE guifg=#abb2bf ctermfg=White + hi BufferLineCloseButton guibg=NONE ctermbg=NONE guifg=#5c6370 ctermfg=Gray + hi BufferLineCloseButtonSelected guibg=NONE ctermbg=NONE guifg=#e06c75 ctermfg=Red + hi BufferLineCloseButtonVisible guibg=NONE ctermbg=NONE guifg=#5c6370 ctermfg=Gray + hi BufferLineModified guibg=NONE ctermbg=NONE guifg=#e5c07b ctermfg=Yellow + hi BufferLineModifiedSelected guibg=NONE ctermbg=NONE guifg=#e5c07b ctermfg=Yellow + hi BufferLineModifiedVisible guibg=NONE ctermbg=NONE guifg=#e5c07b ctermfg=Yellow + hi BufferLineSeparator guibg=NONE ctermbg=NONE guifg=#3e4452 ctermfg=DarkGray + hi BufferLineSeparatorSelected guibg=NONE ctermbg=NONE guifg=#3e4452 ctermfg=DarkGray + hi BufferLineSeparatorVisible guibg=NONE ctermbg=NONE guifg=#3e4452 ctermfg=DarkGray + hi BufferLineIndicatorSelected guibg=NONE ctermbg=NONE guifg=#61afef ctermfg=Blue + ]]) vim.api.nvim_create_autocmd("TextYankPost", { - group = color_group, callback = function() + vim.cmd("highlight YankHighlight ctermbg=yellow ctermfg=black guibg=yellow guifg=black") vim.highlight.on_yank({ higroup = "YankHighlight", timeout = 150 }) end, }) - end, - }, + end, + }, { "folke/todo-comments.nvim", diff --git a/lua/plugins/indent-blankline.lua b/lua/plugins/indent-blankline.lua index 27fae5a..418ab88 100644 --- a/lua/plugins/indent-blankline.lua +++ b/lua/plugins/indent-blankline.lua @@ -2,17 +2,10 @@ return { { "lukas-reineke/indent-blankline.nvim", config = function() - local hooks = require("ibl.hooks") - - hooks.register(hooks.type.HIGHLIGHT_SETUP, function() - vim.api.nvim_set_hl(0, "IblIndent", { link = "Comment" }) - end) - require("ibl").setup({ - indent = { - char = "|", - highlight = "IblIndent", - }, + --indent = { char = "│" }, + --indent = { char = "⎸" }, + indent = { char = "┆" }, scope = { enabled = false }, diff --git a/lua/plugins/lsp.lua b/lua/plugins/lsp.lua index c31339b..ad0c2a3 100644 --- a/lua/plugins/lsp.lua +++ b/lua/plugins/lsp.lua @@ -141,23 +141,6 @@ return { config = function() local lspconfig = require('lspconfig') - -- Neovim 0.12 exposes built-in :lsp commands and skips lspconfig's legacy - -- :Lsp* aliases. Recreate the old names so existing mappings keep working. - if vim.fn.exists(':lsp') == 2 and vim.fn.exists(':LspStart') == 0 then - vim.api.nvim_create_user_command('LspStart', function(info) - vim.cmd('lsp enable ' .. table.concat(info.fargs, ' ')) - end, { nargs = '*' }) - - vim.api.nvim_create_user_command('LspRestart', function(info) - vim.cmd('lsp restart ' .. table.concat(info.fargs, ' ')) - end, { nargs = '*', bang = true }) - - vim.api.nvim_create_user_command('LspStop', function(info) - local suffix = info.bang and '!' or '' - vim.cmd('lsp stop' .. suffix .. ' ' .. table.concat(info.fargs, ' ')) - end, { nargs = '*', bang = true }) - end - -- Diagnostic display configuration vim.diagnostic.config({ virtual_text = { @@ -182,30 +165,23 @@ return { severity_sort = true, }) - -- Add border to hover and signature help windows. - local hover_handler = vim.lsp.handlers.hover - vim.lsp.handlers['textDocument/hover'] = function(err, result, ctx, config) - return hover_handler(err, result, ctx, vim.tbl_extend('force', config or {}, { - border = 'rounded', - })) - end - - local signature_help_handler = vim.lsp.handlers.signature_help - vim.lsp.handlers['textDocument/signatureHelp'] = function(err, result, ctx, config) - return signature_help_handler(err, result, ctx, vim.tbl_extend('force', config or {}, { - border = 'rounded', - })) - end + -- Add border to hover and signature help windows + vim.lsp.handlers['textDocument/hover'] = vim.lsp.with( + vim.lsp.handlers.hover, + { border = 'rounded' } + ) + vim.lsp.handlers['textDocument/signatureHelp'] = vim.lsp.with( + vim.lsp.handlers.signature_help, + { border = 'rounded' } + ) -- Get all known server names by scanning lspconfig's lsp directory local function get_all_servers() local servers = {} local lsp_path = vim.fn.stdpath('data') .. '/lazy/nvim-lspconfig/lsp' - local files = vim.fn.readdir(lsp_path, function(name) - return name:sub(-4) == '.lua' - end) + local files = vim.fn.globpath(lsp_path, '*.lua', false, true) for _, file in ipairs(files) do - local server = file:sub(1, -5) + local server = vim.fn.fnamemodify(file, ':t:r') table.insert(servers, server) end return servers @@ -270,7 +246,8 @@ return { table.sort(matching) local function start_server(server) - vim.lsp.enable(server) + vim.lsp.enable(server) -- Register on-demand + vim.cmd('LspStart ' .. server) end if #matching == 0 then @@ -293,9 +270,9 @@ return { { "cs", group = "LSP Commands" }, { "cf", function() vim.lsp.buf.format() end, desc = "Code Format" }, { "csi", ":checkhealth vim.lsp", desc = "LSP Info" }, - { "csr", ":lsp restart", desc = "LSP Restart" }, + { "csr", ":LspRestart", desc = "LSP Restart" }, { "css", lsp_start_smart, desc = "LSP Start" }, - { "csx", ":lsp stop", desc = "LSP Stop" }, + { "csx", ":LspStop", desc = "LSP Stop" }, }) end }, diff --git a/lua/plugins/neotree.lua b/lua/plugins/neotree.lua index c7de716..e2bde05 100644 --- a/lua/plugins/neotree.lua +++ b/lua/plugins/neotree.lua @@ -41,20 +41,18 @@ return { }, }) - -- Keep the selected entry readable without a solid row background. - vim.api.nvim_set_hl(0, "NeoTreeCursorLine", { bg = "NONE", fg = "#a6e3a1" }) + -- Set up cursorline highlight for neo-tree (green text on dark bg) + vim.api.nvim_set_hl(0, "NeoTreeCursorLine", { bg = "#313244", fg = "#a6e3a1" }) -- Apply highlight and re-apply on colorscheme change vim.api.nvim_create_autocmd({ "FileType", "ColorScheme" }, { pattern = { "neo-tree", "*" }, callback = function(ev) if ev.event == "ColorScheme" then - vim.api.nvim_set_hl(0, "NeoTreeCursorLine", { bg = "NONE", fg = "#a6e3a1" }) + vim.api.nvim_set_hl(0, "NeoTreeCursorLine", { bg = "#313244", fg = "#a6e3a1" }) end - local win = vim.api.nvim_get_current_win() - local buf = vim.api.nvim_win_get_buf(win) - if vim.bo[buf].filetype == "neo-tree" then - vim.wo[win].winhighlight = "CursorLine:NeoTreeCursorLine" + if vim.bo.filetype == "neo-tree" then + vim.wo.winhighlight = "CursorLine:NeoTreeCursorLine" end end, }) @@ -77,12 +75,12 @@ return { for _, buf in ipairs(bufs) do local name = api.nvim_buf_get_name(buf) if name:match("neo%-tree filesystem") then - vim.cmd("Neotree close") + api.nvim_command(":Neotree close") return end end - vim.cmd("Neotree") + api.nvim_command(":Neotree") end require("which-key").add({ diff --git a/lua/plugins/telescope.lua b/lua/plugins/telescope.lua index 06d1e0c..9bffbd4 100644 --- a/lua/plugins/telescope.lua +++ b/lua/plugins/telescope.lua @@ -1,13 +1,10 @@ local function get_root() - local result = vim.system({ "git", "rev-parse", "--show-toplevel" }, { text = true }):wait() - if result.code == 0 and result.stdout then - local git_dir = vim.trim(result.stdout) - if git_dir ~= "" then - return git_dir - end + local git_dir = vim.fn.systemlist("git rev-parse --show-toplevel")[1] + if git_dir and git_dir ~= "" then + return git_dir + else + return vim.fn.getcwd() -- Fallback to current working directory if not in a Git repo end - - return vim.fn.getcwd() end return { @@ -25,10 +22,8 @@ return { require('telescope.builtin').live_grep({ cwd = get_root() }) end, desc = "grep" }, - { "ff", function() - require('telescope.builtin').find_files({ cwd = get_root() }) - end, - desc = "Search for Files" }, + { "/", ":Telescope live_grep", desc = "grep" }, + { "ff", ":Telescope fd", desc = "Search for Files" }, { "fp", ":Telescope oldfiles", desc = "Oldfiles" }, { "?", ":Telescope command_history", desc = "Command History" }, { "cm", ":Telescope man_pages", desc = "Manpages" }, @@ -40,14 +35,14 @@ return { if next(attached) ~= nil then require('telescope.builtin').lsp_definitions() else - vim.api.nvim_feedkeys("gd", "n", false) + vim.api.nvim_command('normal! gd') end end, mode = "n", desc = "Go to Definition" }, { "gd", ":Telescope lsp_definitions", desc = "Go to Definition" }, - { "gr", ":Telescope lsp_references", desc = "Goto References" }, + { "gr", ":Telescope lsp_references", desc = "Goto References" }, { "gi", ":Telescope lsp_implementations", desc = "Go to Implementations" }, { "gt", ":Telescope lsp_type_definitions", desc = "Go to Type Definition" }, { "cv", ":Telescope treesitter", desc = "Function Names & Variables" }, diff --git a/lua/plugins/which-key.lua b/lua/plugins/which-key.lua index 94aac0a..3c1f8e5 100644 --- a/lua/plugins/which-key.lua +++ b/lua/plugins/which-key.lua @@ -7,12 +7,8 @@ return { { "l", ":Lazy", desc = "Lazy" }, { "t", function() - vim.cmd.botright("new") - vim.opt_local.number = false - vim.opt_local.relativenumber = false - vim.cmd.resize(10) - vim.cmd.terminal() - vim.cmd.startinsert() + vim.cmd("botright new | setlocal nonumber norelativenumber | resize 10 | terminal") + vim.cmd("startinsert") end, mode = "n", desc = "Open Terminal" @@ -28,14 +24,11 @@ return { { "b", group = "Buffers"}, { "bd", function() - local function is_neotree(bufnr) - return vim.bo[bufnr].filetype == "neo-tree" + local function is_neotree() + return vim.bo.filetype == "neo-tree" end - - local current_buf = vim.api.nvim_get_current_buf() - -- Skip if in neo-tree - if is_neotree(current_buf) then + if is_neotree() then vim.notify("Cannot delete buffer from neo-tree", vim.log.levels.WARN) return end @@ -45,32 +38,15 @@ return { vim.notify("Cannot delete last buffer", vim.log.levels.WARN) return end - vim.cmd.bprevious() - vim.cmd.bdelete({ args = { tostring(current_buf) } }) + local buf_to_delete = vim.api.nvim_get_current_buf() + vim.cmd('bprevious') + vim.cmd('bdelete ' .. buf_to_delete) -- If we ended up in neo-tree, move back to a regular window - local new_buf = vim.api.nvim_get_current_buf() - if is_neotree(new_buf) then - vim.cmd.wincmd("l") + if is_neotree() then + vim.cmd('wincmd l') end end, desc = "Delete Buffer" }, - { "bD", function() - local current_buf = vim.api.nvim_get_current_buf() - local current_win = vim.api.nvim_get_current_win() - - if vim.bo[current_buf].filetype == "neo-tree" then - vim.notify("Cannot delete neo-tree buffer", vim.log.levels.WARN) - return - end - - local wins = vim.fn.win_findbuf(current_buf) - if #wins > 1 then - vim.api.nvim_win_close(current_win, false) - end - - if vim.api.nvim_buf_is_valid(current_buf) then - vim.cmd('bdelete! ' .. current_buf) - end - end, desc = "Delete Window & Buffer" }, + { "bD", "execute 'close' | execute 'bd!'", desc = "Delete Window & Buffer" }, { "ca", vim.lsp.buf.code_action, desc = "Code Action" }, { "cr", vim.lsp.buf.rename, desc = "Rename Variable" },