398 lines
10 KiB
Lua
398 lines
10 KiB
Lua
-- vim: fdm=marker
|
|
|
|
|
|
--[[
|
|
|
|
# My Neovim configuration
|
|
|
|
The basic settings were adapted from kickstart.nvim's init.lua[^1].
|
|
|
|
[^1]: https://github.com/nvim-lua/kickstart.nvim/blob/master/init.lua
|
|
|
|
--]]
|
|
|
|
-- Disable netrw
|
|
vim.g.loaded_netrw = 1
|
|
vim.g.loaded_netrwPlugin = 1
|
|
|
|
-- Use <space> as the leader key (must be done before loading plugins)
|
|
vim.g.mapleader = ' '
|
|
vim.g.maplocalleader = ' '
|
|
|
|
|
|
--{{{ Options
|
|
|
|
-- Indent with two spaces by default
|
|
vim.o.tabstop = 2
|
|
vim.o.shiftwidth = 2
|
|
vim.o.expandtab = true
|
|
|
|
-- Enable hybrid line numbers (current line absolute, others relative)
|
|
vim.o.number = true
|
|
vim.o.relativenumber = true
|
|
|
|
-- Enable mouse mode (I don't normally use it, but can't hurt)
|
|
vim.o.mouse = 'a'
|
|
|
|
-- Indent wrapped lines to the same level as the parent
|
|
vim.o.breakindent = true
|
|
|
|
-- Save undo history
|
|
vim.o.undofile = true
|
|
|
|
-- Use smart case for search (insensitive unless \C or capital letters present)
|
|
vim.o.ignorecase = true
|
|
vim.o.smartcase = true
|
|
|
|
-- Always display the signcolumn
|
|
vim.o.signcolumn = 'yes'
|
|
|
|
-- Lower update time
|
|
vim.o.updatetime = 250
|
|
|
|
-- Lower timeout for key sequences
|
|
vim.o.timeoutlen = 300
|
|
|
|
-- Configure how new splits should be opened
|
|
vim.o.splitright = true -- Left/right splits open to right of current
|
|
vim.o.splitbelow = true -- Up/down splits open below current
|
|
|
|
-- Display certain whitespace characters
|
|
vim.o.list = true
|
|
vim.opt.listchars = { tab = '» ', trail = '·', nbsp = '␣' }
|
|
|
|
-- Preview substitutions live, while typing
|
|
vim.o.inccommand = 'split'
|
|
|
|
-- Highlight the current line
|
|
vim.o.cursorline = true
|
|
|
|
-- Minimal number of context lines to keep on screen
|
|
vim.o.scrolloff = 15
|
|
|
|
-- Get confirmation for certain operations instead of failing
|
|
vim.o.confirm = true
|
|
|
|
--}}}
|
|
|
|
|
|
--{{{ Keymaps
|
|
|
|
-- Use <C-[hjkl]> to navigate between splits
|
|
vim.keymap.set('n', '<c-h>', '<c-w>h')
|
|
vim.keymap.set('n', '<c-j>', '<c-w>j')
|
|
vim.keymap.set('n', '<c-k>', '<c-w>k')
|
|
vim.keymap.set('n', '<c-l>', '<c-w>l')
|
|
|
|
-- Use <leader>-[y|p] to yank to or put from the system clipboard
|
|
vim.keymap.set('v', '<leader>y', '"+y', { desc = 'Yank to system clipboard' })
|
|
vim.keymap.set('n', '<leader>p', '"+p', { desc = 'Put from system clipboard' })
|
|
|
|
-- Use <esc> or <C-c> to clear search highlights
|
|
vim.keymap.set('n', '<esc>', '<cmd>nohlsearch<cr>', { desc = 'Clear search highlights' })
|
|
|
|
-- Quickfix list
|
|
vim.keymap.set('n', '<leader>co', '<cmd>copen<cr>', { desc = 'Open quickfix list' })
|
|
vim.keymap.set('n', '<leader>cc', '<cmd>cclose<cr>', { desc = 'Close quickfix list' })
|
|
|
|
-- Location list
|
|
vim.keymap.set('n', '<leader>ls', vim.diagnostic.setloclist, { desc = 'Set (populate) location list' })
|
|
vim.keymap.set('n', '<leader>lo', '<cmd>lopen<cr>', { desc = 'Open location list' })
|
|
vim.keymap.set('n', '<leader>lc', '<cmd>lclose<cr>', { desc = 'Close location list' })
|
|
|
|
-- Exit terminal mode; use <c-\><c-n> if not
|
|
vim.keymap.set('t', '<esc><esc>', '<c-\\><c-n>', { desc = 'Exit terminal mode' })
|
|
|
|
--}}}
|
|
|
|
|
|
--{{{ Autocommands
|
|
|
|
-- Highlight when yanking (copying) text
|
|
vim.api.nvim_create_autocmd('TextYankPost', {
|
|
desc = 'Highlight when yanking text',
|
|
group = vim.api.nvim_create_augroup('grillades-highlight-yank', { clear = true }),
|
|
callback = function()
|
|
vim.hl.on_yank()
|
|
end,
|
|
})
|
|
|
|
--}}}
|
|
|
|
|
|
--{{{ Plugins (lazy.nvim)
|
|
|
|
-- Bootstrap lazy.nvim
|
|
-- This will return something like $XDG_DATA_HOME/lazy/lazy.nvim or equivalent
|
|
local lazypath = vim.fn.stdpath('data') .. '/lazy/lazy.nvim'
|
|
if not (vim.uv or vim.loop).fs_stat(lazypath) then
|
|
local lazyrepo = 'https://github.com/folke/lazy.nvim.git'
|
|
local out = vim.fn.system({ 'git', 'clone', '--filter=blob:none', '--branch=stable', lazyrepo, lazypath })
|
|
if vim.v.shell_error ~= 0 then
|
|
vim.api.nvim_echo({
|
|
{ 'Failed to clone lazy.nvim:\n', 'ErrorMsg' },
|
|
{ out, 'WarningMsg' },
|
|
{ '\nPress any key to exit...' },
|
|
}, true, {})
|
|
vim.fn.getchar()
|
|
os.exit(1)
|
|
end
|
|
end
|
|
vim.opt.rtp:prepend(lazypath)
|
|
|
|
-- Configure lazy.nvim
|
|
require('lazy').setup({
|
|
spec = {
|
|
{
|
|
'folke/tokyonight.nvim',
|
|
lazy = false,
|
|
priority = 1000,
|
|
config = function()
|
|
vim.cmd 'colorscheme tokyonight-night'
|
|
end
|
|
},
|
|
|
|
{ 'tpope/vim-surround' },
|
|
|
|
{ 'justinmk/vim-sneak' },
|
|
|
|
{ 'tpope/vim-repeat' },
|
|
|
|
{ 'tpope/vim-commentary' },
|
|
|
|
{
|
|
'nvim-telescope/telescope.nvim', tag = '0.1.8',
|
|
dependencies = {
|
|
'nvim-lua/plenary.nvim',
|
|
{
|
|
'nvim-telescope/telescope-fzf-native.nvim',
|
|
build = 'make',
|
|
cond = function() return vim.fn.executable('make') == 1 end,
|
|
},
|
|
},
|
|
config = function()
|
|
local telescope = require('telescope')
|
|
local builtin = require('telescope.builtin')
|
|
|
|
telescope.setup({
|
|
defaults = {
|
|
layout_config = { prompt_position = 'top' },
|
|
sorting_strategy = 'ascending',
|
|
},
|
|
extensions = {
|
|
fzf = {
|
|
fuzzy = true,
|
|
override_generic_sorter = true,
|
|
override_file_sorter = true,
|
|
},
|
|
},
|
|
})
|
|
|
|
pcall(telescope.load_extension, 'fzf')
|
|
|
|
-- Keymaps
|
|
vim.keymap.set('n', '<leader>f', builtin.find_files, { desc = 'Find files' })
|
|
vim.keymap.set('n', '<leader>s', builtin.live_grep, { desc = 'Search files' })
|
|
vim.keymap.set('n', '<leader>b', builtin.buffers, { desc = 'Find buffer' })
|
|
vim.keymap.set('n', '<leader>h', builtin.help_tags, { desc = 'Search help' })
|
|
end,
|
|
},
|
|
|
|
{
|
|
'nvim-tree/nvim-tree.lua',
|
|
dependencies = { 'nvim-tree/nvim-web-devicons' },
|
|
config = function()
|
|
require('nvim-tree').setup({
|
|
sync_root_with_cwd = true,
|
|
respect_buf_cwd = true,
|
|
update_focused_file = {
|
|
enable = true,
|
|
update_root = true,
|
|
},
|
|
view = { width = 30 },
|
|
filters = { dotfiles = false },
|
|
git = { enable = true },
|
|
actions = {
|
|
open_file = { quit_on_open = true },
|
|
},
|
|
})
|
|
|
|
vim.keymap.set('n', '<leader>e', '<cmd>NvimTreeToggle<cr>', { desc = 'Toggle file explorer' })
|
|
end,
|
|
},
|
|
|
|
{
|
|
'nvim-treesitter/nvim-treesitter',
|
|
dependencies = {
|
|
'nvim-treesitter/nvim-treesitter-textobjects',
|
|
'nvim-treesitter/nvim-treesitter-context',
|
|
},
|
|
build = ':TSUpdate',
|
|
config = function()
|
|
require('nvim-treesitter.configs').setup({
|
|
ensure_installed = { 'lua', 'vim', 'ruby', 'bash', 'html', 'javascript' },
|
|
highlight = { enable = true },
|
|
indent = { enable = true },
|
|
textobjects = {
|
|
select = {
|
|
enable = true,
|
|
lookahead = true,
|
|
keymaps = {
|
|
['af'] = '@function.outer',
|
|
['if'] = '@function.inner',
|
|
['ac'] = '@class.outer',
|
|
['ic'] = '@class.inner',
|
|
['ab'] = '@block.outer',
|
|
['ib'] = '@block.inner',
|
|
},
|
|
},
|
|
move = {
|
|
enable = true,
|
|
set_jumps = true,
|
|
goto_next_start = {
|
|
[']f'] = '@function.outer',
|
|
[']c'] = '@class.outer',
|
|
[']b'] = '@block.outer',
|
|
},
|
|
goto_previous_start = {
|
|
['[f'] = '@function.outer',
|
|
['[c'] = '@class.outer',
|
|
['[b'] = '@block.outer',
|
|
},
|
|
},
|
|
},
|
|
})
|
|
end,
|
|
},
|
|
|
|
{
|
|
'neovim/nvim-lspconfig',
|
|
dependencies = {
|
|
'hrsh7th/cmp-nvim-lsp',
|
|
},
|
|
config = function()
|
|
local lspconfig = require('lspconfig')
|
|
local capabilities = require('cmp_nvim_lsp').default_capabilities()
|
|
|
|
-- Ruby
|
|
lspconfig.ruby_lsp.setup({
|
|
capabilities = capabilities,
|
|
})
|
|
|
|
-- Lua
|
|
lspconfig.lua_ls.setup({
|
|
capabilities = capabilities,
|
|
settings = {
|
|
Lua = {
|
|
workspace = { checkThirdParty = false },
|
|
telemetry = { enable = false },
|
|
},
|
|
},
|
|
})
|
|
|
|
-- JavaScript/TypeScript
|
|
lspconfig.ts_ls.setup({
|
|
capabilities = capabilities,
|
|
})
|
|
end,
|
|
},
|
|
|
|
{ 'lewis6991/gitsigns.nvim' },
|
|
|
|
{
|
|
'ahmedkhalf/project.nvim',
|
|
config = function()
|
|
local project_nvim = require('project_nvim')
|
|
project_nvim.setup({})
|
|
|
|
local telescope = require('telescope')
|
|
telescope.load_extension('projects')
|
|
vim.keymap.set('n', '<leader>q', telescope.extensions.projects.projects, { desc = 'Find files' })
|
|
end,
|
|
},
|
|
|
|
{
|
|
'hrsh7th/nvim-cmp',
|
|
dependencies = {
|
|
'hrsh7th/cmp-vsnip',
|
|
'hrsh7th/vim-vsnip',
|
|
'hrsh7th/cmp-buffer',
|
|
'hrsh7th/cmp-path',
|
|
'hrsh7th/cmp-cmdline',
|
|
'hrsh7th/cmp-nvim-lsp',
|
|
},
|
|
config = function()
|
|
local cmp = require('cmp')
|
|
|
|
cmp.setup({
|
|
snippet = {
|
|
expand = function(args)
|
|
vim.fn['vsnip#anonymous'](args.body)
|
|
end,
|
|
},
|
|
window = {
|
|
completion = cmp.config.window.bordered(),
|
|
documentation = cmp.config.window.bordered(),
|
|
},
|
|
mapping = cmp.mapping.preset.insert({
|
|
['<C-b>'] = cmp.mapping.scroll_docs(-4),
|
|
['<C-f>'] = cmp.mapping.scroll_docs(4),
|
|
['<C-space>'] = cmp.mapping.complete(),
|
|
['<C-e>'] = cmp.mapping.abort(),
|
|
['<CR>'] = cmp.mapping.confirm({ select = true }),
|
|
}),
|
|
sources = cmp.config.sources({
|
|
{ name = 'nvim_lsp' },
|
|
{ name = 'vsnip' },
|
|
{ name = 'path' },
|
|
}, {
|
|
{ name = 'buffer' },
|
|
}),
|
|
})
|
|
|
|
cmp.setup.cmdline(':', {
|
|
mapping = cmp.mapping.preset.cmdline(),
|
|
sources = {
|
|
{ name = 'path' },
|
|
{ name = 'cmdline' },
|
|
},
|
|
})
|
|
end,
|
|
},
|
|
|
|
{
|
|
"folke/trouble.nvim",
|
|
opts = {},
|
|
cmd = "Trouble",
|
|
keys = {
|
|
{
|
|
"<leader>xx",
|
|
"<cmd>Trouble diagnostics toggle<cr>",
|
|
desc = "Diagnostics (Trouble)",
|
|
},
|
|
},
|
|
},
|
|
|
|
{
|
|
"nvim-lualine/lualine.nvim",
|
|
dependencies = { "nvim-tree/nvim-web-devicons", opt = true },
|
|
config = function()
|
|
local lualine = require("lualine")
|
|
lualine.setup({
|
|
options = {
|
|
theme = 'tokyonight'
|
|
}
|
|
})
|
|
end,
|
|
},
|
|
},
|
|
|
|
install = {
|
|
-- Install missing plugins on startup
|
|
missing = true,
|
|
},
|
|
})
|
|
|
|
--}}}
|
|
|