diff options
Diffstat (limited to 'shared/home-manager/neovim')
-rw-r--r-- | shared/home-manager/neovim/completion.nix | 47 | ||||
-rw-r--r-- | shared/home-manager/neovim/default.nix | 28 | ||||
-rw-r--r-- | shared/home-manager/neovim/editing-plugins.nix | 26 | ||||
-rw-r--r-- | shared/home-manager/neovim/init.vim | 274 | ||||
-rw-r--r-- | shared/home-manager/neovim/lsp.nix | 59 |
5 files changed, 434 insertions, 0 deletions
diff --git a/shared/home-manager/neovim/completion.nix b/shared/home-manager/neovim/completion.nix new file mode 100644 index 0000000..3776674 --- /dev/null +++ b/shared/home-manager/neovim/completion.nix @@ -0,0 +1,47 @@ +# This module sets up auto completion for Neovim. +{pkgs, ...}: { + programs.neovim.plugins = with pkgs.vimPlugins; [ + # This is the actual completion engine. + { + plugin = nvim-cmp; + type = "lua"; + config = '' + local cmp = require("cmp") + + cmp.setup({ + mapping = cmp.mapping.preset.insert({ + ["<C-b>"] = cmp.mapping.scroll_docs(-4), + ["<C-f>"] = cmp.mapping.scroll_docs(4), + ["<C-j>"] = cmp.mapping.select_next_item(), + ["<C-k>"] = cmp.mapping.select_prev_item(), + ["<C-Space>"] = cmp.mapping.complete(), + ["<C-e>"] = cmp.mapping.abort(), + ["<Tab>"] = cmp.mapping.confirm({ select = true }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items. + }), + sources = cmp.config.sources({ + { name = "nvim_lsp" }, + { name = "calc" }, + { name = "path" }, + { name = "buffer" }, + }), + -- disable completion in comments + enabled = function() + local context = require("cmp.config.context") + -- keep command mode completion enabled when cursor is in a comment + if vim.api.nvim_get_mode().mode == "c" then + return true + else + return not context.in_treesitter_capture("comment") + and not context.in_syntax_group("Comment") + end + end + }) + ''; + } + # The following are plugins for the... completion plugin. + cmp-nvim-lsp + cmp-calc + cmp-buffer + cmp-path + ]; +} diff --git a/shared/home-manager/neovim/default.nix b/shared/home-manager/neovim/default.nix new file mode 100644 index 0000000..63a7564 --- /dev/null +++ b/shared/home-manager/neovim/default.nix @@ -0,0 +1,28 @@ +# This file contains the HM configuration options for Neovim. +{...}: { + imports = [ + ./completion.nix + ./editing-plugins.nix + ./lsp.nix + ]; + + programs.neovim = { + enable = true; + + # Import my existing config. I've been working on this for years and when + # my enthusiasm for Nix eventually dies off, I want to take it with me. + extraConfig = builtins.readFile ./init.vim; + + # Typing `vi`, `vim`, or `vimdiff` will also run neovim. + viAlias = true; + vimAlias = true; + vimdiffAlias = true; + }; + + # Set Neovim as the default editor. + home.sessionVariables.EDITOR = "nvim"; + home.sessionVariables.VISUAL = "nvim"; + + # Use neovim as man pager. + home.sessionVariables.MANPAGER = "nvim +Man!"; +} diff --git a/shared/home-manager/neovim/editing-plugins.nix b/shared/home-manager/neovim/editing-plugins.nix new file mode 100644 index 0000000..23c7d63 --- /dev/null +++ b/shared/home-manager/neovim/editing-plugins.nix @@ -0,0 +1,26 @@ +# This module sets up and configures various miscellaneous plugins. +# TODO: I fear this file will become the utils.lua of my Neovim configuration. Remove it! +{pkgs, ...}: { + programs.neovim.plugins = [ + { + plugin = pkgs.vimPlugins.vim-localvimrc; + type = "viml"; + config = '' + let g:localvimrc_persistent = 1 + let g:localvimrc_name = [ "local.vim", "editors/local.vim" ] + ''; + } + { + plugin = pkgs.vimPlugins.vim-sneak; + type = "viml"; + config = '' + let g:sneak#s_next = 1 + let g:sneak#use_ic_scs = 1 + map f <Plug>Sneak_f + map F <Plug>Sneak_F + map t <Plug>Sneak_t + map T <Plug>Sneak_T + ''; + } + ]; +} diff --git a/shared/home-manager/neovim/init.vim b/shared/home-manager/neovim/init.vim new file mode 100644 index 0000000..eeb6920 --- /dev/null +++ b/shared/home-manager/neovim/init.vim @@ -0,0 +1,274 @@ +" Settings +""""""""""""""""""""""""""" + +" Leave boomer mode +set nocompatible + +set history=1000 + +" Backspace in insert mode +set backspace=indent,eol,start + +" Hide buffer when abandoned (you can gd away, etc) +set hid + +" Searching +" NOTE: ignorecase and smartcase must be used together (see :h 'smartcase') +set incsearch gdefault ignorecase smartcase nohlsearch + +" Only auto-continue comments when i_<cr> is pressed (not n_o) +" Must be set after :filetype-plugin-on +filetype plugin indent on +au FileType * setlocal fo-=o fo+=r + +" Enable syntax highlighting +syn on + +" Colorscheme +" au VimEnter * ++nested colorscheme ansi_linus + +" Persistent undo +set undofile + +" Give me some thinking time, jesus! +set timeout timeoutlen=2000 + +" Line numbers +set number relativenumber + +" Improve macro performance +set lazyredraw + +" Show matching brackets +set showmatch +set matchtime=2 + +set listchars=tab:>-,eol:$,space:.,trail:@,nbsp:% + +" Enable mouse input for all modes but visual. +" +" I disable mouse in visual mode so I can select text in the terminal using +" the mouse. This is useful when copying text from a remote instance of vim +" SSH session where "* doesn't work. +set mouse=nicr + +" sussy sus the sussy sus +set nowrap + +" Mappings +""""""""""""""""""""""""""" + +let g:mapleader = "\<space>" +let g:maplocalleader = "\<space>" + +" Some keys are hard to press with the Danish layout. Luckily, we have some +" spare keys! Note that ctrl and esc are swapped at the OS level. +nnoremap æ $ +nnoremap Æ 0 + +" Switching windows +" TODO: make this work with iTerm2 panes +" nnoremap <c-h> <c-w><c-h> +" nnoremap <c-j> <c-w><c-j> +" nnoremap <c-k> <c-w><c-k> +" nnoremap <c-l> <c-w><c-l> +" tnoremap <c-h> <c-\><c-n><c-w><c-h> +" tnoremap <c-j> <c-\><c-n><c-w><c-j> +" tnoremap <c-k> <c-\><c-n><c-w><c-k> +" tnoremap <c-l> <c-\><c-n><c-w><c-l> + +" Resize windows +nnoremap + <c-w>+ +nnoremap - <c-w>- + +" Switching tabs +nnoremap <silent> <leader>tt :tabnext<CR> +nnoremap <silent> <leader>tn :tabnew<CR> +nnoremap <silent> <leader>to :tabonly<CR> +nnoremap <silent> <leader>tc :tabclose<CR> +nnoremap <silent> <leader>tm :tabmove +" Just use gt and gT +" nnoremap <silent> <leader>tl :tabn<CR> +" nnoremap <silent> <leader>th :tabN<CR> +nnoremap <silent> <leader>t<S-L> :tabl<CR> +nnoremap <silent> <leader>t<S-H> :tabr<CR> + +" Fast macros (qq to record) +nnoremap Q @q +vnoremap Q :norm! @q<cr> + +" Make Y act like C and D +nnoremap <s-y> y$ +vnoremap <s-y> $y + +" Indent using tab key +nnoremap <Tab> >l +nnoremap <S-Tab> <l +vnoremap <Tab> >gv +vnoremap <S-Tab> <gv + +noremap! <C-j> <down> +noremap! <C-k> <up> +noremap! <C-h> <left> +noremap! <C-l> <right> + +" Toggle showing 'listchars' +nnoremap <silent> <leader>l :set list!<cr> + +" Escape in terminal mode +tnoremap <esc><esc> <c-\><c-n> + +" Seamlessly enter/leave terminal buffer. +tnoremap <c-w> <c-\><c-n><c-w> +au BufEnter term://* norm! i + +" Join to end of line below +" This is already used by the window switching mappings +nnoremap <c-j> ddpkJ + +" Move window to the left and switch to the eastern window. +" I do this move pretty frequently. +nnoremap <c-w><c-w> <c-w>L<c-w>h + +" If the fzf executable is available, assume that the fzf plugin is going to +" be loaded. In that case we want an easy way to load a file. +if executable("fzf") + nnoremap <leader><leader> <CMD>FZF<CR> +else + nnoremap <leader><leader> <CMD>echo "FZF not found!"<CR> +endif + +" Define go-to-definition help pages, otherwise see the mappings in the hook +" for LSP configuration. +autocmd Filetype help nnoremap <buffer> gd <C-]> + +" Commands +""""""""""""""""""""""""""" + +" Create a temporary buffer +" NOTE: relied on by other commands +command Temp new | setlocal buftype=nofile bufhidden=wipe noswapfile nomodified nobuflisted +command TempTab tabnew | setlocal buftype=nofile bufhidden=wipe noswapfile nomodified nobuflisted + +" Reverse lines +command! -bar -range=% Reverse <line1>,<line2>g/^/m<line1>-1|nohl + +" Redraw screen +" CTRL-L mapping is used in other thing +command Redraw norm! + +" Run buffer contents as vimscript +command! -bar -range=% Run execute 'silent!' . <line1> . ',' . <line2> . 'y|@"' + +" Output the result of a command to the buf +command! -nargs=+ -complete=command Output + \ redir => output | + \ silent execute <q-args> | + \ redir END | + \ tabnew | + \ setlocal buftype=nofile bufhidden=wipe noswapfile nobuflisted nomodified | + \ silent put=output | + \ if <q-args> =~ ':!' | + \ silent 1,2delete _ | + \ else | + \ silent 1,4delete _ | + \ endif + +" Copy buffer to system clipboard +command! Copy silent w !pbcopy + +" Copy the location of the current file +command! CopyDir !echo %:r | pbcopy + +" View in-memory changes before writing to disk +command! DiffOnDisk + \ let orig_filetype=&ft | + \ vert new | + \ read ++edit # | 0d_ | + \ setlocal bt=nofile bh=wipe nobl noswf ro | + \ let &l:filetype = orig_filetype | + \ diffthis | + \ wincmd p | + \ diffthis + +command WrapItUp setlocal wrap + \| nnoremap <buffer> j gj + \| nnoremap <buffer> k gk + \| nnoremap <buffer> 0 g0 + \| nnoremap <buffer> $ g$ + +" Miscellaneous +""""""""""""""""""""""""""" + +" Show the color column only if insert mode (and only if cc is set) +augroup ShowCCInInsertMode + au! + au InsertEnter * if &tw != 0 | let &cc = &tw + 1 | endif + au InsertLeave * let &cc = 0 +augroup END + +" Auto-refresh vim config +" au BufWritePost $XDG_CONFIG_HOME/*.{vim,lua} so % + +" Jump to last editing location when opening files +au BufReadPost * + \ if line("'\"") > 0 && line("'\"") <= line("$") | + \ exe "normal! g'\"" | + \ endif + +augroup Sus + au! + + " Add syntax groups if relevant. This conditional is compensating for + " the lack of negative matches in :au. + " + " See: https://vim.fandom.com/wiki/Highlight_unwanted_spaces + " See: https://stackoverflow.com/questions/6496778/vim-run-autocmd-on-all-filetypes-except + fun! s:AddSyntax() + if bufname() !~ 'term://\|man://' + " Any trailing whitespace at the end of lines. + syn match SusWhitespace /\s\+$/ containedin=ALL + + " Any non-breaking spaces. These are generated by + " CMD+SPACE and deeply annoying. + syn match SusWhitespace /\%u00A0/ containedin=ALL + + " Any characters beyond the maximum width of the text. + if &tw > 0 + let reg = '\%' . (&tw + 1) . 'v.\+' + exe 'syn match SusWhitespace /'.reg.'/ containedin=ALL' + endif + endif + endfun + + " Remove highligt group. + " + " Note that we have to do abit more work since the the syntax rules + " have changed under Vim's nose. Hopefully the perfomance + " characteristics don't come back to haunt us. + fun! s:RemoveSyntax() + syn clear SusWhitespace + syn sync fromstart + endfun + + " Add a persistent highligt group, which matches are going to use. + au VimEnter,ColorScheme * hi SusWhitespace ctermbg=red guibg=red + + " Create some persistent syntax highlighting groups. + au Syntax * call s:AddSyntax() + + " When 'textwidth' changes, we may need to recalculate. + au OptionSet textwidth call s:RemoveSyntax() + \ | call s:AddSyntax() + + " Temporarily remove the groups when in insert mode. + au InsertEnter * call s:RemoveSyntax() + au InsertLeave * call s:AddSyntax() +augroup END + +" Allow for quick prototyping outside of NixOS/Home-Manager by loading some +" extra configuration if relevant. +let extra_vimrc = expand("~/extra-temporary.vimrc") +if filereadable(extra_vimrc) + execute "source " . extra_vimrc +endif diff --git a/shared/home-manager/neovim/lsp.nix b/shared/home-manager/neovim/lsp.nix new file mode 100644 index 0000000..bc10487 --- /dev/null +++ b/shared/home-manager/neovim/lsp.nix @@ -0,0 +1,59 @@ +# Installs and configures lspconfig. The actual LSPs are added in the per-language profiles. +{pkgs, ...}: { + programs.neovim.plugins = [ + { + plugin = pkgs.vimPlugins.nvim-lspconfig; + type = "lua"; + config = '' + local lspconfig = require("lspconfig") + local util = require("lspconfig.util") + + -- Mappings. + -- See `:help vim.diagnostic.*` for documentation on any of the below functions + local opts = { noremap=true, silent=true } + vim.keymap.set('n', '<leader>e', vim.diagnostic.open_float, opts) + vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, opts) + vim.keymap.set('n', ']d', vim.diagnostic.goto_next, opts) + vim.keymap.set('n', '<leader>q', vim.diagnostic.setloclist, opts) + + -- Use an on_attach function to only map the following keys + -- after the language server attaches to the current buffer + vim.api.nvim_create_autocmd("LspAttach", { + callback = function(args) + local bufnr = args.buf + local client = vim.lsp.get_client_by_id(args.data.client_id) + + -- Enable completion triggered by <c-x><c-o> + if client.server_capabilities.completionProvider then + vim.bo[bufnr].omnifunc = "v:lua.vim.lsp.omnifunc" + end + + -- XXX: What does this do? + if client.server_capabilities.definitionProvider then + vim.bo[bufnr].tagfunc = "v:lua.vim.lsp.tagfunc" + end + + -- Mappings. + -- See `:help vim.lsp.*` for documentation on any of the below functions + local bufopts = { noremap=true, silent=true, buffer=bufnr } + vim.keymap.set('n', 'gD', vim.lsp.buf.declaration, bufopts) + vim.keymap.set('n', 'gd', vim.lsp.buf.definition, bufopts) + vim.keymap.set('n', 'K', vim.lsp.buf.hover, bufopts) + vim.keymap.set('n', 'gi', vim.lsp.buf.implementation, bufopts) + vim.keymap.set('n', '<C-k>', vim.lsp.buf.signature_help, bufopts) + vim.keymap.set('n', '<leader>wa', vim.lsp.buf.add_workspace_folder, bufopts) + vim.keymap.set('n', '<leader>wr', vim.lsp.buf.remove_workspace_folder, bufopts) + vim.keymap.set('n', '<leader>wl', function() + print(vim.inspect(vim.lsp.buf.list_workspace_folders())) + end, bufopts) + vim.keymap.set('n', '<leader>D', vim.lsp.buf.type_definition, bufopts) + vim.keymap.set('n', '<leader>rn', vim.lsp.buf.rename, bufopts) + vim.keymap.set('n', '<leader>ca', vim.lsp.buf.code_action, bufopts) + vim.keymap.set('n', 'gr', vim.lsp.buf.references, bufopts) + vim.keymap.set('n', '<leader>f', function() vim.lsp.buf.format { async = true } end, bufopts) + end, + }) + ''; + } + ]; +} |