Last active
September 3, 2026 16:01
-
-
Save WillSams/21429927c030c9870a7d723c62e5cb8a to your computer and use it in GitHub Desktop.
Vim for Storm! Engine Dev
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| " <leader> is the space bar. This MUST come before any <leader> mapping: the | |
| " leader is expanded when a mapping is defined, not when it is pressed, so | |
| " setting it further down would silently leave earlier mappings on backslash. | |
| let mapleader = " " | |
| let maplocalleader = " " | |
| " Space's normal job is 'move right one character', which l already does. | |
| nnoremap <Space> <Nop> | |
| filetype off | |
| runtime! plugin/sensible.vim | |
| if has('mouse') | |
| set mouse=a | |
| endif | |
| set expandtab | |
| set nocompatible | |
| set tabstop=2 " Set tab width to 2 columns | |
| set shiftwidth=2 " Use 2 columns for indentation | |
| set expandtab " Use spaces when pressing <tab> key | |
| set number | |
| " complete-=t removed: it switched off tag completion, which is the fallback | |
| " when clangd is not running. complete-=i stays -- scanning included files on | |
| " every keystroke is slow and clangd does that job properly. | |
| set complete-=i | |
| set completeopt=menuone,popup,noinsert,noselect | |
| set signcolumn=yes " stop the gutter jittering as diagnostics arrive | |
| set updatetime=300 | |
| call plug#begin('~/.vim/plugged') | |
| Plug 'tpope/vim-sensible' | |
| Plug 'sheerun/vim-polyglot' | |
| Plug 'https://github.com/preservim/nerdtree' | |
| Plug 'ryanoasis/vim-devicons' | |
| Plug 'Xuyuanp/nerdtree-git-plugin' | |
| Plug 'tpope/vim-surround' | |
| Plug 'w0rp/ale' | |
| Plug 'tpope/vim-fugitive' | |
| Plug 'ap/vim-css-color' "color previews for css | |
| Plug 'lambdalisue/battery.vim' | |
| Plug 'airblade/vim-gitgutter' | |
| Plug 'vim-airline/vim-airline' | |
| Plug 'vim-airline/vim-airline-themes' | |
| Plug 'editorconfig/editorconfig-vim' | |
| Plug 'junegunn/fzf', { 'do': { -> fzf#install() } } | |
| Plug 'junegunn/fzf.vim' ":Files :Rg :Buffers :Tags | |
| Plug 'tiagofumo/vim-nerdtree-syntax-highlight' | |
| Plug 'voldikss/vim-floaterm' | |
| Plug 'majutsushi/tagbar' | |
| Plug 'scrooloose/nerdcommenter' | |
| Plug 'yegappan/lsp' "C/C++ completion via clangd | |
| call plug#end() | |
| filetype plugin indent on | |
| map <F1> :Git<CR> | |
| map <F2> :NERDTreeToggle<CR> | |
| let NERDTreeShowHidden=1 | |
| " Open the tree automatically, but leave the cursor in the file -- opening into | |
| " the tree means every session starts with an extra keystroke to get out of it. | |
| " | |
| " Three cases are deliberately excluded: | |
| " `vim .` NERDTree already replaces netrw, so opening it again splits | |
| " `vim -` reading from stdin | |
| " git, etc. a commit message buffer does not want a file tree | |
| augroup NerdTreeAuto | |
| autocmd! | |
| autocmd StdinReadPre * let s:std_in = 1 | |
| autocmd VimEnter * | |
| \ if !exists('s:std_in') && &filetype !=# 'gitcommit' | |
| \ && (argc() == 0 || (argc() == 1 && !isdirectory(argv()[0]))) | |
| \ | NERDTree | wincmd p | endif | |
| " Do not leave a lone file tree behind when the last real buffer closes. | |
| autocmd BufEnter * | |
| \ if winnr('$') == 1 && exists('b:NERDTree') && b:NERDTree.isTabTree() | |
| \ | quit | endif | |
| augroup END | |
| map <F3> :FloatermNew /usr/bin/bash<CR> | |
| nmap <F4> <Plug>(ale_fix) | |
| let g:ale_lint_on_save = 1 | |
| let g:ale_fix_on_save = 1 | |
| let g:ale_sign_error = '✖' | |
| let g:ale_sign_warning = '⚠' | |
| let g:ale_echo_msg_error_str = 'E' | |
| let g:ale_echo_msg_warning_str = 'W' | |
| let g:ale_echo_msg_format = '[%linter%] %s [%severity%]' | |
| let g:ale_statusline_format =[' %d E ', ' %d W ', ''] | |
| let g:ale_linters = {'javascript': ['eslint'], 'typescript':['eslint'],'javascriptreact': ['eslint'], 'typescriptireact': ['eslint'],'python': ['flake8'] } | |
| let g:ale_fixers = {'javascript': ['prettier', 'eslint'], 'typescript': ['prettier', 'eslint'], 'javascriptreact': ['prettier', 'eslint'], 'typecriptreact': ['prettier', 'eslint'], 'python': ['isort', 'black'] } | |
| let g:ale_pattern_options = { '.*\.py?$': {'ale_enabled': 1},'.*\.(js|jsx)?$': {'ale_enabled': 1}, '.*\.(ts|tsx)?$': {'ale_enabled': 1}, '.*\.html$': {'ale_enabled': 0},} | |
| vmap ++ <plug>NERDCommenterToggle | |
| nmap <F5> :TagbarToggle<CR> | |
| " ── C/C++ language server ─────────────────────────────────────────────────── | |
| " | |
| " clangd does not guess compile flags -- it reads compile_commands.json. That | |
| " file is generated for the engine and all four games by: | |
| " | |
| " python3 ~/Projects/tools/gen-compile-commands.py | |
| " | |
| " Re-run it after adding a source file. Without it clangd starts, reports no | |
| " errors, and offers nothing useful, which looks like a broken plugin rather | |
| " than a missing file. | |
| " | |
| " The setup runs on VimEnter because vim-plug only puts plugins on the runtime | |
| " path at plug#end(); their plugin/ scripts are sourced after this file is | |
| " finished, so LspOptionsSet does not exist yet at this point. | |
| function! s:SetupLsp() abort | |
| if !exists('*LspAddServer') || !executable('clangd') | |
| return | |
| endif | |
| call LspOptionsSet({ | |
| \ 'autoComplete': v:true, | |
| \ 'showSignature': v:true, | |
| \ 'showDiagWithVirtualText': v:false, | |
| \ 'echoDiagnosticText': v:true, | |
| \ 'useQuickfixForLocations': v:true, | |
| \ 'ignoreMissingServer': v:true, | |
| \ }) | |
| call LspAddServer([{ | |
| \ 'name': 'clangd', | |
| \ 'filetype': ['c', 'cpp'], | |
| \ 'path': exepath('clangd'), | |
| \ 'args': ['--background-index', | |
| \ '--clang-tidy', | |
| \ '--completion-style=detailed', | |
| \ '--header-insertion=never'], | |
| \ }]) | |
| endfunction | |
| " Python deliberately has no language server. jedi-vim was removed because the | |
| " jedi library was never installed, so it had been inert -- and there are four | |
| " tracked .py files across every repo, which does not justify a server running | |
| " in the background. ALE already covers flake8 + black + isort. | |
| " | |
| " If that ever becomes annoying: `sudo apt install python3-pylsp`, then add to | |
| " the LspAddServer list above: | |
| " | |
| " {'name': 'pylsp', 'filetype': ['python'], 'path': exepath('pylsp'), 'args': []} | |
| " | |
| " Same keys, same popup, same config block -- one system rather than two. | |
| augroup StormLsp | |
| autocmd! | |
| autocmd VimEnter * call s:SetupLsp() | |
| augroup END | |
| " ALE and clangd both want to diagnose C++, and two sets of signs for the same | |
| " error is worse than one. `explicit` makes ALE run only the linters named in | |
| " g:ale_linters above, so C++ is clangd's alone and JS/TS/Python are unchanged. | |
| let g:ale_linters_explicit = 1 | |
| " Buffer-local, so these keys keep their normal meaning everywhere else. | |
| function! s:CppMaps() abort | |
| if !exists('*LspAddServer') | |
| return | |
| endif | |
| nnoremap <buffer> gd :LspGotoDefinition<CR> | |
| nnoremap <buffer> gD :LspGotoDeclaration<CR> | |
| nnoremap <buffer> gr :LspShowReferences<CR> | |
| nnoremap <buffer> K :LspHover<CR> | |
| nnoremap <buffer> <leader>rn :LspRename<CR> | |
| nnoremap <buffer> <leader>a :LspCodeAction<CR> | |
| nnoremap <buffer> <leader>o :LspSwitchSourceHeader<CR> | |
| nnoremap <buffer> [d :LspDiagPrev<CR> | |
| nnoremap <buffer> ]d :LspDiagNext<CR> | |
| nnoremap <buffer> <leader>d :LspDiagShow<CR> | |
| " Symbol search across the project -- the fastest way into an engine header. | |
| nnoremap <buffer> <leader>s :LspSymbolSearch<Space> | |
| endfunction | |
| augroup StormCpp | |
| autocmd! | |
| autocmd FileType c,cpp call s:CppMaps() | |
| autocmd FileType c,cpp setlocal shiftwidth=2 tabstop=2 expandtab textwidth=80 | |
| augroup END | |
| " ── Finding things ────────────────────────────────────────────────────────── | |
| " ctrlp is gone; fzf.vim replaces it and is faster on a tree the size of the | |
| " engine. :Rg needs ripgrep, which is installed. | |
| nnoremap <leader>f :Files<CR> | |
| nnoremap <leader>b :Buffers<CR> | |
| nnoremap <leader>g :Rg<Space> | |
| nnoremap <leader>t :Tags<CR> | |
| nnoremap <leader>h :History<CR> | |
| if executable('rg') | |
| set grepprg=rg\ --vimgrep\ --smart-case | |
| set grepformat=%f:%l:%c:%m | |
| endif | |
| " gf and :find reach engine headers from a game's source tree. | |
| set path+=/usr/local/include,src,common | |
| " ── Build and run ─────────────────────────────────────────────────────────── | |
| " The engine and the games build differently, so the binding asks the directory | |
| " rather than making you remember. Errors land in the quickfix list. | |
| function! s:MakePrg() abort | |
| if filereadable('Makefile.debian') | |
| return 'make -f Makefile.debian' | |
| endif | |
| return 'make' | |
| endfunction | |
| function! s:Build() abort | |
| let &l:makeprg = s:MakePrg() | |
| silent! wall | |
| make! | |
| cwindow | |
| endfunction | |
| function! s:Run() abort | |
| let l:cmd = filereadable('Makefile.debian') | |
| \ ? 'make -f Makefile.debian test' | |
| \ : 'make run' | |
| execute 'FloatermNew --autoclose=0' l:cmd | |
| endfunction | |
| nnoremap <F6> :call <SID>Build()<CR> | |
| nnoremap <F7> :call <SID>Run()<CR> | |
| " Quickfix, which is where build errors arrive. | |
| nnoremap <F8> :cwindow<CR> | |
| nnoremap ]q :cnext<CR> | |
| nnoremap [q :cprevious<CR> | |
| " ── The cheatsheet ────────────────────────────────────────────────────────── | |
| " A real Vim help file at ~/.vim/doc/storm-cheat.txt, so :help completion, | |
| " tags and searching all work on it. <leader>? opens it in a vertical split. | |
| nnoremap <leader>? :vertical help storm-cheat<CR> | |
| command! Cheat vertical help storm-cheat |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment