From 11e10c32928f217b0394ec342cd8072c21ffccc6 Mon Sep 17 00:00:00 2001 From: arielherself Date: Tue, 14 Jan 2025 20:46:01 +0800 Subject: [PATCH] regular backup - feat(home-manager): mount Dropbox on startup - feat(nvim): switch to nvim-lsp --- .vimrc | 177 +++++++++++++++----------- home-manager/home.nix | 26 +++- nvim2/config.lua | 289 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 413 insertions(+), 79 deletions(-) create mode 100644 nvim2/config.lua diff --git a/.vimrc b/.vimrc index 5cdfaf9..bb1aebe 100644 --- a/.vimrc +++ b/.vimrc @@ -85,8 +85,8 @@ let g:mapleader = " " " Install vim-plug let data_dir = '~/.vim' if empty(glob(data_dir . '/autoload/plug.vim')) - silent execute '!curl -fLo '.data_dir.'/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim' - autocmd VimEnter * PlugInstall --sync | source $MYVIMRC + silent execute '!curl -fLo '.data_dir.'/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim' + autocmd VimEnter * PlugInstall --sync | source $MYVIMRC endif call plug#begin('~/.vim/plugged') @@ -105,12 +105,12 @@ endif Plug 'wakatime/vim-wakatime' Plug 'tpope/vim-surround' Plug 'tpope/vim-commentary' -Plug 'arielherself/vim-lsp' -Plug 'prabirshrestha/asyncomplete.vim' -Plug 'prabirshrestha/asyncomplete-lsp.vim' +" Plug 'arielherself/vim-lsp' +" Plug 'prabirshrestha/asyncomplete.vim' +" Plug 'prabirshrestha/asyncomplete-lsp.vim' " Plug 'Shougo/ddc.vim' " Plug 'shun/ddc-vim-lsp' -Plug 'mattn/vim-lsp-settings' +" Plug 'mattn/vim-lsp-settings' Plug 'jdhao/better-escape.vim' Plug 'jiangmiao/auto-pairs' Plug 'easymotion/vim-easymotion' @@ -121,18 +121,45 @@ Plug 'ryanoasis/vim-devicons' " this plugin slows vim down when dealing " with large files, so I switch to the Nvim version " Plug 'airblade/vim-gitgutter' -if has('nvim') - Plug 'lewis6991/gitsigns.nvim' -endif +Plug 'lewis6991/gitsigns.nvim' Plug 'tpope/vim-fugitive' Plug 'Yggdroot/indentLine' Plug '907th/vim-auto-save' Plug 'markonm/traces.vim' Plug 'stevearc/oil.nvim' Plug 'vim-scripts/LargeFile' +Plug 'lambdalisue/vim-fern' + Plug 'lambdalisue/vim-fern-git-status' + Plug 'lambdalisue/vim-fern-renderer-nerdfont' +Plug 'lambdalisue/nerdfont.vim' + +" Use Neovim LSP +Plug 'neovim/nvim-lspconfig' +Plug 'nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'} +Plug 'hrsh7th/nvim-cmp' + Plug 'hrsh7th/cmp-nvim-lsp' + Plug 'hrsh7th/cmp-buffer' + Plug 'hrsh7th/cmp-path' + Plug 'hrsh7th/cmp-cmdline' + Plug 'saadparwaiz1/cmp_luasnip' + Plug 'L3MON4D3/LuaSnip' + Plug 'hrsh7th/cmp-emoji' + Plug 'chrisgrieser/cmp-nerdfont' + Plug 'hrsh7th/cmp-calc' +Plug 'arielherself/lspkind.nvim' + Plug 'nvim-tree/nvim-web-devicons' +Plug 'folke/trouble.nvim' +Plug 'kevinhwang91/nvim-ufo' + Plug 'kevinhwang91/promise-async' +Plug 'rmagatti/goto-preview' call plug#end() +" Why?! +set noshowmode +set showcmd + + " Color scheme set background=dark let g:embark_terminal_italics = 1 @@ -174,11 +201,11 @@ let g:lsp_settings = { \ 'clangd': { 'cmd': [ 'clangd' ] }, \} function! s:truncate(str) - if len(a:str) > 50 - return a:str[:50] . '...' - else - return a:str - endif + if len(a:str) > 50 + return a:str[:50] . '...' + else + return a:str + endif endfunction function! s:truncate_labels(options, matches) abort let l:items = [] @@ -209,14 +236,15 @@ nnoremap w (easymotion-bd-w) vnoremap w (easymotion-bd-w) nnoremap o Files nnoremap g Rg -nnoremap gpd LspPeekDefinition -nnoremap gd LspDefinition -nnoremap dd LspDocumentDiagnostics -nnoremap dn LspNextDiagnostic -nnoremap dp LspPreviousDiagnostic -nnoremap grr LspRename -nnoremap a LspCodeAction -nnoremap K LspHover +nnoremap . Fern . -drawer +" nnoremap gpd LspPeekDefinition +" nnoremap gd LspDefinition +" nnoremap dd LspDocumentDiagnostics +" nnoremap dn LspNextDiagnostic +" nnoremap dp LspPreviousDiagnostic +" nnoremap grr LspRename +" nnoremap a LspCodeAction +" nnoremap K LspHover nnoremap Q q nnoremap q inoremap {A}%li$ik^i @@ -239,18 +267,18 @@ nnoremap x %s/\s\+$//e " Delete buffer while keeping window layout (don't close buffer's windows). " Version 2008-11-18 from http://vim.wikia.com/wiki/VimTip165 if v:version < 700 || exists('loaded_bclose') || &cp - finish + finish endif let loaded_bclose = 1 if !exists('bclose_multiple') - let bclose_multiple = 1 + let bclose_multiple = 1 endif " Display an error message. function! s:Warn(msg) - echohl ErrorMsg - echomsg a:msg - echohl NONE + echohl ErrorMsg + echomsg a:msg + echohl NONE endfunction " Command ':Bclose' executes ':bd' to delete buffer in current window. @@ -259,52 +287,52 @@ endfunction " Command ':Bclose!' is the same, but executes ':bd!' (discard changes). " An optional argument can specify which buffer to close (name or number). function! s:Bclose(bang, buffer) - if empty(a:buffer) - let btarget = bufnr('%') - elseif a:buffer =~ '^\d\+$' - let btarget = bufnr(str2nr(a:buffer)) - else - let btarget = bufnr(a:buffer) - endif - if btarget < 0 - call s:Warn('No matching buffer for '.a:buffer) - return - endif - if empty(a:bang) && getbufvar(btarget, '&modified') - call s:Warn('No write since last change for buffer '.btarget.' (use :Bclose!)') - return - endif - " Numbers of windows that view target buffer which we will delete. - let wnums = filter(range(1, winnr('$')), 'winbufnr(v:val) == btarget') - if !g:bclose_multiple && len(wnums) > 1 - call s:Warn('Buffer is in multiple windows (use ":let bclose_multiple=1")') - return - endif - let wcurrent = winnr() - for w in wnums - execute w.'wincmd w' - let prevbuf = bufnr('#') - if prevbuf > 0 && buflisted(prevbuf) && prevbuf != btarget - buffer # + if empty(a:buffer) + let btarget = bufnr('%') + elseif a:buffer =~ '^\d\+$' + let btarget = bufnr(str2nr(a:buffer)) else - bprevious + let btarget = bufnr(a:buffer) endif - if btarget == bufnr('%') - " Numbers of listed buffers which are not the target to be deleted. - let blisted = filter(range(1, bufnr('$')), 'buflisted(v:val) && v:val != btarget') - " Listed, not target, and not displayed. - let bhidden = filter(copy(blisted), 'bufwinnr(v:val) < 0') - " Take the first buffer, if any (could be more intelligent). - let bjump = (bhidden + blisted + [-1])[0] - if bjump > 0 - execute 'buffer '.bjump - else - execute 'enew'.a:bang - endif + if btarget < 0 + call s:Warn('No matching buffer for '.a:buffer) + return endif - endfor - execute 'bdelete'.a:bang.' '.btarget - execute wcurrent.'wincmd w' + if empty(a:bang) && getbufvar(btarget, '&modified') + call s:Warn('No write since last change for buffer '.btarget.' (use :Bclose!)') + return + endif + " Numbers of windows that view target buffer which we will delete. + let wnums = filter(range(1, winnr('$')), 'winbufnr(v:val) == btarget') + if !g:bclose_multiple && len(wnums) > 1 + call s:Warn('Buffer is in multiple windows (use ":let bclose_multiple=1")') + return + endif + let wcurrent = winnr() + for w in wnums + execute w.'wincmd w' + let prevbuf = bufnr('#') + if prevbuf > 0 && buflisted(prevbuf) && prevbuf != btarget + buffer # + else + bprevious + endif + if btarget == bufnr('%') + " Numbers of listed buffers which are not the target to be deleted. + let blisted = filter(range(1, bufnr('$')), 'buflisted(v:val) && v:val != btarget') + " Listed, not target, and not displayed. + let bhidden = filter(copy(blisted), 'bufwinnr(v:val) < 0') + " Take the first buffer, if any (could be more intelligent). + let bjump = (bhidden + blisted + [-1])[0] + if bjump > 0 + execute 'buffer '.bjump + else + execute 'enew'.a:bang + endif + endif + endfor + execute 'bdelete'.a:bang.' '.btarget + execute wcurrent.'wincmd w' endfunction command! -bang -complete=buffer -nargs=? Bclose call Bclose(, ) """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" @@ -333,10 +361,17 @@ highlight VertSplit guifg=#585273 " airline styling " ref: https://github.com/vim-airline/vim-airline/issues/323#issuecomment-27336312 +if !exists('g:airline_symbols') + let g:airline_symbols = {} +endif let g:airline_left_sep = '' let g:airline_left_alt_sep = '' let g:airline_right_sep = '' let g:airline_right_alt_sep = '' +let g:airline_symbols.notexists = ' ' +let g:airline_symbols.dirty = ' ' + +let g:fern#renderer = "nerdfont" if has('nvim') lua require('local-highlight').setup { cw_hlgroup = 'LspReferenceText' } @@ -347,5 +382,3 @@ endif " ref: https://github.com/tpope/vim-commentary/issues/15#issuecomment-23127749 autocmd FileType c,cpp,cs,java setlocal commentstring=//\ %s -" Why?! -set noshowmode diff --git a/home-manager/home.nix b/home-manager/home.nix index f9234b8..881ab95 100644 --- a/home-manager/home.nix +++ b/home-manager/home.nix @@ -116,13 +116,7 @@ in { ''; }; "nvim/lua/config.lua" = { - text = '' - require('oil').setup { - view_options = { - show_hidden = true, - }, - } - ''; + source = config.lib.file.mkOutOfStoreSymlink ../nvim2/config.lua; }; "nvim/ftplugin/java.lua" = { text = '' @@ -316,6 +310,7 @@ in { # pkgs.screenkey pkgs.ipatool # Search and download IPAs unstable.open-webui + pkgs.web-ext # My version of BerkeleyMono NF is incomplete. Should add some fallback fonts. # (pkgs.nerdfonts.override { fonts = [ @@ -516,6 +511,23 @@ in { Restart = "always"; }; }; + rclone-dropbox = { + Unit = { + Description = "mount Dropbox."; + After = [ "network-online.target" ]; + }; + Install = { + WantedBy = [ "default.target" ]; + }; + Service = { + Type = "forking"; + Environment = [ "PATH=/run/wrappers/bin/:$PATH" ]; + ExecStart = "${pkgs.rclone}/bin/rclone mount dropbox: /mnt/dropbox --copy-links --allow-other --allow-non-empty --umask 000 --daemon --vfs-cache-mode writes --buffer-size 10M"; + ExecStop = "fusermount -u /mnt/dropbox"; + Restart = "always"; + RestartSec = 10; + }; + }; }; } diff --git a/nvim2/config.lua b/nvim2/config.lua new file mode 100644 index 0000000..495f285 --- /dev/null +++ b/nvim2/config.lua @@ -0,0 +1,289 @@ +# vim:foldmethod=marker:foldmarker={{{,}}}: + +require('oil').setup { + columns = { + "icon", + "permissions", + "size", + "mtime", + }, + keymaps = { + [""] = { "actions.select", opts = { vertical = true } }, + [""] = { "actions.select", opts = { horizontal = true } }, + }, + view_options = { + show_hidden = true, + }, +} + +-- {{{ LSP Related +vim.diagnostic.config({ virtual_text = false }) + +--- {{{ nvim-treesitter setup +local config = require("nvim-treesitter.configs") +config.setup { + ensure_installed = {"lua", "cpp", "rust", "javascript", "python", "typescript", "html", "css", "scss"}, + auto_install = true, + highlight = { enable = true}, + indent = { enable = true}, +} +--- }}} + +--- {{{ nvim-cmp setup +local cmp_status, cmp = pcall(require, "cmp") +if not cmp_status then + return +end + +local luasnip_status, luasnip = pcall(require, "luasnip") +if not luasnip_status then + return +end + +vim.opt.completeopt = "menu,menuone,noselect" + +local has_words_before = function() + unpack = unpack or table.unpack + local line, col = unpack(vim.api.nvim_win_get_cursor(0)) + return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil +end + +local is_empty_line = function() + unpack = unpack or table.unpack + local line, _ = unpack(vim.api.nvim_win_get_cursor(0)) + return vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:match("%S") == nil +end + +local feedkey = function(key, mode) + vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(key, true, true, true), mode, true) +end + +local lspkind = require('lspkind') + +cmp.setup { + snippet = { + expand = function(args) + luasnip.lsp_expand(args.body) + end, + }, + mapping = { + [""] = cmp.mapping(function(fallback) + if cmp.visible() then + if not is_empty_line() then + cmp.confirm({ select = true }) + else + fallback() + end + elseif luasnip_status and luasnip.expand_or_jumpable() then + luasnip.expand_or_jump() + elseif has_words_before() then + cmp.complete() + else + fallback() + end + end, { "i", "s" }), + + [""] = cmp.mapping(function() + if cmp.visible() then + cmp.select_prev_item() + elseif vim.fn["vsnip#jumpable"](-1) == 1 then + feedkey("(vsnip-jump-prev)", "") + end + end, { "i", "s" }), + + [''] = cmp.mapping.select_prev_item(), + [''] = cmp.mapping.select_next_item(), + [''] = cmp.mapping.abort(), + }, + -- sources for autocompletion + sources = cmp.config.sources({ + { name = "cody" }, + { + name = "nvim_lsp", + option = { + markdown_oxide = { keyword_pattern = [[\(\k\| \|\/\|#\)\+]] } + } + }, -- LSP + { name = "luasnip" }, -- snippets + { name = "buffer" }, -- text within the current buffer + { name = "path" }, -- file system paths + { name = "emoji" }, + { name = "nerdfont" }, + { name = "calc" }, + }), + formatting = { + fields = { cmp.ItemField.Abbr, cmp.ItemField.Kind, cmp.ItemField.Menu }, + format = lspkind.cmp_format({ + mode = 'symbol_text', -- show only symbol annotations + maxwidth = 50, -- prevent the popup from showing more than provided characters (e.g 50 will not show more than 50 characters) + -- can also be a function to dynamically calculate max width such as + -- maxwidth = function() return math.floor(0.45 * vim.o.columns) end, + ellipsis_char = '…', -- when popup menu exceed maxwidth, the truncated part would show ellipsis_char instead (must define maxwidth first) + show_labelDetails = true, -- show labelDetails in menu. Disabled by default + + -- The function below will be called before any actual modifications from lspkind + -- so that you can provide more controls on popup customization. (See [#30](https://github.com/onsails/lspkind-nvim/pull/30)) + before = function (entry, vim_item) + -- local word = entry:get_insert_text() + -- if entry.completion_item.insertTextFormat == types.lsp.InsertTextFormat.Snippet then + -- word = word + -- -- word = vim.lsp.util.parse_snippet(word) + -- end + -- word = str.oneline(word) + -- if entry.completion_item.insertTextFormat == types.lsp.InsertTextFormat.Snippet and string.sub(vim_item.abbr, -1, -1) == "~" then + -- word = word .. "~" + -- end + -- vim_item.abbr = word + return vim_item + end + }) + } +} +--- }}} + +--- {{{ Configuration for specific LSPs +local lspconfig = require('lspconfig') +local capabilities = require('cmp_nvim_lsp').default_capabilities() +-- local extended_caps = require('cmp_nvim_lsp').default_capabilities(vim.lsp.protocol.make_client_capabilities) +-- lspconfig.svls.setup { +-- capabilities = capabilities +-- } +lspconfig.clangd.setup { + capabilities = capabilities, + root_dir = function(fname) + return lspconfig.util.root_pattern('compile_commands.json')(fname) or lspconfig.util.find_git_ancestor(fname) or vim.fn.getcwd() + end, + cmd = { + "clangd", + -- "--header-insertion=never", + "--clang-tidy", + "--clang-tidy-checks=*", + } +} +lspconfig.pyright.setup { + capabilities = capabilities +} +lspconfig.ts_ls.setup { + capabilities = capabilities +} +lspconfig.rust_analyzer.setup { + capabilities = capabilities, + -- Server-specific settings. See `:help lspconfig-setup` + settings = { + ['rust-analyzer'] = { + checkOnSave = { + command = 'clippy', + } + }, + }, +} +lspconfig.hls.setup {} +lspconfig.lua_ls.setup { + capabilities = capabilities +} +lspconfig.cmake.setup {} +lspconfig.asm_lsp.setup { + capabilities = capabilities +} +lspconfig.nil_ls.setup { + capabilities = capabilities +} +lspconfig.mojo.setup {} +lspconfig.nushell.setup {} +--- }}} + +--- {{{ Smart inlay hints +vim.api.nvim_create_autocmd("LspAttach", { + callback = function() + vim.lsp.inlay_hint.enable(true) + end, +}) + +vim.api.nvim_create_autocmd('InsertEnter', { + callback = function() + vim.lsp.inlay_hint.enable(false) + end +}) + +vim.api.nvim_create_autocmd('InsertLeave', { + callback = function() + vim.lsp.inlay_hint.enable(true) + end +}) +--- }}} + +--- {{{ trouble.nvim keybinds +require('trouble').setup() +vim.keymap.set('n', 'dd', 'Trouble diagnostics toggle focus=true filter.buf=0'); +vim.keymap.set('n', 'dw', 'Trouble diagnostics toggle focus=true'); +vim.keymap.set('n', 'dq', 'Trouble qflist toggle focus=true'); +vim.keymap.set('n', 'w', 'Trouble lsp toggle focus=true'); +--- }}} + +--- {{{ Common diagnostics keybinds +vim.keymap.set('n', 'qq', vim.diagnostic.open_float); +vim.keymap.set('n', 'qn', vim.diagnostic.goto_next); +vim.keymap.set('n', 'qp', vim.diagnostic.goto_prev); +--- }}} + +--- {{{ LSP keybinds +vim.api.nvim_create_autocmd('LspAttach', { + group = vim.api.nvim_create_augroup('UserLspConfig', {}), + callback = function(ev) + -- Enable completion triggered by + -- vim.bo[ev.buf].omnifunc = 'v:lua.vim.lsp.omnifunc' + + -- Buffer local mappings. + -- See `:help vim.lsp.*` for documentation on any of the below functions + local opts = { buffer = ev.buf } + vim.keymap.set('n', 'gD', vim.lsp.buf.declaration, opts) + vim.keymap.set('n', 'gd', vim.lsp.buf.definition, opts) + vim.keymap.set('n', 'K', vim.lsp.buf.hover, opts) + vim.keymap.set('n', 'gi', vim.lsp.buf.implementation, opts) + vim.keymap.set('n', '', vim.lsp.buf.signature_help, opts) + vim.keymap.set('n', 'wa', vim.lsp.buf.add_workspace_folder, opts) + vim.keymap.set('n', 'wr', vim.lsp.buf.remove_workspace_folder, opts) + vim.keymap.set('n', 'wl', function() + print(vim.inspect(vim.lsp.buf.list_workspace_folders())) + end, opts) + vim.keymap.set('n', 'D', vim.lsp.buf.type_definition, opts) + vim.keymap.set('n', 'rn', vim.lsp.buf.rename, opts) + vim.keymap.set({ 'n', 'v' }, 'ca', vim.lsp.buf.code_action, opts) + vim.keymap.set('n', 'gr', vim.lsp.buf.references, opts) + end, +}) +--- }}} + +require('goto-preview').setup { + default_mappings = true +} +-- }}} + +-- {{{ Fold Management +vim.o.foldcolumn = '1' -- '0' is not bad +vim.o.foldlevel = 99 -- Using ufo provider need a large value, feel free to decrease the value +vim.o.foldlevelstart = 99 +vim.o.foldenable = true + +-- Using ufo provider need remap `zR` and `zM`. If Neovim is 0.6.1, remap yourself +vim.keymap.set('n', 'zR', require('ufo').openAllFolds) +vim.keymap.set('n', 'zM', require('ufo').closeAllFolds) + +-- Option 2: nvim lsp as LSP client +-- Tell the server the capability of foldingRange, +-- Neovim hasn't added foldingRange to default capabilities, users must add it manually +local capabilities = vim.lsp.protocol.make_client_capabilities() +capabilities.textDocument.foldingRange = { + dynamicRegistration = false, + lineFoldingOnly = true +} +local language_servers = require("lspconfig").util.available_servers() -- or list servers manually like {'gopls', 'clangd'} +for _, ls in ipairs(language_servers) do + require('lspconfig')[ls].setup({ + capabilities = capabilities + -- you can add other fields for setting up lsp server in this table + }) +end +require('ufo').setup() + +-- }}}