Personal Nix setup
at main 27 kB view raw
1-- utilities 2local function t(str) 3 return vim.api.nvim_replace_termcodes(str, true, true, true) 4end 5 6local function hi(group, str) 7 return str ~= '' and string.format('%%#%s#%s', group, str) or '' 8end 9 10vim.loader.enable() 11 12-- terminal options 13vim.api.nvim_exec([[ 14 set t_Co=256 15 set t_ZH=^\[\[3m 16 set t_ZR=^\[\[23m 17 let &t_Cs = "\e\[4:3m" 18 let &t_Ce = "\e\[4:0m" 19 let &t_ut='' 20]], false) 21 22-- default save options 23vim.o.hidden = true 24vim.o.encoding = 'utf8' 25 26-- scroll and mouse options 27vim.o.mouse = 'a' 28vim.o.scrolloff = 2 29 30-- indentation options 31vim.o.autoindent = true 32vim.o.smartindent = false 33vim.o.breakindent = true 34 35-- default tab options 36vim.o.expandtab = true 37vim.o.tabstop = 2 38vim.o.softtabstop = 2 39vim.o.shiftwidth = 2 40 41-- tweak redraw timings 42vim.o.lazyredraw = true 43vim.o.updatetime = 500 44vim.o.timeoutlen = 500 45 46-- fold options 47vim.o.foldenable = true 48vim.o.foldmethod = 'indent' 49vim.o.foldnestmax = 9 50vim.o.foldlevelstart = 3 51 52-- search options 53vim.o.ignorecase = true 54vim.o.smartcase = true 55vim.o.infercase = true 56vim.o.hlsearch = false 57vim.o.incsearch = true 58vim.o.inccommand = 'nosplit' 59 60-- status options 61vim.o.laststatus = 2 62vim.o.statusline = '%F%m%r%h%w [%l,%c] [%L,%p%%]' 63 64-- disable backups and swaps 65vim.o.backup = false 66vim.o.writebackup = false 67vim.o.swapfile = false 68 69-- disable matchparen 70vim.o.showmatch = false 71vim.g.loaded_matchparen = 1 72 73-- disable netrw 74vim.g.loaded_netrw = 1 75vim.g.loaded_netrwPlugin = 1 76 77-- no completion or startup messages 78vim.o.shortmess = vim.o.shortmess .. 'WcCIAa' 79 80-- line numbers 81vim.wo.number = true 82 83-- char options 84vim.opt.fillchars = { 85 vert = '', 86 diff = '', 87 horiz = '', 88 horizup = '', 89 horizdown = '', 90 vertleft = '', 91 vertright = '', 92 verthoriz = '', 93 eob = ' ', 94} 95vim.opt.listchars = { 96 nbsp = "", 97 extends = "»", 98 precedes = "«", 99 tab = "", 100} 101vim.o.list = true 102 103-- splitting options 104vim.go.diffopt = 'filler,vertical,foldcolumn:0,closeoff,indent-heuristic,iwhite,algorithm:patience' 105vim.go.splitbelow = true 106vim.go.splitright = true 107vim.o.splitkeep = 'screen' 108vim.o.switchbuf = 'uselast' 109vim.o.previewheight = 5 110 111-- undo history 112local undodir = vim.fn.expand('$HOME') .. '/.cache/nvim/undo' 113if vim.fn.isdirectory(undodir) == 0 then 114 vim.fn.mkdir(undodir, 'p') 115end 116 117vim.o.undodir = undodir 118vim.o.undofile = true 119vim.o.undolevels = 1000 120vim.o.undoreload = 10000 121 122-- display options 123vim.o.wrap = false 124vim.o.showmode = false 125vim.o.ruler = false 126vim.o.termguicolors = true 127vim.o.cmdheight = 0 128vim.o.background = 'dark' 129vim.wo.signcolumn = 'number' 130vim.wo.cursorline = true 131vim.cmd('colorscheme theme') 132 133-- misc. options 134vim.o.completeopt = 'menuone,noinsert,noselect,popup' 135vim.o.pumheight = 10 136vim.o.winblend = 5 137vim.o.backspace = 'indent,eol,start' 138vim.o.virtualedit = 'block' -- Allow going past the end of line in visual block mode 139vim.o.formatoptions = 'qjl1' -- Don't autoformat comments 140vim.o.synmaxcol = 300 -- Don't highlight long lines 141vim.o.path = '**' -- Use a recursive path (for :find) 142vim.o.gdefault = true -- Use //g for replacements by default 143 144-- wildmenu 145vim.opt.wildignore:append( 146 '*.png,*.jpg,*.jpeg,*.gif,*.wav,*.aiff,*.dll,*.pdb,*.mdb,*.so,*.swp,*.zip,*.gz,*.bz2,*.meta,*.svg,*.cache,*/.git/*' 147) 148vim.o.wildmenu = true 149vim.o.wildmode = 'longest,list,full' 150 151-- built-in ftplugins should not change my keybindings 152vim.g.no_plugin_maps = true 153vim.cmd.filetype({ args = { 'plugin', 'on' } }) 154vim.cmd.filetype({ args = { 'plugin', 'indent', 'on' } }) 155 156--- ripgrep 157vim.o.grepprg = nix_bins.ripgrep .. ' --vimgrep --no-heading --smart-case' 158vim.o.grepformat = "%f:%l:%c:%m,%f:%l:%m" 159 160-- unmap special keys 161local key_opt = { noremap = true, silent = true } 162 163vim.keymap.set('', '<Space>', '<nop>', { noremap = true, silent = true }) 164vim.keymap.set('', '<F1>', '<nop>', { noremap = true, silent = true }) 165 166-- period command in visual mode 167vim.keymap.set('x', '.', '<cmd>norm .<cr>', { noremap = true, silent = true }) 168 169-- match ctrl-c to escape 170vim.keymap.set('', '<c-c>', '<esc>', { noremap = true, silent = true }) 171vim.keymap.set('!', '<c-c>', '<esc>', { noremap = true, silent = true }) 172 173-- window controls 174vim.keymap.set('', '<c-w>,', ':vsp<cr>', { noremap = true, silent = true }) 175vim.keymap.set('', '<c-w>.', ':sp<cr>', { noremap = true, silent = true }) 176 177-- remap semicolon to colon 178vim.keymap.set('n', ';', ':', { noremap = true, silent = true }) 179 180-- destructive x-commands 181vim.keymap.set('', 'X', '"_d', { noremap = true, silent = true }) 182vim.keymap.set('n', 'XX', '"_dd', { noremap = true, silent = true }) 183vim.keymap.set('v', 'x', '"_d', { noremap = true, silent = true }) 184vim.keymap.set('n', 'x', 'v"_d', { noremap = true, silent = true }) 185 186-- clipboard controls 187vim.keymap.set('x', 'Y', '"+y', { noremap = true, silent = true }) 188vim.keymap.set('x', '<m-c>', '"+y', { noremap = true, silent = true }) 189vim.keymap.set('x', '<m-v>', '"+p', { noremap = true, silent = true }) 190vim.keymap.set('n', '<m-v>', '"+P', { noremap = true, silent = true }) 191 192-- indentation in visual mode 193vim.keymap.set('v', '<', '<gv', { noremap = true, silent = true }) 194vim.keymap.set('v', '>', '>gv', { noremap = true, silent = true }) 195 196-- swap visual gj, gk, with jk 197vim.keymap.set({'n', 'x'}, 'j', [[v:count == 0 ? 'gj' : 'j']], { noremap = true, silent = true, expr = true }) 198vim.keymap.set({'n', 'x'}, 'k', [[v:count == 0 ? 'gk' : 'k']], { noremap = true, silent = true, expr = true}) 199 200-- macros per line 201vim.keymap.set('v', '@', ':<C-u>execute ":\'<,\'>normal @".nr2char(getchar())<CR>', { noremap = true, silent = true }) 202 203-- fold controls 204vim.keymap.set('n', '<bar>', '<cmd>norm zc<cr>', { noremap = true, silent = true }) 205vim.keymap.set('n', '<bslash>', '<cmd>norm za<cr>', { noremap = true, silent = true }) 206 207-- set space as leader 208vim.g.mapleader = ' ' 209vim.g.maplocalleader = ' ' 210 211-- buffer controls 212vim.keymap.set('n', '<leader>h', '<cmd>bp<cr>', { desc = 'Previous Buffer' }) 213vim.keymap.set('n', '<leader>l', '<cmd>bn<cr>', { desc = 'Next Buffer' }) 214vim.keymap.set('n', '<leader>j', '<cmd>enew<cr>', { desc = 'New Buffer' }) 215vim.keymap.set('n', '<leader>k', '<cmd>bp <bar> bd #<cr>', { desc = 'Close Buffer' }) 216 217-- golden_size 218local function ignore_trouble_window() 219 local ft = vim.api.nvim_buf_get_option(0, 'filetype') 220 if ft == 'Trouble' then 221 return 1 222 elseif ft == 'gitsigns-blame' then 223 return 1 224 end 225end 226 227require('golden_size').set_ignore_callbacks { 228 { ignore_trouble_window }, 229 { require('golden_size').ignore_float_windows }, 230 { require('golden_size').ignore_by_window_flag }, 231} 232 233-- markdown 234vim.api.nvim_create_autocmd({ 'FileType' }, { 235 pattern = "markdown", 236 callback = function() 237 vim.opt_local.wrap = true 238 vim.o.whichwrap = 'h,l' 239 vim.opt_local.linebreak = true 240 vim.opt_local.formatoptions = vim.opt_local.formatoptions + 'tcn12' 241 end, 242}) 243 244-- telescope 245require('telescope').load_extension('zf-native') 246require('telescope').setup { 247 defaults = { 248 vimgrep_arguments = { 249 nix_bins.ripgrep, 250 '--color=never', '--no-heading', '--with-filename', '--line-number', '--column', '--smart-case' 251 }, 252 prompt_prefix = '', 253 selection_caret = '', 254 mappings = { 255 i = { 256 ['<c-t>'] = require('trouble.sources.telescope').open, 257 ['<c-c>'] = require('telescope.actions').close, 258 }, 259 n = { 260 ['<c-t>'] = require('trouble.sources.telescope').open, 261 ['<esc>'] = require('telescope.actions').close, 262 }, 263 }, 264 }, 265} 266 267vim.keymap.set('n', '<leader>b', function() 268 require('telescope.builtin').buffers() 269end, { desc = 'Workspace Search' }) 270 271vim.keymap.set('n', '<leader>f', function() 272 require('telescope.builtin').live_grep() 273end, { desc = 'Workspace Search' }) 274 275vim.keymap.set('n', '<leader>n', function() 276 require('telescope.builtin').lsp_document_symbols( 277 require('telescope.themes').get_ivy({ 278 ignore_symbols = { 'variable', 'constant', 'property' }, 279 }) 280 ) 281end, { desc = 'Document Symbols' }) 282 283vim.keymap.set('n', '<leader>N', function() 284 require('telescope.builtin').lsp_dynamic_workspace_symbols( 285 require('telescope.themes').get_ivy({ 286 ignore_symbols = { 'variable', 'constant', 'property' }, 287 }) 288 ) 289end, { desc = 'Workspace Symbols' }) 290 291vim.keymap.set('n', '<leader>o', function() 292 local telescope_builtins = require('telescope.builtin') 293 vim.fn.system('git rev-parse --is-inside-work-tree') 294 if vim.v.shell_error == 0 then 295 telescope_builtins.git_files() 296 else 297 telescope_builtins.find_files() 298 end 299end, { desc = 'Workspace Files' }) 300 301-- define signs 302vim.fn.sign_define("DiagnosticSignError", { text = "", texthl = "DiagnosticSignError" }) 303vim.fn.sign_define("DiagnosticSignWarn", { text = "", texthl = "DiagnosticSignWarn" }) 304vim.fn.sign_define("DiagnosticSignHint", { text = "", texthl = "DiagnosticSignHint" }) 305vim.fn.sign_define("DiagnosticSignInfo", { text = "", texthl = "DiagnosticSignInfo" }) 306 307-- configure vim diagnostics 308vim.diagnostic.config({ 309 underline = true, 310 signs = true, 311 update_in_insert = false, 312 severity_sort = true, 313 virtual_text = { 314 severity = { min = vim.diagnostic.severity.W }, 315 source = 'if_many', 316 }, 317 float = { 318 show_header = true, 319 source = 'if_many', 320 border = 'rounded', 321 focusable = false, 322 severity_sort = true, 323 }, 324}) 325 326vim.keymap.set('n', 'gk', vim.diagnostic.open_float, { desc = 'Show Diagnostic' }) 327vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, { desc = 'Previous Diagnostic' }) 328vim.keymap.set('n', ']d', vim.diagnostic.goto_next, { desc = 'Next Diagnostic' }) 329 330-- customise hover window size 331vim.lsp.handlers["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, { 332 max_width = math.max(math.floor(vim.o.columns * 0.7), 100), 333 max_height = math.max(math.floor(vim.o.lines * 0.3), 30), 334}) 335 336-- register custom filetypes 337vim.filetype.add({ 338 extension = { 339 mdx = 'markdown', 340 astro = 'astro', 341 envrc = 'bash', 342 }, 343 pattern = { 344 ['.*/%.vscode/.*%.json'] = 'json5', 345 }, 346}) 347 348-- lspconfig 349local lsp = require('lspconfig') 350local lsp_util = require('lspconfig.util') 351 352local function lsp_on_attach(client, buf) 353 if client.config.flags and not client.config.flags.allow_incremental_sync ~= nil then 354 client.config.flags.allow_incremental_sync = true 355 end 356 357 vim.api.nvim_buf_set_option(buf, 'formatexpr', 'v:lua.vim.lsp.formatexpr()') 358 vim.api.nvim_buf_set_option(buf, 'omnifunc', 'v:lua.vim.lsp.omnifunc') 359 vim.api.nvim_buf_set_option(buf, 'tagfunc', 'v:lua.vim.lsp.tagfunc') 360 361 if pcall(function() 362 return vim.api.nvim_buf_get_var(buf, 'lsp:keys_attached') 363 end) ~= true then 364 vim.api.nvim_buf_set_var(buf, 'lsp:keys_attached', true) 365 366 vim.keymap.set('n', 'gd', vim.lsp.buf.definition, { desc = 'Go to definition', buffer = buf }) 367 vim.keymap.set('n', 'gD', vim.lsp.buf.declaration, { desc = 'Go to declaration', buffer = buf }) 368 vim.keymap.set('n', 'gy', vim.lsp.buf.type_definition, { desc = 'Go to type definition', buffer = buf }) 369 vim.keymap.set('n', 'gi', vim.lsp.buf.implementation, { desc = 'Go to implementation', buffer = buf }) 370 vim.keymap.set('n', 'gn', vim.lsp.buf.rename, { desc = 'Rename', buffer = buf }) 371 vim.keymap.set('n', 'gf', vim.lsp.buf.code_action, { desc = 'Code Actions', buffer = buf }) 372 vim.keymap.set('n', 'gr', '<cmd>Trouble lsp open<cr>', { desc = 'Show references', buffer = buf }) 373 vim.keymap.set('n', 'K', vim.lsp.buf.hover, { buffer = buf }) 374 vim.keymap.set('n', '<C-k>', vim.lsp.buf.signature_help, { buffer = buf }) 375 vim.keymap.set('n', '<C-k>', vim.lsp.buf.signature_help, { buffer = buf }) 376 end 377end 378 379local function lsp_capabilities(extends) 380 local capabilities = vim.tbl_deep_extend( 381 "force", 382 {}, 383 vim.lsp.protocol.make_client_capabilities(), 384 require('cmp_nvim_lsp').default_capabilities() or {}, 385 extends or {} 386 ) 387 capabilities.textDocument.completion.completionItem.documentationFormat = { "markdown" } 388 capabilities.textDocument.completion.completionItem.snippetSupport = true 389 capabilities.workspace.didChangeWatchedFiles.dynamicRegistration = true 390 capabilities.workspace.workspaceFolders = true 391 return capabilities 392end 393 394local function lsp_setup(server, opts) 395 local config = lsp[server] 396 opts.autostart = false 397 opts.capabilities = lsp_capabilities(opts.capabilities) 398 opts.on_attach = lsp_on_attach 399 config.setup(opts) 400 401 local event 402 local pattern 403 if config.filetypes then 404 event = 'FileType' 405 pattern = table.concat(config.filetypes, ',') 406 else 407 event = 'BufReadPost' 408 pattern = '*' 409 end 410 411 vim.api.nvim_create_autocmd(event, { 412 pattern = pattern, 413 callback = function(opt) 414 if not vim.b[opt.buf or vim.api.nvim_get_current_buf()].big then 415 config.manager:try_add(opt.buf) 416 end 417 end, 418 group = lsp_group, 419 }) 420end 421 422lsp_setup('ts_ls', { 423 cmd = { nix_bins.tsserver, "--stdio" }, 424 flags = { debounce_text_changes = 200 }, 425 single_file_support = false, 426 init_options = { 427 hostInfo = 'neovim', 428 disableAutomaticTypingAcquisition = true, 429 preferences = { 430 importModuleSpecifierPreference = 'project-relative', 431 }, 432 }, 433 root_dir = function(fname) 434 if lsp_util.root_pattern('.flowconfig')(fname) ~= nil then 435 return nil 436 else 437 return lsp_util.root_pattern('tsconfig.json', 'package.json', 'jsconfig.json', '.git')(fname) 438 end 439 end, 440}) 441 442lsp_setup('flow', { 443 cmd = { nix_bins.bunx, "--no-install", "flow", "lsp" }, 444 flags = { debounce_text_changes = 200 }, 445 single_file_support = false, 446}) 447 448lsp_setup('eslint', { 449 cmd = { nix_bins.eslintls, "--stdio" }, 450 flags = { debounce_text_changes = 200 }, 451 settings = { 452 rulesCustomizations = { 453 { rule = 'prettier/prettier', severity = 'off' }, 454 { rule = 'sort-keys', severity = 'off' }, 455 { rule = 'quotes', severity = 'off' }, 456 { rule = 'max-len', severity = 'off' }, 457 { rule = 'no-tabs', severity = 'off' }, 458 }, 459 }, 460}) 461 462lsp_setup('cssls', { 463 cmd = { nix_bins.cssls, "--stdio" }, 464 flags = { debounce_text_changes = 200 }, 465}) 466 467lsp_setup('html', { 468 cmd = { nix_bins.htmlls, "--stdio" }, 469 flags = { debounce_text_changes = 200 }, 470}) 471 472lsp_setup('jsonls', { 473 cmd = { nix_bins.jsonls, "--stdio" }, 474 flags = { debounce_text_changes = 200 }, 475}) 476 477lsp_setup('rust_analyzer', { 478 cmd = { nix_bins.rustanalyzer }, 479 flags = { debounce_text_changes = 200 }, 480 settings = { 481 ["rust-analyzer"] = { 482 assist = { 483 importGranularity = "module", 484 importPrefix = "self", 485 }, 486 cargo = { 487 loadOutDirsFromCheck = true, 488 }, 489 procMacro = { 490 enable = true, 491 }, 492 }, 493 }, 494}) 495 496lsp_setup('terraformls', { 497 cmd = { nix_bins.terraformls }, 498 flags = { debounce_text_changes = 200 }, 499}) 500 501lsp_setup('zls', { 502 cmd = { nix_bins.zls }, 503 flags = { debounce_text_changes = 200 }, 504 settings = { 505 zls = { 506 zig_exe_path = nix_bins.zig, 507 }, 508 } 509}) 510 511-- treesitter 512vim.opt.runtimepath:append("~/.local/share/nvim/site/parser") 513 514require('nvim-treesitter.install').compilers = { nix_bins.clang } 515 516require('nvim-treesitter.configs').setup { 517 auto_install = false, 518 highlight = { 519 enable = true, 520 disable = function(lang, buf) 521 return vim.b[buf].big 522 end, 523 }, 524 incremental_selection = { 525 enable = true, 526 disable = function(lang, buf) 527 return vim.b[buf].big 528 end, 529 keymaps = { 530 node_incremental = "]", 531 scope_incremental = "=", 532 node_decremental = "[", 533 }, 534 }, 535 refactor = { 536 highlight_definitions = { 537 enable = true, 538 disable = function(lang, buf) 539 return vim.b[buf].big 540 end, 541 }, 542 smart_rename = { 543 enable = true, 544 disable = function(lang, buf) 545 return vim.b[buf].big 546 end, 547 keymaps = { smart_rename = "gn" } 548 }, 549 }, 550 textobjects = { 551 select = { 552 enable = true, 553 disable = function(lang, buf) 554 return vim.b[buf].big 555 end, 556 keymaps = { 557 ["af"] = "@function.outer", 558 ["if"] = "@function.inner", 559 ["ac"] = "@call.outer", 560 ["ic"] = "@call.inner", 561 }, 562 }, 563 }, 564} 565 566vim.keymap.set('n', '<c-e', function() 567 print(vim.inspect(vim.treesitter.get_captures_at_cursor(0))) 568end, { desc = 'Output Treesitter Token' }) 569 570-- lspkind 571require('lspkind').init { 572 mode = 'symbol_text', 573 preset = 'codicons', 574} 575 576-- file browser 577require("oil").setup({ 578 default_file_explorer = true, 579 delete_to_trash = false, 580 skip_confirm_for_simple_edits = true, 581 prompt_save_on_select_new_entry = true, 582 cleanup_delay_ms = 2000, 583 lsp_file_methods = { 584 timeout_ms = 1000, 585 autosave_changes = false, 586 }, 587 constrain_cursor = 'editable', 588 watch_for_changes = false, 589 use_default_keymaps = true, 590 keymaps = { 591 ["<C-c>"] = false, 592 }, 593 view_options = { 594 show_hidden = false, 595 is_hidden_file = function(name, bufnr) 596 return vim.startswith(name, '.') 597 end, 598 is_always_hidden = function(name, bufnr) 599 return name == '.DS_Store' 600 end, 601 natural_order = true, 602 case_insensitive = true, 603 sort = { 604 { 'type', 'asc' }, 605 { 'name', 'asc' }, 606 }, 607 }, 608 float = { 609 preview_split = 'auto', 610 border = 'none', 611 win_options = { 612 winblend = 5, 613 }, 614 }, 615 preview = { 616 border = 'none', 617 win_options = { winblend = 5 }, 618 update_on_cursor_moved = true, 619 }, 620 progress = { 621 border = 'none', 622 minimized_border = 'none', 623 win_options = { winblend = 5 }, 624 }, 625 ssh = { border = 'none', }, 626 keymaps_help = { border = 'none' }, 627}) 628 629vim.keymap.set('n', '-', require('oil').open, { noremap = true, silent = true }) 630 631-- hide sticky commands 632vim.api.nvim_create_autocmd({ 'CursorHold' }, { 633 pattern = "*", 634 callback = function() 635 vim.defer_fn(function() 636 if vim.api.nvim_get_mode().mode == 'n' then 637 vim.cmd('echon ""') 638 end 639 end, 3000) 640 end, 641}) 642 643-- mark big buffers 644vim.api.nvim_create_autocmd({ 'BufReadPre' }, { 645 pattern = "*", 646 callback = function() 647 local buf = vim.api.nvim_get_current_buf() 648 local ok, stats = pcall(vim.loop.fs_stat, vim.api.nvim_buf_get_name(buf)) 649 vim.b[buf].big = ok and stats and (stats.size > 100 * 1024) 650 if vim.b[buf].big then 651 vim.opt_local.spell = false 652 vim.opt_local.showmatch = false 653 vim.opt_local.undofile = false 654 vim.opt_local.foldmethod = 'manual' 655 end 656 end, 657}) 658 659-- customise fold text 660vim.api.nvim_exec([[ 661 function! FoldText() 662 let nl = v:foldend - v:foldstart + 1 663 let start = substitute(getline(v:foldstart), "^ *", "", 1) 664 let end = substitute(getline(v:foldend),"^ *", "", 1) 665 let txt = ' ' . start . ' … ' . end . ' (' . nl . ' lines) ' 666 return txt 667 endfunction 668 set foldtext=FoldText() 669]], false) 670 671-- autocompletion 672local cmp = require('cmp') 673 674local has_words_before = function() 675 local line, col = unpack(vim.api.nvim_win_get_cursor(0)) 676 return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil 677end 678 679cmp.setup { 680 enabled = function() 681 local context = require('cmp.config.context') 682 if vim.b[vim.api.nvim_get_current_buf()].big then 683 return false 684 elseif vim.api.nvim_get_mode().mode == 'c' then 685 return true 686 else 687 return not context.in_treesitter_capture('comment') 688 and not context.in_syntax_group('Comment') 689 end 690 end, 691 preselect = cmp.PreselectMode.None, 692 mapping = cmp.mapping.preset.insert({ 693 ['<C-d>'] = cmp.mapping.scroll_docs(-4), 694 ['<C-f>'] = cmp.mapping.scroll_docs(4), 695 ['<C-Space>'] = cmp.mapping.complete(), 696 ['<C-c>'] = cmp.mapping(function(fallback) 697 if cmp.visible() then 698 cmp.close() 699 end 700 fallback() 701 end, {"i", "c"}), 702 ['<CR>'] = cmp.mapping({ 703 i = cmp.mapping.confirm({ behavior = cmp.ConfirmBehavior.Replace, select = false }), 704 c = function(fallback) 705 if cmp.visible() then 706 cmp.confirm({ behavior = cmp.ConfirmBehavior.Replace, select = false }) 707 else 708 fallback() 709 end 710 end 711 }), 712 ['<Tab>'] = cmp.mapping(function(fallback) 713 if cmp.visible() then 714 cmp.select_next_item() 715 elseif has_words_before() then 716 cmp.complete() 717 else 718 fallback() 719 end 720 end, {"i", "s"}), 721 ['<S-Tab>'] = cmp.mapping(function(fallback) 722 if cmp.visible() then 723 cmp.select_prev_item() 724 else 725 fallback() 726 end 727 end, {"i", "s"}), 728 }), 729 snippet = { 730 expand = function(args) 731 vim.snippet.expand(args.body) 732 end, 733 }, 734 completion = { 735 keyword_length = 3 736 }, 737 view = { 738 entries = "native", 739 }, 740 experimental = { 741 ghost_text = { 742 hl_group = 'GhostText', 743 }, 744 }, 745 sources = cmp.config.sources({ 746 { name = 'nvim_lsp_signature_help' }, 747 { name = 'nvim_lsp' }, 748 { name = 'treesitter' }, 749 }), 750 formatting = { 751 format = require('lspkind').cmp_format(), 752 }, 753} 754 755cmp.setup.filetype('gitcommit', { 756 enabled = false, 757}) 758 759-- gitsigns 760require('gitsigns').setup { 761 signcolumn = true, 762 numhl = false, 763 linehl = false, 764 word_diff = false, 765 current_line_blame = false, 766 signs = { 767 add = { text = '' }, 768 change = { text = '' }, 769 delete = { text = '' }, 770 topdelete = { text = '' }, 771 changedelete = { text = '' }, 772 }, 773 diff_opts = { 774 algorithm = 'histogram', 775 internal = true, 776 linematch = true, 777 indent_heuristic = true, 778 ignore_blank_lines = true, 779 ignore_whitespace_change = true, 780 ignore_whitespace_change_at_eol = true, 781 }, 782 preview_config = { 783 border = 'none', 784 style = 'minimal', 785 relative = 'cursor', 786 row = 1, 787 col = 0 788 }, 789 on_attach = function(buf) 790 local actions = require('gitsigns.actions') 791 792 vim.keymap.set('n', ']c', function() 793 require('gitsigns.actions').next_hunk() 794 end, { desc = 'Next Git Hunk', buffer = buf }) 795 vim.keymap.set('n', '[c', function() 796 require('gitsigns.actions').next_hunk() 797 end, { desc = 'Previous Git Hunk', buffer = buf }) 798 vim.keymap.set('n', 'gb', function() 799 require('gitsigns.actions').blame_line({ full = true }) 800 end, { desc = 'Blame Line', buffer = buf }) 801 vim.keymap.set('n', 'gB', function() 802 require('gitsigns.actions').blame() 803 end, { desc = 'Blame Buffer', buffer = buf }) 804 vim.keymap.set('n', 'gh', function() 805 require('gitsigns.actions').preview_hunk(true) 806 end, { desc = 'Show Git Hunk', buffer = buf }) 807 vim.keymap.set('n', 'gs', function() 808 require('gitsigns.actions').stage_hunk() 809 end, { desc = 'Stage Git Hunk', buffer = buf }) 810 vim.keymap.set('n', 'gS', function() 811 require('gitsigns.actions').stage_hunk() 812 end, { desc = 'Unstage Git Hunk', buffer = buf }) 813 vim.keymap.set('n', 'gt', function() 814 require('gitsigns.actions').diffthis() 815 end, { desc = 'Diff against HEAD', buffer = buf }) 816 vim.keymap.set('n', 'gT', function() 817 require('gitsigns.actions').diffthis('~') 818 end, { desc = 'Diff against HEAD~1', buffer = buf }) 819 end, 820} 821 822-- hardline 823local function status_diagnostic_handler(prefix, severity) 824 return function() 825 local count = #vim.diagnostic.get(0, { severity = severity }) 826 if count > 0 then 827 return string.format('%s %d', prefix, count) 828 else 829 return '' 830 end 831 end 832end 833 834local function status_git() 835 local b = vim.b 836 if b.gitsigns_status_dict then 837 return table.concat({ 838 hi('GitSignsAdd', string.format(' %d', b.gitsigns_status_dict.added or 0)), 839 hi('GitSignsChange', string.format(' %d', b.gitsigns_status_dict.changed or 0)), 840 hi('GitSignsDelete', string.format(' %d', b.gitsigns_status_dict.removed or 0)), 841 hi('DiagnosticSignInfo', b.gitsigns_head ~= nil and string.format('( %s)', b.gitsigns_head) or ''), 842 }, ' ') 843 else 844 return '' 845 end 846end 847 848local function status_filetype() 849 return (vim.bo.filetype ~= '' and string.format(' %s', vim.bo.filetype) or '') 850end 851 852local function status_progress() 853 local blocks = {'', '', '', '', '', '', '', '', ' '} 854 local nbline = vim.fn.line('$') 855 local line = vim.fn.line('.') 856 local progress = blocks[math.ceil(line / (nbline / 9))] 857 return nbline ~= 1 and table.concat({ 858 string.format('%s%d/%d', string.rep('·', #tostring(nbline) - #tostring(line)), line, nbline), 859 progress, 860 }, ' ') or '' 861end 862 863require('hardline').setup { 864 bufferline = false, 865 theme = vim.tbl_deep_extend( 866 "force", 867 require('hardline.themes.custom_colors').set(hardline_colors), 868 { 869 mode = { 870 inactive = { 871 guibg = hardline_colors.inactive_menu.gui, 872 ctermbg = hardline_colors.inactive_menu.cterm, 873 }, 874 }, 875 } 876 ), 877 sections = { 878 {class = 'mode', item = require('hardline.parts.mode').get_item}, 879 {class = 'high', item = function() return vim.fn.expand('%:~:.') end }, 880 {class = 'med', item = status_git, hide = 100}, 881 '%<', 882 {class = 'med', item = '%='}, 883 {class = 'error', item = status_diagnostic_handler('', vim.diagnostic.severity.ERROR) }, 884 {class = 'warning', item = status_diagnostic_handler('', vim.diagnostic.severity.WARN) }, 885 {class = 'high', item = status_filetype, hide = 80}, 886 {class = 'mode', item = status_progress }, 887 }, 888} 889 890-- trouble 891require('trouble').setup { 892 height = 13, 893 fold_open = "", 894 fold_closed = "", 895 padding = false, 896 indent_lines = false, 897 icons = { 898 ---@type trouble.Indent.symbols 899 indent = { 900 top = "", 901 middle = "├╴", 902 last = "└╴", 903 fold_open = "", 904 fold_closed = "", 905 ws = " ", 906 }, 907 folder_closed = "", 908 folder_open = "", 909 kinds = { 910 Array = "", 911 Boolean = "", 912 Class = "", 913 Constant = "", 914 Constructor = "", 915 Enum = "", 916 EnumMember = "", 917 Event = "", 918 Field = "", 919 File = "", 920 Function = "", 921 Interface = "", 922 Key = "", 923 Method = "", 924 Module = "", 925 Namespace = "", 926 Null = "", 927 Number = "", 928 Object = "", 929 Operator = "", 930 Package = "", 931 Property = "", 932 String = "", 933 Struct = "", 934 TypeParameter = "", 935 Variable = "", 936 }, 937 }, 938} 939 940vim.api.nvim_create_autocmd({ 'FileType' }, { 941 pattern = "Trouble", 942 callback = function() 943 vim.opt_local.wrap = true 944 vim.opt_local.linebreak = true 945 end, 946}) 947 948vim.keymap.set('n', '<leader>q', '<cmd>Trouble qflist open<cr>', { desc = 'Quickfix list' }) 949vim.keymap.set('n', '<leader>p', '<cmd>Trouble loclist open<cr>', { desc = 'Location list' }) 950vim.keymap.set('n', '<leader>d', '<cmd>Trouble diagnostics open filter.buf=0<cr>', { desc = 'Document Diagnostics' }) 951vim.keymap.set('n', '<leader>D', '<cmd>Trouble diagnostics open<cr>', { desc = 'Workspace Diagnostics' }) 952 953-- dressing 954require('dressing').setup { 955 select = { 956 backend = { "telescope", "builtin", "nui" }, 957 telescope = require('telescope.themes').get_cursor(), 958 }, 959}