DEVenv/Internal/os_nvim_init.lua
2026-03-11 21:22:14 +11:00

494 lines
14 KiB
Lua

-- ============================================================================
-- 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 = {
{
"<leader>f",
function() require('fff').find_files() end,
desc = 'FFFind files',
},
{
"<leader>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',
},
{
"<leader>R",
function() require('fff').live_grep({ query = vim.fn.expand("<cword>") }) 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'}, '<tab>', '<Plug>(leap)')
vim.keymap.set({'n', 'x', 'o'}, '<S-tab>', '<Plug>(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('<enter>', '<backspace>')
-- 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({
['<CR>'] = cmp.mapping.confirm({ select = false }),
['<Tab>'] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }),
['<S-Tab>'] = 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", "<F2>", vim.lsp.buf.rename, opts)
vim.keymap.set("n", "<F4>", 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', '<C-=>', function() adjust_fontsize(1) end)
vim.keymap.set('n', '<C-->', function() adjust_fontsize(-1) end)
-- FZF Bindings
vim.keymap.set('n', '<leader>h', '<cmd>FzfLua oldfiles<cr>')
vim.keymap.set('n', '<leader>t', '<cmd>FzfLua lsp_live_workspace_symbols<cr>')
vim.keymap.set('n', '<leader>T', '<cmd>FzfLua lsp_finder<cr>')
vim.keymap.set('n', '<leader>b', '<cmd>FzfLua buffers<cr>')
vim.keymap.set('n', '<leader><leader>', '<cmd>FzfLua<cr>')
-- Window navigation
vim.keymap.set('n', '<C-h>', '<C-w>h', { silent = true })
vim.keymap.set('n', '<C-j>', '<C-w>j', { silent = true })
vim.keymap.set('n', '<C-k>', '<C-w>k', { silent = true })
vim.keymap.set('n', '<C-l>', '<C-w>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', '<C-n>', ':NERDTreeToggle<CR>')
-- 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', '<leader>s', ':vs<CR>')
-- Quickfix navigation
vim.keymap.set('n', '<A-j>', ':cn<CR>')
vim.keymap.set('n', '<A-k>', ':cp<CR>')
-- Terminal escape
vim.keymap.set('t', '<Esc>', '<C-\\><C-n>')
-- Make (Vim Dispatch)
vim.keymap.set('n', '<C-b>', ':Make<CR>', { noremap = true })
-- Easy-Align
vim.keymap.set('x', '<leader>a', '<Plug>(LiveEasyAlign)')
-- RAD Debugger
vim.keymap.set('n', '<F6>', function() raddbg_open_file() end, { silent = true })
vim.keymap.set('n', '<F5>', function() raddbg_start_debugging() end, { silent = true })
vim.keymap.set('n', '<S-F5>', function() raddbg_stop_debugging() end, { silent = true })
vim.keymap.set('n', '<F9>', function() raddbg_add_breakpoint() end, { silent = true })
vim.keymap.set('n', '<C-F10>', function() raddbg_run_to_cursor() end, { silent = true })