{ config, pkgs, lib, ... }: with lib; let rust-analyzer = if (pkgs ? rust-analyzer-nightly && config.class ? dev) then pkgs.rust-analyzer-nightly else pkgs.rust-analyzer; rust-sdk = with pkgs; if config.class ? dev then symlinkJoin { name = "nvim-fenix"; paths = [ (fenix.latest.withComponents [ "cargo" "clippy-preview" "rust-src" "rust-std" "rustc" "rustfmt-preview" ]) cargo-watch ]; } else symlinkJoin { name = "nvim-rust"; paths = [ rustc cargo rustfmt clippy cargo-watch ]; }; in { programs.neovim = { # https://github.com/nix-community/home-manager/blob/master/modules/programs/neovim.nix enable = true; vimAlias = true; withNodeJs = true; extraPackages = with pkgs; [ fzf xclip fish ]; plugins = with pkgs.vimPlugins; [ vim-fugitive neogit diffview-nvim vim-airline zephyr-nvim vim-nix vim-toml elm-vim vim-markdown split-term-vim # vim-grammarous markdown-preview-nvim rainbow nerdtree nerdtree-git-plugin fzf-vim coc-sh coc-nvim coc-rust-analyzer coc-json coc-yaml coc-tsserver coc-prettier coc-pyright coc-diagnostic vimtex coc-vimtex coc-html coc-go coc-spell-checker editorconfig-nvim # tmuxline-vim nvim-dap nvim-dap-ui nvim-notify rust-tools-nvim crates-nvim nvim-lspconfig telescope-nvim telescope-undo-nvim oil-nvim distant-nvim ]; extraConfig = let pkgBin = pkg: "${pkgs.${pkg}}/bin/${pkg}"; in '' let mapleader = "," set hidden " disable mouse set mouse= " GoTo code navigation. nmap gd (coc-definition) nmap gy (coc-type-definition) nmap gi (coc-implementation) nmap gr (coc-references) " Rename nmap rn (coc-rename) " Use K to show documentation in preview window. nnoremap K :call ShowDocumentation() nmap ac (coc-codeaction) nmap as (coc-codeaction-cursor) nmap cl (coc-codelens-action) nmap [G (coc-diagnostic-next-error) nmap ]G (coc-diagnostic-prev-error) nmap [g (coc-diagnostic-next) nmap ]g (coc-diagnostic-prev) " NERDTree config " autocmd VimEnter * NERDTree autocmd BufEnter * NERDTreeMirror "CTRL-t to toggle tree view with CTRL-t nmap :NERDTreeToggle "Set F2 to put the cursor to the nerdtree nmap :NERDTreeFind function! ShowDocumentation() if CocAction('hasProvider', 'hover') call CocActionAsync('doHover') else call feedkeys('K', 'in') endif endfunction " Highlight the symbol and its references when holding the cursor. autocmd CursorHold * silent call CocActionAsync('highlight') " Formatting selected code. xmap f (coc-format-selected) nmap f (coc-format-selected) nmap F (coc-format) " " Copy to clipboard vnoremap y "+y nnoremap Y "+yg_ nnoremap y "+y nnoremap yy "+yy " " Paste from clipboard nnoremap p "+p nnoremap P "+P vnoremap p "+p vnoremap P "+P " " Tabbing https://webdevetc.com/blog/tabs-in-vim/ map tn :tabnew map t :tabnext map tm :tabmove map tc :tabclose map to :tabonly " Display line numbers set number relativenumber inoremap coc#pum#visible() ? coc#_select_confirm() \: "\u\\=coc#on_enter()\" map :mksession! .nvim_session " Quick write session with F3 map :source .nvim_session " And load session with F4 set undofile set undodir=~/.vim/undodir " Remember last posistion " split-term-vim let g:split_term_default_shell = "fish" set splitright " Airline let g:airline#extensions#tabline#enabled = 1 let g:airline#extensions#tabline#show_tab_nr = 1 let g:airline#extensions#tabline#tab_nr_type = 1 " DAP nnoremap lua require'dap'.continue() nnoremap lua require'dap'.step_over() nnoremap lua require'dap'.step_into() nnoremap lua require'dap'.step_out() nnoremap b lua require'dap'.toggle_breakpoint() nnoremap B lua require'dap'.set_breakpoint(vim.fn.input('Breakpoint condition: ')) nnoremap lp lua require'dap'.set_breakpoint(nil, nil, vim.fn.input('Log point message: ')) nnoremap dr lua require'dap'.repl.open() nnoremap dl lua require'dap'.run_last() if has("autocmd") au BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif endif ''; extraLuaConfig = '' vim.opt.termguicolors = true vim.notify = require("notify") vim.notify.setup({ background_colour = "#000000" }) local distant = require('distant') distant:setup() require("oil").setup() local telescope = require('telescope.builtin') vim.keymap.set('n', 'ff', telescope.find_files, {}) vim.keymap.set('n', 'fg', telescope.live_grep, {}) vim.keymap.set('n', 'fb', telescope.buffers, {}) vim.keymap.set('n', 'fh', telescope.help_tags, {}) require("telescope").setup({ extensions = { undo = { side_by_side = true, layout_strategy = "vertical", layout_config = { preview_height = 0.8, }, }, }, }) require('telescope').load_extension("undo") local neogit = require('neogit') -- git commit -- vim.keymap.set('n', 'gc', neogit.open, { "commit" }) -- git neo -> Neogit vim.keymap.set('n', 'gN', neogit.open, {}) neogit.setup({ git_services = { ["github.com"] = "https://github.com/''${owner}/''${repository}/compare/''${branch_name}?expand=1", ["bitbucket.org"] = "https://bitbucket.org/''${owner}/''${repository}/pull-requests/new?source=''${branch_name}&t=1", ["gitlab.com"] = "https://gitlab.com/''${owner}/''${repository}/merge_requests/new?merge_request[source_branch]=''${branch_name}", ["apps.terminal"] = "http://apps.terminal/''${owner}/''${repository}/merge_requests/new?merge_request[source_branch]=''${branch_name}", }, }) local dap, dapui = require("dap"), require("dapui") dap.adapters.lldb = { type = "executable", command = "${pkgs.lldb}/bin/lldb-vscode", name = "lldb", } local lldb = { name = "Launch lldb", type = "lldb", -- matches the adapter request = "launch", -- could also attach to a currently running process program = function() return vim.fn.input( "Path to executable: ", vim.fn.getcwd() .. "/", "file" ) end, cwd = "$${workspaceFolder}", stopOnEntry = false, args = {}, console = internalConsole, runInTerminal = true, } dap.configurations.rust = { lldb -- different debuggers or more configurations can be used here } --[[ local opts = { dap = { adapter = require("rust-tools.dap").get_codelldb_adapter("${pkgs.lldb}/bin/lldb-vscode", "${pkgs.lldb.lib}/lib/liblldb.so"), }, } require("rust-tools").setup { opts } ]] local dap_breakpoint = { error = { text = "🟥", texthl = "LspDiagnosticsSignError", linehl = "", numhl = "", }, rejected = { text = "", texthl = "LspDiagnosticsSignHint", linehl = "", numhl = "", }, stopped = { text = "⭐️", texthl = "LspDiagnosticsSignInformation", linehl = "DiagnosticUnderlineInfo", numhl = "LspDiagnosticsSignInformation", }, } vim.fn.sign_define("DapBreakpoint", dap_breakpoint.error) vim.fn.sign_define("DapStopped", dap_breakpoint.stopped) vim.fn.sign_define("DapBreakpointRejected", dap_breakpoint.rejected) dapui.setup() -- Auto open and close dapUI dap.listeners.after.event_initialized["dapui_config"] = function() dapui.open() end dap.listeners.before.event_terminated["dapui_config"] = function() dapui.close() end dap.listeners.before.event_exited["dapui_config"] = function() dapui.close() end ''; }; programs.git.ignores = [ ".nvim_session" ]; xdg.configFile."nvim/coc-settings.json".text = let preferProjectEnv = binName: alternate: pkgs.writeShellScript "${binName}-switcher" '' if command -v ${binName}; then ${binName} ''${@} else ${alternate} ''${@} fi ''; addSDK = { name, lsp, sdk }: with pkgs; runCommandLocal name { nativeBuildInputs = [ makeWrapper ]; } '' makeWrapper ${lsp} $out \ --prefix PATH : ${lib.makeBinPath sdk} ''; in builtins.toJSON { python = { pythonPath = preferProjectEnv "python3" (pkgs.python3 + "/bin/python3"); formatting.autopep8Path = "${pkgs.python3Packages.autopep8}/bin/autopep8"; }; pyright = { enable = true; }; # https://rust-analyzer.github.io/manual.html rust-analyzer = { cargo = { allFeatures = true; runBuildScripts = true; autoreload = true; }; completion = { autoimport.enable = true; privateEditable.enable = true; fullFunctionSignatures.enable = true; # https://github.com/rust-lang/rust-analyzer/pull/15582 snippets = rec { "return Err(..)" = { postfix = [ "reterr" ]; body = ''return Err($${receiver});''; description = "return expression as Err"; scope = "expr"; }; "format!(..)" = { postfix = [ "fmt" ]; body = ''format!($${receiver})''; description = "use receiver as format string"; scope = "expr"; }; "wrap { .. }" = { postfix = [ "brace" "wrap" ]; body = ''{$${receiver}}''; description = "wrap this type in { .. }"; scope = "expr"; }; "async move { .. }" = { postfix = [ "asyncm" ]; body = ''async move {$${receiver}}''; description = "wrap this type in async move { .. }"; scope = "expr"; }; "try { .. }" = { postfix = [ "try" ]; body = ''let result: Result<_,_> = try {$${receiver}};''; description = "wrap this type in try { .. }"; scope = "expr"; }; "while let Some(item) = { .. } {}" = { postfix = [ "letwhile" ]; body = ''while let Some(item) = $${receiver} {}''; description = "wrap this type in while let Some"; scope = "expr"; }; "let $x = $x.clone()" = { postfix = [ "cloned" ]; body = ''let $${receiver} = $${receiver}.clone();''; description = "clone a variable into a new binding"; scope = "expr"; }; "let $x = $x.into()" = { postfix = [ "into" ]; body = ''let $${receiver} = $${receiver}.clone();''; description = "call into() and create a new binding"; scope = "expr"; }; "assert_eq!($x, .. );" = { postfix = [ "asseq" ]; body = ''assert_eq!($${receiver}, );''; description = "create an assertion for the expression"; scope = "expr"; }; }; }; procMacro = { enable = true; attributes.enable = true; }; serverPath = addSDK { name = "rust-env"; lsp = "${rust-analyzer}/bin/rust-analyzer"; sdk = [ rust-sdk ]; }; imports.group.enable = true; # inlayHints = { # closureReturnTypeHints.enable = false; # }; highlightRelated = { yieldPoints.enable = true; references.enable = true; exitPoints.enable = true; breakPoints.enable = true; }; checkOnSave = { #https://github.com/rust-lang/rust-clippy/issues/9560 enable = false; allFeatures = true; command = "clippy"; # extraArgs = [ "--message-format=json" ]; }; diagnostics = { enable = true; experimental.enable = true; }; files.excludeDirs = [ "result" "target" ]; extraEnv = { RA_LOG = "debug"; }; }; languageserver = { ccls = { command = preferProjectEnv "ccls" "${pkgs.ccls}/bin/ccls"; filetypes = [ "c" "cc" "cpp" "c++" "objc" "objcpp" ]; rootPatterns = [ ".ccls" "compile_commands.json" ".git/" ".hg/" ]; initializationOptions = { cache = { directory = "${config.xdg.cacheHome}/ccls"; }; }; clang.extraOptions = [ "-std=c++20" ]; }; nix = { command = "${pkgs.nil}/bin/nil"; rootPatterns = [ "flake.nix" ]; filetypes = [ "nix" ]; }; diagnostic-languageserver = { filetypes = { sh = [ "${pkgs.shellcheck}/bin/shellcheck" ]; }; }; cSpell = { diagnosticLevel = "hint"; }; }; }; home.sessionVariables = rec { EDITOR = "nvim"; VISUAL_EDITOR = EDITOR; }; }