-- 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, }) 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')