diff --git a/files/.config/nvim b/files/.config/nvim deleted file mode 120000 index 815cbcc2..00000000 --- a/files/.config/nvim +++ /dev/null @@ -1 +0,0 @@ -../.vim \ No newline at end of file diff --git a/files/.config/nvim/init.lua b/files/.config/nvim/init.lua new file mode 100644 index 00000000..79f7103f --- /dev/null +++ b/files/.config/nvim/init.lua @@ -0,0 +1,154 @@ +local augroup = vim.api.nvim_create_augroup("vimrc", { clear = true }) + +-- {{{ General + +vim.opt.backup = true +vim.opt.backupdir:remove(".") +vim.opt.undofile = true +vim.opt.ignorecase = true +vim.opt.smartcase = true + +vim.g.tex_flavor = "latex" + +vim.cmd("silent! packadd! cfilter") + +-- See :h :DiffOrig +vim.cmd([[ + command! DiffOrig vert new | set bt=nofile | r ++edit # | 0d_ | diffthis + \ | wincmd p | diffthis +]]) + +-- }}} +-- {{{ Editing + +vim.opt.expandtab = true +vim.opt.shiftwidth = 2 +vim.opt.softtabstop = 2 +vim.opt.copyindent = true +vim.opt.preserveindent = true +vim.opt.formatoptions:append({ "m", "B" }) +vim.opt.fileencodings = { + "ucs-bom", + "utf-8", + "iso-2022-jp", + "euc-jp", + "cp932", + "default", + "latin1", +} + +-- jump to the last known cursor position +vim.api.nvim_create_autocmd("BufReadPost", { + group = augroup, + callback = function(opts) + local ft = vim.bo[opts.buf].filetype + local line = vim.api.nvim_buf_get_mark(opts.buf, '"')[1] + local in_range = 1 < line and line <= vim.api.nvim_buf_line_count(opts.buf) + + if in_range and not ft:match("commit") then + vim.api.nvim_feedkeys([[g`"]], "nx", false) + end + end, +}) + +-- }}} +-- {{{ UI + +vim.opt.colorcolumn = "81" +vim.opt.foldenable = false +vim.opt.inccommand = "split" +vim.opt.lazyredraw = true +vim.opt.mouse = "a" +vim.opt.number = true +vim.opt.showmatch = true +vim.opt.title = true +vim.opt.wildignorecase = true +vim.opt.diffopt = { + "internal", + "filler", + "closeoff", + "algorithm:histogram", + "indent-heuristic", +} + +vim.api.nvim_create_autocmd("TextYankPost", { + group = augroup, + pattern = "*", + callback = function(args) + vim.highlight.on_yank({ + higroup = "Visual", + timeout = 300, + }) + end, +}) + +vim.api.nvim_create_autocmd("QuickfixCmdPost", { + group = augroup, + pattern = [[\C[^lA-Z]*]], + command = "botright cwindow", +}) + +vim.api.nvim_create_autocmd("QuickfixCmdPost", { + group = augroup, + pattern = "l*", + command = "botright lwindow", +}) + +-- }}} +-- {{{ Keybindings + +vim.g.mapleader = " " +vim.g.maplocalleader = "\\" + +vim.keymap.set("n", "b", "bmodified") + +vim.keymap.set({ "i", "s" }, "", function() + if vim.snippet.active({ direction = 1 }) then + return "lua vim.snippet.jump(1)" + else + return "" + end +end, { expr = true }) + +vim.keymap.set({ "i", "s" }, "", function() + if vim.snippet.active({ direction = -1 }) then + return "lua vim.snippet.jump(-1)" + else + return "" + end +end, { expr = true }) + +-- find merge conflict marker +vim.keymap.set({ "n", "x", "o" }, "fc", [[/\v^[<=>]{7}( .*$)]]) +-- find whitespace errors +vim.keymap.set({ "n", "x", "o" }, "f ", [[/\s\+$\ \+\ze\t]]) +-- find full-width punctuation marks +vim.keymap.set({ "n", "x", "o" }, "f.", [[/\v(\.。)]]) +vim.keymap.set({ "n", "x", "o" }, "f,", [[/\v(,、)]]) +vim.keymap.set({ "n", "x", "o" }, "f!", [[f! /\v(!!)]]) +vim.keymap.set({ "n", "x", "o" }, "f!", [[f? /\v(\??)]]) + +-- text objects +vim.keymap.set("x", "al", "0v$") +vim.keymap.set("o", "al", "normal! 0v$") +vim.keymap.set("x", "il", "^vg_") +vim.keymap.set("o", "il", "normal! ^vg_") +vim.keymap.set("x", "ag", "gg0oG$") +vim.keymap.set("o", "ag", [[exe "normal! m`"keepjumps normal! ggVG]]) + +-- toggles +vim.keymap.set("n", "ts", "setlocal spell! spell?") +vim.keymap.set("n", "tv", "call vimrc#toggle_virtualedit()") +vim.keymap.set("n", "tq", "call vimrc#toggle_textwidth()") +vim.keymap.set("n", "t#", "setlocal relativenumber! relativenumber?") +vim.keymap.set("n", "t ", "call vimrc#toggle_whitespace_check()") +vim.keymap.set("n", "t", "call vimrc#toggle_whitespace_visibility()") + +-- 3-way merge +vim.keymap.set("n", "1", "diffget LOCAL") +vim.keymap.set("n", "2", "diffget BASE") +vim.keymap.set("n", "3", "diffget REMOTE") + +-- }}} + +-- vim:set foldmethod=marker: diff --git a/files/.vim/ftplugin/fugitive.vim b/files/.vim/ftplugin/fugitive.vim index abfe314a..6f6d66d0 100644 --- a/files/.vim/ftplugin/fugitive.vim +++ b/files/.vim/ftplugin/fugitive.vim @@ -1,3 +1,5 @@ if !empty(mapcheck('q', 'n')) nunmap q endif + +let b:editorconfig = v:false diff --git a/files/.vim/ginit.vim b/files/.vim/ginit.vim deleted file mode 120000 index 954cda61..00000000 --- a/files/.vim/ginit.vim +++ /dev/null @@ -1 +0,0 @@ -gvimrc \ No newline at end of file diff --git a/files/.vim/init.vim b/files/.vim/init.vim deleted file mode 120000 index c9a3c9c4..00000000 --- a/files/.vim/init.vim +++ /dev/null @@ -1 +0,0 @@ -vimrc \ No newline at end of file diff --git a/nix/devshells/default.nix b/nix/devshells/default.nix index 643db04e..72da971f 100644 --- a/nix/devshells/default.nix +++ b/nix/devshells/default.nix @@ -13,7 +13,7 @@ ansible = pkgs.callPackage ./ansible.nix { }; - setup = pkgs.callPackage ./setup.nix { inherit (self'.packages) neovim; }; + setup = pkgs.callPackage ./setup.nix { }; quic = pkgs.callPackage ./quic.nix { }; }; diff --git a/nix/devshells/setup.nix b/nix/devshells/setup.nix index e57ce022..535cc262 100644 --- a/nix/devshells/setup.nix +++ b/nix/devshells/setup.nix @@ -4,7 +4,6 @@ curl, emacs-nox, git, - neovim, }: mkShellNoCC { @@ -13,6 +12,5 @@ mkShellNoCC { curl emacs-nox git - neovim ]; } diff --git a/nix/home/modules/vim.nix b/nix/home/modules/vim.nix index 7e55dfd6..41a092fe 100644 --- a/nix/home/modules/vim.nix +++ b/nix/home/modules/vim.nix @@ -33,6 +33,7 @@ in }; }; }; + default = { }; description = "Install the specified vim plugins."; }; diff --git a/nix/home/profiles/default.nix b/nix/home/profiles/default.nix index 7dc3528c..51a94d24 100644 --- a/nix/home/profiles/default.nix +++ b/nix/home/profiles/default.nix @@ -10,6 +10,7 @@ ./development.nix ./fonts.nix ./macos.nix + ./neovim.nix ./web.nix ]; diff --git a/nix/home/profiles/minimal.nix b/nix/home/profiles/minimal.nix index 6f83b40d..f824362c 100644 --- a/nix/home/profiles/minimal.nix +++ b/nix/home/profiles/minimal.nix @@ -34,7 +34,6 @@ in less ripgrep zsh-syntax-highlighting - myPkgs.neovim ]; programs.direnv = { @@ -42,6 +41,8 @@ in nix-direnv.enable = mkDefault true; }; + dotfiles.profiles.neovim.enable = mkDefault true; + dotfiles.manpages = { enable = mkDefault true; useSystemMan = mkDefault (!isNixOS); diff --git a/nix/home/profiles/neovim.nix b/nix/home/profiles/neovim.nix new file mode 100644 index 00000000..3a6e8c05 --- /dev/null +++ b/nix/home/profiles/neovim.nix @@ -0,0 +1,331 @@ +{ + config, + lib, + pkgs, + ... +}: + +let + cfg = config.dotfiles.profiles.neovim; + + vimDir = ../../../files/.vim; + vimFiles = map toString (lib.filesystem.listFilesRecursive vimDir); + vimFilesRelative = map (lib.removePrefix (toString vimDir + "/")) vimFiles; + vimFilesFiltered = lib.filter (lib.hasInfix "/") vimFilesRelative; + vimRuntime = lib.genAttrs vimFilesFiltered (path: { + source = toString vimDir + "/" + path; + }); +in +{ + options.dotfiles.profiles.neovim.enable = lib.mkEnableOption "neovim"; + + config = lib.mkIf cfg.enable { + programs.neovim = { + enable = true; + extraLuaConfig = builtins.readFile ../../../files/.config/nvim/init.lua; + plugins = [ + { + plugin = pkgs.emptyDirectory; + runtime = vimRuntime; + } + + # Editing + { + plugin = pkgs.vimPlugins.vim-easy-align; + type = "lua"; + config = '' + vim.keymap.set({ "n", "x" }, "g=", "(EasyAlign)", { remap = true }) + ''; + } + { + plugin = pkgs.vimPlugins.vim-easymotion; + type = "lua"; + config = '' + vim.g.EasyMotion_do_mapping = false + vim.g.EasyMotion_smartcase = true + vim.g.EasyMotion_use_migemo = true + vim.keymap.set({ "n", "x", "o" }, "j", "(easymotion-j)", { remap = true }) + vim.keymap.set({ "n", "x", "o" }, "k", "(easymotion-k)", { remap = true }) + vim.keymap.set({ "x", "o" }, "s", "(easymotion-s2)", { remap = true }) + vim.keymap.set("n", "s", "(easymotion-overwin-f2)", { remap = true }) + vim.keymap.set({ "n", "x", "o" }, "g/", "(easymotion-sn)", { remap = true }) + ''; + } + { + plugin = pkgs.vimPlugins.vim-sandwich; + type = "lua"; + config = '' + vim.keymap.set({ "n", "x" }, "s", "", { remap = true }) + + -- NOTE: Same feature as vim/vim#958 + vim.keymap.set( + { "x", "o" }, + "im", + "(textobj-sandwich-literal-query-i)", + { remap = true } + ) + vim.keymap.set( + { "x", "o" }, + "am", + "(textobj-sandwich-literal-query-a)", + { remap = true } + ) + ''; + } + + # Colorscheme + { + plugin = pkgs.vimPlugins.gruvbox; + config = '' + colorscheme gruvbox + set cursorline + set pumblend=15 winblend=15 + ''; + } + + # UI + pkgs.vimPlugins.vim-airline-themes + pkgs.vimPlugins.vim-peekaboo + { + plugin = pkgs.vimPlugins.vim-airline; + type = "lua"; + # https://github.com/neovim/neovim/issues/14281 + config = '' + vim.opt.showmode = false + vim.g.airline_skip_empty_sections = true + if vim.env.USE_POWERLINE ~= "" then + vim.g.airline_powerline_fonts = true + + -- Fira Code doesn't contain the colnr symbol yet + -- https://github.com/tonsky/FiraCode/issues/1243 + vim.g.airline_symbols = { colnr = "${builtins.fromJSON ''"\u33c7"''}" } + end + vim.g["airline#parts#ffenc#skip_expected_string"] = "utf-8[unix]" + ''; + } + { + plugin = pkgs.vimPlugins.context-vim; + type = "lua"; + config = '' + vim.g.context_enabled = false + vim.keymap.set("n", "tz", "ContextToggle") + ''; + } + { + plugin = pkgs.vimPlugins.fzfWrapper; + config = '' + let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } } + + command! -bang Compilers call vimrc#fzf_compilers(0, 0) + command! -bang BCompilers call vimrc#fzf_compilers(1, 0) + command! -bang -nargs=* Projects call vimrc#fzf_projects(, 0) + ''; + } + { + plugin = pkgs.vimPlugins.fzf-vim; + type = "lua"; + config = '' + vim.keymap.set("n", "", "GitFiles") + vim.keymap.set("n", ",", "Buffers") + vim.keymap.set("n", ".", "Files") + vim.keymap.set("n", "gp", "Projects") + vim.keymap.set("n", "g/", "Lines") + vim.keymap.set("n", "g]", "Tags =expand('')") + vim.keymap.set("n", "o", "History") + vim.keymap.set("n", "q:", "History:") + vim.keymap.set("n", "q/", "History/") + vim.keymap.set("n", "'", "Marks") + vim.keymap.set("n", "/", "BLines") + vim.keymap.set("n", ":", "Commands") + vim.keymap.set("n", "]", "BTags =expand('')") + ''; + } + { + plugin = pkgs.vimPlugins.gitsigns-nvim; + type = "lua"; + config = '' + local gitsigns = require("gitsigns") + gitsigns.setup({ + on_attach = function(bufnr) + local function map(mode, l, r, opts) + opts = opts or {} + opts.buffer = bufnr + vim.keymap.set(mode, l, r, opts) + end + + map("n", "]c", function() + if vim.wo.diff then + vim.cmd.normal({"]c", bang = true}) + else + gitsigns.nav_hunk("next") + end + end) + + map("n", "[c", function() + if vim.wo.diff then + vim.cmd.normal({"[c", bang = true}) + else + gitsigns.nav_hunk("prev") + end + end) + end + }) + ''; + } + { + plugin = pkgs.vimPlugins.vim-illuminate; + config = '' + hi link IlluminatedWordText cursorLine + hi link IlluminatedWordRead cursorLine + hi link IlluminatedWordWrite cursorLine + nnoremap t* IlluminationToggle + ''; + } + { + plugin = pkgs.vimPlugins.indent-blankline-nvim; + type = "lua"; + config = '' + require("ibl").setup({ + enabled = false, + }) + vim.keymap.set("n", "t", "IBLToggle") + ''; + } + + # Language Support + pkgs.vimPlugins.cmp-buffer + pkgs.vimPlugins.cmp-path + pkgs.vimPlugins.cmp-nvim-lsp + pkgs.vimPlugins.cmp-nvim-lsp-signature-help + { + plugin = pkgs.vimPlugins.nvim-lspconfig; + type = "lua"; + config = '' + local capabilities = require("cmp_nvim_lsp").default_capabilities() + local lspconfig = require("lspconfig") + local servers = { + "ansiblels", + "clangd", + "eslint", + "jdtls", + "rust_analyzer", + "rubocop", + "pyright", + "tsserver", + } + + for _, lsp in ipairs(servers) do + lspconfig[lsp].setup({ + capabilities = capabilities, + }) + end + ''; + } + { + plugin = pkgs.vimPlugins.nvim-cmp; + type = "lua"; + config = '' + local cmp = require("cmp") + cmp.setup({ + mapping = cmp.mapping.preset.insert(), + sources = cmp.config.sources({ + { name = "nvim_lsp" }, + { name = "nvim_lsp_signature_help" }, + }, { + { name = "path" }, + }, { + { name = "buffer" }, + }), + snippet = { + expand = function(args) + vim.snippet.expand(args.body) + end, + }, + }) + ''; + } + { + plugin = pkgs.vimPlugins.ale; + type = "lua"; + config = '' + vim.g.ale_use_neovim_diagnostics_api = true + vim.g.ale_disable_lsp = true + vim.g.ale_set_quickfix = false + vim.g.ale_set_loclist = false + ''; + } + + # TreeSitter + { + plugin = pkgs.vimPlugins.nvim-treesitter.withAllGrammars; + type = "lua"; + config = '' + require("nvim-treesitter.configs").setup({ + auto_install = false, + highlight = { + enable = true, + }, + }) + ''; + } + { + plugin = pkgs.vimPlugins.nvim-treesitter-textobjects; + type = "lua"; + config = '' + require("nvim-treesitter.configs").setup({ + textobjects = { + select = { + enable = true, + lookahead = true, + keymaps = { + ["af"] = "@function.outer", + ["if"] = "@function.inner", + ["ac"] = "@class.outer", + ["ic"] = "@class.inner", + }, + }, + swap = { + enable = true, + swap_next = { + [">"] = "@parameter.inner", + }, + swap_previous = { + ["<"] = "@parameter.inner", + }, + }, + }, + }) + ''; + } + + # Utilities + pkgs.vimPlugins.direnv-vim + pkgs.vimPlugins.vim-fugitive + pkgs.vimPlugins.gv-vim + { + plugin = pkgs.vimPlugins.nerdtree; + type = "lua"; + config = '' + vim.keymap.set("n", "tf", "NERDTreeToggle") + vim.keymap.set("n", "tF", "NERDTreeFind") + ''; + } + { + plugin = pkgs.vimPlugins.tagbar; + type = "lua"; + config = '' + vim.keymap.set("n", "tt", "TagbarToggle") + ''; + } + { + plugin = pkgs.vimPlugins.undotree; + type = "lua"; + config = '' + vim.g.undotree_WindowLayout = 2 + vim.keymap.set("n", "tu", "UndotreeToggle") + ''; + } + ]; + }; + }; +} diff --git a/nix/packages/by-name/neovim.nix b/nix/packages/by-name/neovim.nix deleted file mode 100644 index df63f985..00000000 --- a/nix/packages/by-name/neovim.nix +++ /dev/null @@ -1,3 +0,0 @@ -{ wrapNeovim, neovim-unwrapped }: - -wrapNeovim neovim-unwrapped { withNodeJs = true; } diff --git a/nix/style.nix b/nix/style.nix index 57a979b7..bc6f0802 100644 --- a/nix/style.nix +++ b/nix/style.nix @@ -12,6 +12,7 @@ programs = { nixfmt.enable = lib.mkDefault true; shellcheck.enable = lib.mkDefault true; + stylua.enable = lib.mkDefault true; prettier = { enable = lib.mkDefault true; settings.proseWrap = lib.mkDefault "always"; diff --git a/setup.sh b/setup.sh index e2f2964d..036937f6 100755 --- a/setup.sh +++ b/setup.sh @@ -33,11 +33,14 @@ install: shell config install: Vim config - .vim - - .config/nvim - download: \ https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim \ ~/.vim/autoload/plug.vim +install: Neovim config + - skip: true # It's installed by Home Manager + - .config/nvim/init.lua + install: Git config - .config/git/attributes - .config/git/config @@ -106,7 +109,6 @@ install: miscellaneous config run: package installation - init: true - - nvim --headless +PlugInstall +'%print' +qall - ~/.config/emacs/bin/doom -y install --no-config githooks: