-- ============================================================================ -- Modern Neovim Configuration (lazy.nvim) -- ============================================================================ -- Bootstrap lazy.nvim 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) -- ============================================================================ -- Plugin Specifications -- ============================================================================ require("lazy").setup({ -- File tree { 'scrooloose/nerdtree', cmd = 'NERDTreeToggle', }, -- Build/async tools 'tpope/vim-dispatch', -- Git integration 'tpope/vim-fugitive', -- Text manipulation 'tpope/vim-abolish', -- Large file handling { 'LunarVim/bigfile.nvim', config = function() require('bigfile').setup() end, }, -- FZF { 'junegunn/fzf' }, { 'ibhagwan/fzf-lua', branch = 'main', config = function() require('fzf-lua').setup({ winopts = { height = 0.95, width = 0.95 } }) end, }, 'nvim-tree/nvim-web-devicons', -- Alignment { 'junegunn/vim-easy-align', init = function() vim.g.easy_align_delimiters = { ['>'] = { pattern = '>>\\|=>\\|>' }, ['/'] = { pattern = '//\\+\\|/\\*\\|\\*/', delimiter_align = 'l', ignore_groups = {'!Comment'} }, [']'] = { pattern = '[[\\]]', left_margin = 0, right_margin = 0, stick_to_left = 0 }, [')'] = { pattern = '[)]', left_margin = 0, right_margin = 0, stick_to_left = 0 }, ['('] = { pattern = '[(]', left_margin = 0, right_margin = 0, stick_to_left = 0 }, } end, }, -- File picker { 'dmtrKovalenko/fff.nvim', build = function() -- this will download prebuild binary or try to use existing rustup toolchain to build from source -- (if you are using lazy you can use gb for rebuilding a plugin if needed) require("fff.download").download_or_build_binary() end, -- No need to lazy-load with lazy.nvim. -- This plugin initializes itself lazily. lazy = false, keys = { { "f", function() require('fff').find_files() end, desc = 'FFFind files', }, { "r", function() require('fff').live_grep() end, desc = 'LiFFFe grep', }, { "fz", function() require('fff').live_grep({ grep = { modes = { 'fuzzy', 'plain' } } }) end, desc = 'Live fffuzy grep', }, { "R", function() require('fff').live_grep({ query = vim.fn.expand("") }) end, desc = 'Search current word', }, } }, -- C++ syntax highlighting { 'bfrg/vim-cpp-modern', init = function() vim.g.cpp_function_highlight = 1 vim.g.cpp_attributes_highlight = 1 vim.g.cpp_member_highlight = 0 vim.g.cpp_simple_highlight = 1 end, }, -- Motion { url = 'https://codeberg.org/andyg/leap.nvim', lazy = false, config = function() vim.keymap.set({'n', 'x', 'o'}, '', '(leap)') vim.keymap.set({'n', 'x', 'o'}, '', '(leap-from-window)') -- Highly recommended: define a preview filter to reduce visual noise -- and the blinking effect after the first keypress -- (see `:h leap.opts.preview`). -- For example, skip preview if the first character of the match is -- whitespace or is in the middle of an alphabetic word: require('leap').opts.preview = function(ch0, ch1, ch2) return not ( ch1:match('%s') or (ch0:match('%a') and ch1:match('%a') and ch2:match('%a')) ) end -- Define equivalence classes for brackets and quotes, in addition to -- the default whitespace group: require('leap').opts.equivalence_classes = { ' \t\r\n', '([{', ')]}', '\'"`' } -- Use the traversal keys to repeat the previous motion without -- explicitly invoking Leap: require('leap.user').set_repeat_keys('', '') -- Automatic paste after remote yank operations: vim.api.nvim_create_autocmd('User', { pattern = 'RemoteOperationDone', group = vim.api.nvim_create_augroup('LeapRemote', {}), callback = function(event) if vim.v.operator == 'y' and event.data.register == '"' then vim.cmd('normal! p') end end, }) end }, -- Theme { 'sainnhe/gruvbox-material', priority = 1000, init = function() vim.g.gruvbox_material_background = 'hard' vim.g.gruvbox_material_foreground = 'mix' vim.g.gruvbox_material_disable_italic_comment = 1 vim.g.gruvbox_material_enable_italic = 0 vim.g.gruvbox_material_enable_bold = 0 vim.g.gruvbox_material_diagnostic_virtual_text = 'colored' vim.g.gruvbox_material_better_performance = 1 end, config = function() vim.cmd('colorscheme gruvbox-material') end, }, -- Odin syntax 'Tetralux/odin.vim', -- Treesitter { 'nvim-treesitter/nvim-treesitter', build = ':TSUpdate', }, -- LSP { 'williamboman/mason.nvim', config = function() require('mason').setup({}) end, }, { 'williamboman/mason-lspconfig.nvim', config = function() require('mason-lspconfig').setup({ ensure_installed = { "clangd" }, automatic_enable = true, }) end, }, 'neovim/nvim-lspconfig', -- Completion { 'hrsh7th/nvim-cmp', dependencies = { 'hrsh7th/cmp-nvim-lsp', 'hrsh7th/cmp-buffer', 'hrsh7th/cmp-path', 'L3MON4D3/LuaSnip', }, config = function() local cmp = require('cmp') cmp.setup({ sources = { { name = 'nvim_lsp' }, { name = 'buffer' }, { name = 'path' }, }, mapping = cmp.mapping.preset.insert({ [''] = cmp.mapping.confirm({ select = false }), [''] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }), [''] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Insert }), }), snippet = { expand = function(args) require('luasnip').lsp_expand(args.body) end, }, }) end, }, 'hrsh7th/cmp-nvim-lsp', 'hrsh7th/cmp-buffer', 'hrsh7th/cmp-path', 'L3MON4D3/LuaSnip', -- Utilities 'nvim-lua/plenary.nvim', }, { install = { colorscheme = { "gruvbox-material" }, }, checker = { enabled = false, }, }) -- ============================================================================ -- Options -- ============================================================================ vim.opt.autowrite = true vim.opt.colorcolumn = { 80, 100 } vim.opt.completeopt = { 'menu', 'menuone', 'noselect' } vim.opt.cpoptions:append('$') vim.opt.cursorline = true vim.opt.expandtab = true vim.opt.guifont = 'JetBrains_Mono,Consolas:h9' vim.opt.hlsearch = false vim.opt.ignorecase = true vim.opt.linebreak = true vim.opt.list = true vim.opt.listchars:append('tab:>-,trail:■,extends:»,precedes:«') vim.opt.number = true vim.opt.relativenumber = true vim.opt.shiftwidth = 4 vim.opt.splitright = true vim.opt.swapfile = false vim.opt.textwidth = 80 vim.opt.visualbell = true vim.opt.wrap = false vim.opt.signcolumn = 'no' -- Setup undo and backup directories vim.opt.undofile = true vim.opt.undodir = vim.fn.stdpath('config') .. '/undo' vim.opt.backupdir = vim.fn.stdpath('config') .. '/backup' -- Status line vim.opt.statusline = '%<%F%h%m%r [%{&ff}] (%{strftime("%H:%M %d/%m/%Y",getftime(expand("%:p")))})%=%l,%c%V %P' -- Wild ignore vim.opt.wildignore:append('*.class,*.o,*\\tmp\\*,*.swp,*.zip,*.exe,*.obj,*.vcxproj,*.pdb,*.idb') -- Mouse support vim.opt.mouse = 'a' -- Spelling vim.opt.spell = true -- ============================================================================ -- LSP Configuration -- ============================================================================ local opts = { noremap = true, silent = true } vim.keymap.set("n", "", vim.lsp.buf.rename, opts) vim.keymap.set("n", "", vim.lsp.buf.code_action, opts) vim.keymap.set('n', 'gd', vim.lsp.buf.definition, opts) vim.keymap.set('n', 'gr', vim.lsp.buf.references, opts) -- Diagnostic configuration vim.diagnostic.config({ signs = false, virtual_text = true, }) -- Spelling highlight vim.api.nvim_create_autocmd("LspAttach", { callback = function() vim.cmd("highlight SpellBad gui=underline guifg=#d3869b") end, }) -- ============================================================================ -- Vim Dispatch Configuration -- ============================================================================ if vim.fn.has('win64') == 1 or vim.fn.has('win32') == 1 or vim.fn.has('win16') == 1 then if os.getenv('SHELL') ~= nil then vim.o.shellcmdflag = '-c' vim.o.makeprg = "./build.sh" else vim.o.makeprg = "build.bat" end else vim.o.makeprg = "./build.sh" end -- ============================================================================ -- Autocommands -- ============================================================================ -- Automatically scroll to bottom of quickfix window when opened vim.api.nvim_create_autocmd("FileType", { pattern = "qf", callback = function() vim.cmd('normal! G') end, }) -- Per-Project Bindings - load project file on buffer enter vim.api.nvim_create_autocmd("BufEnter", { callback = function() local project_file = vim.fn.getcwd() .. '/project_nvim.lua' if vim.fn.filereadable(project_file) == 1 then vim.cmd('luafile ' .. vim.fn.fnameescape(project_file)) end end, }) -- Formatting options vim.api.nvim_create_augroup("persistent_settings", { clear = true }) vim.api.nvim_create_autocmd("BufEnter", { group = "persistent_settings", pattern = "*", command = "set formatoptions=q1j", }) -- ============================================================================ -- Functions -- ============================================================================ local function raddbg_open_file() local filepath = vim.fn.expand("%:p"):gsub('\\', '/') vim.fn.system("dev raddbg --ipc open " .. filepath) vim.fn.system("dev raddbg --ipc goto_line " .. vim.fn.line(".")) vim.fn.system("powershell -Command Add-Type -AssemblyName Microsoft.VisualBasic; [Microsoft.VisualBasic.Interaction]::AppActivate('The RAD Debugger')") end local function raddbg_start_debugging() vim.fn.system("dev raddbg --ipc run") end local function raddbg_stop_debugging() vim.fn.system("dev raddbg --ipc kill_all") end local function raddbg_run_to_cursor() local filepath = vim.fn.expand("%:p"):gsub('\\', '/') vim.fn.system("dev raddbg --ipc open " .. filepath) vim.fn.system("dev raddbg --ipc goto_line " .. vim.fn.line(".")) vim.fn.system("dev raddbg --ipc run_to_cursor " .. filepath .. ":" .. vim.fn.line(".")) vim.fn.system("powershell -Command Add-Type -AssemblyName Microsoft.VisualBasic; [Microsoft.VisualBasic.Interaction]::AppActivate('The RAD Debugger')") end local function raddbg_add_breakpoint() local filepath = vim.fn.expand("%:p"):gsub('\\', '/') vim.fn.system("dev raddbg --ipc open " .. filepath) vim.fn.system("dev raddbg --ipc goto_line " .. vim.fn.line(".")) vim.fn.system("dev raddbg --ipc toggle_breakpoint " .. filepath .. ":" .. vim.fn.line(".")) vim.fn.system("powershell -Command Add-Type -AssemblyName Microsoft.VisualBasic; [Microsoft.VisualBasic.Interaction]::AppActivate('The RAD Debugger')") end -- ============================================================================ -- Keymaps -- ============================================================================ local function adjust_fontsize(amount) -- Get current font and size local current_font = vim.opt.guifont:get()[1] or "Consolas" local current_size = tonumber(current_font:match(":h(%d+)")) or 12 -- Extract font name (everything before :h) local font_name = current_font:match("^(.+):h%d+") or current_font -- Calculate new size local new_size = math.max(6, current_size + amount) -- Minimum size of 6 -- Apply new font setting if vim.g.neovide then vim.opt.guifont = font_name .. ":h" .. new_size else vim.cmd("GuiFont! " .. font_name .. ":h" .. new_size) end end -- Numpad mappings vim.keymap.set('n', '', function() adjust_fontsize(1) end) vim.keymap.set('n', '', function() adjust_fontsize(-1) end) -- FZF Bindings vim.keymap.set('n', 'h', 'FzfLua oldfiles') vim.keymap.set('n', 't', 'FzfLua lsp_live_workspace_symbols') vim.keymap.set('n', 'T', 'FzfLua lsp_finder') vim.keymap.set('n', 'b', 'FzfLua buffers') vim.keymap.set('n', '', 'FzfLua') -- Window navigation vim.keymap.set('n', '', 'h', { silent = true }) vim.keymap.set('n', '', 'j', { silent = true }) vim.keymap.set('n', '', 'k', { silent = true }) vim.keymap.set('n', '', 'l', { silent = true }) -- Move by wrapped lines vim.keymap.set('n', 'j', 'gj') vim.keymap.set('n', 'k', 'gk') vim.keymap.set('n', 'gj', 'j') vim.keymap.set('n', 'gk', 'k') -- NERDTree vim.keymap.set('n', '', ':NERDTreeToggle') -- Change to current buffer's directory vim.keymap.set('n', 'cd', function() vim.cmd('cd ' .. vim.fn.expand('%:p:h')) end) -- Buffer splitting vim.keymap.set('n', 's', ':vs') -- Quickfix navigation vim.keymap.set('n', '', ':cn') vim.keymap.set('n', '', ':cp') -- Terminal escape vim.keymap.set('t', '', '') -- Make (Vim Dispatch) vim.keymap.set('n', '', ':Make', { noremap = true }) -- Easy-Align vim.keymap.set('x', 'a', '(LiveEasyAlign)') -- RAD Debugger vim.keymap.set('n', '', function() raddbg_open_file() end, { silent = true }) vim.keymap.set('n', '', function() raddbg_start_debugging() end, { silent = true }) vim.keymap.set('n', '', function() raddbg_stop_debugging() end, { silent = true }) vim.keymap.set('n', '', function() raddbg_add_breakpoint() end, { silent = true }) vim.keymap.set('n', '', function() raddbg_run_to_cursor() end, { silent = true })