diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..f075029 --- /dev/null +++ b/init.lua @@ -0,0 +1,265 @@ +-- https://github.com/SylvanFranklin/.config/blob/main/nvim/init.lua +-- new keymap defaults: https://neovim.io/doc/user/news-0.11.html + + +-- 1. Plugins +-- requires nvim 0.12+ +-- mise plugins add neovim +-- mise install neovim@nightly +-- https://github.com/jdx/mise/discussions/6787#discussioncomment-14803999 +vim.pack.add({ + 'https://github.com/shaunsingh/nord.nvim', + 'https://github.com/stevearc/oil.nvim', + 'https://github.com/christoomey/vim-tmux-navigator', + 'https://github.com/tpope/vim-surround', + 'https://github.com/tpope/vim-fugitive', + 'https://github.com/kevinhwang91/nvim-bqf', + 'https://github.com/nvim-lua/plenary.nvim', + 'https://github.com/nvim-telescope/telescope.nvim', +}) + +require('telescope').setup() +require('oil').setup({ + keymaps = { + [''] = false, + [''] = false + } +}) + + +-- 2. Options +vim.opt.smartindent = true -- autoindenting when starting a new line +vim.opt.tabstop = 2 -- tab counts as 2 columns +vim.opt.shiftwidth = 2 -- numbers of spaces to (auto)indent +vim.opt.expandtab = true -- tabs to spaces +vim.opt.clipboard = 'unnamedplus' -- share clipboard with the OS +vim.opt.number = true -- display line numbers +vim.opt.synmaxcol = 500 -- do not try to highlight lines longer than 500 characters +vim.opt.lazyredraw = true -- do not redraw while running macros +vim.opt.showmatch = true -- show matching braces +vim.opt.matchtime = 2 -- show matching braces for 0.2 sec +vim.opt.showmode = true -- shows when you are in insert mode +vim.opt.title = true -- show title in console status bar +vim.opt.laststatus = 3 -- single status line +vim.opt.wrap = false -- dont wrap lines +vim.opt.scrolloff = 5 -- keep 5 rows on the screen when scrolling +vim.opt.sidescrolloff = 15 -- horizontal scrolloff +vim.opt.visualbell = false -- no visual bell +vim.opt.backup = false -- no backups +vim.opt.writebackup = false -- no backups +vim.opt.swapfile = false -- no backups +vim.opt.mouse = '' -- disable mouse +vim.opt.list = true -- list mode +vim.opt.timeoutlen = 1000 -- delay for mappings +vim.opt.ttimeoutlen = 0 -- delay between modes +vim.opt.termguicolors = true -- 24-bit RGB color +vim.opt.autoindent = true +vim.opt.updatetime = 100 +vim.opt.timeout = true +vim.opt.timeoutlen = 1000 +vim.opt.ttimeoutlen = 10 +vim.opt.completeopt = { + 'menu', + 'menuone', + 'noselect' +} +vim.opt.listchars = { + nbsp = '⦸', -- circled reverse solidus (U+29B8, UTF-8: E2 A6 B8) + extends = '»', -- right-pointing double angle quotation mark (U+00BB, UTF-8: C2 BB) + precedes = '«', -- left-pointing double angle quotation mark (U+00AB, UTF-8: C2 AB) + trail = '•', -- bullet (U+2022, UTF-8: E2 80 A2) + space = ' ', + tab = '→ ' +} +vim.opt.fillchars = { + diff = '⣿', + eob = ' ', -- no-break space (U+00A0, UTF-8: C2 A0) to suppress ~ at EndOfBuffer + vert = '│', + msgsep = '‾', + fold = '·', -- middle dot (U+00B7, UTF-8: C2 B7) + foldopen = '▾', + foldsep = '│', + foldclose = '▸' +} +vim.opt.shortmess = { + t = true, -- truncate file messages at start + A = true, -- ignore annoying swap file messages + o = true, -- file-read message overwrites previous + O = true, -- file-read message overwrites previous + T = true, -- truncate non-file messages in middle + f = true, -- (file x of x) instead of just (x of x + F = true, -- don't give file info when editing a file, NOTE: this breaks autocommand messages + s = true, + I = true, -- disable welcome message (:intro) + a = true, -- shortmess for everything + c = true, + W = true, -- don't show w or written when writing +} +vim.opt.wildignore = { -- ignore when autocompleting + '*.aux', '*.out', '*.toc', '*.o', '*.obj', + '*.dll', '*.jar', '*.pyc', '*.rbc', '*.class', + '*.gif', '*.ico', '*.jpg', '*.jpeg', '*.png', + '*.avi', '*.wav', '*.*~', '*~ ', '*.swp', + '.lock', '.DS_Store', 'tags.lock' +} + +if vim.fn.executable('rg') > 0 then + vim.opt.grepprg = [[rg --glob "!.git" --no-heading --vimgrep --follow $*]] +end + +-- find the correct ruby interpreter +vim.g.ruby_host_prog = 'asdf exec neovim-ruby-host' + +-- highlight yanked text briefly +vim.api.nvim_create_autocmd('TextYankPost', { + callback = function() + vim.highlight.on_yank { + higroup = 'Search', + timeout = 250, + on_visual = true, + } + end, +}) + +-- resize splits when Vim is resized +vim.api.nvim_create_autocmd('VimResized', { command = 'horizontal wincmd =' }) + +vim.api.nvim_create_augroup('cursorline_focus', {}) +vim.api.nvim_create_autocmd({ 'InsertLeave', 'WinEnter' }, { + group = 'cursorline_focus', + callback = function() + vim.wo.cursorline = true + end, +}) +vim.api.nvim_create_autocmd({ 'InsertEnter', 'WinLeave' }, { + group = 'cursorline_focus', + callback = function() + vim.wo.cursorline = false + end, +}) + +-- Experimental +-- vim.opt.iskeyword:prepend { '-' } -- treat dash separated words as a word textobject + +local function map(mode, lhs, rhs, opts) + local options = { noremap = true } + if opts then options = vim.tbl_extend('force', options, opts) end + vim.keymap.set(mode, lhs, rhs, options) +end + +local function nmap(lhs, rhs, opts) + map('n', lhs, rhs, opts) +end + +--- Mappings +-- Essentials +vim.g.mapleader = ' ' + +vim.keymap.set('n', ';', ':') +vim.keymap.set('v', ';', ':') +vim.keymap.set('n', ',,', '') +vim.keymap.set('n', 'Q', ':q!') +vim.keymap.set('n', 'w', ':w') -- TODO: :h autowriteall +vim.keymap.set('n', '', ':nohlsearch', { silent = true }) + +vim.keymap.set('n', 'ff', function() require('telescope.builtin').find_files({ hidden = true }) end) +vim.keymap.set('n', 'fb', function() require('telescope.builtin').buffers({ hidden = true }) end) +vim.keymap.set('n', 'fh', function() require('telescope.builtin').help_tags() end) +vim.keymap.set('n', 'fq', function() require('telescope.builtin').quickfix() end) +vim.keymap.set('n', 'fo', function() + require('telescope.builtin').find_files({ cwd = '~/Syncthing/Obsidian/Personal/', search_file = '*.md' }) +end) +vim.keymap.set('n', 'fO', function() + require('telescope.builtin').live_grep({ cwd = '~/Syncthing/Obsidian/Personal/', search_file = '*.md' }) +end) + +-- Convenience +vim.keymap.set('n', 'yy', 'Y') +vim.keymap.set('n', 'Y', 'y$') +vim.keymap.set('n', 'N', 'Nzz') +vim.keymap.set('n', 'n', 'nzz') +vim.keymap.set('n', 'j', 'gj') +vim.keymap.set('n', 'k', 'gk') +vim.keymap.set('n', 'H', '^') +vim.keymap.set('n', 'L', '$') +vim.keymap.set('n', 'J', 'mzJ`z') +vim.keymap.set('n', 'gQ', '') +vim.keymap.set('n', 'vv', ':vs') + +-- Tabs +nmap('t', ':tabnew', { silent = true }) +nmap('', ':tabnext', { silent = true }) +nmap('', ':tabprevious', { silent = true }) + +-- Visual mode +map('v', '.', ':normal .') +map('v', 'J', ':m \'>+1gv=gv') +map('v', 'K', ':m \'<-2gv=gv') +map('v', '<', '', '>gv') + +-- vim-easy-align +map("n", "ga", "(EasyAlign)") +map("x", "ga", "(EasyAlign)") + +vim.keymap.set("n", "-", ":Oil") + +-- fugitive.vim +nmap('ga', ':Gwrite') +nmap('gs', ':Git') +nmap('gb', ':Git blame') + +-- test +nmap('r', function() + os.execute("tmux send-keys -t '{down-of}' './bin/rspec '" .. vim.fn.expand("%") .. " Enter") +end) +nmap('R', function() + os.execute("tmux send-keys -t '{down-of}' './bin/rspec .' Enter") +end) + +-- grep +nmap('', ':grep ') + +-- reformat +nmap('=', ':lua vim.lsp.buf.format():w', { silent = true }) + +nmap('W', ':TrimWhitespace') + +nmap('q', ':copen') + +-- command mode +vim.keymap.set('c', '', '') +vim.keymap.set('c', '', '') + +-- paste in visual mode and keep available +vim.keymap.set('x', 'p', [['pgv"'.v:register.'y`>']], { expr = true, noremap = false, silent = false }) +vim.keymap.set('x', 'P', [['Pgv"'.v:register.'y`>']], { expr = true, noremap = false, silent = false }) + +vim.keymap.set('n', '', 'zz', { desc = 'Scroll downwards' }) +vim.keymap.set('n', '', 'zz', { desc = 'Scroll upwards' }) + +-- Make U opposite to u. +-- vim.keymap.set('n', 'U', '', { desc = 'Redo' }) + +-- default +vim.lsp.config('*', { + root_markers = { '.git' }, +}) + +vim.lsp.config['lua_ls'] = { + cmd = { 'lua-language-server' }, + filetypes = { 'lua' }, + root_markers = { { '.luarc.json', '.luarc.jsonc' } }, + settings = { Lua = { runtime = { version = 'LuaJIT' } } } +} + +vim.lsp.enable('lua_ls') + +local function trim_trailing_whitespace() + local pos = vim.api.nvim_win_get_cursor(0) + vim.cmd [[silent keepjumps keeppatterns %s/\s\+$//e]] + vim.api.nvim_win_set_cursor(0, pos) +end +vim.api.nvim_create_user_command('TrimWhitespace', trim_trailing_whitespace, {}) + +vim.cmd('colorscheme nord')