-- Enable experimental faster module loader vim.loader.enable() ---- Built in settings ---- -- Create convenient aliases local o = vim.o local g = vim.g local fn = vim.fn local opt = vim.opt -- Whether to enable workman remappings local workman = false -- Set font o.guifont = 'IosevkaTermSlab Nerd Font,IosevkaTerm Nerd Font,Iosevka Term Slab,Iosevka:h10:#e-subpixelantialias' g.neovide_floating_z_height = 1 g.neovide_confirm_quit = true -- Confirm closing neovide window when changes are unsaved g.neovide_cursor_smooth_blink = true if fn.hostname() == 'tappy' then g.neovide_refresh_rate = 144 end opt.guicursor:append('a:blinkon1500-blinkoff1500-blinkwait1200') -- Blink cursor once every 1.5 seconds o.mouse = 'a' -- Enable mouse input o.termguicolors = true -- Enable 24bit terminal colors -- Other interface settings o.clipboard = 'unnamedplus' -- Use system clipboard by default o.hidden = true -- Allow buffers to not be attached to a window o.linebreak = true -- Enable word-wrapping at the end of visual lines o.breakindent = true -- preserve indentention on lines continuing from a wrap opt.breakindentopt = { 'sbr' -- 'showbreak' character should appear before virtual indentention } o.hlsearch = true -- Highlight search results o.scrolloff = 5 -- Margin between cursor and screen top/bottom o.showmatch = true -- Highlight matching brackets o.splitright = true -- Open new windows below o.splitbelow = true -- Open new windows to the right o.splitkeep = 'screen' -- Keep window position when creating splits o.title = true -- Set title of terminal window o.updatetime = 300 -- Write swap file every 300 ms (supposedly reduces delays) o.foldlevel = 99 -- Keep all folds open o.foldlevelstart = 99 o.foldenable = true -- Don't disable folds o.conceallevel = 2 -- Hide concealed text, use replacement if defined o.sbr = '┆' opt.listchars = { -- Symbols for whitespace chars when 'list' is enabled tab = '🭰 ', trail = '-', nbsp = '+' } opt.fillchars = { -- Characters to fill certain types of empty space with diff = ' ', fold = ' ', foldopen = '', foldsep = ' ', foldclose = '' } opt.diffopt:append({'indent-heuristic', 'algorithm:histogram'}) if fn.has('nvim-0.10') then o.smoothscroll = true -- Scroll by screen lines instead of physical lines opt.display:append('lastline') end o.tabstop = 4 -- A physical tab is 4 characters wide o.shiftwidth = 4 -- A unit of indentention is 4 levels wide o.wrapmargin = 0 -- Disable hard line wrapping o.textwidth = 0 -- Comments lines should wrap at 100 chars o.laststatus = 3 -- Use one global status bar -- Set key g.mapleader = ' ' g.maplocalleader = '\\' vim.cmd 'filetype plugin indent on' o.exrc = true -- Load .nvim.lua .nvimrc and .exrc files -- Enable persistent undo if fn.has('persistent_undo') then o.undodir = fn.stdpath('data') .. '/undo' o.undofile = true end -- Use rg as grep program if fn.executable('rg') then o.grepprg = 'rg --vimgrep --smart-case --hidden' o.grepformat = '%f:%l:%c:%m' end if vim.fn.executable('darkman') then local mode = vim.trim(vim.fn.system('darkman get')) if mode == 'dark' or mode == 'light' then vim.o.background = mode end end local zoom_notification = nil --- "Zoom" by changing gui font size --- @param delta integer function _G.zoom(delta) local properties = { hide_from_history = true, render = 'compact', on_close = function() zoom_notification = nil end } if zoom_notification ~= nil then properties.replace = zoom_notification.id end local message if vim.g.neovide_scale_factor ~= nil then properties.title = 'Zoom' vim.g.neovide_scale_factor = vim.g.neovide_scale_factor + (delta * 0.05) message = 'Zoom set to ' .. vim.g.neovide_scale_factor * 100 .. '%' else properties.title = 'Font size' local size = fn.substitute(o.guifont, [[^.*:h\([^:]*\).*$]], [[\1]], '') size = size + delta local guifont = fn.substitute(o.guifont, [[:h\([^:]*\)]], ':h' .. size, '') o.guifont = guifont message = 'Font size set to ' .. size end zoom_notification = vim.notify(message, vim.log.levels.INFO, properties) end local function zoom_in() zoom(1) end local function zoom_out() zoom(-1) end vim.keymap.set('n', '!', 'copen', { desc = 'Quickfix window' }) vim.keymap.set('n', '', 'set number! relativenumber!', { desc = 'Toggle relative numbers' }) vim.keymap.set('n', '', 'set number!', { desc = 'Toggle line numbers' }) vim.keymap.set('n', '', 'set list!', { desc = 'Annotate whitespace' }) vim.keymap.set('n', '', 'h', { desc = 'Go to the left window' }) vim.keymap.set('n', '', 'l', { desc = 'Go to the right window' }) vim.keymap.set('n', '', 'j', { desc = 'Go to the up window' }) vim.keymap.set('n', '', 'k', { desc = 'Go to the down window' }) vim.keymap.set('n', '' , zoom_in, { desc = 'Zoom in' }) vim.keymap.set('n', '' , zoom_out, { desc = 'Zoom out' }) vim.keymap.set('n', '', function() local ok, notify = pcall(require, 'notify') if ok then notify.dismiss {} end vim.lsp.buf.clear_references() vim.cmd('nohlsearch|diffupdate|normal! ') end, { desc = 'Clear' }) -- Quickfix mappings local function quickfix_toggle() for _, win in pairs(vim.fn.getwininfo()) do if win.quickfix == 1 then vim.cmd.cclose() return end end vim.cmd.copen() end vim.keymap.set('n', 'qq', quickfix_toggle, { desc = 'Open' }) vim.keymap.set('n', 'qc', 'cclose', { desc = 'Close' }) vim.keymap.set('n', 'qj', 'cnext', { desc = 'Next' }) vim.keymap.set('n', 'qk', 'cprev', { desc = 'Previous' }) vim.keymap.set('n', 'qh', 'colder', { desc = 'Older list' }) vim.keymap.set('n', 'ql', 'cnewer', { desc = 'Newer list' }) vim.keymap.set('n', 'c', 'vert te', { desc = 'Terminal (vsplit)' }) vim.keymap.set('n', 'C', 'tab te', { desc = 'Terminal (tab)' }) -- Diagnostic mappings vim.keymap.set('n', 'eo', vim.diagnostic.open_float, { desc = 'Open diagnostic' }) vim.keymap.set('n', 'eq', vim.diagnostic.setqflist, { desc = 'Save to quickfix' }) vim.keymap.set('n', 'e]', vim.diagnostic.goto_next, { desc = 'Next diagnostic' }) vim.keymap.set('n', 'e[', vim.diagnostic.goto_prev, { desc = 'Previous diagnostic' }) vim.keymap.set('n', 'ee', function() vim.diagnostic.goto_next { severity = vim.diagnostic.severity.E } end, { desc = 'Next error' }) vim.keymap.set('n', 'eE', function() vim.diagnostic.goto_prev { severity = vim.diagnostic.severity.E } end, { desc = 'Previous error' }) vim.keymap.set('n', 'ew', function() vim.diagnostic.goto_next { severity = vim.diagnostic.severity.W } end, { desc = 'Next warning' }) vim.keymap.set('n', 'eW', function() vim.diagnostic.goto_prev { severity = vim.diagnostic.severity.W } end, { desc = 'Previous warning' }) vim.keymap.set('n', ']e', function() vim.diagnostic.goto_next { severity = vim.diagnostic.severity.E } end, { desc = 'Next error' }) vim.keymap.set('n', '[e', function() vim.diagnostic.goto_prev { severity = vim.diagnostic.severity.E } end, { desc = 'Previous error' }) vim.keymap.set('n', ']w', function() vim.diagnostic.goto_next { severity = vim.diagnostic.severity.W } end, { desc = 'Next warning' }) vim.keymap.set('n', '[w', function() vim.diagnostic.goto_prev { severity = vim.diagnostic.severity.W } end, { desc = 'Previous warning' }) vim.keymap.set('n', 'eh', vim.diagnostic.hide, { desc = 'Hide diagnostics' }) vim.keymap.set('n', 'es', vim.diagnostic.show, { desc = 'Show diagnostics' }) vim.keymap.set('n', 'eC', vim.diagnostic.reset, { desc = 'Clear diagnostics' }) -- Commands vim.cmd [[ command! Light set background=light command! Dark set background=dark ]] -- Autocommands local augroup = vim.api.nvim_create_augroup('luarc', {clear = true}) local au = function(autocmd, opts) opts.group = augroup vim.api.nvim_create_autocmd(autocmd, opts) end au('User', { pattern = 'StartifyReady', callback = function() if workman then vim.keymap.set('', 'n', 'gj', {silent = true, buffer = true}) vim.keymap.set('', 'e', 'gk', {silent = true, buffer = true}) end end, desc = 'Override Startify mappings', }) au('TextYankPost', { callback = function() vim.highlight.on_yank() end, desc = 'Highlight when text is yanked', }) au('BufReadPost', { callback = function() local mark = vim.api.nvim_buf_get_mark(0, '"') local lcount = vim.api.nvim_buf_line_count(0) if mark[1] > 0 and mark[1] <= lcount then pcall(vim.api.nvim_win_set_cursor, 0, mark) end end, desc = 'Remember cursor position across restarts' }) -- Diagnostics vim.diagnostic.config { -- Configure underlining diagnostics underline = { -- Only underline warnings and up severity = { min = vim.diagnostic.severity.WARN } } } fn.sign_define('DiagnosticSignInfo', { text = '', texthl = 'DiagnosticSignInfo' }) fn.sign_define('DiagnosticSignHint', { text = '', texthl = 'DiagnosticSignHint' }) fn.sign_define('DiagnosticSignWarn', { text = '', texthl = 'DiagnosticSignWarn' }) fn.sign_define('DiagnosticSignError', { text = '', texthl = 'DiagnosticSignError' }) au('LspAttach', { callback = function(event) require'which-key'.register({ ['l'] = { name = 'LSP', D = {vim.lsp.buf.declaration, 'Declaration'}, d = {'Telescope lsp_definitions', 'Definition'}, i = {'Telescope lsp_implementations', 'Implementation'}, I = {vim.lsp.buf.implementation, 'Implementation (quickfix)'}, r = {vim.lsp.buf.rename, 'Rename'}, h = {function() vim.lsp.inlay_hint.enable(0, not vim.lsp.inlay_hint.is_enabled()) end, 'Inlay hints'}, l = {vim.lsp.codelens.refresh, 'Show codelenses'}, L = {vim.lsp.codelens.run, 'Run codelens'}, t = {'Telescope lsp_type_definitions', 'Type definition'}, u = {'Telescope lsp_references', 'Usages/references'}, U = {vim.lsp.buf.references, 'Usages/references (quickfix)'}, }, g = { d = {vim.lsp.buf.definition, 'Goto definition'}, D = {vim.lsp.buf.implementation, 'Goto implementation'}, R = {vim.lsp.buf.rename, 'Rename'}, y = {vim.lsp.buf.type_definition, 'Type definition'}, }, [''] = {vim.lsp.buf.document_highlight, 'Highlight object under cursor'}, }, { buffer = event.buf }) end }) function _G.mason_path(package) return vim.fn.stdpath('data') .. '/mason/packages/' .. package end -- Bootstrap plugin system local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" if not vim.loop.fs_stat(lazypath) then vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", "--branch=stable", -- latest stable release lazypath, }) end vim.opt.rtp:prepend(lazypath) require('lazy').setup({ -- Themes -- {'miikanissi/modus-themes.nvim', opts = {}}, 'arcticicestudio/nord-vim', 'folke/tokyonight.nvim', {'catppuccin/nvim', name = 'catppuccin', opts = { integrations = { barbar = true, } }}, 'navarasu/onedark.nvim', -- Filetype plugins -- 'rhysd/vim-crystal', 'bakpakin/fennel.vim', 'mboughaba/i3config.vim', 'mracos/mermaid.vim', 'lifepillar/pgsql.vim', 'ajouellette/sway-vim-syntax', 'cespare/vim-toml', -- Editing {'LunarWatcher/auto-pairs', init = function() vim.g.AutoPairsMultilineClose = 0 vim.g.AutoPairsMapBS = 1 vim.g.AutoPairsMapCR = 1 vim.g.AutoPairsCompatibleMaps = 1 vim.g.AutoPairsShortcutToggleMultilineClose = '' end}, 'ojroques/nvim-bufdel', {'stevearc/conform.nvim', config = function () require'conform'.setup { formatters_by_ft = { html = {"prettier"}, }, format_on_save = { lsp_fallback = true, filter = function(client) return client.name == 'rust-analyzer' end } } vim.api.nvim_create_user_command( 'Conform', function() require'conform'.format { lsp_fallback = true, } end, { desc = 'Format buffer', } ) au('LspAttach', { callback = function() vim.bo.formatexpr = "v:lua.require'conform'.formatexpr()" end }) end}, 'direnv/direnv.vim', 'jbyuki/instant.nvim', {'mizlan/iswap.nvim', config = function() require'iswap'.setup {} vim.keymap.set('', 's', 'ISwapWith', { desc = 'Swap' }) end}, {'windwp/nvim-projectconfig', opts = { -- Load project configuration when changing directory autocmd = true, }}, 'tpope/vim-repeat', 'tpope/vim-sleuth', 'AndrewRadev/splitjoin.vim', {'kylechui/nvim-surround', opts = {}}, 'wellle/targets.vim', {'vim-test/vim-test', init = function() vim.g['test#neovim#term_position'] = 'vert' vim.g['test#strategy'] = 'neovim' end}, {'julian/vim-textobj-variable-segment', dependencies = {'kana/vim-textobj-user'}}, {'nvim-treesitter/nvim-treesitter', build = ':TSUpdate', opts = { -- Configure the nvim-ts-autotag plugin autotag = { enable = true, }, ensure_installed = {'lua', 'html', 'c', 'cpp', 'nix', 'vim', 'vimdoc', 'rust', 'bash', 'markdown', 'java', 'markdown_inline'}, highlight = { enable = true, disable = {'rust', 'bash'} }, incremental_selection = { enable = true }, }, config = function(_, opts) require'nvim-treesitter.configs'.setup(opts) end}, 'windwp/nvim-ts-autotag', {'kevinhwang91/nvim-ufo', dependencies = 'kevinhwang91/promise-async', config = function() local ufo = require('ufo') vim.keymap.set('n', 'zR', ufo.openAllFolds) vim.keymap.set('n', 'zR', ufo.closeAllFolds) ufo.setup {} end}, 'hrsh7th/vim-vsnip', -- LSP -- {'neovim/nvim-lspconfig', dependencies = {'hrsh7th/cmp-nvim-lsp', 'williamboman/mason-lspconfig.nvim'}, config = function() local lspconfig = require'lspconfig' -- Tweak the advertized LSP client capabilities local capabilities = require'cmp_nvim_lsp'.default_capabilities() -- Set options for nvim-ufo capabilities.textDocument.foldingRange = { dynamicRegistration = false, lineFoldingOnly = true, } -- Update the default for all servers lspconfig.util.default_config.capabilities = capabilities -- Set up language servers lspconfig.bashls.setup {} lspconfig.clangd.setup {} lspconfig.eslint.setup { autostart = false } lspconfig.lemminx.setup {} lspconfig.lua_ls.setup { settings = { Lua = { runtime = { version = 'LuaJIT', }, diagnostics = { globals = {'vim'}, }, workspace = { library = vim.api.nvim_get_runtime_file('', true), checkThirdParty = false, }, telemetry = { enable = false, }, } } } lspconfig.nil_ls.setup {} lspconfig.basedpyright.setup {} lspconfig.vimls.setup {} -- TODO decide what to do with autocmd end}, {'hrsh7th/nvim-cmp', dependencies = { 'rcarriga/cmp-dap', 'hrsh7th/cmp-nvim-lua', 'hrsh7th/cmp-nvim-lsp', 'hrsh7th/cmp-buffer', 'hrsh7th/cmp-path', 'hrsh7th/cmp-cmdline', 'dcampos/nvim-snippy', 'dcampos/cmp-snippy', 'LunarWatcher/auto-pairs' }, config = function() local cmp = require'cmp' local cmp_dap = require'cmp_dap' local snippy = require'snippy' vim.opt.completeopt:append({'menuone', 'noinsert', '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 cmp.setup { enabled = function() return vim.bo.buftype ~= 'prompt' or cmp_dap.is_dap_buffer() end, preselect = cmp.PreselectMode.None, snippet = { expand = function(args) require('snippy').expand_snippet(args.body) end, }, mapping = cmp.mapping.preset.insert { -- Next item, or expand or jump snippet, or fallback [''] = cmp.mapping( function(fallback) if cmp.visible() then cmp.select_next_item() elseif snippy.can_expand_or_advance() then snippy.expand_or_advance() elseif has_words_before() then cmp.complete() else fallback() end end, {'i', 's'} ), -- Prev item, or jump snippet back, or fallback [''] = cmp.mapping( function(fallback) if cmp.visible() then cmp.select_prev_item() elseif snippy.can_jump(-1) then snippy.previous() else fallback() end end, {'i', 's'} ), -- Scroll documentation up [''] = cmp.mapping(cmp.mapping.scroll_docs(4), {'i', 'c'}), -- Scroll documentation down [''] = cmp.mapping(cmp.mapping.scroll_docs(-4), {'i', 'c'}), -- Complete common substring [''] = cmp.mapping(cmp.mapping.complete_common_string(), {'i', 'c'}), -- Complete [''] = cmp.mapping(cmp.mapping.complete {}, {'i', 'c'}), -- Confirm [''] = cmp.mapping(cmp.mapping.confirm { select = false }, {'i', 'c'}), }, sources = { { name = 'path' }, { name = 'nvim_lsp' }, { name = 'nvim_lua' }, { name = 'snippy' }, }, -- Experimental features experimental = { -- Show completion result as virtual text ghost_text = true, }, } cmp.setup.cmdline(':', { mapping = cmp.mapping.preset.cmdline(), sources = cmp.config.sources({ { name = 'path' } }, { { name = 'cmdline', option = { ignore_cmds = { 'Man', '!' } } } }), }) cmp.setup.cmdline({'/', '?'}, { mapping = cmp.mapping.preset.cmdline(), sources = { { name = 'buffer' } }, }) cmp.setup.filetype({'dap-repl', 'dapui_watches', 'dapui_hover'}, { sources = { { name = 'dap' }, }, }) end}, {'mfussenegger/nvim-jdtls', dependencies = {'neovim/nvim-lspconfig'}, config = function() au('FileType', { pattern = 'java', callback = function() local jdtls = require 'jdtls' jdtls.tests = require'jdtls.tests' jdtls.dap = require'jdtls.dap' _G.jdt = jdtls local lspconfig = require'lspconfig' local root_dir = jdtls.setup.find_root({'.git', 'mvnw', 'gradlew'}) local config = { -- The command to launch jdtls with cmd = { 'jdtls', -- Enable logging '--jvm-arg=-Dlog.level=ALL', '--jvm-arg=-Dlog.protocol=true', -- Enable lombok '--jvm-arg=-javaagent:' .. mason_path('jdtls') .. '/lombok.jar', -- store workpace data in ~/.local/share/eclipse/ '-data', vim.fn.expand('~/.local/share/eclipse/') .. vim.fn.fnamemodify(root_dir, ':p:h:t') }, root_dir = root_dir, capabilities = lspconfig.util.default_config.capabilities, settings = { java = { autobuild = { enabled = false }, }, }, init_options = { -- JDTLS plugins bundles = (function() -- add java-debug-adapter local bundles = { vim.fn.glob(mason_path'java-debug-adapter' .. '/extension/server/com.microsoft.java.debug.plugin-*.jar', true) } -- add java-test vim.list_extend(bundles, vim.split( vim.fn.glob(vim.fn.expand('~/.local/share/vscode-java-test/server') .. '/*.jar', true), '\n' )) return bundles end)(), }, on_attach = function(client, bufnr) jdtls.setup_dap() end, } jdtls.start_or_attach(config) end }) end}, {'mrcjkb/rustaceanvim', config = function () vim.g.rustaceanvim = { server = { default_settings = { ['rust-analyzer'] = { cargo = { -- Load OUT_DIR when running check on save, needed for proc macros loadOutDirsFromCheck = true, }, checkOnSave = true, -- Error checking settings check = { -- Use clippy for error checking command = "clippy", -- Also run checks for tests allTargets = true, }, diagnostics = { -- Disable diagnostics with false positives disabled = {'unresolved-import'}, }, procMacro = { -- Enable proc macro support enable = true, }, rustfmt = { extraArgs = { '+nightly' } }, }, } }, } end}, {'Saecki/crates.nvim', opts = { lsp = { enabled = true, actions = true, completion = true, hover = true, } }}, {'pmizio/typescript-tools.nvim', opts = { settings = { tsserve_file_preferences = { quotePreference = 'single' }, tsserver_plugins = (function () if fn.has('nvim-0.10') == 0 then return end if vim.system({'npm', 'list', '-g', '@styled/typescript-styled-plugin'}):wait().code == 0 then return {'@styled/typescript-styled-plugin'} else return {} end end)() } }}, {'dmmulroy/ts-error-translator.nvim', opts = {}}, {'nvimtools/none-ls.nvim', dependencies = {'nvim-lua/plenary.nvim'}, config = function() local null_ls = require'null-ls' null_ls.setup { sources = { null_ls.builtins.diagnostics.zsh, } } end}, {'SmiteshP/nvim-navic', config = function() au('LspAttach', { callback = function(event) local client = vim.lsp.get_client_by_id(event.data.client_id) if not client then return end if client.server_capabilities.documentSymbolProvider then require'nvim-navic'.attach(client, event.buf) end end }) end}, {'utilyre/barbecue.nvim', opts = { show_modified = true, lead_custom_section = function() return { {' ', 'WinBar'} } end, }}, -- UI Elements -- {'vim-airline/vim-airline', dependencies = {'vim-airline/vim-airline-themes'}, init = function () -- Permit spaces after tabs but not in between when doing mixed indent checking -- (mainly for multiline /* */ style comments) vim.g['airline#extensions#whitespace#mixed_indent_algo'] = 2 -- truncate leading branch paths, i.e. agraven/foo → a/foo vim.g['airline#extensions#branch#format'] = 2 vim.g['airline#extensions#c_like_langs'] = {'typescript'} -- Hide encoding section vim.g['airline#extensions#default#layout'] = {{'a', 'b', 'c'}, {'x', 'z', 'warning', 'error'}} vim.g.airline_detect_spell = 1 -- Show if 'spell' is enabled vim.g.airline_detect_spelllang = 1 -- Display what language spell is using if enabled vim.g.airline_inactive_collapse = 1 -- Show only filename in inactive windows vim.g.airline_highlighting_cache = 1 -- Improves performance vim.g.airline_theme = 'ayu_mirage' -- Airline's theme vim.g.airline_powerline_fonts = 1 -- Enable symbols from the powerline font patch -- This doesn't work in lua for some reason vim.cmd [[ if !exists('g:airline_symbols') let g:airline_symbols = {} " Initialize the table of symbols endif let g:airline_symbols.linenr = ' ' " Symbol before line number let g:airline_symbols.maxlinenr = '' " Symbol after max line number let g:airline_symbols.colnr = ' ' " Symbol before column number let g:airline_symbols.dirty = '+' " Symbol on modified branch let g:airline_symbols.notexists = '?' " Symbol for untracked file ]] end}, {'romgrk/barbar.nvim', lazy = false, keys = { {'', 'BufferPrevious', { desc = 'Next buffer' }}, {'', 'BufferNext', { desc = 'Previous buffer' }}, {'', 'BufferPick', { desc = 'Pick buffer' }}, {'', 'BufferPin', { desc = 'Pin buffer' }}, {'', 'BufferClose', { desc = 'Delete buffer' }}, {'', 'BufferPickDelete', { desc = 'Delete picked buffer' }}, {'', 'BufferMovePrevious', { desc = 'Move buffer left' }}, {'>', 'BufferMoveNext', { desc = 'Move buffer right' }}, {'b,', 'BufferPrevious', { desc = 'Next buffer' }}, {'b.', 'BufferNext', { desc = 'Previous buffer' }}, {'bb', 'BufferPick', { desc = 'Pick buffer' }}, {'bp', 'BufferPin', { desc = 'Pin buffer' }}, {'bd', 'BufferClose', { desc = 'Delete buffer' }}, {'bx', 'BufferPickDelete', { desc = 'Delete picked buffer' }}, {'bh', 'BufferMovePrevious', { desc = 'Move buffer left' }}, {'bl', 'BufferMoveNext', { desc = 'Move buffer right' }}, }}, {'luckasRanarison/clear-action.nvim', config = function() require'clear-action'.setup { signs = { enable = true, -- Only show one symbol instead of several per category combine = true, -- Don't show the number of actions, show_count = false, -- Which icons to use for code action sings icons = { combined = '🛈', }, }, popup = { enable = true }, } au('LspAttach', { callback = function(event) local client = vim.lsp.get_client_by_id(event.data.client_id) local code_action if client and client.name ~= 'jdtls' then code_action = require'clear-action'.code_action else code_action = vim.lsp.buf.code_action end vim.keymap.set('n', 'ga', code_action, { buffer = event.buf, desc = 'Code action' }) vim.keymap.set('n', 'la', code_action, { buffer = event.buf, desc = 'Code action' }) end }) end}, {'MattesGroeger/vim-bookmarks', config = function() vim.g.bookmark_no_default_key_mappings = 1 vim.g.bookmark_save_per_working_dir = 1 end}, {'kristijanhusak/vim-dadbod-ui', dependencies = {'tpope/vim-dadbod', 'kristijanhusak/vim-dadbod-completion'}, config = function() vim.g.db_ui_use_nerd_fonts = 1 vim.g.db_ui_auto_execute_table_helpers = 1 vim.g.db_ui_win_position = 'right' vim.o.previewheight = 40 vim.api.nvim_create_autocmd('FileType', { group = 'luarc', pattern = {'sql','mysql','plsql'}, callback = function() require('cmp').setup.buffer({ sources = {{ name = 'vim-dadbod-completion' }} }) end, desc = 'SQL dadbod completion', }) end}, {'mfussenegger/nvim-dap', dependencies = {'folke/which-key.nvim'}, config = function() local dap = require'dap' vim.fn.sign_define('DapBreakpoint', {text = '⯃', texthl = 'DiagnosticError'}) dap.adapters.codelldb = { type = 'server', port = '${port}', executable = { --command = mason_path('codelldb') .. '/extension/adapter/codelldb', --args = {'--liblldb', mason_path('codelldb') .. '/extension/lldb/lib/liblldb.so', '--port', '${port}'}, command = 'codelldb', args = {'--port', '${port}'}, }, } dap.adapters.sh = { type = 'executable', command = mason_path('bash-debug-adapter') .. '/bash-debug-adapter' } dap.adapters['pwa-node'] = { type = 'server', host = 'localhost', port = '${port}', executable = { command = 'node', args = { mason_path('js-debug-adapter') .. '/js-debug/src/dapDebugServer.js', '${port}' }, }, } dap.configurations.cpp = { { name = 'Launch file', type = 'codelldb', request = 'launch', program = function() return vim.fn.input('Path to executable: ', vim.fn.getcwd() .. '/', 'file') end, cwd = '${workspaceFolder}', stopOnEntry = true, }, } dap.configurations.rust = dap.configurations.cpp dap.configurations.c = dap.configurations.cpp dap.configurations.sh = { { name = 'Bash debugger', type = 'sh', request = 'launch', program = '${file}', cwd = '${fileDirname}', pathBashdb = mason_path('bash-debug-adapter') .. '/extension/bashdb_dir/bashdb', pathBashdbLib = mason_path('bash-debug-adapter') .. '/extension/bashdb_dir', pathBash = 'bash', pathCat = 'cat', pathMkfifo = 'mkfifo', pathPkill = 'pkill', env = {}, args = function() return vim.fn.split(vim.fn.input('Arguments: ', '', 'file')) end, }, } dap.configurations.javascript = { { type = 'pwa-node', request = 'launch', name = 'Launch current file', program = '${file}', cwd = '${workspaceFolder}', }, { type = 'pwa-node', request = 'launch', name = 'Launch file', program = function() return vim.fn.input('Path to file: ', vim.fn.getcwd() .. '/', 'file') end, cwd = '${workspaceFolder}', }, { type = 'pwa-node', request = 'attach', name = 'Attach', processId = require'dap.utils'.pick_process, cwd = '${workspaceFolder}', }, { type = 'pwa-node', request = 'launch', name = 'Debug Mocha Tests', -- trace = true, -- include debugger info runtimeExecutable = 'node', runtimeArgs = { './node_modules/mocha/bin/mocha', }, rootPath = '${workspaceFolder}', cwd = '${workspaceFolder}', console = 'integratedTerminal', internalConsoleOptions = 'neverOpen', } } dap.configurations.typescript = dap.configurations.javascript local function conditional_breakpoint() vim.ui.input({prompt = 'Breakpoint condition'}, function(condition) if not condition then return end dap.toggle_breakpoint(condition) end) end require'which-key'.register { ['d'] = { name = 'Debug', c = {dap.continue, 'Continue/start'}, s = {dap.terminate, 'Stop'}, b = {dap.toggle_breakpoint, 'Breakpoint'}, B = {conditional_breakpoint, 'Conditional breakpoint'}, e = {function() dap.set_exception_breakpoints('default') end, 'Exception breakpoints'}, o = {dap.step_over, 'Step over'}, i = {dap.step_into, 'Step into'}, O = {dap.step_out, 'Step out'}, r = {dap.step_back, 'Step back'}, R = {dap.reverse_continue, 'Continue backwards'}, C = {dap.run_to_cursor, 'Continue to cursor'}, p = {dap.pause, 'Pause execution'} } } end}, {'rcarriga/nvim-dap-ui', dependencies = { 'mfussenegger/nvim-dap', 'nvim-neotest/nvim-nio' }, config = function() local dapui, dap = require'dapui', require'dap' dapui.setup() -- Hooks for opening the debugger ui automatically 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 require'which-key'.register { ['dd'] = {dapui.toggle, 'Toggle'} } end}, {'theHamsta/nvim-dap-virtual-text', dependencies = {'mfussenegger/nvim-dap'}, opts = { -- Clear virtual text when the debugger does a continue clear_on_continue = true, }}, {'LiadOz/nvim-dap-repl-highlights', opts = {}}, {'sindrets/diffview.nvim', opts = { -- Use nicer highlighting for diffs enhanced_diff_hl = true, }}, {'stevearc/dressing.nvim', opts = { input = { insert_only = false, win_options = { -- Reuse telescope's highlights for windows made by dressing winhighlight = 'NormalFloat:TelescopeNormal,FloatBorder:TelescopeBorder' } }, select = { enabled = false, }, }, config = function(_, opts) vim.cmd'highlight link FloatTitle TelescopeBorder' require'dressing'.setup(opts) end}, {'j-hui/fidget.nvim', dependencies = {'kyazdani42/nvim-tree.lua', lazy = false}, opts = { progress = { lsp = { -- Workaround for rust-analyzer messages getting stuck progress_ringbuf_size = 2048, } }, integration = { -- Disable nvim-tree integration, has bugs when restoring sessions ["nvim-tree"] = { enable = false, } } }}, {'tpope/vim-fugitive', lazy = false, dependencies = {'tpope/vim-rhubarb', 'shumphrey/fugitive-gitlab.vim'}, keys = { {'g', 'vert Git', desc = 'Git status'}, {'G', 'tab Git', desc = 'Git status (tab)'}, }}, {'harrisoncramer/gitlab.nvim', dependencies = { 'MunifTanjim/nui.nvim', 'nvim-lua/plenary.nvim', 'sindrets/diffview.nvim', }, build = function() require'gitlab.server'.build(true) end, opts = { attachment_dir = vim.fn.expand('~/Downloads/'), popup = { temp_registers = {"p"} }, discussion_tree = { position = 'bottom', }, }, config = function(plugin, opts) local gitlab = require('gitlab') gitlab.setup(opts) require'which-key'.register { ['a'] = { name = '+gitlab', o = {gitlab.review, 'Review'}, s = {gitlab.summary, 'Summary'}, a = {gitlab.add_assignee, 'Add assignee'}, r = {gitlab.add_reviewer, 'Add reviewer'}, A = {gitlab.approve, 'Approve'}, c = {gitlab.create_comment, 'Comment'}, n = {gitlab.create_note, 'Note'}, m = {gitlab.create_mr, 'Create MR'}, x = {gitlab.open_in_browser, 'Open in browser'}, p = {gitlab.pipeline, 'Pipeline'}, q = {gitlab.close_review, 'Close review'}, } } require'which-key'.register({ ['a'] = { c = {gitlab.create_multiline_comment, 'Multiline comment'}, C = {gitlab.create_comment_suggestion, 'Suggestion'}, } }, { mode = "v" }) end}, {'lewis6991/gitsigns.nvim', dependencies = {'folke/which-key.nvim'}, opts = { on_attach = function() local gitsigns = require'gitsigns' vim.keymap.set('n', ']c', gitsigns.next_hunk, {desc = 'Next hunk'}) vim.keymap.set('n', '[c', gitsigns.prev_hunk, {desc = 'Previous hunk'}) require'which-key'.register { ['h'] = { name = '+gitsigns', s = {gitsigns.stage_hunk, 'Stage hunk'}, S = {gitsigns.stage_buffer, 'Stage buffer'}, u = {gitsigns.unstage_hunk, 'Unstage hunk'}, U = {gitsigns.unstage_buffer, 'Unstage buffer'}, r = {gitsigns.reset_hunk, 'Reset hunk'}, v = {gitsigns.select_hunk, 'Visual select hunk'}, d = {gitsigns.toggle_deleted, 'Toggle deleted lines'}, w = {gitsigns.toggle_word_diff, 'Toggle word diffs'}, l = {gitsigns.blame_line, 'Blame current line'}, L = {gitsigns.toggle_current_line_blame, 'Toggle line blame'}, b = {':Gitsigns change_base ', 'Change diff base'}, B = {gitsigns.reset_base, 'Reset diff base'}, p = {gitsigns.preview_hunk_inline, 'Preview hunk'}, P = {gitsigns.preview_hunk, 'Preview hunk popup'}, } } end }}, {'junegunn/goyo.vim', config = function() vim.g.goyo_height = '95%' end}, {url = 'https://git.sr.ht/~whynothugo/lsp_lines.nvim', config = function() require'lsp_lines'.setup() vim.diagnostic.config { virtual_text = { severity = { min = vim.diagnostic.severity.WARN }, }, virtual_lines = { only_current_line = true, } } end}, {'williamboman/mason.nvim', opts = {}}, {'williamboman/mason-lspconfig.nvim', dependencies = {'williamboman/mason.nvim'}, opts = { automatic_installation = true }}, {'NeogitOrg/neogit', lazy = false, opts = { disable_context_highlighting = true, integrations = { diffview = true, }, signs = { item = {"", ""}, section = {"", ""}, }, }, keys = { {'', 'Neogit', { desc = 'Neogit' }} }}, {'rcarriga/nvim-notify', dependencies = {'nvim-telescope/telescope.nvim'}, opts = { stages = 'fade' }, config = function(_, opts) require'notify'.setup(opts) vim.notify = require'notify' require'telescope'.load_extension('notify') end}, {'stevearc/overseer.nvim', dependencies = {'folke/which-key.nvim'}, config = function(plugin, opts) require'overseer'.setup(opts) require'which-key'.register { ['r'] = { name = 'Overseer (run tasks)', r = {'OverseerToggle bottom', 'Open' }, R = {'OverseerToggle right', 'Open (right)' }, n = {'OverseerRun', 'New task' }, c = {'OverseerRunCmd', 'Run shell command' }, l = {'OverseerLoadBundle!', 'Load task list'}, L = {'OverseerLoadBundle', 'Load and start task list'}, s = {'OverseerSaveBundle', 'Save task list'} } } end}, {'mhinz/vim-startify', init = function() -- Don't change working directory when opening files g.startify_change_to_dir = 0 -- Change working dir to version control root when opening file g.startify_change_to_vcs_root = 1 -- Enable unicode box drawing in fortune message g.startify_fortune_use_unicode = 1 -- Items to show on the startup screen g.startify_lists = { { type = 'dir', header = {' Recently used ' .. fn.getcwd()} }, { type = 'files', header = {' Recently used'} }, { type = 'sessions', header = {' Sessions'} }, { type = 'bookmarks', header = {' Bookmarks'} }, { type = 'commands', header = {' Commands'} }, } g.startify_bookmarks = { { c = '~/.config/nvim/init.lua' }, } g.startify_commands = { { L = {'Lazy - plugin manager', 'Lazy'} }, { M = {'Mason - tool manager', 'Mason'} }, } end}, {'nvim-telescope/telescope.nvim', dependencies = { 'nvim-telescope/telescope-fzf-native.nvim', 'nvim-telescope/telescope-file-browser.nvim', 'nvim-telescope/telescope-project.nvim', 'nvim-telescope/telescope-ui-select.nvim', 'nvim-telescope/telescope-dap.nvim', 'debugloop/telescope-undo.nvim', 'folke/which-key.nvim', }, config = function() local ok, telescope = pcall(require, 'telescope') if not ok then return end telescope.builtin = require'telescope.builtin' --telescope.themes = require'telescope.themes' telescope.setup { defaults = { sorting_strategy = 'ascending', mappings = { n = { n = 'move_selection_next', e = 'move_selection_previous', }, i = { [''] = 'which_key', }, }, }, extensions = { fzf = { override_generic_sorter = true, override_file_sorter = true, }, file_browser = { hijack_netrw = false, respect_gitignore = false, }, project = { -- TODO; check if this is right full_path = true, }, ['ui-select'] = require'telescope.themes'.get_cursor { layout_config = { height = 15, }, }, }, } require'which-key'.register { ["f"] = { name = 'Telescope', [""] = {'Telescope', 'List pickers'}, f = {'Telescope find_files', 'Files'}, F = {'Telescope file_browser', 'File browser'}, [''] = { function() vim.ui.input( { completion = 'dir' }, function(input) telescope.builtin.find_files { search_dirs = {input} } end ) end, 'Files in subdirectory' }, d = {'Telescope find_files find_command=fd,--type,d,-I', 'Directories'}, r = {'Telescope oldfiles', 'Recent files'}, g = {'Telescope live_grep', 'Grep'}, G = {function() vim.ui.input({ completion = 'dir' }, function(input) if not input then return end telescope.builtin.live_grep { search_dirs = {input} } end) end, 'Grep in subdirectory'}, b = {'Telescope buffers', 'Buffers'}, e = {'Telescope diagnostics', 'Diagnostics'}, h = {'Telescope help_tags', 'Help page'}, o = {'Telescope options', 'Options'}, p = {'Telescope project', 'Projects'}, s = {'Telescope lsp_dynamic_workspace_symbols', 'Symbols'}, S = {'Telescope lsp_document_symbols', 'Symbols - current file'}, n = {'Telescope notify', 'Notifications'}, m = {'Telescope man_pages sections=ALL', 'Man pages'}, [':'] = {'Telescope commands', 'Commands'}, u = {'Telescope undo', 'Undo'}, ['.'] = {'Telescope resume', 'Resume'}, } } require'telescope'.load_extension('fzf') require'telescope'.load_extension('file_browser') require'telescope'.load_extension('project') require'telescope'.load_extension('ui-select') require'telescope'.load_extension('dap') require'telescope'.load_extension('undo') end}, {'nvim-neotest/neotest', dependencies = { 'nvim-neotest/neotest-vim-test', 'rouge8/neotest-rust', }, config = function() require'neotest'.setup { adapters = { require'neotest-vim-test' { allow_file_types = {'java'} }, require'neotest-rust' {}, } } require'which-key'.register { ['x'] = { name = 'Test', s = {'Neotest summary','Summary'}, a = {'Neotest attach', 'Attach to running test'}, k = {'Neotest stop', 'Stop'}, o = {'Neotest output-panel', 'Output'} } } end}, {'kyazdani42/nvim-tree.lua', opts = { actions = { open_file = { window_picker = { exclude = { filetype = {'Outline', 'qf'}, }, } }, }, -- Don't disable netrw disable_netrw = false, -- Show LSP diagnostics in the sign column diagnostics = { enable = true, icons = { hint = "", }, }, git = { -- Don't hide .gitignore'd files by default ignore = false, -- Extend timeout timeout = 5000, }, -- Reload the tree when its window is focused reload_on_bufenter = true, -- Appeareance settings renderer = { -- highlight git status (unstaged, staged, clean) highlight_git = true, -- Highlight open files highlight_opened_files = 'name', -- Don't hightlight files as spceial special_files = {}, -- Combine nested folders with only one child group_empty = true, -- Icon settings icons = { -- Hide git attribute icons show = { git = false, folder = true, file = true, folder_arrow = true, }, -- Change icons glyphs = { -- Set a default icon so entries are aligned default = '🗋' }, }, }, -- Match tree cwd to vim's cwd update_cwd = true, view = { width = 45, }, }, config = function(plugin, opts) require'nvim-tree'.setup(opts) -- Handle restoring sessions with nvim-tree windows properly au('BufEnter', { pattern = 'NvimTree*', callback = function() local api = require('nvim-tree.api') local view = require('nvim-tree.view') if not view.is_visible() then api.tree.open() end end, }) vim.cmd'highlight NvimTreeOpenedFile guifg=NONE guibg=NONE gui=italic' vim.keymap.set('n', 't', 'NvimTreeFindFile', {desc = 'Nvim Tree'}) end}, {'hedyhli/outline.nvim', opts = { outline_window = { -- Use absolute number of columns instead of percentage for sizing relative_width = false, -- Window should be 30 columns wide width = 30, }, }, keys = { {'o', 'Outline', desc = 'Symbols outline'} }}, {'folke/which-key.nvim', opts = {}, config = function (plugin, opts) require'which-key'.setup(opts) require'which-key'.register { ['q'] = { name = 'Quickfix' }, ['l'] = { name = 'LSP' }, ['b'] = { name = 'Buffer' }, ['e'] = { name = 'Diagnostic' }, } end}, -- Utilities {'ryanoasis/vim-devicons', dependencies = {'mhinz/vim-startify'}}, {'kyazdani42/nvim-web-devicons', opts = { default = true }}, {'ellisonleao/dotenv.nvim', opts = { enable_on_load = false, verbose = true, }} }) vim.cmd 'colorscheme tokyonight-night'