Files
nixos/config/nvim/stobbsm/nvim.lua

557 lines
20 KiB
Lua

-- {{{ plugins
local gh = 'https://github.com/'
local plugins = {
{ src = 'https://git.sprouting.cloud/sprouting.cloud/sproutingcolour', name = 'sproutingcolour' }, -- colorscheme
{ src = gh .. 'MunifTanjim/nui.nvim', name = 'nui' },
{ src = gh .. 'catgoose/nvim-colorizer.lua', name = 'colorizer' }, -- show colours of colour codes
{ src = gh .. 'echasnovski/mini.nvim', name = 'mini' }, -- a bunch of useful plugins
{ src = gh .. 'folke/noice.nvim', name = 'noice' },
{ src = gh .. 'folke/snacks.nvim', name = 'snacks' },
{ src = gh .. 'kdheepak/lazygit.nvim', name = 'lazygit' },
{ src = gh .. 'neovim/nvim-lspconfig', name = 'lspconfig' }, -- LSP support
{ src = gh .. 'nvim-lua/plenary.nvim', name = 'plenary' },
{ src = gh .. 'ray-x/go.nvim', name = 'go' }, -- Go specific language support
{ src = gh .. 'ray-x/guihua.lua', name = 'guihua' }, -- required for go.nvim
{ src = gh .. 'stevearc/conform.nvim', name = 'conform' },
{ src = gh .. 'folke/which-key.nvim', name = 'whichkey' },
{ src = gh .. 'mikavilpas/yazi.nvim', name = 'yazi' },
{ src = gh .. 'nvimdev/dashboard-nvim', name = 'dashboard' },
{ src = gh .. 'nvim-treesitter/nvim-treesitter', name = 'treesitter' },
{ src = gh .. 'coder/claudecode.nvim', name = 'claudecode' },
{ src = gh .. 'Dan7h3x/neaterm.nvim', name = 'neaterm' },
}
vim.pack.add(plugins)
local function update_plugins()
local plist = {}
for _, v in ipairs(plugins)
do
table.insert(plist, v.name)
end
vim.pack.update(plist)
end -- }}}
-- {{{ Global settings
vim.g.mapleader = ' '
vim.g.maplocalleader = ' '
vim.g.have_nerd_font = true
-- Common defaults
vim.opt.clipboard = 'unnamedplus'
vim.opt.cursorline = true
vim.opt.expandtab = true
vim.opt.hlsearch = true
vim.opt.inccommand = 'split'
vim.opt.modeline = true
vim.opt.mouse = 'a'
vim.opt.number = true
vim.opt.preserveindent = true
vim.opt.relativenumber = true
vim.opt.ruler = true
vim.opt.scrolloff = 5
vim.opt.shiftwidth = 2
vim.opt.showmode = true
vim.opt.showtabline = 1
vim.opt.softtabstop = 2
vim.opt.tabstop = 2
vim.opt.termguicolors = true
vim.opt.listchars = { tab = '» ', trail = '·', nbsp = '' }
vim.opt.inccommand = 'split'
-- Set foldmethod, change in .editorconfig of projects
vim.opt.foldmethod = 'marker'
-- General gui settings
vim.o.guifont = 'JetBrainsMono Nerd Font:12'
-- Neovide settings
if vim.g.neovide then
vim.env.PATH = '/usr/local/bin:' .. vim.env.PATH
vim.env.PATH = '/usr/local/go/bin:' .. vim.env.PATH
vim.env.PATH = '/opt/homebrew/bin:' .. vim.env.PATH
vim.env.PATH = vim.env.HOME .. '/.local/bin:' .. vim.env.PATH
vim.env.PATH = vim.env.HOME .. '/.cargo/bin:' .. vim.env.PATH
vim.env.PATH = vim.env.HOME .. '/.local/cargo/bin:' .. vim.env.PATH
vim.env.PATH = vim.env.HOME .. '/go/bin:' .. vim.env.PATH
vim.env.PATH = vim.env.HOME .. '/.local/npm/bin:' .. vim.env.PATH
end
vim.cmd.colorscheme 'sprouting-dark'
-- }}}
-- {{{ Helper functions
function R(name)
require("plenary.reload").reload_module(name)
end
-- }}}
require('snacks').setup({ -- {{{
animate = {},
dim = {},
image = {},
indent = {},
lazygit = {},
picker = {},
}) -- }}}
require('colorizer').setup({})
require('conform').setup({ -- {{{
formatters_by_ft = {
ansible = { 'ansible-lint' },
buf = { 'buf' },
cmake = { 'cmake_format' },
go = { 'goimports' },
markdown = { 'cbfmt', 'mdformat' },
sql = { 'sqlfluff' },
terraform = { 'terraform_fmt' },
templ = { 'go tool templ fmt' },
},
})
vim.g.snacks_animate = true -- }}}
-- {{{ ferminal scratch pad terminal
local ferminal = {}
local state = {
floating = {
buf = -1,
win = -1,
},
}
local function create_floating_window(opts)
opts = opts or {}
local width = opts.width or math.floor(vim.o.columns * 0.8)
local height = opts.height or math.floor(vim.o.lines * 0.8)
-- Calculate the position to center the window
local col = math.floor((vim.o.columns - width) / 2)
local row = math.floor((vim.o.lines - height) / 2)
-- Create a buffer
local buf = nil
if vim.api.nvim_buf_is_valid(opts.buf) then
buf = opts.buf
else
buf = vim.api.nvim_create_buf(false, true) -- No file, scratch buffer
end
-- Define window configuration
local win_config = {
relative = 'editor',
width = width,
height = height,
col = col,
row = row,
style = 'minimal', -- No borders or extra UI elements
border = 'rounded',
}
-- Create the floating window
local win = vim.api.nvim_open_win(buf, true, win_config)
return { buf = buf, win = win }
end
ferminal.toggle_terminal = function()
if not vim.api.nvim_win_is_valid(state.floating.win) then
state.floating = create_floating_window { buf = state.floating.buf }
if vim.bo[state.floating.buf].buftype ~= 'terminal' then
vim.cmd.terminal()
end
else
vim.api.nvim_win_hide(state.floating.win)
end
end -- }}}
-- {{{ Language configurations
require('go').setup()
-- }}}
require('noice').setup({ -- {{{
lsp = {
override = {
['vim.lsp.util.convert_input_to_markdown_lines'] = true,
['vim.lsp.util.stylize_markdown'] = true,
},
},
popupmenu = {
enabled = true,
backend = 'nui',
},
notify = {
enabled = true,
view = 'notify',
},
routes = {
{
view = 'notify',
filter = { event = 'msg_showmode' },
},
},
}) -- }}}
require('yazi').setup({ -- {{{
open_for_directories = true,
keymaps = {
show_help = '<f1>',
},
})
vim.g.loaded_netrwPlugin = 1 -- }}}
require('dashboard').setup({ -- {{{
theme = 'hyper',
config = {
shortcut = {
{ desc = '󰊳 Update ', group = '@property', key = 'u', action = update_plugins },
{ desc = ' Projects ', group = 'label', key = 'p', action = Snacks.picker.projects },
{ desc = '󰪶 Files ', group = 'OkMsg', key = 'f', action = Snacks.picker.files },
{ desc = '󰿅 Quit ', group = 'ErrorMsg', key = 'q', action = ':q' },
},
packages = { enable = false }, -- show number of installed plugins
project = { enable = true, limit = 8, label = '', action = Snacks.picker.projects },
},
}) -- }}}
require('which-key').setup({ -- {{{
preset = 'modern',
}) -- }}}
require('nvim-treesitter').setup({ -- {{{
install_dir = vim.fn.stdpath('data') .. '/site'
})
require('nvim-treesitter').install({
'asm', 'awk',
'bash',
'c', 'c_sharp', 'caddy', 'cmake', 'comment', 'cpp', 'css', 'csv',
'desktop', 'diff', 'dockerfile', 'dtd',
'editorconfig', 'elm',
'fortran',
'gdscript', 'git_config', 'git_rebase', 'gitattributes', 'gitcommit',
'gitignore', 'go', 'gomod', 'gosum', 'gowork', 'gpg',
'hcl', 'helm', 'html', 'http',
'javascript', 'jinja', 'jinja_inline', 'jq', 'json', 'json5',
'kotlin',
'llvm', 'lua', 'luadoc', 'luap',
'make', 'markdown', 'markdown_inline', 'meson', 'muttrc',
'nasm', 'nginx', 'ninja',
'php', 'php_only', 'phpdoc', 'powershell', 'printf', 'properties',
'regex', 'requirements', 'robot', 'robots_txt', 'rst', 'rust',
'scss', 'sql', 'ssh_config',
'templ', 'terraform', 'tmux', 'toml', 'typescript',
'udev',
'vala', 'vim', 'vimdoc', 'vue',
'xml',
'yaml',
'zig', 'zsh',
})
-- Enable treesitter
vim.api.nvim_create_autocmd('FileType', {
callback = function()
pcall(vim.treesitter.start)
vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()"
end,
})
-- Done nvim-treesitter }}}
require('claudecode').setup({ -- {{{
cwd_provider = function(ctx)
local cwd = require('claudecode.cwd').git_root(ctx.file_dir or ctx.cwd) or ctx.file_dir or ctx.cwd
return cwd
end,
})
-- Done claudecode }}}
require('neaterm').setup() -- {{{
-- Done neaterm }}}
-- Filetype configuration {{{
vim.filetype.add({
extension = {
Containerfile = 'dockerfile',
Dockerfile = 'dockerfile',
containerfile = 'containerfile',
dockerfile = 'dockerfile',
j2 = 'jinja',
jinja = 'jinja',
jinja2 = 'jinja',
tf = 'terraform',
tfstate = 'json',
tfvars = 'terraform',
templ = 'templ',
},
}) -- }}}
-- {{{ LSP Configuration
local lspproto = vim.lsp.protocol
local lspconfig = vim.lsp.config
local lspenable = vim.lsp.enable
local capabilities = lspproto.make_client_capabilities()
-- Formatter autocmd
vim.api.nvim_create_autocmd({ 'BufWritePre' }, {
callback = function(args)
require("conform").format({ bufnr = args.buf })
end,
})
-- Simple lspconfigs
vim.lsp.config('ansiblels', capabilities)
vim.lsp.config('bashls', capabilities)
vim.lsp.config('buf_ls', capabilities)
vim.lsp.config('clangd', capabilities)
vim.lsp.config('gopls', capabilities)
vim.lsp.config('intelephense', capabilities)
vim.lsp.config('jinja_lsp', capabilities)
vim.lsp.config('nginx_language_server', capabilities)
vim.lsp.config('pyright', capabilities)
vim.lsp.config('sqlls', capabilities)
vim.lsp.config('templ', capabilities)
vim.lsp.config('terraformls', capabilities)
vim.lsp.config('qmlls', capabilities)
vim.lsp.config('zls', capabilities)
-- LSP with more advanced configuration
local caps_snippt_support = function()
local caps = lspproto.make_client_capabilities()
caps.textDocument.completion.completionItem.snippetSupport = true
return caps
end
vim.lsp.config('cssls', {
capabilities = caps_snippt_support() })
vim.lsp.config('html', {
capabilities = caps_snippt_support(),
filetypes = { 'html', 'templ' }
})
vim.lsp.config('htmx', {
capabilities = caps_snippt_support(),
filetypes = { 'html', 'templ' }
})
vim.lsp.config('jsonls', {
capabilities = caps_snippt_support() })
vim.lsp.config('dockerls', {
settings = { docker = { languageserver = { formatter = { ignoreMultilineInstructions = true }, } } } })
vim.lsp.config('eslint', {
on_attach = function(_, bufnr)
vim.api.nvim_create_autocmd('BufWritePre', { buffer = bufnr, command = 'EslintFixAll', })
end,
})
vim.lsp.config('lua_ls', {
on_init = function(client)
if client.workspace_folders then
local path = client.workspace_folders[1].name
if vim.uv.fs_stat(path .. '/.luarc.json') or vim.uv.fs_stat(path .. '/.luarc.jsonc') then
return
end
end
client.config.settings.Lua = vim.tbl_deep_extend('force', client.config.settings.Lua, {
runtime = { version = 'LuaJIT' },
workspace = { checkThirdParty = false, library = { vim.env.VIMRUNTIME, '${3rd}/luv/library' } },
format = { enable = true, defaultConfig = { indent_style = 'space', indent_size = '2' } },
diagnostics = { globals = { 'vim', 'Snacks', 'MiniSessions', 'MiniPick', 'MiniStatusline' } },
})
end,
settings = {
Lua = {}
}
})
vim.lsp.config('templ', {
cmd = { 'go', 'tool', 'github.com/a-h/templ/cmd/templ', 'lsp' },
})
vim.lsp.config('tailwindcss', {
capabilities = capabilities,
filetypes = { 'templ', 'astro', 'javascript', 'typescript', 'react' },
settings = {
tailwindCSS = {
includeLanguages = {
templ = 'html',
},
},
},
})
vim.lsp.config('yamlls', {
format = { enable = true, bracketSpacing = true },
})
lspenable({
'ansiblels',
'bashls',
'buf_ls',
'clangd',
'cssls',
'dockerls',
'eslint',
'eslint',
'gopls',
'html',
'htmx',
'intelephense',
'jinja_lsp',
'jsonls',
'lua_ls',
'nginx_language_server',
'pyright',
'qmlls',
'sqlls',
'tailwindcss',
'templ',
'terraformls',
'zls',
}) -- end LSPConfig }}}
-- {{{ mini.nvim setup
require('mini.basics').setup()
require('mini.ai').setup({ n_lines = 200 })
require('mini.align').setup()
require('mini.completion').setup()
require('mini.diff').setup()
require('mini.extra').setup()
require('mini.git').setup()
require('mini.icons').setup()
require('mini.move').setup()
require('mini.operators').setup()
require('mini.pairs').setup()
require('mini.snippets').setup()
require('mini.splitjoin').setup()
require('mini.statusline').setup({
content = {
active = function()
local check_macro_recording = function()
if vim.fn.reg_recording() ~= '' then
return '@' .. vim.fn.reg_recording()
else
return ''
end
end
-- configure statusline for active windows
local mode, mode_hl = MiniStatusline.section_mode { trunc_width = 120 }
local git = MiniStatusline.section_git { trunc_width = 40 }
local diff = MiniStatusline.section_diff { trunc_width = 75 }
local diagnostics = MiniStatusline.section_diagnostics { trunc_width = 75 }
local lsp = MiniStatusline.section_lsp { trunc_width = 75 }
local filename = MiniStatusline.section_filename { trunc_width = 140 }
local fileinfo = MiniStatusline.section_fileinfo { trunc_width = 120 }
local location = MiniStatusline.section_location { trunc_width = 75 }
local search = MiniStatusline.section_searchcount { trunc_width = 75 }
local macro = check_macro_recording()
return MiniStatusline.combine_groups {
{ hl = mode_hl, strings = { mode } },
{ hl = 'MiniStatuslineDevinfo', strings = { git, diff, diagnostics, lsp } },
'%<', -- Mark general truncate point
{ hl = 'MiniStatuslineFilename', strings = { filename } },
'%=', -- End left alignment
{ hl = 'MiniStatuslineFilename', strings = { macro } },
{ hl = 'MiniStatuslineFileinfo', strings = { fileinfo } },
{ hl = mode_hl, strings = { search, location } },
}
end,
use_icons = true,
set_vim_settings = true,
},
}) -- }}}
-- {{{ which-key config
local wk = require('which-key')
local wke = require('which-key.extras')
wk.add({
{ -- Normal Mode
{ '<Tab>', '>>', desc = 'increase tab depth of line' },
{ '<S-Tab>', '<<', desc = 'decrease tab depth of line' },
-- file group
{ '<leader>f', group = 'file' },
{ '<leader>fb', '<cmd>Yazi<cr>', desc = '[f]ile [b]rowser' },
{ '<leader>fd', '<cmd>Yazi cwd<cr>', desc = '[f]ile browser for current [d]irectory' },
{ '<leader>fp', Snacks.picker.files, desc = '[f]ile [p]icker' },
{ '<leader>fg', Snacks.picker.grep, desc = '[f]ile [g]rep picker' },
{ '<leader>fz', Snacks.picker.zoxide, desc = '[f]ile [z]oxide picker' },
-- buffer group
{
'<leader>b',
group = 'buffers',
expand = function()
return wke.expand.buf()
end
},
{ '<leader>be', '<cmd>e %<cr>', desc = '[b]uffer r[e]load' },
{ '<leader>bp', Snacks.picker.buffers, desc = '[b]uffer [p]icker' },
{ '<leader>bl', Snacks.picker.lines, desc = '[b]uffer pick [l]ine' },
-- project group
{ '<leader>pp', Snacks.picker.projects, desc = '[p]ick [p]roject' },
-- help group
{ '<leader>h', group = 'help' },
{ '<leader>hh', Snacks.picker.help, desc = '[h]pick [h]elp' },
{ '<leader>hk', Snacks.picker.keymaps, desc = '[h]pick [k]eymaps' },
{ '<leader>hi', Snacks.picker.icons, desc = '[h]pick icon' },
-- git group
{ '<leader>g', group = 'git' },
{ '<leader>gi', '<cmd>LazyGit<CR>', desc = 'lazy[g][i]t open' },
{ '<leader>gc', '<cmd>LazyGitCurrentFile<CR>', desc = 'lazy[g]it [c]urrent file' },
{ '<leader>go', '<cmd>LazyGitConfig<CR>', desc = 'lazy[g]it c[o]nfig' },
{ '<leader>gl', '<cmd>LazyGitLog<CR>', desc = 'Lazy[g]it [l]og' },
-- lsp group
{ '<leader>l', group = 'LSP' },
{ '<leader>lh', vim.lsp.buf.hover, desc = '[l]sp [h]over Documentation' },
{ '<leader>ls', vim.lsp.buf.signature_help, desc = '[l]sp [s]ignature help' },
{ '<leader>lr', vim.lsp.buf.rename, desc = '[l]sp [r]ename' },
{ '<leader>lf', vim.lsp.buf.format, desc = '[l]sp [f]ormat buffer' },
{ '<leader>lgD', Snacks.picker.lsp_declarations, desc = '[l]sp [g]oto [D]eclaration' },
{ '<leader>lgI', Snacks.picker.lsp_implementations, desc = '[l]sp [g]oto [I]mplementation' },
{ '<leader>lgS', Snacks.picker.lsp_workspace_symbols, desc = '[l]sp [g]oto workspace [S]ymbol' },
{ '<leader>lgd', Snacks.picker.lsp_definitions, desc = '[l]sp [g]oto [d]efinition' },
{ '<leader>lgr', Snacks.picker.lsp_references, desc = '[l]sp [g]oto [r]eferences' },
{ '<leader>lgs', Snacks.picker.lsp_symbols, desc = '[l]sp [g]oto document [s]ymbol' },
{ '<leader>lde', vim.diagnostic.open_float, desc = '[l]sp [d]iagnostic [e]rror messages' },
{ '<leader>ldq', vim.diagnostic.setloclist, desc = '[l]sp [d]iagnostic [q]uickfix list' },
-- claude code
{ '<leader>a', group = 'Claude' },
{ '<leader>ac', "<cmd>ClaudeCode<cr>", desc = "Toggle Claude" },
{ '<leader>af', "<cmd>ClaudeCodeFocus<cr>", desc = "Focus Claude" },
{ '<leader>ar', "<cmd>ClaudeCode --resume<cr>", desc = "Resume Claude" },
{ '<leader>aC', "<cmd>ClaudeCode --continue<cr>", desc = "Continue Claude" },
{ '<leader>am', "<cmd>ClaudeCodeSelectModel<cr>", desc = "Select Claude Model" },
{ '<leader>ab', "<cmd>ClaudeCodeAdd %<cr>", desc = "Add current buffer" },
{ '<leader>as', "<cmd>ClaudeCodeSend<cr>", mode = 'v', desc = "Send to Claude" },
{
'<leader>as',
"<cmd>ClaudeCodeTreeAdd<cr>",
desc = "Add file",
ft = { "NvimTree", "neo-tree", "oil", "minifiles", "netrw" },
},
{ '<leader>aa', "<cmd>ClaudeCodeDiffAccept<cr>", desc = "Accept diff" },
{ '<leader>ad', "<cmd>ClaudeCodeDiffDeny<cr>", desc = "Deny diff" },
-- diagnostics
{
'[d',
function() vim.diagnostic.jump({ count = -1, float = true }) end,
desc = 'goto previous [d]iagnostic message'
},
{
']d',
function() vim.diagnostic.jump({ count = 1, float = true }) end,
desc = 'goto next [d]iagnostic message'
},
-- misc
{ '<Esc>', ':nohl<CR>', desc = 'Clear Highlights' },
{ '<leader>tt', ferminal.toggle_terminal, desc = '[t]oggle floating [t]erminal' },
{ '<leader>rr', ':source %<CR>', desc = 'sou[r]ce cu[r]rent file as neovim lua' },
},
{ -- Visual Mode
mode = 'v',
{ '<Tab>', '>>', desc = 'increase tab depth of selection' },
{ '<S-Tab>', '<<', desc = 'decrease tab depth of selection' },
},
{ -- Insert Mode
mode = 'i',
{ '<C-i>', vim.lsp.buf.signature_help, desc = 'signature help' },
{ '<C-d>', vim.lsp.buf.hover, desc = 'Hover [d]ocumentation' },
{ '<Tab>', '<C-t>', desc = 'restore tab functionality' },
{ '<S-Tab>', '<C-d>', desc = 'restore de-tab functionality' },
},
{ -- Terminal Mode
mode = 't',
{ '<Esc>', '<C-\\><C-n>', desc = 'Exit terminal mode' },
-- Window navigation
{ '<C-h>', '<C-\\><C-n><C-w>h', desc = 'Navigate to left window' },
{ '<C-j>', '<C-\\><C-n><C-w>j', desc = 'Navigate to lower window' },
{ '<C-k>', '<C-\\><C-n><C-w>k', desc = 'Navigate to upper window' },
{ '<C-l>', '<C-\\><C-n><C-w>l', desc = 'Navigate to right window' },
-- Tab navigation
{ '<M-h>', '<C-\\><C-n><cmd>tabprev<CR>', desc = 'Navigate to previous tab' },
{ '<M-l>', '<C-\\><C-n><cmd>tabnext<CR>', desc = 'Navigate to next tab' },
},
{ -- Normal, Insert mode
mode = { 'n', 'i' },
-- Window navigation
{ '<C-h>', '<C-w>h', desc = 'Navigate to left window' },
{ '<C-j>', '<C-w>j', desc = 'Navigate to lower window' },
{ '<C-k>', '<C-w>k', desc = 'Navigate to upper window' },
{ '<C-l>', '<C-w>l', desc = 'Navigate to right window' },
-- Tab navigation
{ '<M-h>', '<cmd>tabprev<CR>', desc = 'Navigate to previous tab' },
{ '<M-l>', '<cmd>tabnext<CR>', desc = 'Navigate to next tab' },
},
}) -- }}}