From 176e0e95131fbbd5b60f67b7f4be0782d51bf4ea Mon Sep 17 00:00:00 2001 From: LavaDesu Date: Sat, 9 Oct 2021 20:34:20 +0700 Subject: [PATCH] neovim: move to nvim-lspconfig and lua config --- modules/user/neovim.nix | 158 +++++++-------------------- res/config.lua | 236 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 274 insertions(+), 120 deletions(-) create mode 100644 res/config.lua diff --git a/modules/user/neovim.nix b/modules/user/neovim.nix index dda947c..0feacc9 100644 --- a/modules/user/neovim.nix +++ b/modules/user/neovim.nix @@ -1,21 +1,42 @@ -{ config, pkgs, ... }: { +{ config, lib, pkgs, ... }: +let + nvim-cmp = pkgs.vimUtils.buildVimPluginFrom2Nix { + pname = "nvim-cmp"; + version = "2021-10-09"; + src = pkgs.fetchFromGitHub { + owner = "hrsh7th"; + repo = "nvim-cmp"; + rev = "339fe9177b8eff85b21a0e118db400ab89775c28"; + sha256 = "16k9zqqhsw4z4zx1x1y34yss2k2jzq04f4mlp5xc2rwnfxi8yd93"; + }; + meta.homepage = "https://github.com/hrsh7th/nvim-cmp/"; + }; + luaconf = pkgs.writeText "config.lua" + (lib.replaceStrings ["{{OMNISHARP_PATH}}"] ["${pkgs.omnisharp-roslyn}/bin/omnisharp"] + (builtins.readFile ../../res/config.lua)); +in { + systemd.user.tmpfiles.rules = [ + "D %t/vim/swap 0755 - - - -" + "D %t/vim/undo 0755 - - - -" + ]; programs.neovim = { enable = true; viAlias = true; vimAlias = true; vimdiffAlias = true; package = pkgs.neovim-nightly; + withNodeJs = true; + + extraPackages = with pkgs; [ + rust-analyzer + nodePackages.diagnostic-languageserver + nodePackages.eslint_d + nodePackages.typescript-language-server + nodePackages.vscode-langservers-extracted + nodePackages.yaml-language-server + ]; plugins = with pkgs.vimPlugins; [ - coc-css - coc-html - coc-nvim - coc-eslint - coc-json - coc-rust-analyzer - coc-tsserver - coc-yaml - ctrlp-vim lualine-nvim nerdtree @@ -26,6 +47,12 @@ vim-signify vim-surround + nvim-cmp + nvim-lspconfig + cmp-nvim-lsp + cmp_luasnip + luasnip + (nvim-treesitter.withPlugins (p: with p; [ tree-sitter-comment tree-sitter-c-sharp @@ -46,118 +73,9 @@ tree-sitter-yaml ])) ]; - withNodeJs = true; extraConfig = '' - " configuration - syntax enable - set relativenumber number - set cursorline - set noswapfile - set hlsearch - set ignorecase - set incsearch - set title - set clipboard^=unnamed - set tabstop=8 softtabstop=0 expandtab shiftwidth=4 smarttab - set expandtab - set updatetime=100 - let g:yaml_recommended_style=0 - - " signify - set signcolumn=yes:3 - let g:signify_priority = 5 - let g:signify_sign_show_count = 0 - let g:signify_sign_add = '┃' - let g:signify_sign_delete = g:signify_sign_add - let g:signify_sign_delete_first_line = '┏━' - let g:signify_sign_change = g:signify_sign_add - let g:signify_sign_change_delete = g:signify_sign_delete - - " theming - let g:tokyonight_style='night' - colorscheme tokyonight - - " using tab for trigger completion - function! s:check_back_space() abort - let col = col('.') - 1 - return !col || getline('.')[col - 1] =~ '\s' - endfunction - - inoremap - \ pumvisible() ? "\" : - \ check_back_space() ? "\" : - \ coc#refresh() - - inoremap pumvisible() ? "\" : "\u\" - inoremap coc#refresh() - - " various aliases - nnoremap rs :source $MYVIMRC - nnoremap :NERDTreeToggle - nnoremap h - nnoremap j - nnoremap k - nnoremap l - nnoremap :q - - nmap [g (coc-diagnostic-prev) - nmap ]g (coc-diagnostic-next) - nmap gd (coc-definition) - nmap gy (coc-type-definition) - nmap gi (coc-implementation) - nmap gr (coc-references) - nmap ref (coc-references) - nmap gd :Gdiff - nmap rn (coc-rename) - command! -nargs=0 Sw w !doas tee % > /dev/null - - " autosave rust source files on change - au FileType rust inoremap :update - au TextChanged,FocusLost,BufEnter *.rs silent update - - " disable read-only warning - au BufEnter * set noro - - " set filetype=html for handlebar templates - " au BufRead,BufNewFile *.hbs set filetype=html - - " disable empty line tildes - set fcs=eob:\ - - lua <', 'h', { noremap = true }) +map('n', '', 'j', { noremap = true }) +map('n', '', 'k', { noremap = true }) +map('n', '', 'l', { noremap = true }) +map('n', '', ':q', { noremap = true }) + +-- Autocommands +vim.cmd('au FileType rust inoremap :update') +vim.cmd('au TextChanged,FocusLost,BufEnter *.rs silent update') +vim.cmd('au BufEnter * set noro') +vim.cmd('au CursorHold * lua vim.lsp.diagnostic.show_line_diagnostics({ focusable = false })') +vim.cmd('au CursorHoldI * silent! lua vim.lsp.buf.signature_help()') + +-- Settings +vim.opt.relativenumber = true +vim.opt.number = true +vim.opt.cursorline = true +vim.opt.signcolumn = "yes:3" +vim.opt.title = true +vim.opt.updatetime = 0 +vim.opt.clipboard:prepend('unnamedplus') + +local runtimedir = os.getenv('XDG_RUNTIME_DIR') +vim.opt.directory:prepend(runtimedir..'/vim/swap//') +vim.opt.undodir:prepend(runtimedir..'/vim/undo//') +vim.opt.swapfile = true +vim.opt.undofile = true + +vim.opt.hlsearch = true +vim.opt.ignorecase = true +vim.opt.smartcase = true +vim.opt.incsearch = true + +vim.opt.tabstop = 8 +vim.opt.softtabstop = 0 +vim.opt.expandtab = true +vim.opt.shiftwidth = 4 +vim.opt.smarttab = true + +vim.g.signify_priority = 5 +vim.g.signify_sign_show_count = 0 +vim.g.signify_sign_add = '┃' +vim.g.signify_sign_delete = vim.g.signify_sign_add +vim.g.signify_sign_delete_first_line = '┏━' +vim.g.signify_sign_change = vim.g.signify_sign_add +vim.g.signify_sign_change_delete = vim.g.signify_sign_delete + +-- Theming +vim.g.tokyonight_style = 'night' +vim.cmd[[ + syntax enable + colorscheme tokyonight +]] +local colors = require("tokyonight.colors").setup {} +vim.cmd("highlight SignifySignAdd guifg="..colors.green) +vim.cmd("highlight SignifySignChange guifg="..colors.orange) +vim.cmd("highlight SignifySignDelete guifg="..colors.red) +vim.cmd("highlight SignifySignDeleteFirstLine guifg="..colors.red) +vim.cmd("highlight SignifySignChangeDelete guifg="..colors.red) + +-- Plugins +require('nvim-treesitter.configs').setup { + highlight = { enable = true }, + indent = { enable = false } +} +require('lualine').setup { + options = { + theme = 'tokyonight' + } +} + +-- Block comments indent workaround +-- many thanks to @kristijanhusak +-- https://github.com/nvim-treesitter/nvim-treesitter/issues/1167#issuecomment-920824125 +function _G.javascript_indent() + local line = vim.fn.getline(vim.v.lnum) + local prev_line = vim.fn.getline(vim.v.lnum - 1) + if line:match('^%s*[%*/]%s*') then + if prev_line:match('^%s*%*%s*') then + return vim.fn.indent(vim.v.lnum - 1) + end + if prev_line:match('^%s*/%*%*%s*$') then + return vim.fn.indent(vim.v.lnum - 1) + 1 + end + end + + return vim.fn['GetJavascriptIndent']() +end + +vim.cmd('au FileType javascript setlocal indentexpr=v:lua.javascript_indent()') + +-- LSP +local nvim_lsp = require('lspconfig') + +local on_attach = function(client, bufnr) + local function buf_set_keymap(...) vim.api.nvim_buf_set_keymap(bufnr, ...) end + local function buf_set_option(...) vim.api.nvim_buf_set_option(bufnr, ...) end + + buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc') + + local opts = { noremap = true, silent = true } + + buf_set_keymap('n', 'gD', 'lua vim.lsp.buf.declaration()', opts) + buf_set_keymap('n', 'gd', 'lua vim.lsp.buf.definition()', opts) + buf_set_keymap('n', 'K', 'lua vim.lsp.buf.hover()', opts) + buf_set_keymap('n', 'gi', 'lua vim.lsp.buf.implementation()', opts) + buf_set_keymap('n', '', 'lua vim.lsp.buf.signature_help()', opts) + buf_set_keymap('n', 'wa', 'lua vim.lsp.buf.add_workspace_folder()', opts) + buf_set_keymap('n', 'wr', 'lua vim.lsp.buf.remove_workspace_folder()', opts) + buf_set_keymap('n', 'wl', 'lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))', opts) + buf_set_keymap('n', 'D', 'lua vim.lsp.buf.type_definition()', opts) + buf_set_keymap('n', 'rn', 'lua vim.lsp.buf.rename()', opts) + buf_set_keymap('n', 'ca', 'lua vim.lsp.buf.code_action()', opts) + buf_set_keymap('n', 'gr', 'lua vim.lsp.buf.references()', opts) + buf_set_keymap('n', 'e', 'lua vim.lsp.diagnostic.show_line_diagnostics()', opts) + buf_set_keymap('n', '[d', 'lua vim.lsp.diagnostic.goto_prev()', opts) + buf_set_keymap('n', ']d', 'lua vim.lsp.diagnostic.goto_next()', opts) + buf_set_keymap('n', 'q', 'lua vim.lsp.diagnostic.set_loclist()', opts) + buf_set_keymap('n', 'f', 'lua vim.lsp.buf.formatting()', opts) +end + +vim.lsp.handlers["textDocument/publishDiagnostics"] = vim.lsp.with( + vim.lsp.diagnostic.on_publish_diagnostics, { + virtual_text = false, + underline = true, + signs = true, + update_in_insert = true + } +) + +local capabilities = vim.lsp.protocol.make_client_capabilities() +capabilities.textDocument.completion.completionItem.snippetSupport = true +capabilities = require('cmp_nvim_lsp').update_capabilities(capabilities) + +local servers = { 'cssls', 'html', 'rnix', 'rust_analyzer', 'tsserver', 'yamlls' } +for _, lsp in ipairs(servers) do + nvim_lsp[lsp].setup { + capabilities = capabilities, + on_attach = on_attach, + flags = { + debounce_text_changes = 150, + } + } +end + +-- nvim-cmp +local luasnip = require('luasnip') +local cmp = require('cmp') +cmp.setup { + snippet = { + expand = function(args) + luasnip.lsp_expand(args.body) + end + }, + mapping = { + [''] = cmp.mapping.select_next_item(), + [''] = cmp.mapping.select_prev_item(), + [''] = cmp.mapping.scroll_docs(-4), + [''] = cmp.mapping.scroll_docs(4), + [''] = cmp.mapping.complete(), + [''] = cmp.mapping.close(), + [''] = cmp.mapping.confirm { + behavior = cmp.ConfirmBehavior.Replace, + select = true, + }, + [''] = function(fallback) + if cmp.visible() then + cmp.select_next_item() + elseif luasnip.expand_or_jumpable() then + vim.fn.feedkeys(vim.api.nvim_replace_termcodes('luasnip-expand-or-jump', true, true, true), '') + else + fallback() + end + end, + [''] = function(fallback) + if cmp.visible() then + cmp.select_prev_item() + elseif luasnip.jumpable(-1) then + vim.fn.feedkeys(vim.api.nvim_replace_termcodes('luasnip-jump-prev', true, true, true), '') + else + fallback() + end + end + }, + sources = { + { name = 'nvim_lsp' }, + { name = 'luasnip' } + } +} + +-- LSP/Omnisharp +local pid = vim.fn.getpid() +require'lspconfig'.omnisharp.setup { + capabilities = capabilities, + on_attach = on_attach, + cmd = { "{{OMNISHARP_PATH}}", "--languageserver", "--hostPID", tostring(pid) } +} + +-- LSP/Diagnostics +nvim_lsp.diagnosticls.setup { + capabilities = capabilities, + on_attach = on_attach, + filetypes = { 'javascript', 'javascriptreact', 'typescript', 'typescriptreact' }, + init_options = { + linters = { + eslint = { + command = 'eslint', + rootPatterns = { '.git' }, + debounce = 100, + args = { '--stdin', '--stdin-filename', '%filepath', '--format', 'json' }, + sourceName = 'eslint', + parseJson = { + errorsRoot = '[0].messages', + line = 'line', + column = 'column', + endLine = 'endLine', + endColumn = 'endColumn', + message = '[eslint] ${message} [${ruleId}]', + security = 'severity' + }, + securities = { + [2] = 'error', + [1] = 'warning' + } + } + }, + filetypes = { + javascript = 'eslint', + javascriptreact = 'eslint', + typescript = 'eslint', + typescriptreact = 'eslint' + } + } +}