Skip to content

Instantly share code, notes, and snippets.

@WillSams
Last active September 3, 2026 16:01
Show Gist options
  • Select an option

  • Save WillSams/21429927c030c9870a7d723c62e5cb8a to your computer and use it in GitHub Desktop.

Select an option

Save WillSams/21429927c030c9870a7d723c62e5cb8a to your computer and use it in GitHub Desktop.
Vim for Storm! Engine Dev
" <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