vim9script set nocompatible set termguicolors set encoding=utf-8 scriptencoding utf-8 # Plugins plug#begin() Plug 'vimpostor/vim-lumen' Plug 'tpope/vim-commentary' Plug 'tpope/vim-fugitive' Plug 'tpope/vim-surround' Plug 'tpope/vim-repeat' Plug '/opt/homebrew/opt/fzf' Plug 'junegunn/fzf.vim' Plug 'SirVer/ultisnips' Plug 'dense-analysis/ale' Plug 'vim-pandoc/vim-pandoc-syntax' Plug 'quarto-dev/quarto-vim' Plug 'HerringtonDarkholme/yats.vim' Plug 'elixir-editors/vim-elixir' Plug 'bullets-vim/bullets.vim' plug#end() # Language config g:pandoc#syntax#conceal#use = 0 g:r_indent_align_args = 0 # Syntax and colors and things filetype plugin indent on syntax on # Disable Swapping set nobackup nowritebackup noswapfile # Statusline set laststatus=2 set statusline=—[%n\:\ %t]—%=—%y—[%l/%L,\ %c]—%m%r— set fillchars=stl:—,eob:\ set fillchars+=stlnc:— set fillchars+=vert:\| # Hide intro message set shortmess=I set nowrap # Relative numbering with absolute anchor set number relativenumber set signcolumn=number set cursorline cursorlineopt=both # Keep buffers open in memory when not visible set hidden # Keep buffers up to date with external changes set autoread set backspace=indent,eol,start # Show invisibles set list set listchars=tab:‣\ ,trail:·,extends:◣,precedes:◢,nbsp:○ # Disable folding set foldmethod=manual set nofoldenable # Search fixes set ignorecase smartcase incsearch hlsearch gdefault # Show incomplete command-based changes in realtime set showcmd # And breathe... set scrolloff=5 # I think left to write, top to bottom set splitright splitbelow # Basic whitespace set nojoinspaces set expandtab set shiftwidth=4 set softtabstop=4 set textwidth=79 set autoindent # Show me when my lines are too long # # I wish to limit my lines to 80 characters long. However, Vim creates # the n+1th character when you have n characters in a line. Hence, when # my line is 80 characters long, I see the red line. So, this is set to # 82, meaning that I only see the line when my lines actually are too long. matchadd('ColorColumn', '\%82v', 100) # Mappings etc g:mapleader = "\" g:localmapleader = "\\" # Use jk to escape back to normal inoremap jk inoremap # Hide search highlights nnoremap :noh nnoremap / :noh # Switch between recent buffers nnoremap # Fix shift-semicolon to write noremap ; : # Make it easier to use registers nnoremap ' " # I should map these to something useful inoremap inoremap inoremap inoremap noremap noremap noremap noremap # Case control nnoremap u viwU nnoremap l viwu # Moving lines around nnoremap - ddp== nnoremap _ :-1dpk== # Quick access vimrc nnoremap ev :tabedit $MYVIMRC nnoremap es :so $MYVIMRC # Pane management nnoremap nnoremap nnoremap nnoremap inoremap inoremap inoremap inoremap # I'm getting back into visual mode # And I'm cycling the modes nnoremap v V nnoremap V nnoremap v # FZF nnoremap o :Files nnoremap b :Buffers nnoremap f :Rg nnoremap g :RG g:fzf_vim = {} g:fzf_vim.preview_window = [] def BuildQuickfixList(lines: list) setqflist(map(copy(a:lines), '{ "filename": v:val, "lnum": 1 }')) copen cc enddef g:fzf_action = { \ 'ctrl-q': function('BuildQuickfixList'), \ 'ctrl-t': 'tab split', \ 'ctrl-x': 'split', \ 'ctrl-v': 'vsplit' } augroup FZF autocmd! autocmd FileType fzf tmap jk augroup END # Focus mode g:is_zoomed = false def Zoom() if g:is_zoomed g:is_zoomed = false wincmd = else g:is_zoomed = true wincmd _ wincmd | endif enddef # Git blame nnoremap a Zoom():Git blame # Make directories in a filename if they don't exist. def EnsureDirExists() var required_dir = expand("%:h") if !isdirectory(required_dir) try mkdir(required_dir, 'p') catch echom "Could not create directory" exit endtry endif enddef augroup AutoMkdir autocmd! autocmd BufNewFile * EnsureDirExists() augroup END # Use tab for UltiSnips expansion, navigation, and g:ulti_expand_or_jump_res = 0 g:UltiSnipsExpandOrJumpTrigger = '' def g:Ultisnips_expand(default: string): string UltiSnips#ExpandSnippetOrJump() if g:ulti_expand_or_jump_res == 0 return default else return "" endif enddef # inoremap Ulti_ExpandOrJump_and_getRes("\") # Notes config g:markdown_fenced_languages = ['r', 'elixir', 'python', 'html', 'rust'] g:pandoc#syntax#codeblocks#embeds#langs = ['r', 'elixir', 'python', 'html', 'rust'] # Enable bullets.vim in Quarto files g:bullets_enabled_file_types = ['markdown', 'text', 'gitcommit', 'quarto'] # Disable the bullet changing on indents (for now) g:bullets_outline_levels = ['num', 'std-'] def EditCodeBlock() var b = bufnr("%") var name = b .. ".codeblock" # We only create one code block buffer per buffer. So if it already # exists, we will empty it out. If it doesn't already exist, we # create it. # # If it exists and has unsaved changes, we exit and warn. var code_buffer = bufnr(name, 1) if getbufvar(code_buffer, "&modified") echom "Unsaved changes in existing code block for this file." return endif # Store current cursor position for state restoration later. var p = getpos(".") # Set bottom mark for code block execute "silent normal! /^```\rmb" # Set top mark for code block execute "silent normal! ?^```\rmt" # Yank contents to source register execute "silent normal! j\"cy`b" # Yank filetype to type register, and reset position to top execute "silent normal! `t3l\"fy$`t" # Find offset position of cursor so the new buffer is in the # correct place var line = p[1] var col = p[2] var s = getpos("'t") var start_line = s[1] line = line - start_line # If code block buffer is visible, go there. If it is not visible, # then we should show it below. var window = bufwinnr(code_buffer) if window == -1 execute "below sbuffer " .. code_buffer else execute ":" .. window .. "windo :" execute "buffer " .. code_buffer endif set buftype=acwrite # Clear buffer and fill with new code silent :%d " silent :0put c normal! G"_dd # Position cursor correctly, and mark setpos(".", [0, line, col, 0]) # Link back to the original buffer for saving b:original_buffer = b # Set file type, if it is correctly annotated if @f != '`' execute 'set filetype=' .. @f endif set nomodified enddef def SaveCodeBlock() var b = bufnr("%") silent :%yank c normal! mc silent execute "buffer " .. b:original_buffer silent execute "normal! `tjd`b`t\"cp" silent execute "buffer " .. b set nomodified normal! `c echom "Code block updated" enddef augroup CodeBlocks autocmd! autocmd BufWriteCmd *.codeblock SaveCodeBlock() augroup END augroup Notes # autocmd Filetype quarto setl tw=80 fo+=croqt ts=4 sts=4 sw=4 comments=n:> # Surround mappings for Quarto callouts autocmd FileType quarto b:surround_110 = "::: {.callout-note}\n\r\n:::" autocmd FileType quarto b:surround_116 = "::: {.callout-tip}\n\r\n:::" autocmd FileType quarto b:surround_119 = "::: {.callout-warning}\n\r\n:::" autocmd FileType quarto b:surround_105 = "::: {.callout-important}\n\r\n:::" autocmd FileType quarto imap =g:Ultisnips_expand("\") autocmd FileType quarto imap autocmd FileType quarto onoremap cb :execute "normal! /^```\rk$ms?^```\rj:noh\rv`s" autocmd FileType quarto nnoremap ec EditCodeBlock() autocmd FileType quarto inoremap EditCodeBlock() augroup END nnoremap x :silent keepp s/^- \[ \]/- [o]/e:silent keepp s/^- \[x\]/- [ ]/e:silent keepp s/^- \[o\]/- [x]/e # Daily notes def FormatOffset(offset: number): string if offset == 0 return "" elseif offset > 0 return "-v+" .. offset .. "d " else return "-v" .. offset .. "d " endif enddef def OpenDailyNote(offset = 0) var command = "date -v-4H " .. FormatOffset(offset) .. "\"+%Y-%m-%d\"" var date = trim(system(command)) var filename = $DAILY_NOTES_PATH .. "/" .. date .. "-daily.qmd" if !filereadable(filename) var template = $DAILY_NOTES_PATH .. "/template.py" system(shellescape(template) .. " " .. shellescape(date) .. " > " .. shellescape(filename)) endif execute "edit " .. filename enddef command -nargs=? Daily OpenDailyNote() def StartUp() if @% == "" OpenDailyNote() endif enddef augroup StartUp autocmd! autocmd VimEnter * ++nested StartUp() augroup END # LSP and other completion g:ale_completion_enabled = 1 g:ale_elixir_elixir_ls_release = '/opt/homebrew/opt/elixir-ls/libexec' g:ale_fix_on_save = 1 g:ale_fixers = { \ 'css': ['prettier'], \ 'elixir': ['mix_format'], \ 'html': ['prettier'], \ 'javascript': ['prettier'], \ 'javascriptreact': ['prettier'], \ 'md': ['prettier'], \ 'typescript': ['prettier'], \ 'typescriptreact': ['prettier'], \ 'yaml': ['prettier'], \ } g:ale_linters = { \ 'elixir': ['elixir-ls'], \ 'javascript': ['eslint'], \ } nnoremap za :ALEFirst nnoremap zn :ALENextWrap nnoremap zN :ALEPreviousWrap nnoremap d :ALEGoToDefinition nnoremap de :ALEGoToDefinition nnoremap dx :ALEGoToDefinition -split nnoremap dv :ALEGoToDefinition -vsplit nnoremap dt :ALEGoToDefinition -tab # File Running def PreviewQuarto() ClosePreview() echom 'Starting preview job' b:file = expand('%') b:preview_job = job_start( \ ['quarto', 'preview', b:file], \ ) enddef def ClosePreview() if exists("b:preview_job") echo 'Killing existing job...' job_stop(b:preview_job) endif enddef nnoremap r :echo 'No preview configured' nmap r augroup Previews autocmd! autocmd Filetype quarto nnoremap r PreviewQuarto() augroup END augroup TextFormatting autocmd! autocmd FileType make,go setl noet sw=8 sts=8 ts=8 autocmd FileType r,elixir setl et sw=2 sts=2 ts=2 augroup END # Show syntax highlighting groups for word under cursor # # This is useful for finding rogue elements I forgot in my colour # scheme. def SynStack() if !exists("*synstack") return endif echo map(synstack(line('.'), col('.')), 'synIDattr(v:val,"name")') enddef nnoremap \ SynStack() # Open syntax file for current # Syntax highlighting colorscheme mpwb