summaryrefslogtreecommitdiff
path: root/mac/vimrc
diff options
context:
space:
mode:
Diffstat (limited to 'mac/vimrc')
-rw-r--r--mac/vimrc155
1 files changed, 108 insertions, 47 deletions
diff --git a/mac/vimrc b/mac/vimrc
index 6de4092..ba9bd88 100644
--- a/mac/vimrc
+++ b/mac/vimrc
@@ -1,4 +1,14 @@
1" ~/.vimrc (macOS + Linux) — self-contained; source of truth: dev_env/mac/vimrc 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
2" 12"
3" Setup (LSP servers below are optional — each is guarded by executable()): 13" Setup (LSP servers below are optional — each is guarded by executable()):
4" plugins: curl -fLo ~/.vim/autoload/plug.vim --create-dirs \ 14" plugins: curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
@@ -6,16 +16,39 @@
6" then launch vim and run :PlugInstall 16" then launch vim and run :PlugInstall
7" rust: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y 17" rust: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
8" rustup component add rust-analyzer 18" rustup component add rust-analyzer
9" ts/js: npm i -g typescript@6 typescript-language-server (Linux: sudo npm …)
10" (TypeScript 7 ships no tsserver, which typescript-language-server needs)
11" python: curl -LsSf https://astral.sh/uv/install.sh | sh 19" python: curl -LsSf https://astral.sh/uv/install.sh | sh
12" uv tool install ruff && uv tool install ty 20" uv tool install ruff && uv tool install pyright
13" search: ripgrep (for :Rg); Fedora: dnf install vim-enhanced ripgrep
14" 21"
15" Stop vim from auto-loading defaults.vim, which loads AFTER this file and 22" Stop vim from auto-loading defaults.vim, which loads AFTER this file and
16" would otherwise silently override settings here. Everything is in this file. 23" would otherwise silently override settings here. Everything is in this file.
17let g:skip_defaults_vim = 1 24let g:skip_defaults_vim = 1
18 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
19 52
20 53
21augroup netcat_clipboard 54augroup netcat_clipboard
@@ -47,6 +80,7 @@ set statusline=%F
47set wildmenu 80set wildmenu
48set splitright 81set splitright
49set splitbelow 82set splitbelow
83set hidden " gd/LSP jumps reuse the window even with unsaved changes
50set noswapfile 84set noswapfile
51set regexpengine=2 85set regexpengine=2
52set completeopt=menu,menuone,noinsert,noselect 86set completeopt=menu,menuone,noinsert,noselect
@@ -73,11 +107,24 @@ colorscheme zellner
73 107
74autocmd InsertLeave * silent! update 108autocmd InsertLeave * silent! update
75 109
76inoremap <C-a> <Home> 110" Files rustup and cargo manage (toolchains, downloaded crates) open locked; :setl ma noro to override
77inoremap <C-e> <End> 111function! s:LockIfManaged() abort
78nnoremap <C-a> 0 112 if !exists('s:managed')
79nnoremap <C-e> $ 113 let l:cargo = empty($CARGO_HOME) ? expand('~/.cargo') : $CARGO_HOME
80nnoremap <silent> <C-l> :<C-U>nohlsearch<CR><C-l> 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
81 128
82call plug#begin('~/.vim/plugged') 129call plug#begin('~/.vim/plugged')
83Plug 'prabirshrestha/async.vim' 130Plug 'prabirshrestha/async.vim'
@@ -97,10 +144,6 @@ call plug#end()
97 144
98let g:gitgutter_sign_column_always = 0 145let g:gitgutter_sign_column_always = 0
99 146
100nnoremap <silent> <C-p> :<C-U>Files<CR>
101nnoremap <silent> <leader>rg :<C-U>Rg<CR>
102nnoremap <silent> <leader>b :<C-U>Buffers<CR>
103nnoremap <silent> <leader>n :<C-U>NERDTreeToggle<CR>
104 147
105" rust-analyzer via the rustup proxy shim (portable across toolchains/machines) 148" rust-analyzer via the rustup proxy shim (portable across toolchains/machines)
106if executable(expand('~/.cargo/bin/rust-analyzer')) 149if executable(expand('~/.cargo/bin/rust-analyzer'))
@@ -118,24 +161,6 @@ if executable(expand('~/.cargo/bin/rust-analyzer'))
118 \ }, 161 \ },
119 \ }) 162 \ })
120endif 163endif
121function! s:ts_root(server_info) abort
122 let l:buf = lsp#utils#get_buffer_path()
123 for l:f in ['tsconfig.json', 'package.json']
124 let l:dir = lsp#utils#find_nearest_parent_file_directory(l:buf, l:f)
125 if !empty(l:dir)
126 return lsp#utils#path_to_uri(l:dir)
127 endif
128 endfor
129 return lsp#utils#path_to_uri(getcwd())
130endfunction
131if executable('typescript-language-server')
132 au User lsp_setup call lsp#register_server({
133 \ 'name': 'typescript-language-server',
134 \ 'cmd': {server_info -> ['typescript-language-server', '--stdio']},
135 \ 'allowlist': ['typescript', 'typescriptreact', 'javascript', 'javascriptreact'],
136 \ 'root_uri': function('s:ts_root'),
137 \ })
138endif
139if executable(expand('~/.local/bin/ruff')) 164if executable(expand('~/.local/bin/ruff'))
140 au User lsp_setup call lsp#register_server({ 165 au User lsp_setup call lsp#register_server({
141 \ 'name': 'ruff', 166 \ 'name': 'ruff',
@@ -155,6 +180,23 @@ if executable(expand('~/.local/bin/ty')) && executable(s:uv_bin)
155 \ 'allowlist': ['python'], 180 \ 'allowlist': ['python'],
156 \ }) 181 \ })
157endif 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
158 200
159" Force per-keystroke LSP sync for Python (vim-lsp only syncs on 201" Force per-keystroke LSP sync for Python (vim-lsp only syncs on
160" InsertLeave/TextChanged by default, not while actively typing). 202" InsertLeave/TextChanged by default, not while actively typing).
@@ -167,6 +209,7 @@ let g:lsp_diagnostics_signs_enabled = 0
167let g:lsp_document_highlight_enabled = 0 209let g:lsp_document_highlight_enabled = 0
168let g:lsp_preview_float = 0 210let g:lsp_preview_float = 0
169let g:lsp_hover_ui = 'preview' 211let g:lsp_hover_ui = 'preview'
212let g:lsp_code_action_ui = 'float' " \a = one popup menu, not 3 windows
170let g:lsp_signature_help_enabled = 0 213let g:lsp_signature_help_enabled = 0
171 214
172function! s:set_preview_height() abort 215function! s:set_preview_height() abort
@@ -208,15 +251,6 @@ function! ToggleDiagnostic() abort
208 call win_gotoid(l:cur) 251 call win_gotoid(l:cur)
209endfunction 252endfunction
210 253
211nnoremap <silent> <leader>k :<C-U>call ToggleHover()<CR>
212nnoremap <silent> gd :<C-U>LspDefinition<CR>
213nnoremap <silent> gi :<C-U>LspImplementation<CR>
214nnoremap <silent> <leader>rn :<C-U>LspRename<CR>
215nnoremap <silent> <leader>a :<C-U>LspCodeAction<CR>
216nnoremap <silent> <leader>f :<C-U>LspDocumentFormat<CR>
217nnoremap <silent> <leader>l :<C-U>lopen<CR>
218nnoremap <silent> <leader>D :<C-U>LspDocumentation<CR>
219nnoremap <silent> <leader>e :<C-U>call ToggleDiagnostic()<CR>
220 254
221" rust-analyzer macro expansion (LSP extension, no built-in command). 255" rust-analyzer macro expansion (LSP extension, no built-in command).
222function! ExpandMacro() abort 256function! ExpandMacro() abort
@@ -247,11 +281,38 @@ function! s:expand_macro_handler(data) abort
247 call append(line('$'), split(l:result['expansion'], "\n")) 281 call append(line('$'), split(l:result['expansion'], "\n"))
248endfunction 282endfunction
249 283
250nnoremap <silent> <leader>em :<C-U>call ExpandMacro()<CR>
251 284
252inoremap <silent> <C-Space> <C-x><C-o> 285" gd: say when rust-analyzer is still starting/indexing instead of a false "No definition found"
253inoremap <silent> <C-@> <C-x><C-o> 286let g:lsp_work_done_progress_enabled = 1
254inoremap <expr> <Tab> pumvisible() ? "\<C-n>" : "\<Tab>" 287function! s:GotoDef() abort
255inoremap <expr> <S-Tab> pumvisible() ? "\<C-p>" : "\<S-Tab>" 288 if &filetype ==# 'rust'
256inoremap <expr> <CR> pumvisible() ? "\<C-y>" : "\<CR>" 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
257 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()