" Plugins " ============================================================================== call plug#begin(stdpath('config') . '/plugged') " nerdtree provides a file tree explorer " vim-dispatch allows running async jobs in vim (i.e. builds in the background) Plug 'https://github.com/scrooloose/nerdtree', { 'on': 'NERDTreeToggle' } Plug 'https://github.com/tpope/vim-dispatch' Plug 'https://github.com/tpope/vim-fugitive' " TODO: 2022-06-19 Treesitter is too slow on large C++ files " Plug 'https://github.com/nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'} Plug 'https://github.com/bfrg/vim-cpp-modern' " Telescope file picker, sorter and previewer Plug 'https://github.com/nvim-lua/plenary.nvim' Plug 'https://github.com/nvim-telescope/telescope.nvim' Plug 'nvim-telescope/telescope-fzf-native.nvim', { 'do': 'cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release && cmake --build build --config Release && cmake --install build --prefix build' } " nvim-lspconfig sets up sane defaults for LSP servers (i.e. clangd) " nvim-cmp is a more powerful autocomplete engine " LuaSnip allow writing snippets into the buffer, we can power the snippets from LSP " cmp-nvim-lsp preset capability flags to request more powerful autocomplete from LSP server " cmp_luasnip a LuaSnip addon that provides a completion source to nvim-cmp " cmp-buffer provides a buffer completion source to nvim-cmp " cmp-path provides a path completion source to nvim-cmp Plug 'https://github.com/neovim/nvim-lspconfig' Plug 'https://github.com/hrsh7th/nvim-cmp' Plug 'https://github.com/L3MON4D3/LuaSnip' Plug 'https://github.com/hrsh7th/cmp-nvim-lsp' Plug 'https://github.com/saadparwaiz1/cmp_luasnip' Plug 'https://github.com/hrsh7th/cmp-buffer' Plug 'https://github.com/hrsh7th/cmp-path' " odin for syntax highlighting Plug 'https://github.com/Tetralux/odin.vim' Plug 'https://github.com/sainnhe/gruvbox-material' " Lua cache to speed up load times Plug 'https://github.com/lewis6991/impatient.nvim' call plug#end() " Lua Setup " ============================================================================== lua <"] = require('telescope.actions').move_selection_next, [""] = require('telescope.actions').move_selection_previous, }, n = { [""] = require('telescope.actions').move_selection_next, [""] = require('telescope.actions').move_selection_previous, }, }, }, pickers = { find_files = { find_command = { "fd", "--unrestricted", "--strip-cwd-prefix" } }, } } -- Vim Options -- =========================================================================== vim.opt.autowrite=true -- Automatically save before cmds like :next and :prev vim.opt.colorcolumn={80, 100} -- Set a 80 and 100 char column ruler vim.opt.completeopt={'menu', 'menuone', 'noselect'} vim.opt.cpoptions:append('$') -- $ as end marker for the change operator vim.opt.cursorline=true -- Highlight current line vim.opt.expandtab=true -- Replace tabs with spaces vim.opt.guifont={'JetBrains_Mono:h9', 'Consolas:h9', 'InputMonoCondensed:h9'} vim.opt.hlsearch=false -- Highlight just the first match on search vim.opt.ignorecase=true -- Search is not case sensitive vim.opt.linebreak=true -- On wrapped lines, break on the wrapping word intelligently vim.opt.list=true -- Show the 'listchar' characters on trailing spaces, tabs e.t.c vim.opt.listchars:append('tab:>-,trail:■,extends:»,precedes:«') vim.opt.number=true -- Show line numbers vim.opt.relativenumber=true -- Show relative line numbers vim.opt.shiftwidth=4 -- Number of spaces for each autoindent step vim.opt.splitright=true -- Open new splits to the right of the current one vim.opt.swapfile=false -- Disable swapfile (stores the things changed in a file) vim.opt.textwidth=80 -- On format, format to 80 char long lines vim.opt.visualbell=true -- Flash the screen on error vim.opt.wrap=false -- Don't wrap lines of text automatically vim.diagnostic.config({ -- Turn off the diagnostics signs on the line number. In LSP mode, editing -- a C++ buffer constantly toggles the sign column on and off as you change -- modes which is very visually distracting. signs = false, }) -- Check if there were args (i.e. opened file), non-empty buffer, or started in insert mode if vim.fn.argc() == 0 or vim.fn.line2byte("$") ~= -1 and not opt.insertmode then local ascii = { "", " Useful Bindings (Normal Mode)", " --------------------------------------------------", " to open the file tree explorer", " clang format selected lines", " jump to next compilation error", " jump to prev compilation error", " change working directory to current file", " <\\s> split buffer vertically", " ", " Telescope Bindings (Normal Mode)", " --------------------------------------------------", " <\\te> open telescope menu", " <\\ta> search for symbol via tags", " <\\f> search for file", " <\\g> search for text", " <\\b> search for buffer", " <\\h> search VIM help menu", " ", " LSP Bindings (Normal Mode)", " --------------------------------------------------", " on (applicable) symbol, jump to declaration", " on (applicable) symbol, jump to definition", " on (applicable) symbol, jump to type definition", " on (applicable) symbol, show caller references", " on (applicable) symbol, search available symbols", " on (applicable) symbol, show code-actions prompt", " on (applicable) symbol, code-aware symbol rename", " on (applicable) symbol, show signature help", " on (applicable) symbol, show documentation", " on red underlined symbol error, show error message", " jump to next LSP error", " jump to prev LSP error", } local height = vim.api.nvim_get_option("lines") local width = vim.api.nvim_get_option("columns") local ascii_rows = #ascii local ascii_cols = #ascii[1] local win = vim.api.nvim_get_current_win() local buf = vim.api.nvim_create_buf(true, true) local function reset_start_screen() vim.cmd("enew") local buf = vim.api.nvim_get_current_buf() local win = vim.api.nvim_get_current_win() vim.api.nvim_buf_set_option(buf, "modifiable", true) vim.api.nvim_buf_set_option(buf, "buflisted", true) vim.api.nvim_buf_set_option(buf, "buflisted", true) vim.api.nvim_win_set_option(win, "colorcolumn", "80,100") vim.api.nvim_win_set_option(win, "relativenumber", true) vim.api.nvim_win_set_option(win, "number", true) vim.api.nvim_win_set_option(win, "list", true) end -- Only display if there is enough space if height >= ascii_rows and width >= ascii_cols then vim.api.nvim_buf_set_lines(buf, 0, -1, false, ascii) vim.api.nvim_buf_set_option(buf, "modified", false) vim.api.nvim_buf_set_option(buf, "buflisted", false) vim.api.nvim_buf_set_option(buf, "bufhidden", "wipe") vim.api.nvim_buf_set_option(buf, "buftype", "nofile") vim.api.nvim_buf_set_option(buf, "swapfile", false) vim.api.nvim_win_set_option(win, "colorcolumn", "") vim.api.nvim_win_set_option(win, "relativenumber", false) vim.api.nvim_win_set_option(win, "number", false) vim.api.nvim_win_set_option(win, "list", false) vim.api.nvim_set_current_buf(buf) vim.api.nvim_create_autocmd("InsertEnter,WinEnter", { pattern = "", callback = reset_start_screen, }) end end -- LSP Setup -- =========================================================================== -- Load the additional capabilities supported by nvim-cmp local custom_capabilities = require('cmp_nvim_lsp').update_capabilities(vim.lsp.protocol.make_client_capabilities()) -- Use an on_attach function to only map the following keys -- after the language server attaches to the current buffer local custom_on_attach = function(client, bufnr) -- Enable completion triggered by vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc') -- See `:help vim.diagnostic.*` for documentation on any of the below functions local opts = { noremap=true, silent=true } vim.keymap.set('n', 'e', vim.diagnostic.open_float, opts) vim.keymap.set('n', '', vim.diagnostic.goto_next, opts) vim.keymap.set('n', '', vim.diagnostic.goto_prev, opts) -- See `:help vim.lsp.*` for documentation on any of the below functions local bufopts = { noremap=true, silent=true, buffer=bufnr } vim.keymap.set('n', 'K', vim.lsp.buf.hover, bufopts) vim.keymap.set('n', 'gD', vim.lsp.buf.declaration, bufopts) vim.keymap.set('n', 'gs', vim.lsp.buf.signature_help, bufopts) vim.keymap.set('n', 'ga', vim.lsp.buf.code_action, bufopts) vim.keymap.set('n', 'gR', vim.lsp.buf.rename, bufopts) end -- Request additional completion capabilities from the LSP server(s) local lspconfig = require('lspconfig') -- Clangd LSP Setup -- =========================================================================== lspconfig.clangd.setup { on_attach = custom_on_attach, capabilities = custom_capabilities, single_file_support = false, --- Don't launch LSP if the directory does not have LSP metadata } lspconfig.cmake.setup { on_attach = custom_on_attach, capabilities = custom_capabilities, } -- Autocomplete Setup -- =========================================================================== local luasnip = require 'luasnip' local cmp = require 'cmp' local has_words_before = function() 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 { snippet = { expand = function(args) luasnip.lsp_expand(args.body) end, }, window = { completion = cmp.config.window.bordered(), documentation = cmp.config.window.bordered(), }, completion = { autocomplete = false }, mapping = cmp.mapping.preset.insert({ [''] = cmp.mapping.scroll_docs(4), [''] = cmp.mapping.scroll_docs(-4), [''] = cmp.mapping.scroll_docs(-1), -- Scroll the docs up by 1 line [''] = cmp.mapping.scroll_docs(1), -- Scroll the docs down by 1 line [''] = cmp.mapping.confirm { behavior = cmp.ConfirmBehavior.Replace, select = true, }, [''] = cmp.mapping(function(fallback) -- Move down the autocomplete list if cmp.visible() then cmp.select_next_item() elseif 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(fallback) -- Move up the autocomplete list if cmp.visible() then cmp.select_prev_item() elseif luasnip.jumpable(-1) then luasnip.jump(-1) else fallback() end end, { 'i', 's' }), }), sources = { { name = 'nvim_lsp' }, { name = 'luasnip' }, { name = 'buffer' }, }, } -- TODO: 2022-06-19 Treesitter is too slow on large C++ files -- require('nvim-treesitter.configs').setup { -- ensure_installed = { "c", "cpp" }, -- A list of parser names, or "all" -- sync_install = false, -- Install parsers synchronously (only applied to `ensure_installed`) -- ignore_install = { }, -- List of parsers to ignore installing (for "all") -- highlight = { -- enable = false, -- `false` will disable the whole extension -- -- NOTE: these are the names of the parsers and not the filetype. (for example if you want to -- -- disable highlighting for the `tex` filetype, you need to include `latex` in this list as this is -- -- the name of the parser) -- -- list of language that will be disabled -- disable = { }, -- -- Setting this to true will run `:h syntax` and tree-sitter at the same time. -- -- Set this to `true` if you depend on 'syntax' being enabled (like for indentation). -- -- Using this option may slow down your editor, and you may see some duplicate highlights. -- -- Instead of true it can also be a list of languages -- additional_vim_regex_highlighting = false, -- }, -- } EOF " Theme " ============================================================================== let g:gruvbox_material_background='hard' let g:gruvbox_material_foreground='mix' let g:gruvbox_material_disable_italic_comment=1 let g:gruvbox_material_enable_italic=0 let g:gruvbox_material_enable_bold=0 let g:gruvbox_material_diagnostic_virtual_text='colored' let g:gruvbox_material_better_performance=1 colorscheme gruvbox-material " Vim-cpp-modern customisation " Disable function highlighting (affects both C and C++ files) let g:cpp_function_highlight = 1 " Enable highlighting of C++11 attributes let g:cpp_attributes_highlight = 1 " Highlight struct/class member variables (affects both C and C++ files) let g:cpp_member_highlight = 0 " Put all standard C and C++ keywords under Vim's highlight group 'Statement' " (affects both C and C++ files) let g:cpp_simple_highlight = 1 " Options " ============================================================================== " Show EOL type and last modified timestamp, right after the filename set statusline=%<%F%h%m%r\ [%{&ff}]\ (%{strftime(\"%H:%M\ %d/%m/%Y\",getftime(expand(\"%:p\")))})%=%l,%c%V\ %P " Resize splits when the window is resized au VimResized * :wincmd = " File patterns to ignore in command line auto complete set wildignore+=*.class,*.o set wildignore+=*\\tmp\\*,*.swp,*.zip,*.exe,*.obj,*.vcxproj,*.pdb,*.idb " Setup undo file set undofile let &undodir=stdpath('config') . '/undo' " Setup backup directory let &backupdir=stdpath('config') . '/backup' " Enable mouse support if has('mouse') set mouse=a endif " Functions " ============================================================================== " Increase font size using (Ctrl+Up Arrow) or (Ctrl+Down Arrow) if we are using " gvim Otherwise font size is determined in terminal nnoremap :silent! let &guifont = substitute( \ &guifont, \ ':h\zs\d\+', \ '\=eval(submatch(0)+1)', \ 'g') nnoremap :silent! let &guifont = substitute( \ &guifont, \ ':h\zs\d\+', \ '\=eval(submatch(0)-1)', \ 'g') " Formatting options (see :h fo-table) augroup persistent_settings au! au bufenter * :set formatoptions=q1j augroup end " General Key Bindings " ============================================================================== " Telescope Bindings nnoremap f Telescope find_files nnoremap g Telescope live_grep nnoremap ta Telescope tags nnoremap te Telescope nnoremap b Telescope buffers nnoremap h Telescope help_tags nnoremap gf Telescope lsp_dynamic_workspace_symbols nnoremap gd Telescope lsp_definitions nnoremap gt Telescope lsp_type_definitions nnoremap gr Telescope lsp_references " Map Ctrl+HJKL to navigate buffer window nmap :wincmd h nmap :wincmd j nmap :wincmd k nmap :wincmd l " Move by wrapped lines instead of line numbers nnoremap j gj nnoremap k gk nnoremap gj j nnoremap gk k " Map NERDTree to Ctrl-N map :NERDTreeToggle " Change to current buffer's directory nmap cd :cd =expand("%:p:h") " Buffer Splitting nnoremap s :vs " Go to next error " Go to previous error nnoremap :cn nnoremap :cp " FZF " ============================================================================== " Empty value to disable preview window altogether let g:fzf_preview_window = [] " Prefix all commands with Fzf for discoverability let g:fzf_command_prefix = 'Fzf' " - down / up / left / right let g:fzf_layout = { 'down': '40%' } " Clang Format " ============================================================================== map :py3file ~/clang-format.py " Compiler Error Formats " ============================================================================== " Error message formats thanks to " https://forums.handmadehero.org/index.php/forum?view=topic&catid=4&id=704#3982 set errorformat+=\\\ %#%f(%l\\\,%c):\ %m " MSVC: MSBuild set errorformat+=\\\ %#%f(%l)\ :\ %#%t%[A-z]%#\ %m " MSVC: cl.exe set errorformat+=\\\ %#%t%nxx:\ %m " MSVC: cl.exe, fatal errors is crudely implemented set errorformat+=\\\ %#LINK\ :\ %m " MSVC: link.exe, can't find link library badly implemented set errorformat+=\\\ %#%s\ :\ error\ %m " MSVC: link.exe, errors is badly implemented set errorformat+=\\\ %#%s\ :\ fatal\ error\ %m " MSVC: link.exe, fatal errors is badly implemented set errorformat+=\\\ %#%f(%l\\\,%c-%*[0-9]):\ %#%t%[A-z]%#\ %m " MSVC: HLSL fxc.exe set errorformat+=%\\%%(CTIME%\\)%\\@=%m " ctime.exe -stats " Vim Dispatch " ============================================================================== let s:running_windows = has("win16") || has("win32") || has("win64") if s:running_windows set makeprg=build nnoremap :Make ./build.bat else " Set vim terminal to enter normal mode using escape like normal vim behaviour tnoremap nnoremap :Make ./build.sh set makeprg=./build.sh endif