dotfiles/.config/nvim/init.lua

300 lines
8.9 KiB
Lua

-- vim: :foldmethod=marker
-- === PACKAGE MANAGEMENT === {{{1
local function ensure_plugin(category, name, git_url, opts)
opts = opts or {}
local pack_path = os.getenv("HOME") .. "/.config/nvim/pack/" .. category .. "/" .. (opts.opt and "opt" or "start")
local plugin_path = pack_path .. "/" .. name
-- Create pack directory if it doesn't exist
vim.fn.system("mkdir -p " .. pack_path)
-- Check if plugin exists
if vim.fn.isdirectory(plugin_path) == 0 then
print("Installing " .. name .. "...")
local result = vim.fn.system("git clone --depth=1 " .. git_url .. " " .. plugin_path)
if vim.v.shell_error == 0 then
print("" .. name .. " installed successfully")
else
print("✗ Failed to install " .. name .. ": " .. result)
return false
end
end
-- Load optional plugin if requested
if opts.opt and opts.load then
vim.cmd("packadd " .. name)
end
return true
end
-- Plugin definitions - add more as needed
local plugins = {
-- Colorschemes
{"colors", "papercolor-theme", "https://github.com/NLKNguyen/papercolor-theme.git"},
{"colors", "tokyonight.nvim", "https://github.com/folke/tokyonight.nvim.git"},
-- Essential plugins
{"editor", "telescope.nvim", "https://github.com/nvim-telescope/telescope.nvim.git"},
{"editor", "plenary.nvim", "https://github.com/nvim-lua/plenary.nvim.git"}, -- telescope dependency
{"editor", "nvim-web-devicons", "https://github.com/nvim-tree/nvim-web-devicons.git"}, -- telescope dependency
-- LSP and completion
{"lsp", "nvim-lspconfig", "https://github.com/neovim/nvim-lspconfig.git"},
{"lsp", "mason.nvim", "https://github.com/williamboman/mason.nvim.git"},
{"lsp", "mason-lspconfig.nvim", "https://github.com/williamboman/mason-lspconfig.nvim.git"},
{"lsp", "nvim-cmp", "https://github.com/hrsh7th/nvim-cmp.git"},
{"lsp", "cmp-nvim-lsp", "https://github.com/hrsh7th/cmp-nvim-lsp.git"},
{"lsp", "cmp-buffer", "https://github.com/hrsh7th/cmp-buffer.git"},
{"lsp", "cmp-path", "https://github.com/hrsh7th/cmp-path.git"},
{"lsp", "LuaSnip", "https://github.com/L3MON4D3/LuaSnip.git"},
{"lsp", "cmp_luasnip", "https://github.com/saadparwaiz1/cmp_luasnip.git"},
-- Treesitter
{"syntax", "nvim-treesitter", "https://github.com/nvim-treesitter/nvim-treesitter.git"},
-- Git integration
{"git", "gitsigns.nvim", "https://github.com/lewis6991/gitsigns.nvim.git"},
{"git", "vim-fugitive", "https://github.com/tpope/vim-fugitive.git"},
-- Tools
{"db", "vim-dadbod", "https://github.com/tpope/vim-dadbod.git"},
{"db", "vim-dadbod-completion", "https://github.com/kristijanhusak/vim-dadbod-completion.git"},
{"db", "vim-dadbod-ui", "https://github.com/kristijanhusak/vim-dadbod-ui.git"},
{"env", "dotenv", "https://github.com/tpope/vim-dotenv"},
-- Quality of life
{"editor", "which-key.nvim", "https://github.com/folke/which-key.nvim.git"},
{"editor", "Comment.nvim", "https://github.com/numToStr/Comment.nvim.git"},
{"editor", "nvim-surround", "https://github.com/kylechui/nvim-surround.git"},
}
-- Install all plugins
for _, plugin in ipairs(plugins) do
ensure_plugin(plugin[1], plugin[2], plugin[3], plugin[4])
end
-- === CORE SETTINGS === {{{1
local o = vim.o
local t = vim.t
local v = vim.v
local g = vim.g
local fn = vim.fn
local opt = vim.opt
local cmd = vim.cmd
local api = vim.api
local loop = vim.loop
local keys = vim.keymap
-- Globals
g.mapleader = "\\"
-- Helper function
local function has(val)
return fn.has(val) == 1
end
-- === APPEARANCE === {{{1
-- Basic UI
o.guifont = "Monaco:h13"
o.relativenumber = true
o.number = true
o.signcolumn = "yes"
o.termguicolors = true
o.laststatus = 2
o.statusline = "%f %h%w%m%y%r%=%(%l,%c%V %= %PT%)"
-- Colorscheme and dark mode integration
local function change_background()
o.background = "light"
cmd("colorscheme PaperColor")
cmd("redraw!")
end
if has("gui_macvim") then
local AutoDark = api.nvim_create_augroup("AutoDark", {clear = true})
api.nvim_create_autocmd({"OSAppearanceChanged"}, {
pattern = "*",
group = AutoDark,
callback = change_background
})
else
change_background()
end
-- === EDITOR BEHAVIOR === {{{1
-- Reading and saving
o.autoread = true
opt.clipboard:append("unnamedplus")
-- Indentation
o.autoindent = true
o.expandtab = true
o.tabstop = 2
o.shiftwidth = 2
-- Folding
o.foldmethod = "syntax"
-- Splits
opt.splitright = true
opt.splitbelow = true
-- Editing
opt.iskeyword:append("-")
-- Search
o.ignorecase = true
o.smartcase = true
o.hlsearch = true
o.incsearch = true
-- === PLUGIN CONFIGURATION === {{{1
-- Telescope
pcall(function()
require('telescope').setup({
defaults = {
file_ignore_patterns = {"node_modules", ".git/"}
}
})
end)
-- Which-key
pcall(function()
require('which-key').setup({})
end)
-- Comment.nvim
pcall(function()
require('Comment').setup()
end)
-- nvim-surround
pcall(function()
require('nvim-surround').setup()
end)
-- Gitsigns
pcall(function()
require('gitsigns').setup()
end)
-- Mason (LSP installer)
pcall(function()
require('mason').setup()
require('mason-lspconfig').setup({
ensure_installed = {"lua_ls", "vtsls", "pyright", "rust_analyzer"}
})
end)
-- LSP Configuration
pcall(function()
local lspconfig = require('lspconfig')
local capabilities = require('cmp_nvim_lsp').default_capabilities()
-- Common LSP setup
local servers = {"lua_ls", "vtsls", "pyright", "rust_analyzer"}
for _, lsp in ipairs(servers) do
lspconfig[lsp].setup({
capabilities = capabilities
})
end
end)
-- Completion setup
pcall(function()
local cmp = require('cmp')
local luasnip = require('luasnip')
cmp.setup({
snippet = {
expand = function(args)
luasnip.lsp_expand(args.body)
end,
},
mapping = cmp.mapping.preset.insert({
['<C-d>'] = cmp.mapping.scroll_docs(-4),
['<C-f>'] = cmp.mapping.scroll_docs(4),
['<C-Space>'] = cmp.mapping.complete(),
['<CR>'] = cmp.mapping.confirm({ select = true }),
}),
sources = cmp.config.sources({
{ name = 'nvim_lsp' },
{ name = 'luasnip' },
}, {
{ name = 'buffer' },
{ name = 'path' },
})
})
end)
-- Treesitter
pcall(function()
require('nvim-treesitter.configs').setup({
ensure_installed = {"lua", "typescript", "javascript", "python", "rust", "html", "css"},
highlight = { enable = true },
indent = { enable = true }
})
end)
-- === AUTOCMDS === {{{1
cmd("filetype plugin on")
-- TypeScript formatting on save
local TypescriptSave = api.nvim_create_augroup("TypescriptSave", {clear = true})
api.nvim_create_autocmd({"BufWritePost"}, {
pattern = "*.ts",
group = TypescriptSave,
command = "silent! !yarn prettier -w <afile>:p:S"
})
-- Diff mode settings
api.nvim_create_autocmd({"VimEnter"}, {
pattern = {"*"},
callback = function()
if o.diff then
o.wrap = true
keys.set("n", "ZZ", ":qa<Enter>")
cmd("cnoremap <expr> q<CR> 'qa<CR>'")
end
end
})
-- === KEYMAPS === {{{1
-- Leader key mappings
keys.set("n", "<Leader>rr", ":source $MYVIMRC<CR>", {desc = "Reload config"})
-- Basic editing
keys.set("i", "jk", "<Esc>", {desc = "Exit insert mode"})
keys.set("n", "x", '"_x', {desc = "Delete without copying"})
-- Telescope mappings
keys.set("n", "<Leader>ff", ":Telescope find_files<CR>", {desc = "Find files"})
keys.set("n", "<Leader>fg", ":Telescope live_grep<CR>", {desc = "Live grep"})
keys.set("n", "<Leader>fb", ":Telescope buffers<CR>", {desc = "Find buffers"})
keys.set("n", "<Leader>fh", ":Telescope help_tags<CR>", {desc = "Help tags"})
-- LSP mappings
keys.set("n", "gd", vim.lsp.buf.definition, {desc = "Go to definition"})
keys.set("n", "gD", vim.lsp.buf.declaration, {desc = "Go to declaration"})
keys.set("n", "gr", vim.lsp.buf.references, {desc = "References"})
keys.set("n", "gi", vim.lsp.buf.implementation, {desc = "Implementation"})
keys.set("n", "K", vim.lsp.buf.hover, {desc = "Hover documentation"})
keys.set("n", "<Leader>ca", vim.lsp.buf.code_action, {desc = "Code actions"})
keys.set("n", "<Leader>rn", vim.lsp.buf.rename, {desc = "Rename"})
keys.set("n", "<Leader>d", vim.diagnostic.open_float, {desc = "Show diagnostics"})
keys.set("n", "[d", vim.diagnostic.goto_prev, {desc = "Previous diagnostic"})
keys.set("n", "]d", vim.diagnostic.goto_next, {desc = "Next diagnostic"})
-- Window navigation
keys.set("n", "<C-h>", "<C-w>h", {desc = "Window left"})
keys.set("n", "<C-j>", "<C-w>j", {desc = "Window down"})
keys.set("n", "<C-k>", "<C-w>k", {desc = "Window up"})
keys.set("n", "<C-l>", "<C-w>l", {desc = "Window right"})
-- Clear search highlighting
keys.set("n", "<Leader>nh", ":nohl<CR>", {desc = "Clear highlights"})