dotfiles/vim/vim.xdg.symlink/vimrc
2025-01-19 11:41:20 +00:00

500 lines
11 KiB
VimL

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-eunuch'
Plug 'tpope/vim-fugitive'
Plug 'tpope/vim-repeat'
Plug 'tpope/vim-surround'
Plug 'arthurxavierx/vim-caser'
Plug '/opt/homebrew/opt/fzf'
Plug 'junegunn/fzf.vim'
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 'maxbucknell/vim-mbnotes'
Plug 'SirVer/ultisnips'
Plug 'dense-analysis/ale'
Plug 'prabirshrestha/asyncomplete.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 = "\<space>"
g:maplocalleader = ","
# Use jk to escape back to normal
inoremap jk <esc>
inoremap <esc> <nop>
# Hide search highlights
nnoremap <bs> :noh<cr>
# Switch between recent buffers
nnoremap <leader><leader> <c-^>
# Fix shift-semicolon to colon
noremap ; :
# I should map these to something useful
inoremap <up> <nop>
inoremap <down> <nop>
inoremap <left> <nop>
inoremap <right> <nop>
noremap <up> <nop>
noremap <down> <nop>
# Update almost a decade later: I mapped these to something useful!
noremap <left> :cprev<cr>
noremap <right> :cnext<cr>
# Case control
nnoremap <leader>u viwU
nnoremap <leader>l viwu
# Moving lines around
nnoremap - ddp==
nnoremap _ :-1d<cr>pk==
# Quick access vimrc
nnoremap <leader>ev :tabedit $MYVIMRC<cr>
nnoremap <leader>es :so $MYVIMRC<cr>
# Pane management
nnoremap <c-j> <c-w><c-j>
nnoremap <c-k> <c-w><c-k>
nnoremap <c-h> <c-w><c-h>
nnoremap <c-l> <c-w><c-l>
inoremap <c-j> <esc><c-w><c-j>
inoremap <c-k> <esc><c-w><c-k>
inoremap <c-h> <esc><c-w><c-h>
inoremap <c-l> <esc><c-w><c-l>
# I'm getting back into visual mode
# And I'm cycling the modes
nnoremap v V
nnoremap V <c-v>
nnoremap <c-v> v
# FZF
nnoremap <leader>o :Files<cr>
nnoremap <leader>b :Buffers<cr>
nnoremap <leader>f :Rg<cr>
nnoremap <leader>g :RG<cr>
g:fzf_vim = {}
g:fzf_vim.preview_window = []
def BuildQuickfixList(lines: list<string>)
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 <buffer> jk <c-c>
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 <leader>a <ScriptCmd>Zoom()<cr>:Git blame<cr>
nnoremap <leader>z <ScriptCmd>Zoom()<cr>
# 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 = '<tab>'
g:UltiSnipsSnippetStorageDirectoryForUltiSnipsEdit = $DOTFILES_PATH .. "/vim/vim.xdg.symlink/Ultisnips"
def g:Ultisnips_expand(default: string): string
UltiSnips#ExpandSnippetOrJump()
if g:ulti_expand_or_jump_res == 0
return default
else
return ""
endif
enddef
# inoremap <expr> <tab> <ScriptCmd>Ulti_ExpandOrJump_and_getRes("\<tab>")
# Notes config
g:mbnotes_dir = $HOME .. "/Dropbox (Maestral)/Notes"
g:mbnotes_out_dir = g:mbnotes_dir .. "/_output"
g:mbnotes_open_daily_on_startup = true
g:mbnotes_renderer_show = true
g:mbnotes_renderer_close_on_end = true
nnoremap <leader>t :MBNotesDaily<cr>
nnoremap <leader>n :MBNotes<cr>
nnoremap <c-n> :MBNotesNew<cr>
nnoremap <c-x> :MBNotesNewSplit<cr>
nnoremap <c-v> :vertical MBNotesNewSplit<cr>
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', 'mbnotes', 'mbnotes.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 != '`'
@f = substitute(@f, "[\{\}]", "", "g")
execute 'setf=' .. @f
endif
set nomodified
enddef
command -nargs=0 EditCodeBlock EditCodeBlock()
def g: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 g:SaveCodeBlock()
augroup END
augroup Notes
autocmd!
autocmd FileType mbnotes imap <buffer> <tab> <c-r>=g:Ultisnips_expand("\<c-t>")<cr>
autocmd FileType mbnotes imap <buffer> <s-tab> <c-d>
autocmd FileType mbnotes onoremap <expr> cb :<c-u>execute "normal! /^```\rk$ms?^```\rj:noh\rv`s"<cr>
autocmd FileType mbnotes nnoremap <leader>ec :EditCodeBlock<cr>
autocmd FileType mbnotes inoremap <c-e> <esc>:EditCodeBlock<cr>
augroup END
nnoremap <leader>x :silent keepp s/^- \[ \]/- [o]/e<cr>:silent keepp s/^- \[x\]/- [ ]/e<cr>:silent keepp s/^- \[o\]/- [x]/e<cr>
augroup StartUp
autocmd!
autocmd VimResized * wincmd =
augroup END
# LSP and other completion
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<cr>
nnoremap zn :ALENextWrap<cr>
nnoremap zN :ALEPreviousWrap<cr>
nnoremap <leader>d :ALEGoToDefinition<cr>
nnoremap <leader>de :ALEGoToDefinition<cr>
nnoremap <leader>dx :ALEGoToDefinition -split<cr>
nnoremap <leader>dv :ALEGoToDefinition -vsplit<cr>
nnoremap <leader>dt :ALEGoToDefinition -tab<cr>
# au User asyncomplete_setup call asyncomplete#register_source(asyncomplete#sources#ale#get_source_options({
# \ 'priority': 10, " Provide your own overrides here
# \ }))
inoremap <expr> <cr> pumvisible() ? asyncomplete#close_popup() : "\<cr>"
augroup Completion
autocmd!
autocmd User asyncomplete_setup {
asyncomplete#register_source(
asyncomplete#sources#mbnotes#get_source_options({ 'priority': 9 })
)
asyncomplete#register_source(
asyncomplete#sources#ale#get_source_options({ 'priority': 10 })
)
asyncomplete#register_source(
asyncomplete#sources#ultisnips#get_source_options({ 'priority': 11 })
)
}
augroup END
# File Running
def PreviewQuarto()
ClosePreview()
echom 'Starting preview job'
b:preview_job = job_start([
'quarto',
'preview',
expand('%')
])
enddef
def ClosePreview()
if exists("b:preview_job")
echo 'Killing existing job...'
job_stop(b:preview_job)
endif
enddef
nnoremap <leader>r :echo 'No preview configured'<cr>
nmap <F5> <leader>r
augroup Previews
autocmd!
autocmd Filetype quarto nnoremap <buffer> <leader>r <ScriptCmd>PreviewQuarto()<cr>
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 <leader>\ <ScriptCmd>SynStack()<cr>
# Open syntax file for current
# Syntax highlighting
colorscheme mpwb